source: MondoRescue/trunk/mindi-busybox/networking/libiproute/iproute.c@ 904

Last change on this file since 904 was 821, checked in by Bruno Cornec, 18 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 19.4 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * iproute.c "ip route".
4 *
5 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
6 *
7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 *
9 *
10 * Changes:
11 *
12 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
13 * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
14 */
15
16#include "libbb.h"
17
18#include <sys/socket.h>
19
20#include <string.h>
21#include <fcntl.h>
22#include <unistd.h>
23
24#include "rt_names.h"
25#include "utils.h"
26#include "ip_common.h"
27
28#ifndef RTAX_RTTVAR
29#define RTAX_RTTVAR RTAX_HOPS
30#endif
31
32
33static struct
34{
35 int tb;
36 int flushed;
37 char *flushb;
38 int flushp;
39 int flushe;
40 struct rtnl_handle *rth;
41 int protocol, protocolmask;
42 int scope, scopemask;
43 int type, typemask;
44 int tos, tosmask;
45 int iif, iifmask;
46 int oif, oifmask;
47 int realm, realmmask;
48 inet_prefix rprefsrc;
49 inet_prefix rvia;
50 inet_prefix rdst;
51 inet_prefix mdst;
52 inet_prefix rsrc;
53 inet_prefix msrc;
54} filter;
55
56static int flush_update(void)
57{
58 if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
59 perror("Failed to send flush request\n");
60 return -1;
61 }
62 filter.flushp = 0;
63 return 0;
64}
65
66static int print_route(struct sockaddr_nl *who ATTRIBUTE_UNUSED,
67 struct nlmsghdr *n, void *arg)
68{
69 FILE *fp = (FILE*)arg;
70 struct rtmsg *r = NLMSG_DATA(n);
71 int len = n->nlmsg_len;
72 struct rtattr * tb[RTA_MAX+1];
73 char abuf[256];
74 inet_prefix dst;
75 inet_prefix src;
76 int host_len = -1;
77 SPRINT_BUF(b1);
78
79
80 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
81 fprintf(stderr, "Not a route: %08x %08x %08x\n",
82 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
83 return 0;
84 }
85 if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
86 return 0;
87 len -= NLMSG_LENGTH(sizeof(*r));
88 if (len < 0) {
89 bb_error_msg("wrong nlmsg len %d", len);
90 return -1;
91 }
92
93 if (r->rtm_family == AF_INET6)
94 host_len = 128;
95 else if (r->rtm_family == AF_INET)
96 host_len = 32;
97
98 if (r->rtm_family == AF_INET6) {
99 if (filter.tb) {
100 if (filter.tb < 0) {
101 if (!(r->rtm_flags&RTM_F_CLONED)) {
102 return 0;
103 }
104 } else {
105 if (r->rtm_flags&RTM_F_CLONED) {
106 return 0;
107 }
108 if (filter.tb == RT_TABLE_LOCAL) {
109 if (r->rtm_type != RTN_LOCAL) {
110 return 0;
111 }
112 } else if (filter.tb == RT_TABLE_MAIN) {
113 if (r->rtm_type == RTN_LOCAL) {
114 return 0;
115 }
116 } else {
117 return 0;
118 }
119 }
120 }
121 } else {
122 if (filter.tb > 0 && filter.tb != r->rtm_table) {
123 return 0;
124 }
125 }
126 if (filter.rdst.family &&
127 (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) {
128 return 0;
129 }
130 if (filter.mdst.family &&
131 (r->rtm_family != filter.mdst.family ||
132 (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) {
133 return 0;
134 }
135 if (filter.rsrc.family &&
136 (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) {
137 return 0;
138 }
139 if (filter.msrc.family &&
140 (r->rtm_family != filter.msrc.family ||
141 (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) {
142 return 0;
143 }
144
145 memset(tb, 0, sizeof(tb));
146 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
147
148 if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen))
149 return 0;
150 if (filter.mdst.family && filter.mdst.bitlen >= 0 &&
151 inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len))
152 return 0;
153
154 if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen))
155 return 0;
156 if (filter.msrc.family && filter.msrc.bitlen >= 0 &&
157 inet_addr_match(&src, &filter.msrc, r->rtm_src_len))
158 return 0;
159
160 if (filter.flushb &&
161 r->rtm_family == AF_INET6 &&
162 r->rtm_dst_len == 0 &&
163 r->rtm_type == RTN_UNREACHABLE &&
164 tb[RTA_PRIORITY] &&
165 *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1)
166 return 0;
167
168 if (filter.flushb) {
169 struct nlmsghdr *fn;
170 if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
171 if (flush_update())
172 return -1;
173 }
174 fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
175 memcpy(fn, n, n->nlmsg_len);
176 fn->nlmsg_type = RTM_DELROUTE;
177 fn->nlmsg_flags = NLM_F_REQUEST;
178 fn->nlmsg_seq = ++filter.rth->seq;
179 filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
180 filter.flushed++;
181 return 0;
182 }
183
184 if (n->nlmsg_type == RTM_DELROUTE) {
185 fprintf(fp, "Deleted ");
186 }
187 if (r->rtm_type != RTN_UNICAST && !filter.type) {
188 fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
189 }
190
191 if (tb[RTA_DST]) {
192 if (r->rtm_dst_len != host_len) {
193 fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
194 RTA_PAYLOAD(tb[RTA_DST]),
195 RTA_DATA(tb[RTA_DST]),
196 abuf, sizeof(abuf)),
197 r->rtm_dst_len
198 );
199 } else {
200 fprintf(fp, "%s ", format_host(r->rtm_family,
201 RTA_PAYLOAD(tb[RTA_DST]),
202 RTA_DATA(tb[RTA_DST]),
203 abuf, sizeof(abuf))
204 );
205 }
206 } else if (r->rtm_dst_len) {
207 fprintf(fp, "0/%d ", r->rtm_dst_len);
208 } else {
209 fprintf(fp, "default ");
210 }
211 if (tb[RTA_SRC]) {
212 if (r->rtm_src_len != host_len) {
213 fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
214 RTA_PAYLOAD(tb[RTA_SRC]),
215 RTA_DATA(tb[RTA_SRC]),
216 abuf, sizeof(abuf)),
217 r->rtm_src_len
218 );
219 } else {
220 fprintf(fp, "from %s ", format_host(r->rtm_family,
221 RTA_PAYLOAD(tb[RTA_SRC]),
222 RTA_DATA(tb[RTA_SRC]),
223 abuf, sizeof(abuf))
224 );
225 }
226 } else if (r->rtm_src_len) {
227 fprintf(fp, "from 0/%u ", r->rtm_src_len);
228 }
229 if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
230 fprintf(fp, "via %s ",
231 format_host(r->rtm_family,
232 RTA_PAYLOAD(tb[RTA_GATEWAY]),
233 RTA_DATA(tb[RTA_GATEWAY]),
234 abuf, sizeof(abuf)));
235 }
236 if (tb[RTA_OIF] && filter.oifmask != -1) {
237 fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
238 }
239
240 if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
241 /* Do not use format_host(). It is our local addr
242 and symbolic name will not be useful.
243 */
244 fprintf(fp, " src %s ",
245 rt_addr_n2a(r->rtm_family,
246 RTA_PAYLOAD(tb[RTA_PREFSRC]),
247 RTA_DATA(tb[RTA_PREFSRC]),
248 abuf, sizeof(abuf)));
249 }
250 if (tb[RTA_PRIORITY]) {
251 fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY]));
252 }
253 if (r->rtm_family == AF_INET6) {
254 struct rta_cacheinfo *ci = NULL;
255 if (tb[RTA_CACHEINFO]) {
256 ci = RTA_DATA(tb[RTA_CACHEINFO]);
257 }
258 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
259 static int hz;
260 if (!hz) {
261 hz = get_hz();
262 }
263 if (r->rtm_flags & RTM_F_CLONED) {
264 fprintf(fp, "%s cache ", _SL_);
265 }
266 if (ci->rta_expires) {
267 fprintf(fp, " expires %dsec", ci->rta_expires/hz);
268 }
269 if (ci->rta_error != 0) {
270 fprintf(fp, " error %d", ci->rta_error);
271 }
272 } else if (ci) {
273 if (ci->rta_error != 0)
274 fprintf(fp, " error %d", ci->rta_error);
275 }
276 }
277 if (tb[RTA_IIF] && filter.iifmask != -1) {
278 fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
279 }
280 fprintf(fp, "\n");
281 fflush(fp);
282 return 0;
283}
284
285static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
286{
287 struct rtnl_handle rth;
288 struct {
289 struct nlmsghdr n;
290 struct rtmsg r;
291 char buf[1024];
292 } req;
293 char mxbuf[256];
294 struct rtattr * mxrta = (void*)mxbuf;
295 unsigned mxlock = 0;
296 char *d = NULL;
297 int gw_ok = 0;
298 int dst_ok = 0;
299 int proto_ok = 0;
300 int type_ok = 0;
301
302 memset(&req, 0, sizeof(req));
303
304 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
305 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
306 req.n.nlmsg_type = cmd;
307 req.r.rtm_family = preferred_family;
308 req.r.rtm_table = RT_TABLE_MAIN;
309 req.r.rtm_scope = RT_SCOPE_NOWHERE;
310
311 if (cmd != RTM_DELROUTE) {
312 req.r.rtm_protocol = RTPROT_BOOT;
313 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
314 req.r.rtm_type = RTN_UNICAST;
315 }
316
317 mxrta->rta_type = RTA_METRICS;
318 mxrta->rta_len = RTA_LENGTH(0);
319
320 while (argc > 0) {
321 if (strcmp(*argv, "src") == 0) {
322 inet_prefix addr;
323 NEXT_ARG();
324 get_addr(&addr, *argv, req.r.rtm_family);
325 if (req.r.rtm_family == AF_UNSPEC) {
326 req.r.rtm_family = addr.family;
327 }
328 addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
329 } else if (strcmp(*argv, "via") == 0) {
330 inet_prefix addr;
331 gw_ok = 1;
332 NEXT_ARG();
333 get_addr(&addr, *argv, req.r.rtm_family);
334 if (req.r.rtm_family == AF_UNSPEC) {
335 req.r.rtm_family = addr.family;
336 }
337 addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
338 } else if (strcmp(*argv, "mtu") == 0) {
339 unsigned mtu;
340 NEXT_ARG();
341 if (strcmp(*argv, "lock") == 0) {
342 mxlock |= (1<<RTAX_MTU);
343 NEXT_ARG();
344 }
345 if (get_unsigned(&mtu, *argv, 0)) {
346 invarg(*argv, "mtu");
347 }
348 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
349 } else if (matches(*argv, "protocol") == 0) {
350 uint32_t prot;
351 NEXT_ARG();
352 if (rtnl_rtprot_a2n(&prot, *argv))
353 invarg(*argv, "protocol");
354 req.r.rtm_protocol = prot;
355 proto_ok =1;
356 } else if (strcmp(*argv, "dev") == 0 ||
357 strcmp(*argv, "oif") == 0) {
358 NEXT_ARG();
359 d = *argv;
360 } else {
361 int type;
362 inet_prefix dst;
363
364 if (strcmp(*argv, "to") == 0) {
365 NEXT_ARG();
366 }
367 if ((**argv < '0' || **argv > '9') &&
368 rtnl_rtntype_a2n(&type, *argv) == 0) {
369 NEXT_ARG();
370 req.r.rtm_type = type;
371 type_ok = 1;
372 }
373
374 if (dst_ok) {
375 duparg2("to", *argv);
376 }
377 get_prefix(&dst, *argv, req.r.rtm_family);
378 if (req.r.rtm_family == AF_UNSPEC) {
379 req.r.rtm_family = dst.family;
380 }
381 req.r.rtm_dst_len = dst.bitlen;
382 dst_ok = 1;
383 if (dst.bytelen) {
384 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
385 }
386 }
387 argc--; argv++;
388 }
389
390 if (rtnl_open(&rth, 0) < 0) {
391 exit(1);
392 }
393
394 if (d) {
395 int idx;
396
397 ll_init_map(&rth);
398
399 if (d) {
400 if ((idx = ll_name_to_index(d)) == 0) {
401 bb_error_msg("Cannot find device \"%s\"", d);
402 return -1;
403 }
404 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
405 }
406 }
407
408 if (mxrta->rta_len > RTA_LENGTH(0)) {
409 if (mxlock) {
410 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
411 }
412 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
413 }
414
415 if (req.r.rtm_family == AF_UNSPEC) {
416 req.r.rtm_family = AF_INET;
417 }
418
419 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
420 exit(2);
421 }
422
423 return 0;
424}
425
426static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
427{
428 struct {
429 struct nlmsghdr nlh;
430 struct rtmsg rtm;
431 } req;
432 struct sockaddr_nl nladdr;
433
434 memset(&nladdr, 0, sizeof(nladdr));
435 memset(&req, 0, sizeof(req));
436 nladdr.nl_family = AF_NETLINK;
437
438 req.nlh.nlmsg_len = sizeof(req);
439 req.nlh.nlmsg_type = RTM_GETROUTE;
440 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST;
441 req.nlh.nlmsg_pid = 0;
442 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
443 req.rtm.rtm_family = family;
444 req.rtm.rtm_flags |= RTM_F_CLONED;
445
446 return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
447}
448
449static int iproute_flush_cache(void)
450{
451#define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush"
452
453 int len;
454 int flush_fd = open (ROUTE_FLUSH_PATH, O_WRONLY);
455 char *buffer = "-1";
456
457 if (flush_fd < 0) {
458 fprintf (stderr, "Cannot open \"%s\"\n", ROUTE_FLUSH_PATH);
459 return -1;
460 }
461
462 len = strlen (buffer);
463
464 if ((write (flush_fd, (void *)buffer, len)) < len) {
465 fprintf (stderr, "Cannot flush routing cache\n");
466 return -1;
467 }
468 close(flush_fd);
469 return 0;
470}
471
472static void iproute_reset_filter(void)
473{
474 memset(&filter, 0, sizeof(filter));
475 filter.mdst.bitlen = -1;
476 filter.msrc.bitlen = -1;
477}
478
479static int iproute_list_or_flush(int argc, char **argv, int flush)
480{
481 int do_ipv6 = preferred_family;
482 struct rtnl_handle rth;
483 char *id = NULL;
484 char *od = NULL;
485
486 iproute_reset_filter();
487 filter.tb = RT_TABLE_MAIN;
488
489 if (flush && argc <= 0) {
490 bb_error_msg(bb_msg_requires_arg, "\"ip route flush\"");
491 return -1;
492 }
493
494 while (argc > 0) {
495 if (matches(*argv, "protocol") == 0) {
496 uint32_t prot = 0;
497 NEXT_ARG();
498 filter.protocolmask = -1;
499 if (rtnl_rtprot_a2n(&prot, *argv)) {
500 if (strcmp(*argv, "all") != 0) {
501 invarg(*argv, "protocol");
502 }
503 prot = 0;
504 filter.protocolmask = 0;
505 }
506 filter.protocol = prot;
507 } else if (strcmp(*argv, "dev") == 0 ||
508 strcmp(*argv, "oif") == 0) {
509 NEXT_ARG();
510 od = *argv;
511 } else if (strcmp(*argv, "iif") == 0) {
512 NEXT_ARG();
513 id = *argv;
514 } else if (matches(*argv, "from") == 0) {
515 NEXT_ARG();
516 if (matches(*argv, "root") == 0) {
517 NEXT_ARG();
518 get_prefix(&filter.rsrc, *argv, do_ipv6);
519 } else if (matches(*argv, "match") == 0) {
520 NEXT_ARG();
521 get_prefix(&filter.msrc, *argv, do_ipv6);
522 } else {
523 if (matches(*argv, "exact") == 0) {
524 NEXT_ARG();
525 }
526 get_prefix(&filter.msrc, *argv, do_ipv6);
527 filter.rsrc = filter.msrc;
528 }
529 } else {
530 if (matches(*argv, "to") == 0) {
531 NEXT_ARG();
532 }
533 if (matches(*argv, "root") == 0) {
534 NEXT_ARG();
535 get_prefix(&filter.rdst, *argv, do_ipv6);
536 } else if (matches(*argv, "match") == 0) {
537 NEXT_ARG();
538 get_prefix(&filter.mdst, *argv, do_ipv6);
539 } else if (matches(*argv, "table") == 0) {
540 NEXT_ARG();
541 if (matches(*argv, "cache") == 0) {
542 filter.tb = -1;
543 } else if (matches(*argv, "main") != 0) {
544 invarg(*argv, "table");
545 }
546 } else if (matches(*argv, "cache") == 0) {
547 filter.tb = -1;
548 } else {
549 if (matches(*argv, "exact") == 0) {
550 NEXT_ARG();
551 }
552 get_prefix(&filter.mdst, *argv, do_ipv6);
553 filter.rdst = filter.mdst;
554 }
555 }
556 argc--; argv++;
557 }
558
559 if (do_ipv6 == AF_UNSPEC && filter.tb) {
560 do_ipv6 = AF_INET;
561 }
562
563 if (rtnl_open(&rth, 0) < 0) {
564 exit(1);
565 }
566
567 ll_init_map(&rth);
568
569 if (id || od) {
570 int idx;
571
572 if (id) {
573 if ((idx = ll_name_to_index(id)) == 0) {
574 bb_error_msg("Cannot find device \"%s\"", id);
575 return -1;
576 }
577 filter.iif = idx;
578 filter.iifmask = -1;
579 }
580 if (od) {
581 if ((idx = ll_name_to_index(od)) == 0) {
582 bb_error_msg("Cannot find device \"%s\"", od);
583 }
584 filter.oif = idx;
585 filter.oifmask = -1;
586 }
587 }
588
589 if (flush) {
590 char flushb[4096-512];
591
592 if (filter.tb == -1) {
593 if (do_ipv6 != AF_INET6)
594 iproute_flush_cache();
595 if (do_ipv6 == AF_INET)
596 return 0;
597 }
598
599 filter.flushb = flushb;
600 filter.flushp = 0;
601 filter.flushe = sizeof(flushb);
602 filter.rth = &rth;
603
604 for (;;) {
605 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
606 perror("Cannot send dump request");
607 return -1;
608 }
609 filter.flushed = 0;
610 if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
611 bb_error_msg("Flush terminated\n");
612 return -1;
613 }
614 if (filter.flushed == 0) {
615 fflush(stdout);
616 return 0;
617 }
618 if (flush_update() < 0)
619 exit(1);
620 }
621 }
622
623 if (filter.tb != -1) {
624 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
625 bb_perror_msg_and_die("Cannot send dump request");
626 }
627 } else {
628 if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
629 bb_perror_msg_and_die("Cannot send dump request");
630 }
631 }
632
633 if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
634 bb_error_msg_and_die("Dump terminated");
635 }
636
637 exit(0);
638}
639
640
641static int iproute_get(int argc, char **argv)
642{
643 struct rtnl_handle rth;
644 struct {
645 struct nlmsghdr n;
646 struct rtmsg r;
647 char buf[1024];
648 } req;
649 char *idev = NULL;
650 char *odev = NULL;
651 int connected = 0;
652 int from_ok = 0;
653 static const char * const options[] =
654 { "from", "iif", "oif", "dev", "notify", "connected", "to", 0 };
655
656 memset(&req, 0, sizeof(req));
657
658 iproute_reset_filter();
659
660 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
661 req.n.nlmsg_flags = NLM_F_REQUEST;
662 req.n.nlmsg_type = RTM_GETROUTE;
663 req.r.rtm_family = preferred_family;
664 req.r.rtm_table = 0;
665 req.r.rtm_protocol = 0;
666 req.r.rtm_scope = 0;
667 req.r.rtm_type = 0;
668 req.r.rtm_src_len = 0;
669 req.r.rtm_dst_len = 0;
670 req.r.rtm_tos = 0;
671
672 while (argc > 0) {
673 switch (compare_string_array(options, *argv)) {
674 case 0: /* from */
675 {
676 inet_prefix addr;
677 NEXT_ARG();
678 from_ok = 1;
679 get_prefix(&addr, *argv, req.r.rtm_family);
680 if (req.r.rtm_family == AF_UNSPEC) {
681 req.r.rtm_family = addr.family;
682 }
683 if (addr.bytelen) {
684 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
685 }
686 req.r.rtm_src_len = addr.bitlen;
687 break;
688 }
689 case 1: /* iif */
690 NEXT_ARG();
691 idev = *argv;
692 break;
693 case 2: /* oif */
694 case 3: /* dev */
695 NEXT_ARG();
696 odev = *argv;
697 break;
698 case 4: /* notify */
699 req.r.rtm_flags |= RTM_F_NOTIFY;
700 break;
701 case 5: /* connected */
702 connected = 1;
703 break;
704 case 6: /* to */
705 NEXT_ARG();
706 default:
707 {
708 inet_prefix addr;
709 get_prefix(&addr, *argv, req.r.rtm_family);
710 if (req.r.rtm_family == AF_UNSPEC) {
711 req.r.rtm_family = addr.family;
712 }
713 if (addr.bytelen) {
714 addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
715 }
716 req.r.rtm_dst_len = addr.bitlen;
717 }
718 argc--; argv++;
719 }
720 }
721
722 if (req.r.rtm_dst_len == 0) {
723 bb_error_msg_and_die("need at least destination address");
724 }
725
726 if (rtnl_open(&rth, 0) < 0)
727 exit(1);
728
729 ll_init_map(&rth);
730
731 if (idev || odev) {
732 int idx;
733
734 if (idev) {
735 if ((idx = ll_name_to_index(idev)) == 0) {
736 bb_error_msg("Cannot find device \"%s\"", idev);
737 return -1;
738 }
739 addattr32(&req.n, sizeof(req), RTA_IIF, idx);
740 }
741 if (odev) {
742 if ((idx = ll_name_to_index(odev)) == 0) {
743 bb_error_msg("Cannot find device \"%s\"", odev);
744 return -1;
745 }
746 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
747 }
748 }
749
750 if (req.r.rtm_family == AF_UNSPEC) {
751 req.r.rtm_family = AF_INET;
752 }
753
754 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
755 exit(2);
756 }
757
758 if (connected && !from_ok) {
759 struct rtmsg *r = NLMSG_DATA(&req.n);
760 int len = req.n.nlmsg_len;
761 struct rtattr * tb[RTA_MAX+1];
762
763 if (print_route(NULL, &req.n, (void*)stdout) < 0) {
764 bb_error_msg_and_die("An error :-)");
765 }
766
767 if (req.n.nlmsg_type != RTM_NEWROUTE) {
768 bb_error_msg("Not a route?");
769 return -1;
770 }
771 len -= NLMSG_LENGTH(sizeof(*r));
772 if (len < 0) {
773 bb_error_msg("Wrong len %d", len);
774 return -1;
775 }
776
777 memset(tb, 0, sizeof(tb));
778 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
779
780 if (tb[RTA_PREFSRC]) {
781 tb[RTA_PREFSRC]->rta_type = RTA_SRC;
782 r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
783 } else if (!tb[RTA_SRC]) {
784 bb_error_msg("Failed to connect the route");
785 return -1;
786 }
787 if (!odev && tb[RTA_OIF]) {
788 tb[RTA_OIF]->rta_type = 0;
789 }
790 if (tb[RTA_GATEWAY]) {
791 tb[RTA_GATEWAY]->rta_type = 0;
792 }
793 if (!idev && tb[RTA_IIF]) {
794 tb[RTA_IIF]->rta_type = 0;
795 }
796 req.n.nlmsg_flags = NLM_F_REQUEST;
797 req.n.nlmsg_type = RTM_GETROUTE;
798
799 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
800 exit(2);
801 }
802 }
803
804 if (print_route(NULL, &req.n, (void*)stdout) < 0) {
805 bb_error_msg_and_die("An error :-)");
806 }
807
808 exit(0);
809}
810
811int do_iproute(int argc, char **argv)
812{
813 static const char * const ip_route_commands[] =
814 { "add", "append", "change", "chg", "delete", "del", "get",
815 "list", "show", "prepend", "replace", "test", "flush", 0 };
816 int command_num = 7;
817 unsigned int flags = 0;
818 int cmd = RTM_NEWROUTE;
819
820 if (*argv) {
821 command_num = compare_string_array(ip_route_commands, *argv);
822 }
823 switch(command_num) {
824 case 0: /* add*/
825 flags = NLM_F_CREATE|NLM_F_EXCL;
826 break;
827 case 1: /* append */
828 flags = NLM_F_CREATE|NLM_F_APPEND;
829 break;
830 case 2: /* change */
831 case 3: /* chg */
832 flags = NLM_F_REPLACE;
833 break;
834 case 4: /* delete */
835 case 5: /* del */
836 cmd = RTM_DELROUTE;
837 break;
838 case 6: /* get */
839 return iproute_get(argc-1, argv+1);
840 case 7: /* list */
841 case 8: /* show */
842 return iproute_list_or_flush(argc-1, argv+1, 0);
843 case 9: /* prepend */
844 flags = NLM_F_CREATE;
845 case 10: /* replace */
846 flags = NLM_F_CREATE|NLM_F_REPLACE;
847 case 11: /* test */
848 flags = NLM_F_EXCL;
849 case 12: /* flush */
850 return iproute_list_or_flush(argc-1, argv+1, 1);
851 default:
852 bb_error_msg_and_die("Unknown command %s", *argv);
853 }
854
855 return iproute_modify(cmd, flags, argc-1, argv+1);
856}
Note: See TracBrowser for help on using the repository browser.