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