David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 1 | /* |
| 2 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 3 | * Copyright 2016 gRPC authors. |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 4 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 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 |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 8 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 10 | * |
Jan Tattermusch | 7897ae9 | 2017-06-07 22:57:36 +0200 | [diff] [blame] | 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. |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 16 | * |
| 17 | */ |
| 18 | |
Craig Tiller | 9eb0fde | 2017-03-31 16:59:30 -0700 | [diff] [blame] | 19 | #include "src/core/ext/filters/client_channel/parse_address.h" |
murgatroid99 | dedb923 | 2016-09-26 13:54:04 -0700 | [diff] [blame] | 20 | #include "src/core/lib/iomgr/sockaddr.h" |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 21 | |
| 22 | #include <stdio.h> |
| 23 | #include <string.h> |
murgatroid99 | 623dd4f | 2016-08-08 17:31:27 -0700 | [diff] [blame] | 24 | #ifdef GRPC_HAVE_UNIX_SOCKET |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 25 | #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 Zeng | aa76d3d | 2017-02-15 14:00:01 -0800 | [diff] [blame] | 32 | #include "src/core/lib/support/string.h" |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 33 | |
murgatroid99 | 623dd4f | 2016-08-08 17:31:27 -0700 | [diff] [blame] | 34 | #ifdef GRPC_HAVE_UNIX_SOCKET |
murgatroid99 | 7871f73 | 2016-09-23 13:49:05 -0700 | [diff] [blame] | 35 | |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 36 | bool grpc_parse_unix(const grpc_uri* uri, |
| 37 | grpc_resolved_address* resolved_addr) { |
David Garcia Quintas | 53af23c | 2017-04-15 10:29:46 -0700 | [diff] [blame] | 38 | if (strcmp("unix", uri->scheme) != 0) { |
| 39 | gpr_log(GPR_ERROR, "Expected 'unix' scheme, got '%s'", uri->scheme); |
| 40 | return false; |
| 41 | } |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 42 | struct sockaddr_un* un = (struct sockaddr_un*)resolved_addr->addr; |
David Garcia Quintas | e2869fe | 2017-02-23 09:11:24 -0800 | [diff] [blame] | 43 | const size_t maxlen = sizeof(un->sun_path); |
| 44 | const size_t path_len = strnlen(uri->path, maxlen); |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 45 | if (path_len == maxlen) return false; |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 46 | un->sun_family = AF_UNIX; |
David Garcia Quintas | e2869fe | 2017-02-23 09:11:24 -0800 | [diff] [blame] | 47 | strcpy(un->sun_path, uri->path); |
David Garcia Quintas | d9314ad | 2017-02-23 09:54:55 -0800 | [diff] [blame] | 48 | resolved_addr->len = sizeof(*un); |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 49 | return true; |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 50 | } |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 51 | |
murgatroid99 | 7871f73 | 2016-09-23 13:49:05 -0700 | [diff] [blame] | 52 | #else /* GRPC_HAVE_UNIX_SOCKET */ |
| 53 | |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 54 | bool grpc_parse_unix(const grpc_uri* uri, |
| 55 | grpc_resolved_address* resolved_addr) { |
David Garcia Quintas | 53af23c | 2017-04-15 10:29:46 -0700 | [diff] [blame] | 56 | abort(); |
| 57 | } |
murgatroid99 | 7871f73 | 2016-09-23 13:49:05 -0700 | [diff] [blame] | 58 | |
| 59 | #endif /* GRPC_HAVE_UNIX_SOCKET */ |
| 60 | |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 61 | bool grpc_parse_ipv4_hostport(const char* hostport, grpc_resolved_address* addr, |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 62 | bool log_errors) { |
| 63 | bool success = false; |
| 64 | // Split host and port. |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 65 | char* host; |
| 66 | char* port; |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 67 | 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 Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 71 | struct sockaddr_in* in = (struct sockaddr_in*)addr->addr; |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 72 | 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 Tiller | 4782d92 | 2017-11-10 09:53:21 -0800 | [diff] [blame] | 78 | if (port == nullptr) { |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 79 | 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; |
| 89 | done: |
| 90 | gpr_free(host); |
| 91 | gpr_free(port); |
| 92 | return success; |
| 93 | } |
| 94 | |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 95 | bool grpc_parse_ipv4(const grpc_uri* uri, |
| 96 | grpc_resolved_address* resolved_addr) { |
David Garcia Quintas | 53af23c | 2017-04-15 10:29:46 -0700 | [diff] [blame] | 97 | if (strcmp("ipv4", uri->scheme) != 0) { |
| 98 | gpr_log(GPR_ERROR, "Expected 'ipv4' scheme, got '%s'", uri->scheme); |
| 99 | return false; |
| 100 | } |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 101 | const char* host_port = uri->path; |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 102 | if (*host_port == '/') ++host_port; |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 103 | return grpc_parse_ipv4_hostport(host_port, resolved_addr, |
| 104 | true /* log_errors */); |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 105 | } |
| 106 | |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 107 | bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr, |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 108 | bool log_errors) { |
| 109 | bool success = false; |
| 110 | // Split host and port. |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 111 | char* host; |
| 112 | char* port; |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 113 | 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 Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 117 | struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr->addr; |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 118 | in6->sin6_family = AF_INET6; |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 119 | // Handle the RFC6874 syntax for IPv6 zone identifiers. |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 120 | char* host_end = (char*)gpr_memrchr(host, '%', strlen(host)); |
Craig Tiller | 4782d92 | 2017-11-10 09:53:21 -0800 | [diff] [blame] | 121 | if (host_end != nullptr) { |
Yuchen Zeng | c40d1d8 | 2017-02-15 20:42:06 -0800 | [diff] [blame] | 122 | GPR_ASSERT(host_end >= host); |
| 123 | char host_without_scope[INET6_ADDRSTRLEN]; |
Yuchen Zeng | aa76d3d | 2017-02-15 14:00:01 -0800 | [diff] [blame] | 124 | size_t host_without_scope_len = (size_t)(host_end - host); |
Alexander Polcyn | 648229e | 2017-03-09 14:18:27 -0800 | [diff] [blame] | 125 | uint32_t sin6_scope_id = 0; |
Yuchen Zeng | aa76d3d | 2017-02-15 14:00:01 -0800 | [diff] [blame] | 126 | 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 Polcyn | 648229e | 2017-03-09 14:18:27 -0800 | [diff] [blame] | 134 | &sin6_scope_id) == 0) { |
Yuchen Zeng | aa76d3d | 2017-02-15 14:00:01 -0800 | [diff] [blame] | 135 | gpr_log(GPR_ERROR, "invalid ipv6 scope id: '%s'", host_end + 1); |
| 136 | goto done; |
| 137 | } |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 138 | // Handle "sin6_scope_id" being type "u_long". See grpc issue #10027. |
Alexander Polcyn | 648229e | 2017-03-09 14:18:27 -0800 | [diff] [blame] | 139 | in6->sin6_scope_id = sin6_scope_id; |
Yuchen Zeng | aa76d3d | 2017-02-15 14:00:01 -0800 | [diff] [blame] | 140 | } 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 Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 145 | } |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 146 | // Parse port. |
Craig Tiller | 4782d92 | 2017-11-10 09:53:21 -0800 | [diff] [blame] | 147 | if (port == nullptr) { |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 148 | if (log_errors) gpr_log(GPR_ERROR, "no port given for ipv6 scheme"); |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 149 | goto done; |
| 150 | } |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 151 | 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 Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 158 | done: |
| 159 | gpr_free(host); |
| 160 | gpr_free(port); |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 161 | return success; |
| 162 | } |
| 163 | |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 164 | bool grpc_parse_ipv6(const grpc_uri* uri, |
| 165 | grpc_resolved_address* resolved_addr) { |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 166 | if (strcmp("ipv6", uri->scheme) != 0) { |
| 167 | gpr_log(GPR_ERROR, "Expected 'ipv6' scheme, got '%s'", uri->scheme); |
| 168 | return false; |
| 169 | } |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 170 | const char* host_port = uri->path; |
Mark D. Roth | 96fc54c | 2017-05-18 14:33:07 -0700 | [diff] [blame] | 171 | if (*host_port == '/') ++host_port; |
| 172 | return grpc_parse_ipv6_hostport(host_port, resolved_addr, |
| 173 | true /* log_errors */); |
David Garcia Quintas | 9885bff | 2016-04-07 17:31:29 -0700 | [diff] [blame] | 174 | } |
David Garcia Quintas | 53af23c | 2017-04-15 10:29:46 -0700 | [diff] [blame] | 175 | |
Craig Tiller | baa14a9 | 2017-11-03 09:09:36 -0700 | [diff] [blame] | 176 | bool grpc_parse_uri(const grpc_uri* uri, grpc_resolved_address* resolved_addr) { |
David Garcia Quintas | 53af23c | 2017-04-15 10:29:46 -0700 | [diff] [blame] | 177 | 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 | } |