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