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>
33 #include "ip_common.h"
38 #define RTAX_RTTVAR RTAX_HOPS
47 struct rtnl_handle *rth;
48 int protocol, protocolmask;
63 int print_route(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
65 FILE *fp = (FILE*)arg;
66 struct rtmsg *r = NLMSG_DATA(n);
67 int len = n->nlmsg_len;
68 struct rtattr * tb[RTA_MAX+1];
74 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
75 fprintf(stderr, "Not a route: %08x %08x %08x\n",
76 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
79 len -= NLMSG_LENGTH(sizeof(*r));
81 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
85 if (r->rtm_family == AF_INET6)
87 else if (r->rtm_family == AF_INET)
90 if (r->rtm_family == AF_INET6) {
93 if (!(r->rtm_flags&RTM_F_CLONED))
96 if (r->rtm_flags&RTM_F_CLONED)
98 if (filter.tb == RT_TABLE_LOCAL) {
99 if (r->rtm_type != RTN_LOCAL)
101 } else if (filter.tb == RT_TABLE_MAIN) {
102 if (r->rtm_type == RTN_LOCAL)
110 if (filter.tb > 0 && filter.tb != r->rtm_table)
113 if (filter.rdst.family &&
114 (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len))
116 if (filter.mdst.family &&
117 (r->rtm_family != filter.mdst.family ||
118 (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len)))
120 if (filter.rsrc.family &&
121 (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len))
123 if (filter.msrc.family &&
124 (r->rtm_family != filter.msrc.family ||
125 (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len)))
128 memset(tb, 0, sizeof(tb));
129 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
131 if (n->nlmsg_type == RTM_DELROUTE)
132 fprintf(fp, "Deleted ");
133 if (r->rtm_type != RTN_UNICAST && !filter.type)
134 fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
137 if (r->rtm_dst_len != host_len) {
138 fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
139 RTA_PAYLOAD(tb[RTA_DST]),
140 RTA_DATA(tb[RTA_DST]),
145 fprintf(fp, "%s ", format_host(r->rtm_family,
146 RTA_PAYLOAD(tb[RTA_DST]),
147 RTA_DATA(tb[RTA_DST]),
151 } else if (r->rtm_dst_len) {
152 fprintf(fp, "0/%d ", r->rtm_dst_len);
154 fprintf(fp, "default ");
157 if (r->rtm_src_len != host_len) {
158 fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
159 RTA_PAYLOAD(tb[RTA_SRC]),
160 RTA_DATA(tb[RTA_SRC]),
165 fprintf(fp, "from %s ", format_host(r->rtm_family,
166 RTA_PAYLOAD(tb[RTA_SRC]),
167 RTA_DATA(tb[RTA_SRC]),
171 } else if (r->rtm_src_len) {
172 fprintf(fp, "from 0/%u ", r->rtm_src_len);
174 if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
175 fprintf(fp, "via %s ",
176 format_host(r->rtm_family,
177 RTA_PAYLOAD(tb[RTA_GATEWAY]),
178 RTA_DATA(tb[RTA_GATEWAY]),
179 abuf, sizeof(abuf)));
181 if (tb[RTA_OIF] && filter.oifmask != -1)
182 fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
184 if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
185 /* Do not use format_host(). It is our local addr
186 and symbolic name will not be useful.
188 fprintf(fp, " src %s ",
189 rt_addr_n2a(r->rtm_family,
190 RTA_PAYLOAD(tb[RTA_PREFSRC]),
191 RTA_DATA(tb[RTA_PREFSRC]),
192 abuf, sizeof(abuf)));
194 if (tb[RTA_PRIORITY])
195 fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY]));
196 if (r->rtm_family == AF_INET6) {
197 struct rta_cacheinfo *ci = NULL;
198 if (tb[RTA_CACHEINFO])
199 ci = RTA_DATA(tb[RTA_CACHEINFO]);
200 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
204 if (r->rtm_flags & RTM_F_CLONED)
205 fprintf(fp, "%s cache ", _SL_);
207 fprintf(fp, " expires %dsec", ci->rta_expires/hz);
208 if (ci->rta_error != 0)
209 fprintf(fp, " error %d", ci->rta_error);
211 if (ci->rta_error != 0)
212 fprintf(fp, " error %d", ci->rta_error);
215 if (tb[RTA_IIF] && filter.iifmask != -1) {
216 fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
223 int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
225 struct rtnl_handle rth;
232 struct rtattr * mxrta = (void*)mxbuf;
240 memset(&req, 0, sizeof(req));
242 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
243 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
244 req.n.nlmsg_type = cmd;
245 req.r.rtm_family = preferred_family;
246 req.r.rtm_table = RT_TABLE_MAIN;
247 req.r.rtm_scope = RT_SCOPE_NOWHERE;
249 if (cmd != RTM_DELROUTE) {
250 req.r.rtm_protocol = RTPROT_BOOT;
251 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
252 req.r.rtm_type = RTN_UNICAST;
255 mxrta->rta_type = RTA_METRICS;
256 mxrta->rta_len = RTA_LENGTH(0);
259 if (strcmp(*argv, "src") == 0) {
262 get_addr(&addr, *argv, req.r.rtm_family);
263 if (req.r.rtm_family == AF_UNSPEC)
264 req.r.rtm_family = addr.family;
265 addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
266 } else if (strcmp(*argv, "via") == 0) {
270 get_addr(&addr, *argv, req.r.rtm_family);
271 if (req.r.rtm_family == AF_UNSPEC)
272 req.r.rtm_family = addr.family;
273 addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
274 } else if (strcmp(*argv, "mtu") == 0) {
277 if (strcmp(*argv, "lock") == 0) {
278 mxlock |= (1<<RTAX_MTU);
281 if (get_unsigned(&mtu, *argv, 0))
282 invarg("\"mtu\" value is invalid\n", *argv);
283 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
284 } else if (matches(*argv, "protocol") == 0) {
287 if (rtnl_rtprot_a2n(&prot, *argv))
288 invarg("\"protocol\" value is invalid\n", *argv);
289 req.r.rtm_protocol = prot;
291 } else if (strcmp(*argv, "dev") == 0 ||
292 strcmp(*argv, "oif") == 0) {
299 if (strcmp(*argv, "to") == 0) {
302 if ((**argv < '0' || **argv > '9') &&
303 rtnl_rtntype_a2n(&type, *argv) == 0) {
305 req.r.rtm_type = type;
310 duparg2("to", *argv);
311 get_prefix(&dst, *argv, req.r.rtm_family);
312 if (req.r.rtm_family == AF_UNSPEC)
313 req.r.rtm_family = dst.family;
314 req.r.rtm_dst_len = dst.bitlen;
317 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
322 if (rtnl_open(&rth, 0) < 0)
331 if ((idx = ll_name_to_index(d)) == 0) {
332 fprintf(stderr, "Cannot find device \"%s\"\n", d);
335 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
339 if (mxrta->rta_len > RTA_LENGTH(0)) {
341 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
342 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
345 if (req.r.rtm_family == AF_UNSPEC)
346 req.r.rtm_family = AF_INET;
348 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
354 static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
360 struct sockaddr_nl nladdr;
362 memset(&nladdr, 0, sizeof(nladdr));
363 memset(&req, 0, sizeof(req));
364 nladdr.nl_family = AF_NETLINK;
366 req.nlh.nlmsg_len = sizeof(req);
367 req.nlh.nlmsg_type = RTM_GETROUTE;
368 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST;
369 req.nlh.nlmsg_pid = 0;
370 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
371 req.rtm.rtm_family = family;
372 req.rtm.rtm_flags |= RTM_F_CLONED;
374 return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
377 static int iproute_list(int argc, char **argv)
379 int do_ipv6 = preferred_family;
380 struct rtnl_handle rth;
384 iproute_reset_filter();
385 filter.tb = RT_TABLE_MAIN;
388 if (matches(*argv, "protocol") == 0) {
391 filter.protocolmask = -1;
392 if (rtnl_rtprot_a2n(&prot, *argv)) {
393 if (strcmp(*argv, "all") != 0)
394 invarg("invalid \"protocol\"\n", *argv);
396 filter.protocolmask = 0;
398 filter.protocol = prot;
399 } else if (strcmp(*argv, "dev") == 0 ||
400 strcmp(*argv, "oif") == 0) {
403 } else if (strcmp(*argv, "iif") == 0) {
406 } else if (matches(*argv, "from") == 0) {
408 if (matches(*argv, "root") == 0) {
410 get_prefix(&filter.rsrc, *argv, do_ipv6);
411 } else if (matches(*argv, "match") == 0) {
413 get_prefix(&filter.msrc, *argv, do_ipv6);
415 if (matches(*argv, "exact") == 0) {
418 get_prefix(&filter.msrc, *argv, do_ipv6);
419 filter.rsrc = filter.msrc;
422 if (matches(*argv, "to") == 0) {
425 if (matches(*argv, "root") == 0) {
427 get_prefix(&filter.rdst, *argv, do_ipv6);
428 } else if (matches(*argv, "match") == 0) {
430 get_prefix(&filter.mdst, *argv, do_ipv6);
432 if (matches(*argv, "exact") == 0) {
435 get_prefix(&filter.mdst, *argv, do_ipv6);
436 filter.rdst = filter.mdst;
442 if (do_ipv6 == AF_UNSPEC && filter.tb)
445 if (rtnl_open(&rth, 0) < 0)
454 if ((idx = ll_name_to_index(id)) == 0) {
455 fprintf(stderr, "Cannot find device \"%s\"\n", id);
462 if ((idx = ll_name_to_index(od)) == 0) {
463 fprintf(stderr, "Cannot find device \"%s\"\n", od);
471 if (filter.tb != -1) {
472 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
473 perror("Cannot send dump request");
477 if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
478 perror("Cannot send dump request");
483 if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
484 fprintf(stderr, "Dump terminated\n");
492 int iproute_get(int argc, char **argv)
494 struct rtnl_handle rth;
505 memset(&req, 0, sizeof(req));
507 iproute_reset_filter();
509 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
510 req.n.nlmsg_flags = NLM_F_REQUEST;
511 req.n.nlmsg_type = RTM_GETROUTE;
512 req.r.rtm_family = preferred_family;
514 req.r.rtm_protocol = 0;
517 req.r.rtm_src_len = 0;
518 req.r.rtm_dst_len = 0;
522 if (matches(*argv, "from") == 0) {
526 get_prefix(&addr, *argv, req.r.rtm_family);
527 if (req.r.rtm_family == AF_UNSPEC)
528 req.r.rtm_family = addr.family;
530 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
531 req.r.rtm_src_len = addr.bitlen;
532 } else if (matches(*argv, "iif") == 0) {
535 } else if (matches(*argv, "oif") == 0 ||
536 strcmp(*argv, "dev") == 0) {
539 } else if (matches(*argv, "notify") == 0) {
540 req.r.rtm_flags |= RTM_F_NOTIFY;
541 } else if (matches(*argv, "connected") == 0) {
545 if (strcmp(*argv, "to") == 0) {
548 get_prefix(&addr, *argv, req.r.rtm_family);
549 if (req.r.rtm_family == AF_UNSPEC)
550 req.r.rtm_family = addr.family;
552 addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
553 req.r.rtm_dst_len = addr.bitlen;
558 if (req.r.rtm_dst_len == 0) {
559 fprintf(stderr, "need at least destination address\n");
563 if (rtnl_open(&rth, 0) < 0)
572 if ((idx = ll_name_to_index(idev)) == 0) {
573 fprintf(stderr, "Cannot find device \"%s\"\n", idev);
576 addattr32(&req.n, sizeof(req), RTA_IIF, idx);
579 if ((idx = ll_name_to_index(odev)) == 0) {
580 fprintf(stderr, "Cannot find device \"%s\"\n", odev);
583 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
587 if (req.r.rtm_family == AF_UNSPEC)
588 req.r.rtm_family = AF_INET;
590 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0)
593 if (connected && !from_ok) {
594 struct rtmsg *r = NLMSG_DATA(&req.n);
595 int len = req.n.nlmsg_len;
596 struct rtattr * tb[RTA_MAX+1];
598 if (print_route(NULL, &req.n, (void*)stdout) < 0) {
599 fprintf(stderr, "An error :-)\n");
603 if (req.n.nlmsg_type != RTM_NEWROUTE) {
604 fprintf(stderr, "Not a route?\n");
607 len -= NLMSG_LENGTH(sizeof(*r));
609 fprintf(stderr, "Wrong len %d\n", len);
613 memset(tb, 0, sizeof(tb));
614 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
616 if (tb[RTA_PREFSRC]) {
617 tb[RTA_PREFSRC]->rta_type = RTA_SRC;
618 r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
619 } else if (!tb[RTA_SRC]) {
620 fprintf(stderr, "Failed to connect the route\n");
623 if (!odev && tb[RTA_OIF])
624 tb[RTA_OIF]->rta_type = 0;
626 tb[RTA_GATEWAY]->rta_type = 0;
627 if (!idev && tb[RTA_IIF])
628 tb[RTA_IIF]->rta_type = 0;
629 req.n.nlmsg_flags = NLM_F_REQUEST;
630 req.n.nlmsg_type = RTM_GETROUTE;
632 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0)
636 if (print_route(NULL, &req.n, (void*)stdout) < 0) {
637 fprintf(stderr, "An error :-)\n");
644 void iproute_reset_filter()
646 memset(&filter, 0, sizeof(filter));
647 filter.mdst.bitlen = -1;
648 filter.msrc.bitlen = -1;
651 int do_iproute(int argc, char **argv)
654 return iproute_list(0, NULL);
656 if (matches(*argv, "add") == 0)
657 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL,
659 if (matches(*argv, "change") == 0 || strcmp(*argv, "chg") == 0)
660 return iproute_modify(RTM_NEWROUTE, NLM_F_REPLACE,
662 if (matches(*argv, "replace") == 0)
663 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE,
665 if (matches(*argv, "prepend") == 0)
666 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE,
668 if (matches(*argv, "append") == 0)
669 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_APPEND,
671 if (matches(*argv, "test") == 0)
672 return iproute_modify(RTM_NEWROUTE, NLM_F_EXCL,
674 if (matches(*argv, "delete") == 0)
675 return iproute_modify(RTM_DELROUTE, 0,
677 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
678 || matches(*argv, "lst") == 0)
679 return iproute_list(argc-1, argv+1);
680 if (matches(*argv, "get") == 0)
681 return iproute_get(argc-1, argv+1);
682 fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);