source: MondoRescue/branches/3.3/mindi-busybox/networking/libiproute/iprule.c@ 3902

Last change on this file since 3902 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 7.8 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
48 if (n->nlmsg_type != RTM_NEWRULE)
49 return 0;
50
51 len -= NLMSG_LENGTH(sizeof(*r));
52 if (len < 0)
53 return -1;
54
55 memset(tb, 0, sizeof(tb));
56 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
57
58 if (r->rtm_family == AF_INET)
59 host_len = 32;
60 else if (r->rtm_family == AF_INET6)
61 host_len = 128;
62/* else if (r->rtm_family == AF_DECnet)
63 host_len = 16;
64 else if (r->rtm_family == AF_IPX)
65 host_len = 80;
66*/
67 printf("%u:\t", tb[RTA_PRIORITY] ?
68 *(unsigned*)RTA_DATA(tb[RTA_PRIORITY])
69 : 0);
70 printf("from ");
71 if (tb[RTA_SRC]) {
72 if (r->rtm_src_len != host_len) {
73 printf("%s/%u",
74 rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_SRC])),
75 r->rtm_src_len
76 );
77 } else {
78 fputs(format_host(r->rtm_family,
79 RTA_PAYLOAD(tb[RTA_SRC]),
80 RTA_DATA(tb[RTA_SRC])),
81 stdout
82 );
83 }
84 } else if (r->rtm_src_len) {
85 printf("0/%d", r->rtm_src_len);
86 } else {
87 printf("all");
88 }
89 bb_putchar(' ');
90
91 if (tb[RTA_DST]) {
92 if (r->rtm_dst_len != host_len) {
93 printf("to %s/%u ", rt_addr_n2a(r->rtm_family,
94 RTA_DATA(tb[RTA_DST])),
95 r->rtm_dst_len
96 );
97 } else {
98 printf("to %s ", format_host(r->rtm_family,
99 RTA_PAYLOAD(tb[RTA_DST]),
100 RTA_DATA(tb[RTA_DST])));
101 }
102 } else if (r->rtm_dst_len) {
103 printf("to 0/%d ", r->rtm_dst_len);
104 }
105
106 if (r->rtm_tos) {
107 printf("tos %s ", rtnl_dsfield_n2a(r->rtm_tos));
108 }
109 if (tb[RTA_PROTOINFO]) {
110 printf("fwmark %#x ", *(uint32_t*)RTA_DATA(tb[RTA_PROTOINFO]));
111 }
112
113 if (tb[RTA_IIF]) {
114 printf("iif %s ", (char*)RTA_DATA(tb[RTA_IIF]));
115 }
116
117 if (r->rtm_table)
118 printf("lookup %s ", rtnl_rttable_n2a(r->rtm_table));
119
120 if (tb[RTA_FLOW]) {
121 uint32_t to = *(uint32_t*)RTA_DATA(tb[RTA_FLOW]);
122 uint32_t from = to>>16;
123 to &= 0xFFFF;
124 if (from) {
125 printf("realms %s/",
126 rtnl_rtrealm_n2a(from));
127 }
128 printf("%s ",
129 rtnl_rtrealm_n2a(to));
130 }
131
132 if (r->rtm_type == RTN_NAT) {
133 if (tb[RTA_GATEWAY]) {
134 printf("map-to %s ",
135 format_host(r->rtm_family,
136 RTA_PAYLOAD(tb[RTA_GATEWAY]),
137 RTA_DATA(tb[RTA_GATEWAY]))
138 );
139 } else
140 printf("masquerade");
141 } else if (r->rtm_type != RTN_UNICAST)
142 fputs(rtnl_rtntype_n2a(r->rtm_type), stdout);
143
144 bb_putchar('\n');
145 /*fflush_all();*/
146 return 0;
147}
148
149/* Return value becomes exitcode. It's okay to not return at all */
150static int iprule_list(char **argv)
151{
152 struct rtnl_handle rth;
153 int af = preferred_family;
154
155 if (af == AF_UNSPEC)
156 af = AF_INET;
157
158 if (*argv) {
159 //bb_error_msg("\"rule show\" needs no arguments");
160 bb_warn_ignoring_args(*argv);
161 return -1;
162 }
163
164 xrtnl_open(&rth);
165
166 xrtnl_wilddump_request(&rth, af, RTM_GETRULE);
167 xrtnl_dump_filter(&rth, print_rule, NULL);
168
169 return 0;
170}
171
172/* Return value becomes exitcode. It's okay to not return at all */
173static int iprule_modify(int cmd, char **argv)
174{
175 static const char keywords[] ALIGN1 =
176 "from\0""to\0""preference\0""order\0""priority\0"
177 "tos\0""fwmark\0""realms\0""table\0""lookup\0""dev\0"
178 "iif\0""nat\0""map-to\0""type\0""help\0";
179 enum {
180 ARG_from = 1, ARG_to, ARG_preference, ARG_order, ARG_priority,
181 ARG_tos, ARG_fwmark, ARG_realms, ARG_table, ARG_lookup, ARG_dev,
182 ARG_iif, ARG_nat, ARG_map_to, ARG_type, ARG_help
183 };
184 bool table_ok = 0;
185 struct rtnl_handle rth;
186 struct {
187 struct nlmsghdr n;
188 struct rtmsg r;
189 char buf[1024];
190 } req;
191 smalluint key;
192
193 memset(&req, 0, sizeof(req));
194
195 req.n.nlmsg_type = cmd;
196 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
197 req.n.nlmsg_flags = NLM_F_REQUEST;
198 req.r.rtm_family = preferred_family;
199 req.r.rtm_protocol = RTPROT_BOOT;
200 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
201 req.r.rtm_table = 0;
202 req.r.rtm_type = RTN_UNSPEC;
203
204 if (cmd == RTM_NEWRULE) {
205 req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
206 req.r.rtm_type = RTN_UNICAST;
207 }
208
209 while (*argv) {
210 key = index_in_substrings(keywords, *argv) + 1;
211 if (key == 0) /* no match found in keywords array, bail out. */
212 invarg_1_to_2(*argv, applet_name);
213 if (key == ARG_from) {
214 inet_prefix dst;
215 NEXT_ARG();
216 get_prefix(&dst, *argv, req.r.rtm_family);
217 req.r.rtm_src_len = dst.bitlen;
218 addattr_l(&req.n, sizeof(req), RTA_SRC, &dst.data, dst.bytelen);
219 } else if (key == ARG_to) {
220 inet_prefix dst;
221 NEXT_ARG();
222 get_prefix(&dst, *argv, req.r.rtm_family);
223 req.r.rtm_dst_len = dst.bitlen;
224 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
225 } else if (key == ARG_preference ||
226 key == ARG_order ||
227 key == ARG_priority
228 ) {
229 uint32_t pref;
230 NEXT_ARG();
231 pref = get_u32(*argv, "preference");
232 addattr32(&req.n, sizeof(req), RTA_PRIORITY, pref);
233 } else if (key == ARG_tos) {
234 uint32_t tos;
235 NEXT_ARG();
236 if (rtnl_dsfield_a2n(&tos, *argv))
237 invarg_1_to_2(*argv, "TOS");
238 req.r.rtm_tos = tos;
239 } else if (key == ARG_fwmark) {
240 uint32_t fwmark;
241 NEXT_ARG();
242 fwmark = get_u32(*argv, "fwmark");
243 addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark);
244 } else if (key == ARG_realms) {
245 uint32_t realm;
246 NEXT_ARG();
247 if (get_rt_realms(&realm, *argv))
248 invarg_1_to_2(*argv, "realms");
249 addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
250 } else if (key == ARG_table ||
251 key == ARG_lookup
252 ) {
253 uint32_t tid;
254 NEXT_ARG();
255 if (rtnl_rttable_a2n(&tid, *argv))
256 invarg_1_to_2(*argv, "table ID");
257 req.r.rtm_table = tid;
258 table_ok = 1;
259 } else if (key == ARG_dev ||
260 key == ARG_iif
261 ) {
262 NEXT_ARG();
263 addattr_l(&req.n, sizeof(req), RTA_IIF, *argv, strlen(*argv)+1);
264 } else if (key == ARG_nat ||
265 key == ARG_map_to
266 ) {
267 NEXT_ARG();
268 addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv));
269 req.r.rtm_type = RTN_NAT;
270 } else {
271 int type;
272
273 if (key == ARG_type) {
274 NEXT_ARG();
275 }
276 if (key == ARG_help)
277 bb_show_usage();
278 if (rtnl_rtntype_a2n(&type, *argv))
279 invarg_1_to_2(*argv, "type");
280 req.r.rtm_type = type;
281 }
282 argv++;
283 }
284
285 if (req.r.rtm_family == AF_UNSPEC)
286 req.r.rtm_family = AF_INET;
287
288 if (!table_ok && cmd == RTM_NEWRULE)
289 req.r.rtm_table = RT_TABLE_MAIN;
290
291 xrtnl_open(&rth);
292
293 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
294 return 2;
295
296 return 0;
297}
298
299/* Return value becomes exitcode. It's okay to not return at all */
300int FAST_FUNC do_iprule(char **argv)
301{
302 static const char ip_rule_commands[] ALIGN1 =
303 "add\0""delete\0""list\0""show\0";
304 if (*argv) {
305 int cmd = index_in_substrings(ip_rule_commands, *argv);
306 if (cmd < 0)
307 invarg_1_to_2(*argv, applet_name);
308 argv++;
309 if (cmd < 2)
310 return iprule_modify((cmd == 0) ? RTM_NEWRULE : RTM_DELRULE, argv);
311 }
312 return iprule_list(argv);
313}
Note: See TracBrowser for help on using the repository browser.