• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/core/lib/address_utils/parse_address.h"
20 
21 #include <grpc/support/port_platform.h>
22 
23 #include "src/core/lib/iomgr/port.h"  // IWYU pragma: keep
24 
25 #ifdef GRPC_HAVE_VSOCK
26 #include <linux/vm_sockets.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #ifdef GRPC_HAVE_UNIX_SOCKET
33 #ifdef GPR_WINDOWS
34 // clang-format off
35 #include <ws2def.h>
36 #include <afunix.h>
37 // clang-format on
38 #else
39 #include <sys/un.h>
40 #endif  // GPR_WINDOWS
41 #endif  // GRPC_HAVE_UNIX_SOCKET
42 #include <string>
43 
44 #include "absl/log/check.h"
45 #include "absl/log/log.h"
46 #include "absl/status/status.h"
47 #include "absl/strings/str_cat.h"
48 #include "absl/strings/strip.h"
49 #include "src/core/lib/iomgr/sockaddr.h"
50 #include "src/core/lib/iomgr/socket_utils.h"
51 #include "src/core/util/grpc_if_nametoindex.h"
52 #include "src/core/util/host_port.h"
53 #include "src/core/util/status_helper.h"
54 #include "src/core/util/string.h"
55 
56 // IWYU pragma: no_include <arpa/inet.h>
57 
58 #ifdef GRPC_HAVE_UNIX_SOCKET
59 
grpc_parse_unix(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)60 bool grpc_parse_unix(const grpc_core::URI& uri,
61                      grpc_resolved_address* resolved_addr) {
62   if (uri.scheme() != "unix") {
63     LOG(ERROR) << "Expected 'unix' scheme, got '" << uri.scheme() << "'";
64     return false;
65   }
66   grpc_error_handle error =
67       grpc_core::UnixSockaddrPopulate(uri.path(), resolved_addr);
68   if (!error.ok()) {
69     LOG(ERROR) << "" << grpc_core::StatusToString(error);
70     return false;
71   }
72   return true;
73 }
74 
grpc_parse_unix_abstract(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)75 bool grpc_parse_unix_abstract(const grpc_core::URI& uri,
76                               grpc_resolved_address* resolved_addr) {
77   if (uri.scheme() != "unix-abstract") {
78     LOG(ERROR) << "Expected 'unix-abstract' scheme, got '" << uri.scheme()
79                << "'";
80     return false;
81   }
82   grpc_error_handle error =
83       grpc_core::UnixAbstractSockaddrPopulate(uri.path(), resolved_addr);
84   if (!error.ok()) {
85     LOG(ERROR) << "" << grpc_core::StatusToString(error);
86     return false;
87   }
88   return true;
89 }
90 
91 namespace grpc_core {
92 
UnixSockaddrPopulate(absl::string_view path,grpc_resolved_address * resolved_addr)93 grpc_error_handle UnixSockaddrPopulate(absl::string_view path,
94                                        grpc_resolved_address* resolved_addr) {
95   memset(resolved_addr, 0, sizeof(*resolved_addr));
96   struct sockaddr_un* un =
97       reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
98   const size_t maxlen = sizeof(un->sun_path) - 1;
99   if (path.size() > maxlen) {
100     return GRPC_ERROR_CREATE(absl::StrCat(
101         "Path name should not have more than ", maxlen, " characters"));
102   }
103   un->sun_family = AF_UNIX;
104   path.copy(un->sun_path, path.size());
105   un->sun_path[path.size()] = '\0';
106   resolved_addr->len = static_cast<socklen_t>(sizeof(*un));
107   return absl::OkStatus();
108 }
109 
UnixAbstractSockaddrPopulate(absl::string_view path,grpc_resolved_address * resolved_addr)110 grpc_error_handle UnixAbstractSockaddrPopulate(
111     absl::string_view path, grpc_resolved_address* resolved_addr) {
112   memset(resolved_addr, 0, sizeof(*resolved_addr));
113   struct sockaddr_un* un =
114       reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
115   const size_t maxlen = sizeof(un->sun_path) - 1;
116   if (path.size() > maxlen) {
117     return GRPC_ERROR_CREATE(absl::StrCat(
118         "Path name should not have more than ", maxlen, " characters"));
119   }
120   un->sun_family = AF_UNIX;
121   un->sun_path[0] = '\0';
122   path.copy(un->sun_path + 1, path.size());
123   resolved_addr->len =
124       static_cast<socklen_t>(sizeof(un->sun_family) + path.size() + 1);
125   return absl::OkStatus();
126 }
127 
128 }  // namespace grpc_core
129 
130 #else   // GRPC_HAVE_UNIX_SOCKET
131 
grpc_parse_unix(const grpc_core::URI &,grpc_resolved_address *)132 bool grpc_parse_unix(const grpc_core::URI& /* uri */,
133                      grpc_resolved_address* /* resolved_addr */) {
134   abort();
135 }
136 
grpc_parse_unix_abstract(const grpc_core::URI &,grpc_resolved_address *)137 bool grpc_parse_unix_abstract(const grpc_core::URI& /* uri */,
138                               grpc_resolved_address* /* resolved_addr */) {
139   abort();
140 }
141 
142 namespace grpc_core {
143 
UnixSockaddrPopulate(absl::string_view,grpc_resolved_address *)144 grpc_error_handle UnixSockaddrPopulate(
145     absl::string_view /* path */, grpc_resolved_address* /* resolved_addr */) {
146   abort();
147 }
148 
UnixAbstractSockaddrPopulate(absl::string_view,grpc_resolved_address *)149 grpc_error_handle UnixAbstractSockaddrPopulate(
150     absl::string_view /* path */, grpc_resolved_address* /* resolved_addr */) {
151   abort();
152 }
153 
154 }  // namespace grpc_core
155 #endif  // GRPC_HAVE_UNIX_SOCKET
156 
157 #ifdef GRPC_HAVE_VSOCK
158 
grpc_parse_vsock(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)159 bool grpc_parse_vsock(const grpc_core::URI& uri,
160                       grpc_resolved_address* resolved_addr) {
161   if (uri.scheme() != "vsock") {
162     LOG(ERROR) << "Expected 'vsock' scheme, got '" << uri.scheme() << "'";
163     return false;
164   }
165   grpc_error_handle error =
166       grpc_core::VSockaddrPopulate(uri.path(), resolved_addr);
167   if (!error.ok()) {
168     LOG(ERROR) << "" << grpc_core::StatusToString(error);
169     return false;
170   }
171   return true;
172 }
173 
174 namespace grpc_core {
175 
VSockaddrPopulate(absl::string_view path,grpc_resolved_address * resolved_addr)176 grpc_error_handle VSockaddrPopulate(absl::string_view path,
177                                     grpc_resolved_address* resolved_addr) {
178   memset(resolved_addr, 0, sizeof(*resolved_addr));
179   struct sockaddr_vm* vm =
180       reinterpret_cast<struct sockaddr_vm*>(resolved_addr->addr);
181   vm->svm_family = AF_VSOCK;
182   std::string s = std::string(path);
183   if (sscanf(s.c_str(), "%u:%u", &vm->svm_cid, &vm->svm_port) != 2) {
184     return GRPC_ERROR_CREATE(
185         absl::StrCat("Failed to parse vsock cid/port: ", s));
186   }
187   resolved_addr->len = static_cast<socklen_t>(sizeof(*vm));
188   return absl::OkStatus();
189 }
190 
191 }  // namespace grpc_core
192 
193 #else   // GRPC_HAVE_VSOCK
194 
grpc_parse_vsock(const grpc_core::URI &,grpc_resolved_address *)195 bool grpc_parse_vsock(const grpc_core::URI& /* uri */,
196                       grpc_resolved_address* /* resolved_addr */) {
197   GPR_UNREACHABLE_CODE(return false);
198 }
199 
200 namespace grpc_core {
201 
VSockaddrPopulate(absl::string_view,grpc_resolved_address *)202 grpc_error_handle VSockaddrPopulate(
203     absl::string_view /* path */, grpc_resolved_address* /* resolved_addr */) {
204   GPR_UNREACHABLE_CODE(return absl::InvalidArgumentError("vsock unsupported."));
205 }
206 
207 }  // namespace grpc_core
208 #endif  // GRPC_HAVE_VSOCK
209 
grpc_parse_ipv4_hostport(absl::string_view hostport,grpc_resolved_address * addr,bool log_errors)210 bool grpc_parse_ipv4_hostport(absl::string_view hostport,
211                               grpc_resolved_address* addr, bool log_errors) {
212   bool success = false;
213   // Split host and port.
214   std::string host;
215   std::string port;
216   if (!grpc_core::SplitHostPort(hostport, &host, &port)) {
217     if (log_errors) {
218       LOG(ERROR) << "Failed gpr_split_host_port(" << hostport << ", ...)";
219     }
220     return false;
221   }
222   // Parse IP address.
223   memset(addr, 0, sizeof(*addr));
224   addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
225   grpc_sockaddr_in* in = reinterpret_cast<grpc_sockaddr_in*>(addr->addr);
226   in->sin_family = GRPC_AF_INET;
227   if (grpc_inet_pton(GRPC_AF_INET, host.c_str(), &in->sin_addr) == 0) {
228     if (log_errors) {
229       LOG(ERROR) << "invalid ipv4 address: '" << host << "'";
230     }
231     goto done;
232   }
233   // Parse port.
234   if (port.empty()) {
235     if (log_errors) LOG(ERROR) << "no port given for ipv4 scheme";
236     goto done;
237   }
238   int port_num;
239   if (sscanf(port.c_str(), "%d", &port_num) != 1 || port_num < 0 ||
240       port_num > 65535) {
241     if (log_errors) LOG(ERROR) << "invalid ipv4 port: '" << port << "'";
242     goto done;
243   }
244   in->sin_port = grpc_htons(static_cast<uint16_t>(port_num));
245   success = true;
246 done:
247   return success;
248 }
249 
grpc_parse_ipv4(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)250 bool grpc_parse_ipv4(const grpc_core::URI& uri,
251                      grpc_resolved_address* resolved_addr) {
252   if (uri.scheme() != "ipv4") {
253     LOG(ERROR) << "Expected 'ipv4' scheme, got '" << uri.scheme() << "'";
254     return false;
255   }
256   return grpc_parse_ipv4_hostport(absl::StripPrefix(uri.path(), "/"),
257                                   resolved_addr, true /* log_errors */);
258 }
259 
grpc_parse_ipv6_hostport(absl::string_view hostport,grpc_resolved_address * addr,bool log_errors)260 bool grpc_parse_ipv6_hostport(absl::string_view hostport,
261                               grpc_resolved_address* addr, bool log_errors) {
262   bool success = false;
263   // Split host and port.
264   std::string host;
265   std::string port;
266   if (!grpc_core::SplitHostPort(hostport, &host, &port)) {
267     if (log_errors) {
268       LOG(ERROR) << "Failed gpr_split_host_port(" << hostport << ", ...)";
269     }
270     return false;
271   }
272   // Parse IP address.
273   memset(addr, 0, sizeof(*addr));
274   addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
275   grpc_sockaddr_in6* in6 = reinterpret_cast<grpc_sockaddr_in6*>(addr->addr);
276   in6->sin6_family = GRPC_AF_INET6;
277   // Handle the RFC6874 syntax for IPv6 zone identifiers.
278   char* host_end =
279       static_cast<char*>(gpr_memrchr(host.c_str(), '%', host.size()));
280   if (host_end != nullptr) {
281     CHECK(host_end >= host.c_str());
282     char host_without_scope[GRPC_INET6_ADDRSTRLEN + 1];
283     size_t host_without_scope_len =
284         static_cast<size_t>(host_end - host.c_str());
285     uint32_t sin6_scope_id = 0;
286     if (host_without_scope_len > GRPC_INET6_ADDRSTRLEN) {
287       if (log_errors) {
288         LOG(ERROR) << "invalid ipv6 address length " << host_without_scope_len
289                    << ". Length cannot be greater than "
290                    << "GRPC_INET6_ADDRSTRLEN i.e " << GRPC_INET6_ADDRSTRLEN;
291       }
292       goto done;
293     }
294     strncpy(host_without_scope, host.c_str(), host_without_scope_len);
295     host_without_scope[host_without_scope_len] = '\0';
296     if (grpc_inet_pton(GRPC_AF_INET6, host_without_scope, &in6->sin6_addr) ==
297         0) {
298       if (log_errors) {
299         LOG(ERROR) << "invalid ipv6 address: '" << host_without_scope << "'";
300       }
301       goto done;
302     }
303     if (gpr_parse_bytes_to_uint32(host_end + 1,
304                                   host.size() - host_without_scope_len - 1,
305                                   &sin6_scope_id) == 0) {
306       if ((sin6_scope_id = grpc_if_nametoindex(host_end + 1)) == 0) {
307         LOG(ERROR) << "Invalid interface name: '" << host_end + 1
308                    << "'. Non-numeric and failed if_nametoindex.";
309         goto done;
310       }
311     }
312     // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027.
313     in6->sin6_scope_id = sin6_scope_id;
314   } else {
315     if (grpc_inet_pton(GRPC_AF_INET6, host.c_str(), &in6->sin6_addr) == 0) {
316       if (log_errors) {
317         LOG(ERROR) << "invalid ipv6 address: '" << host << "'";
318       }
319       goto done;
320     }
321   }
322   // Parse port.
323   if (port.empty()) {
324     if (log_errors) LOG(ERROR) << "no port given for ipv6 scheme";
325     goto done;
326   }
327   int port_num;
328   if (sscanf(port.c_str(), "%d", &port_num) != 1 || port_num < 0 ||
329       port_num > 65535) {
330     if (log_errors) LOG(ERROR) << "invalid ipv6 port: '" << port << "'";
331     goto done;
332   }
333   in6->sin6_port = grpc_htons(static_cast<uint16_t>(port_num));
334   success = true;
335 done:
336   return success;
337 }
338 
grpc_parse_ipv6(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)339 bool grpc_parse_ipv6(const grpc_core::URI& uri,
340                      grpc_resolved_address* resolved_addr) {
341   if (uri.scheme() != "ipv6") {
342     LOG(ERROR) << "Expected 'ipv6' scheme, got '" << uri.scheme() << "'";
343     return false;
344   }
345   return grpc_parse_ipv6_hostport(absl::StripPrefix(uri.path(), "/"),
346                                   resolved_addr, true /* log_errors */);
347 }
348 
grpc_parse_uri(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)349 bool grpc_parse_uri(const grpc_core::URI& uri,
350                     grpc_resolved_address* resolved_addr) {
351   if (uri.scheme() == "unix") {
352     return grpc_parse_unix(uri, resolved_addr);
353   }
354   if (uri.scheme() == "unix-abstract") {
355     return grpc_parse_unix_abstract(uri, resolved_addr);
356   }
357   if (uri.scheme() == "vsock") {
358     return grpc_parse_vsock(uri, resolved_addr);
359   }
360   if (uri.scheme() == "ipv4") {
361     return grpc_parse_ipv4(uri, resolved_addr);
362   }
363   if (uri.scheme() == "ipv6") {
364     return grpc_parse_ipv6(uri, resolved_addr);
365   }
366   LOG(ERROR) << "Can't parse scheme '" << uri.scheme() << "'";
367   return false;
368 }
369 
grpc_strhtons(const char * port)370 uint16_t grpc_strhtons(const char* port) {
371   if (strcmp(port, "http") == 0) {
372     return htons(80);
373   } else if (strcmp(port, "https") == 0) {
374     return htons(443);
375   }
376   return htons(static_cast<unsigned short>(atoi(port)));
377 }
378 
379 namespace grpc_core {
380 
StringToSockaddr(absl::string_view address_and_port)381 absl::StatusOr<grpc_resolved_address> StringToSockaddr(
382     absl::string_view address_and_port) {
383   grpc_resolved_address out;
384   memset(&out, 0, sizeof(grpc_resolved_address));
385   if (!grpc_parse_ipv4_hostport(address_and_port, &out, /*log_errors=*/false) &&
386       !grpc_parse_ipv6_hostport(address_and_port, &out, /*log_errors=*/false)) {
387     return absl::InvalidArgumentError(
388         absl::StrCat("Failed to parse address:", address_and_port));
389   }
390   return out;
391 }
392 
StringToSockaddr(absl::string_view address,int port)393 absl::StatusOr<grpc_resolved_address> StringToSockaddr(
394     absl::string_view address, int port) {
395   return StringToSockaddr(JoinHostPort(address, port));
396 }
397 
398 }  // namespace grpc_core
399