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