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