c84d018eb73ae90524c7ebe5814d73d242ccd62a
[platform/upstream/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 unsigned get_unsigned(char *arg, const char *errmsg)
19 {
20         unsigned long res;
21         char *ptr;
22
23         if (*arg) {
24                 res = strtoul(arg, &ptr, 0);
25                 if (!*ptr && res <= UINT_MAX) {
26                         return res;
27                 }
28         }
29         invarg(arg, errmsg); /* does not return */
30 }
31
32 uint32_t get_u32(char *arg, const char *errmsg)
33 {
34         unsigned long res;
35         char *ptr;
36
37         if (*arg) {
38                 res = strtoul(arg, &ptr, 0);
39                 if (!*ptr && res <= 0xFFFFFFFFUL) {
40                         return res;
41                 }
42         }
43         invarg(arg, errmsg); /* does not return */
44 }
45
46 uint16_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                 if (!*ptr && res <= 0xFFFF) {
54                         return res;
55                 }
56         }
57         invarg(arg, errmsg); /* does not return */
58 }
59
60 int get_addr_1(inet_prefix *addr, char *name, int family)
61 {
62         memset(addr, 0, sizeof(*addr));
63
64         if (strcmp(name, bb_str_default) == 0
65          || strcmp(name, "all") == 0
66          || strcmp(name, "any") == 0
67         ) {
68                 addr->family = family;
69                 addr->bytelen = (family == AF_INET6 ? 16 : 4);
70                 addr->bitlen = -1;
71                 return 0;
72         }
73
74         if (strchr(name, ':')) {
75                 addr->family = AF_INET6;
76                 if (family != AF_UNSPEC && family != AF_INET6)
77                         return -1;
78                 if (inet_pton(AF_INET6, name, addr->data) <= 0)
79                         return -1;
80                 addr->bytelen = 16;
81                 addr->bitlen = -1;
82                 return 0;
83         }
84
85         addr->family = AF_INET;
86         if (family != AF_UNSPEC && family != AF_INET)
87                 return -1;
88         if (inet_pton(AF_INET, name, addr->data) <= 0)
89                 return -1;
90         addr->bytelen = 4;
91         addr->bitlen = -1;
92         return 0;
93 }
94
95 static int get_prefix_1(inet_prefix *dst, char *arg, int family)
96 {
97         int err;
98         unsigned plen;
99         char *slash;
100
101         memset(dst, 0, sizeof(*dst));
102
103         if (strcmp(arg, bb_str_default) == 0
104          || strcmp(arg, "all") == 0
105          || strcmp(arg, "any") == 0
106         ) {
107                 dst->family = family;
108                 /*dst->bytelen = 0; - done by memset */
109                 /*dst->bitlen = 0;*/
110                 return 0;
111         }
112
113         slash = strchr(arg, '/');
114         if (slash)
115                 *slash = '\0';
116         err = get_addr_1(dst, arg, family);
117         if (err == 0) {
118                 dst->bitlen = (dst->family == AF_INET6) ? 128 : 32;
119                 if (slash) {
120                         inet_prefix netmask_pfx;
121
122                         netmask_pfx.family = AF_UNSPEC;
123                         plen = bb_strtou(slash + 1, NULL, 0);
124                         if ((errno || plen > dst->bitlen)
125                          && (get_addr_1(&netmask_pfx, slash + 1, family)))
126                                 err = -1;
127                         else if (netmask_pfx.family == AF_INET) {
128                                 /* fill in prefix length of dotted quad */
129                                 uint32_t mask = ntohl(netmask_pfx.data[0]);
130                                 uint32_t host = ~mask;
131
132                                 /* a valid netmask must be 2^n - 1 */
133                                 if (!(host & (host + 1))) {
134                                         for (plen = 0; mask; mask <<= 1)
135                                                 ++plen;
136                                         if (plen >= 0 && plen <= dst->bitlen) {
137                                                 dst->bitlen = plen;
138                                                 /* dst->flags |= PREFIXLEN_SPECIFIED; */
139                                         } else
140                                                 err = -1;
141                                 } else
142                                         err = -1;
143                         } else {
144                                 /* plain prefix */
145                                 dst->bitlen = plen;
146                         }
147                 }
148         }
149         if (slash)
150                 *slash = '/';
151         return err;
152 }
153
154 int get_addr(inet_prefix *dst, char *arg, int family)
155 {
156         if (family == AF_PACKET) {
157                 bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "address");
158         }
159         if (get_addr_1(dst, arg, family)) {
160                 bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "address", arg);
161         }
162         return 0;
163 }
164
165 int get_prefix(inet_prefix *dst, char *arg, int family)
166 {
167         if (family == AF_PACKET) {
168                 bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "prefix");
169         }
170         if (get_prefix_1(dst, arg, family)) {
171                 bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg);
172         }
173         return 0;
174 }
175
176 uint32_t get_addr32(char *name)
177 {
178         inet_prefix addr;
179
180         if (get_addr_1(&addr, name, AF_INET)) {
181                 bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "IP", "address", name);
182         }
183         return addr.data[0];
184 }
185
186 void incomplete_command(void)
187 {
188         bb_error_msg_and_die("command line is not complete, try option \"help\"");
189 }
190
191 void invarg(const char *arg, const char *opt)
192 {
193         bb_error_msg_and_die(bb_msg_invalid_arg, arg, opt);
194 }
195
196 void duparg(const char *key, const char *arg)
197 {
198         bb_error_msg_and_die("duplicate \"%s\": \"%s\" is the second value", key, arg);
199 }
200
201 void duparg2(const char *key, const char *arg)
202 {
203         bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg);
204 }
205
206 int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits)
207 {
208         uint32_t *a1 = a->data;
209         uint32_t *a2 = b->data;
210         int words = bits >> 5;
211
212         bits &= 0x1f;
213
214         if (words)
215                 if (memcmp(a1, a2, words << 2))
216                         return -1;
217
218         if (bits) {
219                 uint32_t w1, w2;
220                 uint32_t mask;
221
222                 w1 = a1[words];
223                 w2 = a2[words];
224
225                 mask = htonl((0xffffffff) << (0x20 - bits));
226
227                 if ((w1 ^ w2) & mask)
228                         return 1;
229         }
230
231         return 0;
232 }
233
234 const char *rt_addr_n2a(int af,
235                 void *addr, char *buf, int buflen)
236 {
237         switch (af) {
238         case AF_INET:
239         case AF_INET6:
240                 return inet_ntop(af, addr, buf, buflen);
241         default:
242                 return "???";
243         }
244 }
245
246 #ifdef RESOLVE_HOSTNAMES
247 const char *format_host(int af, int len, void *addr, char *buf, int buflen)
248 {
249         if (resolve_hosts) {
250                 struct hostent *h_ent;
251
252                 if (len <= 0) {
253                         switch (af) {
254                         case AF_INET:
255                                 len = 4;
256                                 break;
257                         case AF_INET6:
258                                 len = 16;
259                                 break;
260                         default:;
261                         }
262                 }
263                 if (len > 0) {
264                         h_ent = gethostbyaddr(addr, len, af);
265                         if (h_ent != NULL) {
266                                 safe_strncpy(buf, h_ent->h_name, buflen);
267                                 return buf;
268                         }
269                 }
270         }
271         return rt_addr_n2a(af, addr, buf, buflen);
272 }
273 #endif