skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

ip6_scan.c (2336B)


      1 /* ISC license. */
      2 
      3 #include <stdint.h>
      4 
      5 #include <skalibs/uint16.h>
      6 #include <skalibs/fmtscan.h>
      7 
      8 
      9 /* IPv6 scanner
     10 
     11 class   |       0       1       2       3
     12 st\ev   |       other   hex     :       .
     13 
     14 START   |               m
     15 00      |       X       LIMB    COLON1  X
     16 
     17 COLON1  |                       p
     18 01      |       X       X       NEW     X
     19 
     20 NEW     |               m
     21 02      |       END     LIMB    X       X
     22 
     23 LIMB    |       h               h
     24 03      |       END     LIMB    COLON   V4
     25 
     26 COLON   |               m       p
     27 04      |       X       LIMB    NEW     X
     28 
     29 
     30 END = 05
     31 V4 = 06
     32 X = 07
     33 
     34 0x10    m       mark
     35 0x20    p       set doublecolon pos
     36 0x40    h       scan hex, next limb
     37 
     38 */
     39 
     40 size_t ip6_scan (char const *s, char *ip6)
     41 {
     42   static unsigned char const class[256] = "0000000000000000000000000000000000000000000000301111111111200000011111100000000000000000000000000111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ;
     43   static uint8_t const table[5][4] =
     44   {
     45     { 0x07, 0x13, 0x01, 0x07 },
     46     { 0x07, 0x07, 0x22, 0x07 },
     47     { 0x05, 0x13, 0x07, 0x07 },
     48     { 0x45, 0x03, 0x44, 0x06 },
     49     { 0x07, 0x13, 0x22, 0x07 }
     50   } ;
     51   size_t i = 0, mark = 0 ;
     52   uint16_t limb[8] = { 0, 0, 0, 0, 0, 0, 0, 0 } ;
     53   uint8_t pos = 8, j = 0, state = 0 ;
     54 
     55   for (; state < 0x05 ; i++)
     56   {
     57     uint8_t c = table[state][class[(unsigned char)s[i]] - '0'] ;
     58     state = c & 0x07 ;
     59     if (c & 0x10) mark = i ;
     60     if (c & 0x20) { if (pos < 8) state = 0x07 ; else pos = j ; }
     61     if (c & 0x40)
     62       if (j >= 8 || uint16_xscan(s + mark, limb + j++) != i - mark) state = 0x07 ;
     63   }
     64 
     65   switch (state)
     66   {
     67     case 0x05:
     68       if (pos == 8 && j < 8 || (pos < 8 && j > 6)) return 0 ;
     69       i-- ;
     70       break ;
     71     case 0x06:
     72     {
     73       uint32_t ip4 ;
     74       if (pos == 8 && j != 6 || (pos < 8 && j > 4)) return 0 ;
     75       i = ip4_scanu32(s + mark, &ip4) ;
     76       if (!i) return 0 ;
     77       limb[j++] = ip4 >> 16 ;
     78       limb[j++] = ip4 & 0xffff ;
     79       i += mark ;
     80       break ;
     81     }
     82     default : return 0 ;
     83   }
     84 
     85   for (state = j ; state > pos ; state--) limb[state - j + 7] = limb[state - 1] ;
     86   for (; state < pos + 8 - j ; state++) limb[state] = 0 ;
     87   for (j = 0 ; j < 8 ; j++) uint16_pack_big(ip6 + (j<<1), limb[j]) ;
     88   return i ;
     89 }