parseip.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       parseip.c (3525B)
       ---
            1 #include "u.h"
            2 #include "lib.h"
            3 #include "ctype.h"
            4 #include "ip.h"
            5 
            6 char*
            7 v4parseip(uchar *to, char *from)
            8 {
            9         int i;
           10         char *p;
           11 
           12         p = from;
           13         for(i = 0; i < 4 && *p; i++){
           14                 to[i] = strtoul(p, &p, 0);
           15                 if(*p == '.')
           16                         p++;
           17         }
           18         switch(CLASS(to)){
           19         case 0:        /* class A - 1 uchar net */
           20         case 1:
           21                 if(i == 3){
           22                         to[3] = to[2];
           23                         to[2] = to[1];
           24                         to[1] = 0;
           25                 } else if (i == 2){
           26                         to[3] = to[1];
           27                         to[1] = 0;
           28                 }
           29                 break;
           30         case 2:        /* class B - 2 uchar net */
           31                 if(i == 3){
           32                         to[3] = to[2];
           33                         to[2] = 0;
           34                 }
           35                 break;
           36         }
           37         return p;
           38 }
           39 
           40 static int
           41 ipcharok(int c)
           42 {
           43         return c == '.' || c == ':' || (isascii(c) && isxdigit(c));
           44 }
           45 
           46 static int
           47 delimchar(int c)
           48 {
           49         if(c == '\0')
           50                 return 1;
           51         if(c == '.' || c == ':' || (isascii(c) && isalnum(c)))
           52                 return 0;
           53         return 1;
           54 }
           55 
           56 /*
           57  * `from' may contain an address followed by other characters,
           58  * at least in /boot, so we permit whitespace (and more) after the address.
           59  * we do ensure that "delete" cannot be parsed as "de::".
           60  *
           61  * some callers don't check the return value for errors, so
           62  * set `to' to something distinctive in the case of a parse error.
           63  */
           64 vlong
           65 parseip(uchar *to, char *from)
           66 {
           67         int i, elipsis = 0, v4 = 1;
           68         ulong x;
           69         char *p, *op;
           70 
           71         memset(to, 0, IPaddrlen);
           72         p = from;
           73         for(i = 0; i < IPaddrlen && ipcharok(*p); i+=2){
           74                 op = p;
           75                 x = strtoul(p, &p, 16);
           76                 if(*p == '.' || (*p == 0 && i == 0)){        /* ends with v4? */
           77                         p = v4parseip(to+i, op);
           78                         i += 4;
           79                         break;
           80                 }
           81                 /* v6: at most 4 hex digits, followed by colon or delim */
           82                 if(x != (ushort)x || (*p != ':' && !delimchar(*p))) {
           83                         memset(to, 0, IPaddrlen);
           84                         return -1;                        /* parse error */
           85                 }
           86                 to[i] = x>>8;
           87                 to[i+1] = x;
           88                 if(*p == ':'){
           89                         v4 = 0;
           90                         if(*++p == ':'){        /* :: is elided zero short(s) */
           91                                 if (elipsis) {
           92                                         memset(to, 0, IPaddrlen);
           93                                         return -1;        /* second :: */
           94                                 }
           95                                 elipsis = i+2;
           96                                 p++;
           97                         }
           98                 } else if (p == op)                /* strtoul made no progress? */
           99                         break;
          100         }
          101         if (p == from || !delimchar(*p)) {
          102                 memset(to, 0, IPaddrlen);
          103                 return -1;                                /* parse error */
          104         }
          105         if(i < IPaddrlen){
          106                 memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis);
          107                 memset(&to[elipsis], 0, IPaddrlen-i);
          108         }
          109         if(v4){
          110                 to[10] = to[11] = 0xff;
          111                 return nhgetl(to + IPv4off);
          112         } else
          113                 return 6;
          114 }
          115 
          116 /*
          117  *  hack to allow ip v4 masks to be entered in the old
          118  *  style
          119  */
          120 vlong
          121 parseipmask(uchar *to, char *from)
          122 {
          123         int i, w;
          124         vlong x;
          125         uchar *p;
          126 
          127         if(*from == '/'){
          128                 /* as a number of prefix bits */
          129                 i = atoi(from+1);
          130                 if(i < 0)
          131                         i = 0;
          132                 if(i > 128)
          133                         i = 128;
          134                 w = i;
          135                 memset(to, 0, IPaddrlen);
          136                 for(p = to; i >= 8; i -= 8)
          137                         *p++ = 0xff;
          138                 if(i > 0)
          139                         *p = ~((1<<(8-i))-1);
          140                 x = nhgetl(to+IPv4off);
          141                 /*
          142                  * identify as ipv6 if the mask is inexpressible as a v4 mask
          143                  * (because it has too few mask bits).  Arguably, we could
          144                  * always return 6 here.
          145                  */
          146                 if (w < 8*(IPaddrlen-IPv4addrlen))
          147                         return 6;
          148         } else {
          149                 /* as a straight v4 bit mask */
          150                 x = parseip(to, from);
          151                 if (x != -1)
          152                         x = (ulong)nhgetl(to + IPv4off);
          153                 if(memcmp(to, v4prefix, IPv4off) == 0)
          154                         memset(to, 0xff, IPv4off);
          155         }
          156         return x;
          157 }
          158 
          159 /*
          160  *  parse a v4 ip address/mask in cidr format
          161  */
          162 char*
          163 v4parsecidr(uchar *addr, uchar *mask, char *from)
          164 {
          165         int i;
          166         char *p;
          167         uchar *a;
          168 
          169         p = v4parseip(addr, from);
          170 
          171         if(*p == '/'){
          172                 /* as a number of prefix bits */
          173                 i = strtoul(p+1, &p, 0);
          174                 if(i > 32)
          175                         i = 32;
          176                 memset(mask, 0, IPv4addrlen);
          177                 for(a = mask; i >= 8; i -= 8)
          178                         *a++ = 0xff;
          179                 if(i > 0)
          180                         *a = ~((1<<(8-i))-1);
          181         } else 
          182                 memcpy(mask, defmask(addr), IPv4addrlen);
          183         return p;
          184 }