3 * Similar to the standard Unix route, but with only the necessary
6 * Bjorn Wesen, Axis Communications AB
8 * Author of the original route:
9 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
10 * (derived from FvK's 'route.c 1.70 01/04/94')
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.
18 * $Id: route.c,v 1.1 2001/02/14 08:11:27 andersen Exp $
23 #include <sys/types.h>
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <net/route.h>
27 #include <linux/param.h> // HZ
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
41 #define RTACTION_ADD 1
42 #define RTACTION_DEL 2
43 #define RTACTION_HELP 3
44 #define RTACTION_FLUSH 4
45 #define RTACTION_SHOW 5
56 /* resolve XXX.YYY.ZZZ.QQQ -> binary */
59 INET_resolve(char *name, struct sockaddr *sa)
61 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
63 sin->sin_family = AF_INET;
66 /* Default is special, meaning 0.0.0.0. */
67 if (!strcmp(name, "default")) {
68 sin->sin_addr.s_addr = INADDR_ANY;
71 /* Look to see if it's a dotted quad. */
72 if (inet_aton(name, &sin->sin_addr)) {
79 #if defined (SIOCADDRTOLD) || defined (RTF_IRTT) /* route */
80 #define HAVE_NEW_ADDRT 1
82 #ifdef RTF_IRTT /* route */
83 #define HAVE_RTF_IRTT 1
85 #ifdef RTF_REJECT /* route */
86 #define HAVE_RTF_REJECT 1
90 #define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
91 #define full_mask(x) (x)
93 #define mask_in_addr(x) ((x).rt_genmask)
94 #define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
97 /* add or delete a route depending on action */
100 INET_setroute(int action, int options, char **args)
103 char target[128], gateway[128] = "NONE", netmask[128] = "default";
109 if (!strcmp(*args, "-net")) {
112 } else if (!strcmp(*args, "-host")) {
119 safe_strncpy(target, *args++, (sizeof target));
121 /* Clean out the RTREQ structure. */
122 memset((char *) &rt, 0, sizeof(struct rtentry));
125 if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) {
126 fprintf(stderr, "cant resolve %s\n", target);
143 /* Fill in the other fields. */
144 rt.rt_flags = (RTF_UP | RTF_HOST);
146 rt.rt_flags &= ~RTF_HOST;
149 if (!strcmp(*args, "metric")) {
153 if (!*args || !isdigit(**args))
155 metric = atoi(*args);
157 rt.rt_metric = metric + 1;
159 ENOSUPP("inet_setroute", "NEW_ADDRT (metric)");
165 if (!strcmp(*args, "netmask")) {
166 struct sockaddr mask;
169 if (!*args || mask_in_addr(rt))
171 safe_strncpy(netmask, *args, (sizeof netmask));
172 if ((isnet = INET_resolve(netmask, &mask)) < 0) {
173 fprintf(stderr, "cant resolve netmask %s\n", netmask);
176 rt.rt_genmask = full_mask(mask);
181 if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
185 if (rt.rt_flags & RTF_GATEWAY)
187 safe_strncpy(gateway, *args, (sizeof gateway));
188 if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) {
189 fprintf(stderr, "cant resolve gw %s\n", gateway);
194 _("route: %s: cannot use a NETWORK as gateway!\n"),
198 rt.rt_flags |= RTF_GATEWAY;
203 if (!strcmp(*args, "mss")) {
205 rt.rt_flags |= RTF_MSS;
208 rt.rt_mss = atoi(*args);
210 if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
211 fprintf(stderr, _("route: Invalid MSS.\n"));
217 if (!strcmp(*args, "window")) {
221 rt.rt_flags |= RTF_WINDOW;
222 rt.rt_window = atoi(*args);
224 if (rt.rt_window < 128) {
225 fprintf(stderr, _("route: Invalid window.\n"));
231 if (!strcmp(*args, "irtt")) {
237 rt.rt_flags |= RTF_IRTT;
238 rt.rt_irtt = atoi(*(args - 1));
239 rt.rt_irtt *= (HZ / 100); /* FIXME */
240 #if 0 /* FIXME: do we need to check anything of this? */
241 if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
242 fprintf(stderr, _("route: Invalid initial rtt.\n"));
247 ENOSUPP("inet_setroute", "RTF_IRTT");
252 if (!strcmp(*args, "reject")) {
255 rt.rt_flags |= RTF_REJECT;
257 ENOSUPP("inet_setroute", "RTF_REJECT");
261 if (!strcmp(*args, "mod")) {
263 rt.rt_flags |= RTF_MODIFIED;
266 if (!strcmp(*args, "dyn")) {
268 rt.rt_flags |= RTF_DYNAMIC;
271 if (!strcmp(*args, "reinstate")) {
273 rt.rt_flags |= RTF_REINSTATE;
276 if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
278 if (rt.rt_dev || *args == NULL)
283 /* nothing matches */
287 usage(route_usage); /* must be last to catch typos */
293 if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
297 /* sanity checks.. */
298 if (mask_in_addr(rt)) {
299 unsigned long mask = mask_in_addr(rt);
301 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
303 _("route: netmask %.8x doesn't make sense with host route\n"),
307 if (mask & (mask + 1)) {
308 fprintf(stderr, _("route: bogus netmask %s\n"), netmask);
311 mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
312 if (mask & ~mask_in_addr(rt)) {
313 fprintf(stderr, _("route: netmask doesn't match route address\n"));
317 /* Fill out netmask if still unset */
318 if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
319 mask_in_addr(rt) = 0xffffffff;
321 /* Create a socket to the INET kernel. */
322 if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
326 /* Tell the kernel to accept this route. */
327 if (action == RTACTION_DEL) {
328 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
334 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
341 /* Close the socket. */
346 int route_main(int argc, char **argv)
355 fprintf(stderr, "print routes is not implemented yet\n");
359 if (!strcmp(*argv, "add"))
361 else if (!strcmp(*argv, "del") || !strcmp(*argv, "delete"))
363 else if (!strcmp(*argv, "flush"))
364 what = RTACTION_FLUSH;
369 INET_setroute(what, 0, ++argv);