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