aboutsummaryrefslogtreecommitdiff
path: root/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'route.c')
-rw-r--r--route.c372
1 files changed, 372 insertions, 0 deletions
diff --git a/route.c b/route.c
new file mode 100644
index 000000000..76b2306fd
--- /dev/null
+++ b/route.c
@@ -0,0 +1,372 @@
1/* route
2 *
3 * Similar to the standard Unix route, but with only the necessary
4 * parts for AF_INET
5 *
6 * Bjorn Wesen, Axis Communications AB
7 *
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')
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 *
18 * $Id: route.c,v 1.1 2001/02/14 08:11:27 andersen Exp $
19 *
20 */
21
22#include "busybox.h"
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>
30#include <stdio.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <stdlib.h>
34#include <string.h>
35#include <getopt.h>
36#include <unistd.h>
37#include <ctype.h>
38
39#define _(x) x
40
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
46
47#define E_NOTFOUND 8
48#define E_SOCK 7
49#define E_LOOKUP 6
50#define E_VERSION 5
51#define E_USAGE 4
52#define E_OPTERR 3
53#define E_INTERN 2
54#define E_NOSUPP 1
55
56/* resolve XXX.YYY.ZZZ.QQQ -> binary */
57
58static int
59INET_resolve(char *name, struct sockaddr *sa)
60{
61 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
62
63 sin->sin_family = AF_INET;
64 sin->sin_port = 0;
65
66 /* Default is special, meaning 0.0.0.0. */
67 if (!strcmp(name, "default")) {
68 sin->sin_addr.s_addr = INADDR_ANY;
69 return (1);
70 }
71 /* Look to see if it's a dotted quad. */
72 if (inet_aton(name, &sin->sin_addr)) {
73 return 0;
74 }
75 /* guess not.. */
76 return -1;
77}
78
79#if defined (SIOCADDRTOLD) || defined (RTF_IRTT) /* route */
80#define HAVE_NEW_ADDRT 1
81#endif
82#ifdef RTF_IRTT /* route */
83#define HAVE_RTF_IRTT 1
84#endif
85#ifdef RTF_REJECT /* route */
86#define HAVE_RTF_REJECT 1
87#endif
88
89#if HAVE_NEW_ADDRT
90#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
91#define full_mask(x) (x)
92#else
93#define mask_in_addr(x) ((x).rt_genmask)
94#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
95#endif
96
97/* add or delete a route depending on action */
98
99static int
100INET_setroute(int action, int options, char **args)
101{
102 struct rtentry rt;
103 char target[128], gateway[128] = "NONE", netmask[128] = "default";
104 int xflag, isnet;
105 int skfd;
106
107 xflag = 0;
108
109 if (!strcmp(*args, "-net")) {
110 xflag = 1;
111 args++;
112 } else if (!strcmp(*args, "-host")) {
113 xflag = 2;
114 args++;
115 }
116 if (*args == NULL)
117 usage(route_usage);
118
119 safe_strncpy(target, *args++, (sizeof target));
120
121 /* Clean out the RTREQ structure. */
122 memset((char *) &rt, 0, sizeof(struct rtentry));
123
124
125 if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) {
126 fprintf(stderr, "cant resolve %s\n", target);
127 return (1);
128 }
129
130 switch (xflag) {
131 case 1:
132 isnet = 1;
133 break;
134
135 case 2:
136 isnet = 0;
137 break;
138
139 default:
140 break;
141 }
142
143 /* Fill in the other fields. */
144 rt.rt_flags = (RTF_UP | RTF_HOST);
145 if (isnet)
146 rt.rt_flags &= ~RTF_HOST;
147
148 while (*args) {
149 if (!strcmp(*args, "metric")) {
150 int metric;
151
152 args++;
153 if (!*args || !isdigit(**args))
154 usage(route_usage);
155 metric = atoi(*args);
156#if HAVE_NEW_ADDRT
157 rt.rt_metric = metric + 1;
158#else
159 ENOSUPP("inet_setroute", "NEW_ADDRT (metric)");
160#endif
161 args++;
162 continue;
163 }
164
165 if (!strcmp(*args, "netmask")) {
166 struct sockaddr mask;
167
168 args++;
169 if (!*args || mask_in_addr(rt))
170 usage(route_usage);
171 safe_strncpy(netmask, *args, (sizeof netmask));
172 if ((isnet = INET_resolve(netmask, &mask)) < 0) {
173 fprintf(stderr, "cant resolve netmask %s\n", netmask);
174 return (E_LOOKUP);
175 }
176 rt.rt_genmask = full_mask(mask);
177 args++;
178 continue;
179 }
180
181 if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
182 args++;
183 if (!*args)
184 usage(route_usage);
185 if (rt.rt_flags & RTF_GATEWAY)
186 usage(route_usage);
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);
190 return (E_LOOKUP);
191 }
192 if (isnet) {
193 fprintf(stderr,
194 _("route: %s: cannot use a NETWORK as gateway!\n"),
195 gateway);
196 return (E_OPTERR);
197 }
198 rt.rt_flags |= RTF_GATEWAY;
199 args++;
200 continue;
201 }
202
203 if (!strcmp(*args, "mss")) {
204 args++;
205 rt.rt_flags |= RTF_MSS;
206 if (!*args)
207 usage(route_usage);
208 rt.rt_mss = atoi(*args);
209 args++;
210 if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
211 fprintf(stderr, _("route: Invalid MSS.\n"));
212 return (E_OPTERR);
213 }
214 continue;
215 }
216
217 if (!strcmp(*args, "window")) {
218 args++;
219 if (!*args)
220 usage(route_usage);
221 rt.rt_flags |= RTF_WINDOW;
222 rt.rt_window = atoi(*args);
223 args++;
224 if (rt.rt_window < 128) {
225 fprintf(stderr, _("route: Invalid window.\n"));
226 return (E_OPTERR);
227 }
228 continue;
229 }
230
231 if (!strcmp(*args, "irtt")) {
232 args++;
233 if (!*args)
234 usage(route_usage);
235 args++;
236#if HAVE_RTF_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"));
243 return (E_OPTERR);
244 }
245#endif
246#else
247 ENOSUPP("inet_setroute", "RTF_IRTT");
248#endif
249 continue;
250 }
251
252 if (!strcmp(*args, "reject")) {
253 args++;
254#if HAVE_RTF_REJECT
255 rt.rt_flags |= RTF_REJECT;
256#else
257 ENOSUPP("inet_setroute", "RTF_REJECT");
258#endif
259 continue;
260 }
261 if (!strcmp(*args, "mod")) {
262 args++;
263 rt.rt_flags |= RTF_MODIFIED;
264 continue;
265 }
266 if (!strcmp(*args, "dyn")) {
267 args++;
268 rt.rt_flags |= RTF_DYNAMIC;
269 continue;
270 }
271 if (!strcmp(*args, "reinstate")) {
272 args++;
273 rt.rt_flags |= RTF_REINSTATE;
274 continue;
275 }
276 if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
277 args++;
278 if (rt.rt_dev || *args == NULL)
279 usage(route_usage);
280 rt.rt_dev = *args++;
281 continue;
282 }
283 /* nothing matches */
284 if (!rt.rt_dev) {
285 rt.rt_dev = *args++;
286 if (*args)
287 usage(route_usage); /* must be last to catch typos */
288 } else
289 usage(route_usage);
290 }
291
292#if HAVE_RTF_REJECT
293 if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
294 rt.rt_dev = "lo";
295#endif
296
297 /* sanity checks.. */
298 if (mask_in_addr(rt)) {
299 unsigned long mask = mask_in_addr(rt);
300 mask = ~ntohl(mask);
301 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
302 fprintf(stderr,
303 _("route: netmask %.8x doesn't make sense with host route\n"),
304 (unsigned int)mask);
305 return (E_OPTERR);
306 }
307 if (mask & (mask + 1)) {
308 fprintf(stderr, _("route: bogus netmask %s\n"), netmask);
309 return (E_OPTERR);
310 }
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"));
314 return (E_OPTERR);
315 }
316 }
317 /* Fill out netmask if still unset */
318 if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
319 mask_in_addr(rt) = 0xffffffff;
320
321 /* Create a socket to the INET kernel. */
322 if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
323 perror("socket");
324 return (E_SOCK);
325 }
326 /* Tell the kernel to accept this route. */
327 if (action == RTACTION_DEL) {
328 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
329 perror("SIOCDELRT");
330 close(skfd);
331 return (E_SOCK);
332 }
333 } else {
334 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
335 perror("SIOCADDRT");
336 close(skfd);
337 return (E_SOCK);
338 }
339 }
340
341 /* Close the socket. */
342 (void) close(skfd);
343 return (0);
344}
345
346int route_main(int argc, char **argv)
347{
348 int what = 0;
349
350 argc--;
351 argv++;
352
353 if (*argv == NULL) {
354 //displayroutes();
355 fprintf(stderr, "print routes is not implemented yet\n");
356 usage(route_usage);
357 } else {
358 /* check verb */
359 if (!strcmp(*argv, "add"))
360 what = RTACTION_ADD;
361 else if (!strcmp(*argv, "del") || !strcmp(*argv, "delete"))
362 what = RTACTION_DEL;
363 else if (!strcmp(*argv, "flush"))
364 what = RTACTION_FLUSH;
365 else
366 usage(route_usage);
367 }
368
369 INET_setroute(what, 0, ++argv);
370
371 exit(0);
372}