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