diff options
author | Glenn L McGrath <bug1@ihug.co.nz> | 2002-11-10 01:33:55 +0000 |
---|---|---|
committer | Glenn L McGrath <bug1@ihug.co.nz> | 2002-11-10 01:33:55 +0000 |
commit | 9a2d27249cc2235f7e001a9ea8d4605406bc5f38 (patch) | |
tree | b7b2917c3cf46ac3fa25df5f9a27a9a9fbfb0398 /networking/libiproute/iproute.c | |
parent | 021fa7db9139bff3b4bf404dfd7d2b1541ed71f8 (diff) | |
download | busybox-w32-9a2d27249cc2235f7e001a9ea8d4605406bc5f38.tar.gz busybox-w32-9a2d27249cc2235f7e001a9ea8d4605406bc5f38.tar.bz2 busybox-w32-9a2d27249cc2235f7e001a9ea8d4605406bc5f38.zip |
IP applet by Bastian Blank <waldi@debian.org>
Diffstat (limited to 'networking/libiproute/iproute.c')
-rw-r--r-- | networking/libiproute/iproute.c | 674 |
1 files changed, 674 insertions, 0 deletions
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c new file mode 100644 index 000000000..e38abcd01 --- /dev/null +++ b/networking/libiproute/iproute.c | |||
@@ -0,0 +1,674 @@ | |||
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 | #include "ip_common.h" | ||
34 | |||
35 | #include "busybox.h" | ||
36 | |||
37 | #ifndef RTAX_RTTVAR | ||
38 | #define RTAX_RTTVAR RTAX_HOPS | ||
39 | #endif | ||
40 | |||
41 | |||
42 | static struct | ||
43 | { | ||
44 | int tb; | ||
45 | int flushp; | ||
46 | int flushe; | ||
47 | struct rtnl_handle *rth; | ||
48 | int protocol, protocolmask; | ||
49 | int scope, scopemask; | ||
50 | int type, typemask; | ||
51 | int tos, tosmask; | ||
52 | int iif, iifmask; | ||
53 | int oif, oifmask; | ||
54 | int realm, realmmask; | ||
55 | inet_prefix rprefsrc; | ||
56 | inet_prefix rvia; | ||
57 | inet_prefix rdst; | ||
58 | inet_prefix mdst; | ||
59 | inet_prefix rsrc; | ||
60 | inet_prefix msrc; | ||
61 | } filter; | ||
62 | |||
63 | int print_route(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) | ||
64 | { | ||
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]; | ||
69 | char abuf[256]; | ||
70 | int host_len = -1; | ||
71 | SPRINT_BUF(b1); | ||
72 | |||
73 | |||
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); | ||
77 | return 0; | ||
78 | } | ||
79 | len -= NLMSG_LENGTH(sizeof(*r)); | ||
80 | if (len < 0) { | ||
81 | fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); | ||
82 | return -1; | ||
83 | } | ||
84 | |||
85 | if (r->rtm_family == AF_INET6) | ||
86 | host_len = 128; | ||
87 | else if (r->rtm_family == AF_INET) | ||
88 | host_len = 32; | ||
89 | |||
90 | if (r->rtm_family == AF_INET6) { | ||
91 | if (filter.tb) { | ||
92 | if (filter.tb < 0) { | ||
93 | if (!(r->rtm_flags&RTM_F_CLONED)) | ||
94 | return 0; | ||
95 | } else { | ||
96 | if (r->rtm_flags&RTM_F_CLONED) | ||
97 | return 0; | ||
98 | if (filter.tb == RT_TABLE_LOCAL) { | ||
99 | if (r->rtm_type != RTN_LOCAL) | ||
100 | return 0; | ||
101 | } else if (filter.tb == RT_TABLE_MAIN) { | ||
102 | if (r->rtm_type == RTN_LOCAL) | ||
103 | return 0; | ||
104 | } else { | ||
105 | return 0; | ||
106 | } | ||
107 | } | ||
108 | } | ||
109 | } else { | ||
110 | if (filter.tb > 0 && filter.tb != r->rtm_table) | ||
111 | return 0; | ||
112 | } | ||
113 | if (filter.rdst.family && | ||
114 | (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) | ||
115 | return 0; | ||
116 | if (filter.mdst.family && | ||
117 | (r->rtm_family != filter.mdst.family || | ||
118 | (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) | ||
119 | return 0; | ||
120 | if (filter.rsrc.family && | ||
121 | (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) | ||
122 | return 0; | ||
123 | if (filter.msrc.family && | ||
124 | (r->rtm_family != filter.msrc.family || | ||
125 | (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) | ||
126 | return 0; | ||
127 | |||
128 | memset(tb, 0, sizeof(tb)); | ||
129 | parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); | ||
130 | |||
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))); | ||
135 | |||
136 | if (tb[RTA_DST]) { | ||
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]), | ||
141 | abuf, sizeof(abuf)), | ||
142 | r->rtm_dst_len | ||
143 | ); | ||
144 | } else { | ||
145 | fprintf(fp, "%s ", format_host(r->rtm_family, | ||
146 | RTA_PAYLOAD(tb[RTA_DST]), | ||
147 | RTA_DATA(tb[RTA_DST]), | ||
148 | abuf, sizeof(abuf)) | ||
149 | ); | ||
150 | } | ||
151 | } else if (r->rtm_dst_len) { | ||
152 | fprintf(fp, "0/%d ", r->rtm_dst_len); | ||
153 | } else { | ||
154 | fprintf(fp, "default "); | ||
155 | } | ||
156 | if (tb[RTA_SRC]) { | ||
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]), | ||
161 | abuf, sizeof(abuf)), | ||
162 | r->rtm_src_len | ||
163 | ); | ||
164 | } else { | ||
165 | fprintf(fp, "from %s ", format_host(r->rtm_family, | ||
166 | RTA_PAYLOAD(tb[RTA_SRC]), | ||
167 | RTA_DATA(tb[RTA_SRC]), | ||
168 | abuf, sizeof(abuf)) | ||
169 | ); | ||
170 | } | ||
171 | } else if (r->rtm_src_len) { | ||
172 | fprintf(fp, "from 0/%u ", r->rtm_src_len); | ||
173 | } | ||
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))); | ||
180 | } | ||
181 | if (tb[RTA_OIF] && filter.oifmask != -1) | ||
182 | fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); | ||
183 | |||
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. | ||
187 | */ | ||
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))); | ||
193 | } | ||
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)) { | ||
201 | static int hz; | ||
202 | if (!hz) | ||
203 | hz = get_hz(); | ||
204 | if (r->rtm_flags & RTM_F_CLONED) | ||
205 | fprintf(fp, "%s cache ", _SL_); | ||
206 | if (ci->rta_expires) | ||
207 | fprintf(fp, " expires %dsec", ci->rta_expires/hz); | ||
208 | if (ci->rta_error != 0) | ||
209 | fprintf(fp, " error %d", ci->rta_error); | ||
210 | } else if (ci) { | ||
211 | if (ci->rta_error != 0) | ||
212 | fprintf(fp, " error %d", ci->rta_error); | ||
213 | } | ||
214 | } | ||
215 | if (tb[RTA_IIF] && filter.iifmask != -1) { | ||
216 | fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF]))); | ||
217 | } | ||
218 | fprintf(fp, "\n"); | ||
219 | fflush(fp); | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | int iproute_modify(int cmd, unsigned flags, int argc, char **argv) | ||
224 | { | ||
225 | struct rtnl_handle rth; | ||
226 | struct { | ||
227 | struct nlmsghdr n; | ||
228 | struct rtmsg r; | ||
229 | char buf[1024]; | ||
230 | } req; | ||
231 | char mxbuf[256]; | ||
232 | struct rtattr * mxrta = (void*)mxbuf; | ||
233 | unsigned mxlock = 0; | ||
234 | char *d = NULL; | ||
235 | int gw_ok = 0; | ||
236 | int dst_ok = 0; | ||
237 | //int nhs_ok = 0; | ||
238 | //int scope_ok = 0; | ||
239 | //int table_ok = 0; | ||
240 | int proto_ok = 0; | ||
241 | int type_ok = 0; | ||
242 | |||
243 | memset(&req, 0, sizeof(req)); | ||
244 | |||
245 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); | ||
246 | req.n.nlmsg_flags = NLM_F_REQUEST|flags; | ||
247 | req.n.nlmsg_type = cmd; | ||
248 | req.r.rtm_family = preferred_family; | ||
249 | req.r.rtm_table = RT_TABLE_MAIN; | ||
250 | req.r.rtm_scope = RT_SCOPE_NOWHERE; | ||
251 | |||
252 | if (cmd != RTM_DELROUTE) { | ||
253 | req.r.rtm_protocol = RTPROT_BOOT; | ||
254 | req.r.rtm_scope = RT_SCOPE_UNIVERSE; | ||
255 | req.r.rtm_type = RTN_UNICAST; | ||
256 | } | ||
257 | |||
258 | mxrta->rta_type = RTA_METRICS; | ||
259 | mxrta->rta_len = RTA_LENGTH(0); | ||
260 | |||
261 | while (argc > 0) { | ||
262 | if (strcmp(*argv, "src") == 0) { | ||
263 | inet_prefix addr; | ||
264 | NEXT_ARG(); | ||
265 | get_addr(&addr, *argv, req.r.rtm_family); | ||
266 | if (req.r.rtm_family == AF_UNSPEC) | ||
267 | req.r.rtm_family = addr.family; | ||
268 | addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen); | ||
269 | } else if (strcmp(*argv, "via") == 0) { | ||
270 | inet_prefix addr; | ||
271 | gw_ok = 1; | ||
272 | NEXT_ARG(); | ||
273 | get_addr(&addr, *argv, req.r.rtm_family); | ||
274 | if (req.r.rtm_family == AF_UNSPEC) | ||
275 | req.r.rtm_family = addr.family; | ||
276 | addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen); | ||
277 | } else if (strcmp(*argv, "mtu") == 0) { | ||
278 | unsigned mtu; | ||
279 | NEXT_ARG(); | ||
280 | if (strcmp(*argv, "lock") == 0) { | ||
281 | mxlock |= (1<<RTAX_MTU); | ||
282 | NEXT_ARG(); | ||
283 | } | ||
284 | if (get_unsigned(&mtu, *argv, 0)) | ||
285 | invarg("\"mtu\" value is invalid\n", *argv); | ||
286 | rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu); | ||
287 | } else if (matches(*argv, "protocol") == 0) { | ||
288 | int prot; | ||
289 | NEXT_ARG(); | ||
290 | if (rtnl_rtprot_a2n(&prot, *argv)) | ||
291 | invarg("\"protocol\" value is invalid\n", *argv); | ||
292 | req.r.rtm_protocol = prot; | ||
293 | proto_ok =1; | ||
294 | } else if (strcmp(*argv, "dev") == 0 || | ||
295 | strcmp(*argv, "oif") == 0) { | ||
296 | NEXT_ARG(); | ||
297 | d = *argv; | ||
298 | } else { | ||
299 | int type; | ||
300 | inet_prefix dst; | ||
301 | |||
302 | if (strcmp(*argv, "to") == 0) { | ||
303 | NEXT_ARG(); | ||
304 | } | ||
305 | if ((**argv < '0' || **argv > '9') && | ||
306 | rtnl_rtntype_a2n(&type, *argv) == 0) { | ||
307 | NEXT_ARG(); | ||
308 | req.r.rtm_type = type; | ||
309 | type_ok = 1; | ||
310 | } | ||
311 | |||
312 | if (dst_ok) | ||
313 | duparg2("to", *argv); | ||
314 | get_prefix(&dst, *argv, req.r.rtm_family); | ||
315 | if (req.r.rtm_family == AF_UNSPEC) | ||
316 | req.r.rtm_family = dst.family; | ||
317 | req.r.rtm_dst_len = dst.bitlen; | ||
318 | dst_ok = 1; | ||
319 | if (dst.bytelen) | ||
320 | addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen); | ||
321 | } | ||
322 | argc--; argv++; | ||
323 | } | ||
324 | |||
325 | if (rtnl_open(&rth, 0) < 0) | ||
326 | exit(1); | ||
327 | |||
328 | if (mxrta->rta_len > RTA_LENGTH(0)) { | ||
329 | if (mxlock) | ||
330 | rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock); | ||
331 | addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta)); | ||
332 | } | ||
333 | |||
334 | if (req.r.rtm_family == AF_UNSPEC) | ||
335 | req.r.rtm_family = AF_INET; | ||
336 | |||
337 | if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) | ||
338 | exit(2); | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int rtnl_rtcache_request(struct rtnl_handle *rth, int family) | ||
344 | { | ||
345 | struct { | ||
346 | struct nlmsghdr nlh; | ||
347 | struct rtmsg rtm; | ||
348 | } req; | ||
349 | struct sockaddr_nl nladdr; | ||
350 | |||
351 | memset(&nladdr, 0, sizeof(nladdr)); | ||
352 | memset(&req, 0, sizeof(req)); | ||
353 | nladdr.nl_family = AF_NETLINK; | ||
354 | |||
355 | req.nlh.nlmsg_len = sizeof(req); | ||
356 | req.nlh.nlmsg_type = RTM_GETROUTE; | ||
357 | req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST; | ||
358 | req.nlh.nlmsg_pid = 0; | ||
359 | req.nlh.nlmsg_seq = rth->dump = ++rth->seq; | ||
360 | req.rtm.rtm_family = family; | ||
361 | req.rtm.rtm_flags |= RTM_F_CLONED; | ||
362 | |||
363 | return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); | ||
364 | } | ||
365 | |||
366 | static int iproute_list(int argc, char **argv) | ||
367 | { | ||
368 | int do_ipv6 = preferred_family; | ||
369 | struct rtnl_handle rth; | ||
370 | char *id = NULL; | ||
371 | char *od = NULL; | ||
372 | |||
373 | iproute_reset_filter(); | ||
374 | filter.tb = RT_TABLE_MAIN; | ||
375 | |||
376 | while (argc > 0) { | ||
377 | if (matches(*argv, "protocol") == 0) { | ||
378 | int prot = 0; | ||
379 | NEXT_ARG(); | ||
380 | filter.protocolmask = -1; | ||
381 | if (rtnl_rtprot_a2n(&prot, *argv)) { | ||
382 | if (strcmp(*argv, "all") != 0) | ||
383 | invarg("invalid \"protocol\"\n", *argv); | ||
384 | prot = 0; | ||
385 | filter.protocolmask = 0; | ||
386 | } | ||
387 | filter.protocol = prot; | ||
388 | } else if (strcmp(*argv, "dev") == 0 || | ||
389 | strcmp(*argv, "oif") == 0) { | ||
390 | NEXT_ARG(); | ||
391 | od = *argv; | ||
392 | } else if (strcmp(*argv, "iif") == 0) { | ||
393 | NEXT_ARG(); | ||
394 | id = *argv; | ||
395 | } else if (matches(*argv, "from") == 0) { | ||
396 | NEXT_ARG(); | ||
397 | if (matches(*argv, "root") == 0) { | ||
398 | NEXT_ARG(); | ||
399 | get_prefix(&filter.rsrc, *argv, do_ipv6); | ||
400 | } else if (matches(*argv, "match") == 0) { | ||
401 | NEXT_ARG(); | ||
402 | get_prefix(&filter.msrc, *argv, do_ipv6); | ||
403 | } else { | ||
404 | if (matches(*argv, "exact") == 0) { | ||
405 | NEXT_ARG(); | ||
406 | } | ||
407 | get_prefix(&filter.msrc, *argv, do_ipv6); | ||
408 | filter.rsrc = filter.msrc; | ||
409 | } | ||
410 | } else { | ||
411 | if (matches(*argv, "to") == 0) { | ||
412 | NEXT_ARG(); | ||
413 | } | ||
414 | if (matches(*argv, "root") == 0) { | ||
415 | NEXT_ARG(); | ||
416 | get_prefix(&filter.rdst, *argv, do_ipv6); | ||
417 | } else if (matches(*argv, "match") == 0) { | ||
418 | NEXT_ARG(); | ||
419 | get_prefix(&filter.mdst, *argv, do_ipv6); | ||
420 | } else { | ||
421 | if (matches(*argv, "exact") == 0) { | ||
422 | NEXT_ARG(); | ||
423 | } | ||
424 | get_prefix(&filter.mdst, *argv, do_ipv6); | ||
425 | filter.rdst = filter.mdst; | ||
426 | } | ||
427 | } | ||
428 | argc--; argv++; | ||
429 | } | ||
430 | |||
431 | if (do_ipv6 == AF_UNSPEC && filter.tb) | ||
432 | do_ipv6 = AF_INET; | ||
433 | |||
434 | if (rtnl_open(&rth, 0) < 0) | ||
435 | exit(1); | ||
436 | |||
437 | ll_init_map(&rth); | ||
438 | |||
439 | if (id || od) { | ||
440 | int idx; | ||
441 | |||
442 | if (id) { | ||
443 | if ((idx = ll_name_to_index(id)) == 0) { | ||
444 | fprintf(stderr, "Cannot find device \"%s\"\n", id); | ||
445 | return -1; | ||
446 | } | ||
447 | filter.iif = idx; | ||
448 | filter.iifmask = -1; | ||
449 | } | ||
450 | if (od) { | ||
451 | if ((idx = ll_name_to_index(od)) == 0) { | ||
452 | fprintf(stderr, "Cannot find device \"%s\"\n", od); | ||
453 | return -1; | ||
454 | } | ||
455 | filter.oif = idx; | ||
456 | filter.oifmask = -1; | ||
457 | } | ||
458 | } | ||
459 | |||
460 | if (filter.tb != -1) { | ||
461 | if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { | ||
462 | perror("Cannot send dump request"); | ||
463 | exit(1); | ||
464 | } | ||
465 | } else { | ||
466 | if (rtnl_rtcache_request(&rth, do_ipv6) < 0) { | ||
467 | perror("Cannot send dump request"); | ||
468 | exit(1); | ||
469 | } | ||
470 | } | ||
471 | |||
472 | if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) { | ||
473 | fprintf(stderr, "Dump terminated\n"); | ||
474 | exit(1); | ||
475 | } | ||
476 | |||
477 | exit(0); | ||
478 | } | ||
479 | |||
480 | |||
481 | int iproute_get(int argc, char **argv) | ||
482 | { | ||
483 | struct rtnl_handle rth; | ||
484 | struct { | ||
485 | struct nlmsghdr n; | ||
486 | struct rtmsg r; | ||
487 | char buf[1024]; | ||
488 | } req; | ||
489 | char *idev = NULL; | ||
490 | char *odev = NULL; | ||
491 | int connected = 0; | ||
492 | int from_ok = 0; | ||
493 | |||
494 | memset(&req, 0, sizeof(req)); | ||
495 | |||
496 | iproute_reset_filter(); | ||
497 | |||
498 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); | ||
499 | req.n.nlmsg_flags = NLM_F_REQUEST; | ||
500 | req.n.nlmsg_type = RTM_GETROUTE; | ||
501 | req.r.rtm_family = preferred_family; | ||
502 | req.r.rtm_table = 0; | ||
503 | req.r.rtm_protocol = 0; | ||
504 | req.r.rtm_scope = 0; | ||
505 | req.r.rtm_type = 0; | ||
506 | req.r.rtm_src_len = 0; | ||
507 | req.r.rtm_dst_len = 0; | ||
508 | req.r.rtm_tos = 0; | ||
509 | |||
510 | while (argc > 0) { | ||
511 | if (matches(*argv, "from") == 0) { | ||
512 | inet_prefix addr; | ||
513 | NEXT_ARG(); | ||
514 | from_ok = 1; | ||
515 | get_prefix(&addr, *argv, req.r.rtm_family); | ||
516 | if (req.r.rtm_family == AF_UNSPEC) | ||
517 | req.r.rtm_family = addr.family; | ||
518 | if (addr.bytelen) | ||
519 | addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen); | ||
520 | req.r.rtm_src_len = addr.bitlen; | ||
521 | } else if (matches(*argv, "iif") == 0) { | ||
522 | NEXT_ARG(); | ||
523 | idev = *argv; | ||
524 | } else if (matches(*argv, "oif") == 0 || | ||
525 | strcmp(*argv, "dev") == 0) { | ||
526 | NEXT_ARG(); | ||
527 | odev = *argv; | ||
528 | } else if (matches(*argv, "notify") == 0) { | ||
529 | req.r.rtm_flags |= RTM_F_NOTIFY; | ||
530 | } else if (matches(*argv, "connected") == 0) { | ||
531 | connected = 1; | ||
532 | } else { | ||
533 | inet_prefix addr; | ||
534 | if (strcmp(*argv, "to") == 0) { | ||
535 | NEXT_ARG(); | ||
536 | } | ||
537 | get_prefix(&addr, *argv, req.r.rtm_family); | ||
538 | if (req.r.rtm_family == AF_UNSPEC) | ||
539 | req.r.rtm_family = addr.family; | ||
540 | if (addr.bytelen) | ||
541 | addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen); | ||
542 | req.r.rtm_dst_len = addr.bitlen; | ||
543 | } | ||
544 | argc--; argv++; | ||
545 | } | ||
546 | |||
547 | if (req.r.rtm_dst_len == 0) { | ||
548 | fprintf(stderr, "need at least destination address\n"); | ||
549 | exit(1); | ||
550 | } | ||
551 | |||
552 | if (rtnl_open(&rth, 0) < 0) | ||
553 | exit(1); | ||
554 | |||
555 | ll_init_map(&rth); | ||
556 | |||
557 | if (idev || odev) { | ||
558 | int idx; | ||
559 | |||
560 | if (idev) { | ||
561 | if ((idx = ll_name_to_index(idev)) == 0) { | ||
562 | fprintf(stderr, "Cannot find device \"%s\"\n", idev); | ||
563 | return -1; | ||
564 | } | ||
565 | addattr32(&req.n, sizeof(req), RTA_IIF, idx); | ||
566 | } | ||
567 | if (odev) { | ||
568 | if ((idx = ll_name_to_index(odev)) == 0) { | ||
569 | fprintf(stderr, "Cannot find device \"%s\"\n", odev); | ||
570 | return -1; | ||
571 | } | ||
572 | addattr32(&req.n, sizeof(req), RTA_OIF, idx); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | if (req.r.rtm_family == AF_UNSPEC) | ||
577 | req.r.rtm_family = AF_INET; | ||
578 | |||
579 | if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) | ||
580 | exit(2); | ||
581 | |||
582 | if (connected && !from_ok) { | ||
583 | struct rtmsg *r = NLMSG_DATA(&req.n); | ||
584 | int len = req.n.nlmsg_len; | ||
585 | struct rtattr * tb[RTA_MAX+1]; | ||
586 | |||
587 | if (print_route(NULL, &req.n, (void*)stdout) < 0) { | ||
588 | fprintf(stderr, "An error :-)\n"); | ||
589 | exit(1); | ||
590 | } | ||
591 | |||
592 | if (req.n.nlmsg_type != RTM_NEWROUTE) { | ||
593 | fprintf(stderr, "Not a route?\n"); | ||
594 | return -1; | ||
595 | } | ||
596 | len -= NLMSG_LENGTH(sizeof(*r)); | ||
597 | if (len < 0) { | ||
598 | fprintf(stderr, "Wrong len %d\n", len); | ||
599 | return -1; | ||
600 | } | ||
601 | |||
602 | memset(tb, 0, sizeof(tb)); | ||
603 | parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); | ||
604 | |||
605 | if (tb[RTA_PREFSRC]) { | ||
606 | tb[RTA_PREFSRC]->rta_type = RTA_SRC; | ||
607 | r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]); | ||
608 | } else if (!tb[RTA_SRC]) { | ||
609 | fprintf(stderr, "Failed to connect the route\n"); | ||
610 | return -1; | ||
611 | } | ||
612 | if (!odev && tb[RTA_OIF]) | ||
613 | tb[RTA_OIF]->rta_type = 0; | ||
614 | if (tb[RTA_GATEWAY]) | ||
615 | tb[RTA_GATEWAY]->rta_type = 0; | ||
616 | if (!idev && tb[RTA_IIF]) | ||
617 | tb[RTA_IIF]->rta_type = 0; | ||
618 | req.n.nlmsg_flags = NLM_F_REQUEST; | ||
619 | req.n.nlmsg_type = RTM_GETROUTE; | ||
620 | |||
621 | if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) | ||
622 | exit(2); | ||
623 | } | ||
624 | |||
625 | if (print_route(NULL, &req.n, (void*)stdout) < 0) { | ||
626 | fprintf(stderr, "An error :-)\n"); | ||
627 | exit(1); | ||
628 | } | ||
629 | |||
630 | exit(0); | ||
631 | } | ||
632 | |||
633 | void iproute_reset_filter() | ||
634 | { | ||
635 | memset(&filter, 0, sizeof(filter)); | ||
636 | filter.mdst.bitlen = -1; | ||
637 | filter.msrc.bitlen = -1; | ||
638 | } | ||
639 | |||
640 | int do_iproute(int argc, char **argv) | ||
641 | { | ||
642 | if (argc < 1) | ||
643 | return iproute_list(0, NULL); | ||
644 | |||
645 | if (matches(*argv, "add") == 0) | ||
646 | return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL, | ||
647 | argc-1, argv+1); | ||
648 | if (matches(*argv, "change") == 0 || strcmp(*argv, "chg") == 0) | ||
649 | return iproute_modify(RTM_NEWROUTE, NLM_F_REPLACE, | ||
650 | argc-1, argv+1); | ||
651 | if (matches(*argv, "replace") == 0) | ||
652 | return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE, | ||
653 | argc-1, argv+1); | ||
654 | if (matches(*argv, "prepend") == 0) | ||
655 | return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE, | ||
656 | argc-1, argv+1); | ||
657 | if (matches(*argv, "append") == 0) | ||
658 | return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_APPEND, | ||
659 | argc-1, argv+1); | ||
660 | if (matches(*argv, "test") == 0) | ||
661 | return iproute_modify(RTM_NEWROUTE, NLM_F_EXCL, | ||
662 | argc-1, argv+1); | ||
663 | if (matches(*argv, "delete") == 0) | ||
664 | return iproute_modify(RTM_DELROUTE, 0, | ||
665 | argc-1, argv+1); | ||
666 | if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 | ||
667 | || matches(*argv, "lst") == 0) | ||
668 | return iproute_list(argc-1, argv+1); | ||
669 | if (matches(*argv, "get") == 0) | ||
670 | return iproute_get(argc-1, argv+1); | ||
671 | fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv); | ||
672 | exit(-1); | ||
673 | } | ||
674 | |||