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/ext/filters/client_channel/parse_address.h"
22 #include "src/core/lib/iomgr/sockaddr.h"
23 #include "src/core/lib/iomgr/socket_utils.h"
24
25 #include <stdio.h>
26 #include <string.h>
27 #ifdef GRPC_HAVE_UNIX_SOCKET
28 #include <sys/un.h>
29 #endif
30
31 #include <grpc/support/alloc.h>
32 #include <grpc/support/log.h>
33 #include <grpc/support/string_util.h>
34
35 #include "src/core/lib/gpr/host_port.h"
36 #include "src/core/lib/gpr/string.h"
37
38 #ifdef GRPC_HAVE_UNIX_SOCKET
39
grpc_parse_unix(const grpc_uri * uri,grpc_resolved_address * resolved_addr)40 bool grpc_parse_unix(const grpc_uri* uri,
41 grpc_resolved_address* resolved_addr) {
42 if (strcmp("unix", uri->scheme) != 0) {
43 gpr_log(GPR_ERROR, "Expected 'unix' scheme, got '%s'", uri->scheme);
44 return false;
45 }
46 struct sockaddr_un* un =
47 reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
48 const size_t maxlen = sizeof(un->sun_path);
49 const size_t path_len = strnlen(uri->path, maxlen);
50 if (path_len == maxlen) return false;
51 un->sun_family = AF_UNIX;
52 strcpy(un->sun_path, uri->path);
53 resolved_addr->len = static_cast<socklen_t>(sizeof(*un));
54 return true;
55 }
56
57 #else /* GRPC_HAVE_UNIX_SOCKET */
58
grpc_parse_unix(const grpc_uri * uri,grpc_resolved_address * resolved_addr)59 bool grpc_parse_unix(const grpc_uri* uri,
60 grpc_resolved_address* resolved_addr) {
61 abort();
62 }
63
64 #endif /* GRPC_HAVE_UNIX_SOCKET */
65
grpc_parse_ipv4_hostport(const char * hostport,grpc_resolved_address * addr,bool log_errors)66 bool grpc_parse_ipv4_hostport(const char* hostport, grpc_resolved_address* addr,
67 bool log_errors) {
68 bool success = false;
69 // Split host and port.
70 char* host;
71 char* port;
72 if (!gpr_split_host_port(hostport, &host, &port)) return false;
73 // Parse IP address.
74 memset(addr, 0, sizeof(*addr));
75 addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in));
76 grpc_sockaddr_in* in = reinterpret_cast<grpc_sockaddr_in*>(addr->addr);
77 in->sin_family = GRPC_AF_INET;
78 if (grpc_inet_pton(GRPC_AF_INET, host, &in->sin_addr) == 0) {
79 if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host);
80 goto done;
81 }
82 // Parse port.
83 if (port == nullptr) {
84 if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv4 scheme");
85 goto done;
86 }
87 int port_num;
88 if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || port_num > 65535) {
89 if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port);
90 goto done;
91 }
92 in->sin_port = grpc_htons(static_cast<uint16_t>(port_num));
93 success = true;
94 done:
95 gpr_free(host);
96 gpr_free(port);
97 return success;
98 }
99
grpc_parse_ipv4(const grpc_uri * uri,grpc_resolved_address * resolved_addr)100 bool grpc_parse_ipv4(const grpc_uri* uri,
101 grpc_resolved_address* resolved_addr) {
102 if (strcmp("ipv4", uri->scheme) != 0) {
103 gpr_log(GPR_ERROR, "Expected 'ipv4' scheme, got '%s'", uri->scheme);
104 return false;
105 }
106 const char* host_port = uri->path;
107 if (*host_port == '/') ++host_port;
108 return grpc_parse_ipv4_hostport(host_port, resolved_addr,
109 true /* log_errors */);
110 }
111
grpc_parse_ipv6_hostport(const char * hostport,grpc_resolved_address * addr,bool log_errors)112 bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr,
113 bool log_errors) {
114 bool success = false;
115 // Split host and port.
116 char* host;
117 char* port;
118 if (!gpr_split_host_port(hostport, &host, &port)) return false;
119 // Parse IP address.
120 memset(addr, 0, sizeof(*addr));
121 addr->len = static_cast<socklen_t>(sizeof(grpc_sockaddr_in6));
122 grpc_sockaddr_in6* in6 = reinterpret_cast<grpc_sockaddr_in6*>(addr->addr);
123 in6->sin6_family = GRPC_AF_INET6;
124 // Handle the RFC6874 syntax for IPv6 zone identifiers.
125 char* host_end = static_cast<char*>(gpr_memrchr(host, '%', strlen(host)));
126 if (host_end != nullptr) {
127 GPR_ASSERT(host_end >= host);
128 char host_without_scope[GRPC_INET6_ADDRSTRLEN + 1];
129 size_t host_without_scope_len = static_cast<size_t>(host_end - host);
130 uint32_t sin6_scope_id = 0;
131 if (host_without_scope_len > GRPC_INET6_ADDRSTRLEN) {
132 if (log_errors) {
133 gpr_log(
134 GPR_ERROR,
135 "invalid ipv6 address length %zu. Length cannot be greater than "
136 "GRPC_INET6_ADDRSTRLEN i.e %d)",
137 host_without_scope_len, GRPC_INET6_ADDRSTRLEN);
138 }
139 goto done;
140 }
141 strncpy(host_without_scope, host, host_without_scope_len);
142 host_without_scope[host_without_scope_len] = '\0';
143 if (grpc_inet_pton(GRPC_AF_INET6, host_without_scope, &in6->sin6_addr) ==
144 0) {
145 if (log_errors) {
146 gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
147 }
148 goto done;
149 }
150 if (gpr_parse_bytes_to_uint32(host_end + 1,
151 strlen(host) - host_without_scope_len - 1,
152 &sin6_scope_id) == 0) {
153 if (log_errors) {
154 gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1);
155 }
156 goto done;
157 }
158 // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027.
159 in6->sin6_scope_id = sin6_scope_id;
160 } else {
161 if (grpc_inet_pton(GRPC_AF_INET6, host, &in6->sin6_addr) == 0) {
162 if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
163 goto done;
164 }
165 }
166 // Parse port.
167 if (port == nullptr) {
168 if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv6 scheme");
169 goto done;
170 }
171 int port_num;
172 if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || port_num > 65535) {
173 if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port);
174 goto done;
175 }
176 in6->sin6_port = grpc_htons(static_cast<uint16_t>(port_num));
177 success = true;
178 done:
179 gpr_free(host);
180 gpr_free(port);
181 return success;
182 }
183
grpc_parse_ipv6(const grpc_uri * uri,grpc_resolved_address * resolved_addr)184 bool grpc_parse_ipv6(const grpc_uri* uri,
185 grpc_resolved_address* resolved_addr) {
186 if (strcmp("ipv6", uri->scheme) != 0) {
187 gpr_log(GPR_ERROR, "Expected 'ipv6' scheme, got '%s'", uri->scheme);
188 return false;
189 }
190 const char* host_port = uri->path;
191 if (*host_port == '/') ++host_port;
192 return grpc_parse_ipv6_hostport(host_port, resolved_addr,
193 true /* log_errors */);
194 }
195
grpc_parse_uri(const grpc_uri * uri,grpc_resolved_address * resolved_addr)196 bool grpc_parse_uri(const grpc_uri* uri, grpc_resolved_address* resolved_addr) {
197 if (strcmp("unix", uri->scheme) == 0) {
198 return grpc_parse_unix(uri, resolved_addr);
199 } else if (strcmp("ipv4", uri->scheme) == 0) {
200 return grpc_parse_ipv4(uri, resolved_addr);
201 } else if (strcmp("ipv6", uri->scheme) == 0) {
202 return grpc_parse_ipv6(uri, resolved_addr);
203 }
204 gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri->scheme);
205 return false;
206 }
207
grpc_strhtons(const char * port)208 uint16_t grpc_strhtons(const char* port) {
209 if (strcmp(port, "http") == 0) {
210 return htons(80);
211 } else if (strcmp(port, "https") == 0) {
212 return htons(443);
213 }
214 return htons(static_cast<unsigned short>(atoi(port)));
215 }
216