ipme.c (5400B)
1 #include "ipme.h" 2 3 #include <sys/types.h> 4 #include <sys/param.h> 5 #include <sys/time.h> 6 #include <sys/ioctl.h> 7 #include <sys/socket.h> 8 #include <net/if.h> 9 #include <netinet/in.h> 10 #ifndef SIOCGIFCONF /* whatever works */ 11 #include <sys/sockio.h> 12 #endif 13 #include <unistd.h> 14 #include "hassalen.h" 15 #include "byte.h" 16 #include "ip.h" 17 #include "ipalloc.h" 18 #ifdef USING_SKALIBS 19 #include <skalibs/stralloc.h> 20 #else 21 #include "stralloc.h" 22 #endif 23 24 static int ipmeok = 0; 25 static int ip6meok = 0; 26 ipalloc ipme = {0}; 27 ipalloc ip6me = {0}; 28 29 int ip4me_is(struct ip_address *ip) 30 { 31 int i; 32 if (ip4me_init() != 1) return -1; 33 if (ip->is6) return 0; 34 for (i = 0;i < ipme.len;++i) 35 if (byte_equal(&(ipme.ix[i].ip.ip.a),4,&(ip->ip.a))) 36 return 1; 37 return 0; 38 } 39 40 static stralloc buf = {0}; 41 42 int ip4me_init() 43 { 44 struct ifconf ifc; 45 char *x; 46 struct ifreq *ifr; 47 struct sockaddr_in *sin; 48 int len; 49 int s; 50 struct ip_mx ix; 51 52 if (ipmeok) return 1; 53 if (!ipalloc_readyplus(&ipme,0)) return 0; 54 ipme.len = 0; 55 ix.pref = 0; 56 57 /* 0.0.0.0 is a special address which always refers to 58 * "this host, this network", according to RFC 1122, Sec. 3.2.1.3a. 59 */ 60 memset(&ix.ip,0,sizeof(struct ip_address)); 61 ix.ip.is6 = 0; 62 if (!ipalloc_append(&ipme,&ix)) { return 0; } 63 if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) return -1; 64 65 ifc.ifc_buf = 0; 66 ifc.ifc_len = 0; 67 68 /* first pass: just ask what the correct length for all addresses is */ 69 len = 0; 70 if (ioctl(s,SIOCGIFCONF,&ifc) >= 0 && ifc.ifc_len > 0) { /* > is for System V */ 71 if (!stralloc_ready(&buf,ifc.ifc_len)) { close(s); return 0; } 72 ifc.ifc_buf = buf.s; 73 if (ioctl(s,SIOCGIFCONF,&ifc) >= 0) 74 buf.len = ifc.ifc_len; 75 } 76 77 /* check if we have complete length, otherwise try so sort that out */ 78 if (buf.len == 0) { 79 len = 256; 80 for (;;) { 81 if (!stralloc_ready(&buf,len)) { close(s); return 0; } 82 buf.len = 0; 83 ifc.ifc_buf = buf.s; 84 ifc.ifc_len = len; 85 if (ioctl(s,SIOCGIFCONF,&ifc) >= 0) /* > is for System V */ 86 if (ifc.ifc_len + sizeof(*ifr) + 64 < len) { /* what a stupid interface */ 87 buf.len = ifc.ifc_len; 88 break; 89 } 90 if (len > 200000) { close(s); return -1; } 91 len += 100 + (len >> 2); 92 } 93 } 94 x = buf.s; 95 while (x < buf.s + buf.len) { 96 ifr = (struct ifreq *) x; 97 #ifdef HASSALEN 98 len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len; 99 if (len < sizeof(*ifr)) 100 len = sizeof(*ifr); 101 #else 102 len = sizeof(*ifr); 103 #endif 104 memset(&ix.ip,0,sizeof(struct ip_address)); 105 if (ifr->ifr_addr.sa_family == AF_INET) { 106 sin = (struct sockaddr_in *) &ifr->ifr_addr; 107 ix.ip.is6 = 0; 108 byte_copy(&ix.ip.ip.a.d,4,&sin->sin_addr); 109 if (ioctl(s,SIOCGIFFLAGS,x) == 0) 110 if (ifr->ifr_flags & IFF_UP) 111 if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; } 112 } 113 x += len; 114 } 115 close(s); 116 ipmeok = 1; 117 return 1; 118 } 119 120 int ip6me_is(struct ip_address *ip) 121 { 122 int i; 123 if (ip6me_init() != 1) return -1; 124 for (i = 0;i < ip6me.len;++i) 125 if (byte_equal(&(ip6me.ix[i].ip.ip.aaaa.d),16,&(ip->ip.aaaa.d))) 126 return 1; 127 return 0; 128 } 129 130 int ip6me_init() 131 { 132 struct ifconf ifc; 133 char *x; 134 struct ifreq *ifr; 135 struct sockaddr_in6 *sin; 136 int len; 137 int s; 138 struct ip_mx ix; 139 140 if (ip6meok) return 1; 141 if (!ipalloc_readyplus(&ip6me,0)) return 0; 142 ip6me.len = 0; 143 ix.pref = 0; 144 145 /* :: is a special address which is specifically unspecified. 146 */ 147 memset(&ix.ip,0,sizeof(struct ip_address)); 148 ix.ip.is6 = 1; 149 if (!ipalloc_append(&ip6me,&ix)) { return 0; } 150 if ((s = socket(AF_INET6,SOCK_STREAM,0)) == -1) return -1; 151 152 ifc.ifc_buf = 0; 153 ifc.ifc_len = 0; 154 155 /* first pass: just ask what the correct length for all addresses is */ 156 len = 0; 157 if (ioctl(s,SIOCGIFCONF,&ifc) >= 0 && ifc.ifc_len > 0) { /* > is for System V */ 158 if (!stralloc_ready(&buf,ifc.ifc_len)) { close(s); return 0; } 159 ifc.ifc_buf = buf.s; 160 if (ioctl(s,SIOCGIFCONF,&ifc) >= 0) 161 buf.len = ifc.ifc_len; 162 } 163 164 /* check if we have complete length, otherwise try so sort that out */ 165 if (buf.len == 0) { 166 len = 256; 167 for (;;) { 168 if (!stralloc_ready(&buf,len)) { close(s); return 0; } 169 buf.len = 0; 170 ifc.ifc_buf = buf.s; 171 ifc.ifc_len = len; 172 if (ioctl(s,SIOCGIFCONF,&ifc) >= 0) /* > is for System V */ 173 if (ifc.ifc_len + sizeof(*ifr) + 64 < len) { /* what a stupid interface */ 174 buf.len = ifc.ifc_len; 175 break; 176 } 177 if (len > 200000) { close(s); return -1; } 178 len += 100 + (len >> 2); 179 } 180 } 181 x = buf.s; 182 while (x < buf.s + buf.len) { 183 ifr = (struct ifreq *) x; 184 #ifdef HASSALEN 185 len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len; 186 if (len < sizeof(*ifr)) 187 len = sizeof(*ifr); 188 #else 189 len = sizeof(*ifr); 190 #endif 191 memset(&ix.ip,0,sizeof(struct ip_address)); 192 if (ifr->ifr_addr.sa_family == AF_INET6) { 193 sin = (struct sockaddr_in6 *) &ifr->ifr_addr; 194 ix.ip.is6 = 1; 195 byte_copy(&ix.ip.ip.aaaa,16,&sin->sin6_addr); 196 if (ioctl(s,SIOCGIFFLAGS,x) == 0) 197 if (ifr->ifr_flags & IFF_UP) 198 if (!ip6alloc_append(&ip6me,&ix)) { close(s); return 0; } 199 } 200 x += len; 201 } 202 close(s); 203 ip6meok = 1; 204 return 1; 205 } 206 207 int ipme_is(struct ip_address *ip) { 208 return (ip->is6 ? ip6me_is(ip) : ip4me_is(ip)); 209 } 210 211 int ipme_init() { 212 if (!ip4me_init()) return 0; 213 if (!ip6me_init()) return 0; 214 return 1; 215 }