/* * * Copyright 2014, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "src/core/iomgr/sockaddr_utils.h" #include #include #include "src/core/support/string.h" #include #include #include static const gpr_uint8 kV4MappedPrefix[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; int grpc_sockaddr_is_v4mapped(const struct sockaddr *addr, struct sockaddr_in *addr4_out) { GPR_ASSERT(addr != (struct sockaddr *)addr4_out); if (addr->sa_family == AF_INET6) { const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; if (memcmp(addr6->sin6_addr.s6_addr, kV4MappedPrefix, sizeof(kV4MappedPrefix)) == 0) { if (addr4_out != NULL) { /* Normalize ::ffff:0.0.0.0/96 to IPv4. */ memset(addr4_out, 0, sizeof(*addr4_out)); addr4_out->sin_family = AF_INET; /* s6_addr32 would be nice, but it's non-standard. */ memcpy(&addr4_out->sin_addr, &addr6->sin6_addr.s6_addr[12], 4); addr4_out->sin_port = addr6->sin6_port; } return 1; } } return 0; } int grpc_sockaddr_to_v4mapped(const struct sockaddr *addr, struct sockaddr_in6 *addr6_out) { GPR_ASSERT(addr != (struct sockaddr *)addr6_out); if (addr->sa_family == AF_INET) { const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; memset(addr6_out, 0, sizeof(*addr6_out)); addr6_out->sin6_family = AF_INET6; memcpy(&addr6_out->sin6_addr.s6_addr[0], kV4MappedPrefix, 12); memcpy(&addr6_out->sin6_addr.s6_addr[12], &addr4->sin_addr, 4); addr6_out->sin6_port = addr4->sin_port; return 1; } return 0; } int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out) { struct sockaddr_in addr4_normalized; if (grpc_sockaddr_is_v4mapped(addr, &addr4_normalized)) { addr = (struct sockaddr *)&addr4_normalized; } if (addr->sa_family == AF_INET) { /* Check for 0.0.0.0 */ const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; if (addr4->sin_addr.s_addr != 0) { return 0; } *port_out = ntohs(addr4->sin_port); return 1; } else if (addr->sa_family == AF_INET6) { /* Check for :: */ const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; int i; for (i = 0; i < 16; i++) { if (addr6->sin6_addr.s6_addr[i] != 0) { return 0; } } *port_out = ntohs(addr6->sin6_port); return 1; } else { return 0; } } void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out, struct sockaddr_in6 *wild6_out) { grpc_sockaddr_make_wildcard4(port, wild4_out); grpc_sockaddr_make_wildcard6(port, wild6_out); } void grpc_sockaddr_make_wildcard4(int port, struct sockaddr_in *wild_out) { memset(wild_out, 0, sizeof(*wild_out)); wild_out->sin_family = AF_INET; wild_out->sin_port = htons(port); } void grpc_sockaddr_make_wildcard6(int port, struct sockaddr_in6 *wild_out) { memset(wild_out, 0, sizeof(*wild_out)); wild_out->sin6_family = AF_INET6; wild_out->sin6_port = htons(port); } int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr, int normalize) { const int save_errno = errno; struct sockaddr_in addr_normalized; char ntop_buf[INET6_ADDRSTRLEN]; const void *ip = NULL; int port; int ret; *out = NULL; if (normalize && grpc_sockaddr_is_v4mapped(addr, &addr_normalized)) { addr = (const struct sockaddr *)&addr_normalized; } if (addr->sa_family == AF_INET) { const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr; ip = &addr4->sin_addr; port = ntohs(addr4->sin_port); } else if (addr->sa_family == AF_INET6) { const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr; ip = &addr6->sin6_addr; port = ntohs(addr6->sin6_port); } if (ip != NULL && inet_ntop(addr->sa_family, ip, ntop_buf, sizeof(ntop_buf)) != NULL) { ret = gpr_join_host_port(out, ntop_buf, port); } else { ret = gpr_asprintf(out, "(sockaddr family=%d)", addr->sa_family); } /* This is probably redundant, but we wouldn't want to log the wrong error. */ errno = save_errno; return ret; } int grpc_sockaddr_get_port(const struct sockaddr *addr) { switch (addr->sa_family) { case AF_INET: return ntohs(((struct sockaddr_in *)addr)->sin_port); case AF_INET6: return ntohs(((struct sockaddr_in6 *)addr)->sin6_port); case AF_UNIX: return 1; default: gpr_log(GPR_ERROR, "Unknown socket family %d in %s", addr->sa_family, __FUNCTION__); return 0; } } int grpc_sockaddr_set_port(const struct sockaddr *addr, int port) { switch (addr->sa_family) { case AF_INET: ((struct sockaddr_in *)addr)->sin_port = htons(port); return 1; case AF_INET6: ((struct sockaddr_in6 *)addr)->sin6_port = htons(port); return 1; default: gpr_log(GPR_ERROR, "Unknown socket family %d in %s", addr->sa_family, __FUNCTION__); return 0; } }