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