blob: e63bb27fb95af2110acf4882e4757940e103a94e [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00002/*
3 * utils.c
4 *
Bernhard Reutner-Fischer20f40002006-01-30 17:17:14 +00005 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00006 *
7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 *
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00009 * Changes:
10 *
11 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
12 */
13
Rob Landleyecae66a2006-06-02 20:53:38 +000014#include "libbb.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000015#include "utils.h"
"Vladimir N. Oleynik"007a0112005-09-22 11:11:11 +000016#include "inet_common.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000017
18int 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}
Bernhard Reutner-Fischerc98c3172007-04-12 11:36:56 +000031//XXX: FIXME: use some libbb function instead
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000032int 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
Denis Vlasenko98ee06d2006-12-31 18:57:37 +000046int get_u32(uint32_t * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000047{
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
Denis Vlasenko98ee06d2006-12-31 18:57:37 +000060int get_u16(uint16_t * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000061{
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
Denis Vlasenko98ee06d2006-12-31 18:57:37 +000074int get_u8(uint8_t * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000075{
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
Denis Vlasenko98ee06d2006-12-31 18:57:37 +000088int get_s16(int16_t * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000089{
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
Denis Vlasenko98ee06d2006-12-31 18:57:37 +0000102int get_s8(int8_t * val, char *arg, int base)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000103{
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
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000116int get_addr_1(inet_prefix * addr, char *name, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000117{
118 char *cp;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000119 unsigned char *ap = (unsigned char *) addr->data;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000120 int i;
121
122 memset(addr, 0, sizeof(*addr));
123
Denis Vlasenko7ca39212006-11-21 20:34:21 +0000124 if (strcmp(name, bb_str_default) == 0 ||
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000125 strcmp(name, "all") == 0 || strcmp(name, "any") == 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000126 addr->family = family;
127 addr->bytelen = (family == AF_INET6 ? 16 : 4);
128 addr->bitlen = -1;
129 return 0;
130 }
131
132 if (strchr(name, ':')) {
133 addr->family = AF_INET6;
134 if (family != AF_UNSPEC && family != AF_INET6)
135 return -1;
136 if (inet_pton(AF_INET6, name, addr->data) <= 0)
137 return -1;
138 addr->bytelen = 16;
139 addr->bitlen = -1;
140 return 0;
141 }
142
143 addr->family = AF_INET;
144 if (family != AF_UNSPEC && family != AF_INET)
145 return -1;
146 addr->bytelen = 4;
147 addr->bitlen = -1;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000148 for (cp = name, i = 0; *cp; cp++) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000149 if (*cp <= '9' && *cp >= '0') {
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000150 ap[i] = 10 * ap[i] + (*cp - '0');
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000151 continue;
152 }
153 if (*cp == '.' && ++i <= 3)
154 continue;
155 return -1;
156 }
157 return 0;
158}
159
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000160int get_prefix_1(inet_prefix * dst, char *arg, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000161{
162 int err;
Eric Andersend78aea82006-01-30 18:00:02 +0000163 int plen;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000164 char *slash;
165
166 memset(dst, 0, sizeof(*dst));
167
Denis Vlasenko7ca39212006-11-21 20:34:21 +0000168 if (strcmp(arg, bb_str_default) == 0 || strcmp(arg, "any") == 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000169 dst->family = family;
170 dst->bytelen = 0;
171 dst->bitlen = 0;
172 return 0;
173 }
174
175 slash = strchr(arg, '/');
176 if (slash)
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000177 *slash = '\0';
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000178 err = get_addr_1(dst, arg, family);
179 if (err == 0) {
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000180 switch (dst->family) {
181 case AF_INET6:
182 dst->bitlen = 128;
183 break;
184 default:
185 case AF_INET:
186 dst->bitlen = 32;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000187 }
188 if (slash) {
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000189 if (get_integer(&plen, slash + 1, 0) || plen > dst->bitlen) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000190 err = -1;
191 goto done;
192 }
193 dst->bitlen = plen;
194 }
195 }
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000196 done:
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000197 if (slash)
198 *slash = '/';
199 return err;
200}
201
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000202int get_addr(inet_prefix * dst, char *arg, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000203{
204 if (family == AF_PACKET) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000205 bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000206 }
207 if (get_addr_1(dst, arg, family)) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000208 bb_error_msg_and_die("an inet address is expected rather than \"%s\"", arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000209 }
210 return 0;
211}
212
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000213int get_prefix(inet_prefix * dst, char *arg, int family)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000214{
215 if (family == AF_PACKET) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000216 bb_error_msg_and_die("\"%s\" may be inet address, but it is not allowed in this context", arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000217 }
218 if (get_prefix_1(dst, arg, family)) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000219 bb_error_msg_and_die("an inet address is expected rather than \"%s\"", arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000220 }
221 return 0;
222}
223
Denis Vlasenko98ee06d2006-12-31 18:57:37 +0000224uint32_t get_addr32(char *name)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000225{
226 inet_prefix addr;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000227
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000228 if (get_addr_1(&addr, name, AF_INET)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000229 bb_error_msg_and_die("an IP address is expected rather than \"%s\"", name);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000230 }
231 return addr.data[0];
232}
233
Mike Frysinger4e5936e2005-04-16 04:30:38 +0000234void incomplete_command(void)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000235{
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000236 bb_error_msg_and_die("command line is not complete, try option \"help\"");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000237}
238
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000239void invarg(const char *arg, const char *opt)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000240{
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000241 bb_error_msg_and_die(bb_msg_invalid_arg, arg, opt);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000242}
243
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000244void duparg(const char *key, const char *arg)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000245{
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000246 bb_error_msg_and_die("duplicate \"%s\": \"%s\" is the second value", key, arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000247}
248
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000249void duparg2(const char *key, const char *arg)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000250{
Denis Vlasenkoab2aea42007-01-29 22:51:58 +0000251 bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000252}
253
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000254int inet_addr_match(inet_prefix * a, inet_prefix * b, int bits)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000255{
Denis Vlasenko98ee06d2006-12-31 18:57:37 +0000256 uint32_t *a1 = a->data;
257 uint32_t *a2 = b->data;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000258 int words = bits >> 0x05;
259
260 bits &= 0x1f;
261
262 if (words)
263 if (memcmp(a1, a2, words << 2))
264 return -1;
265
266 if (bits) {
Denis Vlasenko98ee06d2006-12-31 18:57:37 +0000267 uint32_t w1, w2;
268 uint32_t mask;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000269
270 w1 = a1[words];
271 w2 = a2[words];
272
273 mask = htonl((0xffffffff) << (0x20 - bits));
274
275 if ((w1 ^ w2) & mask)
276 return 1;
277 }
278
279 return 0;
280}
281
Bernhard Reutner-Fischer20f40002006-01-30 17:17:14 +0000282const char *rt_addr_n2a(int af, int ATTRIBUTE_UNUSED len,
283 void *addr, char *buf, int buflen)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000284{
285 switch (af) {
286 case AF_INET:
287 case AF_INET6:
288 return inet_ntop(af, addr, buf, buflen);
289 default:
290 return "???";
291 }
292}
293
294
295const char *format_host(int af, int len, void *addr, char *buf, int buflen)
296{
297#ifdef RESOLVE_HOSTNAMES
298 if (resolve_hosts) {
299 struct hostent *h_ent;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000300
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000301 if (len <= 0) {
302 switch (af) {
303 case AF_INET:
304 len = 4;
305 break;
306 case AF_INET6:
307 len = 16;
308 break;
Glenn L McGrath50c00f42002-11-18 07:26:42 +0000309 default:;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000310 }
311 }
Denis Vlasenko8c1aaf32007-06-04 21:03:51 +0000312 if (len > 0) {
313 h_ent = gethostbyaddr(addr, len, af);
314 if (h_ent != NULL) {
315 safe_strncpy(buf, h_ent->h_name, buflen);
316 return buf;
317 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000318 }
319 }
320#endif
321 return rt_addr_n2a(af, len, addr, buf, buflen);
322}