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