Yet another major rework of the BusyBox config system, using the considerably
[oweals/busybox.git] / networking / libiproute / iproute.c
1 /*
2  * iproute.c            "ip route".
3  *
4  *              This program is free software; you can redistribute it and/or
5  *              modify it under the terms of the GNU General Public License
6  *              as published by the Free Software Foundation; either version
7  *              2 of the License, or (at your option) any later version.
8  *
9  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10  *
11  *
12  * Changes:
13  *
14  * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
15  * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <syslog.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <sys/time.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <netinet/ip.h>
28 #include <arpa/inet.h>
29 #include <linux/in_route.h>
30
31 #include "rt_names.h"
32 #include "utils.h"
33
34 #include "busybox.h"
35
36 #ifndef RTAX_RTTVAR
37 #define RTAX_RTTVAR RTAX_HOPS
38 #endif
39
40
41 static struct
42 {
43         int tb;
44         int flushp;
45         int flushe;
46         struct rtnl_handle *rth;
47         int protocol, protocolmask;
48         int scope, scopemask;
49         int type, typemask;
50         int tos, tosmask;
51         int iif, iifmask;
52         int oif, oifmask;
53         int realm, realmmask;
54         inet_prefix rprefsrc;
55         inet_prefix rvia;
56         inet_prefix rdst;
57         inet_prefix mdst;
58         inet_prefix rsrc;
59         inet_prefix msrc;
60 } filter;
61
62 static int print_route(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
63 {
64         FILE *fp = (FILE*)arg;
65         struct rtmsg *r = NLMSG_DATA(n);
66         int len = n->nlmsg_len;
67         struct rtattr * tb[RTA_MAX+1];
68         char abuf[256];
69         int host_len = -1;
70         SPRINT_BUF(b1);
71         
72
73         if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
74                 fprintf(stderr, "Not a route: %08x %08x %08x\n",
75                         n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
76                 return 0;
77         }
78         len -= NLMSG_LENGTH(sizeof(*r));
79         if (len < 0) {
80                 error_msg("wrong nlmsg len %d", len);
81                 return -1;
82         }
83
84         if (r->rtm_family == AF_INET6)
85                 host_len = 128;
86         else if (r->rtm_family == AF_INET)
87                 host_len = 32;
88
89         if (r->rtm_family == AF_INET6) {
90                 if (filter.tb) {
91                         if (filter.tb < 0) {
92                                 if (!(r->rtm_flags&RTM_F_CLONED)) {
93                                         return 0;
94                                 }
95                         } else {
96                                 if (r->rtm_flags&RTM_F_CLONED) {
97                                         return 0;
98                                 }
99                                 if (filter.tb == RT_TABLE_LOCAL) {
100                                         if (r->rtm_type != RTN_LOCAL) {
101                                                 return 0;
102                                         }
103                                 } else if (filter.tb == RT_TABLE_MAIN) {
104                                         if (r->rtm_type == RTN_LOCAL) {
105                                                 return 0;
106                                         }
107                                 } else {
108                                         return 0;
109                                 }
110                         }
111                 }
112         } else {
113                 if (filter.tb > 0 && filter.tb != r->rtm_table) {
114                         return 0;
115                 }
116         }
117         if (filter.rdst.family &&
118             (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) {
119                 return 0;
120         }
121         if (filter.mdst.family &&
122             (r->rtm_family != filter.mdst.family ||
123              (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) {
124                 return 0;
125         }
126         if (filter.rsrc.family &&
127             (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) {
128                 return 0;
129         }
130         if (filter.msrc.family &&
131             (r->rtm_family != filter.msrc.family ||
132              (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) {
133                 return 0;
134         }
135
136         memset(tb, 0, sizeof(tb));
137         parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
138
139         if (n->nlmsg_type == RTM_DELROUTE) {
140                 fprintf(fp, "Deleted ");
141         }
142         if (r->rtm_type != RTN_UNICAST && !filter.type) {
143                 fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
144         }
145
146         if (tb[RTA_DST]) {
147                 if (r->rtm_dst_len != host_len) {
148                         fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
149                                                          RTA_PAYLOAD(tb[RTA_DST]),
150                                                          RTA_DATA(tb[RTA_DST]),
151                                                          abuf, sizeof(abuf)),
152                                 r->rtm_dst_len
153                                 );
154                 } else {
155                         fprintf(fp, "%s ", format_host(r->rtm_family,
156                                                        RTA_PAYLOAD(tb[RTA_DST]),
157                                                        RTA_DATA(tb[RTA_DST]),
158                                                        abuf, sizeof(abuf))
159                                 );
160                 }
161         } else if (r->rtm_dst_len) {
162                 fprintf(fp, "0/%d ", r->rtm_dst_len);
163         } else {
164                 fprintf(fp, "default ");
165         }
166         if (tb[RTA_SRC]) {
167                 if (r->rtm_src_len != host_len) {
168                         fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
169                                                          RTA_PAYLOAD(tb[RTA_SRC]),
170                                                          RTA_DATA(tb[RTA_SRC]),
171                                                          abuf, sizeof(abuf)),
172                                 r->rtm_src_len
173                                 );
174                 } else {
175                         fprintf(fp, "from %s ", format_host(r->rtm_family,
176                                                        RTA_PAYLOAD(tb[RTA_SRC]),
177                                                        RTA_DATA(tb[RTA_SRC]),
178                                                        abuf, sizeof(abuf))
179                                 );
180                 }
181         } else if (r->rtm_src_len) {
182                 fprintf(fp, "from 0/%u ", r->rtm_src_len);
183         }
184         if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
185                 fprintf(fp, "via %s ", 
186                         format_host(r->rtm_family,
187                                     RTA_PAYLOAD(tb[RTA_GATEWAY]),
188                                     RTA_DATA(tb[RTA_GATEWAY]),
189                                     abuf, sizeof(abuf)));
190         }
191         if (tb[RTA_OIF] && filter.oifmask != -1) {
192                 fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
193         }
194
195         if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
196                 /* Do not use format_host(). It is our local addr
197                    and symbolic name will not be useful.
198                  */
199                 fprintf(fp, " src %s ", 
200                         rt_addr_n2a(r->rtm_family,
201                                     RTA_PAYLOAD(tb[RTA_PREFSRC]),
202                                     RTA_DATA(tb[RTA_PREFSRC]),
203                                     abuf, sizeof(abuf)));
204         }
205         if (tb[RTA_PRIORITY]) {
206                 fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY]));
207         }
208         if (r->rtm_family == AF_INET6) {
209                 struct rta_cacheinfo *ci = NULL;
210                 if (tb[RTA_CACHEINFO]) {
211                         ci = RTA_DATA(tb[RTA_CACHEINFO]);
212                 }
213                 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
214                         static int hz;
215                         if (!hz) {
216                                 hz = get_hz();
217                         }
218                         if (r->rtm_flags & RTM_F_CLONED) {
219                                 fprintf(fp, "%s    cache ", _SL_);
220                         }
221                         if (ci->rta_expires) {
222                                 fprintf(fp, " expires %dsec", ci->rta_expires/hz);
223                         }
224                         if (ci->rta_error != 0) {
225                                 fprintf(fp, " error %d", ci->rta_error);
226                         }
227                 } else if (ci) {
228                         if (ci->rta_error != 0)
229                                 fprintf(fp, " error %d", ci->rta_error);
230                 }
231         }
232         if (tb[RTA_IIF] && filter.iifmask != -1) {
233                 fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
234         }
235         fprintf(fp, "\n");
236         fflush(fp);
237         return 0;
238 }
239
240 static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
241 {
242         struct rtnl_handle rth;
243         struct {
244                 struct nlmsghdr         n;
245                 struct rtmsg            r;
246                 char                    buf[1024];
247         } req;
248         char  mxbuf[256];
249         struct rtattr * mxrta = (void*)mxbuf;
250         unsigned mxlock = 0;
251         char  *d = NULL;
252         int gw_ok = 0;
253         int dst_ok = 0;
254         int proto_ok = 0;
255         int type_ok = 0;
256
257         memset(&req, 0, sizeof(req));
258
259         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
260         req.n.nlmsg_flags = NLM_F_REQUEST|flags;
261         req.n.nlmsg_type = cmd;
262         req.r.rtm_family = preferred_family;
263         req.r.rtm_table = RT_TABLE_MAIN;
264         req.r.rtm_scope = RT_SCOPE_NOWHERE;
265
266         if (cmd != RTM_DELROUTE) {
267                 req.r.rtm_protocol = RTPROT_BOOT;
268                 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
269                 req.r.rtm_type = RTN_UNICAST;
270         }
271
272         mxrta->rta_type = RTA_METRICS;
273         mxrta->rta_len = RTA_LENGTH(0);
274
275         while (argc > 0) {
276                 if (strcmp(*argv, "src") == 0) {
277                         inet_prefix addr;
278                         NEXT_ARG();
279                         get_addr(&addr, *argv, req.r.rtm_family);
280                         if (req.r.rtm_family == AF_UNSPEC) {
281                                 req.r.rtm_family = addr.family;
282                         }
283                         addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
284                 } else if (strcmp(*argv, "via") == 0) {
285                         inet_prefix addr;
286                         gw_ok = 1;
287                         NEXT_ARG();
288                         get_addr(&addr, *argv, req.r.rtm_family);
289                         if (req.r.rtm_family == AF_UNSPEC) {
290                                 req.r.rtm_family = addr.family;
291                         }
292                         addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
293                 } else if (strcmp(*argv, "mtu") == 0) {
294                         unsigned mtu;
295                         NEXT_ARG();
296                         if (strcmp(*argv, "lock") == 0) {
297                                 mxlock |= (1<<RTAX_MTU);
298                                 NEXT_ARG();
299                         }
300                         if (get_unsigned(&mtu, *argv, 0)) {
301                                 invarg("\"mtu\" value is invalid\n", *argv);
302                         }
303                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
304                 } else if (matches(*argv, "protocol") == 0) {
305                         int prot;
306                         NEXT_ARG();
307                         if (rtnl_rtprot_a2n(&prot, *argv))
308                                 invarg("\"protocol\" value is invalid\n", *argv);
309                         req.r.rtm_protocol = prot;
310                         proto_ok =1;
311                 } else if (strcmp(*argv, "dev") == 0 ||
312                            strcmp(*argv, "oif") == 0) {
313                         NEXT_ARG();
314                         d = *argv;
315                 } else {
316                         int type;
317                         inet_prefix dst;
318
319                         if (strcmp(*argv, "to") == 0) {
320                                 NEXT_ARG();
321                         }
322                         if ((**argv < '0' || **argv > '9') &&
323                             rtnl_rtntype_a2n(&type, *argv) == 0) {
324                                 NEXT_ARG();
325                                 req.r.rtm_type = type;
326                                 type_ok = 1;
327                         }
328
329                         if (dst_ok) {
330                                 duparg2("to", *argv);
331                         }
332                         get_prefix(&dst, *argv, req.r.rtm_family);
333                         if (req.r.rtm_family == AF_UNSPEC) {
334                                 req.r.rtm_family = dst.family;
335                         }
336                         req.r.rtm_dst_len = dst.bitlen;
337                         dst_ok = 1;
338                         if (dst.bytelen) {
339                                 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
340                         }
341                 }
342                 argc--; argv++;
343         }
344
345         if (rtnl_open(&rth, 0) < 0) {
346                 exit(1);
347         }
348
349         if (d)  {
350                 int idx;
351
352                 ll_init_map(&rth);
353
354                 if (d) {
355                         if ((idx = ll_name_to_index(d)) == 0) {
356                                 error_msg("Cannot find device \"%s\"", d);
357                                 return -1;
358                         }
359                         addattr32(&req.n, sizeof(req), RTA_OIF, idx);
360                 }
361         }
362
363         if (mxrta->rta_len > RTA_LENGTH(0)) {
364                 if (mxlock) {
365                         rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
366                 }
367                 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
368         }
369
370         if (req.r.rtm_family == AF_UNSPEC) {
371                 req.r.rtm_family = AF_INET;
372         }
373
374         if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
375                 exit(2);
376         }
377
378         return 0;
379 }
380
381 static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
382 {
383         struct {
384                 struct nlmsghdr nlh;
385                 struct rtmsg rtm;
386         } req;
387         struct sockaddr_nl nladdr;
388
389         memset(&nladdr, 0, sizeof(nladdr));
390         memset(&req, 0, sizeof(req));
391         nladdr.nl_family = AF_NETLINK;
392
393         req.nlh.nlmsg_len = sizeof(req);
394         req.nlh.nlmsg_type = RTM_GETROUTE;
395         req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST;
396         req.nlh.nlmsg_pid = 0;
397         req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
398         req.rtm.rtm_family = family;
399         req.rtm.rtm_flags |= RTM_F_CLONED;
400
401         return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
402 }
403
404 static void iproute_reset_filter(void)
405 {
406         memset(&filter, 0, sizeof(filter));
407         filter.mdst.bitlen = -1;
408         filter.msrc.bitlen = -1;
409 }
410
411 static int iproute_list(int argc, char **argv)
412 {
413         int do_ipv6 = preferred_family;
414         struct rtnl_handle rth;
415         char *id = NULL;
416         char *od = NULL;
417
418         iproute_reset_filter();
419         filter.tb = RT_TABLE_MAIN;
420
421         while (argc > 0) {
422                 if (matches(*argv, "protocol") == 0) {
423                         int prot = 0;
424                         NEXT_ARG();
425                         filter.protocolmask = -1;
426                         if (rtnl_rtprot_a2n(&prot, *argv)) {
427                                 if (strcmp(*argv, "all") != 0) {
428                                         invarg("invalid \"protocol\"\n", *argv);
429                                 }
430                                 prot = 0;
431                                 filter.protocolmask = 0;
432                         }
433                         filter.protocol = prot;
434                 } else if (strcmp(*argv, "dev") == 0 ||
435                            strcmp(*argv, "oif") == 0) {
436                         NEXT_ARG();
437                         od = *argv;
438                 } else if (strcmp(*argv, "iif") == 0) {
439                         NEXT_ARG();
440                         id = *argv;
441                 } else if (matches(*argv, "from") == 0) {
442                         NEXT_ARG();
443                         if (matches(*argv, "root") == 0) {
444                                 NEXT_ARG();
445                                 get_prefix(&filter.rsrc, *argv, do_ipv6);
446                         } else if (matches(*argv, "match") == 0) {
447                                 NEXT_ARG();
448                                 get_prefix(&filter.msrc, *argv, do_ipv6);
449                         } else {
450                                 if (matches(*argv, "exact") == 0) {
451                                         NEXT_ARG();
452                                 }
453                                 get_prefix(&filter.msrc, *argv, do_ipv6);
454                                 filter.rsrc = filter.msrc;
455                         }
456                 } else {
457                         if (matches(*argv, "to") == 0) {
458                                 NEXT_ARG();
459                         }
460                         if (matches(*argv, "root") == 0) {
461                                 NEXT_ARG();
462                                 get_prefix(&filter.rdst, *argv, do_ipv6);
463                         } else if (matches(*argv, "match") == 0) {
464                                 NEXT_ARG();
465                                 get_prefix(&filter.mdst, *argv, do_ipv6);
466                         } else {
467                                 if (matches(*argv, "exact") == 0) {
468                                         NEXT_ARG();
469                                 }
470                                 get_prefix(&filter.mdst, *argv, do_ipv6);
471                                 filter.rdst = filter.mdst;
472                         }
473                 }
474                 argc--; argv++;
475         }
476
477         if (do_ipv6 == AF_UNSPEC && filter.tb) {
478                 do_ipv6 = AF_INET;
479         }
480
481         if (rtnl_open(&rth, 0) < 0) {
482                 exit(1);
483         }
484
485         ll_init_map(&rth);
486
487         if (id || od)  {
488                 int idx;
489
490                 if (id) {
491                         if ((idx = ll_name_to_index(id)) == 0) {
492                                 error_msg("Cannot find device \"%s\"", id);
493                                 return -1;
494                         }
495                         filter.iif = idx;
496                         filter.iifmask = -1;
497                 }
498                 if (od) {
499                         if ((idx = ll_name_to_index(od)) == 0) {
500                                 error_msg("Cannot find device \"%s\"", od);
501                         }
502                         filter.oif = idx;
503                         filter.oifmask = -1;
504                 }
505         }
506
507         if (filter.tb != -1) {
508                 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
509                         perror_msg_and_die("Cannot send dump request");
510                 }
511         } else {
512                 if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
513                         perror_msg_and_die("Cannot send dump request");
514                 }
515         }
516
517         if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
518                 error_msg_and_die("Dump terminated");
519         }
520
521         exit(0);
522 }
523
524
525 static int iproute_get(int argc, char **argv)
526 {
527         struct rtnl_handle rth;
528         struct {
529                 struct nlmsghdr         n;
530                 struct rtmsg            r;
531                 char                    buf[1024];
532         } req;
533         char  *idev = NULL;
534         char  *odev = NULL;
535         int connected = 0;
536         int from_ok = 0;
537         const char *options[] = { "from", "iif", "oif", "dev", "notify", "connected", "to", 0 };
538
539         memset(&req, 0, sizeof(req));
540
541         iproute_reset_filter();
542
543         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
544         req.n.nlmsg_flags = NLM_F_REQUEST;
545         req.n.nlmsg_type = RTM_GETROUTE;
546         req.r.rtm_family = preferred_family;
547         req.r.rtm_table = 0;
548         req.r.rtm_protocol = 0;
549         req.r.rtm_scope = 0;
550         req.r.rtm_type = 0;
551         req.r.rtm_src_len = 0;
552         req.r.rtm_dst_len = 0;
553         req.r.rtm_tos = 0;
554         
555         while (argc > 0) {
556                 switch (compare_string_array(options, *argv)) {
557                         case 0: /* from */
558                         {
559                                 inet_prefix addr;
560                                 NEXT_ARG();
561                                 from_ok = 1;
562                                 get_prefix(&addr, *argv, req.r.rtm_family);
563                                 if (req.r.rtm_family == AF_UNSPEC) {
564                                         req.r.rtm_family = addr.family;
565                                 }
566                                 if (addr.bytelen) {
567                                         addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
568                                 }
569                                 req.r.rtm_src_len = addr.bitlen;
570                                 break;
571                         }
572                         case 1: /* iif */
573                                 NEXT_ARG();
574                                 idev = *argv;
575                                 break;
576                         case 2: /* oif */
577                         case 3: /* dev */
578                                 NEXT_ARG();
579                                 odev = *argv;
580                                 break;
581                         case 4: /* notify */
582                                 req.r.rtm_flags |= RTM_F_NOTIFY;
583                                 break;
584                         case 5: /* connected */
585                                 connected = 1;
586                                 break;
587                         case 6: /* to */
588                                 NEXT_ARG();
589                         default:
590                         {
591                                 inet_prefix addr;
592                                 get_prefix(&addr, *argv, req.r.rtm_family);
593                                 if (req.r.rtm_family == AF_UNSPEC) {
594                                         req.r.rtm_family = addr.family;
595                                 }
596                                 if (addr.bytelen) {
597                                         addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
598                                 }
599                                 req.r.rtm_dst_len = addr.bitlen;
600                         }
601                         argc--; argv++;
602                 }
603         }
604
605         if (req.r.rtm_dst_len == 0) {
606                 error_msg_and_die("need at least destination address");
607         }
608
609         if (rtnl_open(&rth, 0) < 0)
610                 exit(1);
611
612         ll_init_map(&rth);
613
614         if (idev || odev)  {
615                 int idx;
616
617                 if (idev) {
618                         if ((idx = ll_name_to_index(idev)) == 0) {
619                                 error_msg("Cannot find device \"%s\"", idev);
620                                 return -1;
621                         }
622                         addattr32(&req.n, sizeof(req), RTA_IIF, idx);
623                 }
624                 if (odev) {
625                         if ((idx = ll_name_to_index(odev)) == 0) {
626                                 error_msg("Cannot find device \"%s\"", odev);
627                                 return -1;
628                         }
629                         addattr32(&req.n, sizeof(req), RTA_OIF, idx);
630                 }
631         }
632
633         if (req.r.rtm_family == AF_UNSPEC) {
634                 req.r.rtm_family = AF_INET;
635         }
636
637         if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
638                 exit(2);
639         }
640
641         if (connected && !from_ok) {
642                 struct rtmsg *r = NLMSG_DATA(&req.n);
643                 int len = req.n.nlmsg_len;
644                 struct rtattr * tb[RTA_MAX+1];
645
646                 if (print_route(NULL, &req.n, (void*)stdout) < 0) {
647                         error_msg_and_die("An error :-)");
648                 }
649
650                 if (req.n.nlmsg_type != RTM_NEWROUTE) {
651                         error_msg("Not a route?");
652                         return -1;
653                 }
654                 len -= NLMSG_LENGTH(sizeof(*r));
655                 if (len < 0) {
656                         error_msg("Wrong len %d", len);
657                         return -1;
658                 }
659
660                 memset(tb, 0, sizeof(tb));
661                 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
662
663                 if (tb[RTA_PREFSRC]) {
664                         tb[RTA_PREFSRC]->rta_type = RTA_SRC;
665                         r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
666                 } else if (!tb[RTA_SRC]) {
667                         error_msg("Failed to connect the route");
668                         return -1;
669                 }
670                 if (!odev && tb[RTA_OIF]) {
671                         tb[RTA_OIF]->rta_type = 0;
672                 }
673                 if (tb[RTA_GATEWAY]) {
674                         tb[RTA_GATEWAY]->rta_type = 0;
675                 }
676                 if (!idev && tb[RTA_IIF]) {
677                         tb[RTA_IIF]->rta_type = 0;
678                 }
679                 req.n.nlmsg_flags = NLM_F_REQUEST;
680                 req.n.nlmsg_type = RTM_GETROUTE;
681
682                 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
683                         exit(2);
684                 }
685         }
686
687         if (print_route(NULL, &req.n, (void*)stdout) < 0) {
688                 error_msg_and_die("An error :-)");
689         }
690
691         exit(0);
692 }
693
694 int do_iproute(int argc, char **argv)
695 {
696         const char *ip_route_commands[] = { "add", "append", "change", "chg",
697                 "delete", "get", "list", "show", "prepend", "replace", "test", 0 };
698         unsigned short command_num = 6;
699         unsigned int flags = 0;
700         int cmd = RTM_NEWROUTE;
701
702         if (*argv) {
703                 command_num = compare_string_array(ip_route_commands, *argv);
704         }
705         switch(command_num) {
706                 case 0: /* add*/
707                         flags = NLM_F_CREATE|NLM_F_EXCL;
708                         break;
709                 case 1: /* append */
710                         flags = NLM_F_CREATE|NLM_F_APPEND;
711                         break;
712                 case 2: /* change */
713                 case 3: /* chg */
714                         flags = NLM_F_REPLACE;
715                         break;
716                 case 4: /* delete */
717                         cmd = RTM_DELROUTE;
718                         break;
719                 case 5: /* get */
720                         return iproute_get(argc-1, argv+1);
721                 case 6: /* list */
722                 case 7: /* show */
723                         return iproute_list(argc-1, argv+1);
724                 case 8: /* prepend */
725                         flags = NLM_F_CREATE;
726                 case 9: /* replace */
727                         flags = NLM_F_CREATE|NLM_F_REPLACE;
728                 case 10: /* test */
729                         flags = NLM_F_EXCL;
730                 default:
731                         error_msg_and_die("Unknown command %s", *argv);
732         }
733
734         return iproute_modify(cmd, flags, argc-1, argv+1);
735 }
736