• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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