date and time created 87/10/22 10:11:57 by bostic
[unix-history] / usr / src / sbin / route / route.c
CommitLineData
5ff67f98
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1983 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
4bec325f 13#ifndef lint
e2fe1192 14static char sccsid[] = "@(#)route.c 5.7 (Berkeley) %G%";
5ff67f98 15#endif not lint
4bec325f 16
a2280e64 17#include <sys/param.h>
4bec325f
BJ
18#include <sys/socket.h>
19#include <sys/ioctl.h>
63c817da 20#include <sys/mbuf.h>
94a2d2a7 21
4bec325f 22#include <net/route.h>
94a2d2a7 23#include <netinet/in.h>
eac76d14 24#include <netns/ns.h>
94a2d2a7
SL
25
26#include <stdio.h>
4bec325f
BJ
27#include <errno.h>
28#include <ctype.h>
accbc2e3 29#include <netdb.h>
4bec325f
BJ
30
31struct rtentry route;
4bec325f 32int s;
a2280e64 33int forcehost, forcenet, doflush, nflag;
4bec325f 34struct sockaddr_in sin = { AF_INET };
379dcc38 35struct in_addr inet_makeaddr();
55e026df 36char *malloc();
4bec325f
BJ
37
38main(argc, argv)
39 int argc;
40 char *argv[];
41{
42
43 if (argc < 2)
a2280e64 44 printf("usage: route [ -n ] [ -f ] [ cmd [ net | host ] args ]\n"),
b3933da8 45 exit(1);
f508555e 46 s = socket(AF_INET, SOCK_RAW, 0);
4bec325f 47 if (s < 0) {
5a635333 48 perror("route: socket");
4bec325f
BJ
49 exit(1);
50 }
51 argc--, argv++;
b3933da8
MK
52 for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
53 for (argv[0]++; *argv[0]; argv[0]++)
54 switch (*argv[0]) {
55 case 'f':
a2280e64 56 doflush++;
b3933da8
MK
57 break;
58 case 'n':
a2280e64 59 nflag++;
b3933da8
MK
60 break;
61 }
62 }
a2280e64
MK
63 if (doflush)
64 flushroutes();
63c817da
SL
65 if (argc > 0) {
66 if (strcmp(*argv, "add") == 0)
67 newroute(argc, argv);
68 else if (strcmp(*argv, "delete") == 0)
69 newroute(argc, argv);
70 else if (strcmp(*argv, "change") == 0)
71 changeroute(argc-1, argv+1);
72 else
73 printf("%s: huh?\n", *argv);
74 }
75}
76
77/*
78 * Purge all entries in the routing tables not
79 * associated with network interfaces.
80 */
81#include <nlist.h>
82
83struct nlist nl[] = {
84#define N_RTHOST 0
85 { "_rthost" },
86#define N_RTNET 1
87 { "_rtnet" },
f508555e
MK
88#define N_RTHASHSIZE 2
89 { "_rthashsize" },
63c817da
SL
90 "",
91};
92
93flushroutes()
94{
95 struct mbuf mb;
96 register struct rtentry *rt;
97 register struct mbuf *m;
f508555e
MK
98 struct mbuf **routehash;
99 int rthashsize, i, doinghost = 1, kmem;
a2280e64 100 char *routename(), *netname();
63c817da
SL
101
102 nlist("/vmunix", nl);
103 if (nl[N_RTHOST].n_value == 0) {
104 printf("route: \"rthost\", symbol not in namelist\n");
105 exit(1);
106 }
107 if (nl[N_RTNET].n_value == 0) {
108 printf("route: \"rtnet\", symbol not in namelist\n");
109 exit(1);
110 }
f508555e
MK
111 if (nl[N_RTHASHSIZE].n_value == 0) {
112 printf("route: \"rthashsize\", symbol not in namelist\n");
113 exit(1);
114 }
63c817da
SL
115 kmem = open("/dev/kmem", 0);
116 if (kmem < 0) {
117 perror("route: /dev/kmem");
118 exit(1);
119 }
f508555e
MK
120 lseek(kmem, nl[N_RTHASHSIZE].n_value, 0);
121 read(kmem, &rthashsize, sizeof (rthashsize));
122 routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *));
123
63c817da 124 lseek(kmem, nl[N_RTHOST].n_value, 0);
f508555e 125 read(kmem, routehash, rthashsize*sizeof (struct mbuf *));
63c817da
SL
126 printf("Flushing routing tables:\n");
127again:
f508555e 128 for (i = 0; i < rthashsize; i++) {
63c817da
SL
129 if (routehash[i] == 0)
130 continue;
131 m = routehash[i];
132 while (m) {
133 lseek(kmem, m, 0);
134 read(kmem, &mb, sizeof (mb));
135 rt = mtod(&mb, struct rtentry *);
136 if (rt->rt_flags & RTF_GATEWAY) {
eac76d14
MK
137 printf("%-20.20s ", doinghost ?
138 routename(&rt->rt_dst) :
139 netname(&rt->rt_dst));
140 printf("%-20.20s ", routename(&rt->rt_gateway));
63c817da
SL
141 if (ioctl(s, SIOCDELRT, (caddr_t)rt) < 0)
142 error("delete");
143 else
144 printf("done\n");
145 }
146 m = mb.m_next;
147 }
148 }
149 if (doinghost) {
150 lseek(kmem, nl[N_RTNET].n_value, 0);
f508555e 151 read(kmem, routehash, rthashsize*sizeof (struct mbuf *));
63c817da
SL
152 doinghost = 0;
153 goto again;
154 }
155 close(kmem);
f508555e 156 free(routehash);
63c817da
SL
157}
158
159char *
eac76d14
MK
160routename(sa)
161 struct sockaddr *sa;
63c817da 162{
a2280e64 163 register char *cp;
63c817da 164 static char line[50];
6edb1941 165 struct hostent *hp;
a2280e64
MK
166 static char domain[MAXHOSTNAMELEN + 1];
167 static int first = 1;
168 char *index();
eac76d14 169 char *ns_print();
63c817da 170
a2280e64
MK
171 if (first) {
172 first = 0;
173 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
174 (cp = index(domain, '.')))
175 (void) strcpy(domain, cp + 1);
176 else
177 domain[0] = 0;
178 }
eac76d14
MK
179 switch (sa->sa_family) {
180
181 case AF_INET:
182 { struct in_addr in;
183 in = ((struct sockaddr_in *)sa)->sin_addr;
184
185 cp = 0;
186 if (in.s_addr == INADDR_ANY)
187 cp = "default";
188 if (cp == 0 && !nflag) {
189 hp = gethostbyaddr(&in, sizeof (struct in_addr),
190 AF_INET);
191 if (hp) {
192 if ((cp = index(hp->h_name, '.')) &&
193 !strcmp(cp + 1, domain))
194 *cp = 0;
195 cp = hp->h_name;
196 }
a2280e64 197 }
eac76d14
MK
198 if (cp)
199 strcpy(line, cp);
200 else {
a2280e64 201#define C(x) ((x) & 0xff)
eac76d14
MK
202 in.s_addr = ntohl(in.s_addr);
203 sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
204 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
205 }
206 break;
207 }
208
209 case AF_NS:
210 return (ns_print((struct sockaddr_ns *)sa));
211
212 default:
213 { u_short *s = (u_short *)sa->sa_data;
214
215 sprintf(line, "af %d: %x %x %x %x %x %x %x", sa->sa_family,
216 s[0], s[1], s[2], s[3], s[4], s[5], s[6]);
217 break;
218 }
a2280e64
MK
219 }
220 return (line);
221}
222
223/*
224 * Return the name of the network whose address is given.
225 * The address is assumed to be that of a net or subnet, not a host.
226 */
227char *
eac76d14
MK
228netname(sa)
229 struct sockaddr *sa;
a2280e64
MK
230{
231 char *cp = 0;
232 static char line[50];
233 struct netent *np = 0;
234 u_long net, mask;
e2fe1192 235 register u_long i;
a2280e64
MK
236 int subnetshift;
237
eac76d14
MK
238 switch (sa->sa_family) {
239
240 case AF_INET:
241 { struct in_addr in;
242 in = ((struct sockaddr_in *)sa)->sin_addr;
243
e2fe1192 244 i = in.s_addr = ntohl(in.s_addr);
eac76d14
MK
245 if (in.s_addr == 0)
246 cp = "default";
247 else if (!nflag) {
248 if (IN_CLASSA(i)) {
249 mask = IN_CLASSA_NET;
250 subnetshift = 8;
251 } else if (IN_CLASSB(i)) {
252 mask = IN_CLASSB_NET;
253 subnetshift = 8;
254 } else {
255 mask = IN_CLASSC_NET;
256 subnetshift = 4;
257 }
258 /*
259 * If there are more bits than the standard mask
260 * would suggest, subnets must be in use.
261 * Guess at the subnet mask, assuming reasonable
262 * width subnet fields.
263 */
264 while (in.s_addr &~ mask)
265 mask = (long)mask >> subnetshift;
266 net = in.s_addr & mask;
267 while ((mask & 1) == 0)
268 mask >>= 1, net >>= 1;
269 np = getnetbyaddr(net, AF_INET);
270 if (np)
271 cp = np->n_name;
a2280e64 272 }
eac76d14
MK
273 if (cp)
274 strcpy(line, cp);
275 else if ((in.s_addr & 0xffffff) == 0)
276 sprintf(line, "%u", C(in.s_addr >> 24));
277 else if ((in.s_addr & 0xffff) == 0)
278 sprintf(line, "%u.%u", C(in.s_addr >> 24),
279 C(in.s_addr >> 16));
280 else if ((in.s_addr & 0xff) == 0)
281 sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
282 C(in.s_addr >> 16), C(in.s_addr >> 8));
283 else
284 sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
285 C(in.s_addr >> 16), C(in.s_addr >> 8),
286 C(in.s_addr));
287 break;
288 }
289
290 case AF_NS:
291 return (ns_print((struct sockaddr_ns *)sa));
292 break;
293
294 default:
295 { u_short *s = (u_short *)sa->sa_data;
296
297 sprintf(line, "af %d: %x %x %x %x %x %x %x", sa->sa_family,
298 s[0], s[1], s[2], s[3], s[4], s[5], s[6]);
299 break;
300 }
63c817da
SL
301 }
302 return (line);
4bec325f
BJ
303}
304
305newroute(argc, argv)
306 int argc;
307 char *argv[];
308{
309 struct sockaddr_in *sin;
792b0612
MK
310 char *cmd, *dest, *gateway;
311 int ishost, metric = 0, ret, attempts, oerrno;
312 struct hostent *hp;
313 extern int errno;
4bec325f 314
183ef13b 315 cmd = argv[0];
a2280e64
MK
316 if ((strcmp(argv[1], "host")) == 0) {
317 forcehost++;
318 argc--, argv++;
319 } else if ((strcmp(argv[1], "net")) == 0) {
320 forcenet++;
321 argc--, argv++;
322 }
6edb1941
MK
323 if (*cmd == 'a') {
324 if (argc != 4) {
325 printf("usage: %s destination gateway metric\n", cmd);
326 printf("(metric of 0 if gateway is this host)\n");
327 return;
328 }
c4693c18 329 metric = atoi(argv[3]);
6edb1941 330 } else {
55e026df 331 if (argc < 3) {
6edb1941
MK
332 printf("usage: %s destination gateway\n", cmd);
333 return;
334 }
335 }
792b0612 336 sin = (struct sockaddr_in *)&route.rt_dst;
a2280e64 337 ishost = getaddr(argv[1], &route.rt_dst, &hp, &dest, forcenet);
b3933da8
MK
338 if (forcehost)
339 ishost = 1;
340 if (forcenet)
341 ishost = 0;
792b0612 342 sin = (struct sockaddr_in *)&route.rt_gateway;
a2280e64 343 (void) getaddr(argv[2], &route.rt_gateway, &hp, &gateway, 0);
4bec325f 344 route.rt_flags = RTF_UP;
6edb1941 345 if (ishost)
4bec325f 346 route.rt_flags |= RTF_HOST;
c4693c18 347 if (metric > 0)
183ef13b 348 route.rt_flags |= RTF_GATEWAY;
792b0612
MK
349 for (attempts = 1; ; attempts++) {
350 errno = 0;
351 if ((ret = ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT,
352 (caddr_t)&route)) == 0)
353 break;
354 if (errno != ENETUNREACH && errno != ESRCH)
355 break;
356 if (hp && hp->h_addr_list[1]) {
357 hp->h_addr_list++;
358 bcopy(hp->h_addr_list[0], (caddr_t)&sin->sin_addr,
359 hp->h_length);
360 } else
361 break;
362 }
363 oerrno = errno;
364 printf("%s %s %s: gateway %s", cmd, ishost? "host" : "net",
365 dest, gateway);
366 if (attempts > 1 && ret == 0)
367 printf(" (%s)",
368 inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
369 if (ret == 0)
370 printf("\n");
371 else {
372 printf(": ");
373 fflush(stdout);
374 errno = oerrno;
375 error(0);
376 }
4bec325f
BJ
377}
378
379changeroute(argc, argv)
380 int argc;
381 char *argv[];
382{
383 printf("not supported\n");
384}
385
386error(cmd)
387 char *cmd;
388{
4bec325f
BJ
389
390 if (errno == ESRCH)
391 fprintf(stderr, "not in table\n");
392 else if (errno == EBUSY)
393 fprintf(stderr, "entry in use\n");
394 else if (errno == ENOBUFS)
395 fprintf(stderr, "routing table overflow\n");
396 else
397 perror(cmd);
398}
399
55e026df
MK
400char *
401savestr(s)
402 char *s;
403{
404 char *sav;
405
406 sav = malloc(strlen(s) + 1);
407 if (sav == NULL) {
408 fprintf("route: out of memory\n");
409 exit(1);
410 }
411 strcpy(sav, s);
412 return (sav);
413}
414
6edb1941
MK
415/*
416 * Interpret an argument as a network address of some kind,
417 * returning 1 if a host address, 0 if a network address.
418 */
a2280e64 419getaddr(s, sin, hpp, name, isnet)
4bec325f
BJ
420 char *s;
421 struct sockaddr_in *sin;
792b0612 422 struct hostent **hpp;
c28affab 423 char **name;
a2280e64 424 int isnet;
4bec325f 425{
accbc2e3 426 struct hostent *hp;
379dcc38
SL
427 struct netent *np;
428 u_long val;
accbc2e3 429
792b0612 430 *hpp = 0;
89a108e6
SL
431 if (strcmp(s, "default") == 0) {
432 sin->sin_family = AF_INET;
433 sin->sin_addr = inet_makeaddr(0, INADDR_ANY);
55e026df 434 *name = "default";
6edb1941 435 return(0);
89a108e6 436 }
792b0612 437 sin->sin_family = AF_INET;
a2280e64
MK
438 if (isnet == 0) {
439 val = inet_addr(s);
440 if (val != -1) {
441 sin->sin_addr.s_addr = val;
442 *name = s;
443 return(inet_lnaof(sin->sin_addr) != INADDR_ANY);
444 }
792b0612
MK
445 }
446 val = inet_network(s);
447 if (val != -1) {
448 sin->sin_addr = inet_makeaddr(val, INADDR_ANY);
c28affab 449 *name = s;
792b0612
MK
450 return(0);
451 }
379dcc38
SL
452 np = getnetbyname(s);
453 if (np) {
454 sin->sin_family = np->n_addrtype;
455 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
55e026df 456 *name = savestr(np->n_name);
6edb1941 457 return(0);
379dcc38 458 }
78160c55
MK
459 hp = gethostbyname(s);
460 if (hp) {
792b0612 461 *hpp = hp;
78160c55
MK
462 sin->sin_family = hp->h_addrtype;
463 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
55e026df 464 *name = savestr(hp->h_name);
78160c55
MK
465 return(1);
466 }
379dcc38
SL
467 fprintf(stderr, "%s: bad value\n", s);
468 exit(1);
183ef13b 469}
eac76d14
MK
470
471short ns_nullh[] = {0,0,0};
472short ns_bh[] = {-1,-1,-1};
473
474char *
475ns_print(sns)
476struct sockaddr_ns *sns;
477{
478 struct ns_addr work;
479 union { union ns_net net_e; u_long long_e; } net;
480 u_short port;
481 static char mybuf[50], cport[10], chost[25];
482 char *host = "";
483 register char *p; register u_char *q; u_char *q_lim;
484
485 work = sns->sns_addr;
486 port = ntohs(work.x_port);
487 work.x_port = 0;
488 net.net_e = work.x_net;
489 if (ns_nullhost(work) && net.long_e == 0) {
490 if (port ) {
491 sprintf(mybuf, "*.%xH", port);
492 upHex(mybuf);
493 } else
494 sprintf(mybuf, "*.*");
495 return (mybuf);
496 }
497
498 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
499 host = "any";
500 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
501 host = "*";
502 } else {
503 q = work.x_host.c_host;
504 sprintf(chost, "%02x%02x%02x%02x%02x%02xH",
505 q[0], q[1], q[2], q[3], q[4], q[5]);
506 for (p = chost; *p == '0' && p < chost + 12; p++);
507 host = p;
508 }
509 if (port)
510 sprintf(cport, ".%xH", htons(port));
511 else
512 *cport = 0;
513
514 sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport);
515 upHex(mybuf);
516 return(mybuf);
517}
518
519upHex(p0)
520char *p0;
521{
522 register char *p = p0;
523 for (; *p; p++) switch (*p) {
524
525 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
526 *p += ('A' - 'a');
527 }
528}