1*11044SHuie-Ying.Lee@Sun.COM /* $OpenBSD: addrmatch.c,v 1.4 2008/12/10 03:55:20 stevesk Exp $ */ 2*11044SHuie-Ying.Lee@Sun.COM 3*11044SHuie-Ying.Lee@Sun.COM /* 4*11044SHuie-Ying.Lee@Sun.COM * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org> 5*11044SHuie-Ying.Lee@Sun.COM * 6*11044SHuie-Ying.Lee@Sun.COM * Permission to use, copy, modify, and distribute this software for any 7*11044SHuie-Ying.Lee@Sun.COM * purpose with or without fee is hereby granted, provided that the above 8*11044SHuie-Ying.Lee@Sun.COM * copyright notice and this permission notice appear in all copies. 9*11044SHuie-Ying.Lee@Sun.COM * 10*11044SHuie-Ying.Lee@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*11044SHuie-Ying.Lee@Sun.COM * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*11044SHuie-Ying.Lee@Sun.COM * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*11044SHuie-Ying.Lee@Sun.COM * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*11044SHuie-Ying.Lee@Sun.COM * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*11044SHuie-Ying.Lee@Sun.COM * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*11044SHuie-Ying.Lee@Sun.COM * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*11044SHuie-Ying.Lee@Sun.COM */ 18*11044SHuie-Ying.Lee@Sun.COM 19*11044SHuie-Ying.Lee@Sun.COM #include "includes.h" 20*11044SHuie-Ying.Lee@Sun.COM 21*11044SHuie-Ying.Lee@Sun.COM #include <sys/types.h> 22*11044SHuie-Ying.Lee@Sun.COM #include <sys/socket.h> 23*11044SHuie-Ying.Lee@Sun.COM #include <netinet/in.h> 24*11044SHuie-Ying.Lee@Sun.COM #include <arpa/inet.h> 25*11044SHuie-Ying.Lee@Sun.COM 26*11044SHuie-Ying.Lee@Sun.COM #include <netdb.h> 27*11044SHuie-Ying.Lee@Sun.COM #include <string.h> 28*11044SHuie-Ying.Lee@Sun.COM #include <stdlib.h> 29*11044SHuie-Ying.Lee@Sun.COM #include <stdio.h> 30*11044SHuie-Ying.Lee@Sun.COM #include <stdarg.h> 31*11044SHuie-Ying.Lee@Sun.COM 32*11044SHuie-Ying.Lee@Sun.COM #include "match.h" 33*11044SHuie-Ying.Lee@Sun.COM #include "log.h" 34*11044SHuie-Ying.Lee@Sun.COM #include "xmalloc.h" 35*11044SHuie-Ying.Lee@Sun.COM 36*11044SHuie-Ying.Lee@Sun.COM struct xaddr { 37*11044SHuie-Ying.Lee@Sun.COM sa_family_t af; 38*11044SHuie-Ying.Lee@Sun.COM union { 39*11044SHuie-Ying.Lee@Sun.COM struct in_addr v4; 40*11044SHuie-Ying.Lee@Sun.COM struct in6_addr v6; 41*11044SHuie-Ying.Lee@Sun.COM u_int8_t addr8[16]; 42*11044SHuie-Ying.Lee@Sun.COM u_int32_t addr32[4]; 43*11044SHuie-Ying.Lee@Sun.COM } xa; /* 128-bit address */ 44*11044SHuie-Ying.Lee@Sun.COM u_int32_t scope_id; /* iface scope id for v6 */ 45*11044SHuie-Ying.Lee@Sun.COM #define v4 xa.v4 46*11044SHuie-Ying.Lee@Sun.COM #define v6 xa.v6 47*11044SHuie-Ying.Lee@Sun.COM #define addr8 xa.addr8 48*11044SHuie-Ying.Lee@Sun.COM #define addr32 xa.addr32 49*11044SHuie-Ying.Lee@Sun.COM }; 50*11044SHuie-Ying.Lee@Sun.COM 51*11044SHuie-Ying.Lee@Sun.COM static int 52*11044SHuie-Ying.Lee@Sun.COM addr_unicast_masklen(int af) 53*11044SHuie-Ying.Lee@Sun.COM { 54*11044SHuie-Ying.Lee@Sun.COM switch (af) { 55*11044SHuie-Ying.Lee@Sun.COM case AF_INET: 56*11044SHuie-Ying.Lee@Sun.COM return 32; 57*11044SHuie-Ying.Lee@Sun.COM case AF_INET6: 58*11044SHuie-Ying.Lee@Sun.COM return 128; 59*11044SHuie-Ying.Lee@Sun.COM default: 60*11044SHuie-Ying.Lee@Sun.COM return -1; 61*11044SHuie-Ying.Lee@Sun.COM } 62*11044SHuie-Ying.Lee@Sun.COM } 63*11044SHuie-Ying.Lee@Sun.COM 64*11044SHuie-Ying.Lee@Sun.COM static inline int 65*11044SHuie-Ying.Lee@Sun.COM masklen_valid(int af, u_int masklen) 66*11044SHuie-Ying.Lee@Sun.COM { 67*11044SHuie-Ying.Lee@Sun.COM switch (af) { 68*11044SHuie-Ying.Lee@Sun.COM case AF_INET: 69*11044SHuie-Ying.Lee@Sun.COM return masklen <= 32 ? 0 : -1; 70*11044SHuie-Ying.Lee@Sun.COM case AF_INET6: 71*11044SHuie-Ying.Lee@Sun.COM return masklen <= 128 ? 0 : -1; 72*11044SHuie-Ying.Lee@Sun.COM default: 73*11044SHuie-Ying.Lee@Sun.COM return -1; 74*11044SHuie-Ying.Lee@Sun.COM } 75*11044SHuie-Ying.Lee@Sun.COM } 76*11044SHuie-Ying.Lee@Sun.COM 77*11044SHuie-Ying.Lee@Sun.COM /* 78*11044SHuie-Ying.Lee@Sun.COM * Convert struct sockaddr to struct xaddr 79*11044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 80*11044SHuie-Ying.Lee@Sun.COM */ 81*11044SHuie-Ying.Lee@Sun.COM static int 82*11044SHuie-Ying.Lee@Sun.COM addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa) 83*11044SHuie-Ying.Lee@Sun.COM { 84*11044SHuie-Ying.Lee@Sun.COM struct sockaddr_in *in4 = (struct sockaddr_in *)sa; 85*11044SHuie-Ying.Lee@Sun.COM struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; 86*11044SHuie-Ying.Lee@Sun.COM 87*11044SHuie-Ying.Lee@Sun.COM memset(xa, '\0', sizeof(*xa)); 88*11044SHuie-Ying.Lee@Sun.COM 89*11044SHuie-Ying.Lee@Sun.COM switch (sa->sa_family) { 90*11044SHuie-Ying.Lee@Sun.COM case AF_INET: 91*11044SHuie-Ying.Lee@Sun.COM if (slen < sizeof(*in4)) 92*11044SHuie-Ying.Lee@Sun.COM return -1; 93*11044SHuie-Ying.Lee@Sun.COM xa->af = AF_INET; 94*11044SHuie-Ying.Lee@Sun.COM memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4)); 95*11044SHuie-Ying.Lee@Sun.COM break; 96*11044SHuie-Ying.Lee@Sun.COM case AF_INET6: 97*11044SHuie-Ying.Lee@Sun.COM if (slen < sizeof(*in6)) 98*11044SHuie-Ying.Lee@Sun.COM return -1; 99*11044SHuie-Ying.Lee@Sun.COM xa->af = AF_INET6; 100*11044SHuie-Ying.Lee@Sun.COM memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6)); 101*11044SHuie-Ying.Lee@Sun.COM #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 102*11044SHuie-Ying.Lee@Sun.COM xa->scope_id = in6->sin6_scope_id; 103*11044SHuie-Ying.Lee@Sun.COM #endif 104*11044SHuie-Ying.Lee@Sun.COM break; 105*11044SHuie-Ying.Lee@Sun.COM default: 106*11044SHuie-Ying.Lee@Sun.COM return -1; 107*11044SHuie-Ying.Lee@Sun.COM } 108*11044SHuie-Ying.Lee@Sun.COM 109*11044SHuie-Ying.Lee@Sun.COM return 0; 110*11044SHuie-Ying.Lee@Sun.COM } 111*11044SHuie-Ying.Lee@Sun.COM 112*11044SHuie-Ying.Lee@Sun.COM /* 113*11044SHuie-Ying.Lee@Sun.COM * Calculate a netmask of length 'l' for address family 'af' and 114*11044SHuie-Ying.Lee@Sun.COM * store it in 'n'. 115*11044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 116*11044SHuie-Ying.Lee@Sun.COM */ 117*11044SHuie-Ying.Lee@Sun.COM static int 118*11044SHuie-Ying.Lee@Sun.COM addr_netmask(int af, u_int l, struct xaddr *n) 119*11044SHuie-Ying.Lee@Sun.COM { 120*11044SHuie-Ying.Lee@Sun.COM int i; 121*11044SHuie-Ying.Lee@Sun.COM 122*11044SHuie-Ying.Lee@Sun.COM if (masklen_valid(af, l) != 0 || n == NULL) 123*11044SHuie-Ying.Lee@Sun.COM return -1; 124*11044SHuie-Ying.Lee@Sun.COM 125*11044SHuie-Ying.Lee@Sun.COM memset(n, '\0', sizeof(*n)); 126*11044SHuie-Ying.Lee@Sun.COM switch (af) { 127*11044SHuie-Ying.Lee@Sun.COM case AF_INET: 128*11044SHuie-Ying.Lee@Sun.COM n->af = AF_INET; 129*11044SHuie-Ying.Lee@Sun.COM n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff); 130*11044SHuie-Ying.Lee@Sun.COM return 0; 131*11044SHuie-Ying.Lee@Sun.COM case AF_INET6: 132*11044SHuie-Ying.Lee@Sun.COM n->af = AF_INET6; 133*11044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4 && l >= 32; i++, l -= 32) 134*11044SHuie-Ying.Lee@Sun.COM n->addr32[i] = 0xffffffffU; 135*11044SHuie-Ying.Lee@Sun.COM if (i < 4 && l != 0) 136*11044SHuie-Ying.Lee@Sun.COM n->addr32[i] = htonl((0xffffffff << (32 - l)) & 137*11044SHuie-Ying.Lee@Sun.COM 0xffffffff); 138*11044SHuie-Ying.Lee@Sun.COM return 0; 139*11044SHuie-Ying.Lee@Sun.COM default: 140*11044SHuie-Ying.Lee@Sun.COM return -1; 141*11044SHuie-Ying.Lee@Sun.COM } 142*11044SHuie-Ying.Lee@Sun.COM } 143*11044SHuie-Ying.Lee@Sun.COM 144*11044SHuie-Ying.Lee@Sun.COM /* 145*11044SHuie-Ying.Lee@Sun.COM * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'. 146*11044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 147*11044SHuie-Ying.Lee@Sun.COM */ 148*11044SHuie-Ying.Lee@Sun.COM static int 149*11044SHuie-Ying.Lee@Sun.COM addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b) 150*11044SHuie-Ying.Lee@Sun.COM { 151*11044SHuie-Ying.Lee@Sun.COM int i; 152*11044SHuie-Ying.Lee@Sun.COM 153*11044SHuie-Ying.Lee@Sun.COM if (dst == NULL || a == NULL || b == NULL || a->af != b->af) 154*11044SHuie-Ying.Lee@Sun.COM return -1; 155*11044SHuie-Ying.Lee@Sun.COM 156*11044SHuie-Ying.Lee@Sun.COM memcpy(dst, a, sizeof(*dst)); 157*11044SHuie-Ying.Lee@Sun.COM switch (a->af) { 158*11044SHuie-Ying.Lee@Sun.COM case AF_INET: 159*11044SHuie-Ying.Lee@Sun.COM dst->v4.s_addr &= b->v4.s_addr; 160*11044SHuie-Ying.Lee@Sun.COM return 0; 161*11044SHuie-Ying.Lee@Sun.COM case AF_INET6: 162*11044SHuie-Ying.Lee@Sun.COM dst->scope_id = a->scope_id; 163*11044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4; i++) 164*11044SHuie-Ying.Lee@Sun.COM dst->addr32[i] &= b->addr32[i]; 165*11044SHuie-Ying.Lee@Sun.COM return 0; 166*11044SHuie-Ying.Lee@Sun.COM default: 167*11044SHuie-Ying.Lee@Sun.COM return -1; 168*11044SHuie-Ying.Lee@Sun.COM } 169*11044SHuie-Ying.Lee@Sun.COM } 170*11044SHuie-Ying.Lee@Sun.COM 171*11044SHuie-Ying.Lee@Sun.COM /* 172*11044SHuie-Ying.Lee@Sun.COM * Compare addresses 'a' and 'b' 173*11044SHuie-Ying.Lee@Sun.COM * Return 0 if addresses are identical, -1 if (a < b) or 1 if (a > b) 174*11044SHuie-Ying.Lee@Sun.COM */ 175*11044SHuie-Ying.Lee@Sun.COM static int 176*11044SHuie-Ying.Lee@Sun.COM addr_cmp(const struct xaddr *a, const struct xaddr *b) 177*11044SHuie-Ying.Lee@Sun.COM { 178*11044SHuie-Ying.Lee@Sun.COM int i; 179*11044SHuie-Ying.Lee@Sun.COM 180*11044SHuie-Ying.Lee@Sun.COM if (a->af != b->af) 181*11044SHuie-Ying.Lee@Sun.COM return a->af == AF_INET6 ? 1 : -1; 182*11044SHuie-Ying.Lee@Sun.COM 183*11044SHuie-Ying.Lee@Sun.COM switch (a->af) { 184*11044SHuie-Ying.Lee@Sun.COM case AF_INET: 185*11044SHuie-Ying.Lee@Sun.COM if (a->v4.s_addr == b->v4.s_addr) 186*11044SHuie-Ying.Lee@Sun.COM return 0; 187*11044SHuie-Ying.Lee@Sun.COM return ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1; 188*11044SHuie-Ying.Lee@Sun.COM case AF_INET6: 189*11044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 16; i++) 190*11044SHuie-Ying.Lee@Sun.COM if (a->addr8[i] - b->addr8[i] != 0) 191*11044SHuie-Ying.Lee@Sun.COM return a->addr8[i] > b->addr8[i] ? 1 : -1; 192*11044SHuie-Ying.Lee@Sun.COM if (a->scope_id == b->scope_id) 193*11044SHuie-Ying.Lee@Sun.COM return 0; 194*11044SHuie-Ying.Lee@Sun.COM return a->scope_id > b->scope_id ? 1 : -1; 195*11044SHuie-Ying.Lee@Sun.COM default: 196*11044SHuie-Ying.Lee@Sun.COM return -1; 197*11044SHuie-Ying.Lee@Sun.COM } 198*11044SHuie-Ying.Lee@Sun.COM } 199*11044SHuie-Ying.Lee@Sun.COM 200*11044SHuie-Ying.Lee@Sun.COM /* 201*11044SHuie-Ying.Lee@Sun.COM * Parse string address 'p' into 'n' 202*11044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 203*11044SHuie-Ying.Lee@Sun.COM */ 204*11044SHuie-Ying.Lee@Sun.COM static int 205*11044SHuie-Ying.Lee@Sun.COM addr_pton(const char *p, struct xaddr *n) 206*11044SHuie-Ying.Lee@Sun.COM { 207*11044SHuie-Ying.Lee@Sun.COM struct addrinfo hints, *ai; 208*11044SHuie-Ying.Lee@Sun.COM 209*11044SHuie-Ying.Lee@Sun.COM memset(&hints, '\0', sizeof(hints)); 210*11044SHuie-Ying.Lee@Sun.COM hints.ai_flags = AI_NUMERICHOST; 211*11044SHuie-Ying.Lee@Sun.COM 212*11044SHuie-Ying.Lee@Sun.COM if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0) 213*11044SHuie-Ying.Lee@Sun.COM return -1; 214*11044SHuie-Ying.Lee@Sun.COM 215*11044SHuie-Ying.Lee@Sun.COM if (ai == NULL || ai->ai_addr == NULL) 216*11044SHuie-Ying.Lee@Sun.COM return -1; 217*11044SHuie-Ying.Lee@Sun.COM 218*11044SHuie-Ying.Lee@Sun.COM if (n != NULL && 219*11044SHuie-Ying.Lee@Sun.COM addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1) { 220*11044SHuie-Ying.Lee@Sun.COM freeaddrinfo(ai); 221*11044SHuie-Ying.Lee@Sun.COM return -1; 222*11044SHuie-Ying.Lee@Sun.COM } 223*11044SHuie-Ying.Lee@Sun.COM 224*11044SHuie-Ying.Lee@Sun.COM freeaddrinfo(ai); 225*11044SHuie-Ying.Lee@Sun.COM return 0; 226*11044SHuie-Ying.Lee@Sun.COM } 227*11044SHuie-Ying.Lee@Sun.COM 228*11044SHuie-Ying.Lee@Sun.COM /* 229*11044SHuie-Ying.Lee@Sun.COM * Perform bitwise negation of address 230*11044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 231*11044SHuie-Ying.Lee@Sun.COM */ 232*11044SHuie-Ying.Lee@Sun.COM static int 233*11044SHuie-Ying.Lee@Sun.COM addr_invert(struct xaddr *n) 234*11044SHuie-Ying.Lee@Sun.COM { 235*11044SHuie-Ying.Lee@Sun.COM int i; 236*11044SHuie-Ying.Lee@Sun.COM 237*11044SHuie-Ying.Lee@Sun.COM if (n == NULL) 238*11044SHuie-Ying.Lee@Sun.COM return (-1); 239*11044SHuie-Ying.Lee@Sun.COM 240*11044SHuie-Ying.Lee@Sun.COM switch (n->af) { 241*11044SHuie-Ying.Lee@Sun.COM case AF_INET: 242*11044SHuie-Ying.Lee@Sun.COM n->v4.s_addr = ~n->v4.s_addr; 243*11044SHuie-Ying.Lee@Sun.COM return (0); 244*11044SHuie-Ying.Lee@Sun.COM case AF_INET6: 245*11044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4; i++) 246*11044SHuie-Ying.Lee@Sun.COM n->addr32[i] = ~n->addr32[i]; 247*11044SHuie-Ying.Lee@Sun.COM return (0); 248*11044SHuie-Ying.Lee@Sun.COM default: 249*11044SHuie-Ying.Lee@Sun.COM return (-1); 250*11044SHuie-Ying.Lee@Sun.COM } 251*11044SHuie-Ying.Lee@Sun.COM } 252*11044SHuie-Ying.Lee@Sun.COM 253*11044SHuie-Ying.Lee@Sun.COM /* 254*11044SHuie-Ying.Lee@Sun.COM * Calculate a netmask of length 'l' for address family 'af' and 255*11044SHuie-Ying.Lee@Sun.COM * store it in 'n'. 256*11044SHuie-Ying.Lee@Sun.COM * Returns 0 on success, -1 on failure. 257*11044SHuie-Ying.Lee@Sun.COM */ 258*11044SHuie-Ying.Lee@Sun.COM static int 259*11044SHuie-Ying.Lee@Sun.COM addr_hostmask(int af, u_int l, struct xaddr *n) 260*11044SHuie-Ying.Lee@Sun.COM { 261*11044SHuie-Ying.Lee@Sun.COM if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1) 262*11044SHuie-Ying.Lee@Sun.COM return (-1); 263*11044SHuie-Ying.Lee@Sun.COM return (0); 264*11044SHuie-Ying.Lee@Sun.COM } 265*11044SHuie-Ying.Lee@Sun.COM 266*11044SHuie-Ying.Lee@Sun.COM /* 267*11044SHuie-Ying.Lee@Sun.COM * Test whether address 'a' is all zeros (i.e. 0.0.0.0 or ::) 268*11044SHuie-Ying.Lee@Sun.COM * Returns 0 on if address is all-zeros, -1 if not all zeros or on failure. 269*11044SHuie-Ying.Lee@Sun.COM */ 270*11044SHuie-Ying.Lee@Sun.COM static int 271*11044SHuie-Ying.Lee@Sun.COM addr_is_all0s(const struct xaddr *a) 272*11044SHuie-Ying.Lee@Sun.COM { 273*11044SHuie-Ying.Lee@Sun.COM int i; 274*11044SHuie-Ying.Lee@Sun.COM 275*11044SHuie-Ying.Lee@Sun.COM switch (a->af) { 276*11044SHuie-Ying.Lee@Sun.COM case AF_INET: 277*11044SHuie-Ying.Lee@Sun.COM return (a->v4.s_addr == 0 ? 0 : -1); 278*11044SHuie-Ying.Lee@Sun.COM case AF_INET6:; 279*11044SHuie-Ying.Lee@Sun.COM for (i = 0; i < 4; i++) 280*11044SHuie-Ying.Lee@Sun.COM if (a->addr32[i] != 0) 281*11044SHuie-Ying.Lee@Sun.COM return (-1); 282*11044SHuie-Ying.Lee@Sun.COM return (0); 283*11044SHuie-Ying.Lee@Sun.COM default: 284*11044SHuie-Ying.Lee@Sun.COM return (-1); 285*11044SHuie-Ying.Lee@Sun.COM } 286*11044SHuie-Ying.Lee@Sun.COM } 287*11044SHuie-Ying.Lee@Sun.COM 288*11044SHuie-Ying.Lee@Sun.COM /* 289*11044SHuie-Ying.Lee@Sun.COM * Test whether host portion of address 'a', as determined by 'masklen' 290*11044SHuie-Ying.Lee@Sun.COM * is all zeros. 291*11044SHuie-Ying.Lee@Sun.COM * Returns 0 on if host portion of address is all-zeros, 292*11044SHuie-Ying.Lee@Sun.COM * -1 if not all zeros or on failure. 293*11044SHuie-Ying.Lee@Sun.COM */ 294*11044SHuie-Ying.Lee@Sun.COM static int 295*11044SHuie-Ying.Lee@Sun.COM addr_host_is_all0s(const struct xaddr *a, u_int masklen) 296*11044SHuie-Ying.Lee@Sun.COM { 297*11044SHuie-Ying.Lee@Sun.COM struct xaddr tmp_addr, tmp_mask, tmp_result; 298*11044SHuie-Ying.Lee@Sun.COM 299*11044SHuie-Ying.Lee@Sun.COM memcpy(&tmp_addr, a, sizeof(tmp_addr)); 300*11044SHuie-Ying.Lee@Sun.COM if (addr_hostmask(a->af, masklen, &tmp_mask) == -1) 301*11044SHuie-Ying.Lee@Sun.COM return (-1); 302*11044SHuie-Ying.Lee@Sun.COM if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1) 303*11044SHuie-Ying.Lee@Sun.COM return (-1); 304*11044SHuie-Ying.Lee@Sun.COM return (addr_is_all0s(&tmp_result)); 305*11044SHuie-Ying.Lee@Sun.COM } 306*11044SHuie-Ying.Lee@Sun.COM 307*11044SHuie-Ying.Lee@Sun.COM /* 308*11044SHuie-Ying.Lee@Sun.COM * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z). 309*11044SHuie-Ying.Lee@Sun.COM * Return -1 on parse error, -2 on inconsistency or 0 on success. 310*11044SHuie-Ying.Lee@Sun.COM */ 311*11044SHuie-Ying.Lee@Sun.COM static int 312*11044SHuie-Ying.Lee@Sun.COM addr_pton_cidr(const char *p, struct xaddr *n, u_int *l) 313*11044SHuie-Ying.Lee@Sun.COM { 314*11044SHuie-Ying.Lee@Sun.COM struct xaddr tmp; 315*11044SHuie-Ying.Lee@Sun.COM long unsigned int masklen = 999; 316*11044SHuie-Ying.Lee@Sun.COM char addrbuf[64], *mp, *cp; 317*11044SHuie-Ying.Lee@Sun.COM 318*11044SHuie-Ying.Lee@Sun.COM /* Don't modify argument */ 319*11044SHuie-Ying.Lee@Sun.COM if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) > sizeof(addrbuf)) 320*11044SHuie-Ying.Lee@Sun.COM return -1; 321*11044SHuie-Ying.Lee@Sun.COM 322*11044SHuie-Ying.Lee@Sun.COM if ((mp = strchr(addrbuf, '/')) != NULL) { 323*11044SHuie-Ying.Lee@Sun.COM *mp = '\0'; 324*11044SHuie-Ying.Lee@Sun.COM mp++; 325*11044SHuie-Ying.Lee@Sun.COM masklen = strtoul(mp, &cp, 10); 326*11044SHuie-Ying.Lee@Sun.COM if (*mp == '\0' || *cp != '\0' || masklen > 128) 327*11044SHuie-Ying.Lee@Sun.COM return -1; 328*11044SHuie-Ying.Lee@Sun.COM } 329*11044SHuie-Ying.Lee@Sun.COM 330*11044SHuie-Ying.Lee@Sun.COM if (addr_pton(addrbuf, &tmp) == -1) 331*11044SHuie-Ying.Lee@Sun.COM return -1; 332*11044SHuie-Ying.Lee@Sun.COM 333*11044SHuie-Ying.Lee@Sun.COM if (mp == NULL) 334*11044SHuie-Ying.Lee@Sun.COM masklen = addr_unicast_masklen(tmp.af); 335*11044SHuie-Ying.Lee@Sun.COM if (masklen_valid(tmp.af, masklen) == -1) 336*11044SHuie-Ying.Lee@Sun.COM return -2; 337*11044SHuie-Ying.Lee@Sun.COM if (addr_host_is_all0s(&tmp, masklen) != 0) 338*11044SHuie-Ying.Lee@Sun.COM return -2; 339*11044SHuie-Ying.Lee@Sun.COM 340*11044SHuie-Ying.Lee@Sun.COM if (n != NULL) 341*11044SHuie-Ying.Lee@Sun.COM memcpy(n, &tmp, sizeof(*n)); 342*11044SHuie-Ying.Lee@Sun.COM if (l != NULL) 343*11044SHuie-Ying.Lee@Sun.COM *l = masklen; 344*11044SHuie-Ying.Lee@Sun.COM 345*11044SHuie-Ying.Lee@Sun.COM return 0; 346*11044SHuie-Ying.Lee@Sun.COM } 347*11044SHuie-Ying.Lee@Sun.COM 348*11044SHuie-Ying.Lee@Sun.COM static int 349*11044SHuie-Ying.Lee@Sun.COM addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen) 350*11044SHuie-Ying.Lee@Sun.COM { 351*11044SHuie-Ying.Lee@Sun.COM struct xaddr tmp_mask, tmp_result; 352*11044SHuie-Ying.Lee@Sun.COM 353*11044SHuie-Ying.Lee@Sun.COM if (host->af != net->af) 354*11044SHuie-Ying.Lee@Sun.COM return -1; 355*11044SHuie-Ying.Lee@Sun.COM 356*11044SHuie-Ying.Lee@Sun.COM if (addr_netmask(host->af, masklen, &tmp_mask) == -1) 357*11044SHuie-Ying.Lee@Sun.COM return -1; 358*11044SHuie-Ying.Lee@Sun.COM if (addr_and(&tmp_result, host, &tmp_mask) == -1) 359*11044SHuie-Ying.Lee@Sun.COM return -1; 360*11044SHuie-Ying.Lee@Sun.COM return addr_cmp(&tmp_result, net); 361*11044SHuie-Ying.Lee@Sun.COM } 362*11044SHuie-Ying.Lee@Sun.COM 363*11044SHuie-Ying.Lee@Sun.COM /* 364*11044SHuie-Ying.Lee@Sun.COM * Match "addr" against list pattern list "_list", which may contain a 365*11044SHuie-Ying.Lee@Sun.COM * mix of CIDR addresses and old-school wildcards. 366*11044SHuie-Ying.Lee@Sun.COM * 367*11044SHuie-Ying.Lee@Sun.COM * If addr is NULL, then no matching is performed, but _list is parsed 368*11044SHuie-Ying.Lee@Sun.COM * and checked for well-formedness. 369*11044SHuie-Ying.Lee@Sun.COM * 370*11044SHuie-Ying.Lee@Sun.COM * Returns 1 on match found (never returned when addr == NULL). 371*11044SHuie-Ying.Lee@Sun.COM * Returns 0 on if no match found, or no errors found when addr == NULL. 372*11044SHuie-Ying.Lee@Sun.COM * Returns -1 on negated match found (never returned when addr == NULL). 373*11044SHuie-Ying.Lee@Sun.COM * Returns -2 on invalid list entry. 374*11044SHuie-Ying.Lee@Sun.COM */ 375*11044SHuie-Ying.Lee@Sun.COM int 376*11044SHuie-Ying.Lee@Sun.COM addr_match_list(const char *addr, const char *_list) 377*11044SHuie-Ying.Lee@Sun.COM { 378*11044SHuie-Ying.Lee@Sun.COM char *list, *cp, *o; 379*11044SHuie-Ying.Lee@Sun.COM struct xaddr try_addr, match_addr; 380*11044SHuie-Ying.Lee@Sun.COM u_int masklen, neg; 381*11044SHuie-Ying.Lee@Sun.COM int ret = 0, r; 382*11044SHuie-Ying.Lee@Sun.COM 383*11044SHuie-Ying.Lee@Sun.COM if (addr != NULL && addr_pton(addr, &try_addr) != 0) { 384*11044SHuie-Ying.Lee@Sun.COM debug2("%s: couldn't parse address %.100s", __func__, addr); 385*11044SHuie-Ying.Lee@Sun.COM return 0; 386*11044SHuie-Ying.Lee@Sun.COM } 387*11044SHuie-Ying.Lee@Sun.COM if ((o = list = strdup(_list)) == NULL) 388*11044SHuie-Ying.Lee@Sun.COM return -1; 389*11044SHuie-Ying.Lee@Sun.COM while ((cp = strsep(&list, ",")) != NULL) { 390*11044SHuie-Ying.Lee@Sun.COM neg = *cp == '!'; 391*11044SHuie-Ying.Lee@Sun.COM if (neg) 392*11044SHuie-Ying.Lee@Sun.COM cp++; 393*11044SHuie-Ying.Lee@Sun.COM if (*cp == '\0') { 394*11044SHuie-Ying.Lee@Sun.COM ret = -2; 395*11044SHuie-Ying.Lee@Sun.COM break; 396*11044SHuie-Ying.Lee@Sun.COM } 397*11044SHuie-Ying.Lee@Sun.COM /* Prefer CIDR address matching */ 398*11044SHuie-Ying.Lee@Sun.COM r = addr_pton_cidr(cp, &match_addr, &masklen); 399*11044SHuie-Ying.Lee@Sun.COM if (r == -2) { 400*11044SHuie-Ying.Lee@Sun.COM error("Inconsistent mask length for " 401*11044SHuie-Ying.Lee@Sun.COM "network \"%.100s\"", cp); 402*11044SHuie-Ying.Lee@Sun.COM ret = -2; 403*11044SHuie-Ying.Lee@Sun.COM break; 404*11044SHuie-Ying.Lee@Sun.COM } else if (r == 0) { 405*11044SHuie-Ying.Lee@Sun.COM if (addr != NULL && addr_netmatch(&try_addr, 406*11044SHuie-Ying.Lee@Sun.COM &match_addr, masklen) == 0) { 407*11044SHuie-Ying.Lee@Sun.COM foundit: 408*11044SHuie-Ying.Lee@Sun.COM if (neg) { 409*11044SHuie-Ying.Lee@Sun.COM ret = -1; 410*11044SHuie-Ying.Lee@Sun.COM break; 411*11044SHuie-Ying.Lee@Sun.COM } 412*11044SHuie-Ying.Lee@Sun.COM ret = 1; 413*11044SHuie-Ying.Lee@Sun.COM } 414*11044SHuie-Ying.Lee@Sun.COM continue; 415*11044SHuie-Ying.Lee@Sun.COM } else { 416*11044SHuie-Ying.Lee@Sun.COM /* If CIDR parse failed, try wildcard string match */ 417*11044SHuie-Ying.Lee@Sun.COM if (addr != NULL && match_pattern(addr, cp) == 1) 418*11044SHuie-Ying.Lee@Sun.COM goto foundit; 419*11044SHuie-Ying.Lee@Sun.COM } 420*11044SHuie-Ying.Lee@Sun.COM } 421*11044SHuie-Ying.Lee@Sun.COM xfree(o); 422*11044SHuie-Ying.Lee@Sun.COM 423*11044SHuie-Ying.Lee@Sun.COM return ret; 424*11044SHuie-Ying.Lee@Sun.COM } 425