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  * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
11  */
12 
13 #include "ip_common.h"  /* #include "libbb.h" is inside */
14 #include "common_bufsiz.h"
15 #include "rt_names.h"
16 #include "utils.h"
17 
18 #ifndef RTAX_RTTVAR
19 #define RTAX_RTTVAR RTAX_HOPS
20 #endif
21 
22 
23 struct filter_t {
24 	int tb;
25 	smallint flushed;
26 	char *flushb;
27 	int flushp;
28 	int flushe;
29 	struct rtnl_handle *rth;
30 	//int protocol, protocolmask; - write-only fields?!
31 	//int scope, scopemask; - unused
32 	//int type; - read-only
33 	//int typemask; - unused
34 	//int tos, tosmask; - unused
35 	int iif;
36 	int oif;
37 	//int realm, realmmask; - unused
38 	//inet_prefix rprefsrc; - read-only
39 	inet_prefix rvia;
40 	inet_prefix rdst;
41 	inet_prefix mdst;
42 	inet_prefix rsrc;
43 	inet_prefix msrc;
44 } FIX_ALIASING;
45 typedef struct filter_t filter_t;
46 
47 #define G_filter (*(filter_t*)bb_common_bufsiz1)
48 #define INIT_G() do { setup_common_bufsiz(); } while (0)
49 
flush_update(void)50 static int flush_update(void)
51 {
52 	if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
53 		bb_perror_msg("can't send flush request");
54 		return -1;
55 	}
56 	G_filter.flushp = 0;
57 	return 0;
58 }
59 
print_route(const struct sockaddr_nl * who UNUSED_PARAM,struct nlmsghdr * n,void * arg UNUSED_PARAM)60 static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
61 		struct nlmsghdr *n, void *arg UNUSED_PARAM)
62 {
63 	struct rtmsg *r = NLMSG_DATA(n);
64 	int len = n->nlmsg_len;
65 	struct rtattr *tb[RTA_MAX+1];
66 	inet_prefix dst;
67 	inet_prefix src;
68 	int host_len = -1;
69 	uint32_t tid;
70 
71 	if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
72 		fprintf(stderr, "Not a route: %08x %08x %08x\n",
73 			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
74 		return 0;
75 	}
76 	if (G_filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
77 		return 0;
78 	len -= NLMSG_LENGTH(sizeof(*r));
79 	if (len < 0)
80 		bb_error_msg_and_die("wrong nlmsg len %d", len);
81 
82 	memset(tb, 0, sizeof(tb));
83 	parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
84 
85 	if (tb[RTA_TABLE])
86 		tid = *(uint32_t *)RTA_DATA(tb[RTA_TABLE]);
87 	else
88 		tid = r->rtm_table;
89 
90 	if (r->rtm_family == AF_INET6)
91 		host_len = 128;
92 	else if (r->rtm_family == AF_INET)
93 		host_len = 32;
94 
95 	if (r->rtm_family == AF_INET6) {
96 		if (G_filter.tb) {
97 			if (G_filter.tb < 0) {
98 				if (!(r->rtm_flags & RTM_F_CLONED)) {
99 					return 0;
100 				}
101 			} else {
102 				if (r->rtm_flags & RTM_F_CLONED) {
103 					return 0;
104 				}
105 				if (G_filter.tb == RT_TABLE_LOCAL) {
106 					if (r->rtm_type != RTN_LOCAL) {
107 						return 0;
108 					}
109 				} else if (G_filter.tb == RT_TABLE_MAIN) {
110 					if (r->rtm_type == RTN_LOCAL) {
111 						return 0;
112 					}
113 				} else {
114 					return 0;
115 				}
116 			}
117 		}
118 	} else {
119 		if (G_filter.tb > 0 && G_filter.tb != tid) {
120 			return 0;
121 		}
122 	}
123 	if (G_filter.rdst.family
124 	 && (r->rtm_family != G_filter.rdst.family || G_filter.rdst.bitlen > r->rtm_dst_len)
125 	) {
126 		return 0;
127 	}
128 	if (G_filter.mdst.family
129 	 && (r->rtm_family != G_filter.mdst.family
130 	    || (G_filter.mdst.bitlen >= 0 && G_filter.mdst.bitlen < r->rtm_dst_len)
131 	    )
132 	) {
133 		return 0;
134 	}
135 	if (G_filter.rsrc.family
136 	 && (r->rtm_family != G_filter.rsrc.family || G_filter.rsrc.bitlen > r->rtm_src_len)
137 	) {
138 		return 0;
139 	}
140 	if (G_filter.msrc.family
141 	 && (r->rtm_family != G_filter.msrc.family
142 	    || (G_filter.msrc.bitlen >= 0 && G_filter.msrc.bitlen < r->rtm_src_len)
143 	    )
144 	) {
145 		return 0;
146 	}
147 
148 	memset(&src, 0, sizeof(src));
149 	memset(&dst, 0, sizeof(dst));
150 
151 	if (tb[RTA_SRC]) {
152 		src.bitlen = r->rtm_src_len;
153 		src.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
154 		memcpy(src.data, RTA_DATA(tb[RTA_SRC]), src.bytelen);
155 	}
156 	if (tb[RTA_DST]) {
157 		dst.bitlen = r->rtm_dst_len;
158 		dst.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
159 		memcpy(dst.data, RTA_DATA(tb[RTA_DST]), dst.bytelen);
160 	}
161 
162 	if (G_filter.rdst.family
163 	 && inet_addr_match(&dst, &G_filter.rdst, G_filter.rdst.bitlen)
164 	) {
165 		return 0;
166 	}
167 	if (G_filter.mdst.family
168 	 && G_filter.mdst.bitlen >= 0
169 	 && inet_addr_match(&dst, &G_filter.mdst, r->rtm_dst_len)
170 	) {
171 		return 0;
172 	}
173 	if (G_filter.rsrc.family
174 	 && inet_addr_match(&src, &G_filter.rsrc, G_filter.rsrc.bitlen)
175 	) {
176 		return 0;
177 	}
178 	if (G_filter.msrc.family && G_filter.msrc.bitlen >= 0
179 	 && inet_addr_match(&src, &G_filter.msrc, r->rtm_src_len)
180 	) {
181 		return 0;
182 	}
183 	if (G_filter.oif != 0) {
184 		if (!tb[RTA_OIF])
185 			return 0;
186 		if (G_filter.oif != *(int*)RTA_DATA(tb[RTA_OIF]))
187 			return 0;
188 	}
189 
190 	if (G_filter.flushb) {
191 		struct nlmsghdr *fn;
192 
193 		/* We are creating route flush commands */
194 
195 		if (r->rtm_family == AF_INET6
196 		 && r->rtm_dst_len == 0
197 		 && r->rtm_type == RTN_UNREACHABLE
198 		 && tb[RTA_PRIORITY]
199 		 && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1
200 		) {
201 			return 0;
202 		}
203 
204 		if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) {
205 			if (flush_update())
206 				xfunc_die();
207 		}
208 		fn = (void*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp));
209 		memcpy(fn, n, n->nlmsg_len);
210 		fn->nlmsg_type = RTM_DELROUTE;
211 		fn->nlmsg_flags = NLM_F_REQUEST;
212 		fn->nlmsg_seq = ++G_filter.rth->seq;
213 		G_filter.flushp = (((char*)fn) + n->nlmsg_len) - G_filter.flushb;
214 		G_filter.flushed = 1;
215 		return 0;
216 	}
217 
218 	/* We are printing routes */
219 
220 	if (n->nlmsg_type == RTM_DELROUTE) {
221 		printf("Deleted ");
222 	}
223 	if (r->rtm_type != RTN_UNICAST /* && !G_filter.type - always 0 */) {
224 		printf("%s ", rtnl_rtntype_n2a(r->rtm_type));
225 	}
226 
227 	if (tb[RTA_DST]) {
228 		if (r->rtm_dst_len != host_len) {
229 			printf("%s/%u ",
230 				rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_DST])),
231 				r->rtm_dst_len
232 			);
233 		} else {
234 			printf("%s ", format_host(r->rtm_family,
235 						RTA_PAYLOAD(tb[RTA_DST]),
236 						RTA_DATA(tb[RTA_DST]))
237 			);
238 		}
239 	} else if (r->rtm_dst_len) {
240 		printf("0/%d ", r->rtm_dst_len);
241 	} else {
242 		printf("default ");
243 	}
244 	if (tb[RTA_SRC]) {
245 		if (r->rtm_src_len != host_len) {
246 			printf("from %s/%u ",
247 				rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_SRC])),
248 				r->rtm_src_len
249 			);
250 		} else {
251 			printf("from %s ", format_host(r->rtm_family,
252 						RTA_PAYLOAD(tb[RTA_SRC]),
253 						RTA_DATA(tb[RTA_SRC]))
254 			);
255 		}
256 	} else if (r->rtm_src_len) {
257 		printf("from 0/%u ", r->rtm_src_len);
258 	}
259 	if (tb[RTA_GATEWAY] && G_filter.rvia.bitlen != host_len) {
260 		printf("via %s ", format_host(r->rtm_family,
261 					RTA_PAYLOAD(tb[RTA_GATEWAY]),
262 					RTA_DATA(tb[RTA_GATEWAY]))
263 		);
264 	}
265 	if (tb[RTA_OIF]) {
266 		printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
267 	}
268 #if ENABLE_FEATURE_IP_RULE
269 	if (tid && tid != RT_TABLE_MAIN && !G_filter.tb)
270 		printf("table %s ", rtnl_rttable_n2a(tid));
271 #endif
272 
273 	/* Todo: parse & show "proto kernel", "scope link" here */
274 
275 	if (tb[RTA_PREFSRC] && /*G_filter.rprefsrc.bitlen - always 0*/ 0 != host_len) {
276 		/* Do not use format_host(). It is our local addr
277 		   and symbolic name will not be useful.
278 		 */
279 		printf(" src %s ", rt_addr_n2a(r->rtm_family,
280 					RTA_DATA(tb[RTA_PREFSRC])));
281 	}
282 	if (tb[RTA_PRIORITY]) {
283 		printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
284 	}
285 	if (r->rtm_flags & RTNH_F_DEAD) {
286 		printf("dead ");
287 	}
288 	if (r->rtm_flags & RTNH_F_ONLINK) {
289 		printf("onlink ");
290 	}
291 	if (r->rtm_flags & RTNH_F_PERVASIVE) {
292 		printf("pervasive ");
293 	}
294 	if (r->rtm_flags & RTM_F_NOTIFY) {
295 		printf("notify ");
296 	}
297 
298 	if (r->rtm_family == AF_INET6) {
299 		struct rta_cacheinfo *ci = NULL;
300 		if (tb[RTA_CACHEINFO]) {
301 			ci = RTA_DATA(tb[RTA_CACHEINFO]);
302 		}
303 		if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
304 			if (r->rtm_flags & RTM_F_CLONED) {
305 				printf("%c    cache ", _SL_);
306 			}
307 			if (ci->rta_expires) {
308 				printf(" expires %dsec", ci->rta_expires / get_hz());
309 			}
310 			if (ci->rta_error != 0) {
311 				printf(" error %d", ci->rta_error);
312 			}
313 		} else if (ci) {
314 			if (ci->rta_error != 0)
315 				printf(" error %d", ci->rta_error);
316 		}
317 	}
318 	if (tb[RTA_IIF] && G_filter.iif == 0) {
319 		printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
320 	}
321 	bb_putchar('\n');
322 	return 0;
323 }
324 
325 /* Return value becomes exitcode. It's okay to not return at all */
iproute_modify(int cmd,unsigned flags,char ** argv)326 static int iproute_modify(int cmd, unsigned flags, char **argv)
327 {
328 	static const char keywords[] ALIGN1 =
329 		"src\0""via\0""mtu\0""lock\0""scope\0""protocol\0"IF_FEATURE_IP_RULE("table\0")
330 		"dev\0""oif\0""to\0""metric\0""onlink\0";
331 	enum {
332 		ARG_src,
333 		ARG_via,
334 		ARG_mtu, PARM_lock,
335 		ARG_scope,
336 		ARG_protocol,
337 IF_FEATURE_IP_RULE(ARG_table,)
338 		ARG_dev,
339 		ARG_oif,
340 		ARG_to,
341 		ARG_metric,
342 		ARG_onlink,
343 	};
344 	enum {
345 		gw_ok = 1 << 0,
346 		dst_ok = 1 << 1,
347 		proto_ok = 1 << 2,
348 		type_ok = 1 << 3
349 	};
350 	struct rtnl_handle rth;
351 	struct {
352 		struct nlmsghdr n;
353 		struct rtmsg    r;
354 		char            buf[1024];
355 	} req;
356 	char mxbuf[256];
357 	struct rtattr * mxrta = (void*)mxbuf;
358 	unsigned mxlock = 0;
359 	char *d = NULL;
360 	smalluint ok = 0;
361 	smalluint scope_ok = 0;
362 	int arg;
363 
364 	memset(&req, 0, sizeof(req));
365 
366 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
367 	req.n.nlmsg_flags = NLM_F_REQUEST | flags;
368 	req.n.nlmsg_type = cmd;
369 	req.r.rtm_family = preferred_family;
370 	if (RT_TABLE_MAIN != 0) /* if it is zero, memset already did it */
371 		req.r.rtm_table = RT_TABLE_MAIN;
372 	if (RT_SCOPE_NOWHERE != 0)
373 		req.r.rtm_scope = RT_SCOPE_NOWHERE;
374 
375 	if (cmd != RTM_DELROUTE) {
376 		req.r.rtm_scope = RT_SCOPE_UNIVERSE;
377 		if (RTPROT_BOOT != 0)
378 			req.r.rtm_protocol = RTPROT_BOOT;
379 		if (RTN_UNICAST != 0)
380 			req.r.rtm_type = RTN_UNICAST;
381 	}
382 
383 	mxrta->rta_type = RTA_METRICS;
384 	mxrta->rta_len = RTA_LENGTH(0);
385 
386 	while (*argv) {
387 		arg = index_in_substrings(keywords, *argv);
388 		if (arg == ARG_src) {
389 			inet_prefix addr;
390 			NEXT_ARG();
391 			get_addr(&addr, *argv, req.r.rtm_family);
392 			if (req.r.rtm_family == AF_UNSPEC)
393 				req.r.rtm_family = addr.family;
394 			addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
395 		} else if (arg == ARG_via) {
396 			inet_prefix addr;
397 			ok |= gw_ok;
398 			NEXT_ARG();
399 			get_addr(&addr, *argv, req.r.rtm_family);
400 			if (req.r.rtm_family == AF_UNSPEC) {
401 				req.r.rtm_family = addr.family;
402 			}
403 			addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
404 		} else if (arg == ARG_mtu) {
405 			unsigned mtu;
406 			NEXT_ARG();
407 			if (index_in_strings(keywords, *argv) == PARM_lock) {
408 				mxlock |= (1 << RTAX_MTU);
409 				NEXT_ARG();
410 			}
411 			mtu = get_unsigned(*argv, "mtu");
412 			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
413 		} else if (arg == ARG_scope) {
414 			uint32_t scope;
415 			NEXT_ARG();
416 			if (rtnl_rtscope_a2n(&scope, *argv))
417 				invarg_1_to_2(*argv, "scope");
418 			req.r.rtm_scope = scope;
419 			scope_ok = 1;
420 		} else if (arg == ARG_protocol) {
421 			uint32_t prot;
422 			NEXT_ARG();
423 			if (rtnl_rtprot_a2n(&prot, *argv))
424 				invarg_1_to_2(*argv, "protocol");
425 			req.r.rtm_protocol = prot;
426 			ok |= proto_ok;
427 #if ENABLE_FEATURE_IP_RULE
428 		} else if (arg == ARG_table) {
429 			uint32_t tid;
430 			NEXT_ARG();
431 			if (rtnl_rttable_a2n(&tid, *argv))
432 				invarg_1_to_2(*argv, "table");
433 			if (tid < 256)
434 				req.r.rtm_table = tid;
435 			else {
436 				req.r.rtm_table = RT_TABLE_UNSPEC;
437 				addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
438 			}
439 #endif
440 		} else if (arg == ARG_dev || arg == ARG_oif) {
441 			NEXT_ARG();
442 			d = *argv;
443 		} else if (arg == ARG_metric) {
444 			uint32_t metric;
445 			NEXT_ARG();
446 			metric = get_u32(*argv, "metric");
447 			addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
448 		} else if (arg == ARG_onlink) {
449 			req.r.rtm_flags |= RTNH_F_ONLINK;
450 		} else {
451 			int type;
452 			inet_prefix dst;
453 
454 			if (arg == ARG_to) {
455 				NEXT_ARG();
456 			}
457 			if ((**argv < '0' || **argv > '9')
458 			 && rtnl_rtntype_a2n(&type, *argv) == 0
459 			) {
460 				NEXT_ARG();
461 				req.r.rtm_type = type;
462 				ok |= type_ok;
463 			}
464 
465 			if (ok & dst_ok) {
466 				duparg2("to", *argv);
467 			}
468 			get_prefix(&dst, *argv, req.r.rtm_family);
469 			if (req.r.rtm_family == AF_UNSPEC) {
470 				req.r.rtm_family = dst.family;
471 			}
472 			req.r.rtm_dst_len = dst.bitlen;
473 			ok |= dst_ok;
474 			if (dst.bytelen) {
475 				addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
476 			}
477 		}
478 		argv++;
479 	}
480 
481 	xrtnl_open(&rth);
482 
483 	if (d)  {
484 		int idx;
485 
486 		ll_init_map(&rth);
487 
488 		if (d) {
489 			idx = xll_name_to_index(d);
490 			addattr32(&req.n, sizeof(req), RTA_OIF, idx);
491 		}
492 	}
493 
494 	if (mxrta->rta_len > RTA_LENGTH(0)) {
495 		if (mxlock) {
496 			rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
497 		}
498 		addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
499 	}
500 
501 	if (!scope_ok) {
502 		if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT)
503 			req.r.rtm_scope = RT_SCOPE_HOST;
504 		else
505 		if (req.r.rtm_type == RTN_BROADCAST
506 		 || req.r.rtm_type == RTN_MULTICAST
507 		 || req.r.rtm_type == RTN_ANYCAST
508 		) {
509 			req.r.rtm_scope = RT_SCOPE_LINK;
510 		}
511 		else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) {
512 			if (cmd == RTM_DELROUTE)
513 				req.r.rtm_scope = RT_SCOPE_NOWHERE;
514 			else if (!(ok & gw_ok))
515 				req.r.rtm_scope = RT_SCOPE_LINK;
516 		}
517 	}
518 
519 	if (req.r.rtm_family == AF_UNSPEC) {
520 		req.r.rtm_family = AF_INET;
521 	}
522 
523 	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
524 		return 2;
525 	}
526 
527 	return 0;
528 }
529 
rtnl_rtcache_request(struct rtnl_handle * rth,int family)530 static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
531 {
532 	struct {
533 		struct nlmsghdr nlh;
534 		struct rtmsg rtm;
535 	} req;
536 	struct sockaddr_nl nladdr;
537 
538 	memset(&nladdr, 0, sizeof(nladdr));
539 	memset(&req, 0, sizeof(req));
540 	nladdr.nl_family = AF_NETLINK;
541 
542 	req.nlh.nlmsg_len = sizeof(req);
543 	if (RTM_GETROUTE)
544 		req.nlh.nlmsg_type = RTM_GETROUTE;
545 	if (NLM_F_ROOT | NLM_F_REQUEST)
546 		req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
547 	/*req.nlh.nlmsg_pid = 0; - memset did it already */
548 	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
549 	req.rtm.rtm_family = family;
550 	if (RTM_F_CLONED)
551 		req.rtm.rtm_flags = RTM_F_CLONED;
552 
553 	return xsendto(rth->fd, (void*)&req, sizeof(req), (struct sockaddr*)&nladdr, sizeof(nladdr));
554 }
555 
iproute_flush_cache(void)556 static void iproute_flush_cache(void)
557 {
558 	static const char fn[] ALIGN1 = "/proc/sys/net/ipv4/route/flush";
559 	int flush_fd = open_or_warn(fn, O_WRONLY);
560 
561 	if (flush_fd < 0) {
562 		return;
563 	}
564 
565 	if (write(flush_fd, "-1", 2) < 2) {
566 		bb_perror_msg("can't flush routing cache");
567 		return;
568 	}
569 	close(flush_fd);
570 }
571 
iproute_reset_filter(void)572 static void iproute_reset_filter(void)
573 {
574 	memset(&G_filter, 0, sizeof(G_filter));
575 	G_filter.mdst.bitlen = -1;
576 	G_filter.msrc.bitlen = -1;
577 }
578 
579 /* Return value becomes exitcode. It's okay to not return at all */
iproute_list_or_flush(char ** argv,int flush)580 static int iproute_list_or_flush(char **argv, int flush)
581 {
582 	int do_ipv6 = preferred_family;
583 	struct rtnl_handle rth;
584 	char *id = NULL;
585 	char *od = NULL;
586 	static const char keywords[] ALIGN1 =
587 		/* "ip route list/flush" parameters: */
588 		"protocol\0" "dev\0"   "oif\0"   "iif\0"
589 		"via\0"      "table\0" "cache\0"
590 		"from\0"     "to\0"
591 		/* and possible further keywords */
592 		"all\0"
593 		"root\0"
594 		"match\0"
595 		"exact\0"
596 		"main\0"
597 		;
598 	enum {
599 		KW_proto, KW_dev,   KW_oif,  KW_iif,
600 		KW_via,   KW_table, KW_cache,
601 		KW_from,  KW_to,
602 		/* */
603 		KW_all,
604 		KW_root,
605 		KW_match,
606 		KW_exact,
607 		KW_main,
608 	};
609 	int arg, parm;
610 
611 	iproute_reset_filter();
612 	G_filter.tb = RT_TABLE_MAIN;
613 
614 	if (flush && !*argv)
615 		bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\"");
616 
617 	while (*argv) {
618 		arg = index_in_substrings(keywords, *argv);
619 		if (arg == KW_proto) {
620 			uint32_t prot = 0;
621 			NEXT_ARG();
622 			//G_filter.protocolmask = -1;
623 			if (rtnl_rtprot_a2n(&prot, *argv)) {
624 				if (index_in_strings(keywords, *argv) != KW_all)
625 					invarg_1_to_2(*argv, "protocol");
626 				prot = 0;
627 				//G_filter.protocolmask = 0;
628 			}
629 			//G_filter.protocol = prot;
630 		} else if (arg == KW_dev || arg == KW_oif) {
631 			NEXT_ARG();
632 			od = *argv;
633 		} else if (arg == KW_iif) {
634 			NEXT_ARG();
635 			id = *argv;
636 		} else if (arg == KW_via) {
637 			NEXT_ARG();
638 			get_prefix(&G_filter.rvia, *argv, do_ipv6);
639 		} else if (arg == KW_table) { /* table all/cache/main */
640 			NEXT_ARG();
641 			parm = index_in_substrings(keywords, *argv);
642 			if (parm == KW_cache)
643 				G_filter.tb = -1;
644 			else if (parm == KW_all)
645 				G_filter.tb = 0;
646 			else if (parm != KW_main) {
647 #if ENABLE_FEATURE_IP_RULE
648 				uint32_t tid;
649 				if (rtnl_rttable_a2n(&tid, *argv))
650 					invarg_1_to_2(*argv, "table");
651 				G_filter.tb = tid;
652 #else
653 				invarg_1_to_2(*argv, "table");
654 #endif
655 			}
656 		} else if (arg == KW_cache) {
657 			/* The command 'ip route flush cache' is used by OpenSWAN.
658 			 * Assuming it's a synonym for 'ip route flush table cache' */
659 			G_filter.tb = -1;
660 		} else if (arg == KW_from) {
661 			NEXT_ARG();
662 			parm = index_in_substrings(keywords, *argv);
663 			if (parm == KW_root) {
664 				NEXT_ARG();
665 				get_prefix(&G_filter.rsrc, *argv, do_ipv6);
666 			} else if (parm == KW_match) {
667 				NEXT_ARG();
668 				get_prefix(&G_filter.msrc, *argv, do_ipv6);
669 			} else {
670 				if (parm == KW_exact)
671 					NEXT_ARG();
672 				get_prefix(&G_filter.msrc, *argv, do_ipv6);
673 				G_filter.rsrc = G_filter.msrc;
674 			}
675 		} else { /* "to" is the default parameter */
676 			if (arg == KW_to) {
677 				NEXT_ARG();
678 				arg = index_in_substrings(keywords, *argv);
679 			}
680 			/* parm = arg; - would be more plausible, but we reuse 'arg' here */
681 			if (arg == KW_root) {
682 				NEXT_ARG();
683 				get_prefix(&G_filter.rdst, *argv, do_ipv6);
684 			} else if (arg == KW_match) {
685 				NEXT_ARG();
686 				get_prefix(&G_filter.mdst, *argv, do_ipv6);
687 			} else { /* "to exact" is the default */
688 				if (arg == KW_exact)
689 					NEXT_ARG();
690 				get_prefix(&G_filter.mdst, *argv, do_ipv6);
691 				G_filter.rdst = G_filter.mdst;
692 			}
693 		}
694 		argv++;
695 	}
696 
697 	if (do_ipv6 == AF_UNSPEC && G_filter.tb) {
698 		do_ipv6 = AF_INET;
699 	}
700 
701 	xrtnl_open(&rth);
702 	ll_init_map(&rth);
703 
704 	if (id || od)  {
705 		int idx;
706 
707 		if (id) {
708 			idx = xll_name_to_index(id);
709 			G_filter.iif = idx;
710 		}
711 		if (od) {
712 			idx = xll_name_to_index(od);
713 			G_filter.oif = idx;
714 		}
715 	}
716 
717 	if (flush) {
718 		char flushb[4096-512];
719 
720 		if (G_filter.tb == -1) { /* "flush table cache" */
721 			if (do_ipv6 != AF_INET6)
722 				iproute_flush_cache();
723 			if (do_ipv6 == AF_INET)
724 				return 0;
725 		}
726 
727 		G_filter.flushb = flushb;
728 		G_filter.flushp = 0;
729 		G_filter.flushe = sizeof(flushb);
730 		G_filter.rth = &rth;
731 
732 		for (;;) {
733 			xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
734 			G_filter.flushed = 0;
735 			xrtnl_dump_filter(&rth, print_route, NULL);
736 			if (G_filter.flushed == 0)
737 				return 0;
738 			if (flush_update())
739 				return 1;
740 		}
741 	}
742 
743 	if (G_filter.tb != -1) {
744 		xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
745 	} else if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
746 		bb_perror_msg_and_die("can't send dump request");
747 	}
748 	xrtnl_dump_filter(&rth, print_route, NULL);
749 
750 	return 0;
751 }
752 
753 
754 /* Return value becomes exitcode. It's okay to not return at all */
iproute_get(char ** argv)755 static int iproute_get(char **argv)
756 {
757 	struct rtnl_handle rth;
758 	struct {
759 		struct nlmsghdr n;
760 		struct rtmsg    r;
761 		char            buf[1024];
762 	} req;
763 	char *idev = NULL;
764 	char *odev = NULL;
765 	bool connected = 0;
766 	bool from_ok = 0;
767 	static const char options[] ALIGN1 =
768 		"from\0""iif\0""oif\0""dev\0""notify\0""connected\0""to\0";
769 
770 	memset(&req, 0, sizeof(req));
771 
772 	iproute_reset_filter();
773 
774 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
775 	if (NLM_F_REQUEST)
776 		req.n.nlmsg_flags = NLM_F_REQUEST;
777 	if (RTM_GETROUTE)
778 		req.n.nlmsg_type = RTM_GETROUTE;
779 	req.r.rtm_family = preferred_family;
780 	/*req.r.rtm_table = 0; - memset did this already */
781 	/*req.r.rtm_protocol = 0;*/
782 	/*req.r.rtm_scope = 0;*/
783 	/*req.r.rtm_type = 0;*/
784 	/*req.r.rtm_src_len = 0;*/
785 	/*req.r.rtm_dst_len = 0;*/
786 	/*req.r.rtm_tos = 0;*/
787 
788 	while (*argv) {
789 		switch (index_in_strings(options, *argv)) {
790 			case 0: /* from */
791 			{
792 				inet_prefix addr;
793 				NEXT_ARG();
794 				from_ok = 1;
795 				get_prefix(&addr, *argv, req.r.rtm_family);
796 				if (req.r.rtm_family == AF_UNSPEC) {
797 					req.r.rtm_family = addr.family;
798 				}
799 				if (addr.bytelen) {
800 					addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
801 				}
802 				req.r.rtm_src_len = addr.bitlen;
803 				break;
804 			}
805 			case 1: /* iif */
806 				NEXT_ARG();
807 				idev = *argv;
808 				break;
809 			case 2: /* oif */
810 			case 3: /* dev */
811 				NEXT_ARG();
812 				odev = *argv;
813 				break;
814 			case 4: /* notify */
815 				req.r.rtm_flags |= RTM_F_NOTIFY;
816 				break;
817 			case 5: /* connected */
818 				connected = 1;
819 				break;
820 			case 6: /* to */
821 				NEXT_ARG();
822 			default:
823 			{
824 				inet_prefix addr;
825 				get_prefix(&addr, *argv, req.r.rtm_family);
826 				if (req.r.rtm_family == AF_UNSPEC) {
827 					req.r.rtm_family = addr.family;
828 				}
829 				if (addr.bytelen) {
830 					addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
831 				}
832 				req.r.rtm_dst_len = addr.bitlen;
833 			}
834 		}
835 		argv++;
836 	}
837 
838 	if (req.r.rtm_dst_len == 0) {
839 		bb_error_msg_and_die("need at least destination address");
840 	}
841 
842 	xrtnl_open(&rth);
843 
844 	ll_init_map(&rth);
845 
846 	if (idev || odev)  {
847 		int idx;
848 
849 		if (idev) {
850 			idx = xll_name_to_index(idev);
851 			addattr32(&req.n, sizeof(req), RTA_IIF, idx);
852 		}
853 		if (odev) {
854 			idx = xll_name_to_index(odev);
855 			addattr32(&req.n, sizeof(req), RTA_OIF, idx);
856 		}
857 	}
858 
859 	if (req.r.rtm_family == AF_UNSPEC) {
860 		req.r.rtm_family = AF_INET;
861 	}
862 
863 	if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
864 		return 2;
865 	}
866 
867 	if (connected && !from_ok) {
868 		struct rtmsg *r = NLMSG_DATA(&req.n);
869 		int len = req.n.nlmsg_len;
870 		struct rtattr * tb[RTA_MAX+1];
871 
872 		print_route(NULL, &req.n, NULL);
873 
874 		if (req.n.nlmsg_type != RTM_NEWROUTE) {
875 			bb_error_msg_and_die("not a route?");
876 		}
877 		len -= NLMSG_LENGTH(sizeof(*r));
878 		if (len < 0) {
879 			bb_error_msg_and_die("wrong len %d", len);
880 		}
881 
882 		memset(tb, 0, sizeof(tb));
883 		parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
884 
885 		if (tb[RTA_PREFSRC]) {
886 			tb[RTA_PREFSRC]->rta_type = RTA_SRC;
887 			r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
888 		} else if (!tb[RTA_SRC]) {
889 			bb_error_msg_and_die("can't connect the route");
890 		}
891 		if (!odev && tb[RTA_OIF]) {
892 			tb[RTA_OIF]->rta_type = 0;
893 		}
894 		if (tb[RTA_GATEWAY]) {
895 			tb[RTA_GATEWAY]->rta_type = 0;
896 		}
897 		if (!idev && tb[RTA_IIF]) {
898 			tb[RTA_IIF]->rta_type = 0;
899 		}
900 		req.n.nlmsg_flags = NLM_F_REQUEST;
901 		req.n.nlmsg_type = RTM_GETROUTE;
902 
903 		if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
904 			return 2;
905 		}
906 	}
907 	print_route(NULL, &req.n, NULL);
908 	return 0;
909 }
910 
911 /* Return value becomes exitcode. It's okay to not return at all */
do_iproute(char ** argv)912 int FAST_FUNC do_iproute(char **argv)
913 {
914 	static const char ip_route_commands[] ALIGN1 =
915 	/*0-3*/	"add\0""append\0""change\0""chg\0"
916 	/*4-7*/	"delete\0""get\0""list\0""show\0"
917 	/*8..*/	"prepend\0""replace\0""test\0""flush\0";
918 	int command_num;
919 	unsigned flags = 0;
920 	int cmd = RTM_NEWROUTE;
921 
922 	INIT_G();
923 
924 	if (!*argv)
925 		return iproute_list_or_flush(argv, 0);
926 
927 	/* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */
928 	/* It probably means that it is using "first match" rule */
929 	command_num = index_in_substrings(ip_route_commands, *argv);
930 
931 	switch (command_num) {
932 		case 0: /* add */
933 			flags = NLM_F_CREATE|NLM_F_EXCL;
934 			break;
935 		case 1: /* append */
936 			flags = NLM_F_CREATE|NLM_F_APPEND;
937 			break;
938 		case 2: /* change */
939 		case 3: /* chg */
940 			flags = NLM_F_REPLACE;
941 			break;
942 		case 4: /* delete */
943 			cmd = RTM_DELROUTE;
944 			break;
945 		case 5: /* get */
946 			return iproute_get(argv+1);
947 		case 6: /* list */
948 		case 7: /* show */
949 			return iproute_list_or_flush(argv+1, 0);
950 		case 8: /* prepend */
951 			flags = NLM_F_CREATE;
952 			break;
953 		case 9: /* replace */
954 			flags = NLM_F_CREATE|NLM_F_REPLACE;
955 			break;
956 		case 10: /* test */
957 			flags = NLM_F_EXCL;
958 			break;
959 		case 11: /* flush */
960 			return iproute_list_or_flush(argv+1, 1);
961 		default:
962 			invarg_1_to_2(*argv, applet_name);
963 	}
964 
965 	return iproute_modify(cmd, flags, argv+1);
966 }
967