/* vim: set expandtab ts=4 sw=4: */ /* * You may redistribute this program and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "util/events/libuv/UvWrapper.h" #include "benc/String.h" #include "memory/Allocator.h" #include "util/platform/Sockaddr.h" #include "util/CString.h" #include "util/Bits.h" #include "util/Hex.h" #include #include #include #include struct Sockaddr_pvt { struct Sockaddr pub; struct sockaddr_storage ss; }; struct Sockaddr_in_pvt { struct Sockaddr pub; struct sockaddr_in si; }; struct Sockaddr_in6_pvt { struct Sockaddr pub; struct sockaddr_in6 si; }; const struct Sockaddr* const Sockaddr_LOOPBACK_be = (const struct Sockaddr*) &((const struct Sockaddr_in_pvt) { .pub = { .addrLen = sizeof(struct Sockaddr_in_pvt) }, .si = { .sin_family = AF_INET, .sin_addr = { .s_addr = 0x7f000001 } } }); const struct Sockaddr* const Sockaddr_LOOPBACK_le = (const struct Sockaddr*) &((const struct Sockaddr_in_pvt) { .pub = { .addrLen = sizeof(struct Sockaddr_in_pvt) }, .si = { .sin_family = AF_INET, .sin_addr = { .s_addr = 0x0100007f } } }); const struct Sockaddr* const Sockaddr_LOOPBACK6 = (const struct Sockaddr*) &((const struct Sockaddr_in6_pvt) { .pub = { .addrLen = sizeof(struct Sockaddr_in6_pvt) }, .si = { .sin6_family = AF_INET6, .sin6_addr = { .s6_addr = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }} } }); struct Sockaddr* Sockaddr_fromNative(const void* ss, int addrLen, struct Allocator* alloc) { struct Sockaddr_pvt* out = Allocator_calloc(alloc, addrLen + Sockaddr_OVERHEAD, 1); Bits_memcpy(&out->ss, ss, addrLen); out->pub.addrLen = addrLen + Sockaddr_OVERHEAD; Sockaddr_normalizeNative(&out->ss); return &out->pub; } int Sockaddr_parse(const char* str, struct Sockaddr_storage* out) { struct Sockaddr_storage unusedOut; if (!out) { out = &unusedOut; } Bits_memset(out, 0, sizeof(struct Sockaddr_storage)); char* lastColon = CString_strrchr(str, ':'); if (!lastColon || lastColon == CString_strchr(str, ':')) { // IPv4 int port = 0; int addrLen; if (lastColon) { addrLen = (lastColon - str); port = atoi(lastColon+1); if (port > 65535 || port < 0) { return -1; } } else { addrLen = CString_strlen(str); } uint8_t addr[16] = {0}; if (addrLen > 15 || addrLen < 7) { return -1; } Bits_memcpy(addr, str, addrLen); struct sockaddr_in* in = ((struct sockaddr_in*) Sockaddr_asNative(&out->addr)); if (uv_inet_pton(AF_INET, (char*) addr, &in->sin_addr) != 0) { return -1; } out->addr.addrLen = sizeof(struct sockaddr_in) + Sockaddr_OVERHEAD; in->sin_port = Endian_hostToBigEndian16(port); in->sin_family = AF_INET; } else { // IPv6 int port = 0; int addrLen; if (*str == '[') { str++; { char* endBracket = CString_strchr(str, ']'); if (!endBracket) { return -1; } addrLen = (endBracket - str); } if (str[addrLen+1] == ':') { port = atoi(&str[addrLen+2]); if (port > 65535 || port < 0) { return -1; } } } else { addrLen = CString_strlen(str); } uint8_t addr[40] = {0}; if (addrLen > 39 || addrLen < 2) { return -1; } Bits_memcpy(addr, str, addrLen); struct sockaddr_in6* in6 = (struct sockaddr_in6*) Sockaddr_asNative(&out->addr); int ret = uv_inet_pton(AF_INET6, (char*) addr, &in6->sin6_addr); if (ret != 0) { return -1; } out->addr.addrLen = sizeof(struct sockaddr_in6) + Sockaddr_OVERHEAD; in6->sin6_port = Endian_hostToBigEndian16(port); in6->sin6_family = AF_INET6; } return 0; } struct Sockaddr* Sockaddr_clone(const struct Sockaddr* addr, struct Allocator* alloc) { return Sockaddr_fromNative(Sockaddr_asNativeConst(addr), addr->addrLen - Sockaddr_OVERHEAD, alloc); } char* Sockaddr_print(struct Sockaddr* sockaddr, struct Allocator* alloc) { if (sockaddr->addrLen < (2 + Sockaddr_OVERHEAD) || sockaddr->addrLen > Sockaddr_MAXSIZE + Sockaddr_OVERHEAD) { return "invalid"; } struct Sockaddr_pvt* addr = (struct Sockaddr_pvt*) sockaddr; void* inAddr; uint16_t port; switch (addr->ss.ss_family) { case AF_INET: inAddr = &((struct sockaddr_in*) &addr->ss)->sin_addr; port = Endian_bigEndianToHost16(((struct sockaddr_in*)&addr->ss)->sin_port); break; case AF_INET6: inAddr = &((struct sockaddr_in6*) &addr->ss)->sin6_addr; port = Endian_bigEndianToHost16(((struct sockaddr_in6*)&addr->ss)->sin6_port); break; default: { uint8_t buff[Sockaddr_MAXSIZE * 2 + 1] = {0}; Hex_encode(buff, sizeof(buff), (uint8_t*)&addr->ss, sockaddr->addrLen); String* out = String_printf(alloc, "unknown (%s)", buff); return out->bytes; } }; #define BUFF_SZ 64 char printedAddr[BUFF_SZ] = {0}; int ret = uv_inet_ntop(addr->ss.ss_family, inAddr, printedAddr, BUFF_SZ - 1); if (ret != 0) { return "invalid"; } if (port) { int totalLength = CString_strlen(printedAddr) + CString_strlen("[]:65535") + 1; char* out = Allocator_calloc(alloc, totalLength, 1); const char* format = (addr->ss.ss_family == AF_INET6) ? "[%s]:%u" : "%s:%u"; snprintf(out, totalLength, format, printedAddr, port); return out; } int totalLength = CString_strlen(printedAddr) + 1; char* out = Allocator_calloc(alloc, totalLength, 1); Bits_memcpy(out, printedAddr, totalLength); return out; } static uint16_t* getPortPtr(struct Sockaddr* sockaddr) { if (sockaddr->addrLen < (2 + Sockaddr_OVERHEAD)) { return NULL; } struct Sockaddr_pvt* sa = (struct Sockaddr_pvt*) sockaddr; switch (sa->ss.ss_family) { case AF_INET: return &((struct sockaddr_in*)&sa->ss)->sin_port; case AF_INET6: return &((struct sockaddr_in6*)&sa->ss)->sin6_port; } return NULL; } int Sockaddr_getPort(struct Sockaddr* sockaddr) { uint16_t* pp = getPortPtr(sockaddr); return (pp) ? Endian_bigEndianToHost16(*pp) : -1; } int Sockaddr_setPort(struct Sockaddr* sockaddr, uint16_t port) { uint16_t* pp = getPortPtr(sockaddr); if (pp) { *pp = Endian_hostToBigEndian16(port); return 0; } return -1; } int Sockaddr_getAddress(struct Sockaddr* sockaddr, void* addrPtr) { if (sockaddr->addrLen < (2 + Sockaddr_OVERHEAD)) { return -1; } struct Sockaddr_pvt* sa = (struct Sockaddr_pvt*) sockaddr; if (addrPtr) { void** ap = (void**) addrPtr; switch (sa->ss.ss_family) { case AF_INET: *ap = &((struct sockaddr_in*)&sa->ss)->sin_addr; break; case AF_INET6: *ap = &((struct sockaddr_in6*)&sa->ss)->sin6_addr; break; } } switch (sa->ss.ss_family) { case AF_INET: return 4; case AF_INET6: return 16; } return -1; } const int Sockaddr_AF_INET = AF_INET; const int Sockaddr_AF_INET6 = AF_INET6; int Sockaddr_getFamily(struct Sockaddr* sockaddr) { if (sockaddr->addrLen < (2 + Sockaddr_OVERHEAD)) { return -1; } struct Sockaddr_pvt* sa = (struct Sockaddr_pvt*) sockaddr; return sa->ss.ss_family; } struct Sockaddr* Sockaddr_fromBytes(const uint8_t* bytes, int addrFamily, struct Allocator* alloc) { struct sockaddr_storage ss; Bits_memset(&ss, 0, sizeof(struct sockaddr_storage)); int addrLen; switch (addrFamily) { case AF_INET: { ss.ss_family = AF_INET; Bits_memcpyConst(&((struct sockaddr_in*)&ss)->sin_addr, bytes, 4); addrLen = sizeof(struct sockaddr_in); break; } case AF_INET6: { ss.ss_family = AF_INET6; Bits_memcpyConst(&((struct sockaddr_in6*)&ss)->sin6_addr, bytes, 16); addrLen = sizeof(struct sockaddr_in6); break; } default: Assert_failure("unrecognized address type [%d]", addrFamily); } struct Sockaddr_pvt* out = Allocator_calloc(alloc, addrLen + Sockaddr_OVERHEAD, 1); Bits_memcpy(&out->ss, &ss, addrLen); out->pub.addrLen = addrLen + Sockaddr_OVERHEAD; return &out->pub; } void Sockaddr_normalizeNative(void* nativeSockaddr) { #if defined(freebsd) || defined(openbsd) || defined(darwin) ((struct sockaddr*)nativeSockaddr)->sa_len = 0; #endif } struct Sockaddr* Sockaddr_fromName(char* name, struct Allocator* alloc) { struct addrinfo* servinfo; if (getaddrinfo(name, 0, NULL, &servinfo) == 0) { struct Sockaddr* adr; adr = Sockaddr_fromNative(servinfo->ai_addr, servinfo->ai_addrlen, alloc); freeaddrinfo(servinfo); return adr; } return NULL; }