98dd1bcb87ffe8af0de1b36be43f855de0cd9f31
[platform/upstream/grpc.git] / src / core / lib / address_utils / parse_address.cc
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 <string.h>
25 #ifdef GRPC_HAVE_UNIX_SOCKET
26 #include <sys/un.h>
27 #endif
28 #ifdef GRPC_POSIX_SOCKET
29 #include <errno.h>
30 #include <net/if.h>
31 #endif
32
33 #include "absl/strings/str_cat.h"
34 #include "absl/strings/strip.h"
35
36 #include <grpc/support/alloc.h>
37 #include <grpc/support/log.h>
38 #include <grpc/support/string_util.h>
39
40 #include "src/core/lib/gpr/string.h"
41 #include "src/core/lib/gprpp/host_port.h"
42 #include "src/core/lib/iomgr/grpc_if_nametoindex.h"
43 #include "src/core/lib/iomgr/sockaddr.h"
44 #include "src/core/lib/iomgr/socket_utils.h"
45
46 #ifdef GRPC_HAVE_UNIX_SOCKET
47
48 bool grpc_parse_unix(const grpc_core::URI& uri,
49                      grpc_resolved_address* resolved_addr) {
50   if (uri.scheme() != "unix") {
51     gpr_log(GPR_ERROR, "Expected 'unix' scheme, got '%s'",
52             uri.scheme().c_str());
53     return false;
54   }
55   grpc_error_handle error =
56       grpc_core::UnixSockaddrPopulate(uri.path(), resolved_addr);
57   if (error != GRPC_ERROR_NONE) {
58     gpr_log(GPR_ERROR, "%s", grpc_error_std_string(error).c_str());
59     GRPC_ERROR_UNREF(error);
60     return false;
61   }
62   return true;
63 }
64
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 != GRPC_ERROR_NONE) {
75     gpr_log(GPR_ERROR, "%s", grpc_error_std_string(error).c_str());
76     GRPC_ERROR_UNREF(error);
77     return false;
78   }
79   return true;
80 }
81
82 namespace grpc_core {
83
84 grpc_error_handle UnixSockaddrPopulate(absl::string_view path,
85                                        grpc_resolved_address* 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_FROM_COPIED_STRING(
91         absl::StrCat("Path name should not have more than ", maxlen,
92                      " characters")
93             .c_str());
94   }
95   un->sun_family = AF_UNIX;
96   path.copy(un->sun_path, path.size());
97   un->sun_path[path.size()] = '\0';
98   resolved_addr->len = static_cast<socklen_t>(sizeof(*un));
99   return GRPC_ERROR_NONE;
100 }
101
102 grpc_error_handle UnixAbstractSockaddrPopulate(
103     absl::string_view path, grpc_resolved_address* resolved_addr) {
104   struct sockaddr_un* un =
105       reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
106   const size_t maxlen = sizeof(un->sun_path) - 1;
107   if (path.size() > maxlen) {
108     return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
109         absl::StrCat("Path name should not have more than ", maxlen,
110                      " characters")
111             .c_str());
112   }
113   un->sun_family = AF_UNIX;
114   un->sun_path[0] = '\0';
115   path.copy(un->sun_path + 1, path.size());
116   resolved_addr->len =
117       static_cast<socklen_t>(sizeof(un->sun_family) + path.size() + 1);
118   return GRPC_ERROR_NONE;
119 }
120
121 }  // namespace grpc_core
122
123 #else  /* GRPC_HAVE_UNIX_SOCKET */
124
125 bool grpc_parse_unix(const grpc_core::URI& /* uri */,
126                      grpc_resolved_address* /* resolved_addr */) {
127   abort();
128 }
129
130 bool grpc_parse_unix_abstract(const grpc_core::URI& /* uri */,
131                               grpc_resolved_address* /* resolved_addr */) {
132   abort();
133 }
134
135 namespace grpc_core {
136
137 grpc_error_handle UnixSockaddrPopulate(
138     absl::string_view /* path */, grpc_resolved_address* /* resolved_addr */) {
139   abort();
140 }
141
142 grpc_error_handle UnixAbstractSockaddrPopulate(
143     absl::string_view /* path */, grpc_resolved_address* /* resolved_addr */) {
144   abort();
145 }
146
147 }  // namespace grpc_core
148 #endif /* GRPC_HAVE_UNIX_SOCKET */
149
150 bool grpc_parse_ipv4_hostport(absl::string_view hostport,
151                               grpc_resolved_address* addr, bool log_errors) {
152   bool success = false;
153   // Split host and port.
154   std::string host;
155   std::string port;
156   if (!grpc_core::SplitHostPort(hostport, &host, &port)) {
157     if (log_errors) {
158       gpr_log(GPR_ERROR, "Failed gpr_split_host_port(%s, ...)",
159               std::string(hostport).c_str());
160     }
161     return false;
162   }
163   // Parse IP address.
164   memset(addr, 0, sizeof(*addr));
165   addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
166   grpc_sockaddr_in* in = reinterpret_cast<grpc_sockaddr_in*>(addr->addr);
167   in->sin_family = GRPC_AF_INET;
168   if (grpc_inet_pton(GRPC_AF_INET, host.c_str(), &in->sin_addr) == 0) {
169     if (log_errors) {
170       gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host.c_str());
171     }
172     goto done;
173   }
174   // Parse port.
175   if (port.empty()) {
176     if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv4 scheme");
177     goto done;
178   }
179   int port_num;
180   if (sscanf(port.c_str(), "%d", &port_num) != 1 || port_num < 0 ||
181       port_num > 65535) {
182     if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port.c_str());
183     goto done;
184   }
185   in->sin_port = grpc_htons(static_cast<uint16_t>(port_num));
186   success = true;
187 done:
188   return success;
189 }
190
191 bool grpc_parse_ipv4(const grpc_core::URI& uri,
192                      grpc_resolved_address* resolved_addr) {
193   if (uri.scheme() != "ipv4") {
194     gpr_log(GPR_ERROR, "Expected 'ipv4' scheme, got '%s'",
195             uri.scheme().c_str());
196     return false;
197   }
198   return grpc_parse_ipv4_hostport(absl::StripPrefix(uri.path(), "/"),
199                                   resolved_addr, true /* log_errors */);
200 }
201
202 bool grpc_parse_ipv6_hostport(absl::string_view hostport,
203                               grpc_resolved_address* addr, bool log_errors) {
204   bool success = false;
205   // Split host and port.
206   std::string host;
207   std::string port;
208   if (!grpc_core::SplitHostPort(hostport, &host, &port)) {
209     if (log_errors) {
210       gpr_log(GPR_ERROR, "Failed gpr_split_host_port(%s, ...)",
211               std::string(hostport).c_str());
212     }
213     return false;
214   }
215   // Parse IP address.
216   memset(addr, 0, sizeof(*addr));
217   addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
218   grpc_sockaddr_in6* in6 = reinterpret_cast<grpc_sockaddr_in6*>(addr->addr);
219   in6->sin6_family = GRPC_AF_INET6;
220   // Handle the RFC6874 syntax for IPv6 zone identifiers.
221   char* host_end =
222       static_cast<char*>(gpr_memrchr(host.c_str(), '%', host.size()));
223   if (host_end != nullptr) {
224     GPR_ASSERT(host_end >= host.c_str());
225     char host_without_scope[GRPC_INET6_ADDRSTRLEN + 1];
226     size_t host_without_scope_len =
227         static_cast<size_t>(host_end - host.c_str());
228     uint32_t sin6_scope_id = 0;
229     if (host_without_scope_len > GRPC_INET6_ADDRSTRLEN) {
230       if (log_errors) {
231         gpr_log(
232             GPR_ERROR,
233             "invalid ipv6 address length %zu. Length cannot be greater than "
234             "GRPC_INET6_ADDRSTRLEN i.e %d)",
235             host_without_scope_len, GRPC_INET6_ADDRSTRLEN);
236       }
237       goto done;
238     }
239     strncpy(host_without_scope, host.c_str(), host_without_scope_len);
240     host_without_scope[host_without_scope_len] = '\0';
241     if (grpc_inet_pton(GRPC_AF_INET6, host_without_scope, &in6->sin6_addr) ==
242         0) {
243       if (log_errors) {
244         gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
245       }
246       goto done;
247     }
248     if (gpr_parse_bytes_to_uint32(host_end + 1,
249                                   host.size() - host_without_scope_len - 1,
250                                   &sin6_scope_id) == 0) {
251       if ((sin6_scope_id = grpc_if_nametoindex(host_end + 1)) == 0) {
252         gpr_log(GPR_ERROR,
253                 "Invalid interface name: '%s'. "
254                 "Non-numeric and failed if_nametoindex.",
255                 host_end + 1);
256         goto done;
257       }
258     }
259     // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027.
260     in6->sin6_scope_id = sin6_scope_id;
261   } else {
262     if (grpc_inet_pton(GRPC_AF_INET6, host.c_str(), &in6->sin6_addr) == 0) {
263       if (log_errors) {
264         gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host.c_str());
265       }
266       goto done;
267     }
268   }
269   // Parse port.
270   if (port.empty()) {
271     if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv6 scheme");
272     goto done;
273   }
274   int port_num;
275   if (sscanf(port.c_str(), "%d", &port_num) != 1 || port_num < 0 ||
276       port_num > 65535) {
277     if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port.c_str());
278     goto done;
279   }
280   in6->sin6_port = grpc_htons(static_cast<uint16_t>(port_num));
281   success = true;
282 done:
283   return success;
284 }
285
286 bool grpc_parse_ipv6(const grpc_core::URI& uri,
287                      grpc_resolved_address* resolved_addr) {
288   if (uri.scheme() != "ipv6") {
289     gpr_log(GPR_ERROR, "Expected 'ipv6' scheme, got '%s'",
290             uri.scheme().c_str());
291     return false;
292   }
293   return grpc_parse_ipv6_hostport(absl::StripPrefix(uri.path(), "/"),
294                                   resolved_addr, true /* log_errors */);
295 }
296
297 bool grpc_parse_uri(const grpc_core::URI& uri,
298                     grpc_resolved_address* resolved_addr) {
299   if (uri.scheme() == "unix") {
300     return grpc_parse_unix(uri, resolved_addr);
301   }
302   if (uri.scheme() == "unix-abstract") {
303     return grpc_parse_unix_abstract(uri, resolved_addr);
304   }
305   if (uri.scheme() == "ipv4") {
306     return grpc_parse_ipv4(uri, resolved_addr);
307   }
308   if (uri.scheme() == "ipv6") {
309     return grpc_parse_ipv6(uri, resolved_addr);
310   }
311   gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri.scheme().c_str());
312   return false;
313 }
314
315 uint16_t grpc_strhtons(const char* port) {
316   if (strcmp(port, "http") == 0) {
317     return htons(80);
318   } else if (strcmp(port, "https") == 0) {
319     return htons(443);
320   }
321   return htons(static_cast<unsigned short>(atoi(port)));
322 }