vconfig: make it NOEXEC
[oweals/busybox.git] / networking / libiproute / iproute.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4  *
5  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
6  *
7  * Changes:
8  *
9  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
10  * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
11  */
12
13 #include "ip_common.h"  /* #include "libbb.h" is inside */
14 #include "common_bufsiz.h"
15 #include "rt_names.h"
16 #include "utils.h"
17
18 #ifndef RTAX_RTTVAR
19 #define RTAX_RTTVAR RTAX_HOPS
20 #endif
21
22
23 struct filter_t {
24         int tb;
25         smallint flushed;
26         char *flushb;
27         int flushp;
28         int flushe;
29         struct rtnl_handle *rth;
30         //int protocol, protocolmask; - write-only fields?!
31         int scope, scopemask;
32         //int type; - read-only
33         //int typemask; - unused
34         //int tos, tosmask; - unused
35         int iif;
36         int oif;
37         //int realm, realmmask; - unused
38         //inet_prefix rprefsrc; - read-only
39         inet_prefix rvia;
40         inet_prefix rdst;
41         inet_prefix mdst;
42         inet_prefix rsrc;
43         inet_prefix msrc;
44 } FIX_ALIASING;
45 typedef struct filter_t filter_t;
46
47 #define G_filter (*(filter_t*)bb_common_bufsiz1)
48 #define INIT_G() do { setup_common_bufsiz(); } while (0)
49
50 static int flush_update(void)
51 {
52         if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
53                 bb_perror_msg("can't send flush request");
54                 return -1;
55         }
56         G_filter.flushp = 0;
57         return 0;
58 }
59
60 static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
61                 struct nlmsghdr *n, void *arg UNUSED_PARAM)
62 {
63         struct rtmsg *r = NLMSG_DATA(n);
64         int len = n->nlmsg_len;
65         struct rtattr *tb[RTA_MAX+1];
66         inet_prefix dst;
67         inet_prefix src;
68         int host_len = -1;
69         uint32_t tid;
70
71         if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
72                 fprintf(stderr, "Not a route: %08x %08x %08x\n",
73                         n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
74                 return 0;
75         }
76         if (G_filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
77                 return 0;
78         len -= NLMSG_LENGTH(sizeof(*r));
79         if (len < 0)
80                 bb_error_msg_and_die("wrong nlmsg len %d", len);
81
82         memset(tb, 0, sizeof(tb));
83         parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
84
85         if (tb[RTA_TABLE])
86                 tid = *(uint32_t *)RTA_DATA(tb[RTA_TABLE]);
87         else
88                 tid = r->rtm_table;
89
90         if (r->rtm_family == AF_INET6)
91                 host_len = 128;
92         else if (r->rtm_family == AF_INET)
93                 host_len = 32;
94
95         if (r->rtm_family == AF_INET6) {
96                 if (G_filter.tb) {
97                         if (G_filter.tb < 0) {
98                                 if (!(r->rtm_flags & RTM_F_CLONED)) {
99                                         return 0;
100                                 }
101                         } else {
102                                 if (r->rtm_flags & RTM_F_CLONED) {
103                                         return 0;
104                                 }
105                                 if (G_filter.tb == RT_TABLE_LOCAL) {
106                                         if (r->rtm_type != RTN_LOCAL) {
107                                                 return 0;
108                                         }
109                                 } else if (G_filter.tb == RT_TABLE_MAIN) {
110                                         if (r->rtm_type == RTN_LOCAL) {
111                                                 return 0;
112                                         }
113                                 } else {
114                                         return 0;
115                                 }
116                         }
117                 }
118         } else {
119                 if (G_filter.tb > 0 && G_filter.tb != tid) {
120                         return 0;
121                 }
122         }
123         if ((G_filter.scope ^ r->rtm_scope) & G_filter.scopemask)
124                 return 0;
125         if (G_filter.rdst.family
126          && (r->rtm_family != G_filter.rdst.family || G_filter.rdst.bitlen > r->rtm_dst_len)
127         ) {
128                 return 0;
129         }
130         if (G_filter.mdst.family
131          && (r->rtm_family != G_filter.mdst.family
132             || (G_filter.mdst.bitlen >= 0 && G_filter.mdst.bitlen < r->rtm_dst_len)
133             )
134         ) {
135                 return 0;
136         }
137         if (G_filter.rsrc.family
138          && (r->rtm_family != G_filter.rsrc.family || G_filter.rsrc.bitlen > r->rtm_src_len)
139         ) {
140                 return 0;
141         }
142         if (G_filter.msrc.family
143          && (r->rtm_family != G_filter.msrc.family
144             || (G_filter.msrc.bitlen >= 0 && G_filter.msrc.bitlen < r->rtm_src_len)
145             )
146         ) {
147                 return 0;
148         }
149
150         memset(&src, 0, sizeof(src));
151         memset(&dst, 0, sizeof(dst));
152
153         if (tb[RTA_SRC]) {
154                 src.bitlen = r->rtm_src_len;
155                 src.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
156                 memcpy(src.data, RTA_DATA(tb[RTA_SRC]), src.bytelen);
157         }
158         if (tb[RTA_DST]) {
159                 dst.bitlen = r->rtm_dst_len;
160                 dst.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
161                 memcpy(dst.data, RTA_DATA(tb[RTA_DST]), dst.bytelen);
162         }
163
164         if (G_filter.rdst.family
165          && inet_addr_match(&dst, &G_filter.rdst, G_filter.rdst.bitlen)
166         ) {
167                 return 0;
168         }
169         if (G_filter.mdst.family
170          && G_filter.mdst.bitlen >= 0
171          && inet_addr_match(&dst, &G_filter.mdst, r->rtm_dst_len)
172         ) {
173                 return 0;
174         }
175         if (G_filter.rsrc.family
176          && inet_addr_match(&src, &G_filter.rsrc, G_filter.rsrc.bitlen)
177         ) {
178                 return 0;
179         }
180         if (G_filter.msrc.family && G_filter.msrc.bitlen >= 0
181          && inet_addr_match(&src, &G_filter.msrc, r->rtm_src_len)
182         ) {
183                 return 0;
184         }
185         if (G_filter.oif != 0) {
186                 if (!tb[RTA_OIF])
187                         return 0;
188                 if (G_filter.oif != *(int*)RTA_DATA(tb[RTA_OIF]))
189                         return 0;
190         }
191
192         if (G_filter.flushb) {
193                 struct nlmsghdr *fn;
194
195                 /* We are creating route flush commands */
196
197                 if (r->rtm_family == AF_INET6
198                  && r->rtm_dst_len == 0
199                  && r->rtm_type == RTN_UNREACHABLE
200                  && tb[RTA_PRIORITY]
201                  && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1
202                 ) {
203                         return 0;
204                 }
205
206                 if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) {
207                         if (flush_update())
208                                 xfunc_die();
209                 }
210                 fn = (void*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp));
211                 memcpy(fn, n, n->nlmsg_len);
212                 fn->nlmsg_type = RTM_DELROUTE;
213                 fn->nlmsg_flags = NLM_F_REQUEST;
214                 fn->nlmsg_seq = ++G_filter.rth->seq;
215                 G_filter.flushp = (((char*)fn) + n->nlmsg_len) - G_filter.flushb;
216                 G_filter.flushed = 1;
217                 return 0;
218         }
219
220         /* We are printing routes */
221
222         if (n->nlmsg_type == RTM_DELROUTE) {
223                 printf("Deleted ");
224         }
225         if (r->rtm_type != RTN_UNICAST /* && !G_filter.type - always 0 */) {
226                 printf("%s ", rtnl_rtntype_n2a(r->rtm_type));
227         }
228
229         if (tb[RTA_DST]) {
230                 if (r->rtm_dst_len != host_len) {
231                         printf("%s/%u ",
232                                 rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_DST])),
233                                 r->rtm_dst_len
234                         );
235                 } else {
236                         printf("%s ", format_host(r->rtm_family,
237                                                 RTA_PAYLOAD(tb[RTA_DST]),
238                                                 RTA_DATA(tb[RTA_DST]))
239                         );
240                 }
241         } else if (r->rtm_dst_len) {
242                 printf("0/%d ", r->rtm_dst_len);
243         } else {
244                 printf("default ");
245         }
246         if (tb[RTA_SRC]) {
247                 if (r->rtm_src_len != host_len) {
248                         printf("from %s/%u ",
249                                 rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_SRC])),
250                                 r->rtm_src_len
251                         );
252                 } else {
253                         printf("from %s ", format_host(r->rtm_family,
254                                                 RTA_PAYLOAD(tb[RTA_SRC]),
255                                                 RTA_DATA(tb[RTA_SRC]))
256                         );
257                 }
258         } else if (r->rtm_src_len) {
259                 printf("from 0/%u ", r->rtm_src_len);
260         }
261         if (tb[RTA_GATEWAY] && G_filter.rvia.bitlen != host_len) {
262                 printf("via %s ", format_host(r->rtm_family,
263                                         RTA_PAYLOAD(tb[RTA_GATEWAY]),
264                                         RTA_DATA(tb[RTA_GATEWAY]))
265                 );
266         }
267         if (tb[RTA_OIF]) {
268                 printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
269         }
270 #if ENABLE_FEATURE_IP_RULE
271         if (tid && tid != RT_TABLE_MAIN && !G_filter.tb)
272                 printf("table %s ", rtnl_rttable_n2a(tid));
273 #endif
274
275         /* Todo: parse & show "proto kernel" here */
276         if (!(r->rtm_flags & RTM_F_CLONED)) {
277                 if ((r->rtm_scope != RT_SCOPE_UNIVERSE) && G_filter.scopemask != -1)
278                         printf("scope %s ", rtnl_rtscope_n2a(r->rtm_scope));
279         }
280
281         if (tb[RTA_PREFSRC] && /*G_filter.rprefsrc.bitlen - always 0*/ 0 != host_len) {
282                 /* Do not use format_host(). It is our local addr
283                    and symbolic name will not be useful.
284                  */
285                 printf(" src %s ", rt_addr_n2a(r->rtm_family,
286                                         RTA_DATA(tb[RTA_PREFSRC])));
287         }
288         if (tb[RTA_PRIORITY]) {
289                 printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
290         }
291         if (r->rtm_flags & RTNH_F_DEAD) {
292                 printf("dead ");
293         }
294         if (r->rtm_flags & RTNH_F_ONLINK) {
295                 printf("onlink ");
296         }
297         if (r->rtm_flags & RTNH_F_PERVASIVE) {
298                 printf("pervasive ");
299         }
300         if (r->rtm_flags & RTM_F_NOTIFY) {
301                 printf("notify ");
302         }
303
304         if (r->rtm_family == AF_INET6) {
305                 struct rta_cacheinfo *ci = NULL;
306                 if (tb[RTA_CACHEINFO]) {
307                         ci = RTA_DATA(tb[RTA_CACHEINFO]);
308                 }
309                 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
310                         if (r->rtm_flags & RTM_F_CLONED) {
311                                 printf("%c    cache ", _SL_);
312                         }
313                         if (ci->rta_expires) {
314                                 printf(" expires %dsec", ci->rta_expires / get_hz());
315                         }
316                         if (ci->rta_error != 0) {
317                                 printf(" error %d", ci->rta_error);
318                         }
319                 } else if (ci) {
320                         if (ci->rta_error != 0)
321                                 printf(" error %d", ci->rta_error);
322                 }
323         }
324         if (tb[RTA_IIF] && G_filter.iif == 0) {
325                 printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
326         }
327         bb_putchar('\n');
328         return 0;
329 }
330
331 static int str_is_lock(const char *str)
332 {
333         return strcmp(str, "lock") == 0;
334 }
335
336 /* Return value becomes exitcode. It's okay to not return at all */
337 static int iproute_modify(int cmd, unsigned flags, char **argv)
338 {
339         /* If you add stuff here, update iproute_full_usage */
340         static const char keywords[] ALIGN1 =
341                 "src\0""via\0"
342                 "mtu\0""advmss\0"
343                 "scope\0""protocol\0"IF_FEATURE_IP_RULE("table\0")
344                 "dev\0""oif\0""to\0""metric\0""onlink\0";
345 #define keyword_via    (keywords       + sizeof("src"))
346 #define keyword_mtu    (keyword_via    + sizeof("via"))
347 #define keyword_advmss (keyword_mtu    + sizeof("mtu"))
348 #define keyword_scope  (keyword_advmss + sizeof("advmss"))
349 #define keyword_proto  (keyword_scope  + sizeof("scope"))
350 #define keyword_table  (keyword_proto  + sizeof("protocol"))
351         enum {
352                 ARG_src,
353                 ARG_via,
354                 ARG_mtu,
355                 ARG_advmss,
356                 ARG_scope,
357                 ARG_protocol,
358 IF_FEATURE_IP_RULE(ARG_table,)
359                 ARG_dev,
360                 ARG_oif,
361                 ARG_to,
362                 ARG_metric,
363                 ARG_onlink,
364         };
365         enum {
366                 gw_ok = 1 << 0,
367                 dst_ok = 1 << 1,
368                 proto_ok = 1 << 2,
369                 type_ok = 1 << 3
370         };
371         struct rtnl_handle rth;
372         struct {
373                 struct nlmsghdr n;
374                 struct rtmsg    r;
375                 char            buf[1024];
376         } req;
377         char mxbuf[256];
378         struct rtattr * mxrta = (void*)mxbuf;
379         unsigned mxlock = 0;
380         char *d = NULL;
381         smalluint ok = 0;
382         smalluint scope_ok = 0;
383         int arg;
384
385         memset(&req, 0, sizeof(req));
386
387         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
388         req.n.nlmsg_flags = NLM_F_REQUEST | flags;
389         req.n.nlmsg_type = cmd;
390         req.r.rtm_family = preferred_family;
391         if (RT_TABLE_MAIN != 0) /* if it is zero, memset already did it */
392                 req.r.rtm_table = RT_TABLE_MAIN;
393         if (RT_SCOPE_NOWHERE != 0)
394                 req.r.rtm_scope = RT_SCOPE_NOWHERE;
395
396         if (cmd != RTM_DELROUTE) {
397                 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
398                 if (RTPROT_BOOT != 0)
399                         req.r.rtm_protocol = RTPROT_BOOT;
400                 if (RTN_UNICAST != 0)
401                         req.r.rtm_type = RTN_UNICAST;
402         }
403
404         mxrta->rta_type = RTA_METRICS;
405         mxrta->rta_len = RTA_LENGTH(0);
406
407         while (*argv) {
408                 arg = index_in_substrings(keywords, *argv);
409                 if (arg == ARG_src) {
410                         inet_prefix addr;
411                         NEXT_ARG();
412                         get_addr(&addr, *argv, req.r.rtm_family);
413                         if (req.r.rtm_family == AF_UNSPEC)
414                                 req.r.rtm_family = addr.family;
415                         addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
416                 } else if (arg == ARG_via) {
417                         inet_prefix addr;
418                         ok |= gw_ok;
419                         NEXT_ARG();
420                         get_addr(&addr, *argv, req.r.rtm_family);
421                         if (req.r.rtm_family == AF_UNSPEC) {
422                                 req.r.rtm_family = addr.family;
423                         }
424                         addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
425                 } else if (arg == ARG_mtu) {
426                         unsigned mtu;
427                         NEXT_ARG();
428                         if (str_is_lock(*argv)) {
429                                 mxlock |= (1 << RTAX_MTU);
430                                 NEXT_ARG();
431                         }
432                         mtu = get_unsigned(*argv, keyword_mtu);
433                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
434                 } else if (arg == ARG_advmss) {
435                         unsigned mss;
436                         NEXT_ARG();
437                         if (str_is_lock(*argv)) {
438                                 mxlock |= (1 << RTAX_ADVMSS);
439                                 NEXT_ARG();
440                         }
441                         mss = get_unsigned(*argv, keyword_advmss);
442                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_ADVMSS, mss);
443                 } else if (arg == ARG_scope) {
444                         uint32_t scope;
445                         NEXT_ARG();
446                         if (rtnl_rtscope_a2n(&scope, *argv))
447                                 invarg_1_to_2(*argv, keyword_scope);
448                         req.r.rtm_scope = scope;
449                         scope_ok = 1;
450                 } else if (arg == ARG_protocol) {
451                         uint32_t prot;
452                         NEXT_ARG();
453                         if (rtnl_rtprot_a2n(&prot, *argv))
454                                 invarg_1_to_2(*argv, keyword_proto);
455                         req.r.rtm_protocol = prot;
456                         ok |= proto_ok;
457 #if ENABLE_FEATURE_IP_RULE
458                 } else if (arg == ARG_table) {
459                         uint32_t tid;
460                         NEXT_ARG();
461                         if (rtnl_rttable_a2n(&tid, *argv))
462                                 invarg_1_to_2(*argv, keyword_table);
463                         if (tid < 256)
464                                 req.r.rtm_table = tid;
465                         else {
466                                 req.r.rtm_table = RT_TABLE_UNSPEC;
467                                 addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
468                         }
469 #endif
470                 } else if (arg == ARG_dev || arg == ARG_oif) {
471                         NEXT_ARG();
472                         d = *argv;
473                 } else if (arg == ARG_metric) {
474 //TODO: "metric", "priority" and "preference" are synonyms
475                         uint32_t metric;
476                         NEXT_ARG();
477                         metric = get_u32(*argv, "metric");
478                         addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
479                 } else if (arg == ARG_onlink) {
480                         req.r.rtm_flags |= RTNH_F_ONLINK;
481                 } else {
482                         int type;
483                         inet_prefix dst;
484
485                         if (arg == ARG_to) {
486                                 NEXT_ARG();
487                         }
488                         if ((**argv < '0' || **argv > '9')
489                          && rtnl_rtntype_a2n(&type, *argv) == 0
490                         ) {
491                                 NEXT_ARG();
492                                 req.r.rtm_type = type;
493                                 ok |= type_ok;
494                         }
495
496                         if (ok & dst_ok) {
497                                 duparg2("to", *argv);
498                         }
499                         get_prefix(&dst, *argv, req.r.rtm_family);
500                         if (req.r.rtm_family == AF_UNSPEC) {
501                                 req.r.rtm_family = dst.family;
502                         }
503                         req.r.rtm_dst_len = dst.bitlen;
504                         ok |= dst_ok;
505                         if (dst.bytelen) {
506                                 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
507                         }
508                 }
509 /* Other keywords recognized by iproute2-3.19.0: */
510 #if 0
511                 } else if (strcmp(*argv, "from") == 0) {
512                         inet_prefix addr;
513                         NEXT_ARG();
514                         get_prefix(&addr, *argv, req.r.rtm_family);
515                         if (req.r.rtm_family == AF_UNSPEC)
516                                 req.r.rtm_family = addr.family;
517                         if (addr.bytelen)
518                                 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
519                         req.r.rtm_src_len = addr.bitlen;
520                 } else if (strcmp(*argv, "tos") == 0 ||
521                            matches(*argv, "dsfield") == 0) {
522                         __u32 tos;
523                         NEXT_ARG();
524                         if (rtnl_dsfield_a2n(&tos, *argv))
525                                 invarg("\"tos\" value is invalid\n", *argv);
526                         req.r.rtm_tos = tos;
527                 } else if (strcmp(*argv, "hoplimit") == 0) {
528                         unsigned hoplimit;
529                         NEXT_ARG();
530                         if (strcmp(*argv, "lock") == 0) {
531                                 mxlock |= (1<<RTAX_HOPLIMIT);
532                                 NEXT_ARG();
533                         }
534                         if (get_unsigned(&hoplimit, *argv, 0))
535                                 invarg("\"hoplimit\" value is invalid\n", *argv);
536                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_HOPLIMIT, hoplimit);
537                 } else if (matches(*argv, "reordering") == 0) {
538                         unsigned reord;
539                         NEXT_ARG();
540                         if (strcmp(*argv, "lock") == 0) {
541                                 mxlock |= (1<<RTAX_REORDERING);
542                                 NEXT_ARG();
543                         }
544                         if (get_unsigned(&reord, *argv, 0))
545                                 invarg("\"reordering\" value is invalid\n", *argv);
546                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_REORDERING, reord);
547                 } else if (strcmp(*argv, "rtt") == 0) {
548                         unsigned rtt;
549                         NEXT_ARG();
550                         if (strcmp(*argv, "lock") == 0) {
551                                 mxlock |= (1<<RTAX_RTT);
552                                 NEXT_ARG();
553                         }
554                         if (get_time_rtt(&rtt, *argv, &raw))
555                                 invarg("\"rtt\" value is invalid\n", *argv);
556                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT,
557                                 (raw) ? rtt : rtt * 8);
558                 } else if (strcmp(*argv, "rto_min") == 0) {
559                         unsigned rto_min;
560                         NEXT_ARG();
561                         mxlock |= (1<<RTAX_RTO_MIN);
562                         if (get_time_rtt(&rto_min, *argv, &raw))
563                                 invarg("\"rto_min\" value is invalid\n",
564                                        *argv);
565                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTO_MIN,
566                                       rto_min);
567                 } else if (matches(*argv, "window") == 0) {
568                         unsigned win;
569                         NEXT_ARG();
570                         if (strcmp(*argv, "lock") == 0) {
571                                 mxlock |= (1<<RTAX_WINDOW);
572                                 NEXT_ARG();
573                         }
574                         if (get_unsigned(&win, *argv, 0))
575                                 invarg("\"window\" value is invalid\n", *argv);
576                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_WINDOW, win);
577                 } else if (matches(*argv, "cwnd") == 0) {
578                         unsigned win;
579                         NEXT_ARG();
580                         if (strcmp(*argv, "lock") == 0) {
581                                 mxlock |= (1<<RTAX_CWND);
582                                 NEXT_ARG();
583                         }
584                         if (get_unsigned(&win, *argv, 0))
585                                 invarg("\"cwnd\" value is invalid\n", *argv);
586                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win);
587                 } else if (matches(*argv, "initcwnd") == 0) {
588                         unsigned win;
589                         NEXT_ARG();
590                         if (strcmp(*argv, "lock") == 0) {
591                                 mxlock |= (1<<RTAX_INITCWND);
592                                 NEXT_ARG();
593                         }
594                         if (get_unsigned(&win, *argv, 0))
595                                 invarg("\"initcwnd\" value is invalid\n", *argv);
596                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITCWND, win);
597                 } else if (matches(*argv, "initrwnd") == 0) {
598                         unsigned win;
599                         NEXT_ARG();
600                         if (strcmp(*argv, "lock") == 0) {
601                                 mxlock |= (1<<RTAX_INITRWND);
602                                 NEXT_ARG();
603                         }
604                         if (get_unsigned(&win, *argv, 0))
605                                 invarg("\"initrwnd\" value is invalid\n", *argv);
606                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITRWND, win);
607                 } else if (matches(*argv, "features") == 0) {
608                         unsigned int features = 0;
609
610                         while (argc > 0) {
611                                 NEXT_ARG();
612
613                                 if (strcmp(*argv, "ecn") == 0)
614                                         features |= RTAX_FEATURE_ECN;
615                                 else
616                                         invarg("\"features\" value not valid\n", *argv);
617                                 break;
618                         }
619
620                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_FEATURES, features);
621                 } else if (matches(*argv, "quickack") == 0) {
622                         unsigned quickack;
623                         NEXT_ARG();
624                         if (get_unsigned(&quickack, *argv, 0))
625                                 invarg("\"quickack\" value is invalid\n", *argv);
626                         if (quickack != 1 && quickack != 0)
627                                 invarg("\"quickack\" value should be 0 or 1\n", *argv);
628                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_QUICKACK, quickack);
629                 } else if (matches(*argv, "rttvar") == 0) {
630                         unsigned win;
631                         NEXT_ARG();
632                         if (strcmp(*argv, "lock") == 0) {
633                                 mxlock |= (1<<RTAX_RTTVAR);
634                                 NEXT_ARG();
635                         }
636                         if (get_time_rtt(&win, *argv, &raw))
637                                 invarg("\"rttvar\" value is invalid\n", *argv);
638                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR,
639                                 (raw) ? win : win * 4);
640                 } else if (matches(*argv, "ssthresh") == 0) {
641                         unsigned win;
642                         NEXT_ARG();
643                         if (strcmp(*argv, "lock") == 0) {
644                                 mxlock |= (1<<RTAX_SSTHRESH);
645                                 NEXT_ARG();
646                         }
647                         if (get_unsigned(&win, *argv, 0))
648                                 invarg("\"ssthresh\" value is invalid\n", *argv);
649                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_SSTHRESH, win);
650                 } else if (matches(*argv, "realms") == 0) {
651                         __u32 realm;
652                         NEXT_ARG();
653                         if (get_rt_realms(&realm, *argv))
654                                 invarg("\"realm\" value is invalid\n", *argv);
655                         addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
656                 } else if (strcmp(*argv, "nexthop") == 0) {
657                         nhs_ok = 1;
658                         break;
659                 }
660 #endif
661                 argv++;
662         }
663
664         xrtnl_open(&rth);
665
666         if (d)  {
667                 int idx;
668
669                 ll_init_map(&rth);
670
671                 if (d) {
672                         idx = xll_name_to_index(d);
673                         addattr32(&req.n, sizeof(req), RTA_OIF, idx);
674                 }
675         }
676
677         if (mxrta->rta_len > RTA_LENGTH(0)) {
678                 if (mxlock) {
679                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
680                 }
681                 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
682         }
683
684         if (!scope_ok) {
685                 if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT)
686                         req.r.rtm_scope = RT_SCOPE_HOST;
687                 else
688                 if (req.r.rtm_type == RTN_BROADCAST
689                  || req.r.rtm_type == RTN_MULTICAST
690                  || req.r.rtm_type == RTN_ANYCAST
691                 ) {
692                         req.r.rtm_scope = RT_SCOPE_LINK;
693                 }
694                 else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) {
695                         if (cmd == RTM_DELROUTE)
696                                 req.r.rtm_scope = RT_SCOPE_NOWHERE;
697                         else if (!(ok & gw_ok))
698                                 req.r.rtm_scope = RT_SCOPE_LINK;
699                 }
700         }
701
702         if (req.r.rtm_family == AF_UNSPEC) {
703                 req.r.rtm_family = AF_INET;
704         }
705
706         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
707                 return 2;
708         }
709
710         return 0;
711 }
712
713 static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
714 {
715         struct {
716                 struct nlmsghdr nlh;
717                 struct rtmsg rtm;
718         } req;
719         struct sockaddr_nl nladdr;
720
721         memset(&nladdr, 0, sizeof(nladdr));
722         memset(&req, 0, sizeof(req));
723         nladdr.nl_family = AF_NETLINK;
724
725         req.nlh.nlmsg_len = sizeof(req);
726         if (RTM_GETROUTE)
727                 req.nlh.nlmsg_type = RTM_GETROUTE;
728         if (NLM_F_ROOT | NLM_F_REQUEST)
729                 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
730         /*req.nlh.nlmsg_pid = 0; - memset did it already */
731         req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
732         req.rtm.rtm_family = family;
733         if (RTM_F_CLONED)
734                 req.rtm.rtm_flags = RTM_F_CLONED;
735
736         return xsendto(rth->fd, (void*)&req, sizeof(req), (struct sockaddr*)&nladdr, sizeof(nladdr));
737 }
738
739 static void iproute_flush_cache(void)
740 {
741         static const char fn[] ALIGN1 = "/proc/sys/net/ipv4/route/flush";
742         int flush_fd = open_or_warn(fn, O_WRONLY);
743
744         if (flush_fd < 0) {
745                 return;
746         }
747
748         if (write(flush_fd, "-1", 2) < 2) {
749                 bb_perror_msg("can't flush routing cache");
750                 return;
751         }
752         close(flush_fd);
753 }
754
755 static void iproute_reset_filter(void)
756 {
757         memset(&G_filter, 0, sizeof(G_filter));
758         G_filter.mdst.bitlen = -1;
759         G_filter.msrc.bitlen = -1;
760 }
761
762 /* Return value becomes exitcode. It's okay to not return at all */
763 static int iproute_list_or_flush(char **argv, int flush)
764 {
765         int do_ipv6 = preferred_family;
766         struct rtnl_handle rth;
767         char *id = NULL;
768         char *od = NULL;
769         static const char keywords[] ALIGN1 =
770                 /* If you add stuff here, update iproute_full_usage */
771                 /* "ip route list/flush" parameters: */
772                 "protocol\0" "dev\0"   "oif\0"   "iif\0"
773                 "via\0"      "table\0" "cache\0"
774                 "from\0"     "to\0"    "scope\0"
775                 /* and possible further keywords */
776                 "all\0"
777                 "root\0"
778                 "match\0"
779                 "exact\0"
780                 "main\0"
781                 ;
782         enum {
783                 KW_proto, KW_dev,   KW_oif,  KW_iif,
784                 KW_via,   KW_table, KW_cache,
785                 KW_from,  KW_to,    KW_scope,
786                 /* */
787                 KW_all,
788                 KW_root,
789                 KW_match,
790                 KW_exact,
791                 KW_main,
792         };
793         int arg, parm;
794
795         iproute_reset_filter();
796         G_filter.tb = RT_TABLE_MAIN;
797
798         if (flush && !*argv)
799                 bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\"");
800
801         while (*argv) {
802                 arg = index_in_substrings(keywords, *argv);
803                 if (arg == KW_proto) {
804                         uint32_t prot = 0;
805                         NEXT_ARG();
806                         //G_filter.protocolmask = -1;
807                         if (rtnl_rtprot_a2n(&prot, *argv)) {
808                                 if (index_in_strings(keywords, *argv) != KW_all)
809                                         invarg_1_to_2(*argv, "protocol");
810                                 prot = 0;
811                                 //G_filter.protocolmask = 0;
812                         }
813                         //G_filter.protocol = prot;
814                 } else if (arg == KW_dev || arg == KW_oif) {
815                         NEXT_ARG();
816                         od = *argv;
817                 } else if (arg == KW_iif) {
818                         NEXT_ARG();
819                         id = *argv;
820                 } else if (arg == KW_via) {
821                         NEXT_ARG();
822                         get_prefix(&G_filter.rvia, *argv, do_ipv6);
823                 } else if (arg == KW_table) { /* table all/cache/main */
824                         NEXT_ARG();
825                         parm = index_in_substrings(keywords, *argv);
826                         if (parm == KW_cache)
827                                 G_filter.tb = -1;
828                         else if (parm == KW_all)
829                                 G_filter.tb = 0;
830                         else if (parm != KW_main) {
831 #if ENABLE_FEATURE_IP_RULE
832                                 uint32_t tid;
833                                 if (rtnl_rttable_a2n(&tid, *argv))
834                                         invarg_1_to_2(*argv, "table");
835                                 G_filter.tb = tid;
836 #else
837                                 invarg_1_to_2(*argv, "table");
838 #endif
839                         }
840                 } else if (arg == KW_cache) {
841                         /* The command 'ip route flush cache' is used by OpenSWAN.
842                          * Assuming it's a synonym for 'ip route flush table cache' */
843                         G_filter.tb = -1;
844                 } else if (arg == KW_scope) {
845                         uint32_t scope;
846                         NEXT_ARG();
847                         G_filter.scopemask = -1;
848                         if (rtnl_rtscope_a2n(&scope, *argv)) {
849                                 if (strcmp(*argv, "all") != 0)
850                                         invarg_1_to_2(*argv, "scope");
851                                 scope = RT_SCOPE_NOWHERE;
852                                 G_filter.scopemask = 0;
853                         }
854                         G_filter.scope = scope;
855                 } else if (arg == KW_from) {
856                         NEXT_ARG();
857                         parm = index_in_substrings(keywords, *argv);
858                         if (parm == KW_root) {
859                                 NEXT_ARG();
860                                 get_prefix(&G_filter.rsrc, *argv, do_ipv6);
861                         } else if (parm == KW_match) {
862                                 NEXT_ARG();
863                                 get_prefix(&G_filter.msrc, *argv, do_ipv6);
864                         } else {
865                                 if (parm == KW_exact)
866                                         NEXT_ARG();
867                                 get_prefix(&G_filter.msrc, *argv, do_ipv6);
868                                 G_filter.rsrc = G_filter.msrc;
869                         }
870                 } else { /* "to" is the default parameter */
871                         if (arg == KW_to) {
872                                 NEXT_ARG();
873                                 arg = index_in_substrings(keywords, *argv);
874                         }
875                         /* parm = arg; - would be more plausible, but we reuse 'arg' here */
876                         if (arg == KW_root) {
877                                 NEXT_ARG();
878                                 get_prefix(&G_filter.rdst, *argv, do_ipv6);
879                         } else if (arg == KW_match) {
880                                 NEXT_ARG();
881                                 get_prefix(&G_filter.mdst, *argv, do_ipv6);
882                         } else { /* "to exact" is the default */
883                                 if (arg == KW_exact)
884                                         NEXT_ARG();
885                                 get_prefix(&G_filter.mdst, *argv, do_ipv6);
886                                 G_filter.rdst = G_filter.mdst;
887                         }
888                 }
889                 argv++;
890         }
891
892         if (do_ipv6 == AF_UNSPEC && G_filter.tb) {
893                 do_ipv6 = AF_INET;
894         }
895
896         xrtnl_open(&rth);
897         ll_init_map(&rth);
898
899         if (id || od)  {
900                 int idx;
901
902                 if (id) {
903                         idx = xll_name_to_index(id);
904                         G_filter.iif = idx;
905                 }
906                 if (od) {
907                         idx = xll_name_to_index(od);
908                         G_filter.oif = idx;
909                 }
910         }
911
912         if (flush) {
913                 char flushb[4096-512];
914
915                 if (G_filter.tb == -1) { /* "flush table cache" */
916                         if (do_ipv6 != AF_INET6)
917                                 iproute_flush_cache();
918                         if (do_ipv6 == AF_INET)
919                                 return 0;
920                 }
921
922                 G_filter.flushb = flushb;
923                 G_filter.flushp = 0;
924                 G_filter.flushe = sizeof(flushb);
925                 G_filter.rth = &rth;
926
927                 for (;;) {
928                         xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
929                         G_filter.flushed = 0;
930                         xrtnl_dump_filter(&rth, print_route, NULL);
931                         if (G_filter.flushed == 0)
932                                 return 0;
933                         if (flush_update())
934                                 return 1;
935                 }
936         }
937
938         if (G_filter.tb != -1) {
939                 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
940         } else if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
941                 bb_perror_msg_and_die("can't send dump request");
942         }
943         xrtnl_dump_filter(&rth, print_route, NULL);
944
945         return 0;
946 }
947
948
949 /* Return value becomes exitcode. It's okay to not return at all */
950 static int iproute_get(char **argv)
951 {
952         struct rtnl_handle rth;
953         struct {
954                 struct nlmsghdr n;
955                 struct rtmsg    r;
956                 char            buf[1024];
957         } req;
958         char *idev = NULL;
959         char *odev = NULL;
960         bool connected = 0;
961         bool from_ok = 0;
962         static const char options[] ALIGN1 =
963                 "from\0""iif\0""oif\0""dev\0""notify\0""connected\0""to\0";
964
965         memset(&req, 0, sizeof(req));
966
967         iproute_reset_filter();
968
969         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
970         if (NLM_F_REQUEST)
971                 req.n.nlmsg_flags = NLM_F_REQUEST;
972         if (RTM_GETROUTE)
973                 req.n.nlmsg_type = RTM_GETROUTE;
974         req.r.rtm_family = preferred_family;
975         /*req.r.rtm_table = 0; - memset did this already */
976         /*req.r.rtm_protocol = 0;*/
977         /*req.r.rtm_scope = 0;*/
978         /*req.r.rtm_type = 0;*/
979         /*req.r.rtm_src_len = 0;*/
980         /*req.r.rtm_dst_len = 0;*/
981         /*req.r.rtm_tos = 0;*/
982
983         while (*argv) {
984                 switch (index_in_strings(options, *argv)) {
985                         case 0: /* from */
986                         {
987                                 inet_prefix addr;
988                                 NEXT_ARG();
989                                 from_ok = 1;
990                                 get_prefix(&addr, *argv, req.r.rtm_family);
991                                 if (req.r.rtm_family == AF_UNSPEC) {
992                                         req.r.rtm_family = addr.family;
993                                 }
994                                 if (addr.bytelen) {
995                                         addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
996                                 }
997                                 req.r.rtm_src_len = addr.bitlen;
998                                 break;
999                         }
1000                         case 1: /* iif */
1001                                 NEXT_ARG();
1002                                 idev = *argv;
1003                                 break;
1004                         case 2: /* oif */
1005                         case 3: /* dev */
1006                                 NEXT_ARG();
1007                                 odev = *argv;
1008                                 break;
1009                         case 4: /* notify */
1010                                 req.r.rtm_flags |= RTM_F_NOTIFY;
1011                                 break;
1012                         case 5: /* connected */
1013                                 connected = 1;
1014                                 break;
1015                         case 6: /* to */
1016                                 NEXT_ARG();
1017                         default:
1018                         {
1019                                 inet_prefix addr;
1020                                 get_prefix(&addr, *argv, req.r.rtm_family);
1021                                 if (req.r.rtm_family == AF_UNSPEC) {
1022                                         req.r.rtm_family = addr.family;
1023                                 }
1024                                 if (addr.bytelen) {
1025                                         addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
1026                                 }
1027                                 req.r.rtm_dst_len = addr.bitlen;
1028                         }
1029                 }
1030                 argv++;
1031         }
1032
1033         if (req.r.rtm_dst_len == 0) {
1034                 bb_error_msg_and_die("need at least destination address");
1035         }
1036
1037         xrtnl_open(&rth);
1038
1039         ll_init_map(&rth);
1040
1041         if (idev || odev)  {
1042                 int idx;
1043
1044                 if (idev) {
1045                         idx = xll_name_to_index(idev);
1046                         addattr32(&req.n, sizeof(req), RTA_IIF, idx);
1047                 }
1048                 if (odev) {
1049                         idx = xll_name_to_index(odev);
1050                         addattr32(&req.n, sizeof(req), RTA_OIF, idx);
1051                 }
1052         }
1053
1054         if (req.r.rtm_family == AF_UNSPEC) {
1055                 req.r.rtm_family = AF_INET;
1056         }
1057
1058         if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
1059                 return 2;
1060         }
1061
1062         if (connected && !from_ok) {
1063                 struct rtmsg *r = NLMSG_DATA(&req.n);
1064                 int len = req.n.nlmsg_len;
1065                 struct rtattr * tb[RTA_MAX+1];
1066
1067                 print_route(NULL, &req.n, NULL);
1068
1069                 if (req.n.nlmsg_type != RTM_NEWROUTE) {
1070                         bb_error_msg_and_die("not a route?");
1071                 }
1072                 len -= NLMSG_LENGTH(sizeof(*r));
1073                 if (len < 0) {
1074                         bb_error_msg_and_die("wrong len %d", len);
1075                 }
1076
1077                 memset(tb, 0, sizeof(tb));
1078                 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
1079
1080                 if (tb[RTA_PREFSRC]) {
1081                         tb[RTA_PREFSRC]->rta_type = RTA_SRC;
1082                         r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
1083                 } else if (!tb[RTA_SRC]) {
1084                         bb_error_msg_and_die("can't connect the route");
1085                 }
1086                 if (!odev && tb[RTA_OIF]) {
1087                         tb[RTA_OIF]->rta_type = 0;
1088                 }
1089                 if (tb[RTA_GATEWAY]) {
1090                         tb[RTA_GATEWAY]->rta_type = 0;
1091                 }
1092                 if (!idev && tb[RTA_IIF]) {
1093                         tb[RTA_IIF]->rta_type = 0;
1094                 }
1095                 req.n.nlmsg_flags = NLM_F_REQUEST;
1096                 req.n.nlmsg_type = RTM_GETROUTE;
1097
1098                 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
1099                         return 2;
1100                 }
1101         }
1102         print_route(NULL, &req.n, NULL);
1103         return 0;
1104 }
1105
1106 /* Return value becomes exitcode. It's okay to not return at all */
1107 int FAST_FUNC do_iproute(char **argv)
1108 {
1109         static const char ip_route_commands[] ALIGN1 =
1110                 "a\0""add\0""append\0""change\0""chg\0"
1111                 "delete\0""get\0""list\0""show\0"
1112                 "prepend\0""replace\0""test\0""flush\0"
1113         ;
1114         enum {
1115                 CMD_a = 0, CMD_add, CMD_append, CMD_change, CMD_chg,
1116                 CMD_delete, CMD_get, CMD_list, CMD_show,
1117                 CMD_prepend, CMD_replace, CMD_test, CMD_flush,
1118         };
1119         int command_num;
1120         unsigned flags = 0;
1121         int cmd = RTM_NEWROUTE;
1122
1123         INIT_G();
1124
1125         if (!*argv)
1126                 return iproute_list_or_flush(argv, 0);
1127
1128         /* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */
1129         /* It probably means that it is using "first match" rule */
1130         command_num = index_in_substrings(ip_route_commands, *argv);
1131
1132         switch (command_num) {
1133                 case CMD_a:
1134                 case CMD_add:
1135                         flags = NLM_F_CREATE|NLM_F_EXCL;
1136                         break;
1137                 case CMD_append:
1138                         flags = NLM_F_CREATE|NLM_F_APPEND;
1139                         break;
1140                 case CMD_change:
1141                 case CMD_chg:
1142                         flags = NLM_F_REPLACE;
1143                         break;
1144                 case CMD_delete:
1145                         cmd = RTM_DELROUTE;
1146                         break;
1147                 case CMD_get:
1148                         return iproute_get(argv + 1);
1149                 case CMD_list:
1150                 case CMD_show:
1151                         return iproute_list_or_flush(argv + 1, 0);
1152                 case CMD_prepend:
1153                         flags = NLM_F_CREATE;
1154                         break;
1155                 case CMD_replace:
1156                         flags = NLM_F_CREATE|NLM_F_REPLACE;
1157                         break;
1158                 case CMD_test:
1159                         flags = NLM_F_EXCL;
1160                         break;
1161                 case CMD_flush:
1162                         return iproute_list_or_flush(argv + 1, 1);
1163                 default:
1164                         invarg_1_to_2(*argv, applet_name);
1165         }
1166
1167         return iproute_modify(cmd, flags, argv + 1);
1168 }