Yet another major rework of the BusyBox config system, using the considerably
[oweals/busybox.git] / networking / libiproute / utils.c
1 /*
2  * utils.c
3  *
4  *              This program is free software; you can redistribute it and/or
5  *              modify it under the terms of the GNU General Public License
6  *              as published by the Free Software Foundation; either version
7  *              2 of the License, or (at your option) any later version.
8  *
9  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10  *
11  *
12  * Changes:
13  *
14  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <syslog.h>
21 #include <fcntl.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <string.h>
25 #include <netdb.h>
26 #include <arpa/inet.h>
27 #include <resolv.h>
28
29 #include "./linux/pkt_sched.h"
30 #include "utils.h"
31 #include "libbb.h"
32
33 int get_integer(int *val, char *arg, int base)
34 {
35         long res;
36         char *ptr;
37
38         if (!arg || !*arg)
39                 return -1;
40         res = strtol(arg, &ptr, base);
41         if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN)
42                 return -1;
43         *val = res;
44         return 0;
45 }
46
47 int get_unsigned(unsigned *val, char *arg, int base)
48 {
49         unsigned long res;
50         char *ptr;
51
52         if (!arg || !*arg)
53                 return -1;
54         res = strtoul(arg, &ptr, base);
55         if (!ptr || ptr == arg || *ptr || res > UINT_MAX)
56                 return -1;
57         *val = res;
58         return 0;
59 }
60
61 int get_u32(__u32 * val, char *arg, int base)
62 {
63         unsigned long res;
64         char *ptr;
65
66         if (!arg || !*arg)
67                 return -1;
68         res = strtoul(arg, &ptr, base);
69         if (!ptr || ptr == arg || *ptr || res > 0xFFFFFFFFUL)
70                 return -1;
71         *val = res;
72         return 0;
73 }
74
75 int get_u16(__u16 * val, char *arg, int base)
76 {
77         unsigned long res;
78         char *ptr;
79
80         if (!arg || !*arg)
81                 return -1;
82         res = strtoul(arg, &ptr, base);
83         if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
84                 return -1;
85         *val = res;
86         return 0;
87 }
88
89 int get_u8(__u8 * val, char *arg, int base)
90 {
91         unsigned long res;
92         char *ptr;
93
94         if (!arg || !*arg)
95                 return -1;
96         res = strtoul(arg, &ptr, base);
97         if (!ptr || ptr == arg || *ptr || res > 0xFF)
98                 return -1;
99         *val = res;
100         return 0;
101 }
102
103 int get_s16(__s16 * val, char *arg, int base)
104 {
105         long res;
106         char *ptr;
107
108         if (!arg || !*arg)
109                 return -1;
110         res = strtol(arg, &ptr, base);
111         if (!ptr || ptr == arg || *ptr || res > 0x7FFF || res < -0x8000)
112                 return -1;
113         *val = res;
114         return 0;
115 }
116
117 int get_s8(__s8 * val, char *arg, int base)
118 {
119         long res;
120         char *ptr;
121
122         if (!arg || !*arg)
123                 return -1;
124         res = strtol(arg, &ptr, base);
125         if (!ptr || ptr == arg || *ptr || res > 0x7F || res < -0x80)
126                 return -1;
127         *val = res;
128         return 0;
129 }
130
131 int get_addr_1(inet_prefix * addr, char *name, int family)
132 {
133         char *cp;
134         unsigned char *ap = (unsigned char *) addr->data;
135         int i;
136
137         memset(addr, 0, sizeof(*addr));
138
139         if (strcmp(name, "default") == 0 ||
140                 strcmp(name, "all") == 0 || strcmp(name, "any") == 0) {
141                 addr->family = family;
142                 addr->bytelen = (family == AF_INET6 ? 16 : 4);
143                 addr->bitlen = -1;
144                 return 0;
145         }
146
147         if (strchr(name, ':')) {
148                 addr->family = AF_INET6;
149                 if (family != AF_UNSPEC && family != AF_INET6)
150                         return -1;
151                 if (inet_pton(AF_INET6, name, addr->data) <= 0)
152                         return -1;
153                 addr->bytelen = 16;
154                 addr->bitlen = -1;
155                 return 0;
156         }
157
158         addr->family = AF_INET;
159         if (family != AF_UNSPEC && family != AF_INET)
160                 return -1;
161         addr->bytelen = 4;
162         addr->bitlen = -1;
163         for (cp = name, i = 0; *cp; cp++) {
164                 if (*cp <= '9' && *cp >= '0') {
165                         ap[i] = 10 * ap[i] + (*cp - '0');
166                         continue;
167                 }
168                 if (*cp == '.' && ++i <= 3)
169                         continue;
170                 return -1;
171         }
172         return 0;
173 }
174
175 int get_prefix_1(inet_prefix * dst, char *arg, int family)
176 {
177         int err;
178         unsigned plen;
179         char *slash;
180
181         memset(dst, 0, sizeof(*dst));
182
183         if (strcmp(arg, "default") == 0 || strcmp(arg, "any") == 0) {
184                 dst->family = family;
185                 dst->bytelen = 0;
186                 dst->bitlen = 0;
187                 return 0;
188         }
189
190         slash = strchr(arg, '/');
191         if (slash)
192                 *slash = 0;
193         err = get_addr_1(dst, arg, family);
194         if (err == 0) {
195                 switch (dst->family) {
196                 case AF_INET6:
197                         dst->bitlen = 128;
198                         break;
199                 default:
200                 case AF_INET:
201                         dst->bitlen = 32;
202                 }
203                 if (slash) {
204                         if (get_integer(&plen, slash + 1, 0) || plen > dst->bitlen) {
205                                 err = -1;
206                                 goto done;
207                         }
208                         dst->bitlen = plen;
209                 }
210         }
211   done:
212         if (slash)
213                 *slash = '/';
214         return err;
215 }
216
217 int get_addr(inet_prefix * dst, char *arg, int family)
218 {
219         if (family == AF_PACKET) {
220                 error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context.", arg);
221         }
222         if (get_addr_1(dst, arg, family)) {
223                 error_msg_and_die("an inet address is expected rather than \"%s\".", arg);
224         }
225         return 0;
226 }
227
228 int get_prefix(inet_prefix * dst, char *arg, int family)
229 {
230         if (family == AF_PACKET) {
231                 error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context.", arg);
232         }
233         if (get_prefix_1(dst, arg, family)) {
234                 error_msg_and_die("an inet address is expected rather than \"%s\".", arg);
235         }
236         return 0;
237 }
238
239 __u32 get_addr32(char *name)
240 {
241         inet_prefix addr;
242
243         if (get_addr_1(&addr, name, AF_INET)) {
244                 error_msg_and_die("an IP address is expected rather than \"%s\"", name);
245         }
246         return addr.data[0];
247 }
248
249 void incomplete_command()
250 {
251         error_msg("Command line is not complete. Try option \"help\"");
252         exit(-1);
253 }
254
255 void invarg(char *msg, char *arg)
256 {
257         error_msg("argument \"%s\" is wrong: %s", arg, msg);
258         exit(-1);
259 }
260
261 void duparg(char *key, char *arg)
262 {
263         error_msg("duplicate \"%s\": \"%s\" is the second value.", key, arg);
264         exit(-1);
265 }
266
267 void duparg2(char *key, char *arg)
268 {
269         error_msg("either \"%s\" is duplicate, or \"%s\" is a garbage.", key, arg);
270         exit(-1);
271 }
272
273 int matches(char *cmd, char *pattern)
274 {
275         int len = strlen(cmd);
276
277         if (len > strlen(pattern)) {
278                 return -1;
279         }
280         return memcmp(pattern, cmd, len);
281 }
282
283 int inet_addr_match(inet_prefix * a, inet_prefix * b, int bits)
284 {
285         __u32 *a1 = a->data;
286         __u32 *a2 = b->data;
287         int words = bits >> 0x05;
288
289         bits &= 0x1f;
290
291         if (words)
292                 if (memcmp(a1, a2, words << 2))
293                         return -1;
294
295         if (bits) {
296                 __u32 w1, w2;
297                 __u32 mask;
298
299                 w1 = a1[words];
300                 w2 = a2[words];
301
302                 mask = htonl((0xffffffff) << (0x20 - bits));
303
304                 if ((w1 ^ w2) & mask)
305                         return 1;
306         }
307
308         return 0;
309 }
310
311 int __iproute2_hz_internal;
312
313 int __get_hz(void)
314 {
315         int hz = 0;
316         FILE *fp = fopen("/proc/net/psched", "r");
317
318         if (fp) {
319                 unsigned nom, denom;
320
321                 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
322                         if (nom == 1000000)
323                                 hz = denom;
324                 fclose(fp);
325         }
326         if (hz)
327                 return hz;
328         return HZ;
329 }
330
331 const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen)
332 {
333         switch (af) {
334         case AF_INET:
335         case AF_INET6:
336                 return inet_ntop(af, addr, buf, buflen);
337         default:
338                 return "???";
339         }
340 }
341
342
343 const char *format_host(int af, int len, void *addr, char *buf, int buflen)
344 {
345 #ifdef RESOLVE_HOSTNAMES
346         if (resolve_hosts) {
347                 struct hostent *h_ent;
348
349                 if (len <= 0) {
350                         switch (af) {
351                         case AF_INET:
352                                 len = 4;
353                                 break;
354                         case AF_INET6:
355                                 len = 16;
356                                 break;
357                         default:;
358                         }
359                 }
360                 if (len > 0 && (h_ent = gethostbyaddr(addr, len, af)) != NULL) {
361                         snprintf(buf, buflen - 1, "%s", h_ent->h_name);
362                         return buf;
363                 }
364         }
365 #endif
366         return rt_addr_n2a(af, len, addr, buf, buflen);
367 }