source: branches/3.2/mindi-busybox/networking/libiproute/utils.c @ 3232

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