]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libip/parseip.c
libip: return -1 in parseipmask() and parseipandmask() when mask is not ipv4 and...
[plan9front.git] / sys / src / libip / parseip.c
1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h>
4 #include <ip.h>
5
6 char*
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
41 ipcharok(int c)
42 {
43         return c == '.' || c == ':' || isascii(c) && isxdigit(c);
44 }
45
46 static int
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
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 == '.' || (*p == 0 && i == 0)){   /* ends with v4? */
77                         if(i > IPaddrlen-4){
78                                 memset(to, 0, IPaddrlen);
79                                 return -1;              /* parse error */
80                         }
81                         p = v4parseip(to+i, op);
82                         i += 4;
83                         break;
84                 }
85                 /* v6: at most 4 hex digits, followed by colon or delim */
86                 if(x != (ushort)x || *p != ':' && !delimchar(*p)) {
87                         memset(to, 0, IPaddrlen);
88                         return -1;                      /* parse error */
89                 }
90                 to[i] = x>>8;
91                 to[i+1] = x;
92                 if(*p == ':'){
93                         v4 = 0;
94                         if(*++p == ':'){        /* :: is elided zero short(s) */
95                                 if (elipsis) {
96                                         memset(to, 0, IPaddrlen);
97                                         return -1;      /* second :: */
98                                 }
99                                 elipsis = i+2;
100                                 p++;
101                         }
102                 } else if (p == op)             /* strtoul made no progress? */
103                         break;
104         }
105         if (p == from || !delimchar(*p)) {
106                 memset(to, 0, IPaddrlen);
107                 return -1;                              /* parse error */
108         }
109         if(i < IPaddrlen){
110                 memmove(&to[elipsis+IPaddrlen-i], &to[elipsis], i-elipsis);
111                 memset(&to[elipsis], 0, IPaddrlen-i);
112         }
113         if(v4){
114                 to[10] = to[11] = 0xff;
115                 return (ulong)nhgetl(to + IPv4off);
116         } else
117                 return 6;
118 }
119
120 /*
121  *  hack to allow ip v4 masks to be entered in the old
122  *  style
123  */
124 vlong
125 parseipmask(uchar *to, char *from, int v4)
126 {
127         vlong x;
128         int i, w;
129         uchar *p;
130
131         if(*from == '/'){
132                 /* as a number of prefix bits */
133                 i = atoi(from+1);
134                 if(i < 0)
135                         i = 0;
136                 if(i <= 32 && v4)
137                         i += 96;
138                 if(i > 128)
139                         i = 128;
140                 w = i;
141                 memset(to, 0, IPaddrlen);
142                 for(p = to; i >= 8; i -= 8)
143                         *p++ = 0xff;
144                 if(i > 0)
145                         *p = ~((1<<(8-i))-1);
146                 /*
147                  * identify as ipv6 if the mask is inexpressible as a v4 mask
148                  * (because it has too few mask bits).  Arguably, we could
149                  * always return 6 here.
150                  */
151                 if (w < 96)
152                         return v4 ? -1 : 6;
153                 x = (ulong)nhgetl(to+IPv4off);
154         } else {
155                 /* as a straight v4 bit mask */
156                 x = parseip(to, from);
157                 if(memcmp(to, v4prefix, IPv4off) == 0)
158                         memset(to, 0xff, IPv4off);
159                 else if(v4)
160                         x = -1;
161         }
162         return x;
163 }
164
165 vlong
166 parseipandmask(uchar *ip, uchar *mask, char *ipstr, char *maskstr)
167 {
168         vlong x;
169
170         x = parseip(ip, ipstr);
171         if(maskstr == nil)
172                 memset(mask, 0xff, IPaddrlen);
173         else if(parseipmask(mask, maskstr, memcmp(ip, v4prefix, IPv4off) == 0) == -1)
174                 x = -1;
175         return x;
176 }