13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 3*ea58ad6fSDavid du Colombier #include <ctype.h> 47dd7cddfSDavid du Colombier #include <ip.h> 53e12c5d1SDavid du Colombier 67dd7cddfSDavid du Colombier char* 77dd7cddfSDavid du Colombier v4parseip(uchar *to, char *from) 83e12c5d1SDavid du Colombier { 93e12c5d1SDavid du Colombier int i; 103e12c5d1SDavid du Colombier char *p; 113e12c5d1SDavid du Colombier 123e12c5d1SDavid du Colombier p = from; 133e12c5d1SDavid du Colombier for(i = 0; i < 4 && *p; i++){ 143e12c5d1SDavid du Colombier to[i] = strtoul(p, &p, 0); 153e12c5d1SDavid du Colombier if(*p == '.') 163e12c5d1SDavid du Colombier p++; 173e12c5d1SDavid du Colombier } 183e12c5d1SDavid du Colombier switch(CLASS(to)){ 197dd7cddfSDavid du Colombier case 0: /* class A - 1 uchar net */ 203e12c5d1SDavid du Colombier case 1: 213e12c5d1SDavid du Colombier if(i == 3){ 223e12c5d1SDavid du Colombier to[3] = to[2]; 233e12c5d1SDavid du Colombier to[2] = to[1]; 243e12c5d1SDavid du Colombier to[1] = 0; 253e12c5d1SDavid du Colombier } else if (i == 2){ 263e12c5d1SDavid du Colombier to[3] = to[1]; 273e12c5d1SDavid du Colombier to[1] = 0; 283e12c5d1SDavid du Colombier } 293e12c5d1SDavid du Colombier break; 307dd7cddfSDavid du Colombier case 2: /* class B - 2 uchar net */ 313e12c5d1SDavid du Colombier if(i == 3){ 323e12c5d1SDavid du Colombier to[3] = to[2]; 333e12c5d1SDavid du Colombier to[2] = 0; 343e12c5d1SDavid du Colombier } 353e12c5d1SDavid du Colombier break; 363e12c5d1SDavid du Colombier } 377dd7cddfSDavid du Colombier return p; 387dd7cddfSDavid du Colombier } 397dd7cddfSDavid du Colombier 40*ea58ad6fSDavid du Colombier static int 41*ea58ad6fSDavid du Colombier ipcharok(int c) 42*ea58ad6fSDavid du Colombier { 43*ea58ad6fSDavid du Colombier return c == '.' || c == ':' || isascii(c) && isxdigit(c); 44*ea58ad6fSDavid du Colombier } 45*ea58ad6fSDavid du Colombier 46*ea58ad6fSDavid du Colombier static int 47*ea58ad6fSDavid du Colombier delimchar(int c) 48*ea58ad6fSDavid du Colombier { 49*ea58ad6fSDavid du Colombier if(c == '\0') 50*ea58ad6fSDavid du Colombier return 1; 51*ea58ad6fSDavid du Colombier if(c == '.' || c == ':' || isascii(c) && isalnum(c)) 52*ea58ad6fSDavid du Colombier return 0; 53*ea58ad6fSDavid du Colombier return 1; 54*ea58ad6fSDavid du Colombier } 55*ea58ad6fSDavid du Colombier 56*ea58ad6fSDavid du Colombier /* 57*ea58ad6fSDavid du Colombier * `from' may contain an address followed by other characters, 58*ea58ad6fSDavid du Colombier * at least in /boot, so we permit whitespace (and more) after the address. 59*ea58ad6fSDavid du Colombier * we do ensure that "delete" cannot be parsed as "de::". 60*ea58ad6fSDavid du Colombier * 61*ea58ad6fSDavid du Colombier * some callers don't check the return value for errors, so 62*ea58ad6fSDavid du Colombier * set `to' to something distinctive in the case of a parse error. 63*ea58ad6fSDavid du Colombier */ 64*ea58ad6fSDavid du Colombier vlong 657dd7cddfSDavid du Colombier parseip(uchar *to, char *from) 667dd7cddfSDavid du Colombier { 677dd7cddfSDavid du Colombier int i, elipsis = 0, v4 = 1; 687dd7cddfSDavid du Colombier ulong x; 697dd7cddfSDavid du Colombier char *p, *op; 707dd7cddfSDavid du Colombier 717dd7cddfSDavid du Colombier memset(to, 0, IPaddrlen); 727dd7cddfSDavid du Colombier p = from; 73*ea58ad6fSDavid du Colombier for(i = 0; i < IPaddrlen && ipcharok(*p); i+=2){ 747dd7cddfSDavid du Colombier op = p; 757dd7cddfSDavid du Colombier x = strtoul(p, &p, 16); 76*ea58ad6fSDavid du Colombier if(*p == '.' || (*p == 0 && i == 0)){ /* ends with v4? */ 777dd7cddfSDavid du Colombier p = v4parseip(to+i, op); 787dd7cddfSDavid du Colombier i += 4; 797dd7cddfSDavid du Colombier break; 807dd7cddfSDavid du Colombier } 81*ea58ad6fSDavid du Colombier /* v6: at most 4 hex digits, followed by colon or delim */ 82*ea58ad6fSDavid du Colombier if(x != (ushort)x || *p != ':' && !delimchar(*p)) { 83*ea58ad6fSDavid du Colombier memset(to, 0, IPaddrlen); 84*ea58ad6fSDavid du Colombier return -1; /* parse error */ 85*ea58ad6fSDavid du Colombier } 867dd7cddfSDavid du Colombier to[i] = x>>8; 877dd7cddfSDavid du Colombier to[i+1] = x; 887dd7cddfSDavid du Colombier if(*p == ':'){ 897dd7cddfSDavid du Colombier v4 = 0; 90*ea58ad6fSDavid du Colombier if(*++p == ':'){ /* :: is elided zero short(s) */ 91*ea58ad6fSDavid du Colombier if (elipsis) { 92*ea58ad6fSDavid du Colombier memset(to, 0, IPaddrlen); 93*ea58ad6fSDavid du Colombier return -1; /* second :: */ 94*ea58ad6fSDavid du Colombier } 957dd7cddfSDavid du Colombier elipsis = i+2; 967dd7cddfSDavid du Colombier p++; 977dd7cddfSDavid du Colombier } 98*ea58ad6fSDavid du Colombier } else if (p == op) /* strtoul made no progress? */ 99*ea58ad6fSDavid du Colombier break; 1007dd7cddfSDavid du Colombier } 101*ea58ad6fSDavid du Colombier if (p == from || !delimchar(*p)) { 102*ea58ad6fSDavid du Colombier memset(to, 0, IPaddrlen); 103*ea58ad6fSDavid du Colombier return -1; /* parse error */ 1047dd7cddfSDavid du Colombier } 105*ea58ad6fSDavid du Colombier if(i < IPaddrlen){ 106*ea58ad6fSDavid du Colombier memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis); 107*ea58ad6fSDavid du Colombier memset(&to[elipsis], 0, IPaddrlen-i); 1087dd7cddfSDavid du Colombier } 1097dd7cddfSDavid du Colombier if(v4){ 1107dd7cddfSDavid du Colombier to[10] = to[11] = 0xff; 111*ea58ad6fSDavid du Colombier return nhgetl(to + IPv4off); 1127dd7cddfSDavid du Colombier } else 1137dd7cddfSDavid du Colombier return 6; 1147dd7cddfSDavid du Colombier } 1157dd7cddfSDavid du Colombier 1167dd7cddfSDavid du Colombier /* 1177dd7cddfSDavid du Colombier * hack to allow ip v4 masks to be entered in the old 1187dd7cddfSDavid du Colombier * style 1197dd7cddfSDavid du Colombier */ 120*ea58ad6fSDavid du Colombier vlong 1217dd7cddfSDavid du Colombier parseipmask(uchar *to, char *from) 1227dd7cddfSDavid du Colombier { 123c62728daSDavid du Colombier int i, w; 124*ea58ad6fSDavid du Colombier vlong x; 1257dd7cddfSDavid du Colombier uchar *p; 1267dd7cddfSDavid du Colombier 1277dd7cddfSDavid du Colombier if(*from == '/'){ 1287dd7cddfSDavid du Colombier /* as a number of prefix bits */ 1297dd7cddfSDavid du Colombier i = atoi(from+1); 1307dd7cddfSDavid du Colombier if(i < 0) 1317dd7cddfSDavid du Colombier i = 0; 1327dd7cddfSDavid du Colombier if(i > 128) 1337dd7cddfSDavid du Colombier i = 128; 134c62728daSDavid du Colombier w = i; 1357dd7cddfSDavid du Colombier memset(to, 0, IPaddrlen); 1367dd7cddfSDavid du Colombier for(p = to; i >= 8; i -= 8) 1377dd7cddfSDavid du Colombier *p++ = 0xff; 1387dd7cddfSDavid du Colombier if(i > 0) 1397dd7cddfSDavid du Colombier *p = ~((1<<(8-i))-1); 1407dd7cddfSDavid du Colombier x = nhgetl(to+IPv4off); 141c62728daSDavid du Colombier /* 142c62728daSDavid du Colombier * identify as ipv6 if the mask is inexpressible as a v4 mask 143*ea58ad6fSDavid du Colombier * (because it has too few mask bits). Arguably, we could 144c62728daSDavid du Colombier * always return 6 here. 145c62728daSDavid du Colombier */ 146*ea58ad6fSDavid du Colombier if (w < 8*(IPaddrlen-IPv4addrlen)) 147c62728daSDavid du Colombier return 6; 1487dd7cddfSDavid du Colombier } else { 149*ea58ad6fSDavid du Colombier /* as a straight v4 bit mask */ 1507dd7cddfSDavid du Colombier x = parseip(to, from); 151*ea58ad6fSDavid du Colombier if (x != -1) 152*ea58ad6fSDavid du Colombier x = (ulong)nhgetl(to + IPv4off); 1537dd7cddfSDavid du Colombier if(memcmp(to, v4prefix, IPv4off) == 0) 1547dd7cddfSDavid du Colombier memset(to, 0xff, IPv4off); 1557dd7cddfSDavid du Colombier } 1567dd7cddfSDavid du Colombier return x; 1577dd7cddfSDavid du Colombier } 1587dd7cddfSDavid du Colombier 1597dd7cddfSDavid du Colombier /* 1607dd7cddfSDavid du Colombier * parse a v4 ip address/mask in cidr format 1617dd7cddfSDavid du Colombier */ 1627dd7cddfSDavid du Colombier char* 1637dd7cddfSDavid du Colombier v4parsecidr(uchar *addr, uchar *mask, char *from) 1647dd7cddfSDavid du Colombier { 1657dd7cddfSDavid du Colombier int i; 1667dd7cddfSDavid du Colombier char *p; 1677dd7cddfSDavid du Colombier uchar *a; 1687dd7cddfSDavid du Colombier 1697dd7cddfSDavid du Colombier p = v4parseip(addr, from); 1707dd7cddfSDavid du Colombier 1717dd7cddfSDavid du Colombier if(*p == '/'){ 1727dd7cddfSDavid du Colombier /* as a number of prefix bits */ 1737dd7cddfSDavid du Colombier i = strtoul(p+1, &p, 0); 1747dd7cddfSDavid du Colombier if(i > 32) 1757dd7cddfSDavid du Colombier i = 32; 1767dd7cddfSDavid du Colombier memset(mask, 0, IPv4addrlen); 1777dd7cddfSDavid du Colombier for(a = mask; i >= 8; i -= 8) 1787dd7cddfSDavid du Colombier *a++ = 0xff; 1797dd7cddfSDavid du Colombier if(i > 0) 1807dd7cddfSDavid du Colombier *a = ~((1<<(8-i))-1); 1817dd7cddfSDavid du Colombier } else 1827dd7cddfSDavid du Colombier memcpy(mask, defmask(addr), IPv4addrlen); 1837dd7cddfSDavid du Colombier return p; 1843e12c5d1SDavid du Colombier } 185