blob: 083149a3d8336c1ed6c69eadba4923aa53ab1870 [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 *
Manuel Novoa III cad53642003-03-19 09:13:01 +000018 * $Id: route.c,v 1.22 2003/03/19 09:12:39 mjn3 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)
Manuel Novoa III cad53642003-03-19 09:13:01 +000091 bb_show_usage();
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000092 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)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000100 bb_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) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000110 bb_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))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000138 bb_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))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000154 bb_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) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000159 bb_error_msg(_("can't resolve netmask %s"), netmask);
Mark Whitley99806ad2001-02-15 23:00:48 +0000160 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)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000170 bb_show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000171 if (rt.rt_flags & RTF_GATEWAY)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000172 bb_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) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000177 bb_error_msg(_("can't resolve gw %s"), gateway);
Mark Whitley99806ad2001-02-15 23:00:48 +0000178 return E_LOOKUP;
Eric Andersenec455952001-02-14 08:11:27 +0000179 }
180 if (isnet) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000181 bb_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)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000193 bb_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) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000197 bb_error_msg(_("Invalid MSS."));
Mark Whitley99806ad2001-02-15 23:00:48 +0000198 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)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000206 bb_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) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000211 bb_error_msg(_("Invalid window."));
Mark Whitley99806ad2001-02-15 23:00:48 +0000212 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)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000220 bb_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)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000228 bb_error_msg(_("Invalid initial rtt."));
Mark Whitley99806ad2001-02-15 23:00:48 +0000229 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)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000265 bb_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)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000273 bb_show_usage(); /* must be last to catch typos */
Mark Whitley99806ad2001-02-15 23:00:48 +0000274 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000275 bb_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) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000290 bb_error_msg(_("netmask %.8x doesn't make sense with host route"),
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000291 (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)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000295 bb_error_msg(_("bogus netmask %s"), netmask);
Mark Whitley99806ad2001-02-15 23:00:48 +0000296 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)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000300 bb_error_msg(_("netmask doesn't match route address"));
Mark Whitley99806ad2001-02-15 23:00:48 +0000301 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)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000346 bb_show_usage();
Eric Andersen51b8bd62002-07-03 11:46:38 +0000347
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))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000356 bb_show_usage();
Eric Andersen51b8bd62002-07-03 11:46:38 +0000357 *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) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000362 bb_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))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000384 bb_show_usage();
Eric Andersen51b8bd62002-07-03 11:46:38 +0000385 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)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000393 bb_show_usage();
Eric Andersen51b8bd62002-07-03 11:46:38 +0000394 if (rt.rtmsg_flags & RTF_GATEWAY)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000395 bb_show_usage();
Eric Andersen51b8bd62002-07-03 11:46:38 +0000396 strcpy(gateway, *args);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000397 if (INET6_resolve(gateway, (struct sockaddr_in6 *) &sa6) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000398 bb_error_msg(_("can't resolve gw %s"), gateway);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000399 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)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000420 bb_show_usage();
Eric Andersen51b8bd62002-07-03 11:46:38 +0000421 } else if (args[1])
Manuel Novoa III cad53642003-03-19 09:13:01 +0000422 bb_show_usage();
Eric Andersen51b8bd62002-07-03 11:46:38 +0000423
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
Manuel Novoa III cad53642003-03-19 09:13:01 +0000496 FILE *fp = bb_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
Robert Grieblbe2ae242002-12-16 22:04:18 +0000501 printf("Kernel IP routing table\n");
502 printf
503 ("Destination Gateway Genmask Flags %s Iface\n",
504 netstatfmt ? " MSS Window irtt" : "Metric Ref Use");
505
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000506 while (fgets(buff, sizeof(buff), fp) != NULL) {
507 if (nl) {
Eric Andersen68be2ab2001-02-14 19:26:39 +0000508 int ifl = 0;
Eric Andersencd8c4362001-11-10 11:22:46 +0000509 int numeric;
510 struct sockaddr_in s_addr;
511
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000512 while (buff[ifl] != ' ' && buff[ifl] != '\t' && buff[ifl] != '\0')
Eric Andersen68be2ab2001-02-14 19:26:39 +0000513 ifl++;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000514 buff[ifl] = 0; /* interface */
515 if (sscanf(buff + ifl + 1, "%lx%lx%X%d%d%d%lx%d%d%d",
516 &d, &g, &flgs, &ref, &use, &metric, &m, &mtu, &win,
517 &ir) != 10) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000518 bb_error_msg_and_die("Unsuported kernel route format\n");
Eric Andersen68be2ab2001-02-14 19:26:39 +0000519 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000520 ifl = 0; /* parse flags */
521 if (flgs & RTF_UP) {
522 if (flgs & RTF_REJECT)
523 flags[ifl++] = '!';
524 else
525 flags[ifl++] = 'U';
526 if (flgs & RTF_GATEWAY)
527 flags[ifl++] = 'G';
528 if (flgs & RTF_HOST)
529 flags[ifl++] = 'H';
530 if (flgs & RTF_REINSTATE)
531 flags[ifl++] = 'R';
532 if (flgs & RTF_DYNAMIC)
533 flags[ifl++] = 'D';
534 if (flgs & RTF_MODIFIED)
535 flags[ifl++] = 'M';
536 flags[ifl] = 0;
537 dest.s_addr = d;
538 gw.s_addr = g;
539 mask.s_addr = m;
Eric Andersencd8c4362001-11-10 11:22:46 +0000540 memset(&s_addr, 0, sizeof(struct sockaddr_in));
541 s_addr.sin_family = AF_INET;
542 s_addr.sin_addr = dest;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000543 numeric = noresolve | 0x8000; /* default instead of * */
Eric Andersencd8c4362001-11-10 11:22:46 +0000544 INET_rresolve(sdest, sizeof(sdest), &s_addr, numeric, m);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000545 numeric = noresolve | 0x4000; /* host instead of net */
Eric Andersencd8c4362001-11-10 11:22:46 +0000546 s_addr.sin_addr = gw;
547 INET_rresolve(sgw, sizeof(sgw), &s_addr, numeric, m);
Robert Grieblc30c5e82002-05-16 19:14:15 +0000548
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000549 printf("%-16s%-16s%-16s%-6s", sdest, sgw, inet_ntoa(mask),
550 flags);
551 if (netstatfmt)
552 printf("%5d %-5d %6d %s\n", mtu, win, ir, buff);
553 else
554 printf("%-6d %-2d %7d %s\n", metric, ref, use, buff);
Eric Andersenb9408502001-09-05 19:32:00 +0000555 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000556 }
Eric Andersenb9408502001-09-05 19:32:00 +0000557 nl++;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000558 }
Eric Andersen68be2ab2001-02-14 19:26:39 +0000559}
560
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000561#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000562static void INET6_displayroutes(int noresolve)
563{
564 char buff[256];
565 char iface[16], flags[16];
566 char addr6[128], naddr6[128];
567 struct sockaddr_in6 saddr6, snaddr6;
568 int iflags, metric, refcnt, use, prefix_len, slen;
569 int numeric;
570
571 char addr6p[8][5], saddr6p[8][5], naddr6p[8][5];
572
Manuel Novoa III cad53642003-03-19 09:13:01 +0000573 FILE *fp = bb_xfopen("/proc/net/ipv6_route", "r");
Eric Andersen51b8bd62002-07-03 11:46:38 +0000574
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000575 flags[0] = 'U';
576
577 if (noresolve)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000578 noresolve = 0x0fff;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000579 numeric = noresolve | 0x8000; /* default instead of * */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000580
581 printf("Kernel IPv6 routing table\n"
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000582 "Destination "
583 "Next Hop "
584 "Flags Metric Ref Use Iface\n");
Eric Andersen51b8bd62002-07-03 11:46:38 +0000585
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000586 while (fgets(buff, sizeof(buff), fp) != NULL) {
Eric Andersen51b8bd62002-07-03 11:46:38 +0000587 int ifl;
588
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000589 if (sscanf(buff, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
590 "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
591 "%4s%4s%4s%4s%4s%4s%4s%4s %08x %08x %08x %08x %s\n",
592 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
593 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
594 &prefix_len,
595 saddr6p[0], saddr6p[1], saddr6p[2], saddr6p[3],
596 saddr6p[4], saddr6p[5], saddr6p[6], saddr6p[7],
597 &slen,
598 naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
599 naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7],
600 &metric, &use, &refcnt, &iflags, iface) != 31) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000601 bb_error_msg_and_die("Unsuported kernel route format\n");
Eric Andersen51b8bd62002-07-03 11:46:38 +0000602 }
603
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000604 ifl = 1; /* parse flags */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000605 if (!(iflags & RTF_UP))
606 continue;
607 if (iflags & RTF_GATEWAY)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000608 flags[ifl++] = 'G';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000609 if (iflags & RTF_HOST)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000610 flags[ifl++] = 'H';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000611 if (iflags & RTF_DEFAULT)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000612 flags[ifl++] = 'D';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000613 if (iflags & RTF_ADDRCONF)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000614 flags[ifl++] = 'A';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000615 if (iflags & RTF_CACHE)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000616 flags[ifl++] = 'C';
617 flags[ifl] = 0;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000618
619 /* Fetch and resolve the target address. */
620 snprintf(addr6, sizeof(addr6), "%s:%s:%s:%s:%s:%s:%s:%s",
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000621 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
622 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000623 inet_pton(AF_INET6, addr6, (struct sockaddr *) &saddr6.sin6_addr);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000624 saddr6.sin6_family = AF_INET6;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000625
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000626 INET6_rresolve(addr6, sizeof(addr6), (struct sockaddr_in6 *) &saddr6,
627 numeric);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000628 snprintf(addr6, sizeof(addr6), "%s/%d", addr6, prefix_len);
629
630 /* Fetch and resolve the nexthop address. */
631 snprintf(naddr6, sizeof(naddr6), "%s:%s:%s:%s:%s:%s:%s:%s",
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000632 naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
633 naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7]);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000634 inet_pton(AF_INET6, naddr6, (struct sockaddr *) &snaddr6.sin6_addr);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000635 snaddr6.sin6_family = AF_INET6;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000636
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000637 INET6_rresolve(naddr6, sizeof(naddr6),
638 (struct sockaddr_in6 *) &snaddr6, numeric);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000639
640 /* Print the info. */
641 printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000642 addr6, naddr6, flags, metric, refcnt, use, iface);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000643 }
644}
645#endif
646
Eric Andersenec455952001-02-14 08:11:27 +0000647int route_main(int argc, char **argv)
648{
Robert Griebl820098f2002-05-14 23:03:23 +0000649 int opt;
Eric Andersenec455952001-02-14 08:11:27 +0000650 int what = 0;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000651
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000652#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000653 int af = AF_INET;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000654#endif
Eric Andersenec455952001-02-14 08:11:27 +0000655
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000656 if (!argv[1] || (argv[1][0] == '-')) {
Robert Griebl820098f2002-05-14 23:03:23 +0000657 /* check options */
658 int noresolve = 0;
659 int extended = 0;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000660
Eric Andersen51b8bd62002-07-03 11:46:38 +0000661 while ((opt = getopt(argc, argv, "A:ne")) > 0) {
Robert Griebl820098f2002-05-14 23:03:23 +0000662 switch (opt) {
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000663 case 'n':
664 noresolve = 1;
665 break;
666 case 'e':
667 extended = 1;
668 break;
669 case 'A':
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000670#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000671 if (strcmp(optarg, "inet6") == 0)
672 af = AF_INET6;
673 break;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000674#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000675 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000676 bb_show_usage();
Robert Griebl820098f2002-05-14 23:03:23 +0000677 }
678 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000679
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000680#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000681 if (af == AF_INET6)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000682 INET6_displayroutes(*argv != NULL);
683 else
684#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000685 displayroutes(noresolve, extended);
Eric Andersen26d53eb2001-03-07 06:33:01 +0000686 return EXIT_SUCCESS;
Eric Andersenec455952001-02-14 08:11:27 +0000687 } else {
688 /* check verb */
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000689 if (strcmp(argv[1], "add") == 0)
Eric Andersenec455952001-02-14 08:11:27 +0000690 what = RTACTION_ADD;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000691 else if (strcmp(argv[1], "del") == 0
692 || strcmp(argv[1], "delete") == 0)
Eric Andersenec455952001-02-14 08:11:27 +0000693 what = RTACTION_DEL;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000694 else if (strcmp(argv[1], "flush") == 0)
Eric Andersenec455952001-02-14 08:11:27 +0000695 what = RTACTION_FLUSH;
696 else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000697 bb_show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000698 }
699
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000700#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000701 if (af == AF_INET6)
702 return INET6_setroute(what, 0, argv + 2);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000703#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000704 return INET_setroute(what, 0, argv + 2);
Eric Andersenec455952001-02-14 08:11:27 +0000705}