blob: 39b1237c77009890a0185f7570b3bdb230f79a78 [file] [log] [blame]
David Garcia Quintas9885bff2016-04-07 17:31:29 -07001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2016 gRPC authors.
David Garcia Quintas9885bff2016-04-07 17:31:29 -07004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * 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
David Garcia Quintas9885bff2016-04-07 17:31:29 -07008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
David Garcia Quintas9885bff2016-04-07 17:31:29 -070010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * 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.
David Garcia Quintas9885bff2016-04-07 17:31:29 -070016 *
17 */
18
Craig Tiller9eb0fde2017-03-31 16:59:30 -070019#include "src/core/ext/filters/client_channel/parse_address.h"
murgatroid99dedb9232016-09-26 13:54:04 -070020#include "src/core/lib/iomgr/sockaddr.h"
David Garcia Quintas9885bff2016-04-07 17:31:29 -070021
22#include <stdio.h>
23#include <string.h>
murgatroid99623dd4f2016-08-08 17:31:27 -070024#ifdef GRPC_HAVE_UNIX_SOCKET
David Garcia Quintas9885bff2016-04-07 17:31:29 -070025#include <sys/un.h>
26#endif
27
28#include <grpc/support/alloc.h>
29#include <grpc/support/host_port.h>
30#include <grpc/support/log.h>
31#include <grpc/support/string_util.h>
Yuchen Zengaa76d3d2017-02-15 14:00:01 -080032#include "src/core/lib/support/string.h"
David Garcia Quintas9885bff2016-04-07 17:31:29 -070033
murgatroid99623dd4f2016-08-08 17:31:27 -070034#ifdef GRPC_HAVE_UNIX_SOCKET
murgatroid997871f732016-09-23 13:49:05 -070035
Craig Tillerbaa14a92017-11-03 09:09:36 -070036bool grpc_parse_unix(const grpc_uri* uri,
37 grpc_resolved_address* resolved_addr) {
David Garcia Quintas53af23c2017-04-15 10:29:46 -070038 if (strcmp("unix", uri->scheme) != 0) {
39 gpr_log(GPR_ERROR, "Expected 'unix' scheme, got '%s'", uri->scheme);
40 return false;
41 }
Craig Tillerbaa14a92017-11-03 09:09:36 -070042 struct sockaddr_un* un = (struct sockaddr_un*)resolved_addr->addr;
David Garcia Quintase2869fe2017-02-23 09:11:24 -080043 const size_t maxlen = sizeof(un->sun_path);
44 const size_t path_len = strnlen(uri->path, maxlen);
Mark D. Roth96fc54c2017-05-18 14:33:07 -070045 if (path_len == maxlen) return false;
David Garcia Quintas9885bff2016-04-07 17:31:29 -070046 un->sun_family = AF_UNIX;
David Garcia Quintase2869fe2017-02-23 09:11:24 -080047 strcpy(un->sun_path, uri->path);
David Garcia Quintasd9314ad2017-02-23 09:54:55 -080048 resolved_addr->len = sizeof(*un);
Mark D. Roth96fc54c2017-05-18 14:33:07 -070049 return true;
David Garcia Quintas9885bff2016-04-07 17:31:29 -070050}
David Garcia Quintas9885bff2016-04-07 17:31:29 -070051
murgatroid997871f732016-09-23 13:49:05 -070052#else /* GRPC_HAVE_UNIX_SOCKET */
53
Craig Tillerbaa14a92017-11-03 09:09:36 -070054bool grpc_parse_unix(const grpc_uri* uri,
55 grpc_resolved_address* resolved_addr) {
David Garcia Quintas53af23c2017-04-15 10:29:46 -070056 abort();
57}
murgatroid997871f732016-09-23 13:49:05 -070058
59#endif /* GRPC_HAVE_UNIX_SOCKET */
60
Craig Tillerbaa14a92017-11-03 09:09:36 -070061bool grpc_parse_ipv4_hostport(const char* hostport, grpc_resolved_address* addr,
Mark D. Roth96fc54c2017-05-18 14:33:07 -070062 bool log_errors) {
63 bool success = false;
64 // Split host and port.
Craig Tillerbaa14a92017-11-03 09:09:36 -070065 char* host;
66 char* port;
Mark D. Roth96fc54c2017-05-18 14:33:07 -070067 if (!gpr_split_host_port(hostport, &host, &port)) return false;
68 // Parse IP address.
69 memset(addr, 0, sizeof(*addr));
70 addr->len = sizeof(struct sockaddr_in);
Craig Tillerbaa14a92017-11-03 09:09:36 -070071 struct sockaddr_in* in = (struct sockaddr_in*)addr->addr;
Mark D. Roth96fc54c2017-05-18 14:33:07 -070072 in->sin_family = AF_INET;
73 if (inet_pton(AF_INET, host, &in->sin_addr) == 0) {
74 if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 address: '%s'", host);
75 goto done;
76 }
77 // Parse port.
Craig Tiller4782d922017-11-10 09:53:21 -080078 if (port == nullptr) {
Mark D. Roth96fc54c2017-05-18 14:33:07 -070079 if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv4 scheme");
80 goto done;
81 }
82 int port_num;
83 if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || port_num > 65535) {
84 if (log_errors) gpr_log(GPR_ERROR, "invalid ipv4 port: '%s'", port);
85 goto done;
86 }
87 in->sin_port = htons((uint16_t)port_num);
88 success = true;
89done:
90 gpr_free(host);
91 gpr_free(port);
92 return success;
93}
94
Craig Tillerbaa14a92017-11-03 09:09:36 -070095bool grpc_parse_ipv4(const grpc_uri* uri,
96 grpc_resolved_address* resolved_addr) {
David Garcia Quintas53af23c2017-04-15 10:29:46 -070097 if (strcmp("ipv4", uri->scheme) != 0) {
98 gpr_log(GPR_ERROR, "Expected 'ipv4' scheme, got '%s'", uri->scheme);
99 return false;
100 }
Craig Tillerbaa14a92017-11-03 09:09:36 -0700101 const char* host_port = uri->path;
David Garcia Quintas9885bff2016-04-07 17:31:29 -0700102 if (*host_port == '/') ++host_port;
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700103 return grpc_parse_ipv4_hostport(host_port, resolved_addr,
104 true /* log_errors */);
David Garcia Quintas9885bff2016-04-07 17:31:29 -0700105}
106
Craig Tillerbaa14a92017-11-03 09:09:36 -0700107bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr,
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700108 bool log_errors) {
109 bool success = false;
110 // Split host and port.
Craig Tillerbaa14a92017-11-03 09:09:36 -0700111 char* host;
112 char* port;
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700113 if (!gpr_split_host_port(hostport, &host, &port)) return false;
114 // Parse IP address.
115 memset(addr, 0, sizeof(*addr));
116 addr->len = sizeof(struct sockaddr_in6);
Craig Tillerbaa14a92017-11-03 09:09:36 -0700117 struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr->addr;
David Garcia Quintas9885bff2016-04-07 17:31:29 -0700118 in6->sin6_family = AF_INET6;
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700119 // Handle the RFC6874 syntax for IPv6 zone identifiers.
Craig Tillerbaa14a92017-11-03 09:09:36 -0700120 char* host_end = (char*)gpr_memrchr(host, '%', strlen(host));
Craig Tiller4782d922017-11-10 09:53:21 -0800121 if (host_end != nullptr) {
Yuchen Zengc40d1d82017-02-15 20:42:06 -0800122 GPR_ASSERT(host_end >= host);
123 char host_without_scope[INET6_ADDRSTRLEN];
Yuchen Zengaa76d3d2017-02-15 14:00:01 -0800124 size_t host_without_scope_len = (size_t)(host_end - host);
Alexander Polcyn648229e2017-03-09 14:18:27 -0800125 uint32_t sin6_scope_id = 0;
Yuchen Zengaa76d3d2017-02-15 14:00:01 -0800126 strncpy(host_without_scope, host, host_without_scope_len);
127 host_without_scope[host_without_scope_len] = '\0';
128 if (inet_pton(AF_INET6, host_without_scope, &in6->sin6_addr) == 0) {
129 gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host_without_scope);
130 goto done;
131 }
132 if (gpr_parse_bytes_to_uint32(host_end + 1,
133 strlen(host) - host_without_scope_len - 1,
Alexander Polcyn648229e2017-03-09 14:18:27 -0800134 &sin6_scope_id) == 0) {
Yuchen Zengaa76d3d2017-02-15 14:00:01 -0800135 gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1);
136 goto done;
137 }
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700138 // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027.
Alexander Polcyn648229e2017-03-09 14:18:27 -0800139 in6->sin6_scope_id = sin6_scope_id;
Yuchen Zengaa76d3d2017-02-15 14:00:01 -0800140 } else {
141 if (inet_pton(AF_INET6, host, &in6->sin6_addr) == 0) {
142 gpr_log(GPR_ERROR, "invalid ipv6 address: '%s'", host);
143 goto done;
144 }
David Garcia Quintas9885bff2016-04-07 17:31:29 -0700145 }
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700146 // Parse port.
Craig Tiller4782d922017-11-10 09:53:21 -0800147 if (port == nullptr) {
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700148 if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv6 scheme");
David Garcia Quintas9885bff2016-04-07 17:31:29 -0700149 goto done;
150 }
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700151 int port_num;
152 if (sscanf(port, "%d", &port_num) != 1 || port_num < 0 || port_num > 65535) {
153 if (log_errors) gpr_log(GPR_ERROR, "invalid ipv6 port: '%s'", port);
154 goto done;
155 }
156 in6->sin6_port = htons((uint16_t)port_num);
157 success = true;
David Garcia Quintas9885bff2016-04-07 17:31:29 -0700158done:
159 gpr_free(host);
160 gpr_free(port);
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700161 return success;
162}
163
Craig Tillerbaa14a92017-11-03 09:09:36 -0700164bool grpc_parse_ipv6(const grpc_uri* uri,
165 grpc_resolved_address* resolved_addr) {
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700166 if (strcmp("ipv6", uri->scheme) != 0) {
167 gpr_log(GPR_ERROR, "Expected 'ipv6' scheme, got '%s'", uri->scheme);
168 return false;
169 }
Craig Tillerbaa14a92017-11-03 09:09:36 -0700170 const char* host_port = uri->path;
Mark D. Roth96fc54c2017-05-18 14:33:07 -0700171 if (*host_port == '/') ++host_port;
172 return grpc_parse_ipv6_hostport(host_port, resolved_addr,
173 true /* log_errors */);
David Garcia Quintas9885bff2016-04-07 17:31:29 -0700174}
David Garcia Quintas53af23c2017-04-15 10:29:46 -0700175
Craig Tillerbaa14a92017-11-03 09:09:36 -0700176bool grpc_parse_uri(const grpc_uri* uri, grpc_resolved_address* resolved_addr) {
David Garcia Quintas53af23c2017-04-15 10:29:46 -0700177 if (strcmp("unix", uri->scheme) == 0) {
178 return grpc_parse_unix(uri, resolved_addr);
179 } else if (strcmp("ipv4", uri->scheme) == 0) {
180 return grpc_parse_ipv4(uri, resolved_addr);
181 } else if (strcmp("ipv6", uri->scheme) == 0) {
182 return grpc_parse_ipv6(uri, resolved_addr);
183 }
184 gpr_log(GPR_ERROR, "Can't parse scheme '%s'", uri->scheme);
185 return false;
186}