"Fossies" - the Fresh Open Source Software Archive

Member "rbldnsd-0.998/ip6addr.c" (6 Apr 2013, 6720 Bytes) of package /linux/misc/dns/rbldnsd-0.998.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ip6addr.c" see the Fossies "Dox" file reference documentation.

    1 /* IPv6 address-related routines
    2  */
    3 
    4 #include "ip6addr.h"
    5 #include <string.h>
    6 #include <stdio.h>
    7 
    8 #define digit(x) ((x)>='0'&&(x)<='9')
    9 #define d2n(x) ((x)-'0')
   10 
   11 /* parse address (prefix) in a form ffff:ffff:ffff:ffff:...
   12  * granularity (bits) is 16, so the routine will return
   13  * 16, 32, 48, 64, ... _bits_ on output or <0 on error.
   14  * "an" is the max amount of bytes (not bits!) to store in *ap,
   15  * should be even (2, 4, 6, 8, ...) and should be at least 2.
   16  * The routine does support shortcuts like ffff::ffff.
   17  */
   18 int ip6prefix(const char *s, ip6oct_t ap[IP6ADDR_FULL], char **np) {
   19   static signed char hex_table[] = { /* map ascii to hex nibble value */
   20     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   21     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   22     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   23      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
   24     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   25     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   26     -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   27     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   28   };
   29   unsigned bytes = 0;     /* number of bytes we filled in ap so far */
   30   int zstart = -1;        /* location of "::", if any */
   31   int ret = -1;
   32 
   33   /* memset is better be done here instead of zeroing the tail,
   34    * since it's faster to zerofill full words.
   35    * We may even change that to a by-word loop, since all
   36    * addresses are aligned properly anyway */
   37   memset(ap, 0, IP6ADDR_FULL);
   38 
   39   if (s[0] == ':' && s[1] == ':') {
   40     zstart = 0;
   41     s += 2;
   42   }
   43 
   44   /* loop by semicolon-separated 2-byte (4 hex digits) fields */
   45   for(;;) {
   46     unsigned v = 0;     /* 2-byte (4 hex digit) field */
   47     const char *ss = s;     /* save `s' value */
   48 
   49     while ((*s & '\x80') == 0) {
   50       int nibble = hex_table[(unsigned)*s];
   51       if (nibble < 0)
   52         break;                  /* not a hex digit */
   53       v = (v << 4) + nibble;
   54       if (v > 0xffff)       /* a field can't be > 0xffff */
   55         break;
   56       ++s;
   57     }
   58     if (ss == s || v > 0xffff)  /* if no field has been consumed */
   59       break;
   60     ap[bytes++] = v >> 8;
   61     ap[bytes++] = v & 0xff;
   62     if (*s != ':' || bytes + 2 > IP6ADDR_FULL) {
   63       ret = bytes * 8;
   64       break;
   65     }
   66     ++s;
   67     if (zstart < 0 && *s == ':') {
   68       zstart = bytes;
   69       ++s;
   70     }
   71   }
   72 
   73   if (zstart >= 0) {
   74     /* expand the "::" */
   75     unsigned nzeros = IP6ADDR_FULL - bytes;
   76     if (nzeros == 0)
   77       ret = -1;                 /* illegal - no space for zeros */
   78     else {
   79       memmove(&ap[zstart + nzeros], &ap[zstart], bytes - zstart);
   80       memset(&ap[zstart], 0, nzeros);
   81       ret = 8 * IP6ADDR_FULL;
   82     }
   83   }
   84 
   85   if (np)
   86     *np = (char*)s;
   87   else if (*s)
   88     /* no success return if no 'tail' (np) pointer is given
   89      * and the tail isn't empty */
   90     ret = -1;
   91   return ret;
   92 }
   93 
   94 /* Parse ip6 CIDR range in `s', store base
   95  * in *ap (of size an bytes) and return number
   96  * of _bits_ (may be 0) or <0 on error.
   97  */
   98 int ip6cidr(const char *s, ip6oct_t ap[IP6ADDR_FULL], char **np) {
   99   int bits = ip6prefix(s, ap, (char**)&s);
  100 
  101   if (bits >= 0 && *s == '/') { /* parse /bits CIDR range */
  102     ++s;
  103     if (!digit(*s))
  104       bits = -1;
  105     else {
  106       bits = d2n(*s++);
  107       while(digit(*s))
  108         if ((bits = bits * 10 + d2n(*s++)) > 128) {
  109           bits = -1;
  110           break;
  111         }
  112     }
  113   }
  114   else if (bits == 16)
  115     bits = -1;          /* disallow bare number */
  116 
  117   if (np)
  118     *np = (char*)s;
  119   else if (*s)
  120     bits = -1;
  121   return bits;
  122 }
  123 
  124 int ip6mask(const ip6oct_t *ap, ip6oct_t *bp, unsigned n, unsigned bits) {
  125   unsigned i;
  126   int r = 0;
  127 
  128   i = bits / 8;
  129   bits %= 8;
  130 
  131   /* copy head */
  132   if (bp && bp != ap)
  133     memcpy(bp, ap, i < n ? i : n);
  134 
  135   /* check the middle byte */
  136   if (i < n && bits) {
  137     if (ap[i] & (0xff >> bits))
  138       r = 1;
  139     if (bp)
  140       bp[i] = ap[i] & (0xff << (8 - bits));
  141     ++i;
  142   }
  143 
  144   /* check-n-zero tail */
  145   while(i < n) {
  146     if (ap[i])
  147       r = 1;
  148     if (bp)
  149       bp[i] = 0;
  150     ++i;
  151   }
  152 
  153   return r;
  154 }
  155 
  156 const char *ip6atos(const ip6oct_t *ap, unsigned an) {
  157   static char buf[(4+1)*8+1];
  158   unsigned awords = an / 2;
  159   char *bp = buf;
  160   unsigned nzeros = 0, zstart = 0, i;
  161 
  162   if (awords > IP6ADDR_FULL / 2)
  163     awords = IP6ADDR_FULL / 2;
  164 
  165   /* find longest string of repeated zero words */
  166   for (i = 0; i + nzeros < IP6ADDR_FULL / 2; i++) {
  167     unsigned nz;                 /* count zero words */
  168     for (nz = 0; i + nz < awords; nz++)
  169       if (ap[2 * (i + nz)] != 0 || ap[2 * (i + nz) + 1] != 0)
  170         break;
  171     if (i + nz == awords)
  172       nz += IP6ADDR_FULL / 2 - awords;
  173 
  174     if (nz > 1 && nz > nzeros) {
  175       nzeros = nz;
  176       zstart = i;
  177     }
  178   }
  179 
  180   for (i = 0; i < zstart; i++)
  181     bp += sprintf(bp, ":%x", (((unsigned)ap[2*i]) << 8) + ap[2*i+1]);
  182   if (nzeros) {
  183     *bp++ = ':';
  184     if (zstart == 0)
  185       *bp++ = ':';                /* leading "::" */
  186     if (zstart + nzeros == IP6ADDR_FULL / 2)
  187       *bp++ = ':';                /* trailing "::" */
  188   }
  189   for (i += nzeros; i < awords; i++)
  190     bp += sprintf(bp, ":%x", (((unsigned)ap[2*i]) << 8) + ap[2*i+1]);
  191   for (; i < IP6ADDR_FULL / 2; i++) {
  192     *bp++ = ':';
  193     *bp++ = '0';
  194   }
  195   *bp = '\0';
  196   return buf + 1;
  197 }
  198 
  199 #ifdef TEST
  200 #include <stdlib.h>
  201 
  202 /* our own version of assert()
  203  *
  204  * (mostly so that checks still happen even when compiled with
  205  * -DNDEBUG)
  206  */
  207 #define CHECK(expr) ((expr) ? (void) 0 : report_failure(#expr, __LINE__))
  208 
  209 static void
  210 report_failure(const char *expr, unsigned line)
  211 {
  212   printf("%s:%u: check `%s' failed\n", __FILE__, line, expr);
  213   abort();
  214 }
  215 
  216 int main(int argc, char **argv) {
  217   int i;
  218   ip6oct_t a[IP6ADDR_FULL];
  219   int bits;
  220   char *np;
  221 
  222 
  223 #define ip6tos(a,bits) (bits < 0 ? "err" : ip6atos(a,sizeof(a)))
  224 
  225   for(i = 1; i < argc; ++i) {
  226     char *s = argv[i];
  227     printf("%s:\n", s);
  228 
  229     bits = ip6prefix(s, a, NULL);
  230     printf(" pfx: %s/%d\n", ip6tos(a, bits), bits);
  231     bits = ip6prefix(s, a, &np);
  232     printf(" pfx: %s/%d tail=`%s'\n", ip6tos(a, bits), bits, np);
  233 
  234     bits = ip6cidr(s, a, NULL);
  235     printf("cidr: %s/%d\n", ip6tos(a, bits), bits);
  236     bits = ip6cidr(s, a, &np);
  237     printf("cidr: %s/%d tail=`%s'\n", ip6tos(a, bits), bits, np);
  238     if (bits >= 0) {
  239       bits = ip6mask(a, a, IP6ADDR_FULL, bits);
  240       printf("mask: %s (host=%d)\n", ip6atos(a, sizeof(a)), bits);
  241     }
  242   }
  243 
  244   CHECK(ip6prefix("::1", a, NULL) == 128);
  245   CHECK(strcmp(ip6atos(a, 128), "::1") == 0);
  246 
  247   CHECK(ip6prefix("1::", a, NULL) == 128);
  248   CHECK(strcmp(ip6atos(a, 128), "1::") == 0);
  249 
  250   CHECK(ip6prefix("1::4:0:0:0:8", a, NULL) == 128);
  251   CHECK(strcmp(ip6atos(a, 128), "1:0:0:4::8") == 0);
  252 
  253   return 0;
  254 }
  255 
  256 #endif