Berkeley header
[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
a48a48cc 14static char sccsid[] = "@(#)route.c 5.9 (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 202 in.s_addr = ntohl(in.s_addr);
9bd38ba8 203 (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
eac76d14
MK
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
9bd38ba8
KB
215 (void)sprintf(line, "af %d: %x %x %x %x %x %x %x",
216 sa->sa_family, s[0], s[1], s[2], s[3], s[4], s[5], s[6]);
eac76d14
MK
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 236 int subnetshift;
a48a48cc 237 char *ns_print();
a2280e64 238
eac76d14
MK
239 switch (sa->sa_family) {
240
241 case AF_INET:
242 { struct in_addr in;
243 in = ((struct sockaddr_in *)sa)->sin_addr;
244
e2fe1192 245 i = in.s_addr = ntohl(in.s_addr);
eac76d14
MK
246 if (in.s_addr == 0)
247 cp = "default";
248 else if (!nflag) {
249 if (IN_CLASSA(i)) {
250 mask = IN_CLASSA_NET;
251 subnetshift = 8;
252 } else if (IN_CLASSB(i)) {
253 mask = IN_CLASSB_NET;
254 subnetshift = 8;
255 } else {
256 mask = IN_CLASSC_NET;
257 subnetshift = 4;
258 }
259 /*
260 * If there are more bits than the standard mask
261 * would suggest, subnets must be in use.
262 * Guess at the subnet mask, assuming reasonable
263 * width subnet fields.
264 */
265 while (in.s_addr &~ mask)
266 mask = (long)mask >> subnetshift;
267 net = in.s_addr & mask;
268 while ((mask & 1) == 0)
269 mask >>= 1, net >>= 1;
270 np = getnetbyaddr(net, AF_INET);
271 if (np)
272 cp = np->n_name;
a2280e64 273 }
eac76d14
MK
274 if (cp)
275 strcpy(line, cp);
276 else if ((in.s_addr & 0xffffff) == 0)
9bd38ba8 277 (void)sprintf(line, "%u", C(in.s_addr >> 24));
eac76d14 278 else if ((in.s_addr & 0xffff) == 0)
9bd38ba8 279 (void)sprintf(line, "%u.%u", C(in.s_addr >> 24),
eac76d14
MK
280 C(in.s_addr >> 16));
281 else if ((in.s_addr & 0xff) == 0)
9bd38ba8 282 (void)sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
eac76d14
MK
283 C(in.s_addr >> 16), C(in.s_addr >> 8));
284 else
9bd38ba8 285 (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
eac76d14
MK
286 C(in.s_addr >> 16), C(in.s_addr >> 8),
287 C(in.s_addr));
288 break;
289 }
290
291 case AF_NS:
292 return (ns_print((struct sockaddr_ns *)sa));
293 break;
294
295 default:
296 { u_short *s = (u_short *)sa->sa_data;
297
9bd38ba8
KB
298 (void)sprintf(line, "af %d: %x %x %x %x %x %x %x",
299 sa->sa_family, s[0], s[1], s[2], s[3], s[4], s[5], s[6]);
eac76d14
MK
300 break;
301 }
63c817da
SL
302 }
303 return (line);
4bec325f
BJ
304}
305
306newroute(argc, argv)
307 int argc;
308 char *argv[];
309{
310 struct sockaddr_in *sin;
792b0612
MK
311 char *cmd, *dest, *gateway;
312 int ishost, metric = 0, ret, attempts, oerrno;
313 struct hostent *hp;
314 extern int errno;
4bec325f 315
183ef13b 316 cmd = argv[0];
a2280e64
MK
317 if ((strcmp(argv[1], "host")) == 0) {
318 forcehost++;
319 argc--, argv++;
320 } else if ((strcmp(argv[1], "net")) == 0) {
321 forcenet++;
322 argc--, argv++;
323 }
6edb1941
MK
324 if (*cmd == 'a') {
325 if (argc != 4) {
326 printf("usage: %s destination gateway metric\n", cmd);
327 printf("(metric of 0 if gateway is this host)\n");
328 return;
329 }
c4693c18 330 metric = atoi(argv[3]);
6edb1941 331 } else {
55e026df 332 if (argc < 3) {
6edb1941
MK
333 printf("usage: %s destination gateway\n", cmd);
334 return;
335 }
336 }
792b0612 337 sin = (struct sockaddr_in *)&route.rt_dst;
a2280e64 338 ishost = getaddr(argv[1], &route.rt_dst, &hp, &dest, forcenet);
b3933da8
MK
339 if (forcehost)
340 ishost = 1;
341 if (forcenet)
342 ishost = 0;
792b0612 343 sin = (struct sockaddr_in *)&route.rt_gateway;
a2280e64 344 (void) getaddr(argv[2], &route.rt_gateway, &hp, &gateway, 0);
4bec325f 345 route.rt_flags = RTF_UP;
6edb1941 346 if (ishost)
4bec325f 347 route.rt_flags |= RTF_HOST;
c4693c18 348 if (metric > 0)
183ef13b 349 route.rt_flags |= RTF_GATEWAY;
792b0612
MK
350 for (attempts = 1; ; attempts++) {
351 errno = 0;
352 if ((ret = ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT,
353 (caddr_t)&route)) == 0)
354 break;
355 if (errno != ENETUNREACH && errno != ESRCH)
356 break;
357 if (hp && hp->h_addr_list[1]) {
358 hp->h_addr_list++;
359 bcopy(hp->h_addr_list[0], (caddr_t)&sin->sin_addr,
360 hp->h_length);
361 } else
362 break;
363 }
364 oerrno = errno;
365 printf("%s %s %s: gateway %s", cmd, ishost? "host" : "net",
366 dest, gateway);
367 if (attempts > 1 && ret == 0)
368 printf(" (%s)",
369 inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
370 if (ret == 0)
371 printf("\n");
372 else {
373 printf(": ");
374 fflush(stdout);
375 errno = oerrno;
376 error(0);
377 }
4bec325f
BJ
378}
379
380changeroute(argc, argv)
381 int argc;
382 char *argv[];
383{
384 printf("not supported\n");
385}
386
387error(cmd)
388 char *cmd;
389{
a48a48cc 390 extern int errno;
4bec325f 391
a48a48cc
KB
392 switch(errno) {
393 case ESRCH:
4bec325f 394 fprintf(stderr, "not in table\n");
a48a48cc
KB
395 break;
396 case EBUSY:
4bec325f 397 fprintf(stderr, "entry in use\n");
a48a48cc
KB
398 break;
399 case ENOBUFS:
4bec325f 400 fprintf(stderr, "routing table overflow\n");
a48a48cc
KB
401 break;
402 default:
4bec325f 403 perror(cmd);
a48a48cc 404 }
4bec325f
BJ
405}
406
55e026df
MK
407char *
408savestr(s)
409 char *s;
410{
411 char *sav;
412
413 sav = malloc(strlen(s) + 1);
414 if (sav == NULL) {
415 fprintf("route: out of memory\n");
416 exit(1);
417 }
418 strcpy(sav, s);
419 return (sav);
420}
421
6edb1941
MK
422/*
423 * Interpret an argument as a network address of some kind,
424 * returning 1 if a host address, 0 if a network address.
425 */
a2280e64 426getaddr(s, sin, hpp, name, isnet)
4bec325f
BJ
427 char *s;
428 struct sockaddr_in *sin;
792b0612 429 struct hostent **hpp;
c28affab 430 char **name;
a2280e64 431 int isnet;
4bec325f 432{
accbc2e3 433 struct hostent *hp;
379dcc38
SL
434 struct netent *np;
435 u_long val;
accbc2e3 436
792b0612 437 *hpp = 0;
89a108e6
SL
438 if (strcmp(s, "default") == 0) {
439 sin->sin_family = AF_INET;
440 sin->sin_addr = inet_makeaddr(0, INADDR_ANY);
55e026df 441 *name = "default";
6edb1941 442 return(0);
89a108e6 443 }
792b0612 444 sin->sin_family = AF_INET;
a2280e64
MK
445 if (isnet == 0) {
446 val = inet_addr(s);
447 if (val != -1) {
448 sin->sin_addr.s_addr = val;
449 *name = s;
450 return(inet_lnaof(sin->sin_addr) != INADDR_ANY);
451 }
792b0612
MK
452 }
453 val = inet_network(s);
454 if (val != -1) {
455 sin->sin_addr = inet_makeaddr(val, INADDR_ANY);
c28affab 456 *name = s;
792b0612
MK
457 return(0);
458 }
379dcc38
SL
459 np = getnetbyname(s);
460 if (np) {
461 sin->sin_family = np->n_addrtype;
462 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
55e026df 463 *name = savestr(np->n_name);
6edb1941 464 return(0);
379dcc38 465 }
78160c55
MK
466 hp = gethostbyname(s);
467 if (hp) {
792b0612 468 *hpp = hp;
78160c55
MK
469 sin->sin_family = hp->h_addrtype;
470 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
55e026df 471 *name = savestr(hp->h_name);
78160c55
MK
472 return(1);
473 }
379dcc38
SL
474 fprintf(stderr, "%s: bad value\n", s);
475 exit(1);
183ef13b 476}
eac76d14
MK
477
478short ns_nullh[] = {0,0,0};
479short ns_bh[] = {-1,-1,-1};
480
481char *
482ns_print(sns)
483struct sockaddr_ns *sns;
484{
485 struct ns_addr work;
486 union { union ns_net net_e; u_long long_e; } net;
487 u_short port;
488 static char mybuf[50], cport[10], chost[25];
489 char *host = "";
490 register char *p; register u_char *q; u_char *q_lim;
491
492 work = sns->sns_addr;
493 port = ntohs(work.x_port);
494 work.x_port = 0;
495 net.net_e = work.x_net;
496 if (ns_nullhost(work) && net.long_e == 0) {
497 if (port ) {
9bd38ba8 498 (void)sprintf(mybuf, "*.%xH", port);
eac76d14
MK
499 upHex(mybuf);
500 } else
9bd38ba8 501 (void)sprintf(mybuf, "*.*");
eac76d14
MK
502 return (mybuf);
503 }
504
505 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
506 host = "any";
507 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
508 host = "*";
509 } else {
510 q = work.x_host.c_host;
9bd38ba8 511 (void)sprintf(chost, "%02x%02x%02x%02x%02x%02xH",
eac76d14
MK
512 q[0], q[1], q[2], q[3], q[4], q[5]);
513 for (p = chost; *p == '0' && p < chost + 12; p++);
514 host = p;
515 }
516 if (port)
9bd38ba8 517 (void)sprintf(cport, ".%xH", htons(port));
eac76d14
MK
518 else
519 *cport = 0;
520
9bd38ba8 521 (void)sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport);
eac76d14
MK
522 upHex(mybuf);
523 return(mybuf);
524}
525
526upHex(p0)
527char *p0;
528{
529 register char *p = p0;
530 for (; *p; p++) switch (*p) {
531
532 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
533 *p += ('A' - 'a');
534 }
535}