going to change main, so reformat to KNF
[unix-history] / usr / src / sbin / route / route.c
CommitLineData
5ff67f98 1/*
7b3729cc 2 * Copyright (c) 1983, 1989 The Regents of the University of California.
fca7493d
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
5ff67f98
DF
16 */
17
18#ifndef lint
19char copyright[] =
7d5f817b 20"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
5ff67f98 21 All rights reserved.\n";
fca7493d 22#endif /* not lint */
5ff67f98 23
4bec325f 24#ifndef lint
7b3729cc 25static char sccsid[] = "@(#)route.c 5.17 (Berkeley) %G%";
fca7493d 26#endif /* not lint */
4bec325f 27
7d5f817b 28#include <paths.h>
a2280e64 29#include <sys/param.h>
4bec325f
BJ
30#include <sys/socket.h>
31#include <sys/ioctl.h>
5c7868a2 32#include <sys/file.h>
63c817da 33#include <sys/mbuf.h>
94a2d2a7 34
4bec325f 35#include <net/route.h>
94a2d2a7 36#include <netinet/in.h>
eac76d14 37#include <netns/ns.h>
7d5f817b 38#include <netiso/iso.h>
94a2d2a7 39
5c7868a2 40#include <netdb.h>
94a2d2a7 41#include <stdio.h>
4bec325f
BJ
42#include <errno.h>
43#include <ctype.h>
44
57cacc90 45struct ortentry route;
7d5f817b
KS
46union {
47 struct sockaddr sa;
48 struct sockaddr_in sin;
49 struct sockaddr_ns sns;
50 struct sockaddr_iso siso;
51} so_dst, so_gate, so_mask;
4bec325f 52int s;
7b3729cc 53int forcehost, forcenet, doflush, nflag, xnsflag, qflag, Cflag = 1;
7d5f817b 54int iflag, osiflag, verbose;
57cacc90 55int pid;
b268b889 56struct sockaddr_in sin = { sizeof(sin), AF_INET };
379dcc38 57struct in_addr inet_makeaddr();
5c7868a2 58char *malloc(), *vmunix = _PATH_UNIX;
b268b889
MK
59#define kget(p, d) \
60 (lseek(kmem, (off_t)(p), 0), read(kmem, (char *)&(d), sizeof (d)))
4bec325f
BJ
61
62main(argc, argv)
63 int argc;
64 char *argv[];
65{
66
b268b889 67 char *argvp;
4bec325f 68 if (argc < 2)
5c7868a2 69 usage:
b268b889
MK
70 fprintf(stderr,
71 "usage: route [ -n ] [ -f ] [ cmd [ net | host ] args ]\n"),
b3933da8 72 exit(1);
4bec325f 73 argc--, argv++;
b3933da8 74 for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
b268b889 75 for (argvp = argv[0]++; *argvp; argvp++)
b3933da8
MK
76 switch (*argv[0]) {
77 case 'f':
a2280e64 78 doflush++;
b3933da8
MK
79 break;
80 case 'n':
a2280e64 81 nflag++;
b3933da8 82 break;
b268b889
MK
83 case 'x':
84 xnsflag++;
85 break;
ae578a19
KS
86 case 'q':
87 qflag++;
88 break;
5c7868a2
KS
89 case 'C':
90 Cflag++; /* Use old ioctls */
57cacc90 91 break;
b268b889
MK
92 case 'k':
93 vmunix = *++argv;
94 argc--;
95 break;
57cacc90
KS
96 case 'i':
97 iflag++;
98 break;
7d5f817b
KS
99 case 'o':
100 osiflag++;
101 break;
102 case 'v':
103 verbose++;
104 break;
7b3729cc
KS
105
106 case 'N':
107 Cflag = 0; /* Use routing socket */
b3933da8
MK
108 }
109 }
5c7868a2
KS
110 pid = getpid();
111 if (Cflag)
57cacc90 112 s = socket(AF_INET, SOCK_RAW, 0);
5c7868a2
KS
113 else
114 s = socket(PF_ROUTE, SOCK_RAW, 0);
57cacc90
KS
115 if (s < 0) {
116 perror("route: socket");
117 exit(1);
118 }
119 if (doflush) {
a2280e64 120 flushroutes();
57cacc90
KS
121 exit(0);
122 }
63c817da
SL
123 if (argc > 0) {
124 if (strcmp(*argv, "add") == 0)
125 newroute(argc, argv);
126 else if (strcmp(*argv, "delete") == 0)
127 newroute(argc, argv);
128 else if (strcmp(*argv, "change") == 0)
129 changeroute(argc-1, argv+1);
5c7868a2
KS
130 else if (strcmp(*argv, "monitor") == 0)
131 monitor();
63c817da 132 else
b268b889 133 fprintf(stderr, "%s: huh?\n", *argv);
57cacc90 134 } else
5c7868a2 135 goto usage;
63c817da
SL
136}
137
138/*
139 * Purge all entries in the routing tables not
140 * associated with network interfaces.
141 */
142#include <nlist.h>
143
144struct nlist nl[] = {
145#define N_RTHOST 0
146 { "_rthost" },
147#define N_RTNET 1
148 { "_rtnet" },
f508555e
MK
149#define N_RTHASHSIZE 2
150 { "_rthashsize" },
b268b889
MK
151#define N_RTREE 3
152 { "_radix_node_head" },
63c817da
SL
153 "",
154};
155
b268b889 156int kmem;
63c817da
SL
157flushroutes()
158{
5c7868a2 159 extern int errno;
57cacc90 160 register struct ortentry *rt;
63c817da 161 register struct mbuf *m;
5c7868a2 162 struct mbuf mb, **routehash;
b268b889 163 int rthashsize, i, doinghost = 1;
5c7868a2 164 char *routename(), *netname(), *strerror();
63c817da 165
b268b889 166 nlist(vmunix, nl);
5c7868a2 167 kmem = open(_PATH_KMEM, O_RDONLY, 0);
b268b889 168 if (kmem < 0) {
5c7868a2
KS
169 (void)fprintf(stderr,
170 "route: %s: %s\n", _PATH_KMEM, strerror(errno));
b268b889
MK
171 exit(1);
172 }
173 if (nl[N_RTREE].n_value)
174 return (treestuff(nl[N_RTREE].n_value));
63c817da 175 if (nl[N_RTHOST].n_value == 0) {
b268b889
MK
176 fprintf(stderr,
177 "route: \"rthost\", symbol not in namelist\n");
63c817da
SL
178 exit(1);
179 }
180 if (nl[N_RTNET].n_value == 0) {
b268b889
MK
181 fprintf(stderr,
182 "route: \"rtnet\", symbol not in namelist\n");
63c817da
SL
183 exit(1);
184 }
f508555e 185 if (nl[N_RTHASHSIZE].n_value == 0) {
b268b889
MK
186 fprintf(stderr,
187 "route: \"rthashsize\", symbol not in namelist\n");
63c817da
SL
188 exit(1);
189 }
b268b889 190 kget(nl[N_RTHASHSIZE].n_value, rthashsize);
f508555e
MK
191 routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *));
192
63c817da 193 lseek(kmem, nl[N_RTHOST].n_value, 0);
f508555e 194 read(kmem, routehash, rthashsize*sizeof (struct mbuf *));
63c817da
SL
195 printf("Flushing routing tables:\n");
196again:
f508555e 197 for (i = 0; i < rthashsize; i++) {
63c817da
SL
198 if (routehash[i] == 0)
199 continue;
200 m = routehash[i];
201 while (m) {
b268b889 202 kget(m, mb);
57cacc90 203 d_ortentry((struct ortentry *)(mb.m_dat), doinghost);
63c817da
SL
204 m = mb.m_next;
205 }
206 }
207 if (doinghost) {
208 lseek(kmem, nl[N_RTNET].n_value, 0);
f508555e 209 read(kmem, routehash, rthashsize*sizeof (struct mbuf *));
63c817da
SL
210 doinghost = 0;
211 goto again;
212 }
213 close(kmem);
f508555e 214 free(routehash);
b268b889
MK
215 return;
216}
57cacc90 217typedef u_char blob[128];
b268b889 218
ae578a19
KS
219struct rtbatch {
220 struct rtbatch *nb;
221 int ifree;
57cacc90
KS
222 struct x {
223 struct rtentry rt;
224 union {
225 struct sockaddr sa;
226 blob data;
227 } dst, gate, mask;
228 } x[100];
ae578a19
KS
229} firstbatch, *curbatch = &firstbatch;
230
ae578a19 231w_tree(rn)
b268b889
MK
232struct radix_node *rn;
233{
b268b889 234
b268b889 235 struct radix_node rnode;
57cacc90
KS
236 register struct rtentry *rt;
237 struct sockaddr *dst;
238 register struct x *x;
dc947964 239
b268b889
MK
240 kget(rn, rnode);
241 if (rnode.rn_b < 0) {
b268b889 242 if ((rnode.rn_flags & RNF_ROOT) == 0) {
ae578a19 243 register struct rtbatch *b = curbatch;
dc947964
MK
244 if ((rnode.rn_flags & RNF_ACTIVE) == 0) {
245 printf("Dead entry in tree: %x\n", rn);
246 exit(1);
247 }
ae578a19 248 if (b->ifree >= 100) {
57cacc90 249 R_Malloc(b->nb, struct rtbatch *,
ae578a19
KS
250 sizeof (*b));
251 if (b->nb) {
252 b = b->nb;
253 Bzero(b, sizeof(*b));
254 curbatch = b;
255 } else {
256 printf("out of space\n");
257 exit(1);
258 }
dc947964 259 }
57cacc90
KS
260 x = b->x + b->ifree;
261 rt = &x->rt;
262 kget(rn, *rt);
263 dst = &x->dst.sa;
264 kget(rt_key(rt), *dst);
265 if (dst->sa_len > sizeof (*dst))
266 kget(rt_key(rt), x->dst);
267 rt->rt_nodes->rn_key = (char *)dst;
268 kget(rt->rt_gateway, x->gate.sa);
269 if (x->gate.sa.sa_len > sizeof (*dst))
270 kget(rt->rt_gateway, x->gate);
271 rt->rt_gateway = &x->gate.sa;
5c7868a2 272 if (Cflag == 0) {
57cacc90
KS
273 kget(rt_mask(rt), x->mask.sa);
274 if (x->mask.sa.sa_len > sizeof(x->mask.sa))
275 kget(rt_mask(rt), x->mask);
276 rt->rt_nodes->rn_mask = (char *)&x->mask.sa;
277 }
278 b->ifree++;
b268b889 279 }
ae578a19
KS
280 if (rnode.rn_dupedkey)
281 w_tree(rnode.rn_dupedkey);
b268b889 282 } else {
ae578a19
KS
283 rn = rnode.rn_r;
284 w_tree(rnode.rn_l);
285 w_tree(rn);
b268b889 286 }
b268b889
MK
287}
288
57cacc90
KS
289treestuff(rtree)
290off_t rtree;
291{
292 struct radix_node_head *rnh, head;
293 register struct rtbatch *b;
294 register int i;
295
296 for (kget(rtree, rnh); rnh; rnh = head.rnh_next) {
297 kget(rnh, head);
298 if (head.rnh_af) {
299 w_tree(head.rnh_treetop);
300 }
301 }
302 for (b = &firstbatch; b; b = b->nb)
303 for (i = 0; i < b->ifree; i++)
304 d_rtentry(&(b->x[i].rt));
305}
306
307d_ortentry(rt)
308register struct ortentry *rt;
b268b889 309{
ae578a19
KS
310 int doinghost = rt->rt_flags & RTF_HOST;
311
b268b889 312 if (rt->rt_flags & RTF_GATEWAY) {
ae578a19 313 if (qflag == 0) {
b268b889
MK
314 printf("%-20.20s ", doinghost ?
315 routename(&rt->rt_dst) :
316 netname(&rt->rt_dst));
317 printf("%-20.20s ", routename(&rt->rt_gateway));
318 if (ioctl(s, SIOCDELRT, (caddr_t)rt) < 0) {
319 fflush(stdout);
320 error("delete");
321 } else
322 printf("done\n");
ae578a19
KS
323 } else
324 (void) ioctl(s, SIOCDELRT, (caddr_t)rt);
b268b889 325 }
63c817da
SL
326}
327
57cacc90
KS
328struct ortentry ortentry;
329d_rtentry(rt)
330register struct rtentry *rt;
331{
332 int doinghost = rt->rt_flags & RTF_HOST;
7d5f817b 333 int result;
57cacc90
KS
334
335 ortentry.rt_flags = rt->rt_flags;
336 ortentry.rt_dst = *(rt_key(rt));
337 ortentry.rt_gateway = *(rt->rt_gateway);
338 if (rt->rt_flags & RTF_GATEWAY) {
7d5f817b
KS
339 if (Cflag == 0)
340 result = rtmsg('d', rt_key(rt), rt->rt_gateway,
341 rt_mask(rt), rt->rt_flags);
342 else
343 result = ioctl(s, SIOCDELRT, (caddr_t)&ortentry);
344 if (qflag == 0) {
345 printf("%-20.20s ", doinghost ?
346 routename(rt_key(rt)) : netname(rt_key(rt)));
347 printf("%-20.20s ", routename(rt->rt_gateway));
348 if (result < 0) {
349 fflush(stdout);
350 error("delete");
351 } else
352 printf("done\n");
353 }
57cacc90
KS
354 }
355}
356
63c817da 357char *
eac76d14
MK
358routename(sa)
359 struct sockaddr *sa;
63c817da 360{
a2280e64 361 register char *cp;
63c817da 362 static char line[50];
6edb1941 363 struct hostent *hp;
a2280e64
MK
364 static char domain[MAXHOSTNAMELEN + 1];
365 static int first = 1;
366 char *index();
eac76d14 367 char *ns_print();
63c817da 368
a2280e64
MK
369 if (first) {
370 first = 0;
371 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
372 (cp = index(domain, '.')))
373 (void) strcpy(domain, cp + 1);
374 else
375 domain[0] = 0;
376 }
eac76d14
MK
377 switch (sa->sa_family) {
378
379 case AF_INET:
380 { struct in_addr in;
381 in = ((struct sockaddr_in *)sa)->sin_addr;
382
383 cp = 0;
384 if (in.s_addr == INADDR_ANY)
385 cp = "default";
386 if (cp == 0 && !nflag) {
387 hp = gethostbyaddr(&in, sizeof (struct in_addr),
388 AF_INET);
389 if (hp) {
390 if ((cp = index(hp->h_name, '.')) &&
391 !strcmp(cp + 1, domain))
392 *cp = 0;
393 cp = hp->h_name;
394 }
a2280e64 395 }
eac76d14
MK
396 if (cp)
397 strcpy(line, cp);
398 else {
a2280e64 399#define C(x) ((x) & 0xff)
eac76d14 400 in.s_addr = ntohl(in.s_addr);
9bd38ba8 401 (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
eac76d14
MK
402 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
403 }
404 break;
405 }
406
407 case AF_NS:
408 return (ns_print((struct sockaddr_ns *)sa));
409
410 default:
411 { u_short *s = (u_short *)sa->sa_data;
412
57cacc90 413 (void)sprintf(line, "(%d) %x %x %x %x %x %x %x",
9bd38ba8 414 sa->sa_family, s[0], s[1], s[2], s[3], s[4], s[5], s[6]);
eac76d14
MK
415 break;
416 }
a2280e64
MK
417 }
418 return (line);
419}
420
421/*
422 * Return the name of the network whose address is given.
423 * The address is assumed to be that of a net or subnet, not a host.
424 */
425char *
eac76d14
MK
426netname(sa)
427 struct sockaddr *sa;
a2280e64
MK
428{
429 char *cp = 0;
430 static char line[50];
431 struct netent *np = 0;
432 u_long net, mask;
e2fe1192 433 register u_long i;
a2280e64 434 int subnetshift;
a48a48cc 435 char *ns_print();
a2280e64 436
eac76d14
MK
437 switch (sa->sa_family) {
438
439 case AF_INET:
440 { struct in_addr in;
441 in = ((struct sockaddr_in *)sa)->sin_addr;
442
e2fe1192 443 i = in.s_addr = ntohl(in.s_addr);
eac76d14
MK
444 if (in.s_addr == 0)
445 cp = "default";
446 else if (!nflag) {
447 if (IN_CLASSA(i)) {
448 mask = IN_CLASSA_NET;
449 subnetshift = 8;
450 } else if (IN_CLASSB(i)) {
451 mask = IN_CLASSB_NET;
452 subnetshift = 8;
453 } else {
454 mask = IN_CLASSC_NET;
455 subnetshift = 4;
456 }
457 /*
458 * If there are more bits than the standard mask
459 * would suggest, subnets must be in use.
460 * Guess at the subnet mask, assuming reasonable
461 * width subnet fields.
462 */
463 while (in.s_addr &~ mask)
464 mask = (long)mask >> subnetshift;
465 net = in.s_addr & mask;
466 while ((mask & 1) == 0)
467 mask >>= 1, net >>= 1;
468 np = getnetbyaddr(net, AF_INET);
469 if (np)
470 cp = np->n_name;
a2280e64 471 }
eac76d14
MK
472 if (cp)
473 strcpy(line, cp);
474 else if ((in.s_addr & 0xffffff) == 0)
9bd38ba8 475 (void)sprintf(line, "%u", C(in.s_addr >> 24));
eac76d14 476 else if ((in.s_addr & 0xffff) == 0)
9bd38ba8 477 (void)sprintf(line, "%u.%u", C(in.s_addr >> 24),
eac76d14
MK
478 C(in.s_addr >> 16));
479 else if ((in.s_addr & 0xff) == 0)
9bd38ba8 480 (void)sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
eac76d14
MK
481 C(in.s_addr >> 16), C(in.s_addr >> 8));
482 else
9bd38ba8 483 (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
eac76d14
MK
484 C(in.s_addr >> 16), C(in.s_addr >> 8),
485 C(in.s_addr));
486 break;
487 }
488
489 case AF_NS:
490 return (ns_print((struct sockaddr_ns *)sa));
491 break;
492
493 default:
494 { u_short *s = (u_short *)sa->sa_data;
495
9bd38ba8
KB
496 (void)sprintf(line, "af %d: %x %x %x %x %x %x %x",
497 sa->sa_family, s[0], s[1], s[2], s[3], s[4], s[5], s[6]);
eac76d14
MK
498 break;
499 }
63c817da
SL
500 }
501 return (line);
4bec325f
BJ
502}
503
504newroute(argc, argv)
505 int argc;
506 char *argv[];
507{
508 struct sockaddr_in *sin;
57cacc90 509 char *cmd, *dest, *gateway, *mask;
7d5f817b 510 int ishost, metric = 0, ret, attempts, oerrno, flags = 0;
792b0612
MK
511 struct hostent *hp;
512 extern int errno;
4bec325f 513
183ef13b 514 cmd = argv[0];
a2280e64
MK
515 if ((strcmp(argv[1], "host")) == 0) {
516 forcehost++;
517 argc--, argv++;
518 } else if ((strcmp(argv[1], "net")) == 0) {
519 forcenet++;
520 argc--, argv++;
521 }
7d5f817b 522 ishost = getaddr(argv[1], &so_dst.sa, &so_mask.sa,
57cacc90 523 &hp, &dest, forcenet);
b3933da8
MK
524 if (forcehost)
525 ishost = 1;
526 if (forcenet)
527 ishost = 0;
7d5f817b 528 (void) getaddr(argv[2], &so_gate.sa, 0, &hp, &gateway, 0);
5c7868a2 529 if ((Cflag == 0) && argc == 4) {
7b3729cc
KS
530 ret = atoi(argv[3]);
531 if (ret == 0) {
532 printf("old usage of trailing 0, assuming route to if\n");
533 iflag = 1;
534 } else if (ret > 0 && ret < 10) {
535 printf("old usage of trailing digit, ");
536 printf("assuming route via gateway\n");
537 iflag = 0;
538 } else
539 (void) getaddr(argv[3], &so_mask.sa, 0, &hp, &mask, 0);
57cacc90 540 }
7d5f817b 541 flags = RTF_UP;
6edb1941 542 if (ishost)
7d5f817b 543 flags |= RTF_HOST;
57cacc90 544 if (iflag == 0)
7d5f817b 545 flags |= RTF_GATEWAY;
792b0612
MK
546 for (attempts = 1; ; attempts++) {
547 errno = 0;
5c7868a2 548 if (Cflag) {
7d5f817b
KS
549 route.rt_flags = flags;
550 route.rt_dst = so_dst.sa;
551 route.rt_gateway = so_gate.sa;
57cacc90
KS
552 if ((ret = ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT,
553 (caddr_t)&route)) == 0)
554 break;
555 } else {
7d5f817b
KS
556 if ((ret = rtmsg(*cmd, &so_dst.sa, &so_gate.sa,
557 (ishost ? 0 : &so_mask.sa), flags)) == 0)
57cacc90
KS
558 break;
559 }
792b0612
MK
560 if (errno != ENETUNREACH && errno != ESRCH)
561 break;
562 if (hp && hp->h_addr_list[1]) {
563 hp->h_addr_list++;
7d5f817b 564 bcopy(hp->h_addr_list[0], (caddr_t)&so_dst.sin.sin_addr,
792b0612
MK
565 hp->h_length);
566 } else
567 break;
568 }
569 oerrno = errno;
570 printf("%s %s %s: gateway %s", cmd, ishost? "host" : "net",
571 dest, gateway);
572 if (attempts > 1 && ret == 0)
573 printf(" (%s)",
574 inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
575 if (ret == 0)
576 printf("\n");
577 else {
578 printf(": ");
579 fflush(stdout);
580 errno = oerrno;
581 error(0);
582 }
4bec325f
BJ
583}
584
585changeroute(argc, argv)
586 int argc;
587 char *argv[];
588{
589 printf("not supported\n");
590}
591
592error(cmd)
593 char *cmd;
594{
a48a48cc 595 extern int errno;
4bec325f 596
a48a48cc
KB
597 switch(errno) {
598 case ESRCH:
ae578a19 599 printf("not in table\n");
a48a48cc
KB
600 break;
601 case EBUSY:
ae578a19 602 printf("entry in use\n");
a48a48cc
KB
603 break;
604 case ENOBUFS:
ae578a19 605 printf("routing table overflow\n");
a48a48cc
KB
606 break;
607 default:
57cacc90 608 printf("ioctl returns %d\n", errno);
4bec325f 609 perror(cmd);
a48a48cc 610 }
ae578a19
KS
611 fflush(stdout);
612 errno = 0;
4bec325f
BJ
613}
614
55e026df
MK
615char *
616savestr(s)
617 char *s;
618{
619 char *sav;
620
621 sav = malloc(strlen(s) + 1);
622 if (sav == NULL) {
623 fprintf("route: out of memory\n");
624 exit(1);
625 }
626 strcpy(sav, s);
627 return (sav);
628}
629
5c7868a2
KS
630inet_makenetandmask(net, sin, sockmask)
631u_long net;
632struct sockaddr_in *sin, *sockmask;
57cacc90
KS
633{
634 u_long addr;
5c7868a2 635 u_long mask = 0;
57cacc90
KS
636
637 if (net == 0)
5c7868a2 638 mask = addr = 0;
57cacc90
KS
639 else if (net < 128) {
640 addr = net << IN_CLASSA_NSHIFT;
5c7868a2 641 mask = IN_CLASSA_NET;
57cacc90
KS
642 } else if (net < 65536) {
643 addr = net << IN_CLASSB_NSHIFT;
5c7868a2 644 mask = IN_CLASSB_NET;
57cacc90
KS
645 } else if (net < 16777216L) {
646 addr = net << IN_CLASSC_NSHIFT;
5c7868a2 647 mask = IN_CLASSC_NET;
57cacc90
KS
648 } else {
649 addr = net;
650 if ((addr & IN_CLASSA_HOST) == 0)
5c7868a2 651 mask = IN_CLASSA_NET;
57cacc90 652 else if ((addr & IN_CLASSB_HOST) == 0)
5c7868a2 653 mask = IN_CLASSB_NET;
57cacc90 654 else if ((addr & IN_CLASSC_HOST) == 0)
5c7868a2 655 mask = IN_CLASSC_NET;
57cacc90 656 else
5c7868a2
KS
657 mask = -1;
658 }
659 sin->sin_addr.s_addr = (htonl(addr));
660 if (sockmask) {
7d5f817b 661 register char *cp = (char *)&(sockmask->sin_port);
5c7868a2
KS
662 register char *cpbase = (char *)&(sockmask->sin_addr);
663
664 sockmask->sin_addr.s_addr = htonl(mask);
665 sockmask->sin_len = 0;
666 sockmask->sin_family = 0;
667 while (--cp >= cpbase)
668 if (*cp) {
669 sockmask->sin_len = 1 + cp - (caddr_t)sockmask;
670 break;
671 }
57cacc90 672 }
57cacc90
KS
673}
674
6edb1941
MK
675/*
676 * Interpret an argument as a network address of some kind,
677 * returning 1 if a host address, 0 if a network address.
678 */
57cacc90 679getaddr(s, sin, sockmask, hpp, name, isnet)
4bec325f 680 char *s;
57cacc90 681 struct sockaddr_in *sin, *sockmask;
792b0612 682 struct hostent **hpp;
c28affab 683 char **name;
a2280e64 684 int isnet;
4bec325f 685{
b268b889
MK
686 struct sockaddr_ns *sns = (struct sockaddr_ns *)sin;
687 struct ns_addr ns_addr();
accbc2e3 688 struct hostent *hp;
379dcc38 689 struct netent *np;
7d5f817b 690 u_long val = 1;
accbc2e3 691
7d5f817b
KS
692 if (strcmp(s, "default") == 0) {
693 val = 0;
694 *name = "default";
695 }
b268b889
MK
696 if (xnsflag)
697 goto do_xns;
7d5f817b
KS
698 if (osiflag)
699 goto do_osi;
57cacc90
KS
700 sin->sin_family = AF_INET;
701 sin->sin_len = sizeof(*sin);
7d5f817b 702 if (val == 0)
57cacc90 703 goto out;
7d5f817b 704 *hpp = 0;
a2280e64
MK
705 if (isnet == 0) {
706 val = inet_addr(s);
707 if (val != -1) {
708 sin->sin_addr.s_addr = val;
709 *name = s;
57cacc90
KS
710 if (inet_lnaof(sin->sin_addr) != INADDR_ANY)
711 return (1);
712 else
713 goto out;
a2280e64 714 }
792b0612
MK
715 }
716 val = inet_network(s);
717 if (val != -1) {
c28affab 718 *name = s;
5c7868a2 719 goto out;
792b0612 720 }
379dcc38
SL
721 np = getnetbyname(s);
722 if (np) {
5c7868a2 723 val = np->n_net;
55e026df 724 *name = savestr(np->n_name);
5c7868a2 725 goto out;
379dcc38 726 }
78160c55
MK
727 hp = gethostbyname(s);
728 if (hp) {
792b0612 729 *hpp = hp;
78160c55
MK
730 sin->sin_family = hp->h_addrtype;
731 bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
55e026df 732 *name = savestr(hp->h_name);
57cacc90 733 return (1);
78160c55 734 }
379dcc38
SL
735 fprintf(stderr, "%s: bad value\n", s);
736 exit(1);
5c7868a2
KS
737out:
738 inet_makenetandmask(val, sin, sockmask);
739 return (0);
b268b889 740do_xns:
57cacc90 741 bzero((char *)sns, sizeof(*sns));
b268b889 742 sns->sns_family = AF_NS;
57cacc90 743 sns->sns_len = sizeof (*sns);
7d5f817b
KS
744 if (val == 0)
745 return(0);
57cacc90
KS
746 if (sockmask) {
747 extern short ns_bh[3];
5c7868a2 748 struct sockaddr_ns *sms = (struct sockaddr_ns *)sockmask;
57cacc90
KS
749 bzero((char *)sms, sizeof(*sns));
750 sms->sns_family = 0;
751 sms->sns_len = 6;
752 sms->sns_addr.x_net = *(union ns_net *)ns_bh;
753 }
57cacc90 754 *name = s;
b268b889
MK
755 sns->sns_addr = ns_addr(s);
756 return (!ns_nullhost(sns->sns_addr));
7d5f817b
KS
757do_osi:
758 {
759 struct sockaddr_iso *siso = (struct sockaddr_iso *)sin;
760 struct iso_addr iso_addr();
761
762 siso->siso_family = AF_ISO;
763 siso->siso_len = sizeof(*siso);
764 if (val == 0)
765 return (0);
766 *name = s;
767 siso->siso_addr = iso_addr(s);
768 return (1);
769 }
183ef13b 770}
eac76d14
MK
771
772short ns_nullh[] = {0,0,0};
773short ns_bh[] = {-1,-1,-1};
774
775char *
776ns_print(sns)
777struct sockaddr_ns *sns;
778{
779 struct ns_addr work;
780 union { union ns_net net_e; u_long long_e; } net;
781 u_short port;
782 static char mybuf[50], cport[10], chost[25];
783 char *host = "";
784 register char *p; register u_char *q; u_char *q_lim;
785
786 work = sns->sns_addr;
787 port = ntohs(work.x_port);
788 work.x_port = 0;
789 net.net_e = work.x_net;
790 if (ns_nullhost(work) && net.long_e == 0) {
791 if (port ) {
9bd38ba8 792 (void)sprintf(mybuf, "*.%xH", port);
eac76d14
MK
793 upHex(mybuf);
794 } else
9bd38ba8 795 (void)sprintf(mybuf, "*.*");
eac76d14
MK
796 return (mybuf);
797 }
798
799 if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
800 host = "any";
801 } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
802 host = "*";
803 } else {
804 q = work.x_host.c_host;
9bd38ba8 805 (void)sprintf(chost, "%02x%02x%02x%02x%02x%02xH",
eac76d14
MK
806 q[0], q[1], q[2], q[3], q[4], q[5]);
807 for (p = chost; *p == '0' && p < chost + 12; p++);
808 host = p;
809 }
810 if (port)
9bd38ba8 811 (void)sprintf(cport, ".%xH", htons(port));
eac76d14
MK
812 else
813 *cport = 0;
814
9bd38ba8 815 (void)sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport);
eac76d14
MK
816 upHex(mybuf);
817 return(mybuf);
818}
819
820upHex(p0)
821char *p0;
822{
823 register char *p = p0;
824 for (; *p; p++) switch (*p) {
825
826 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
827 *p += ('A' - 'a');
828 }
829}
57cacc90
KS
830
831monitor()
832{
833 int n;
834 char msg[2048];
835 for(;;) {
836 n = read(s, msg, 2048);
837 printf("got message of size %d\n", n);
838 print_rtmsg((struct rt_msghdr *)msg, n);
839 }
840}
841
842struct {
843 struct rt_msghdr m_rtm;
844 struct sockaddr_in m_dst, m_gateway, m_mask;
845} m_rtmsg;
846
847rtmsg(cmd, dst, gateway, mask, flags)
848struct sockaddr_in *dst, *gateway, *mask;
849{
850 static int seq;
851 int len = sizeof(m_rtmsg), rlen;
852 extern int errno;
853
854 errno = 0;
855 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
856 if (cmd == 'a')
857 cmd = RTM_ADD;
858 else if (cmd == 'c')
859 cmd = RTM_CHANGE;
860 else
861 cmd = RTM_DELETE;
862 m_rtmsg.m_rtm.rtm_flags = flags;
863 m_rtmsg.m_rtm.rtm_version = 1;
864 m_rtmsg.m_rtm.rtm_seq = ++seq;
865 m_rtmsg.m_dst = *dst;
866 m_rtmsg.m_gateway = *gateway;
867 if (mask) {
868 m_rtmsg.m_mask = *mask;
869 m_rtmsg.m_rtm.rtm_count = 3;
870 } else {
871 len -= sizeof (*mask);
872 m_rtmsg.m_rtm.rtm_count = 2;
873 }
874 m_rtmsg.m_rtm.rtm_msglen = len;
875 m_rtmsg.m_rtm.rtm_type = cmd;
876 if ((rlen = write(s, (char *)&m_rtmsg, len)) < 0) {
877 perror("writing to routing socket");
878 printf("got only %d for rlen\n", rlen);
7d5f817b 879 return (-1);
57cacc90
KS
880 }
881again:
882 if ((rlen = read(s, (char *)&m_rtmsg, len)) < 0) {
883 perror("reading from routing socket");
884 printf("got only %d for rlen\n", rlen);
7d5f817b 885 return (-1);
57cacc90
KS
886 }
887 if ((m_rtmsg.m_rtm.rtm_pid != pid) ||
888 (m_rtmsg.m_rtm.rtm_seq != seq)) {
889 printf("Got response for somebody else's request");
890 goto again;
891 }
892 if (qflag == 0)
893 print_rtmsg( &m_rtmsg.m_rtm, rlen);
894 if ((m_rtmsg.m_rtm.rtm_flags & RTF_DONE) == 0) {
895 errno = m_rtmsg.m_rtm.rtm_errno;
896 perror("response from routing socket turned down");
897 return (-1);
898 }
899 return (0);
900}
901
902char *msgtypes[] = {
903"",
904"RTM_ADD: Add Route",
905"RTM_DELETE: Delete Route",
906"RTM_CHANGE: Change Metrics or flags",
907"RTM_GET: Report Metrics",
908"RTM_LOSING: Kernel Suspects Partitioning",
909"RTM_REDIRECT: Told to use different route",
910"RTM_MISS: Lookup failed on this address",
911"RTM_LOCK: fix specified metrics",
912"RTM_OLDADD: caused by SIOCADDRT",
913"RTM_OLDDEL: caused by SIOCDELRT",
9140, };
915
916char metricnames[] =
917"\010rttvar\7rtt\6ssthresh\7sendpipe\4recvpipe\3expire\2hopcount\1mtu";
918
919#define ROUNDUP(a) ((char *)(1 + (((((int)a)) - 1) | (sizeof(long) - 1))))
920
921print_rtmsg(rtm, n)
922register struct rt_msghdr *rtm;
923{
924 char *cp;
925 register struct sockaddr *sa;
926 int i = rtm->rtm_count;
927
7d5f817b
KS
928 if (verbose == 0)
929 return;
57cacc90 930 if (rtm->rtm_version != 1) {
5c7868a2 931 printf("routing message version %d not understood\n",
57cacc90 932 rtm->rtm_version);
5c7868a2
KS
933 } else {
934 printf("%s\npid: %d, len %d, seq %d, errno %d, flags:",
935 msgtypes[rtm->rtm_type], rtm->rtm_pid, rtm->rtm_msglen,
936 rtm->rtm_seq, rtm->rtm_errno);
937 bprintf(stdout, rtm->rtm_flags,
938 "\1UP\2GATEWAY\3HOST\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT");
939 printf("\nlocks: "); bprintf(stdout, rtm->rtm_locks, metricnames);
940 printf(" inits: "); bprintf(stdout, rtm->rtm_inits, metricnames);
941 printf("\n%d sockaddrs: ", i);
942 cp = ((char *)(rtm + 1));
943 while (i-- > 0) {
944 sa = (struct sockaddr *)cp;
945 printf(" %s", routename(sa));
946 cp = ROUNDUP(cp + sa->sa_len);
947 }
948 putchar('\n');
57cacc90 949 }
57cacc90
KS
950 fflush(stdout);
951}
952
953bprintf(fp, b, s)
954register FILE *fp;
955register int b;
956register u_char *s;
957{
958 register int i;
959 int gotsome = 0;
960
961 if (b == 0)
962 return;
963 while (i = *s++) {
964 if (b & (1 << (i-1))) {
965 if (gotsome == 0) i = '<'; else i = ',';
966 putc(i, fp);
967 gotsome = 1;
968 for (; (i = *s) > 32; s++)
969 putc(i, fp);
970 } else
971 while (*s > 32)
972 s++;
973 }
974 if (gotsome)
975 putc('>', fp);
976}