source: branches/3.2/mindi-busybox/networking/libiproute/iprule.c @ 3232

Last change on this file since 3232 was 3232, checked in by bruno, 5 years ago
  • Update mindi-busybox to 1.21.1
  • Property svn:eol-style set to native
File size: 8.0 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version
6 * 2 of the License, or (at your option) any later version.
7 *
8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
9 *
10 * Changes:
11 *
12 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
13 * initially integrated into busybox by Bernhard Reutner-Fischer
14 */
15
16#include <netinet/in.h>
17#include <netinet/ip.h>
18#include <arpa/inet.h>
19
20#include "ip_common.h"  /* #include "libbb.h" is inside */
21#include "rt_names.h"
22#include "utils.h"
23
24/*
25static void usage(void) __attribute__((noreturn));
26
27static void usage(void)
28{
29    fprintf(stderr, "Usage: ip rule [ list | add | del ] SELECTOR ACTION\n");
30    fprintf(stderr, "SELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK ]\n");
31    fprintf(stderr, "            [ dev STRING ] [ pref NUMBER ]\n");
32    fprintf(stderr, "ACTION := [ table TABLE_ID ] [ nat ADDRESS ]\n");
33    fprintf(stderr, "          [ prohibit | reject | unreachable ]\n");
34    fprintf(stderr, "          [ realms [SRCREALM/]DSTREALM ]\n");
35    fprintf(stderr, "TABLE_ID := [ local | main | default | NUMBER ]\n");
36    exit(-1);
37}
38*/
39
40static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM,
41                    struct nlmsghdr *n, void *arg UNUSED_PARAM)
42{
43    struct rtmsg *r = NLMSG_DATA(n);
44    int len = n->nlmsg_len;
45    int host_len = -1;
46    struct rtattr * tb[RTA_MAX+1];
47    char abuf[256];
48    SPRINT_BUF(b1);
49
50    if (n->nlmsg_type != RTM_NEWRULE)
51        return 0;
52
53    len -= NLMSG_LENGTH(sizeof(*r));
54    if (len < 0)
55        return -1;
56
57    memset(tb, 0, sizeof(tb));
58    parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
59
60    if (r->rtm_family == AF_INET)
61        host_len = 32;
62    else if (r->rtm_family == AF_INET6)
63        host_len = 128;
64/*  else if (r->rtm_family == AF_DECnet)
65        host_len = 16;
66    else if (r->rtm_family == AF_IPX)
67        host_len = 80;
68*/
69    printf("%u:\t", tb[RTA_PRIORITY] ?
70                    *(unsigned*)RTA_DATA(tb[RTA_PRIORITY])
71                    : 0);
72    printf("from ");
73    if (tb[RTA_SRC]) {
74        if (r->rtm_src_len != host_len) {
75            printf("%s/%u", rt_addr_n2a(r->rtm_family,
76                            RTA_DATA(tb[RTA_SRC]),
77                            abuf, sizeof(abuf)),
78                r->rtm_src_len
79            );
80        } else {
81            fputs(format_host(r->rtm_family,
82                        RTA_PAYLOAD(tb[RTA_SRC]),
83                        RTA_DATA(tb[RTA_SRC]),
84                        abuf, sizeof(abuf)),
85                stdout
86            );
87        }
88    } else if (r->rtm_src_len) {
89        printf("0/%d", r->rtm_src_len);
90    } else {
91        printf("all");
92    }
93    bb_putchar(' ');
94
95    if (tb[RTA_DST]) {
96        if (r->rtm_dst_len != host_len) {
97            printf("to %s/%u ", rt_addr_n2a(r->rtm_family,
98                             RTA_DATA(tb[RTA_DST]),
99                             abuf, sizeof(abuf)),
100                r->rtm_dst_len
101                );
102        } else {
103            printf("to %s ", format_host(r->rtm_family,
104                               RTA_PAYLOAD(tb[RTA_DST]),
105                               RTA_DATA(tb[RTA_DST]),
106                               abuf, sizeof(abuf)));
107        }
108    } else if (r->rtm_dst_len) {
109        printf("to 0/%d ", r->rtm_dst_len);
110    }
111
112    if (r->rtm_tos) {
113        printf("tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1));
114    }
115    if (tb[RTA_PROTOINFO]) {
116        printf("fwmark %#x ", *(uint32_t*)RTA_DATA(tb[RTA_PROTOINFO]));
117    }
118
119    if (tb[RTA_IIF]) {
120        printf("iif %s ", (char*)RTA_DATA(tb[RTA_IIF]));
121    }
122
123    if (r->rtm_table)
124        printf("lookup %s ", rtnl_rttable_n2a(r->rtm_table, b1));
125
126    if (tb[RTA_FLOW]) {
127        uint32_t to = *(uint32_t*)RTA_DATA(tb[RTA_FLOW]);
128        uint32_t from = to>>16;
129        to &= 0xFFFF;
130        if (from) {
131            printf("realms %s/",
132                rtnl_rtrealm_n2a(from, b1));
133        }
134        printf("%s ",
135            rtnl_rtrealm_n2a(to, b1));
136    }
137
138    if (r->rtm_type == RTN_NAT) {
139        if (tb[RTA_GATEWAY]) {
140            printf("map-to %s ",
141                format_host(r->rtm_family,
142                        RTA_PAYLOAD(tb[RTA_GATEWAY]),
143                        RTA_DATA(tb[RTA_GATEWAY]),
144                        abuf, sizeof(abuf)));
145        } else
146            printf("masquerade");
147    } else if (r->rtm_type != RTN_UNICAST)
148        fputs(rtnl_rtntype_n2a(r->rtm_type, b1), stdout);
149
150    bb_putchar('\n');
151    /*fflush_all();*/
152    return 0;
153}
154
155/* Return value becomes exitcode. It's okay to not return at all */
156static int iprule_list(char **argv)
157{
158    struct rtnl_handle rth;
159    int af = preferred_family;
160
161    if (af == AF_UNSPEC)
162        af = AF_INET;
163
164    if (*argv) {
165        //bb_error_msg("\"rule show\" needs no arguments");
166        bb_warn_ignoring_args(*argv);
167        return -1;
168    }
169
170    xrtnl_open(&rth);
171
172    xrtnl_wilddump_request(&rth, af, RTM_GETRULE);
173    xrtnl_dump_filter(&rth, print_rule, NULL);
174
175    return 0;
176}
177
178/* Return value becomes exitcode. It's okay to not return at all */
179static int iprule_modify(int cmd, char **argv)
180{
181    static const char keywords[] ALIGN1 =
182        "from\0""to\0""preference\0""order\0""priority\0"
183        "tos\0""fwmark\0""realms\0""table\0""lookup\0""dev\0"
184        "iif\0""nat\0""map-to\0""type\0""help\0";
185    enum {
186        ARG_from = 1, ARG_to, ARG_preference, ARG_order, ARG_priority,
187        ARG_tos, ARG_fwmark, ARG_realms, ARG_table, ARG_lookup, ARG_dev,
188        ARG_iif, ARG_nat, ARG_map_to, ARG_type, ARG_help
189    };
190    bool table_ok = 0;
191    struct rtnl_handle rth;
192    struct {
193        struct nlmsghdr n;
194        struct rtmsg    r;
195        char            buf[1024];
196    } req;
197    smalluint key;
198
199    memset(&req, 0, sizeof(req));
200
201    req.n.nlmsg_type = cmd;
202    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
203    req.n.nlmsg_flags = NLM_F_REQUEST;
204    req.r.rtm_family = preferred_family;
205    req.r.rtm_protocol = RTPROT_BOOT;
206    req.r.rtm_scope = RT_SCOPE_UNIVERSE;
207    req.r.rtm_table = 0;
208    req.r.rtm_type = RTN_UNSPEC;
209
210    if (cmd == RTM_NEWRULE) {
211        req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
212        req.r.rtm_type = RTN_UNICAST;
213    }
214
215    while (*argv) {
216        key = index_in_substrings(keywords, *argv) + 1;
217        if (key == 0) /* no match found in keywords array, bail out. */
218            bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
219        if (key == ARG_from) {
220            inet_prefix dst;
221            NEXT_ARG();
222            get_prefix(&dst, *argv, req.r.rtm_family);
223            req.r.rtm_src_len = dst.bitlen;
224            addattr_l(&req.n, sizeof(req), RTA_SRC, &dst.data, dst.bytelen);
225        } else if (key == ARG_to) {
226            inet_prefix dst;
227            NEXT_ARG();
228            get_prefix(&dst, *argv, req.r.rtm_family);
229            req.r.rtm_dst_len = dst.bitlen;
230            addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
231        } else if (key == ARG_preference ||
232               key == ARG_order ||
233               key == ARG_priority
234        ) {
235            uint32_t pref;
236            NEXT_ARG();
237            pref = get_u32(*argv, "preference");
238            addattr32(&req.n, sizeof(req), RTA_PRIORITY, pref);
239        } else if (key == ARG_tos) {
240            uint32_t tos;
241            NEXT_ARG();
242            if (rtnl_dsfield_a2n(&tos, *argv))
243                invarg(*argv, "TOS");
244            req.r.rtm_tos = tos;
245        } else if (key == ARG_fwmark) {
246            uint32_t fwmark;
247            NEXT_ARG();
248            fwmark = get_u32(*argv, "fwmark");
249            addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark);
250        } else if (key == ARG_realms) {
251            uint32_t realm;
252            NEXT_ARG();
253            if (get_rt_realms(&realm, *argv))
254                invarg(*argv, "realms");
255            addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
256        } else if (key == ARG_table ||
257               key == ARG_lookup
258        ) {
259            uint32_t tid;
260            NEXT_ARG();
261            if (rtnl_rttable_a2n(&tid, *argv))
262                invarg(*argv, "table ID");
263            req.r.rtm_table = tid;
264            table_ok = 1;
265        } else if (key == ARG_dev ||
266               key == ARG_iif
267        ) {
268            NEXT_ARG();
269            addattr_l(&req.n, sizeof(req), RTA_IIF, *argv, strlen(*argv)+1);
270        } else if (key == ARG_nat ||
271               key == ARG_map_to
272        ) {
273            NEXT_ARG();
274            addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv));
275            req.r.rtm_type = RTN_NAT;
276        } else {
277            int type;
278
279            if (key == ARG_type) {
280                NEXT_ARG();
281            }
282            if (key == ARG_help)
283                bb_show_usage();
284            if (rtnl_rtntype_a2n(&type, *argv))
285                invarg(*argv, "type");
286            req.r.rtm_type = type;
287        }
288        argv++;
289    }
290
291    if (req.r.rtm_family == AF_UNSPEC)
292        req.r.rtm_family = AF_INET;
293
294    if (!table_ok && cmd == RTM_NEWRULE)
295        req.r.rtm_table = RT_TABLE_MAIN;
296
297    xrtnl_open(&rth);
298
299    if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
300        return 2;
301
302    return 0;
303}
304
305/* Return value becomes exitcode. It's okay to not return at all */
306int FAST_FUNC do_iprule(char **argv)
307{
308    static const char ip_rule_commands[] ALIGN1 =
309        "add\0""delete\0""list\0""show\0";
310    if (*argv) {
311        smalluint cmd = index_in_substrings(ip_rule_commands, *argv);
312        if (cmd > 3)
313            bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name);
314        argv++;
315        if (cmd < 2)
316            return iprule_modify((cmd == 0) ? RTM_NEWRULE : RTM_DELRULE, argv);
317    }
318    return iprule_list(argv);
319}
Note: See TracBrowser for help on using the repository browser.