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

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 13 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

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