nightmaremail

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

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 }