blob: 8117b0397409124df30bccdeebfd353027d34f59 [file] [log] [blame]
Eric Andersenec455952001-02-14 08:11:27 +00001/* route
2 *
3 * Similar to the standard Unix route, but with only the necessary
Eric Andersen51b8bd62002-07-03 11:46:38 +00004 * parts for AF_INET and AF_INET6
Eric Andersenec455952001-02-14 08:11:27 +00005 *
6 * Bjorn Wesen, Axis Communications AB
7 *
Eric Andersenb9408502001-09-05 19:32:00 +00008 * Author of the original route:
Eric Andersenec455952001-02-14 08:11:27 +00009 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
10 * (derived from FvK's 'route.c 1.70 01/04/94')
11 *
12 * This program is free software; you can redistribute it
13 * and/or modify it under the terms of the GNU General
14 * Public License as published by the Free Software
15 * Foundation; either version 2 of the License, or (at
16 * your option) any later version.
17 *
Eric Andersen0552b9a2002-12-11 03:57:12 +000018 * $Id: route.c,v 1.20 2002/12/11 03:57:12 andersen Exp $
Eric Andersenec455952001-02-14 08:11:27 +000019 *
Eric Andersen68be2ab2001-02-14 19:26:39 +000020 * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
Eric Andersen26d53eb2001-03-07 06:33:01 +000021 * adjustments by Larry Doolittle <LRDoolittle@lbl.gov>
Eric Andersen51b8bd62002-07-03 11:46:38 +000022 *
23 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
Eric Andersenec455952001-02-14 08:11:27 +000024 */
25
Eric Andersenec455952001-02-14 08:11:27 +000026#include <sys/types.h>
27#include <sys/ioctl.h>
Eric Andersencd8c4362001-11-10 11:22:46 +000028#include "inet_common.h"
Eric Andersenec455952001-02-14 08:11:27 +000029#include <net/route.h>
Eric Andersen51b8bd62002-07-03 11:46:38 +000030#include <net/if.h>
Eric Andersenec455952001-02-14 08:11:27 +000031#include <stdio.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <stdlib.h>
35#include <string.h>
36#include <getopt.h>
37#include <unistd.h>
38#include <ctype.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000039#include "busybox.h"
Eric Andersenec455952001-02-14 08:11:27 +000040
41#define _(x) x
42
43#define RTACTION_ADD 1
44#define RTACTION_DEL 2
45#define RTACTION_HELP 3
46#define RTACTION_FLUSH 4
47#define RTACTION_SHOW 5
48
49#define E_NOTFOUND 8
50#define E_SOCK 7
51#define E_LOOKUP 6
52#define E_VERSION 5
53#define E_USAGE 4
54#define E_OPTERR 3
55#define E_INTERN 2
56#define E_NOSUPP 1
57
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000058#if defined (SIOCADDRTOLD) || defined (RTF_IRTT) /* route */
Eric Andersenec455952001-02-14 08:11:27 +000059#define HAVE_NEW_ADDRT 1
60#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000061#ifdef RTF_IRTT /* route */
Eric Andersenec455952001-02-14 08:11:27 +000062#define HAVE_RTF_IRTT 1
63#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000064#ifdef RTF_REJECT /* route */
Eric Andersenec455952001-02-14 08:11:27 +000065#define HAVE_RTF_REJECT 1
66#endif
67
68#if HAVE_NEW_ADDRT
69#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
70#define full_mask(x) (x)
71#else
72#define mask_in_addr(x) ((x).rt_genmask)
73#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
74#endif
75
Eric Andersencd8c4362001-11-10 11:22:46 +000076
77
Eric Andersenec455952001-02-14 08:11:27 +000078/* add or delete a route depending on action */
79
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000080static int INET_setroute(int action, int options, char **args)
Eric Andersenec455952001-02-14 08:11:27 +000081{
82 struct rtentry rt;
Eric Andersencd8c4362001-11-10 11:22:46 +000083 char target[128], gateway[128] = "NONE";
84 const char *netmask = bb_INET_default;
Eric Andersenec455952001-02-14 08:11:27 +000085 int xflag, isnet;
86 int skfd;
87
88 xflag = 0;
89
Eric Andersena3c84812001-08-23 22:05:33 +000090 if (*args == NULL)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000091 show_usage();
92 if (strcmp(*args, "-net") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +000093 xflag = 1;
94 args++;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000095 } else if (strcmp(*args, "-host") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +000096 xflag = 2;
97 args++;
98 }
Eric Andersencd8c4362001-11-10 11:22:46 +000099 if (*args == NULL)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000100 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000101 safe_strncpy(target, *args++, (sizeof target));
102
103 /* Clean out the RTREQ structure. */
104 memset((char *) &rt, 0, sizeof(struct rtentry));
105
106
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000107 if ((isnet =
108 INET_resolve(target, (struct sockaddr_in *) &rt.rt_dst,
109 xflag != 1)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000110 error_msg(_("can't resolve %s"), target);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000111 return EXIT_FAILURE; /* XXX change to E_something */
Eric Andersenec455952001-02-14 08:11:27 +0000112 }
113
114 switch (xflag) {
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000115 case 1:
116 isnet = 1;
117 break;
Eric Andersenb9408502001-09-05 19:32:00 +0000118
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000119 case 2:
120 isnet = 0;
121 break;
Eric Andersenb9408502001-09-05 19:32:00 +0000122
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000123 default:
124 break;
Eric Andersenec455952001-02-14 08:11:27 +0000125 }
Eric Andersenb9408502001-09-05 19:32:00 +0000126
Eric Andersenec455952001-02-14 08:11:27 +0000127 /* Fill in the other fields. */
128 rt.rt_flags = (RTF_UP | RTF_HOST);
129 if (isnet)
130 rt.rt_flags &= ~RTF_HOST;
131
132 while (*args) {
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000133 if (strcmp(*args, "metric") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000134 int metric;
Eric Andersenb9408502001-09-05 19:32:00 +0000135
Eric Andersenec455952001-02-14 08:11:27 +0000136 args++;
137 if (!*args || !isdigit(**args))
Eric Andersen67991cf2001-02-14 21:23:06 +0000138 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000139 metric = atoi(*args);
140#if HAVE_NEW_ADDRT
141 rt.rt_metric = metric + 1;
142#else
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000143 ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000144#endif
145 args++;
146 continue;
147 }
148
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000149 if (strcmp(*args, "netmask") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000150 struct sockaddr mask;
Eric Andersenb9408502001-09-05 19:32:00 +0000151
Eric Andersenec455952001-02-14 08:11:27 +0000152 args++;
153 if (!*args || mask_in_addr(rt))
Eric Andersen67991cf2001-02-14 21:23:06 +0000154 show_usage();
Eric Andersencd8c4362001-11-10 11:22:46 +0000155 netmask = *args;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000156 if ((isnet =
157 INET_resolve(netmask, (struct sockaddr_in *) &mask,
158 0)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000159 error_msg(_("can't resolve netmask %s"), netmask);
160 return E_LOOKUP;
Eric Andersenec455952001-02-14 08:11:27 +0000161 }
162 rt.rt_genmask = full_mask(mask);
163 args++;
164 continue;
165 }
166
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000167 if (strcmp(*args, "gw") == 0 || strcmp(*args, "gateway") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000168 args++;
169 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000170 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000171 if (rt.rt_flags & RTF_GATEWAY)
Eric Andersen67991cf2001-02-14 21:23:06 +0000172 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000173 safe_strncpy(gateway, *args, (sizeof gateway));
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000174 if ((isnet =
175 INET_resolve(gateway, (struct sockaddr_in *) &rt.rt_gateway,
176 1)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000177 error_msg(_("can't resolve gw %s"), gateway);
178 return E_LOOKUP;
Eric Andersenec455952001-02-14 08:11:27 +0000179 }
180 if (isnet) {
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000181 error_msg(_("%s: cannot use a NETWORK as gateway!"), gateway);
Mark Whitley99806ad2001-02-15 23:00:48 +0000182 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000183 }
184 rt.rt_flags |= RTF_GATEWAY;
185 args++;
186 continue;
187 }
188
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000189 if (strcmp(*args, "mss") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000190 args++;
191 rt.rt_flags |= RTF_MSS;
192 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000193 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000194 rt.rt_mss = atoi(*args);
195 args++;
196 if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000197 error_msg(_("Invalid MSS."));
198 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000199 }
200 continue;
201 }
202
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000203 if (strcmp(*args, "window") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000204 args++;
205 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000206 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000207 rt.rt_flags |= RTF_WINDOW;
208 rt.rt_window = atoi(*args);
209 args++;
210 if (rt.rt_window < 128) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000211 error_msg(_("Invalid window."));
212 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000213 }
214 continue;
215 }
216
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000217 if (strcmp(*args, "irtt") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000218 args++;
219 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000220 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000221 args++;
222#if HAVE_RTF_IRTT
223 rt.rt_flags |= RTF_IRTT;
224 rt.rt_irtt = atoi(*(args - 1));
Eric Andersen0552b9a2002-12-11 03:57:12 +0000225 rt.rt_irtt *= (sysconf(_SC_CLK_TCK) / 100); /* FIXME */
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000226#if 0 /* FIXME: do we need to check anything of this? */
Eric Andersenec455952001-02-14 08:11:27 +0000227 if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000228 error_msg(_("Invalid initial rtt."));
229 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000230 }
231#endif
232#else
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000233 ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000234#endif
235 continue;
236 }
237
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000238 if (strcmp(*args, "reject") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000239 args++;
240#if HAVE_RTF_REJECT
241 rt.rt_flags |= RTF_REJECT;
242#else
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000243 ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000244#endif
245 continue;
246 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000247 if (strcmp(*args, "mod") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000248 args++;
249 rt.rt_flags |= RTF_MODIFIED;
250 continue;
251 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000252 if (strcmp(*args, "dyn") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000253 args++;
254 rt.rt_flags |= RTF_DYNAMIC;
255 continue;
256 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000257 if (strcmp(*args, "reinstate") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000258 args++;
259 rt.rt_flags |= RTF_REINSTATE;
260 continue;
261 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000262 if (strcmp(*args, "device") == 0 || strcmp(*args, "dev") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000263 args++;
264 if (rt.rt_dev || *args == NULL)
Eric Andersen67991cf2001-02-14 21:23:06 +0000265 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000266 rt.rt_dev = *args++;
267 continue;
268 }
269 /* nothing matches */
270 if (!rt.rt_dev) {
271 rt.rt_dev = *args++;
272 if (*args)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000273 show_usage(); /* must be last to catch typos */
Mark Whitley99806ad2001-02-15 23:00:48 +0000274 } else {
Eric Andersen67991cf2001-02-14 21:23:06 +0000275 show_usage();
Mark Whitley99806ad2001-02-15 23:00:48 +0000276 }
Eric Andersenec455952001-02-14 08:11:27 +0000277 }
278
279#if HAVE_RTF_REJECT
280 if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
281 rt.rt_dev = "lo";
282#endif
283
284 /* sanity checks.. */
285 if (mask_in_addr(rt)) {
286 unsigned long mask = mask_in_addr(rt);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000287
Eric Andersenec455952001-02-14 08:11:27 +0000288 mask = ~ntohl(mask);
289 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000290 error_msg(_("netmask %.8x doesn't make sense with host route"),
291 (unsigned int) mask);
Mark Whitley99806ad2001-02-15 23:00:48 +0000292 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000293 }
294 if (mask & (mask + 1)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000295 error_msg(_("bogus netmask %s"), netmask);
296 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000297 }
298 mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
299 if (mask & ~mask_in_addr(rt)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000300 error_msg(_("netmask doesn't match route address"));
301 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000302 }
303 }
304 /* Fill out netmask if still unset */
305 if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
306 mask_in_addr(rt) = 0xffffffff;
307
308 /* Create a socket to the INET kernel. */
309 if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
310 perror("socket");
Mark Whitley99806ad2001-02-15 23:00:48 +0000311 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000312 }
313 /* Tell the kernel to accept this route. */
314 if (action == RTACTION_DEL) {
315 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
316 perror("SIOCDELRT");
317 close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000318 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000319 }
320 } else {
321 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
322 perror("SIOCADDRT");
323 close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000324 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000325 }
326 }
Eric Andersenb9408502001-09-05 19:32:00 +0000327
Eric Andersenec455952001-02-14 08:11:27 +0000328 /* Close the socket. */
329 (void) close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000330 return EXIT_SUCCESS;
Eric Andersenec455952001-02-14 08:11:27 +0000331}
332
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000333#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000334static int INET6_setroute(int action, int options, char **args)
335{
336 struct in6_rtmsg rt;
337 struct ifreq ifr;
338 struct sockaddr_in6 sa6;
339 char target[128], gateway[128] = "NONE";
340 int metric, prefix_len;
341 char *devname = NULL;
342 char *cp;
343 int skfd;
344
345 if (*args == NULL)
346 show_usage();
347
348 strcpy(target, *args++);
349 if (!strcmp(target, "default")) {
350 prefix_len = 0;
351 memset(&sa6, 0, sizeof(sa6));
352 } else {
353 if ((cp = strchr(target, '/'))) {
354 prefix_len = atol(cp + 1);
355 if ((prefix_len < 0) || (prefix_len > 128))
356 show_usage();
357 *cp = 0;
358 } else {
359 prefix_len = 128;
360 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000361 if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) {
Eric Andersen51b8bd62002-07-03 11:46:38 +0000362 error_msg(_("can't resolve %s"), target);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000363 return EXIT_FAILURE; /* XXX change to E_something */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000364 }
365 }
366
367 /* Clean out the RTREQ structure. */
368 memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
369
370 memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
371
372 /* Fill in the other fields. */
373 rt.rtmsg_flags = RTF_UP;
374 if (prefix_len == 128)
375 rt.rtmsg_flags |= RTF_HOST;
376 rt.rtmsg_metric = 1;
377 rt.rtmsg_dst_len = prefix_len;
378
379 while (*args) {
380 if (!strcmp(*args, "metric")) {
381
382 args++;
383 if (!*args || !isdigit(**args))
384 show_usage();
385 metric = atoi(*args);
386 rt.rtmsg_metric = metric;
387 args++;
388 continue;
389 }
390 if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
391 args++;
392 if (!*args)
393 show_usage();
394 if (rt.rtmsg_flags & RTF_GATEWAY)
395 show_usage();
396 strcpy(gateway, *args);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000397 if (INET6_resolve(gateway, (struct sockaddr_in6 *) &sa6) < 0) {
Eric Andersen51b8bd62002-07-03 11:46:38 +0000398 error_msg(_("can't resolve gw %s"), gateway);
399 return (E_LOOKUP);
400 }
401 memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000402 sizeof(struct in6_addr));
Eric Andersen51b8bd62002-07-03 11:46:38 +0000403 rt.rtmsg_flags |= RTF_GATEWAY;
404 args++;
405 continue;
406 }
407 if (!strcmp(*args, "mod")) {
408 args++;
409 rt.rtmsg_flags |= RTF_MODIFIED;
410 continue;
411 }
412 if (!strcmp(*args, "dyn")) {
413 args++;
414 rt.rtmsg_flags |= RTF_DYNAMIC;
415 continue;
416 }
417 if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
418 args++;
419 if (!*args)
420 show_usage();
421 } else if (args[1])
422 show_usage();
423
424 devname = *args;
425 args++;
426 }
427
428 /* Create a socket to the INET6 kernel. */
429 if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
430 perror("socket");
431 return (E_SOCK);
432 }
433 if (devname) {
434 memset(&ifr, 0, sizeof(ifr));
435 strcpy(ifr.ifr_name, devname);
436
437 if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) {
438 perror("SIOGIFINDEX");
439 return (E_SOCK);
440 }
441 rt.rtmsg_ifindex = ifr.ifr_ifindex;
442 } else
443 rt.rtmsg_ifindex = 0;
444
445 /* Tell the kernel to accept this route. */
446 if (action == RTACTION_DEL) {
447 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
448 perror("SIOCDELRT");
449 close(skfd);
450 return (E_SOCK);
451 }
452 } else {
453 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
454 perror("SIOCADDRT");
455 close(skfd);
456 return (E_SOCK);
457 }
458 }
459
460 /* Close the socket. */
461 (void) close(skfd);
462 return (0);
463}
464#endif
465
Eric Andersen863a3e12001-08-27 17:57:27 +0000466#ifndef RTF_UP
467/* Keep this in sync with /usr/src/linux/include/linux/route.h */
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000468#define RTF_UP 0x0001 /* route usable */
469#define RTF_GATEWAY 0x0002 /* destination is a gateway */
470#define RTF_HOST 0x0004 /* host entry (net otherwise) */
471#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */
472#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
473#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
474#define RTF_MTU 0x0040 /* specific MTU for this route */
Eric Andersen863a3e12001-08-27 17:57:27 +0000475#ifndef RTF_MSS
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000476#define RTF_MSS RTF_MTU /* Compatibility :-( */
Eric Andersen863a3e12001-08-27 17:57:27 +0000477#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000478#define RTF_WINDOW 0x0080 /* per route window clamping */
479#define RTF_IRTT 0x0100 /* Initial round trip time */
480#define RTF_REJECT 0x0200 /* Reject route */
Eric Andersen863a3e12001-08-27 17:57:27 +0000481#endif
482
Robert Griebl820098f2002-05-14 23:03:23 +0000483void displayroutes(int noresolve, int netstatfmt)
Eric Andersen68be2ab2001-02-14 19:26:39 +0000484{
485 char buff[256];
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000486 int nl = 0;
Eric Andersen68be2ab2001-02-14 19:26:39 +0000487 struct in_addr dest;
488 struct in_addr gw;
489 struct in_addr mask;
Robert Griebl820098f2002-05-14 23:03:23 +0000490 int flgs, ref, use, metric, mtu, win, ir;
Eric Andersenb9408502001-09-05 19:32:00 +0000491 char flags[64];
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000492 unsigned long int d, g, m;
Eric Andersen68be2ab2001-02-14 19:26:39 +0000493
494 char sdest[16], sgw[16];
495
Eric Andersenf1bbb222001-02-18 20:12:25 +0000496 FILE *fp = xfopen("/proc/net/route", "r");
Eric Andersen68be2ab2001-02-14 19:26:39 +0000497
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000498 if (noresolve)
Eric Andersencd8c4362001-11-10 11:22:46 +0000499 noresolve = 0x0fff;
500
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000501 while (fgets(buff, sizeof(buff), fp) != NULL) {
502 if (nl) {
Eric Andersen68be2ab2001-02-14 19:26:39 +0000503 int ifl = 0;
Eric Andersencd8c4362001-11-10 11:22:46 +0000504 int numeric;
505 struct sockaddr_in s_addr;
506
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000507 while (buff[ifl] != ' ' && buff[ifl] != '\t' && buff[ifl] != '\0')
Eric Andersen68be2ab2001-02-14 19:26:39 +0000508 ifl++;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000509 buff[ifl] = 0; /* interface */
510 if (sscanf(buff + ifl + 1, "%lx%lx%X%d%d%d%lx%d%d%d",
511 &d, &g, &flgs, &ref, &use, &metric, &m, &mtu, &win,
512 &ir) != 10) {
513 error_msg_and_die("Unsuported kernel route format\n");
Eric Andersen68be2ab2001-02-14 19:26:39 +0000514 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000515 if (nl == 1) {
Robert Griebl820098f2002-05-14 23:03:23 +0000516 printf("Kernel IP routing table\n");
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000517 printf
518 ("Destination Gateway Genmask Flags %s Iface\n",
519 netstatfmt ? " MSS Window irtt" : "Metric Ref Use");
Robert Griebl820098f2002-05-14 23:03:23 +0000520 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000521 ifl = 0; /* parse flags */
522 if (flgs & RTF_UP) {
523 if (flgs & RTF_REJECT)
524 flags[ifl++] = '!';
525 else
526 flags[ifl++] = 'U';
527 if (flgs & RTF_GATEWAY)
528 flags[ifl++] = 'G';
529 if (flgs & RTF_HOST)
530 flags[ifl++] = 'H';
531 if (flgs & RTF_REINSTATE)
532 flags[ifl++] = 'R';
533 if (flgs & RTF_DYNAMIC)
534 flags[ifl++] = 'D';
535 if (flgs & RTF_MODIFIED)
536 flags[ifl++] = 'M';
537 flags[ifl] = 0;
538 dest.s_addr = d;
539 gw.s_addr = g;
540 mask.s_addr = m;
Eric Andersencd8c4362001-11-10 11:22:46 +0000541 memset(&s_addr, 0, sizeof(struct sockaddr_in));
542 s_addr.sin_family = AF_INET;
543 s_addr.sin_addr = dest;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000544 numeric = noresolve | 0x8000; /* default instead of * */
Eric Andersencd8c4362001-11-10 11:22:46 +0000545 INET_rresolve(sdest, sizeof(sdest), &s_addr, numeric, m);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000546 numeric = noresolve | 0x4000; /* host instead of net */
Eric Andersencd8c4362001-11-10 11:22:46 +0000547 s_addr.sin_addr = gw;
548 INET_rresolve(sgw, sizeof(sgw), &s_addr, numeric, m);
Robert Grieblc30c5e82002-05-16 19:14:15 +0000549
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000550 printf("%-16s%-16s%-16s%-6s", sdest, sgw, inet_ntoa(mask),
551 flags);
552 if (netstatfmt)
553 printf("%5d %-5d %6d %s\n", mtu, win, ir, buff);
554 else
555 printf("%-6d %-2d %7d %s\n", metric, ref, use, buff);
Eric Andersenb9408502001-09-05 19:32:00 +0000556 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000557 }
Eric Andersenb9408502001-09-05 19:32:00 +0000558 nl++;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000559 }
Eric Andersen68be2ab2001-02-14 19:26:39 +0000560}
561
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000562#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000563static void INET6_displayroutes(int noresolve)
564{
565 char buff[256];
566 char iface[16], flags[16];
567 char addr6[128], naddr6[128];
568 struct sockaddr_in6 saddr6, snaddr6;
569 int iflags, metric, refcnt, use, prefix_len, slen;
570 int numeric;
571
572 char addr6p[8][5], saddr6p[8][5], naddr6p[8][5];
573
574 FILE *fp = xfopen("/proc/net/ipv6_route", "r");
Eric Andersen51b8bd62002-07-03 11:46:38 +0000575
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000576 flags[0] = 'U';
577
578 if (noresolve)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000579 noresolve = 0x0fff;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000580 numeric = noresolve | 0x8000; /* default instead of * */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000581
582 printf("Kernel IPv6 routing table\n"
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000583 "Destination "
584 "Next Hop "
585 "Flags Metric Ref Use Iface\n");
Eric Andersen51b8bd62002-07-03 11:46:38 +0000586
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000587 while (fgets(buff, sizeof(buff), fp) != NULL) {
Eric Andersen51b8bd62002-07-03 11:46:38 +0000588 int ifl;
589
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000590 if (sscanf(buff, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
591 "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
592 "%4s%4s%4s%4s%4s%4s%4s%4s %08x %08x %08x %08x %s\n",
593 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
594 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
595 &prefix_len,
596 saddr6p[0], saddr6p[1], saddr6p[2], saddr6p[3],
597 saddr6p[4], saddr6p[5], saddr6p[6], saddr6p[7],
598 &slen,
599 naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
600 naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7],
601 &metric, &use, &refcnt, &iflags, iface) != 31) {
602 error_msg_and_die("Unsuported kernel route format\n");
Eric Andersen51b8bd62002-07-03 11:46:38 +0000603 }
604
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000605 ifl = 1; /* parse flags */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000606 if (!(iflags & RTF_UP))
607 continue;
608 if (iflags & RTF_GATEWAY)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000609 flags[ifl++] = 'G';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000610 if (iflags & RTF_HOST)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000611 flags[ifl++] = 'H';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000612 if (iflags & RTF_DEFAULT)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000613 flags[ifl++] = 'D';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000614 if (iflags & RTF_ADDRCONF)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000615 flags[ifl++] = 'A';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000616 if (iflags & RTF_CACHE)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000617 flags[ifl++] = 'C';
618 flags[ifl] = 0;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000619
620 /* Fetch and resolve the target address. */
621 snprintf(addr6, sizeof(addr6), "%s:%s:%s:%s:%s:%s:%s:%s",
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000622 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
623 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000624 inet_pton(AF_INET6, addr6, (struct sockaddr *) &saddr6.sin6_addr);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000625 saddr6.sin6_family = AF_INET6;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000626
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000627 INET6_rresolve(addr6, sizeof(addr6), (struct sockaddr_in6 *) &saddr6,
628 numeric);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000629 snprintf(addr6, sizeof(addr6), "%s/%d", addr6, prefix_len);
630
631 /* Fetch and resolve the nexthop address. */
632 snprintf(naddr6, sizeof(naddr6), "%s:%s:%s:%s:%s:%s:%s:%s",
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000633 naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
634 naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7]);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000635 inet_pton(AF_INET6, naddr6, (struct sockaddr *) &snaddr6.sin6_addr);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000636 snaddr6.sin6_family = AF_INET6;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000637
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000638 INET6_rresolve(naddr6, sizeof(naddr6),
639 (struct sockaddr_in6 *) &snaddr6, numeric);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000640
641 /* Print the info. */
642 printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000643 addr6, naddr6, flags, metric, refcnt, use, iface);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000644 }
645}
646#endif
647
Eric Andersenec455952001-02-14 08:11:27 +0000648int route_main(int argc, char **argv)
649{
Robert Griebl820098f2002-05-14 23:03:23 +0000650 int opt;
Eric Andersenec455952001-02-14 08:11:27 +0000651 int what = 0;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000652
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000653#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000654 int af = AF_INET;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000655#endif
Eric Andersenec455952001-02-14 08:11:27 +0000656
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000657 if (!argv[1] || (argv[1][0] == '-')) {
Robert Griebl820098f2002-05-14 23:03:23 +0000658 /* check options */
659 int noresolve = 0;
660 int extended = 0;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000661
Eric Andersen51b8bd62002-07-03 11:46:38 +0000662 while ((opt = getopt(argc, argv, "A:ne")) > 0) {
Robert Griebl820098f2002-05-14 23:03:23 +0000663 switch (opt) {
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000664 case 'n':
665 noresolve = 1;
666 break;
667 case 'e':
668 extended = 1;
669 break;
670 case 'A':
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000671#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000672 if (strcmp(optarg, "inet6") == 0)
673 af = AF_INET6;
674 break;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000675#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000676 default:
677 show_usage();
Robert Griebl820098f2002-05-14 23:03:23 +0000678 }
679 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000680
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000681#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000682 if (af == AF_INET6)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000683 INET6_displayroutes(*argv != NULL);
684 else
685#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000686 displayroutes(noresolve, extended);
Eric Andersen26d53eb2001-03-07 06:33:01 +0000687 return EXIT_SUCCESS;
Eric Andersenec455952001-02-14 08:11:27 +0000688 } else {
689 /* check verb */
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000690 if (strcmp(argv[1], "add") == 0)
Eric Andersenec455952001-02-14 08:11:27 +0000691 what = RTACTION_ADD;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000692 else if (strcmp(argv[1], "del") == 0
693 || strcmp(argv[1], "delete") == 0)
Eric Andersenec455952001-02-14 08:11:27 +0000694 what = RTACTION_DEL;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000695 else if (strcmp(argv[1], "flush") == 0)
Eric Andersenec455952001-02-14 08:11:27 +0000696 what = RTACTION_FLUSH;
697 else
Eric Andersen67991cf2001-02-14 21:23:06 +0000698 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000699 }
700
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000701#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000702 if (af == AF_INET6)
703 return INET6_setroute(what, 0, argv + 2);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000704#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000705 return INET_setroute(what, 0, argv + 2);
Eric Andersenec455952001-02-14 08:11:27 +0000706}