111044SHuie-Ying.Lee@Sun.COM /* $OpenBSD: addrmatch.c,v 1.4 2008/12/10 03:55:20 stevesk Exp $ */ 211044SHuie-Ying.Lee@Sun.COM 311044SHuie-Ying.Lee@Sun.COM /* 411044SHuie-Ying.Lee@Sun.COM * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org> 511044SHuie-Ying.Lee@Sun.COM * 611044SHuie-Ying.Lee@Sun.COM * Permission to use, copy, modify, and distribute this software for any 711044SHuie-Ying.Lee@Sun.COM * purpose with or without fee is hereby granted, provided that the above 811044SHuie-Ying.Lee@Sun.COM * copyright notice and this permission notice appear in all copies. 911044SHuie-Ying.Lee@Sun.COM * 1011044SHuie-Ying.Lee@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1111044SHuie-Ying.Lee@Sun.COM * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1211044SHuie-Ying.Lee@Sun.COM * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1311044SHuie-Ying.Lee@Sun.COM * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1411044SHuie-Ying.Lee@Sun.COM * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1511044SHuie-Ying.Lee@Sun.COM * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1611044SHuie-Ying.Lee@Sun.COM * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1711044SHuie-Ying.Lee@Sun.COM */ 1811044SHuie-Ying.Lee@Sun.COM 1911044SHuie-Ying.Lee@Sun.COM #include "includes.h" 2011044SHuie-Ying.Lee@Sun.COM 2111044SHuie-Ying.Lee@Sun.COM #include <sys/types.h> 2211044SHuie-Ying.Lee@Sun.COM #include <sys/socket.h> 2311044SHuie-Ying.Lee@Sun.COM #include <netinet/in.h> 2411044SHuie-Ying.Lee@Sun.COM #include <arpa/inet.h> 2511044SHuie-Ying.Lee@Sun.COM 2611044SHuie-Ying.Lee@Sun.COM #include <netdb.h> 2711044SHuie-Ying.Lee@Sun.COM #include <string.h> 2811044SHuie-Ying.Lee@Sun.COM #include <stdlib.h> 2911044SHuie-Ying.Lee@Sun.COM #include <stdio.h> 3011044SHuie-Ying.Lee@Sun.COM #include <stdarg.h> 3111044SHuie-Ying.Lee@Sun.COM 3211044SHuie-Ying.Lee@Sun.COM #include "match.h" 3311044SHuie-Ying.Lee@Sun.COM #include "log.h" 3411044SHuie-Ying.Lee@Sun.COM #include "xmalloc.h" 3511044SHuie-Ying.Lee@Sun.COM 3611044SHuie-Ying.Lee@Sun.COM struct xaddr { 3711044SHuie-Ying.Lee@Sun.COM sa_family_t af; 3811044SHuie-Ying.Lee@Sun.COM union { 3911044SHuie-Ying.Lee@Sun.COM struct in_addr v4; 4011044SHuie-Ying.Lee@Sun.COM struct in6_addr v6; 4111044SHuie-Ying.Lee@Sun.COM u_int8_t addr8[16]; 4211044SHuie-Ying.Lee@Sun.COM u_int32_t addr32[4]; 4311044SHuie-Ying.Lee@Sun.COM } xa; /* 128-bit address */ 4411044SHuie-Ying.Lee@Sun.COM u_int32_t scope_id; /* iface scope id for v6 */ 4511044SHuie-Ying.Lee@Sun.COM #define v4 xa.v4 4611044SHuie-Ying.Lee@Sun.COM #define v6 xa.v6 4711044SHuie-Ying.Lee@Sun.COM #define addr8 xa.addr8 4811044SHuie-Ying.Lee@Sun.COM #define addr32 xa.addr32 4911044SHuie-Ying.Lee@Sun.COM }; 5011044SHuie-Ying.Lee@Sun.COM 5111044SHuie-Ying.Lee@Sun.COM static int 5211044SHuie-Ying.Lee@Sun.COM addr_unicast_masklen(int af) 5311044SHuie-Ying.Lee@Sun.COM { 5411044SHuie-Ying.Lee@Sun.COM switch (af) { 5511044SHuie-Ying.Lee@Sun.COM case AF_INET: 5611044SHuie-Ying.Lee@Sun.COM return 32; 5711044SHuie-Ying.Lee@Sun.COM case AF_INET6: 5811044SHuie-Ying.Lee@Sun.COM return 128; 5911044SHuie-Ying.Lee@Sun.COM default: 6011044SHuie-Ying.Lee@Sun.COM return -1; 6111044SHuie-Ying.Lee@Sun.COM } 6211044SHuie-Ying.Lee@Sun.COM } 6311044SHuie-Ying.Lee@Sun.COM 6411044SHuie-Ying.Lee@Sun.COM static inline int 6511044SHuie-Ying.Lee@Sun.COM masklen_valid(int af, u_int masklen) 6611044SHuie-Ying.Lee@Sun.COM { 6711044SHuie-Ying.Lee@Sun.COM switch (af) { 6811044SHuie-Ying.Lee@Sun.COM case AF_INET: 6911044SHuie-Ying.Lee@Sun.COM return masklen <= 32 ? 0 : -1; 7011044SHuie-Ying.Lee@Sun.COM case AF_INET6: 7111044SHuie-Ying.Lee@Sun.COM return masklen <= 128 ? 0 : -1; 7211044SHuie-Ying.Lee@Sun.COM default: 7311044SHuie-Ying.Lee@Sun.COM return -1; 7411044SHuie-Ying.Lee@Sun.COM } 7511044SHuie-Ying.Lee@Sun.COM } 7611044SHuie-Ying.Lee@Sun.COM 7711044SHuie-Ying.Lee@Sun.COM /* 7811044SHuie-Ying.Lee@Sun.COM * Convert struct sockaddr to struct xaddr 7911044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 8011044SHuie-Ying.Lee@Sun.COM */ 8111044SHuie-Ying.Lee@Sun.COM static int 8211044SHuie-Ying.Lee@Sun.COM addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa) 8311044SHuie-Ying.Lee@Sun.COM { 84*11060SHuie-Ying.Lee@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */ 8511044SHuie-Ying.Lee@Sun.COM struct sockaddr_in *in4 = (struct sockaddr_in *)sa; 86*11060SHuie-Ying.Lee@Sun.COM /* LINTED E_BAD_PTR_CAST_ALIGN */ 8711044SHuie-Ying.Lee@Sun.COM struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; 8811044SHuie-Ying.Lee@Sun.COM 8911044SHuie-Ying.Lee@Sun.COM memset(xa, '\0', sizeof(*xa)); 9011044SHuie-Ying.Lee@Sun.COM 9111044SHuie-Ying.Lee@Sun.COM switch (sa->sa_family) { 9211044SHuie-Ying.Lee@Sun.COM case AF_INET: 9311044SHuie-Ying.Lee@Sun.COM if (slen < sizeof(*in4)) 9411044SHuie-Ying.Lee@Sun.COM return -1; 9511044SHuie-Ying.Lee@Sun.COM xa->af = AF_INET; 9611044SHuie-Ying.Lee@Sun.COM memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4)); 9711044SHuie-Ying.Lee@Sun.COM break; 9811044SHuie-Ying.Lee@Sun.COM case AF_INET6: 9911044SHuie-Ying.Lee@Sun.COM if (slen < sizeof(*in6)) 10011044SHuie-Ying.Lee@Sun.COM return -1; 10111044SHuie-Ying.Lee@Sun.COM xa->af = AF_INET6; 10211044SHuie-Ying.Lee@Sun.COM memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6)); 10311044SHuie-Ying.Lee@Sun.COM #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 10411044SHuie-Ying.Lee@Sun.COM xa->scope_id = in6->sin6_scope_id; 10511044SHuie-Ying.Lee@Sun.COM #endif 10611044SHuie-Ying.Lee@Sun.COM break; 10711044SHuie-Ying.Lee@Sun.COM default: 10811044SHuie-Ying.Lee@Sun.COM return -1; 10911044SHuie-Ying.Lee@Sun.COM } 11011044SHuie-Ying.Lee@Sun.COM 11111044SHuie-Ying.Lee@Sun.COM return 0; 11211044SHuie-Ying.Lee@Sun.COM } 11311044SHuie-Ying.Lee@Sun.COM 11411044SHuie-Ying.Lee@Sun.COM /* 11511044SHuie-Ying.Lee@Sun.COM * Calculate a netmask of length 'l' for address family 'af' and 11611044SHuie-Ying.Lee@Sun.COM * store it in 'n'. 11711044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 11811044SHuie-Ying.Lee@Sun.COM */ 11911044SHuie-Ying.Lee@Sun.COM static int 12011044SHuie-Ying.Lee@Sun.COM addr_netmask(int af, u_int l, struct xaddr *n) 12111044SHuie-Ying.Lee@Sun.COM { 12211044SHuie-Ying.Lee@Sun.COM int i; 12311044SHuie-Ying.Lee@Sun.COM 12411044SHuie-Ying.Lee@Sun.COM if (masklen_valid(af, l) != 0 || n == NULL) 12511044SHuie-Ying.Lee@Sun.COM return -1; 12611044SHuie-Ying.Lee@Sun.COM 12711044SHuie-Ying.Lee@Sun.COM memset(n, '\0', sizeof(*n)); 12811044SHuie-Ying.Lee@Sun.COM switch (af) { 12911044SHuie-Ying.Lee@Sun.COM case AF_INET: 13011044SHuie-Ying.Lee@Sun.COM n->af = AF_INET; 13111044SHuie-Ying.Lee@Sun.COM n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff); 13211044SHuie-Ying.Lee@Sun.COM return 0; 13311044SHuie-Ying.Lee@Sun.COM case AF_INET6: 13411044SHuie-Ying.Lee@Sun.COM n->af = AF_INET6; 13511044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4 && l >= 32; i++, l -= 32) 13611044SHuie-Ying.Lee@Sun.COM n->addr32[i] = 0xffffffffU; 13711044SHuie-Ying.Lee@Sun.COM if (i < 4 && l != 0) 13811044SHuie-Ying.Lee@Sun.COM n->addr32[i] = htonl((0xffffffff << (32 - l)) & 13911044SHuie-Ying.Lee@Sun.COM 0xffffffff); 14011044SHuie-Ying.Lee@Sun.COM return 0; 14111044SHuie-Ying.Lee@Sun.COM default: 14211044SHuie-Ying.Lee@Sun.COM return -1; 14311044SHuie-Ying.Lee@Sun.COM } 14411044SHuie-Ying.Lee@Sun.COM } 14511044SHuie-Ying.Lee@Sun.COM 14611044SHuie-Ying.Lee@Sun.COM /* 14711044SHuie-Ying.Lee@Sun.COM * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'. 14811044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 14911044SHuie-Ying.Lee@Sun.COM */ 15011044SHuie-Ying.Lee@Sun.COM static int 15111044SHuie-Ying.Lee@Sun.COM addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b) 15211044SHuie-Ying.Lee@Sun.COM { 15311044SHuie-Ying.Lee@Sun.COM int i; 15411044SHuie-Ying.Lee@Sun.COM 15511044SHuie-Ying.Lee@Sun.COM if (dst == NULL || a == NULL || b == NULL || a->af != b->af) 15611044SHuie-Ying.Lee@Sun.COM return -1; 15711044SHuie-Ying.Lee@Sun.COM 15811044SHuie-Ying.Lee@Sun.COM memcpy(dst, a, sizeof(*dst)); 15911044SHuie-Ying.Lee@Sun.COM switch (a->af) { 16011044SHuie-Ying.Lee@Sun.COM case AF_INET: 16111044SHuie-Ying.Lee@Sun.COM dst->v4.s_addr &= b->v4.s_addr; 16211044SHuie-Ying.Lee@Sun.COM return 0; 16311044SHuie-Ying.Lee@Sun.COM case AF_INET6: 16411044SHuie-Ying.Lee@Sun.COM dst->scope_id = a->scope_id; 16511044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4; i++) 16611044SHuie-Ying.Lee@Sun.COM dst->addr32[i] &= b->addr32[i]; 16711044SHuie-Ying.Lee@Sun.COM return 0; 16811044SHuie-Ying.Lee@Sun.COM default: 16911044SHuie-Ying.Lee@Sun.COM return -1; 17011044SHuie-Ying.Lee@Sun.COM } 17111044SHuie-Ying.Lee@Sun.COM } 17211044SHuie-Ying.Lee@Sun.COM 17311044SHuie-Ying.Lee@Sun.COM /* 17411044SHuie-Ying.Lee@Sun.COM * Compare addresses 'a' and 'b' 17511044SHuie-Ying.Lee@Sun.COM * Return 0 if addresses are identical, -1 if (a < b) or 1 if (a > b) 17611044SHuie-Ying.Lee@Sun.COM */ 17711044SHuie-Ying.Lee@Sun.COM static int 17811044SHuie-Ying.Lee@Sun.COM addr_cmp(const struct xaddr *a, const struct xaddr *b) 17911044SHuie-Ying.Lee@Sun.COM { 18011044SHuie-Ying.Lee@Sun.COM int i; 18111044SHuie-Ying.Lee@Sun.COM 18211044SHuie-Ying.Lee@Sun.COM if (a->af != b->af) 18311044SHuie-Ying.Lee@Sun.COM return a->af == AF_INET6 ? 1 : -1; 18411044SHuie-Ying.Lee@Sun.COM 18511044SHuie-Ying.Lee@Sun.COM switch (a->af) { 18611044SHuie-Ying.Lee@Sun.COM case AF_INET: 18711044SHuie-Ying.Lee@Sun.COM if (a->v4.s_addr == b->v4.s_addr) 18811044SHuie-Ying.Lee@Sun.COM return 0; 18911044SHuie-Ying.Lee@Sun.COM return ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1; 19011044SHuie-Ying.Lee@Sun.COM case AF_INET6: 19111044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 16; i++) 19211044SHuie-Ying.Lee@Sun.COM if (a->addr8[i] - b->addr8[i] != 0) 19311044SHuie-Ying.Lee@Sun.COM return a->addr8[i] > b->addr8[i] ? 1 : -1; 19411044SHuie-Ying.Lee@Sun.COM if (a->scope_id == b->scope_id) 19511044SHuie-Ying.Lee@Sun.COM return 0; 19611044SHuie-Ying.Lee@Sun.COM return a->scope_id > b->scope_id ? 1 : -1; 19711044SHuie-Ying.Lee@Sun.COM default: 19811044SHuie-Ying.Lee@Sun.COM return -1; 19911044SHuie-Ying.Lee@Sun.COM } 20011044SHuie-Ying.Lee@Sun.COM } 20111044SHuie-Ying.Lee@Sun.COM 20211044SHuie-Ying.Lee@Sun.COM /* 20311044SHuie-Ying.Lee@Sun.COM * Parse string address 'p' into 'n' 20411044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 20511044SHuie-Ying.Lee@Sun.COM */ 20611044SHuie-Ying.Lee@Sun.COM static int 20711044SHuie-Ying.Lee@Sun.COM addr_pton(const char *p, struct xaddr *n) 20811044SHuie-Ying.Lee@Sun.COM { 20911044SHuie-Ying.Lee@Sun.COM struct addrinfo hints, *ai; 21011044SHuie-Ying.Lee@Sun.COM 21111044SHuie-Ying.Lee@Sun.COM memset(&hints, '\0', sizeof(hints)); 21211044SHuie-Ying.Lee@Sun.COM hints.ai_flags = AI_NUMERICHOST; 21311044SHuie-Ying.Lee@Sun.COM 21411044SHuie-Ying.Lee@Sun.COM if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0) 21511044SHuie-Ying.Lee@Sun.COM return -1; 21611044SHuie-Ying.Lee@Sun.COM 21711044SHuie-Ying.Lee@Sun.COM if (ai == NULL || ai->ai_addr == NULL) 21811044SHuie-Ying.Lee@Sun.COM return -1; 21911044SHuie-Ying.Lee@Sun.COM 22011044SHuie-Ying.Lee@Sun.COM if (n != NULL && 22111044SHuie-Ying.Lee@Sun.COM addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1) { 22211044SHuie-Ying.Lee@Sun.COM freeaddrinfo(ai); 22311044SHuie-Ying.Lee@Sun.COM return -1; 22411044SHuie-Ying.Lee@Sun.COM } 22511044SHuie-Ying.Lee@Sun.COM 22611044SHuie-Ying.Lee@Sun.COM freeaddrinfo(ai); 22711044SHuie-Ying.Lee@Sun.COM return 0; 22811044SHuie-Ying.Lee@Sun.COM } 22911044SHuie-Ying.Lee@Sun.COM 23011044SHuie-Ying.Lee@Sun.COM /* 23111044SHuie-Ying.Lee@Sun.COM * Perform bitwise negation of address 23211044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 23311044SHuie-Ying.Lee@Sun.COM */ 23411044SHuie-Ying.Lee@Sun.COM static int 23511044SHuie-Ying.Lee@Sun.COM addr_invert(struct xaddr *n) 23611044SHuie-Ying.Lee@Sun.COM { 23711044SHuie-Ying.Lee@Sun.COM int i; 23811044SHuie-Ying.Lee@Sun.COM 23911044SHuie-Ying.Lee@Sun.COM if (n == NULL) 24011044SHuie-Ying.Lee@Sun.COM return (-1); 24111044SHuie-Ying.Lee@Sun.COM 24211044SHuie-Ying.Lee@Sun.COM switch (n->af) { 24311044SHuie-Ying.Lee@Sun.COM case AF_INET: 24411044SHuie-Ying.Lee@Sun.COM n->v4.s_addr = ~n->v4.s_addr; 24511044SHuie-Ying.Lee@Sun.COM return (0); 24611044SHuie-Ying.Lee@Sun.COM case AF_INET6: 24711044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4; i++) 24811044SHuie-Ying.Lee@Sun.COM n->addr32[i] = ~n->addr32[i]; 24911044SHuie-Ying.Lee@Sun.COM return (0); 25011044SHuie-Ying.Lee@Sun.COM default: 25111044SHuie-Ying.Lee@Sun.COM return (-1); 25211044SHuie-Ying.Lee@Sun.COM } 25311044SHuie-Ying.Lee@Sun.COM } 25411044SHuie-Ying.Lee@Sun.COM 25511044SHuie-Ying.Lee@Sun.COM /* 25611044SHuie-Ying.Lee@Sun.COM * Calculate a netmask of length 'l' for address family 'af' and 25711044SHuie-Ying.Lee@Sun.COM * store it in 'n'. 25811044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 25911044SHuie-Ying.Lee@Sun.COM */ 26011044SHuie-Ying.Lee@Sun.COM static int 26111044SHuie-Ying.Lee@Sun.COM addr_hostmask(int af, u_int l, struct xaddr *n) 26211044SHuie-Ying.Lee@Sun.COM { 26311044SHuie-Ying.Lee@Sun.COM if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1) 26411044SHuie-Ying.Lee@Sun.COM return (-1); 26511044SHuie-Ying.Lee@Sun.COM return (0); 26611044SHuie-Ying.Lee@Sun.COM } 26711044SHuie-Ying.Lee@Sun.COM 26811044SHuie-Ying.Lee@Sun.COM /* 26911044SHuie-Ying.Lee@Sun.COM * Test whether address 'a' is all zeros (i.e. 0.0.0.0 or ::) 27011044SHuie-Ying.Lee@Sun.COM * Returns 0 on if address is all-zeros, -1 if not all zeros or on failure. 27111044SHuie-Ying.Lee@Sun.COM */ 27211044SHuie-Ying.Lee@Sun.COM static int 27311044SHuie-Ying.Lee@Sun.COM addr_is_all0s(const struct xaddr *a) 27411044SHuie-Ying.Lee@Sun.COM { 27511044SHuie-Ying.Lee@Sun.COM int i; 27611044SHuie-Ying.Lee@Sun.COM 27711044SHuie-Ying.Lee@Sun.COM switch (a->af) { 27811044SHuie-Ying.Lee@Sun.COM case AF_INET: 27911044SHuie-Ying.Lee@Sun.COM return (a->v4.s_addr == 0 ? 0 : -1); 28011044SHuie-Ying.Lee@Sun.COM case AF_INET6:; 28111044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4; i++) 28211044SHuie-Ying.Lee@Sun.COM if (a->addr32[i] != 0) 28311044SHuie-Ying.Lee@Sun.COM return (-1); 28411044SHuie-Ying.Lee@Sun.COM return (0); 28511044SHuie-Ying.Lee@Sun.COM default: 28611044SHuie-Ying.Lee@Sun.COM return (-1); 28711044SHuie-Ying.Lee@Sun.COM } 28811044SHuie-Ying.Lee@Sun.COM } 28911044SHuie-Ying.Lee@Sun.COM 29011044SHuie-Ying.Lee@Sun.COM /* 29111044SHuie-Ying.Lee@Sun.COM * Test whether host portion of address 'a', as determined by 'masklen' 29211044SHuie-Ying.Lee@Sun.COM * is all zeros. 29311044SHuie-Ying.Lee@Sun.COM * Returns 0 on if host portion of address is all-zeros, 29411044SHuie-Ying.Lee@Sun.COM * -1 if not all zeros or on failure. 29511044SHuie-Ying.Lee@Sun.COM */ 29611044SHuie-Ying.Lee@Sun.COM static int 29711044SHuie-Ying.Lee@Sun.COM addr_host_is_all0s(const struct xaddr *a, u_int masklen) 29811044SHuie-Ying.Lee@Sun.COM { 29911044SHuie-Ying.Lee@Sun.COM struct xaddr tmp_addr, tmp_mask, tmp_result; 30011044SHuie-Ying.Lee@Sun.COM 30111044SHuie-Ying.Lee@Sun.COM memcpy(&tmp_addr, a, sizeof(tmp_addr)); 30211044SHuie-Ying.Lee@Sun.COM if (addr_hostmask(a->af, masklen, &tmp_mask) == -1) 30311044SHuie-Ying.Lee@Sun.COM return (-1); 30411044SHuie-Ying.Lee@Sun.COM if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1) 30511044SHuie-Ying.Lee@Sun.COM return (-1); 30611044SHuie-Ying.Lee@Sun.COM return (addr_is_all0s(&tmp_result)); 30711044SHuie-Ying.Lee@Sun.COM } 30811044SHuie-Ying.Lee@Sun.COM 30911044SHuie-Ying.Lee@Sun.COM /* 31011044SHuie-Ying.Lee@Sun.COM * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z). 31111044SHuie-Ying.Lee@Sun.COM * Return -1 on parse error, -2 on inconsistency or 0 on success. 31211044SHuie-Ying.Lee@Sun.COM */ 31311044SHuie-Ying.Lee@Sun.COM static int 31411044SHuie-Ying.Lee@Sun.COM addr_pton_cidr(const char *p, struct xaddr *n, u_int *l) 31511044SHuie-Ying.Lee@Sun.COM { 31611044SHuie-Ying.Lee@Sun.COM struct xaddr tmp; 31711044SHuie-Ying.Lee@Sun.COM long unsigned int masklen = 999; 31811044SHuie-Ying.Lee@Sun.COM char addrbuf[64], *mp, *cp; 31911044SHuie-Ying.Lee@Sun.COM 32011044SHuie-Ying.Lee@Sun.COM /* Don't modify argument */ 32111044SHuie-Ying.Lee@Sun.COM if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) > sizeof(addrbuf)) 32211044SHuie-Ying.Lee@Sun.COM return -1; 32311044SHuie-Ying.Lee@Sun.COM 32411044SHuie-Ying.Lee@Sun.COM if ((mp = strchr(addrbuf, '/')) != NULL) { 32511044SHuie-Ying.Lee@Sun.COM *mp = '\0'; 32611044SHuie-Ying.Lee@Sun.COM mp++; 32711044SHuie-Ying.Lee@Sun.COM masklen = strtoul(mp, &cp, 10); 32811044SHuie-Ying.Lee@Sun.COM if (*mp == '\0' || *cp != '\0' || masklen > 128) 32911044SHuie-Ying.Lee@Sun.COM return -1; 33011044SHuie-Ying.Lee@Sun.COM } 33111044SHuie-Ying.Lee@Sun.COM 33211044SHuie-Ying.Lee@Sun.COM if (addr_pton(addrbuf, &tmp) == -1) 33311044SHuie-Ying.Lee@Sun.COM return -1; 33411044SHuie-Ying.Lee@Sun.COM 33511044SHuie-Ying.Lee@Sun.COM if (mp == NULL) 33611044SHuie-Ying.Lee@Sun.COM masklen = addr_unicast_masklen(tmp.af); 33711044SHuie-Ying.Lee@Sun.COM if (masklen_valid(tmp.af, masklen) == -1) 33811044SHuie-Ying.Lee@Sun.COM return -2; 33911044SHuie-Ying.Lee@Sun.COM if (addr_host_is_all0s(&tmp, masklen) != 0) 34011044SHuie-Ying.Lee@Sun.COM return -2; 34111044SHuie-Ying.Lee@Sun.COM 34211044SHuie-Ying.Lee@Sun.COM if (n != NULL) 34311044SHuie-Ying.Lee@Sun.COM memcpy(n, &tmp, sizeof(*n)); 34411044SHuie-Ying.Lee@Sun.COM if (l != NULL) 34511044SHuie-Ying.Lee@Sun.COM *l = masklen; 34611044SHuie-Ying.Lee@Sun.COM 34711044SHuie-Ying.Lee@Sun.COM return 0; 34811044SHuie-Ying.Lee@Sun.COM } 34911044SHuie-Ying.Lee@Sun.COM 35011044SHuie-Ying.Lee@Sun.COM static int 35111044SHuie-Ying.Lee@Sun.COM addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen) 35211044SHuie-Ying.Lee@Sun.COM { 35311044SHuie-Ying.Lee@Sun.COM struct xaddr tmp_mask, tmp_result; 35411044SHuie-Ying.Lee@Sun.COM 35511044SHuie-Ying.Lee@Sun.COM if (host->af != net->af) 35611044SHuie-Ying.Lee@Sun.COM return -1; 35711044SHuie-Ying.Lee@Sun.COM 35811044SHuie-Ying.Lee@Sun.COM if (addr_netmask(host->af, masklen, &tmp_mask) == -1) 35911044SHuie-Ying.Lee@Sun.COM return -1; 36011044SHuie-Ying.Lee@Sun.COM if (addr_and(&tmp_result, host, &tmp_mask) == -1) 36111044SHuie-Ying.Lee@Sun.COM return -1; 36211044SHuie-Ying.Lee@Sun.COM return addr_cmp(&tmp_result, net); 36311044SHuie-Ying.Lee@Sun.COM } 36411044SHuie-Ying.Lee@Sun.COM 36511044SHuie-Ying.Lee@Sun.COM /* 36611044SHuie-Ying.Lee@Sun.COM * Match "addr" against list pattern list "_list", which may contain a 36711044SHuie-Ying.Lee@Sun.COM * mix of CIDR addresses and old-school wildcards. 36811044SHuie-Ying.Lee@Sun.COM * 36911044SHuie-Ying.Lee@Sun.COM * If addr is NULL, then no matching is performed, but _list is parsed 37011044SHuie-Ying.Lee@Sun.COM * and checked for well-formedness. 37111044SHuie-Ying.Lee@Sun.COM * 37211044SHuie-Ying.Lee@Sun.COM * Returns 1 on match found (never returned when addr == NULL). 37311044SHuie-Ying.Lee@Sun.COM * Returns 0 on if no match found, or no errors found when addr == NULL. 37411044SHuie-Ying.Lee@Sun.COM * Returns -1 on negated match found (never returned when addr == NULL). 37511044SHuie-Ying.Lee@Sun.COM * Returns -2 on invalid list entry. 37611044SHuie-Ying.Lee@Sun.COM */ 37711044SHuie-Ying.Lee@Sun.COM int 37811044SHuie-Ying.Lee@Sun.COM addr_match_list(const char *addr, const char *_list) 37911044SHuie-Ying.Lee@Sun.COM { 38011044SHuie-Ying.Lee@Sun.COM char *list, *cp, *o; 38111044SHuie-Ying.Lee@Sun.COM struct xaddr try_addr, match_addr; 38211044SHuie-Ying.Lee@Sun.COM u_int masklen, neg; 38311044SHuie-Ying.Lee@Sun.COM int ret = 0, r; 38411044SHuie-Ying.Lee@Sun.COM 38511044SHuie-Ying.Lee@Sun.COM if (addr != NULL && addr_pton(addr, &try_addr) != 0) { 38611044SHuie-Ying.Lee@Sun.COM debug2("%s: couldn't parse address %.100s", __func__, addr); 38711044SHuie-Ying.Lee@Sun.COM return 0; 38811044SHuie-Ying.Lee@Sun.COM } 38911044SHuie-Ying.Lee@Sun.COM if ((o = list = strdup(_list)) == NULL) 39011044SHuie-Ying.Lee@Sun.COM return -1; 39111044SHuie-Ying.Lee@Sun.COM while ((cp = strsep(&list, ",")) != NULL) { 39211044SHuie-Ying.Lee@Sun.COM neg = *cp == '!'; 39311044SHuie-Ying.Lee@Sun.COM if (neg) 39411044SHuie-Ying.Lee@Sun.COM cp++; 39511044SHuie-Ying.Lee@Sun.COM if (*cp == '\0') { 39611044SHuie-Ying.Lee@Sun.COM ret = -2; 39711044SHuie-Ying.Lee@Sun.COM break; 39811044SHuie-Ying.Lee@Sun.COM } 39911044SHuie-Ying.Lee@Sun.COM /* Prefer CIDR address matching */ 40011044SHuie-Ying.Lee@Sun.COM r = addr_pton_cidr(cp, &match_addr, &masklen); 40111044SHuie-Ying.Lee@Sun.COM if (r == -2) { 40211044SHuie-Ying.Lee@Sun.COM error("Inconsistent mask length for " 40311044SHuie-Ying.Lee@Sun.COM "network \"%.100s\"", cp); 40411044SHuie-Ying.Lee@Sun.COM ret = -2; 40511044SHuie-Ying.Lee@Sun.COM break; 40611044SHuie-Ying.Lee@Sun.COM } else if (r == 0) { 40711044SHuie-Ying.Lee@Sun.COM if (addr != NULL && addr_netmatch(&try_addr, 40811044SHuie-Ying.Lee@Sun.COM &match_addr, masklen) == 0) { 40911044SHuie-Ying.Lee@Sun.COM foundit: 41011044SHuie-Ying.Lee@Sun.COM if (neg) { 41111044SHuie-Ying.Lee@Sun.COM ret = -1; 41211044SHuie-Ying.Lee@Sun.COM break; 41311044SHuie-Ying.Lee@Sun.COM } 41411044SHuie-Ying.Lee@Sun.COM ret = 1; 41511044SHuie-Ying.Lee@Sun.COM } 41611044SHuie-Ying.Lee@Sun.COM continue; 41711044SHuie-Ying.Lee@Sun.COM } else { 41811044SHuie-Ying.Lee@Sun.COM /* If CIDR parse failed, try wildcard string match */ 41911044SHuie-Ying.Lee@Sun.COM if (addr != NULL && match_pattern(addr, cp) == 1) 42011044SHuie-Ying.Lee@Sun.COM goto foundit; 42111044SHuie-Ying.Lee@Sun.COM } 42211044SHuie-Ying.Lee@Sun.COM } 42311044SHuie-Ying.Lee@Sun.COM xfree(o); 42411044SHuie-Ying.Lee@Sun.COM 42511044SHuie-Ying.Lee@Sun.COM return ret; 42611044SHuie-Ying.Lee@Sun.COM } 427