xref: /plan9/sys/src/libip/parseip.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 
5 char*
6 v4parseip(uchar *to, char *from)
7 {
8 	int i;
9 	char *p;
10 
11 	p = from;
12 	for(i = 0; i < 4 && *p; i++){
13 		to[i] = strtoul(p, &p, 0);
14 		if(*p == '.')
15 			p++;
16 	}
17 	switch(CLASS(to)){
18 	case 0:	/* class A - 1 uchar net */
19 	case 1:
20 		if(i == 3){
21 			to[3] = to[2];
22 			to[2] = to[1];
23 			to[1] = 0;
24 		} else if (i == 2){
25 			to[3] = to[1];
26 			to[1] = 0;
27 		}
28 		break;
29 	case 2:	/* class B - 2 uchar net */
30 		if(i == 3){
31 			to[3] = to[2];
32 			to[2] = 0;
33 		}
34 		break;
35 	}
36 	return p;
37 }
38 
39 ulong
40 parseip(uchar *to, char *from)
41 {
42 	int i, elipsis = 0, v4 = 1;
43 	ulong x;
44 	char *p, *op;
45 
46 	memset(to, 0, IPaddrlen);
47 	p = from;
48 	for(i = 0; i < 16 && *p; i+=2){
49 		op = p;
50 		x = strtoul(p, &p, 16);
51 		if(*p == '.' || (*p == 0 && i == 0)){
52 			p = v4parseip(to+i, op);
53 			i += 4;
54 			break;
55 		}
56 		to[i] = x>>8;
57 		to[i+1] = x;
58 		if(*p == ':'){
59 			v4 = 0;
60 			if(*++p == ':'){
61 				elipsis = i+2;
62 				p++;
63 			}
64 		}
65 	}
66 	if(i < 16){
67 		memmove(&to[elipsis+16-i], &to[elipsis], i-elipsis);
68 		memset(&to[elipsis], 0, 16-i);
69 	}
70 	if(v4){
71 		to[10] = to[11] = 0xff;
72 		return nhgetl(to+12);
73 	} else
74 		return 6;
75 }
76 
77 /*
78  *  hack to allow ip v4 masks to be entered in the old
79  *  style
80  */
81 ulong
82 parseipmask(uchar *to, char *from)
83 {
84 	ulong x;
85 	int i, w;
86 	uchar *p;
87 
88 	if(*from == '/'){
89 		/* as a number of prefix bits */
90 		i = atoi(from+1);
91 		if(i < 0)
92 			i = 0;
93 		if(i > 128)
94 			i = 128;
95 		w = i;
96 		memset(to, 0, IPaddrlen);
97 		for(p = to; i >= 8; i -= 8)
98 			*p++ = 0xff;
99 		if(i > 0)
100 			*p = ~((1<<(8-i))-1);
101 		x = nhgetl(to+IPv4off);
102 		/*
103 		 * identify as ipv6 if the mask is inexpressible as a v4 mask
104 		 * (because it has too few mask bits) or indistinguishable
105 		 * from the error value (all ones, -1)?  Arguably, we could
106 		 * always return 6 here.
107 		 */
108 		if (w < 8*(IPaddrlen-IPv4addrlen) || w == 128)
109 			return 6;
110 	} else {
111 		/* as a straight bit mask */
112 		x = parseip(to, from);
113 		if(memcmp(to, v4prefix, IPv4off) == 0)
114 			memset(to, 0xff, IPv4off);
115 	}
116 	return x;
117 }
118 
119 /*
120  *  parse a v4 ip address/mask in cidr format
121  */
122 char*
123 v4parsecidr(uchar *addr, uchar *mask, char *from)
124 {
125 	int i;
126 	char *p;
127 	uchar *a;
128 
129 	p = v4parseip(addr, from);
130 
131 	if(*p == '/'){
132 		/* as a number of prefix bits */
133 		i = strtoul(p+1, &p, 0);
134 		if(i > 32)
135 			i = 32;
136 		memset(mask, 0, IPv4addrlen);
137 		for(a = mask; i >= 8; i -= 8)
138 			*a++ = 0xff;
139 		if(i > 0)
140 			*a = ~((1<<(8-i))-1);
141 	} else
142 		memcpy(mask, defmask(addr), IPv4addrlen);
143 	return p;
144 }
145