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 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 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 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 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 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 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 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 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