1*9b241b4eSYuri Pankov /* 2*9b241b4eSYuri Pankov * This file and its contents are supplied under the terms of the 3*9b241b4eSYuri Pankov * Common Development and Distribution License ("CDDL"), version 1.0. 4*9b241b4eSYuri Pankov * You may only use this file in accordance with the terms of version 5*9b241b4eSYuri Pankov * 1.0 of the CDDL. 6*9b241b4eSYuri Pankov * 7*9b241b4eSYuri Pankov * A full copy of the text of the CDDL should have accompanied this 8*9b241b4eSYuri Pankov * source. A copy of the CDDL is also available via the Internet at 9*9b241b4eSYuri Pankov * http://www.illumos.org/license/CDDL. 10*9b241b4eSYuri Pankov * 11*9b241b4eSYuri Pankov * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 12*9b241b4eSYuri Pankov */ 13*9b241b4eSYuri Pankov 14*9b241b4eSYuri Pankov /* 15*9b241b4eSYuri Pankov * inet_matchaddr 16*9b241b4eSYuri Pankov * 17*9b241b4eSYuri Pankov * Match IPv4 or IPv6 address provided in sa (sockaddr_in/sockaddr_in6) 18*9b241b4eSYuri Pankov * against standard text representation specified in name: 19*9b241b4eSYuri Pankov * 20*9b241b4eSYuri Pankov * IPv4: 21*9b241b4eSYuri Pankov * IPv4 22*9b241b4eSYuri Pankov * IPv4/netmask 23*9b241b4eSYuri Pankov * 24*9b241b4eSYuri Pankov * IPv6: 25*9b241b4eSYuri Pankov * [IPv6] 26*9b241b4eSYuri Pankov * [IPv6]/prefix 27*9b241b4eSYuri Pankov */ 28*9b241b4eSYuri Pankov 29*9b241b4eSYuri Pankov #include <sys/socket.h> 30*9b241b4eSYuri Pankov #include <sys/types.h> 31*9b241b4eSYuri Pankov 32*9b241b4eSYuri Pankov #include <arpa/inet.h> 33*9b241b4eSYuri Pankov 34*9b241b4eSYuri Pankov #include <netinet/in.h> 35*9b241b4eSYuri Pankov 36*9b241b4eSYuri Pankov #include <ctype.h> 37*9b241b4eSYuri Pankov #include <err.h> 38*9b241b4eSYuri Pankov #include <netdb.h> 39*9b241b4eSYuri Pankov #include <stdlib.h> 40*9b241b4eSYuri Pankov #include <strings.h> 41*9b241b4eSYuri Pankov 42*9b241b4eSYuri Pankov 43*9b241b4eSYuri Pankov boolean_t 44*9b241b4eSYuri Pankov inet_matchaddr(const void *sa, const char *name) 45*9b241b4eSYuri Pankov { 46*9b241b4eSYuri Pankov boolean_t ret = B_FALSE; 47*9b241b4eSYuri Pankov char *lname, *mp, *p; 48*9b241b4eSYuri Pankov uint32_t claddr4 = 0; 49*9b241b4eSYuri Pankov 50*9b241b4eSYuri Pankov if ((p = lname = strdup(name)) == NULL) 51*9b241b4eSYuri Pankov err(1, "strdup"); 52*9b241b4eSYuri Pankov 53*9b241b4eSYuri Pankov if ((mp = strchr(p, '/')) != NULL) 54*9b241b4eSYuri Pankov *mp++ = '\0'; 55*9b241b4eSYuri Pankov 56*9b241b4eSYuri Pankov switch (((struct sockaddr_in *)sa)->sin_family) { 57*9b241b4eSYuri Pankov case AF_INET6: { 58*9b241b4eSYuri Pankov char *pp; 59*9b241b4eSYuri Pankov int prefix6; 60*9b241b4eSYuri Pankov ipaddr_t ipaddr4; 61*9b241b4eSYuri Pankov struct in6_addr hcaddr6; 62*9b241b4eSYuri Pankov struct in6_addr *claddr6 = 63*9b241b4eSYuri Pankov &((struct sockaddr_in6 *)sa)->sin6_addr; 64*9b241b4eSYuri Pankov 65*9b241b4eSYuri Pankov if (!IN6_IS_ADDR_V4MAPPED(claddr6)) { 66*9b241b4eSYuri Pankov /* IPv6 address */ 67*9b241b4eSYuri Pankov if ((p = strchr(p, '[')) == NULL) 68*9b241b4eSYuri Pankov break; 69*9b241b4eSYuri Pankov p++; 70*9b241b4eSYuri Pankov 71*9b241b4eSYuri Pankov if ((pp = strchr(p, ']')) == NULL) 72*9b241b4eSYuri Pankov break; 73*9b241b4eSYuri Pankov *pp = '\0'; 74*9b241b4eSYuri Pankov 75*9b241b4eSYuri Pankov if (inet_pton(AF_INET6, p, &hcaddr6) != 1) 76*9b241b4eSYuri Pankov break; 77*9b241b4eSYuri Pankov 78*9b241b4eSYuri Pankov if (mp != NULL) { 79*9b241b4eSYuri Pankov /* Match only first prefix bits */ 80*9b241b4eSYuri Pankov if ((prefix6 = (int)strtol(mp, 81*9b241b4eSYuri Pankov (char **)NULL, 10)) == 0) 82*9b241b4eSYuri Pankov break; 83*9b241b4eSYuri Pankov ret = IN6_ARE_PREFIXEDADDR_EQUAL(claddr6, 84*9b241b4eSYuri Pankov &hcaddr6, prefix6); 85*9b241b4eSYuri Pankov break; 86*9b241b4eSYuri Pankov } else { 87*9b241b4eSYuri Pankov /* No prefix, exact match */ 88*9b241b4eSYuri Pankov ret = IN6_ARE_ADDR_EQUAL(claddr6, &hcaddr6); 89*9b241b4eSYuri Pankov break; 90*9b241b4eSYuri Pankov } 91*9b241b4eSYuri Pankov } else { 92*9b241b4eSYuri Pankov /* IPv4-mapped IPv6 address, fallthrough to IPv4 */ 93*9b241b4eSYuri Pankov IN6_V4MAPPED_TO_IPADDR(claddr6, ipaddr4); 94*9b241b4eSYuri Pankov claddr4 = ntohl(ipaddr4); 95*9b241b4eSYuri Pankov } 96*9b241b4eSYuri Pankov /*FALLTHROUGH*/ 97*9b241b4eSYuri Pankov } 98*9b241b4eSYuri Pankov case AF_INET: { 99*9b241b4eSYuri Pankov int bits, i; 100*9b241b4eSYuri Pankov uint32_t hcaddr4 = 0, mask4; 101*9b241b4eSYuri Pankov 102*9b241b4eSYuri Pankov if (claddr4 == 0) 103*9b241b4eSYuri Pankov claddr4 = ntohl( 104*9b241b4eSYuri Pankov ((struct sockaddr_in *)sa)->sin_addr.s_addr); 105*9b241b4eSYuri Pankov 106*9b241b4eSYuri Pankov for (i = 0; i < 4; i++) { 107*9b241b4eSYuri Pankov hcaddr4 |= (int)strtol(p, (char **)NULL, 10) << 108*9b241b4eSYuri Pankov ((3 - i) * 8); 109*9b241b4eSYuri Pankov if ((p = strchr(p, '.')) == NULL) 110*9b241b4eSYuri Pankov break; 111*9b241b4eSYuri Pankov p++; 112*9b241b4eSYuri Pankov } 113*9b241b4eSYuri Pankov 114*9b241b4eSYuri Pankov if (hcaddr4 == 0) 115*9b241b4eSYuri Pankov break; 116*9b241b4eSYuri Pankov 117*9b241b4eSYuri Pankov if (mp != NULL) { 118*9b241b4eSYuri Pankov /* Mask is specified explicitly */ 119*9b241b4eSYuri Pankov if ((bits = (int)strtol(mp, (char **)NULL, 10)) == 0) 120*9b241b4eSYuri Pankov break; 121*9b241b4eSYuri Pankov mask4 = bits ? ~0 << ((sizeof (struct in_addr) * NBBY) 122*9b241b4eSYuri Pankov - bits) : 0; 123*9b241b4eSYuri Pankov hcaddr4 &= mask4; 124*9b241b4eSYuri Pankov } else { 125*9b241b4eSYuri Pankov /* 126*9b241b4eSYuri Pankov * Use old-fashioned implicit netmasking by checking 127*9b241b4eSYuri Pankov * for lower-end zeroes. On the off chance we don't 128*9b241b4eSYuri Pankov * match any well-known prefixes, return an exact- 129*9b241b4eSYuri Pankov * match prefix which is misleadingly labelled as 130*9b241b4eSYuri Pankov * IN_CLASSE_NET. 131*9b241b4eSYuri Pankov */ 132*9b241b4eSYuri Pankov if ((hcaddr4 & IN_CLASSA_HOST) == 0) 133*9b241b4eSYuri Pankov mask4 = IN_CLASSA_NET; 134*9b241b4eSYuri Pankov else if ((hcaddr4 & IN_CLASSB_HOST) == 0) 135*9b241b4eSYuri Pankov mask4 = IN_CLASSB_NET; 136*9b241b4eSYuri Pankov else if ((hcaddr4 & IN_CLASSC_HOST) == 0) 137*9b241b4eSYuri Pankov mask4 = IN_CLASSC_NET; 138*9b241b4eSYuri Pankov else 139*9b241b4eSYuri Pankov mask4 = IN_CLASSE_NET; 140*9b241b4eSYuri Pankov } 141*9b241b4eSYuri Pankov 142*9b241b4eSYuri Pankov ret = ((claddr4 & mask4) == hcaddr4); 143*9b241b4eSYuri Pankov break; 144*9b241b4eSYuri Pankov } 145*9b241b4eSYuri Pankov } 146*9b241b4eSYuri Pankov 147*9b241b4eSYuri Pankov free(lname); 148*9b241b4eSYuri Pankov 149*9b241b4eSYuri Pankov return (ret); 150*9b241b4eSYuri Pankov } 151