13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3ea58ad6fSDavid du Colombier #include <ctype.h>
47dd7cddfSDavid du Colombier #include <ip.h>
53e12c5d1SDavid du Colombier
67dd7cddfSDavid du Colombier char*
v4parseip(uchar * to,char * from)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
40ea58ad6fSDavid du Colombier static int
ipcharok(int c)41ea58ad6fSDavid du Colombier ipcharok(int c)
42ea58ad6fSDavid du Colombier {
43ea58ad6fSDavid du Colombier return c == '.' || c == ':' || isascii(c) && isxdigit(c);
44ea58ad6fSDavid du Colombier }
45ea58ad6fSDavid du Colombier
46ea58ad6fSDavid du Colombier static int
delimchar(int c)47ea58ad6fSDavid du Colombier delimchar(int c)
48ea58ad6fSDavid du Colombier {
49ea58ad6fSDavid du Colombier if(c == '\0')
50ea58ad6fSDavid du Colombier return 1;
51ea58ad6fSDavid du Colombier if(c == '.' || c == ':' || isascii(c) && isalnum(c))
52ea58ad6fSDavid du Colombier return 0;
53ea58ad6fSDavid du Colombier return 1;
54ea58ad6fSDavid du Colombier }
55ea58ad6fSDavid du Colombier
56ea58ad6fSDavid du Colombier /*
57ea58ad6fSDavid du Colombier * `from' may contain an address followed by other characters,
58ea58ad6fSDavid du Colombier * at least in /boot, so we permit whitespace (and more) after the address.
59ea58ad6fSDavid du Colombier * we do ensure that "delete" cannot be parsed as "de::".
60ea58ad6fSDavid du Colombier *
61ea58ad6fSDavid du Colombier * some callers don't check the return value for errors, so
62ea58ad6fSDavid du Colombier * set `to' to something distinctive in the case of a parse error.
63ea58ad6fSDavid du Colombier */
64ea58ad6fSDavid du Colombier vlong
parseip(uchar * to,char * from)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;
73ea58ad6fSDavid 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*03673ce5SDavid du Colombier if((*p == '.' && i <= IPaddrlen-4) || (*p == 0 && i == 0)){
77*03673ce5SDavid du Colombier /* ends with v4 */
787dd7cddfSDavid du Colombier p = v4parseip(to+i, op);
797dd7cddfSDavid du Colombier i += 4;
807dd7cddfSDavid du Colombier break;
817dd7cddfSDavid du Colombier }
82ea58ad6fSDavid du Colombier /* v6: at most 4 hex digits, followed by colon or delim */
83ea58ad6fSDavid du Colombier if(x != (ushort)x || *p != ':' && !delimchar(*p)) {
84ea58ad6fSDavid du Colombier memset(to, 0, IPaddrlen);
85ea58ad6fSDavid du Colombier return -1; /* parse error */
86ea58ad6fSDavid du Colombier }
877dd7cddfSDavid du Colombier to[i] = x>>8;
887dd7cddfSDavid du Colombier to[i+1] = x;
897dd7cddfSDavid du Colombier if(*p == ':'){
907dd7cddfSDavid du Colombier v4 = 0;
91ea58ad6fSDavid du Colombier if(*++p == ':'){ /* :: is elided zero short(s) */
92ea58ad6fSDavid du Colombier if (elipsis) {
93ea58ad6fSDavid du Colombier memset(to, 0, IPaddrlen);
94ea58ad6fSDavid du Colombier return -1; /* second :: */
95ea58ad6fSDavid du Colombier }
967dd7cddfSDavid du Colombier elipsis = i+2;
977dd7cddfSDavid du Colombier p++;
987dd7cddfSDavid du Colombier }
99ea58ad6fSDavid du Colombier } else if (p == op) /* strtoul made no progress? */
100ea58ad6fSDavid du Colombier break;
1017dd7cddfSDavid du Colombier }
102ea58ad6fSDavid du Colombier if (p == from || !delimchar(*p)) {
103ea58ad6fSDavid du Colombier memset(to, 0, IPaddrlen);
104ea58ad6fSDavid du Colombier return -1; /* parse error */
1057dd7cddfSDavid du Colombier }
106ea58ad6fSDavid du Colombier if(i < IPaddrlen){
107ea58ad6fSDavid du Colombier memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis);
108ea58ad6fSDavid du Colombier memset(&to[elipsis], 0, IPaddrlen-i);
1097dd7cddfSDavid du Colombier }
1107dd7cddfSDavid du Colombier if(v4){
1117dd7cddfSDavid du Colombier to[10] = to[11] = 0xff;
112ea58ad6fSDavid du Colombier return nhgetl(to + IPv4off);
1137dd7cddfSDavid du Colombier } else
1147dd7cddfSDavid du Colombier return 6;
1157dd7cddfSDavid du Colombier }
1167dd7cddfSDavid du Colombier
1177dd7cddfSDavid du Colombier /*
1187dd7cddfSDavid du Colombier * hack to allow ip v4 masks to be entered in the old
1197dd7cddfSDavid du Colombier * style
1207dd7cddfSDavid du Colombier */
121ea58ad6fSDavid du Colombier vlong
parseipmask(uchar * to,char * from)1227dd7cddfSDavid du Colombier parseipmask(uchar *to, char *from)
1237dd7cddfSDavid du Colombier {
124c62728daSDavid du Colombier int i, w;
125ea58ad6fSDavid du Colombier vlong x;
1267dd7cddfSDavid du Colombier uchar *p;
1277dd7cddfSDavid du Colombier
1287dd7cddfSDavid du Colombier if(*from == '/'){
1297dd7cddfSDavid du Colombier /* as a number of prefix bits */
1307dd7cddfSDavid du Colombier i = atoi(from+1);
1317dd7cddfSDavid du Colombier if(i < 0)
1327dd7cddfSDavid du Colombier i = 0;
1337dd7cddfSDavid du Colombier if(i > 128)
1347dd7cddfSDavid du Colombier i = 128;
135c62728daSDavid du Colombier w = i;
1367dd7cddfSDavid du Colombier memset(to, 0, IPaddrlen);
1377dd7cddfSDavid du Colombier for(p = to; i >= 8; i -= 8)
1387dd7cddfSDavid du Colombier *p++ = 0xff;
1397dd7cddfSDavid du Colombier if(i > 0)
1407dd7cddfSDavid du Colombier *p = ~((1<<(8-i))-1);
1417dd7cddfSDavid du Colombier x = nhgetl(to+IPv4off);
142c62728daSDavid du Colombier /*
143c62728daSDavid du Colombier * identify as ipv6 if the mask is inexpressible as a v4 mask
144ea58ad6fSDavid du Colombier * (because it has too few mask bits). Arguably, we could
145c62728daSDavid du Colombier * always return 6 here.
146c62728daSDavid du Colombier */
147ea58ad6fSDavid du Colombier if (w < 8*(IPaddrlen-IPv4addrlen))
148c62728daSDavid du Colombier return 6;
1497dd7cddfSDavid du Colombier } else {
150ea58ad6fSDavid du Colombier /* as a straight v4 bit mask */
1517dd7cddfSDavid du Colombier x = parseip(to, from);
152ea58ad6fSDavid du Colombier if (x != -1)
153ea58ad6fSDavid du Colombier x = (ulong)nhgetl(to + IPv4off);
1547dd7cddfSDavid du Colombier if(memcmp(to, v4prefix, IPv4off) == 0)
1557dd7cddfSDavid du Colombier memset(to, 0xff, IPv4off);
1567dd7cddfSDavid du Colombier }
1577dd7cddfSDavid du Colombier return x;
1587dd7cddfSDavid du Colombier }
1597dd7cddfSDavid du Colombier
1607dd7cddfSDavid du Colombier /*
1617dd7cddfSDavid du Colombier * parse a v4 ip address/mask in cidr format
1627dd7cddfSDavid du Colombier */
1637dd7cddfSDavid du Colombier char*
v4parsecidr(uchar * addr,uchar * mask,char * from)1647dd7cddfSDavid du Colombier v4parsecidr(uchar *addr, uchar *mask, char *from)
1657dd7cddfSDavid du Colombier {
1667dd7cddfSDavid du Colombier int i;
1677dd7cddfSDavid du Colombier char *p;
1687dd7cddfSDavid du Colombier uchar *a;
1697dd7cddfSDavid du Colombier
1707dd7cddfSDavid du Colombier p = v4parseip(addr, from);
1717dd7cddfSDavid du Colombier
1727dd7cddfSDavid du Colombier if(*p == '/'){
1737dd7cddfSDavid du Colombier /* as a number of prefix bits */
1747dd7cddfSDavid du Colombier i = strtoul(p+1, &p, 0);
1757dd7cddfSDavid du Colombier if(i > 32)
1767dd7cddfSDavid du Colombier i = 32;
1777dd7cddfSDavid du Colombier memset(mask, 0, IPv4addrlen);
1787dd7cddfSDavid du Colombier for(a = mask; i >= 8; i -= 8)
1797dd7cddfSDavid du Colombier *a++ = 0xff;
1807dd7cddfSDavid du Colombier if(i > 0)
1817dd7cddfSDavid du Colombier *a = ~((1<<(8-i))-1);
1827dd7cddfSDavid du Colombier } else
1837dd7cddfSDavid du Colombier memcpy(mask, defmask(addr), IPv4addrlen);
1847dd7cddfSDavid du Colombier return p;
1853e12c5d1SDavid du Colombier }
186