2 * iproute.c "ip route".
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
14 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
15 * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
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>
37 #define RTAX_RTTVAR RTAX_HOPS
46 struct rtnl_handle *rth;
47 int protocol, protocolmask;
62 static int print_route(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
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];
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);
78 len -= NLMSG_LENGTH(sizeof(*r));
80 error_msg("wrong nlmsg len %d", len);
84 if (r->rtm_family == AF_INET6)
86 else if (r->rtm_family == AF_INET)
89 if (r->rtm_family == AF_INET6) {
92 if (!(r->rtm_flags&RTM_F_CLONED)) {
96 if (r->rtm_flags&RTM_F_CLONED) {
99 if (filter.tb == RT_TABLE_LOCAL) {
100 if (r->rtm_type != RTN_LOCAL) {
103 } else if (filter.tb == RT_TABLE_MAIN) {
104 if (r->rtm_type == RTN_LOCAL) {
113 if (filter.tb > 0 && filter.tb != r->rtm_table) {
117 if (filter.rdst.family &&
118 (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) {
121 if (filter.mdst.family &&
122 (r->rtm_family != filter.mdst.family ||
123 (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) {
126 if (filter.rsrc.family &&
127 (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) {
130 if (filter.msrc.family &&
131 (r->rtm_family != filter.msrc.family ||
132 (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) {
136 memset(tb, 0, sizeof(tb));
137 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
139 if (n->nlmsg_type == RTM_DELROUTE) {
140 fprintf(fp, "Deleted ");
142 if (r->rtm_type != RTN_UNICAST && !filter.type) {
143 fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
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]),
155 fprintf(fp, "%s ", format_host(r->rtm_family,
156 RTA_PAYLOAD(tb[RTA_DST]),
157 RTA_DATA(tb[RTA_DST]),
161 } else if (r->rtm_dst_len) {
162 fprintf(fp, "0/%d ", r->rtm_dst_len);
164 fprintf(fp, "default ");
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]),
175 fprintf(fp, "from %s ", format_host(r->rtm_family,
176 RTA_PAYLOAD(tb[RTA_SRC]),
177 RTA_DATA(tb[RTA_SRC]),
181 } else if (r->rtm_src_len) {
182 fprintf(fp, "from 0/%u ", r->rtm_src_len);
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)));
191 if (tb[RTA_OIF] && filter.oifmask != -1) {
192 fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
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.
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)));
205 if (tb[RTA_PRIORITY]) {
206 fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY]));
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]);
213 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
218 if (r->rtm_flags & RTM_F_CLONED) {
219 fprintf(fp, "%s cache ", _SL_);
221 if (ci->rta_expires) {
222 fprintf(fp, " expires %dsec", ci->rta_expires/hz);
224 if (ci->rta_error != 0) {
225 fprintf(fp, " error %d", ci->rta_error);
228 if (ci->rta_error != 0)
229 fprintf(fp, " error %d", ci->rta_error);
232 if (tb[RTA_IIF] && filter.iifmask != -1) {
233 fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
240 static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
242 struct rtnl_handle rth;
249 struct rtattr * mxrta = (void*)mxbuf;
257 memset(&req, 0, sizeof(req));
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;
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;
272 mxrta->rta_type = RTA_METRICS;
273 mxrta->rta_len = RTA_LENGTH(0);
276 if (strcmp(*argv, "src") == 0) {
279 get_addr(&addr, *argv, req.r.rtm_family);
280 if (req.r.rtm_family == AF_UNSPEC) {
281 req.r.rtm_family = addr.family;
283 addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
284 } else if (strcmp(*argv, "via") == 0) {
288 get_addr(&addr, *argv, req.r.rtm_family);
289 if (req.r.rtm_family == AF_UNSPEC) {
290 req.r.rtm_family = addr.family;
292 addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
293 } else if (strcmp(*argv, "mtu") == 0) {
296 if (strcmp(*argv, "lock") == 0) {
297 mxlock |= (1<<RTAX_MTU);
300 if (get_unsigned(&mtu, *argv, 0)) {
301 invarg("\"mtu\" value is invalid\n", *argv);
303 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
304 } else if (matches(*argv, "protocol") == 0) {
307 if (rtnl_rtprot_a2n(&prot, *argv))
308 invarg("\"protocol\" value is invalid\n", *argv);
309 req.r.rtm_protocol = prot;
311 } else if (strcmp(*argv, "dev") == 0 ||
312 strcmp(*argv, "oif") == 0) {
319 if (strcmp(*argv, "to") == 0) {
322 if ((**argv < '0' || **argv > '9') &&
323 rtnl_rtntype_a2n(&type, *argv) == 0) {
325 req.r.rtm_type = type;
330 duparg2("to", *argv);
332 get_prefix(&dst, *argv, req.r.rtm_family);
333 if (req.r.rtm_family == AF_UNSPEC) {
334 req.r.rtm_family = dst.family;
336 req.r.rtm_dst_len = dst.bitlen;
339 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
345 if (rtnl_open(&rth, 0) < 0) {
355 if ((idx = ll_name_to_index(d)) == 0) {
356 error_msg("Cannot find device \"%s\"", d);
359 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
363 if (mxrta->rta_len > RTA_LENGTH(0)) {
365 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
367 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
370 if (req.r.rtm_family == AF_UNSPEC) {
371 req.r.rtm_family = AF_INET;
374 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
381 static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
387 struct sockaddr_nl nladdr;
389 memset(&nladdr, 0, sizeof(nladdr));
390 memset(&req, 0, sizeof(req));
391 nladdr.nl_family = AF_NETLINK;
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;
401 return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
404 static void iproute_reset_filter(void)
406 memset(&filter, 0, sizeof(filter));
407 filter.mdst.bitlen = -1;
408 filter.msrc.bitlen = -1;
411 static int iproute_list(int argc, char **argv)
413 int do_ipv6 = preferred_family;
414 struct rtnl_handle rth;
418 iproute_reset_filter();
419 filter.tb = RT_TABLE_MAIN;
422 if (matches(*argv, "protocol") == 0) {
425 filter.protocolmask = -1;
426 if (rtnl_rtprot_a2n(&prot, *argv)) {
427 if (strcmp(*argv, "all") != 0) {
428 invarg("invalid \"protocol\"\n", *argv);
431 filter.protocolmask = 0;
433 filter.protocol = prot;
434 } else if (strcmp(*argv, "dev") == 0 ||
435 strcmp(*argv, "oif") == 0) {
438 } else if (strcmp(*argv, "iif") == 0) {
441 } else if (matches(*argv, "from") == 0) {
443 if (matches(*argv, "root") == 0) {
445 get_prefix(&filter.rsrc, *argv, do_ipv6);
446 } else if (matches(*argv, "match") == 0) {
448 get_prefix(&filter.msrc, *argv, do_ipv6);
450 if (matches(*argv, "exact") == 0) {
453 get_prefix(&filter.msrc, *argv, do_ipv6);
454 filter.rsrc = filter.msrc;
457 if (matches(*argv, "to") == 0) {
460 if (matches(*argv, "root") == 0) {
462 get_prefix(&filter.rdst, *argv, do_ipv6);
463 } else if (matches(*argv, "match") == 0) {
465 get_prefix(&filter.mdst, *argv, do_ipv6);
467 if (matches(*argv, "exact") == 0) {
470 get_prefix(&filter.mdst, *argv, do_ipv6);
471 filter.rdst = filter.mdst;
477 if (do_ipv6 == AF_UNSPEC && filter.tb) {
481 if (rtnl_open(&rth, 0) < 0) {
491 if ((idx = ll_name_to_index(id)) == 0) {
492 error_msg("Cannot find device \"%s\"", id);
499 if ((idx = ll_name_to_index(od)) == 0) {
500 error_msg("Cannot find device \"%s\"", od);
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");
512 if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
513 perror_msg_and_die("Cannot send dump request");
517 if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
518 error_msg_and_die("Dump terminated");
525 static int iproute_get(int argc, char **argv)
527 struct rtnl_handle rth;
537 const char *options[] = { "from", "iif", "oif", "dev", "notify", "connected", "to", 0 };
539 memset(&req, 0, sizeof(req));
541 iproute_reset_filter();
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;
548 req.r.rtm_protocol = 0;
551 req.r.rtm_src_len = 0;
552 req.r.rtm_dst_len = 0;
556 switch (compare_string_array(options, *argv)) {
562 get_prefix(&addr, *argv, req.r.rtm_family);
563 if (req.r.rtm_family == AF_UNSPEC) {
564 req.r.rtm_family = addr.family;
567 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
569 req.r.rtm_src_len = addr.bitlen;
582 req.r.rtm_flags |= RTM_F_NOTIFY;
584 case 5: /* connected */
592 get_prefix(&addr, *argv, req.r.rtm_family);
593 if (req.r.rtm_family == AF_UNSPEC) {
594 req.r.rtm_family = addr.family;
597 addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
599 req.r.rtm_dst_len = addr.bitlen;
605 if (req.r.rtm_dst_len == 0) {
606 error_msg_and_die("need at least destination address");
609 if (rtnl_open(&rth, 0) < 0)
618 if ((idx = ll_name_to_index(idev)) == 0) {
619 error_msg("Cannot find device \"%s\"", idev);
622 addattr32(&req.n, sizeof(req), RTA_IIF, idx);
625 if ((idx = ll_name_to_index(odev)) == 0) {
626 error_msg("Cannot find device \"%s\"", odev);
629 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
633 if (req.r.rtm_family == AF_UNSPEC) {
634 req.r.rtm_family = AF_INET;
637 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
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];
646 if (print_route(NULL, &req.n, (void*)stdout) < 0) {
647 error_msg_and_die("An error :-)");
650 if (req.n.nlmsg_type != RTM_NEWROUTE) {
651 error_msg("Not a route?");
654 len -= NLMSG_LENGTH(sizeof(*r));
656 error_msg("Wrong len %d", len);
660 memset(tb, 0, sizeof(tb));
661 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
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");
670 if (!odev && tb[RTA_OIF]) {
671 tb[RTA_OIF]->rta_type = 0;
673 if (tb[RTA_GATEWAY]) {
674 tb[RTA_GATEWAY]->rta_type = 0;
676 if (!idev && tb[RTA_IIF]) {
677 tb[RTA_IIF]->rta_type = 0;
679 req.n.nlmsg_flags = NLM_F_REQUEST;
680 req.n.nlmsg_type = RTM_GETROUTE;
682 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
687 if (print_route(NULL, &req.n, (void*)stdout) < 0) {
688 error_msg_and_die("An error :-)");
694 int do_iproute(int argc, char **argv)
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;
703 command_num = compare_string_array(ip_route_commands, *argv);
705 switch(command_num) {
707 flags = NLM_F_CREATE|NLM_F_EXCL;
710 flags = NLM_F_CREATE|NLM_F_APPEND;
714 flags = NLM_F_REPLACE;
720 return iproute_get(argc-1, argv+1);
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;
731 error_msg_and_die("Unknown command %s", *argv);
734 return iproute_modify(cmd, flags, argc-1, argv+1);