1 //
2 //
3 // Copyright 2016 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/lib/address_utils/parse_address.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #ifdef GRPC_HAVE_UNIX_SOCKET
27 #include <sys/un.h>
28 #endif
29 #include <string>
30
31 #include "absl/status/status.h"
32 #include "absl/strings/str_cat.h"
33 #include "absl/strings/strip.h"
34
35 #include <grpc/support/log.h>
36
37 #include "src/core/lib/gpr/string.h"
38 #include "src/core/lib/gprpp/host_port.h"
39 #include "src/core/lib/gprpp/status_helper.h"
40 #include "src/core/lib/iomgr/grpc_if_nametoindex.h"
41 #include "src/core/lib/iomgr/port.h"
42 #include "src/core/lib/iomgr/sockaddr.h"
43 #include "src/core/lib/iomgr/socket_utils.h"
44
45 // IWYU pragma: no_include <arpa/inet.h>
46
47 #ifdef GRPC_HAVE_UNIX_SOCKET
48
grpc_parse_unix(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)49 bool grpc_parse_unix(const grpc_core::URI& uri,
50 grpc_resolved_address* resolved_addr) {
51 if (uri.scheme() != "unix") {
52 gpr_log(GPR_ERROR, "Expected 'unix' scheme, got '%s'",
53 uri.scheme().c_str());
54 return false;
55 }
56 grpc_error_handle error =
57 grpc_core::UnixSockaddrPopulate(uri.path(), resolved_addr);
58 if (!error.ok()) {
59 gpr_log(GPR_ERROR, "%s", grpc_core::StatusToString(error).c_str());
60 return false;
61 }
62 return true;
63 }
64
grpc_parse_unix_abstract(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)65 bool grpc_parse_unix_abstract(const grpc_core::URI& uri,
66 grpc_resolved_address* resolved_addr) {
67 if (uri.scheme() != "unix-abstract") {
68 gpr_log(GPR_ERROR, "Expected 'unix-abstract' scheme, got '%s'",
69 uri.scheme().c_str());
70 return false;
71 }
72 grpc_error_handle error =
73 grpc_core::UnixAbstractSockaddrPopulate(uri.path(), resolved_addr);
74 if (!error.ok()) {
75 gpr_log(GPR_ERROR, "%s", grpc_core::StatusToString(error).c_str());
76 return false;
77 }
78 return true;
79 }
80
81 namespace grpc_core {
82
UnixSockaddrPopulate(absl::string_view path,grpc_resolved_address * resolved_addr)83 grpc_error_handle UnixSockaddrPopulate(absl::string_view path,
84 grpc_resolved_address* resolved_addr) {
85 memset(resolved_addr, 0, sizeof(*resolved_addr));
86 struct sockaddr_un* un =
87 reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
88 const size_t maxlen = sizeof(un->sun_path) - 1;
89 if (path.size() > maxlen) {
90 return GRPC_ERROR_CREATE(absl::StrCat(
91 "Path name should not have more than ", maxlen, " characters"));
92 }
93 un->sun_family = AF_UNIX;
94 path.copy(un->sun_path, path.size());
95 un->sun_path[path.size()] = '\0';
96 resolved_addr->len = static_cast<socklen_t>(sizeof(*un));
97 return absl::OkStatus();
98 }
99
UnixAbstractSockaddrPopulate(absl::string_view path,grpc_resolved_address * resolved_addr)100 grpc_error_handle UnixAbstractSockaddrPopulate(
101 absl::string_view path, grpc_resolved_address* resolved_addr) {
102 memset(resolved_addr, 0, sizeof(*resolved_addr));
103 struct sockaddr_un* un =
104 reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
105 const size_t maxlen = sizeof(un->sun_path) - 1;
106 if (path.size() > maxlen) {
107 return GRPC_ERROR_CREATE(absl::StrCat(
108 "Path name should not have more than ", maxlen, " characters"));
109 }
110 un->sun_family = AF_UNIX;
111 un->sun_path[0] = '\0';
112 path.copy(un->sun_path + 1, path.size());
113 resolved_addr->len =
114 static_cast<socklen_t>(sizeof(un->sun_family) + path.size() + 1);
115 return absl::OkStatus();
116 }
117
118 } // namespace grpc_core
119
120 #else // GRPC_HAVE_UNIX_SOCKET
121
grpc_parse_unix(const grpc_core::URI &,grpc_resolved_address *)122 bool grpc_parse_unix(const grpc_core::URI& /* uri */,
123 grpc_resolved_address* /* resolved_addr */) {
124 abort();
125 }
126
grpc_parse_unix_abstract(const grpc_core::URI &,grpc_resolved_address *)127 bool grpc_parse_unix_abstract(const grpc_core::URI& /* uri */,
128 grpc_resolved_address* /* resolved_addr */) {
129 abort();
130 }
131
132 namespace grpc_core {
133
UnixSockaddrPopulate(absl::string_view,grpc_resolved_address *)134 grpc_error_handle UnixSockaddrPopulate(
135 absl::string_view /* path */, grpc_resolved_address* /* resolved_addr */) {
136 abort();
137 }
138
UnixAbstractSockaddrPopulate(absl::string_view,grpc_resolved_address *)139 grpc_error_handle UnixAbstractSockaddrPopulate(
140 absl::string_view /* path */, grpc_resolved_address* /* resolved_addr */) {
141 abort();
142 }
143
144 } // namespace grpc_core
145 #endif // GRPC_HAVE_UNIX_SOCKET
146
grpc_parse_ipv4_hostport(absl::string_view hostport,grpc_resolved_address * addr,bool log_errors)147 bool grpc_parse_ipv4_hostport(absl::string_view hostport,
148 grpc_resolved_address* addr, bool log_errors) {
149 bool success = false;
150 // Split host and port.
151 std::string host;
152 std::string port;
153 if (!grpc_core::SplitHostPort(hostport, &host, &port)) {
154 if (log_errors) {
155 gpr_log(GPR_ERROR, "Failed gpr_split_host_port(%s, ...)",
156 std::string(hostport).c_str());
157 }
158 return false;
159 }
160 // Parse IP address.
161 memset(addr, 0, sizeof(*addr));
162 addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
163 grpc_sockaddr_in* in = reinterpret_cast<grpc_sockaddr_in*>(addr->addr);
164 in->sin_family = GRPC_AF_INET;
165 if (grpc_inet_pton(GRPC_AF_INET, host.c_str(), &in->sin_addr) == 0) {
166 if (log_errors) {
167 gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host.c_str());
168 }
169 goto done;
170 }
171 // Parse port.
172 if (port.empty()) {
173 if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv4 scheme");
174 goto done;
175 }
176 int port_num;
177 if (sscanf(port.c_str(), "%d", &port_num) != 1 || port_num < 0 ||
178 port_num > 65535) {
179 if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port.c_str());
180 goto done;
181 }
182 in->sin_port = grpc_htons(static_cast<uint16_t>(port_num));
183 success = true;
184 done:
185 return success;
186 }
187
grpc_parse_ipv4(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)188 bool grpc_parse_ipv4(const grpc_core::URI& uri,
189 grpc_resolved_address* resolved_addr) {
190 if (uri.scheme() != "ipv4") {
191 gpr_log(GPR_ERROR, "Expected 'ipv4' scheme, got '%s'",
192 uri.scheme().c_str());
193 return false;
194 }
195 return grpc_parse_ipv4_hostport(absl::StripPrefix(uri.path(), "/"),
196 resolved_addr, true /* log_errors */);
197 }
198
grpc_parse_ipv6_hostport(absl::string_view hostport,grpc_resolved_address * addr,bool log_errors)199 bool grpc_parse_ipv6_hostport(absl::string_view hostport,
200 grpc_resolved_address* addr, bool log_errors) {
201 bool success = false;
202 // Split host and port.
203 std::string host;
204 std::string port;
205 if (!grpc_core::SplitHostPort(hostport, &host, &port)) {
206 if (log_errors) {
207 gpr_log(GPR_ERROR, "Failed gpr_split_host_port(%s, ...)",
208 std::string(hostport).c_str());
209 }
210 return false;
211 }
212 // Parse IP address.
213 memset(addr, 0, sizeof(*addr));
214 addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
215 grpc_sockaddr_in6* in6 = reinterpret_cast<grpc_sockaddr_in6*>(addr->addr);
216 in6->sin6_family = GRPC_AF_INET6;
217 // Handle the RFC6874 syntax for IPv6 zone identifiers.
218 char* host_end =
219 static_cast<char*>(gpr_memrchr(host.c_str(), '%', host.size()));
220 if (host_end != nullptr) {
221 GPR_ASSERT(host_end >= host.c_str());
222 char host_without_scope[GRPC_INET6_ADDRSTRLEN + 1];
223 size_t host_without_scope_len =
224 static_cast<size_t>(host_end - host.c_str());
225 uint32_t sin6_scope_id = 0;
226 if (host_without_scope_len > GRPC_INET6_ADDRSTRLEN) {
227 if (log_errors) {
228 gpr_log(
229 GPR_ERROR,
230 "invalid ipv6 address length %zu. Length cannot be greater than "
231 "GRPC_INET6_ADDRSTRLEN i.e %d)",
232 host_without_scope_len, GRPC_INET6_ADDRSTRLEN);
233 }
234 goto done;
235 }
236 strncpy(host_without_scope, host.c_str(), host_without_scope_len);
237 host_without_scope[host_without_scope_len] = '\0';
238 if (grpc_inet_pton(GRPC_AF_INET6, host_without_scope, &in6->sin6_addr) ==
239 0) {
240 if (log_errors) {
241 gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
242 }
243 goto done;
244 }
245 if (gpr_parse_bytes_to_uint32(host_end + 1,
246 host.size() - host_without_scope_len - 1,
247 &sin6_scope_id) == 0) {
248 if ((sin6_scope_id = grpc_if_nametoindex(host_end + 1)) == 0) {
249 gpr_log(GPR_ERROR,
250 "Invalid interface name: '%s'. "
251 "Non-numeric and failed if_nametoindex.",
252 host_end + 1);
253 goto done;
254 }
255 }
256 // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027.
257 in6->sin6_scope_id = sin6_scope_id;
258 } else {
259 if (grpc_inet_pton(GRPC_AF_INET6, host.c_str(), &in6->sin6_addr) == 0) {
260 if (log_errors) {
261 gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host.c_str());
262 }
263 goto done;
264 }
265 }
266 // Parse port.
267 if (port.empty()) {
268 if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv6 scheme");
269 goto done;
270 }
271 int port_num;
272 if (sscanf(port.c_str(), "%d", &port_num) != 1 || port_num < 0 ||
273 port_num > 65535) {
274 if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port.c_str());
275 goto done;
276 }
277 in6->sin6_port = grpc_htons(static_cast<uint16_t>(port_num));
278 success = true;
279 done:
280 return success;
281 }
282
grpc_parse_ipv6(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)283 bool grpc_parse_ipv6(const grpc_core::URI& uri,
284 grpc_resolved_address* resolved_addr) {
285 if (uri.scheme() != "ipv6") {
286 gpr_log(GPR_ERROR, "Expected 'ipv6' scheme, got '%s'",
287 uri.scheme().c_str());
288 return false;
289 }
290 return grpc_parse_ipv6_hostport(absl::StripPrefix(uri.path(), "/"),
291 resolved_addr, true /* log_errors */);
292 }
293
grpc_parse_uri(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)294 bool grpc_parse_uri(const grpc_core::URI& uri,
295 grpc_resolved_address* resolved_addr) {
296 if (uri.scheme() == "unix") {
297 return grpc_parse_unix(uri, resolved_addr);
298 }
299 if (uri.scheme() == "unix-abstract") {
300 return grpc_parse_unix_abstract(uri, resolved_addr);
301 }
302 if (uri.scheme() == "ipv4") {
303 return grpc_parse_ipv4(uri, resolved_addr);
304 }
305 if (uri.scheme() == "ipv6") {
306 return grpc_parse_ipv6(uri, resolved_addr);
307 }
308 gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri.scheme().c_str());
309 return false;
310 }
311
grpc_strhtons(const char * port)312 uint16_t grpc_strhtons(const char* port) {
313 if (strcmp(port, "http") == 0) {
314 return htons(80);
315 } else if (strcmp(port, "https") == 0) {
316 return htons(443);
317 }
318 return htons(static_cast<unsigned short>(atoi(port)));
319 }
320
321 namespace grpc_core {
322
StringToSockaddr(absl::string_view address_and_port)323 absl::StatusOr<grpc_resolved_address> StringToSockaddr(
324 absl::string_view address_and_port) {
325 grpc_resolved_address out;
326 memset(&out, 0, sizeof(grpc_resolved_address));
327 if (!grpc_parse_ipv4_hostport(address_and_port, &out, /*log_errors=*/false) &&
328 !grpc_parse_ipv6_hostport(address_and_port, &out, /*log_errors=*/false)) {
329 return absl::InvalidArgumentError(
330 absl::StrCat("Failed to parse address:", address_and_port));
331 }
332 return out;
333 }
334
StringToSockaddr(absl::string_view address,int port)335 absl::StatusOr<grpc_resolved_address> StringToSockaddr(
336 absl::string_view address, int port) {
337 return StringToSockaddr(JoinHostPort(address, port));
338 }
339
340 } // namespace grpc_core
341