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