xref: /plan9/sys/src/cmd/unix/drawterm/libip/parseip.c (revision 58da3067adcdccaaa043d0bfde28ba83b7ced07d)
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