1*632d59bfSdjm /* $OpenBSD: addr.c,v 1.9 2024/10/18 04:30:09 djm Exp $ */ 24b59ce38Sdtucker 34b59ce38Sdtucker /* 44b59ce38Sdtucker * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org> 54b59ce38Sdtucker * 64b59ce38Sdtucker * Permission to use, copy, modify, and distribute this software for any 74b59ce38Sdtucker * purpose with or without fee is hereby granted, provided that the above 84b59ce38Sdtucker * copyright notice and this permission notice appear in all copies. 94b59ce38Sdtucker * 104b59ce38Sdtucker * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 114b59ce38Sdtucker * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 124b59ce38Sdtucker * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 134b59ce38Sdtucker * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 144b59ce38Sdtucker * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 154b59ce38Sdtucker * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 164b59ce38Sdtucker * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 174b59ce38Sdtucker */ 184b59ce38Sdtucker 194b59ce38Sdtucker #include <sys/types.h> 204b59ce38Sdtucker #include <sys/socket.h> 214b59ce38Sdtucker #include <netinet/in.h> 224b59ce38Sdtucker #include <arpa/inet.h> 234b59ce38Sdtucker 244b59ce38Sdtucker #include <netdb.h> 254b59ce38Sdtucker #include <string.h> 264b59ce38Sdtucker #include <stdlib.h> 274b59ce38Sdtucker #include <stdio.h> 28dc987674Sderaadt #include <limits.h> 294b59ce38Sdtucker 304b59ce38Sdtucker #include "addr.h" 314b59ce38Sdtucker 324b59ce38Sdtucker #define _SA(x) ((struct sockaddr *)(x)) 334b59ce38Sdtucker 34*632d59bfSdjm static int 354b59ce38Sdtucker addr_unicast_masklen(int af) 364b59ce38Sdtucker { 374b59ce38Sdtucker switch (af) { 384b59ce38Sdtucker case AF_INET: 394b59ce38Sdtucker return 32; 404b59ce38Sdtucker case AF_INET6: 414b59ce38Sdtucker return 128; 424b59ce38Sdtucker default: 434b59ce38Sdtucker return -1; 444b59ce38Sdtucker } 454b59ce38Sdtucker } 464b59ce38Sdtucker 474b59ce38Sdtucker static inline int 484b59ce38Sdtucker masklen_valid(int af, u_int masklen) 494b59ce38Sdtucker { 504b59ce38Sdtucker switch (af) { 514b59ce38Sdtucker case AF_INET: 524b59ce38Sdtucker return masklen <= 32 ? 0 : -1; 534b59ce38Sdtucker case AF_INET6: 544b59ce38Sdtucker return masklen <= 128 ? 0 : -1; 554b59ce38Sdtucker default: 564b59ce38Sdtucker return -1; 574b59ce38Sdtucker } 584b59ce38Sdtucker } 594b59ce38Sdtucker 60*632d59bfSdjm static int 614b59ce38Sdtucker addr_xaddr_to_sa(const struct xaddr *xa, struct sockaddr *sa, socklen_t *len, 624b59ce38Sdtucker u_int16_t port) 634b59ce38Sdtucker { 644b59ce38Sdtucker struct sockaddr_in *in4 = (struct sockaddr_in *)sa; 654b59ce38Sdtucker struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; 664b59ce38Sdtucker 674b59ce38Sdtucker if (xa == NULL || sa == NULL || len == NULL) 684b59ce38Sdtucker return -1; 694b59ce38Sdtucker 704b59ce38Sdtucker switch (xa->af) { 714b59ce38Sdtucker case AF_INET: 724b59ce38Sdtucker if (*len < sizeof(*in4)) 734b59ce38Sdtucker return -1; 744b59ce38Sdtucker memset(sa, '\0', sizeof(*in4)); 754b59ce38Sdtucker *len = sizeof(*in4); 764b59ce38Sdtucker #ifdef SOCK_HAS_LEN 774b59ce38Sdtucker in4->sin_len = sizeof(*in4); 784b59ce38Sdtucker #endif 794b59ce38Sdtucker in4->sin_family = AF_INET; 804b59ce38Sdtucker in4->sin_port = htons(port); 814b59ce38Sdtucker memcpy(&in4->sin_addr, &xa->v4, sizeof(in4->sin_addr)); 824b59ce38Sdtucker break; 834b59ce38Sdtucker case AF_INET6: 844b59ce38Sdtucker if (*len < sizeof(*in6)) 854b59ce38Sdtucker return -1; 864b59ce38Sdtucker memset(sa, '\0', sizeof(*in6)); 874b59ce38Sdtucker *len = sizeof(*in6); 884b59ce38Sdtucker #ifdef SOCK_HAS_LEN 894b59ce38Sdtucker in6->sin6_len = sizeof(*in6); 904b59ce38Sdtucker #endif 914b59ce38Sdtucker in6->sin6_family = AF_INET6; 924b59ce38Sdtucker in6->sin6_port = htons(port); 934b59ce38Sdtucker memcpy(&in6->sin6_addr, &xa->v6, sizeof(in6->sin6_addr)); 944b59ce38Sdtucker in6->sin6_scope_id = xa->scope_id; 954b59ce38Sdtucker break; 964b59ce38Sdtucker default: 974b59ce38Sdtucker return -1; 984b59ce38Sdtucker } 994b59ce38Sdtucker return 0; 1004b59ce38Sdtucker } 1014b59ce38Sdtucker 1024b59ce38Sdtucker /* 1034b59ce38Sdtucker * Convert struct sockaddr to struct xaddr 1044b59ce38Sdtucker * Returns 0 on success, -1 on failure. 1054b59ce38Sdtucker */ 1064b59ce38Sdtucker int 1074b59ce38Sdtucker addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa) 1084b59ce38Sdtucker { 1094b59ce38Sdtucker struct sockaddr_in *in4 = (struct sockaddr_in *)sa; 1104b59ce38Sdtucker struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; 1114b59ce38Sdtucker 1124b59ce38Sdtucker memset(xa, '\0', sizeof(*xa)); 1134b59ce38Sdtucker 1144b59ce38Sdtucker switch (sa->sa_family) { 1154b59ce38Sdtucker case AF_INET: 1164b59ce38Sdtucker if (slen < (socklen_t)sizeof(*in4)) 1174b59ce38Sdtucker return -1; 1184b59ce38Sdtucker xa->af = AF_INET; 1194b59ce38Sdtucker memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4)); 1204b59ce38Sdtucker break; 1214b59ce38Sdtucker case AF_INET6: 1224b59ce38Sdtucker if (slen < (socklen_t)sizeof(*in6)) 1234b59ce38Sdtucker return -1; 1244b59ce38Sdtucker xa->af = AF_INET6; 1254b59ce38Sdtucker memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6)); 1264b59ce38Sdtucker #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1274b59ce38Sdtucker xa->scope_id = in6->sin6_scope_id; 1284b59ce38Sdtucker #endif 1294b59ce38Sdtucker break; 1304b59ce38Sdtucker default: 1314b59ce38Sdtucker return -1; 1324b59ce38Sdtucker } 1334b59ce38Sdtucker 1344b59ce38Sdtucker return 0; 1354b59ce38Sdtucker } 1364b59ce38Sdtucker 137*632d59bfSdjm static int 1384b59ce38Sdtucker addr_invert(struct xaddr *n) 1394b59ce38Sdtucker { 1404b59ce38Sdtucker int i; 1414b59ce38Sdtucker 1424b59ce38Sdtucker if (n == NULL) 1434b59ce38Sdtucker return -1; 1444b59ce38Sdtucker 1454b59ce38Sdtucker switch (n->af) { 1464b59ce38Sdtucker case AF_INET: 1474b59ce38Sdtucker n->v4.s_addr = ~n->v4.s_addr; 1484b59ce38Sdtucker return 0; 1494b59ce38Sdtucker case AF_INET6: 1504b59ce38Sdtucker for (i = 0; i < 4; i++) 1514b59ce38Sdtucker n->addr32[i] = ~n->addr32[i]; 1524b59ce38Sdtucker return 0; 1534b59ce38Sdtucker default: 1544b59ce38Sdtucker return -1; 1554b59ce38Sdtucker } 1564b59ce38Sdtucker } 1574b59ce38Sdtucker 1584b59ce38Sdtucker /* 1594b59ce38Sdtucker * Calculate a netmask of length 'l' for address family 'af' and 1604b59ce38Sdtucker * store it in 'n'. 1614b59ce38Sdtucker * Returns 0 on success, -1 on failure. 1624b59ce38Sdtucker */ 1634b59ce38Sdtucker int 1644b59ce38Sdtucker addr_netmask(int af, u_int l, struct xaddr *n) 1654b59ce38Sdtucker { 1664b59ce38Sdtucker int i; 1674b59ce38Sdtucker 1684b59ce38Sdtucker if (masklen_valid(af, l) != 0 || n == NULL) 1694b59ce38Sdtucker return -1; 1704b59ce38Sdtucker 1714b59ce38Sdtucker memset(n, '\0', sizeof(*n)); 1724b59ce38Sdtucker switch (af) { 1734b59ce38Sdtucker case AF_INET: 1744b59ce38Sdtucker n->af = AF_INET; 1754b59ce38Sdtucker if (l == 0) 1764b59ce38Sdtucker return 0; 1774b59ce38Sdtucker n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff); 1784b59ce38Sdtucker return 0; 1794b59ce38Sdtucker case AF_INET6: 1804b59ce38Sdtucker n->af = AF_INET6; 1814b59ce38Sdtucker for (i = 0; i < 4 && l >= 32; i++, l -= 32) 1824b59ce38Sdtucker n->addr32[i] = 0xffffffffU; 1834b59ce38Sdtucker if (i < 4 && l != 0) 1844b59ce38Sdtucker n->addr32[i] = htonl((0xffffffff << (32 - l)) & 1854b59ce38Sdtucker 0xffffffff); 1864b59ce38Sdtucker return 0; 1874b59ce38Sdtucker default: 1884b59ce38Sdtucker return -1; 1894b59ce38Sdtucker } 1904b59ce38Sdtucker } 1914b59ce38Sdtucker 192*632d59bfSdjm static int 1934b59ce38Sdtucker addr_hostmask(int af, u_int l, struct xaddr *n) 1944b59ce38Sdtucker { 1954b59ce38Sdtucker if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1) 1964b59ce38Sdtucker return -1; 1974b59ce38Sdtucker return 0; 1984b59ce38Sdtucker } 1994b59ce38Sdtucker 2004b59ce38Sdtucker /* 2014b59ce38Sdtucker * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'. 2024b59ce38Sdtucker * Returns 0 on success, -1 on failure. 2034b59ce38Sdtucker */ 2044b59ce38Sdtucker int 2054b59ce38Sdtucker addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b) 2064b59ce38Sdtucker { 2074b59ce38Sdtucker int i; 2084b59ce38Sdtucker 2094b59ce38Sdtucker if (dst == NULL || a == NULL || b == NULL || a->af != b->af) 2104b59ce38Sdtucker return -1; 2114b59ce38Sdtucker 2124b59ce38Sdtucker memcpy(dst, a, sizeof(*dst)); 2134b59ce38Sdtucker switch (a->af) { 2144b59ce38Sdtucker case AF_INET: 2154b59ce38Sdtucker dst->v4.s_addr &= b->v4.s_addr; 2164b59ce38Sdtucker return 0; 2174b59ce38Sdtucker case AF_INET6: 2184b59ce38Sdtucker dst->scope_id = a->scope_id; 2194b59ce38Sdtucker for (i = 0; i < 4; i++) 2204b59ce38Sdtucker dst->addr32[i] &= b->addr32[i]; 2214b59ce38Sdtucker return 0; 2224b59ce38Sdtucker default: 2234b59ce38Sdtucker return -1; 2244b59ce38Sdtucker } 2254b59ce38Sdtucker } 2264b59ce38Sdtucker 227*632d59bfSdjm static int 228ba77ede9Sdjm addr_or(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b) 229ba77ede9Sdjm { 230ba77ede9Sdjm int i; 231ba77ede9Sdjm 232ba77ede9Sdjm if (dst == NULL || a == NULL || b == NULL || a->af != b->af) 233ba77ede9Sdjm return (-1); 234ba77ede9Sdjm 235ba77ede9Sdjm memcpy(dst, a, sizeof(*dst)); 236ba77ede9Sdjm switch (a->af) { 237ba77ede9Sdjm case AF_INET: 238ba77ede9Sdjm dst->v4.s_addr |= b->v4.s_addr; 239ba77ede9Sdjm return (0); 240ba77ede9Sdjm case AF_INET6: 241ba77ede9Sdjm for (i = 0; i < 4; i++) 242ba77ede9Sdjm dst->addr32[i] |= b->addr32[i]; 243ba77ede9Sdjm return (0); 244ba77ede9Sdjm default: 245ba77ede9Sdjm return (-1); 246ba77ede9Sdjm } 247ba77ede9Sdjm } 248ba77ede9Sdjm 249ba77ede9Sdjm int 2504b59ce38Sdtucker addr_cmp(const struct xaddr *a, const struct xaddr *b) 2514b59ce38Sdtucker { 2524b59ce38Sdtucker int i; 2534b59ce38Sdtucker 2544b59ce38Sdtucker if (a->af != b->af) 2554b59ce38Sdtucker return (a->af == AF_INET6 ? 1 : -1); 2564b59ce38Sdtucker 2574b59ce38Sdtucker switch (a->af) { 2584b59ce38Sdtucker case AF_INET: 2594b59ce38Sdtucker /* 2604b59ce38Sdtucker * Can't just subtract here as 255.255.255.255 - 0.0.0.0 is 2614b59ce38Sdtucker * too big to fit into a signed int 2624b59ce38Sdtucker */ 2634b59ce38Sdtucker if (a->v4.s_addr == b->v4.s_addr) 2644b59ce38Sdtucker return 0; 2654b59ce38Sdtucker return (ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1); 266d4c3ca28Sdtucker case AF_INET6: 2674b59ce38Sdtucker /* 2684b59ce38Sdtucker * Do this a byte at a time to avoid the above issue and 2694b59ce38Sdtucker * any endian problems 2704b59ce38Sdtucker */ 2714b59ce38Sdtucker for (i = 0; i < 16; i++) 2724b59ce38Sdtucker if (a->addr8[i] - b->addr8[i] != 0) 2734b59ce38Sdtucker return (a->addr8[i] - b->addr8[i]); 2744b59ce38Sdtucker if (a->scope_id == b->scope_id) 2754b59ce38Sdtucker return (0); 2764b59ce38Sdtucker return (a->scope_id > b->scope_id ? 1 : -1); 2774b59ce38Sdtucker default: 2784b59ce38Sdtucker return (-1); 2794b59ce38Sdtucker } 2804b59ce38Sdtucker } 2814b59ce38Sdtucker 282*632d59bfSdjm static int 2834b59ce38Sdtucker addr_is_all0s(const struct xaddr *a) 2844b59ce38Sdtucker { 2854b59ce38Sdtucker int i; 2864b59ce38Sdtucker 2874b59ce38Sdtucker switch (a->af) { 2884b59ce38Sdtucker case AF_INET: 2894b59ce38Sdtucker return (a->v4.s_addr == 0 ? 0 : -1); 290d4c3ca28Sdtucker case AF_INET6: 2914b59ce38Sdtucker for (i = 0; i < 4; i++) 2924b59ce38Sdtucker if (a->addr32[i] != 0) 2934b59ce38Sdtucker return -1; 2944b59ce38Sdtucker return 0; 2954b59ce38Sdtucker default: 2964b59ce38Sdtucker return -1; 2974b59ce38Sdtucker } 2984b59ce38Sdtucker } 2994b59ce38Sdtucker 300ba77ede9Sdjm /* Increment the specified address. Note, does not do overflow checking */ 301ba77ede9Sdjm void 302ba77ede9Sdjm addr_increment(struct xaddr *a) 303ba77ede9Sdjm { 304ba77ede9Sdjm int i; 305ba77ede9Sdjm uint32_t n; 306ba77ede9Sdjm 307ba77ede9Sdjm switch (a->af) { 308ba77ede9Sdjm case AF_INET: 309ba77ede9Sdjm a->v4.s_addr = htonl(ntohl(a->v4.s_addr) + 1); 310ba77ede9Sdjm break; 311ba77ede9Sdjm case AF_INET6: 312ba77ede9Sdjm for (i = 0; i < 4; i++) { 313ba77ede9Sdjm /* Increment with carry */ 314ba77ede9Sdjm n = ntohl(a->addr32[3 - i]) + 1; 315ba77ede9Sdjm a->addr32[3 - i] = htonl(n); 316ba77ede9Sdjm if (n != 0) 317ba77ede9Sdjm break; 318ba77ede9Sdjm } 319ba77ede9Sdjm break; 320ba77ede9Sdjm } 321ba77ede9Sdjm } 322ba77ede9Sdjm 3234b59ce38Sdtucker /* 3244b59ce38Sdtucker * Test whether host portion of address 'a', as determined by 'masklen' 3254b59ce38Sdtucker * is all zeros. 326584553ebSdtucker * Returns 0 if host portion of address is all-zeros, 3274b59ce38Sdtucker * -1 if not all zeros or on failure. 3284b59ce38Sdtucker */ 329*632d59bfSdjm static int 3304b59ce38Sdtucker addr_host_is_all0s(const struct xaddr *a, u_int masklen) 3314b59ce38Sdtucker { 3324b59ce38Sdtucker struct xaddr tmp_addr, tmp_mask, tmp_result; 3334b59ce38Sdtucker 3344b59ce38Sdtucker memcpy(&tmp_addr, a, sizeof(tmp_addr)); 3354b59ce38Sdtucker if (addr_hostmask(a->af, masklen, &tmp_mask) == -1) 3364b59ce38Sdtucker return -1; 3374b59ce38Sdtucker if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1) 3384b59ce38Sdtucker return -1; 3394b59ce38Sdtucker return addr_is_all0s(&tmp_result); 3404b59ce38Sdtucker } 3414b59ce38Sdtucker 342ba77ede9Sdjm #if 0 343*632d59bfSdjm static int 344ba77ede9Sdjm addr_host_to_all0s(struct xaddr *a, u_int masklen) 345ba77ede9Sdjm { 346ba77ede9Sdjm struct xaddr tmp_mask; 347ba77ede9Sdjm 348ba77ede9Sdjm if (addr_netmask(a->af, masklen, &tmp_mask) == -1) 349ba77ede9Sdjm return (-1); 350ba77ede9Sdjm if (addr_and(a, a, &tmp_mask) == -1) 351ba77ede9Sdjm return (-1); 352ba77ede9Sdjm return (0); 353ba77ede9Sdjm } 354ba77ede9Sdjm #endif 355ba77ede9Sdjm 356ba77ede9Sdjm int 357ba77ede9Sdjm addr_host_to_all1s(struct xaddr *a, u_int masklen) 358ba77ede9Sdjm { 359ba77ede9Sdjm struct xaddr tmp_mask; 360ba77ede9Sdjm 361ba77ede9Sdjm if (addr_hostmask(a->af, masklen, &tmp_mask) == -1) 362ba77ede9Sdjm return (-1); 363ba77ede9Sdjm if (addr_or(a, a, &tmp_mask) == -1) 364ba77ede9Sdjm return (-1); 365ba77ede9Sdjm return (0); 366ba77ede9Sdjm } 367ba77ede9Sdjm 3684b59ce38Sdtucker /* 369584553ebSdtucker * Parse string address 'p' into 'n'. 3704b59ce38Sdtucker * Returns 0 on success, -1 on failure. 3714b59ce38Sdtucker */ 3724b59ce38Sdtucker int 3734b59ce38Sdtucker addr_pton(const char *p, struct xaddr *n) 3744b59ce38Sdtucker { 3754b59ce38Sdtucker struct addrinfo hints, *ai; 3764b59ce38Sdtucker 3774b59ce38Sdtucker memset(&hints, '\0', sizeof(hints)); 3784b59ce38Sdtucker hints.ai_flags = AI_NUMERICHOST; 3794b59ce38Sdtucker 3804b59ce38Sdtucker if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0) 3814b59ce38Sdtucker return -1; 3824b59ce38Sdtucker 3832ad7106cSdtucker if (ai == NULL) 3844b59ce38Sdtucker return -1; 3854b59ce38Sdtucker 3862ad7106cSdtucker if (ai->ai_addr == NULL) { 3872ad7106cSdtucker freeaddrinfo(ai); 3882ad7106cSdtucker return -1; 3892ad7106cSdtucker } 3902ad7106cSdtucker 3914b59ce38Sdtucker if (n != NULL && addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, 3924b59ce38Sdtucker n) == -1) { 3934b59ce38Sdtucker freeaddrinfo(ai); 3944b59ce38Sdtucker return -1; 3954b59ce38Sdtucker } 3964b59ce38Sdtucker 3974b59ce38Sdtucker freeaddrinfo(ai); 3984b59ce38Sdtucker return 0; 3994b59ce38Sdtucker } 4004b59ce38Sdtucker 401*632d59bfSdjm #if 0 402*632d59bfSdjm static int 4034b59ce38Sdtucker addr_sa_pton(const char *h, const char *s, struct sockaddr *sa, socklen_t slen) 4044b59ce38Sdtucker { 4054b59ce38Sdtucker struct addrinfo hints, *ai; 4064b59ce38Sdtucker 4074b59ce38Sdtucker memset(&hints, '\0', sizeof(hints)); 4084b59ce38Sdtucker hints.ai_flags = AI_NUMERICHOST; 4094b59ce38Sdtucker 4104b59ce38Sdtucker if (h == NULL || getaddrinfo(h, s, &hints, &ai) != 0) 4114b59ce38Sdtucker return -1; 4124b59ce38Sdtucker 4132ad7106cSdtucker if (ai == NULL) 4144b59ce38Sdtucker return -1; 4154b59ce38Sdtucker 4162ad7106cSdtucker if (ai->ai_addr == NULL) { 4172ad7106cSdtucker freeaddrinfo(ai); 4184b59ce38Sdtucker return -1; 4192ad7106cSdtucker } 4202ad7106cSdtucker 4212ad7106cSdtucker if (sa != NULL) { 4222ad7106cSdtucker if (slen < ai->ai_addrlen) { 4232ad7106cSdtucker freeaddrinfo(ai); 4242ad7106cSdtucker return -1; 4252ad7106cSdtucker } 4264b59ce38Sdtucker memcpy(sa, &ai->ai_addr, ai->ai_addrlen); 4274b59ce38Sdtucker } 4284b59ce38Sdtucker 4294b59ce38Sdtucker freeaddrinfo(ai); 4304b59ce38Sdtucker return 0; 4314b59ce38Sdtucker } 432*632d59bfSdjm #endif 4334b59ce38Sdtucker 4344b59ce38Sdtucker int 4354b59ce38Sdtucker addr_ntop(const struct xaddr *n, char *p, size_t len) 4364b59ce38Sdtucker { 4374b59ce38Sdtucker struct sockaddr_storage ss; 4384b59ce38Sdtucker socklen_t slen = sizeof(ss); 4394b59ce38Sdtucker 4404b59ce38Sdtucker if (addr_xaddr_to_sa(n, _SA(&ss), &slen, 0) == -1) 4414b59ce38Sdtucker return -1; 4422ad7106cSdtucker if (p == NULL || len == 0) 4434b59ce38Sdtucker return -1; 4444b59ce38Sdtucker if (getnameinfo(_SA(&ss), slen, p, len, NULL, 0, 445dae09413Sdjm NI_NUMERICHOST) != 0) 4464b59ce38Sdtucker return -1; 4474b59ce38Sdtucker 4484b59ce38Sdtucker return 0; 4494b59ce38Sdtucker } 4504b59ce38Sdtucker 4514b59ce38Sdtucker /* 4524b59ce38Sdtucker * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z). 4534b59ce38Sdtucker * Return -1 on parse error, -2 on inconsistency or 0 on success. 4544b59ce38Sdtucker */ 4554b59ce38Sdtucker int 4564b59ce38Sdtucker addr_pton_cidr(const char *p, struct xaddr *n, u_int *l) 4574b59ce38Sdtucker { 4584b59ce38Sdtucker struct xaddr tmp; 459dc987674Sderaadt u_int masklen = 999; 460dc987674Sderaadt char addrbuf[64], *mp; 461dc987674Sderaadt const char *errstr; 4624b59ce38Sdtucker 4634b59ce38Sdtucker /* Don't modify argument */ 4644b59ce38Sdtucker if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) >= sizeof(addrbuf)) 4654b59ce38Sdtucker return -1; 4664b59ce38Sdtucker 4674b59ce38Sdtucker if ((mp = strchr(addrbuf, '/')) != NULL) { 4684b59ce38Sdtucker *mp = '\0'; 4694b59ce38Sdtucker mp++; 470dc987674Sderaadt masklen = (u_int)strtonum(mp, 0, INT_MAX, &errstr); 471dc987674Sderaadt if (errstr) 4724b59ce38Sdtucker return -1; 4734b59ce38Sdtucker } 4744b59ce38Sdtucker 4754b59ce38Sdtucker if (addr_pton(addrbuf, &tmp) == -1) 4764b59ce38Sdtucker return -1; 4774b59ce38Sdtucker 4784b59ce38Sdtucker if (mp == NULL) 4794b59ce38Sdtucker masklen = addr_unicast_masklen(tmp.af); 4804b59ce38Sdtucker if (masklen_valid(tmp.af, masklen) == -1) 4814b59ce38Sdtucker return -2; 4824b59ce38Sdtucker if (addr_host_is_all0s(&tmp, masklen) != 0) 4834b59ce38Sdtucker return -2; 4844b59ce38Sdtucker 4854b59ce38Sdtucker if (n != NULL) 4864b59ce38Sdtucker memcpy(n, &tmp, sizeof(*n)); 4874b59ce38Sdtucker if (l != NULL) 4884b59ce38Sdtucker *l = masklen; 4894b59ce38Sdtucker 4904b59ce38Sdtucker return 0; 4914b59ce38Sdtucker } 4924b59ce38Sdtucker 4934b59ce38Sdtucker int 4944b59ce38Sdtucker addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen) 4954b59ce38Sdtucker { 4964b59ce38Sdtucker struct xaddr tmp_mask, tmp_result; 4974b59ce38Sdtucker 4984b59ce38Sdtucker if (host->af != net->af) 4994b59ce38Sdtucker return -1; 5004b59ce38Sdtucker 5014b59ce38Sdtucker if (addr_netmask(host->af, masklen, &tmp_mask) == -1) 5024b59ce38Sdtucker return -1; 5034b59ce38Sdtucker if (addr_and(&tmp_result, host, &tmp_mask) == -1) 5044b59ce38Sdtucker return -1; 5054b59ce38Sdtucker return addr_cmp(&tmp_result, net); 5064b59ce38Sdtucker } 507