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