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