blob: d4c65f8cdba3bb8d80edeb6098e473cfb5f645ad [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 *
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +000018 * $Id: route.c,v 1.19 2002/11/26 09:02:06 bug1 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>
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000031#include <linux/param.h> /* HZ */
Eric Andersenec455952001-02-14 08:11:27 +000032#include <stdio.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <stdlib.h>
36#include <string.h>
37#include <getopt.h>
38#include <unistd.h>
39#include <ctype.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000040#include "busybox.h"
Eric Andersenec455952001-02-14 08:11:27 +000041
42#define _(x) x
43
44#define RTACTION_ADD 1
45#define RTACTION_DEL 2
46#define RTACTION_HELP 3
47#define RTACTION_FLUSH 4
48#define RTACTION_SHOW 5
49
50#define E_NOTFOUND 8
51#define E_SOCK 7
52#define E_LOOKUP 6
53#define E_VERSION 5
54#define E_USAGE 4
55#define E_OPTERR 3
56#define E_INTERN 2
57#define E_NOSUPP 1
58
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000059#if defined (SIOCADDRTOLD) || defined (RTF_IRTT) /* route */
Eric Andersenec455952001-02-14 08:11:27 +000060#define HAVE_NEW_ADDRT 1
61#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000062#ifdef RTF_IRTT /* route */
Eric Andersenec455952001-02-14 08:11:27 +000063#define HAVE_RTF_IRTT 1
64#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000065#ifdef RTF_REJECT /* route */
Eric Andersenec455952001-02-14 08:11:27 +000066#define HAVE_RTF_REJECT 1
67#endif
68
69#if HAVE_NEW_ADDRT
70#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
71#define full_mask(x) (x)
72#else
73#define mask_in_addr(x) ((x).rt_genmask)
74#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
75#endif
76
Eric Andersencd8c4362001-11-10 11:22:46 +000077
78
Eric Andersenec455952001-02-14 08:11:27 +000079/* add or delete a route depending on action */
80
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000081static int INET_setroute(int action, int options, char **args)
Eric Andersenec455952001-02-14 08:11:27 +000082{
83 struct rtentry rt;
Eric Andersencd8c4362001-11-10 11:22:46 +000084 char target[128], gateway[128] = "NONE";
85 const char *netmask = bb_INET_default;
Eric Andersenec455952001-02-14 08:11:27 +000086 int xflag, isnet;
87 int skfd;
88
89 xflag = 0;
90
Eric Andersena3c84812001-08-23 22:05:33 +000091 if (*args == NULL)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000092 show_usage();
93 if (strcmp(*args, "-net") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +000094 xflag = 1;
95 args++;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +000096 } else if (strcmp(*args, "-host") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +000097 xflag = 2;
98 args++;
99 }
Eric Andersencd8c4362001-11-10 11:22:46 +0000100 if (*args == NULL)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000101 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000102 safe_strncpy(target, *args++, (sizeof target));
103
104 /* Clean out the RTREQ structure. */
105 memset((char *) &rt, 0, sizeof(struct rtentry));
106
107
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000108 if ((isnet =
109 INET_resolve(target, (struct sockaddr_in *) &rt.rt_dst,
110 xflag != 1)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000111 error_msg(_("can't resolve %s"), target);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000112 return EXIT_FAILURE; /* XXX change to E_something */
Eric Andersenec455952001-02-14 08:11:27 +0000113 }
114
115 switch (xflag) {
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000116 case 1:
117 isnet = 1;
118 break;
Eric Andersenb9408502001-09-05 19:32:00 +0000119
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000120 case 2:
121 isnet = 0;
122 break;
Eric Andersenb9408502001-09-05 19:32:00 +0000123
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000124 default:
125 break;
Eric Andersenec455952001-02-14 08:11:27 +0000126 }
Eric Andersenb9408502001-09-05 19:32:00 +0000127
Eric Andersenec455952001-02-14 08:11:27 +0000128 /* Fill in the other fields. */
129 rt.rt_flags = (RTF_UP | RTF_HOST);
130 if (isnet)
131 rt.rt_flags &= ~RTF_HOST;
132
133 while (*args) {
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000134 if (strcmp(*args, "metric") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000135 int metric;
Eric Andersenb9408502001-09-05 19:32:00 +0000136
Eric Andersenec455952001-02-14 08:11:27 +0000137 args++;
138 if (!*args || !isdigit(**args))
Eric Andersen67991cf2001-02-14 21:23:06 +0000139 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000140 metric = atoi(*args);
141#if HAVE_NEW_ADDRT
142 rt.rt_metric = metric + 1;
143#else
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000144 ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000145#endif
146 args++;
147 continue;
148 }
149
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000150 if (strcmp(*args, "netmask") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000151 struct sockaddr mask;
Eric Andersenb9408502001-09-05 19:32:00 +0000152
Eric Andersenec455952001-02-14 08:11:27 +0000153 args++;
154 if (!*args || mask_in_addr(rt))
Eric Andersen67991cf2001-02-14 21:23:06 +0000155 show_usage();
Eric Andersencd8c4362001-11-10 11:22:46 +0000156 netmask = *args;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000157 if ((isnet =
158 INET_resolve(netmask, (struct sockaddr_in *) &mask,
159 0)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000160 error_msg(_("can't resolve netmask %s"), netmask);
161 return E_LOOKUP;
Eric Andersenec455952001-02-14 08:11:27 +0000162 }
163 rt.rt_genmask = full_mask(mask);
164 args++;
165 continue;
166 }
167
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000168 if (strcmp(*args, "gw") == 0 || strcmp(*args, "gateway") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000169 args++;
170 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000171 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000172 if (rt.rt_flags & RTF_GATEWAY)
Eric Andersen67991cf2001-02-14 21:23:06 +0000173 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000174 safe_strncpy(gateway, *args, (sizeof gateway));
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000175 if ((isnet =
176 INET_resolve(gateway, (struct sockaddr_in *) &rt.rt_gateway,
177 1)) < 0) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000178 error_msg(_("can't resolve gw %s"), gateway);
179 return E_LOOKUP;
Eric Andersenec455952001-02-14 08:11:27 +0000180 }
181 if (isnet) {
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000182 error_msg(_("%s: cannot use a NETWORK as gateway!"), gateway);
Mark Whitley99806ad2001-02-15 23:00:48 +0000183 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000184 }
185 rt.rt_flags |= RTF_GATEWAY;
186 args++;
187 continue;
188 }
189
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000190 if (strcmp(*args, "mss") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000191 args++;
192 rt.rt_flags |= RTF_MSS;
193 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000194 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000195 rt.rt_mss = atoi(*args);
196 args++;
197 if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000198 error_msg(_("Invalid MSS."));
199 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000200 }
201 continue;
202 }
203
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000204 if (strcmp(*args, "window") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000205 args++;
206 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000207 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000208 rt.rt_flags |= RTF_WINDOW;
209 rt.rt_window = atoi(*args);
210 args++;
211 if (rt.rt_window < 128) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000212 error_msg(_("Invalid window."));
213 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000214 }
215 continue;
216 }
217
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000218 if (strcmp(*args, "irtt") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000219 args++;
220 if (!*args)
Eric Andersen67991cf2001-02-14 21:23:06 +0000221 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000222 args++;
223#if HAVE_RTF_IRTT
224 rt.rt_flags |= RTF_IRTT;
225 rt.rt_irtt = atoi(*(args - 1));
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000226 rt.rt_irtt *= (HZ / 100); /* FIXME */
227#if 0 /* FIXME: do we need to check anything of this? */
Eric Andersenec455952001-02-14 08:11:27 +0000228 if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000229 error_msg(_("Invalid initial rtt."));
230 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000231 }
232#endif
233#else
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000234 ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000235#endif
236 continue;
237 }
238
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000239 if (strcmp(*args, "reject") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000240 args++;
241#if HAVE_RTF_REJECT
242 rt.rt_flags |= RTF_REJECT;
243#else
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000244 ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */
Eric Andersenec455952001-02-14 08:11:27 +0000245#endif
246 continue;
247 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000248 if (strcmp(*args, "mod") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000249 args++;
250 rt.rt_flags |= RTF_MODIFIED;
251 continue;
252 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000253 if (strcmp(*args, "dyn") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000254 args++;
255 rt.rt_flags |= RTF_DYNAMIC;
256 continue;
257 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000258 if (strcmp(*args, "reinstate") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000259 args++;
260 rt.rt_flags |= RTF_REINSTATE;
261 continue;
262 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000263 if (strcmp(*args, "device") == 0 || strcmp(*args, "dev") == 0) {
Eric Andersenec455952001-02-14 08:11:27 +0000264 args++;
265 if (rt.rt_dev || *args == NULL)
Eric Andersen67991cf2001-02-14 21:23:06 +0000266 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000267 rt.rt_dev = *args++;
268 continue;
269 }
270 /* nothing matches */
271 if (!rt.rt_dev) {
272 rt.rt_dev = *args++;
273 if (*args)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000274 show_usage(); /* must be last to catch typos */
Mark Whitley99806ad2001-02-15 23:00:48 +0000275 } else {
Eric Andersen67991cf2001-02-14 21:23:06 +0000276 show_usage();
Mark Whitley99806ad2001-02-15 23:00:48 +0000277 }
Eric Andersenec455952001-02-14 08:11:27 +0000278 }
279
280#if HAVE_RTF_REJECT
281 if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
282 rt.rt_dev = "lo";
283#endif
284
285 /* sanity checks.. */
286 if (mask_in_addr(rt)) {
287 unsigned long mask = mask_in_addr(rt);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000288
Eric Andersenec455952001-02-14 08:11:27 +0000289 mask = ~ntohl(mask);
290 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000291 error_msg(_("netmask %.8x doesn't make sense with host route"),
292 (unsigned int) mask);
Mark Whitley99806ad2001-02-15 23:00:48 +0000293 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000294 }
295 if (mask & (mask + 1)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000296 error_msg(_("bogus netmask %s"), netmask);
297 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000298 }
299 mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
300 if (mask & ~mask_in_addr(rt)) {
Mark Whitley99806ad2001-02-15 23:00:48 +0000301 error_msg(_("netmask doesn't match route address"));
302 return E_OPTERR;
Eric Andersenec455952001-02-14 08:11:27 +0000303 }
304 }
305 /* Fill out netmask if still unset */
306 if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
307 mask_in_addr(rt) = 0xffffffff;
308
309 /* Create a socket to the INET kernel. */
310 if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
311 perror("socket");
Mark Whitley99806ad2001-02-15 23:00:48 +0000312 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000313 }
314 /* Tell the kernel to accept this route. */
315 if (action == RTACTION_DEL) {
316 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
317 perror("SIOCDELRT");
318 close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000319 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000320 }
321 } else {
322 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
323 perror("SIOCADDRT");
324 close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000325 return E_SOCK;
Eric Andersenec455952001-02-14 08:11:27 +0000326 }
327 }
Eric Andersenb9408502001-09-05 19:32:00 +0000328
Eric Andersenec455952001-02-14 08:11:27 +0000329 /* Close the socket. */
330 (void) close(skfd);
Mark Whitley99806ad2001-02-15 23:00:48 +0000331 return EXIT_SUCCESS;
Eric Andersenec455952001-02-14 08:11:27 +0000332}
333
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000334#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000335static int INET6_setroute(int action, int options, char **args)
336{
337 struct in6_rtmsg rt;
338 struct ifreq ifr;
339 struct sockaddr_in6 sa6;
340 char target[128], gateway[128] = "NONE";
341 int metric, prefix_len;
342 char *devname = NULL;
343 char *cp;
344 int skfd;
345
346 if (*args == NULL)
347 show_usage();
348
349 strcpy(target, *args++);
350 if (!strcmp(target, "default")) {
351 prefix_len = 0;
352 memset(&sa6, 0, sizeof(sa6));
353 } else {
354 if ((cp = strchr(target, '/'))) {
355 prefix_len = atol(cp + 1);
356 if ((prefix_len < 0) || (prefix_len > 128))
357 show_usage();
358 *cp = 0;
359 } else {
360 prefix_len = 128;
361 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000362 if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) {
Eric Andersen51b8bd62002-07-03 11:46:38 +0000363 error_msg(_("can't resolve %s"), target);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000364 return EXIT_FAILURE; /* XXX change to E_something */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000365 }
366 }
367
368 /* Clean out the RTREQ structure. */
369 memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
370
371 memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
372
373 /* Fill in the other fields. */
374 rt.rtmsg_flags = RTF_UP;
375 if (prefix_len == 128)
376 rt.rtmsg_flags |= RTF_HOST;
377 rt.rtmsg_metric = 1;
378 rt.rtmsg_dst_len = prefix_len;
379
380 while (*args) {
381 if (!strcmp(*args, "metric")) {
382
383 args++;
384 if (!*args || !isdigit(**args))
385 show_usage();
386 metric = atoi(*args);
387 rt.rtmsg_metric = metric;
388 args++;
389 continue;
390 }
391 if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
392 args++;
393 if (!*args)
394 show_usage();
395 if (rt.rtmsg_flags & RTF_GATEWAY)
396 show_usage();
397 strcpy(gateway, *args);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000398 if (INET6_resolve(gateway, (struct sockaddr_in6 *) &sa6) < 0) {
Eric Andersen51b8bd62002-07-03 11:46:38 +0000399 error_msg(_("can't resolve gw %s"), gateway);
400 return (E_LOOKUP);
401 }
402 memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000403 sizeof(struct in6_addr));
Eric Andersen51b8bd62002-07-03 11:46:38 +0000404 rt.rtmsg_flags |= RTF_GATEWAY;
405 args++;
406 continue;
407 }
408 if (!strcmp(*args, "mod")) {
409 args++;
410 rt.rtmsg_flags |= RTF_MODIFIED;
411 continue;
412 }
413 if (!strcmp(*args, "dyn")) {
414 args++;
415 rt.rtmsg_flags |= RTF_DYNAMIC;
416 continue;
417 }
418 if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
419 args++;
420 if (!*args)
421 show_usage();
422 } else if (args[1])
423 show_usage();
424
425 devname = *args;
426 args++;
427 }
428
429 /* Create a socket to the INET6 kernel. */
430 if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
431 perror("socket");
432 return (E_SOCK);
433 }
434 if (devname) {
435 memset(&ifr, 0, sizeof(ifr));
436 strcpy(ifr.ifr_name, devname);
437
438 if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) {
439 perror("SIOGIFINDEX");
440 return (E_SOCK);
441 }
442 rt.rtmsg_ifindex = ifr.ifr_ifindex;
443 } else
444 rt.rtmsg_ifindex = 0;
445
446 /* Tell the kernel to accept this route. */
447 if (action == RTACTION_DEL) {
448 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
449 perror("SIOCDELRT");
450 close(skfd);
451 return (E_SOCK);
452 }
453 } else {
454 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
455 perror("SIOCADDRT");
456 close(skfd);
457 return (E_SOCK);
458 }
459 }
460
461 /* Close the socket. */
462 (void) close(skfd);
463 return (0);
464}
465#endif
466
Eric Andersen863a3e12001-08-27 17:57:27 +0000467#ifndef RTF_UP
468/* Keep this in sync with /usr/src/linux/include/linux/route.h */
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000469#define RTF_UP 0x0001 /* route usable */
470#define RTF_GATEWAY 0x0002 /* destination is a gateway */
471#define RTF_HOST 0x0004 /* host entry (net otherwise) */
472#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */
473#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
474#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
475#define RTF_MTU 0x0040 /* specific MTU for this route */
Eric Andersen863a3e12001-08-27 17:57:27 +0000476#ifndef RTF_MSS
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000477#define RTF_MSS RTF_MTU /* Compatibility :-( */
Eric Andersen863a3e12001-08-27 17:57:27 +0000478#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000479#define RTF_WINDOW 0x0080 /* per route window clamping */
480#define RTF_IRTT 0x0100 /* Initial round trip time */
481#define RTF_REJECT 0x0200 /* Reject route */
Eric Andersen863a3e12001-08-27 17:57:27 +0000482#endif
483
Robert Griebl820098f2002-05-14 23:03:23 +0000484void displayroutes(int noresolve, int netstatfmt)
Eric Andersen68be2ab2001-02-14 19:26:39 +0000485{
486 char buff[256];
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000487 int nl = 0;
Eric Andersen68be2ab2001-02-14 19:26:39 +0000488 struct in_addr dest;
489 struct in_addr gw;
490 struct in_addr mask;
Robert Griebl820098f2002-05-14 23:03:23 +0000491 int flgs, ref, use, metric, mtu, win, ir;
Eric Andersenb9408502001-09-05 19:32:00 +0000492 char flags[64];
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000493 unsigned long int d, g, m;
Eric Andersen68be2ab2001-02-14 19:26:39 +0000494
495 char sdest[16], sgw[16];
496
Eric Andersenf1bbb222001-02-18 20:12:25 +0000497 FILE *fp = xfopen("/proc/net/route", "r");
Eric Andersen68be2ab2001-02-14 19:26:39 +0000498
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000499 if (noresolve)
Eric Andersencd8c4362001-11-10 11:22:46 +0000500 noresolve = 0x0fff;
501
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000502 while (fgets(buff, sizeof(buff), fp) != NULL) {
503 if (nl) {
Eric Andersen68be2ab2001-02-14 19:26:39 +0000504 int ifl = 0;
Eric Andersencd8c4362001-11-10 11:22:46 +0000505 int numeric;
506 struct sockaddr_in s_addr;
507
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000508 while (buff[ifl] != ' ' && buff[ifl] != '\t' && buff[ifl] != '\0')
Eric Andersen68be2ab2001-02-14 19:26:39 +0000509 ifl++;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000510 buff[ifl] = 0; /* interface */
511 if (sscanf(buff + ifl + 1, "%lx%lx%X%d%d%d%lx%d%d%d",
512 &d, &g, &flgs, &ref, &use, &metric, &m, &mtu, &win,
513 &ir) != 10) {
514 error_msg_and_die("Unsuported kernel route format\n");
Eric Andersen68be2ab2001-02-14 19:26:39 +0000515 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000516 if (nl == 1) {
Robert Griebl820098f2002-05-14 23:03:23 +0000517 printf("Kernel IP routing table\n");
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000518 printf
519 ("Destination Gateway Genmask Flags %s Iface\n",
520 netstatfmt ? " MSS Window irtt" : "Metric Ref Use");
Robert Griebl820098f2002-05-14 23:03:23 +0000521 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000522 ifl = 0; /* parse flags */
523 if (flgs & RTF_UP) {
524 if (flgs & RTF_REJECT)
525 flags[ifl++] = '!';
526 else
527 flags[ifl++] = 'U';
528 if (flgs & RTF_GATEWAY)
529 flags[ifl++] = 'G';
530 if (flgs & RTF_HOST)
531 flags[ifl++] = 'H';
532 if (flgs & RTF_REINSTATE)
533 flags[ifl++] = 'R';
534 if (flgs & RTF_DYNAMIC)
535 flags[ifl++] = 'D';
536 if (flgs & RTF_MODIFIED)
537 flags[ifl++] = 'M';
538 flags[ifl] = 0;
539 dest.s_addr = d;
540 gw.s_addr = g;
541 mask.s_addr = m;
Eric Andersencd8c4362001-11-10 11:22:46 +0000542 memset(&s_addr, 0, sizeof(struct sockaddr_in));
543 s_addr.sin_family = AF_INET;
544 s_addr.sin_addr = dest;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000545 numeric = noresolve | 0x8000; /* default instead of * */
Eric Andersencd8c4362001-11-10 11:22:46 +0000546 INET_rresolve(sdest, sizeof(sdest), &s_addr, numeric, m);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000547 numeric = noresolve | 0x4000; /* host instead of net */
Eric Andersencd8c4362001-11-10 11:22:46 +0000548 s_addr.sin_addr = gw;
549 INET_rresolve(sgw, sizeof(sgw), &s_addr, numeric, m);
Robert Grieblc30c5e82002-05-16 19:14:15 +0000550
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000551 printf("%-16s%-16s%-16s%-6s", sdest, sgw, inet_ntoa(mask),
552 flags);
553 if (netstatfmt)
554 printf("%5d %-5d %6d %s\n", mtu, win, ir, buff);
555 else
556 printf("%-6d %-2d %7d %s\n", metric, ref, use, buff);
Eric Andersenb9408502001-09-05 19:32:00 +0000557 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000558 }
Eric Andersenb9408502001-09-05 19:32:00 +0000559 nl++;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000560 }
Eric Andersen68be2ab2001-02-14 19:26:39 +0000561}
562
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000563#ifdef CONFIG_FEATURE_IPV6
Eric Andersen51b8bd62002-07-03 11:46:38 +0000564static void INET6_displayroutes(int noresolve)
565{
566 char buff[256];
567 char iface[16], flags[16];
568 char addr6[128], naddr6[128];
569 struct sockaddr_in6 saddr6, snaddr6;
570 int iflags, metric, refcnt, use, prefix_len, slen;
571 int numeric;
572
573 char addr6p[8][5], saddr6p[8][5], naddr6p[8][5];
574
575 FILE *fp = xfopen("/proc/net/ipv6_route", "r");
Eric Andersen51b8bd62002-07-03 11:46:38 +0000576
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000577 flags[0] = 'U';
578
579 if (noresolve)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000580 noresolve = 0x0fff;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000581 numeric = noresolve | 0x8000; /* default instead of * */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000582
583 printf("Kernel IPv6 routing table\n"
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000584 "Destination "
585 "Next Hop "
586 "Flags Metric Ref Use Iface\n");
Eric Andersen51b8bd62002-07-03 11:46:38 +0000587
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000588 while (fgets(buff, sizeof(buff), fp) != NULL) {
Eric Andersen51b8bd62002-07-03 11:46:38 +0000589 int ifl;
590
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000591 if (sscanf(buff, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
592 "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
593 "%4s%4s%4s%4s%4s%4s%4s%4s %08x %08x %08x %08x %s\n",
594 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
595 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
596 &prefix_len,
597 saddr6p[0], saddr6p[1], saddr6p[2], saddr6p[3],
598 saddr6p[4], saddr6p[5], saddr6p[6], saddr6p[7],
599 &slen,
600 naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
601 naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7],
602 &metric, &use, &refcnt, &iflags, iface) != 31) {
603 error_msg_and_die("Unsuported kernel route format\n");
Eric Andersen51b8bd62002-07-03 11:46:38 +0000604 }
605
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000606 ifl = 1; /* parse flags */
Eric Andersen51b8bd62002-07-03 11:46:38 +0000607 if (!(iflags & RTF_UP))
608 continue;
609 if (iflags & RTF_GATEWAY)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000610 flags[ifl++] = 'G';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000611 if (iflags & RTF_HOST)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000612 flags[ifl++] = 'H';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000613 if (iflags & RTF_DEFAULT)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000614 flags[ifl++] = 'D';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000615 if (iflags & RTF_ADDRCONF)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000616 flags[ifl++] = 'A';
Eric Andersen51b8bd62002-07-03 11:46:38 +0000617 if (iflags & RTF_CACHE)
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000618 flags[ifl++] = 'C';
619 flags[ifl] = 0;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000620
621 /* Fetch and resolve the target address. */
622 snprintf(addr6, sizeof(addr6), "%s:%s:%s:%s:%s:%s:%s:%s",
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000623 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
624 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000625 inet_pton(AF_INET6, addr6, (struct sockaddr *) &saddr6.sin6_addr);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000626 saddr6.sin6_family = AF_INET6;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000627
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000628 INET6_rresolve(addr6, sizeof(addr6), (struct sockaddr_in6 *) &saddr6,
629 numeric);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000630 snprintf(addr6, sizeof(addr6), "%s/%d", addr6, prefix_len);
631
632 /* Fetch and resolve the nexthop address. */
633 snprintf(naddr6, sizeof(naddr6), "%s:%s:%s:%s:%s:%s:%s:%s",
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000634 naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
635 naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7]);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000636 inet_pton(AF_INET6, naddr6, (struct sockaddr *) &snaddr6.sin6_addr);
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000637 snaddr6.sin6_family = AF_INET6;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000638
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000639 INET6_rresolve(naddr6, sizeof(naddr6),
640 (struct sockaddr_in6 *) &snaddr6, numeric);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000641
642 /* Print the info. */
643 printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000644 addr6, naddr6, flags, metric, refcnt, use, iface);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000645 }
646}
647#endif
648
Eric Andersenec455952001-02-14 08:11:27 +0000649int route_main(int argc, char **argv)
650{
Robert Griebl820098f2002-05-14 23:03:23 +0000651 int opt;
Eric Andersenec455952001-02-14 08:11:27 +0000652 int what = 0;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000653
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000654#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000655 int af = AF_INET;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000656#endif
Eric Andersenec455952001-02-14 08:11:27 +0000657
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000658 if (!argv[1] || (argv[1][0] == '-')) {
Robert Griebl820098f2002-05-14 23:03:23 +0000659 /* check options */
660 int noresolve = 0;
661 int extended = 0;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000662
Eric Andersen51b8bd62002-07-03 11:46:38 +0000663 while ((opt = getopt(argc, argv, "A:ne")) > 0) {
Robert Griebl820098f2002-05-14 23:03:23 +0000664 switch (opt) {
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000665 case 'n':
666 noresolve = 1;
667 break;
668 case 'e':
669 extended = 1;
670 break;
671 case 'A':
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000672#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000673 if (strcmp(optarg, "inet6") == 0)
674 af = AF_INET6;
675 break;
Eric Andersen51b8bd62002-07-03 11:46:38 +0000676#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000677 default:
678 show_usage();
Robert Griebl820098f2002-05-14 23:03:23 +0000679 }
680 }
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000681
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000682#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000683 if (af == AF_INET6)
Eric Andersen51b8bd62002-07-03 11:46:38 +0000684 INET6_displayroutes(*argv != NULL);
685 else
686#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000687 displayroutes(noresolve, extended);
Eric Andersen26d53eb2001-03-07 06:33:01 +0000688 return EXIT_SUCCESS;
Eric Andersenec455952001-02-14 08:11:27 +0000689 } else {
690 /* check verb */
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000691 if (strcmp(argv[1], "add") == 0)
Eric Andersenec455952001-02-14 08:11:27 +0000692 what = RTACTION_ADD;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000693 else if (strcmp(argv[1], "del") == 0
694 || strcmp(argv[1], "delete") == 0)
Eric Andersenec455952001-02-14 08:11:27 +0000695 what = RTACTION_DEL;
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000696 else if (strcmp(argv[1], "flush") == 0)
Eric Andersenec455952001-02-14 08:11:27 +0000697 what = RTACTION_FLUSH;
698 else
Eric Andersen67991cf2001-02-14 21:23:06 +0000699 show_usage();
Eric Andersenec455952001-02-14 08:11:27 +0000700 }
701
Glenn L McGrath8ae4cab2002-11-26 09:02:06 +0000702#ifdef CONFIG_FEATURE_IPV6
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000703 if (af == AF_INET6)
704 return INET6_setroute(what, 0, argv + 2);
Eric Andersen51b8bd62002-07-03 11:46:38 +0000705#endif
Glenn L McGrath7c58e9b2002-08-22 18:24:43 +0000706 return INET_setroute(what, 0, argv + 2);
Eric Andersenec455952001-02-14 08:11:27 +0000707}