source: MondoRescue/branches/stable/mindi-busybox/networking/libiproute/iproute.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 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.