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 }