blob: 114fb6c9036dc8e6173fb48706108ff1712819bf [file] [log] [blame]
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00001/*
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
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000018#include <sys/socket.h>
Glenn L McGrath275be872002-12-16 07:37:21 +000019
20#include <stdlib.h>
21#include <string.h>
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000022
23#include "rt_names.h"
24#include "utils.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000025
Glenn L McGrath275be872002-12-16 07:37:21 +000026#include "libbb.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000027
28#ifndef RTAX_RTTVAR
29#define RTAX_RTTVAR RTAX_HOPS
30#endif
31
32
33static struct
34{
35 int tb;
36 int flushp;
37 int flushe;
38 struct rtnl_handle *rth;
39 int protocol, protocolmask;
40 int scope, scopemask;
41 int type, typemask;
42 int tos, tosmask;
43 int iif, iifmask;
44 int oif, oifmask;
45 int realm, realmmask;
46 inet_prefix rprefsrc;
47 inet_prefix rvia;
48 inet_prefix rdst;
49 inet_prefix mdst;
50 inet_prefix rsrc;
51 inet_prefix msrc;
52} filter;
53
Glenn L McGrathc82f2322002-12-02 00:35:23 +000054static int print_route(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000055{
56 FILE *fp = (FILE*)arg;
57 struct rtmsg *r = NLMSG_DATA(n);
58 int len = n->nlmsg_len;
59 struct rtattr * tb[RTA_MAX+1];
60 char abuf[256];
61 int host_len = -1;
62 SPRINT_BUF(b1);
63
64
65 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
66 fprintf(stderr, "Not a route: %08x %08x %08x\n",
67 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
68 return 0;
69 }
70 len -= NLMSG_LENGTH(sizeof(*r));
71 if (len < 0) {
Glenn L McGrath9048ae52002-11-28 10:56:38 +000072 error_msg("wrong nlmsg len %d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000073 return -1;
74 }
75
76 if (r->rtm_family == AF_INET6)
77 host_len = 128;
78 else if (r->rtm_family == AF_INET)
79 host_len = 32;
80
81 if (r->rtm_family == AF_INET6) {
82 if (filter.tb) {
83 if (filter.tb < 0) {
Glenn L McGrath16528552002-11-28 11:17:19 +000084 if (!(r->rtm_flags&RTM_F_CLONED)) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000085 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +000086 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000087 } else {
Glenn L McGrath16528552002-11-28 11:17:19 +000088 if (r->rtm_flags&RTM_F_CLONED) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000089 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +000090 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000091 if (filter.tb == RT_TABLE_LOCAL) {
Glenn L McGrath16528552002-11-28 11:17:19 +000092 if (r->rtm_type != RTN_LOCAL) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000093 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +000094 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000095 } else if (filter.tb == RT_TABLE_MAIN) {
Glenn L McGrath16528552002-11-28 11:17:19 +000096 if (r->rtm_type == RTN_LOCAL) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000097 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +000098 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000099 } else {
100 return 0;
101 }
102 }
103 }
104 } else {
Glenn L McGrath16528552002-11-28 11:17:19 +0000105 if (filter.tb > 0 && filter.tb != r->rtm_table) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000106 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000107 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000108 }
109 if (filter.rdst.family &&
Glenn L McGrath16528552002-11-28 11:17:19 +0000110 (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000111 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000112 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000113 if (filter.mdst.family &&
114 (r->rtm_family != filter.mdst.family ||
Glenn L McGrath16528552002-11-28 11:17:19 +0000115 (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000116 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000117 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000118 if (filter.rsrc.family &&
Glenn L McGrath16528552002-11-28 11:17:19 +0000119 (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000120 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000121 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000122 if (filter.msrc.family &&
123 (r->rtm_family != filter.msrc.family ||
Glenn L McGrath16528552002-11-28 11:17:19 +0000124 (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000125 return 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000126 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000127
128 memset(tb, 0, sizeof(tb));
129 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
130
Glenn L McGrath16528552002-11-28 11:17:19 +0000131 if (n->nlmsg_type == RTM_DELROUTE) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000132 fprintf(fp, "Deleted ");
Glenn L McGrath16528552002-11-28 11:17:19 +0000133 }
134 if (r->rtm_type != RTN_UNICAST && !filter.type) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000135 fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
Glenn L McGrath16528552002-11-28 11:17:19 +0000136 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000137
138 if (tb[RTA_DST]) {
139 if (r->rtm_dst_len != host_len) {
140 fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family,
141 RTA_PAYLOAD(tb[RTA_DST]),
142 RTA_DATA(tb[RTA_DST]),
143 abuf, sizeof(abuf)),
144 r->rtm_dst_len
145 );
146 } else {
147 fprintf(fp, "%s ", format_host(r->rtm_family,
148 RTA_PAYLOAD(tb[RTA_DST]),
149 RTA_DATA(tb[RTA_DST]),
150 abuf, sizeof(abuf))
151 );
152 }
153 } else if (r->rtm_dst_len) {
154 fprintf(fp, "0/%d ", r->rtm_dst_len);
155 } else {
156 fprintf(fp, "default ");
157 }
158 if (tb[RTA_SRC]) {
159 if (r->rtm_src_len != host_len) {
160 fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family,
161 RTA_PAYLOAD(tb[RTA_SRC]),
162 RTA_DATA(tb[RTA_SRC]),
163 abuf, sizeof(abuf)),
164 r->rtm_src_len
165 );
166 } else {
167 fprintf(fp, "from %s ", format_host(r->rtm_family,
168 RTA_PAYLOAD(tb[RTA_SRC]),
169 RTA_DATA(tb[RTA_SRC]),
170 abuf, sizeof(abuf))
171 );
172 }
173 } else if (r->rtm_src_len) {
174 fprintf(fp, "from 0/%u ", r->rtm_src_len);
175 }
176 if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
177 fprintf(fp, "via %s ",
178 format_host(r->rtm_family,
179 RTA_PAYLOAD(tb[RTA_GATEWAY]),
180 RTA_DATA(tb[RTA_GATEWAY]),
181 abuf, sizeof(abuf)));
182 }
Glenn L McGrath16528552002-11-28 11:17:19 +0000183 if (tb[RTA_OIF] && filter.oifmask != -1) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000184 fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
Glenn L McGrath16528552002-11-28 11:17:19 +0000185 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000186
187 if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
188 /* Do not use format_host(). It is our local addr
189 and symbolic name will not be useful.
190 */
191 fprintf(fp, " src %s ",
192 rt_addr_n2a(r->rtm_family,
193 RTA_PAYLOAD(tb[RTA_PREFSRC]),
194 RTA_DATA(tb[RTA_PREFSRC]),
195 abuf, sizeof(abuf)));
196 }
Glenn L McGrath16528552002-11-28 11:17:19 +0000197 if (tb[RTA_PRIORITY]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000198 fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY]));
Glenn L McGrath16528552002-11-28 11:17:19 +0000199 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000200 if (r->rtm_family == AF_INET6) {
201 struct rta_cacheinfo *ci = NULL;
Glenn L McGrath16528552002-11-28 11:17:19 +0000202 if (tb[RTA_CACHEINFO]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000203 ci = RTA_DATA(tb[RTA_CACHEINFO]);
Glenn L McGrath16528552002-11-28 11:17:19 +0000204 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000205 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
206 static int hz;
Glenn L McGrath16528552002-11-28 11:17:19 +0000207 if (!hz) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000208 hz = get_hz();
Glenn L McGrath16528552002-11-28 11:17:19 +0000209 }
210 if (r->rtm_flags & RTM_F_CLONED) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000211 fprintf(fp, "%s cache ", _SL_);
Glenn L McGrath16528552002-11-28 11:17:19 +0000212 }
213 if (ci->rta_expires) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000214 fprintf(fp, " expires %dsec", ci->rta_expires/hz);
Glenn L McGrath16528552002-11-28 11:17:19 +0000215 }
216 if (ci->rta_error != 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000217 fprintf(fp, " error %d", ci->rta_error);
Glenn L McGrath16528552002-11-28 11:17:19 +0000218 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000219 } else if (ci) {
220 if (ci->rta_error != 0)
221 fprintf(fp, " error %d", ci->rta_error);
222 }
223 }
224 if (tb[RTA_IIF] && filter.iifmask != -1) {
225 fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
226 }
227 fprintf(fp, "\n");
228 fflush(fp);
229 return 0;
230}
231
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000232static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000233{
234 struct rtnl_handle rth;
235 struct {
236 struct nlmsghdr n;
237 struct rtmsg r;
238 char buf[1024];
239 } req;
240 char mxbuf[256];
241 struct rtattr * mxrta = (void*)mxbuf;
242 unsigned mxlock = 0;
243 char *d = NULL;
244 int gw_ok = 0;
245 int dst_ok = 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000246 int proto_ok = 0;
247 int type_ok = 0;
248
249 memset(&req, 0, sizeof(req));
250
251 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
252 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
253 req.n.nlmsg_type = cmd;
254 req.r.rtm_family = preferred_family;
255 req.r.rtm_table = RT_TABLE_MAIN;
256 req.r.rtm_scope = RT_SCOPE_NOWHERE;
257
258 if (cmd != RTM_DELROUTE) {
259 req.r.rtm_protocol = RTPROT_BOOT;
260 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
261 req.r.rtm_type = RTN_UNICAST;
262 }
263
264 mxrta->rta_type = RTA_METRICS;
265 mxrta->rta_len = RTA_LENGTH(0);
266
267 while (argc > 0) {
268 if (strcmp(*argv, "src") == 0) {
269 inet_prefix addr;
270 NEXT_ARG();
271 get_addr(&addr, *argv, req.r.rtm_family);
Glenn L McGrath16528552002-11-28 11:17:19 +0000272 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000273 req.r.rtm_family = addr.family;
Glenn L McGrath16528552002-11-28 11:17:19 +0000274 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000275 addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
276 } else if (strcmp(*argv, "via") == 0) {
277 inet_prefix addr;
278 gw_ok = 1;
279 NEXT_ARG();
280 get_addr(&addr, *argv, req.r.rtm_family);
Glenn L McGrath16528552002-11-28 11:17:19 +0000281 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000282 req.r.rtm_family = addr.family;
Glenn L McGrath16528552002-11-28 11:17:19 +0000283 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000284 addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
285 } else if (strcmp(*argv, "mtu") == 0) {
286 unsigned mtu;
287 NEXT_ARG();
288 if (strcmp(*argv, "lock") == 0) {
289 mxlock |= (1<<RTAX_MTU);
290 NEXT_ARG();
291 }
Glenn L McGrath16528552002-11-28 11:17:19 +0000292 if (get_unsigned(&mtu, *argv, 0)) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000293 invarg("\"mtu\" value is invalid\n", *argv);
Glenn L McGrath16528552002-11-28 11:17:19 +0000294 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000295 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
296 } else if (matches(*argv, "protocol") == 0) {
297 int prot;
298 NEXT_ARG();
299 if (rtnl_rtprot_a2n(&prot, *argv))
300 invarg("\"protocol\" value is invalid\n", *argv);
301 req.r.rtm_protocol = prot;
302 proto_ok =1;
303 } else if (strcmp(*argv, "dev") == 0 ||
304 strcmp(*argv, "oif") == 0) {
305 NEXT_ARG();
306 d = *argv;
307 } else {
308 int type;
309 inet_prefix dst;
310
311 if (strcmp(*argv, "to") == 0) {
312 NEXT_ARG();
313 }
314 if ((**argv < '0' || **argv > '9') &&
315 rtnl_rtntype_a2n(&type, *argv) == 0) {
316 NEXT_ARG();
317 req.r.rtm_type = type;
318 type_ok = 1;
319 }
320
Glenn L McGrath16528552002-11-28 11:17:19 +0000321 if (dst_ok) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000322 duparg2("to", *argv);
Glenn L McGrath16528552002-11-28 11:17:19 +0000323 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000324 get_prefix(&dst, *argv, req.r.rtm_family);
Glenn L McGrath16528552002-11-28 11:17:19 +0000325 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000326 req.r.rtm_family = dst.family;
Glenn L McGrath16528552002-11-28 11:17:19 +0000327 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000328 req.r.rtm_dst_len = dst.bitlen;
329 dst_ok = 1;
Glenn L McGrath16528552002-11-28 11:17:19 +0000330 if (dst.bytelen) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000331 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
Glenn L McGrath16528552002-11-28 11:17:19 +0000332 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000333 }
334 argc--; argv++;
335 }
336
Glenn L McGrath16528552002-11-28 11:17:19 +0000337 if (rtnl_open(&rth, 0) < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000338 exit(1);
Glenn L McGrath16528552002-11-28 11:17:19 +0000339 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000340
Eric Andersen5780adb2002-11-15 09:12:47 +0000341 if (d) {
342 int idx;
343
344 ll_init_map(&rth);
345
346 if (d) {
347 if ((idx = ll_name_to_index(d)) == 0) {
Glenn L McGrath9048ae52002-11-28 10:56:38 +0000348 error_msg("Cannot find device \"%s\"", d);
Eric Andersen5780adb2002-11-15 09:12:47 +0000349 return -1;
350 }
351 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
352 }
353 }
354
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000355 if (mxrta->rta_len > RTA_LENGTH(0)) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000356 if (mxlock) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000357 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
Glenn L McGrath16528552002-11-28 11:17:19 +0000358 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000359 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
360 }
361
Glenn L McGrath16528552002-11-28 11:17:19 +0000362 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000363 req.r.rtm_family = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +0000364 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000365
Glenn L McGrath16528552002-11-28 11:17:19 +0000366 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000367 exit(2);
Glenn L McGrath16528552002-11-28 11:17:19 +0000368 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000369
370 return 0;
371}
372
373static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
374{
375 struct {
376 struct nlmsghdr nlh;
377 struct rtmsg rtm;
378 } req;
379 struct sockaddr_nl nladdr;
380
381 memset(&nladdr, 0, sizeof(nladdr));
382 memset(&req, 0, sizeof(req));
383 nladdr.nl_family = AF_NETLINK;
384
385 req.nlh.nlmsg_len = sizeof(req);
386 req.nlh.nlmsg_type = RTM_GETROUTE;
387 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST;
388 req.nlh.nlmsg_pid = 0;
389 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
390 req.rtm.rtm_family = family;
391 req.rtm.rtm_flags |= RTM_F_CLONED;
392
393 return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
394}
395
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000396static void iproute_reset_filter(void)
397{
398 memset(&filter, 0, sizeof(filter));
399 filter.mdst.bitlen = -1;
400 filter.msrc.bitlen = -1;
401}
402
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000403static int iproute_list(int argc, char **argv)
404{
405 int do_ipv6 = preferred_family;
406 struct rtnl_handle rth;
407 char *id = NULL;
408 char *od = NULL;
409
410 iproute_reset_filter();
411 filter.tb = RT_TABLE_MAIN;
412
413 while (argc > 0) {
414 if (matches(*argv, "protocol") == 0) {
415 int prot = 0;
416 NEXT_ARG();
417 filter.protocolmask = -1;
418 if (rtnl_rtprot_a2n(&prot, *argv)) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000419 if (strcmp(*argv, "all") != 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000420 invarg("invalid \"protocol\"\n", *argv);
Glenn L McGrath16528552002-11-28 11:17:19 +0000421 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000422 prot = 0;
423 filter.protocolmask = 0;
424 }
425 filter.protocol = prot;
426 } else if (strcmp(*argv, "dev") == 0 ||
427 strcmp(*argv, "oif") == 0) {
428 NEXT_ARG();
429 od = *argv;
430 } else if (strcmp(*argv, "iif") == 0) {
431 NEXT_ARG();
432 id = *argv;
433 } else if (matches(*argv, "from") == 0) {
434 NEXT_ARG();
435 if (matches(*argv, "root") == 0) {
436 NEXT_ARG();
437 get_prefix(&filter.rsrc, *argv, do_ipv6);
438 } else if (matches(*argv, "match") == 0) {
439 NEXT_ARG();
440 get_prefix(&filter.msrc, *argv, do_ipv6);
441 } else {
442 if (matches(*argv, "exact") == 0) {
443 NEXT_ARG();
444 }
445 get_prefix(&filter.msrc, *argv, do_ipv6);
446 filter.rsrc = filter.msrc;
447 }
448 } else {
449 if (matches(*argv, "to") == 0) {
450 NEXT_ARG();
451 }
452 if (matches(*argv, "root") == 0) {
453 NEXT_ARG();
454 get_prefix(&filter.rdst, *argv, do_ipv6);
455 } else if (matches(*argv, "match") == 0) {
456 NEXT_ARG();
457 get_prefix(&filter.mdst, *argv, do_ipv6);
458 } else {
459 if (matches(*argv, "exact") == 0) {
460 NEXT_ARG();
461 }
462 get_prefix(&filter.mdst, *argv, do_ipv6);
463 filter.rdst = filter.mdst;
464 }
465 }
466 argc--; argv++;
467 }
468
Glenn L McGrath16528552002-11-28 11:17:19 +0000469 if (do_ipv6 == AF_UNSPEC && filter.tb) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000470 do_ipv6 = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +0000471 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000472
Glenn L McGrath16528552002-11-28 11:17:19 +0000473 if (rtnl_open(&rth, 0) < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000474 exit(1);
Glenn L McGrath16528552002-11-28 11:17:19 +0000475 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000476
477 ll_init_map(&rth);
478
479 if (id || od) {
480 int idx;
481
482 if (id) {
483 if ((idx = ll_name_to_index(id)) == 0) {
Glenn L McGrath9048ae52002-11-28 10:56:38 +0000484 error_msg("Cannot find device \"%s\"", id);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000485 return -1;
486 }
487 filter.iif = idx;
488 filter.iifmask = -1;
489 }
490 if (od) {
491 if ((idx = ll_name_to_index(od)) == 0) {
Glenn L McGrath9048ae52002-11-28 10:56:38 +0000492 error_msg("Cannot find device \"%s\"", od);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000493 }
494 filter.oif = idx;
495 filter.oifmask = -1;
496 }
497 }
498
499 if (filter.tb != -1) {
500 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
Glenn L McGrath9048ae52002-11-28 10:56:38 +0000501 perror_msg_and_die("Cannot send dump request");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000502 }
503 } else {
504 if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
Glenn L McGrath9048ae52002-11-28 10:56:38 +0000505 perror_msg_and_die("Cannot send dump request");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000506 }
507 }
508
509 if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
Glenn L McGrathe3e2a7b2002-11-28 12:01:25 +0000510 error_msg_and_die("Dump terminated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000511 }
512
513 exit(0);
514}
515
516
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000517static int iproute_get(int argc, char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000518{
519 struct rtnl_handle rth;
520 struct {
521 struct nlmsghdr n;
522 struct rtmsg r;
523 char buf[1024];
524 } req;
525 char *idev = NULL;
526 char *odev = NULL;
527 int connected = 0;
528 int from_ok = 0;
Glenn L McGrath18eae002002-12-02 00:54:10 +0000529 const char *options[] = { "from", "iif", "oif", "dev", "notify", "connected", "to", 0 };
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000530
531 memset(&req, 0, sizeof(req));
532
533 iproute_reset_filter();
534
535 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
536 req.n.nlmsg_flags = NLM_F_REQUEST;
537 req.n.nlmsg_type = RTM_GETROUTE;
538 req.r.rtm_family = preferred_family;
539 req.r.rtm_table = 0;
540 req.r.rtm_protocol = 0;
541 req.r.rtm_scope = 0;
542 req.r.rtm_type = 0;
543 req.r.rtm_src_len = 0;
544 req.r.rtm_dst_len = 0;
545 req.r.rtm_tos = 0;
546
547 while (argc > 0) {
Glenn L McGrath18eae002002-12-02 00:54:10 +0000548 switch (compare_string_array(options, *argv)) {
549 case 0: /* from */
550 {
551 inet_prefix addr;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000552 NEXT_ARG();
Glenn L McGrath18eae002002-12-02 00:54:10 +0000553 from_ok = 1;
554 get_prefix(&addr, *argv, req.r.rtm_family);
555 if (req.r.rtm_family == AF_UNSPEC) {
556 req.r.rtm_family = addr.family;
557 }
558 if (addr.bytelen) {
559 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
560 }
561 req.r.rtm_src_len = addr.bitlen;
562 break;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000563 }
Glenn L McGrath18eae002002-12-02 00:54:10 +0000564 case 1: /* iif */
565 NEXT_ARG();
566 idev = *argv;
567 break;
568 case 2: /* oif */
569 case 3: /* dev */
570 NEXT_ARG();
571 odev = *argv;
572 break;
573 case 4: /* notify */
574 req.r.rtm_flags |= RTM_F_NOTIFY;
575 break;
576 case 5: /* connected */
577 connected = 1;
578 break;
579 case 6: /* to */
580 NEXT_ARG();
581 default:
582 {
583 inet_prefix addr;
584 get_prefix(&addr, *argv, req.r.rtm_family);
585 if (req.r.rtm_family == AF_UNSPEC) {
586 req.r.rtm_family = addr.family;
587 }
588 if (addr.bytelen) {
589 addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
590 }
591 req.r.rtm_dst_len = addr.bitlen;
592 }
593 argc--; argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000594 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000595 }
596
597 if (req.r.rtm_dst_len == 0) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000598 error_msg_and_die("need at least destination address");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000599 }
600
601 if (rtnl_open(&rth, 0) < 0)
602 exit(1);
603
604 ll_init_map(&rth);
605
606 if (idev || odev) {
607 int idx;
608
609 if (idev) {
610 if ((idx = ll_name_to_index(idev)) == 0) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000611 error_msg("Cannot find device \"%s\"", idev);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000612 return -1;
613 }
614 addattr32(&req.n, sizeof(req), RTA_IIF, idx);
615 }
616 if (odev) {
617 if ((idx = ll_name_to_index(odev)) == 0) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000618 error_msg("Cannot find device \"%s\"", odev);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000619 return -1;
620 }
621 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
622 }
623 }
624
Glenn L McGrath16528552002-11-28 11:17:19 +0000625 if (req.r.rtm_family == AF_UNSPEC) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000626 req.r.rtm_family = AF_INET;
Glenn L McGrath16528552002-11-28 11:17:19 +0000627 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000628
Glenn L McGrath16528552002-11-28 11:17:19 +0000629 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000630 exit(2);
Glenn L McGrath16528552002-11-28 11:17:19 +0000631 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000632
633 if (connected && !from_ok) {
634 struct rtmsg *r = NLMSG_DATA(&req.n);
635 int len = req.n.nlmsg_len;
636 struct rtattr * tb[RTA_MAX+1];
637
638 if (print_route(NULL, &req.n, (void*)stdout) < 0) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000639 error_msg_and_die("An error :-)");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000640 }
641
642 if (req.n.nlmsg_type != RTM_NEWROUTE) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000643 error_msg("Not a route?");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000644 return -1;
645 }
646 len -= NLMSG_LENGTH(sizeof(*r));
647 if (len < 0) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000648 error_msg("Wrong len %d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000649 return -1;
650 }
651
652 memset(tb, 0, sizeof(tb));
653 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
654
655 if (tb[RTA_PREFSRC]) {
656 tb[RTA_PREFSRC]->rta_type = RTA_SRC;
657 r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
658 } else if (!tb[RTA_SRC]) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000659 error_msg("Failed to connect the route");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000660 return -1;
661 }
Glenn L McGrath16528552002-11-28 11:17:19 +0000662 if (!odev && tb[RTA_OIF]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000663 tb[RTA_OIF]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000664 }
665 if (tb[RTA_GATEWAY]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000666 tb[RTA_GATEWAY]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000667 }
668 if (!idev && tb[RTA_IIF]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000669 tb[RTA_IIF]->rta_type = 0;
Glenn L McGrath16528552002-11-28 11:17:19 +0000670 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000671 req.n.nlmsg_flags = NLM_F_REQUEST;
672 req.n.nlmsg_type = RTM_GETROUTE;
673
Glenn L McGrath16528552002-11-28 11:17:19 +0000674 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000675 exit(2);
Glenn L McGrath16528552002-11-28 11:17:19 +0000676 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000677 }
678
679 if (print_route(NULL, &req.n, (void*)stdout) < 0) {
Glenn L McGrath16528552002-11-28 11:17:19 +0000680 error_msg_and_die("An error :-)");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000681 }
682
683 exit(0);
684}
685
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000686int do_iproute(int argc, char **argv)
687{
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000688 const char *ip_route_commands[] = { "add", "append", "change", "chg",
689 "delete", "get", "list", "show", "prepend", "replace", "test", 0 };
690 unsigned short command_num = 6;
691 unsigned int flags = 0;
692 int cmd = RTM_NEWROUTE;
693
694 if (*argv) {
695 command_num = compare_string_array(ip_route_commands, *argv);
Glenn L McGrath16528552002-11-28 11:17:19 +0000696 }
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000697 switch(command_num) {
698 case 0: /* add*/
699 flags = NLM_F_CREATE|NLM_F_EXCL;
700 break;
701 case 1: /* append */
702 flags = NLM_F_CREATE|NLM_F_APPEND;
703 break;
704 case 2: /* change */
705 case 3: /* chg */
706 flags = NLM_F_REPLACE;
707 break;
708 case 4: /* delete */
709 cmd = RTM_DELROUTE;
710 break;
711 case 5: /* get */
712 return iproute_get(argc-1, argv+1);
713 case 6: /* list */
714 case 7: /* show */
715 return iproute_list(argc-1, argv+1);
716 case 8: /* prepend */
717 flags = NLM_F_CREATE;
718 case 9: /* replace */
719 flags = NLM_F_CREATE|NLM_F_REPLACE;
720 case 10: /* test */
721 flags = NLM_F_EXCL;
722 default:
723 error_msg_and_die("Unknown command %s", *argv);
Glenn L McGrath16528552002-11-28 11:17:19 +0000724 }
Glenn L McGrathc82f2322002-12-02 00:35:23 +0000725
726 return iproute_modify(cmd, flags, argc-1, argv+1);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000727}
728