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/iomgr/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
grpc_parse_unix(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)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* error =
56 grpc_core::UnixSockaddrPopulate(uri.path(), resolved_addr);
57 if (error != GRPC_ERROR_NONE) {
58 gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
59 GRPC_ERROR_UNREF(error);
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* error =
73 grpc_core::UnixAbstractSockaddrPopulate(uri.path(), resolved_addr);
74 if (error != GRPC_ERROR_NONE) {
75 gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
76 GRPC_ERROR_UNREF(error);
77 return false;
78 }
79 return true;
80 }
81
82 namespace grpc_core {
83
UnixSockaddrPopulate(absl::string_view path,grpc_resolved_address * resolved_addr)84 grpc_error* 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
UnixAbstractSockaddrPopulate(absl::string_view path,grpc_resolved_address * resolved_addr)102 grpc_error* UnixAbstractSockaddrPopulate(absl::string_view path,
103 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
grpc_parse_unix(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)125 bool grpc_parse_unix(const grpc_core::URI& uri,
126 grpc_resolved_address* resolved_addr) {
127 abort();
128 }
129
grpc_parse_unix_abstract(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)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
UnixSockaddrPopulate(absl::string_view path,grpc_resolved_address * resolved_addr)137 grpc_error* UnixSockaddrPopulate(absl::string_view path,
138 grpc_resolved_address* resolved_addr) {
139 abort();
140 }
141
UnixAbstractSockaddrPopulate(absl::string_view path,grpc_resolved_address * resolved_addr)142 grpc_error* UnixAbstractSockaddrPopulate(absl::string_view path,
143 grpc_resolved_address* resolved_addr) {
144 abort();
145 }
146
147 } // namespace grpc_core
148 #endif /* GRPC_HAVE_UNIX_SOCKET */
149
grpc_parse_ipv4_hostport(absl::string_view hostport,grpc_resolved_address * addr,bool log_errors)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
grpc_parse_ipv4(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)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
grpc_parse_ipv6_hostport(absl::string_view hostport,grpc_resolved_address * addr,bool log_errors)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
grpc_parse_ipv6(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)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
grpc_parse_uri(const grpc_core::URI & uri,grpc_resolved_address * resolved_addr)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
grpc_strhtons(const char * port)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 }
323