lint; KNF; make gcc -Wall happy
[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 *
70ab3c27 5 * %sccs.include.redist.c%
5ff67f98
DF
6 */
7
8#ifndef lint
9char copyright[] =
7d5f817b 10"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
5ff67f98 11 All rights reserved.\n";
fca7493d 12#endif /* not lint */
5ff67f98 13
4bec325f 14#ifndef lint
9494af5d 15static char sccsid[] = "@(#)route.c 5.31 (Berkeley) %G%";
fca7493d 16#endif /* not lint */
4bec325f 17
a2280e64 18#include <sys/param.h>
4bec325f
BJ
19#include <sys/socket.h>
20#include <sys/ioctl.h>
5c7868a2 21#include <sys/file.h>
63c817da 22#include <sys/mbuf.h>
9eb5d442 23#include <sys/kinfo.h>
94a2d2a7 24
4bec325f 25#include <net/route.h>
31bd2db6 26#include <net/if_dl.h>
94a2d2a7 27#include <netinet/in.h>
eac76d14 28#include <netns/ns.h>
7d5f817b 29#include <netiso/iso.h>
94a2d2a7 30
5c7868a2 31#include <netdb.h>
4bec325f
BJ
32#include <errno.h>
33#include <ctype.h>
9494af5d
CT
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
505837c5 37#include <paths.h>
4bec325f 38
31bd2db6
KS
39struct keytab {
40 char *kt_cp;
41 int kt_i;
42} keywords[] = {
43#include "keywords.h"
44{0, 0}
45};
46
57cacc90 47struct ortentry route;
31bd2db6 48union sockunion {
7d5f817b
KS
49 struct sockaddr sa;
50 struct sockaddr_in sin;
51 struct sockaddr_ns sns;
52 struct sockaddr_iso siso;
31bd2db6
KS
53 struct sockaddr_dl sdl;
54} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp, *so_addrs[] =
ac62fbdc 55{ &so_dst, &so_gate, &so_mask, &so_genmask, &so_ifp, &so_ifa, 0};
31bd2db6 56typedef union sockunion *sup;
c64fbe35 57int pid, rtm_addrs, uid;
4bec325f 58int s;
31bd2db6 59int forcehost, forcenet, doflush, nflag, af, qflag, Cflag, keyword();
eb03b231 60int iflag, verbose, aflen = sizeof (struct sockaddr_in);
7cd60aa5 61int locking, lockrest, debugonly;
b268b889 62struct sockaddr_in sin = { sizeof(sin), AF_INET };
7cd60aa5 63struct rt_metrics rt_metrics;
7d8dd943 64u_long rtm_inits;
379dcc38 65struct in_addr inet_makeaddr();
9494af5d
CT
66char *routename(), *netname();
67void flushroutes(), newroute(), monitor();
68void print_getmsg(), print_rtmsg(), pmsg_common(), sodump(), bprintf();
69int getaddr(), rtmsg();
70extern char *inet_ntoa(), *iso_ntoa(), *link_ntoa();
4bec325f 71
9494af5d 72void
31bd2db6 73usage(cp)
9494af5d
CT
74 char *cp;
75{
76 (void) fprintf(stderr,
77 "usage: route [ -nqCv ] cmd [[ -<qualifers> ] args ]\n");
78 if (cp)
79 (void) fprintf(stderr, "(botched keyword: %s)\n", cp);
80 exit(1);
81 /* NOTREACHED */
82}
83
84void
85quit(s)
86 char *s;
31bd2db6 87{
9494af5d 88 int sverrno = errno;
31bd2db6 89
9494af5d
CT
90 (void) fprintf(stderr, "route: ");
91 if (s)
92 (void) fprintf(stderr, "%s: ", s);
93 (void) fprintf(stderr, "%s\n", strerror(sverrno));
31bd2db6 94 exit(1);
9494af5d 95 /* NOTREACHED */
31bd2db6 96}
7d8dd943 97
c64fbe35
KS
98#define ROUNDUP(a) \
99 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
100#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
101
9494af5d 102int
4bec325f
BJ
103main(argc, argv)
104 int argc;
105 char *argv[];
106{
b268b889 107 char *argvp;
9494af5d 108
4bec325f 109 if (argc < 2)
9494af5d 110 usage((char *)NULL);
4bec325f 111 argc--, argv++;
b3933da8 112 for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
b268b889 113 for (argvp = argv[0]++; *argvp; argvp++)
b3933da8 114 switch (*argv[0]) {
b3933da8 115 case 'n':
a2280e64 116 nflag++;
b3933da8 117 break;
ae578a19
KS
118 case 'q':
119 qflag++;
120 break;
5c7868a2
KS
121 case 'C':
122 Cflag++; /* Use old ioctls */
57cacc90 123 break;
7d5f817b
KS
124 case 'v':
125 verbose++;
b3933da8
MK
126 }
127 }
5c7868a2 128 pid = getpid();
c64fbe35 129 uid = getuid();
5c7868a2 130 if (Cflag)
57cacc90 131 s = socket(AF_INET, SOCK_RAW, 0);
5c7868a2
KS
132 else
133 s = socket(PF_ROUTE, SOCK_RAW, 0);
9494af5d
CT
134 if (s < 0)
135 quit("socket");
31bd2db6 136 if (argc > 0) switch (keyword(*argv)) {
ac62fbdc 137 case K_GET:
c64fbe35
KS
138 uid = 0;
139 /* FALLTHROUGH */
31bd2db6 140 case K_CHANGE:
c64fbe35
KS
141 if (Cflag)
142 usage("change or get with -C");
143 /* FALLTHROUGH */
144 case K_ADD:
31bd2db6 145 case K_DELETE:
63c817da 146 newroute(argc, argv);
31bd2db6 147 case K_MONITOR:
5c7868a2 148 monitor();
31bd2db6
KS
149 case K_FLUSH:
150 flushroutes(argc, argv);
151 }
152 usage(*argv);
9494af5d 153 /* NOTREACHED */
63c817da
SL
154}
155
156/*
157 * Purge all entries in the routing tables not
158 * associated with network interfaces.
159 */
9494af5d 160void
31bd2db6 161flushroutes(argc, argv)
9494af5d
CT
162 int argc;
163 char *argv[];
b268b889 164{
9494af5d 165 int needed, seqno, rlen;
9eb5d442
KS
166 char *buf, *next, *lim;
167 register struct rt_msghdr *rtm;
9eb5d442 168
c64fbe35
KS
169 if (uid)
170 usage("must be root to alter routing table");
104e26d6 171 shutdown(s, 0); /* Don't want to read back our messages */
31bd2db6
KS
172 if (argc > 1) {
173 argv++;
eb03b231
KS
174 if (argc == 2 && **argv == '-') switch (keyword(1 + *argv)) {
175 case K_INET: af = AF_INET; break;
176 case K_XNS: af = AF_NS; break;
177 case K_LINK: af = AF_LINK; break;
178 case K_ISO: case K_OSI: af = AF_ISO; break;
31bd2db6
KS
179 default: goto bad;
180 } else
181 bad: usage(*argv);
182 }
9eb5d442 183 if ((needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0)) < 0)
9494af5d
CT
184 quit("route-getkerninfo-estimate");
185 if ((buf = malloc(needed)) == NULL)
186 quit("malloc");
9eb5d442 187 if ((rlen = getkerninfo(KINFO_RT_DUMP, buf, &needed, 0)) < 0)
9494af5d 188 quit("actual retrieval of routing table");
9eb5d442 189 lim = buf + rlen;
9494af5d 190 seqno = 0; /* ??? */
9eb5d442
KS
191 for (next = buf; next < lim; next += rtm->rtm_msglen) {
192 rtm = (struct rt_msghdr *)next;
eb03b231 193 if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
9eb5d442 194 continue;
31bd2db6
KS
195 if (af) {
196 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
197 if (sa->sa_family != af)
198 continue;
199 }
9eb5d442
KS
200 rtm->rtm_type = RTM_DELETE;
201 rtm->rtm_seq = seqno;
ac62fbdc
KS
202 rlen = write(s, next, rtm->rtm_msglen);
203 if (rlen < (int)rtm->rtm_msglen) {
9494af5d
CT
204 (void) fprintf(stderr,
205 "route: write to routing socket: %s\n",
206 strerror(errno));
207 (void) printf("got only %d for rlen\n", rlen);
31bd2db6 208 break;
b268b889 209 }
9eb5d442
KS
210 seqno++;
211 if (qflag)
212 continue;
9494af5d 213 if (verbose)
31bd2db6 214 print_rtmsg(rtm, rlen);
9494af5d 215 else {
039256d2 216 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
9494af5d 217 (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
9eb5d442
KS
218 routename(sa) : netname(sa));
219 sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
9494af5d
CT
220 (void) printf("%-20.20s ", routename(sa));
221 (void) printf("done\n");
57cacc90
KS
222 }
223 }
31bd2db6 224 exit(0);
9494af5d 225 /* NOTREACHED */
57cacc90 226}
9eb5d442 227
63c817da 228char *
eac76d14
MK
229routename(sa)
230 struct sockaddr *sa;
63c817da 231{
a2280e64 232 register char *cp;
63c817da 233 static char line[50];
6edb1941 234 struct hostent *hp;
a2280e64
MK
235 static char domain[MAXHOSTNAMELEN + 1];
236 static int first = 1;
eac76d14 237 char *ns_print();
63c817da 238
a2280e64
MK
239 if (first) {
240 first = 0;
241 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
242 (cp = index(domain, '.')))
243 (void) strcpy(domain, cp + 1);
244 else
245 domain[0] = 0;
246 }
eac76d14
MK
247 switch (sa->sa_family) {
248
249 case AF_INET:
250 { struct in_addr in;
251 in = ((struct sockaddr_in *)sa)->sin_addr;
252
253 cp = 0;
254 if (in.s_addr == INADDR_ANY)
255 cp = "default";
256 if (cp == 0 && !nflag) {
257 hp = gethostbyaddr(&in, sizeof (struct in_addr),
258 AF_INET);
259 if (hp) {
260 if ((cp = index(hp->h_name, '.')) &&
261 !strcmp(cp + 1, domain))
262 *cp = 0;
263 cp = hp->h_name;
264 }
a2280e64 265 }
eac76d14
MK
266 if (cp)
267 strcpy(line, cp);
268 else {
a2280e64 269#define C(x) ((x) & 0xff)
eac76d14 270 in.s_addr = ntohl(in.s_addr);
9494af5d 271 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
eac76d14
MK
272 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
273 }
274 break;
275 }
276
277 case AF_NS:
278 return (ns_print((struct sockaddr_ns *)sa));
279
31bd2db6
KS
280 case AF_LINK:
281 return (link_ntoa((struct sockaddr_dl *)sa));
282
283 case AF_ISO:
284 (void) sprintf(line, "iso %s",
285 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
286 break;
287
eac76d14
MK
288 default:
289 { u_short *s = (u_short *)sa->sa_data;
9494af5d 290 u_short *slim = s + ((sa->sa_len + 1) >> 1);
31bd2db6 291 char *cp = line + sprintf(line, "(%d)", sa->sa_family);
eac76d14 292
9494af5d
CT
293 while (s < slim)
294 cp += sprintf(cp, " %x", *s++);
eac76d14
MK
295 break;
296 }
a2280e64
MK
297 }
298 return (line);
299}
300
301/*
302 * Return the name of the network whose address is given.
303 * The address is assumed to be that of a net or subnet, not a host.
304 */
305char *
eac76d14
MK
306netname(sa)
307 struct sockaddr *sa;
a2280e64
MK
308{
309 char *cp = 0;
310 static char line[50];
311 struct netent *np = 0;
312 u_long net, mask;
e2fe1192 313 register u_long i;
a2280e64 314 int subnetshift;
a48a48cc 315 char *ns_print();
a2280e64 316
eac76d14
MK
317 switch (sa->sa_family) {
318
319 case AF_INET:
320 { struct in_addr in;
321 in = ((struct sockaddr_in *)sa)->sin_addr;
322
e2fe1192 323 i = in.s_addr = ntohl(in.s_addr);
eac76d14
MK
324 if (in.s_addr == 0)
325 cp = "default";
326 else if (!nflag) {
327 if (IN_CLASSA(i)) {
328 mask = IN_CLASSA_NET;
329 subnetshift = 8;
330 } else if (IN_CLASSB(i)) {
331 mask = IN_CLASSB_NET;
332 subnetshift = 8;
333 } else {
334 mask = IN_CLASSC_NET;
335 subnetshift = 4;
336 }
337 /*
338 * If there are more bits than the standard mask
339 * would suggest, subnets must be in use.
340 * Guess at the subnet mask, assuming reasonable
341 * width subnet fields.
342 */
343 while (in.s_addr &~ mask)
344 mask = (long)mask >> subnetshift;
345 net = in.s_addr & mask;
346 while ((mask & 1) == 0)
347 mask >>= 1, net >>= 1;
348 np = getnetbyaddr(net, AF_INET);
349 if (np)
350 cp = np->n_name;
a2280e64 351 }
eac76d14
MK
352 if (cp)
353 strcpy(line, cp);
354 else if ((in.s_addr & 0xffffff) == 0)
9494af5d 355 (void) sprintf(line, "%u", C(in.s_addr >> 24));
eac76d14 356 else if ((in.s_addr & 0xffff) == 0)
9494af5d 357 (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
eac76d14
MK
358 C(in.s_addr >> 16));
359 else if ((in.s_addr & 0xff) == 0)
9494af5d 360 (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
eac76d14
MK
361 C(in.s_addr >> 16), C(in.s_addr >> 8));
362 else
9494af5d 363 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
eac76d14
MK
364 C(in.s_addr >> 16), C(in.s_addr >> 8),
365 C(in.s_addr));
366 break;
367 }
368
369 case AF_NS:
370 return (ns_print((struct sockaddr_ns *)sa));
371 break;
372
31bd2db6
KS
373 case AF_LINK:
374 return (link_ntoa((struct sockaddr_dl *)sa));
375
376 case AF_ISO:
377 (void) sprintf(line, "iso %s",
378 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
379 break;
380
eac76d14
MK
381 default:
382 { u_short *s = (u_short *)sa->sa_data;
31bd2db6
KS
383 u_short *slim = s + ((sa->sa_len + 1)>>1);
384 char *cp = line + sprintf(line, "af %d:", sa->sa_family);
eac76d14 385
9494af5d
CT
386 while (s < slim)
387 cp += sprintf(cp, " %x", *s++);
eac76d14
MK
388 break;
389 }
63c817da
SL
390 }
391 return (line);
4bec325f
BJ
392}
393
9494af5d 394void
7cd60aa5 395set_metric(value, key)
9494af5d
CT
396 char *value;
397 int key;
7cd60aa5
KS
398{
399 int flag = 0;
400 u_long noval, *valp = &noval;
401
402 switch (key) {
403#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
404 caseof(K_MTU, RTV_MTU, rmx_mtu);
405 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
406 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
407 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
408 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
409 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
410 caseof(K_RTT, RTV_RTT, rmx_rtt);
411 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
412 }
7d8dd943 413 rtm_inits |= flag;
7cd60aa5
KS
414 if (lockrest || locking)
415 rt_metrics.rmx_locks |= flag;
416 if (locking)
417 locking = 0;
418 *valp = atoi(value);
419}
420
9494af5d 421void
4bec325f
BJ
422newroute(argc, argv)
423 int argc;
31bd2db6 424 register char **argv;
4bec325f 425{
9494af5d
CT
426 char *cmd, *dest = "", *gateway = "", *err;
427 int ishost = 0, ret, attempts, oerrno, flags = 0;
7cd60aa5 428 int key;
31bd2db6 429 struct hostent *hp = 0;
4bec325f 430
c64fbe35
KS
431 if (uid)
432 usage("must be root to alter routing table");
183ef13b 433 cmd = argv[0];
ac62fbdc
KS
434 if (*cmd != 'g')
435 shutdown(s, 0); /* Don't want to read back our messages */
31bd2db6
KS
436 while (--argc > 0) {
437 if (**(++argv)== '-') {
9494af5d 438 switch (key = keyword(1 + *argv)) {
31bd2db6
KS
439 case K_LINK:
440 af = AF_LINK;
eb03b231 441 aflen = sizeof(struct sockaddr_dl);
31bd2db6
KS
442 break;
443 case K_OSI:
eb03b231 444 case K_ISO:
31bd2db6 445 af = AF_ISO;
eb03b231 446 aflen = sizeof(struct sockaddr_iso);
31bd2db6
KS
447 break;
448 case K_INET:
449 af = AF_INET;
eb03b231 450 aflen = sizeof(struct sockaddr_in);
31bd2db6
KS
451 break;
452 case K_XNS:
453 af = AF_NS;
eb03b231 454 aflen = sizeof(struct sockaddr_ns);
31bd2db6
KS
455 break;
456 case K_IFACE:
7cd60aa5 457 case K_INTERFACE:
31bd2db6
KS
458 iflag++;
459 break;
7cd60aa5
KS
460 case K_LOCK:
461 locking = 1;
462 break;
463 case K_LOCKREST:
464 lockrest = 1;
465 break;
31bd2db6
KS
466 case K_HOST:
467 forcehost++;
468 break;
039256d2
KS
469 case K_REJECT:
470 flags |= RTF_REJECT;
471 break;
7cd60aa5
KS
472 case K_CLONING:
473 flags |= RTF_CLONING;
474 break;
475 case K_XRESOLVE:
476 flags |= RTF_XRESOLVE;
477 break;
ac62fbdc
KS
478 case K_IFA:
479 argc--;
480 (void) getaddr(RTA_IFA, *++argv, 0);
481 break;
482 case K_IFP:
483 argc--;
484 (void) getaddr(RTA_IFP, *++argv, 0);
485 break;
31bd2db6
KS
486 case K_GENMASK:
487 argc--;
488 (void) getaddr(RTA_GENMASK, *++argv, 0);
489 break;
ac62fbdc
KS
490 case K_GATEWAY:
491 argc--;
492 (void) getaddr(RTA_GATEWAY, *++argv, 0);
493 break;
494 case K_DST:
495 argc--;
496 ishost = getaddr(RTA_DST, *++argv, &hp);
497 dest = *argv;
498 break;
499 case K_NETMASK:
500 argc--;
501 (void) getaddr(RTA_NETMASK, *++argv, 0);
502 /* FALLTHROUGH */
503 case K_NET:
504 forcenet++;
505 break;
7cd60aa5
KS
506 case K_MTU:
507 case K_HOPCOUNT:
508 case K_EXPIRE:
509 case K_RECVPIPE:
510 case K_SENDPIPE:
511 case K_SSTHRESH:
512 case K_RTT:
513 case K_RTTVAR:
514 argc--;
515 set_metric(*++argv, key);
516 break;
31bd2db6
KS
517 default:
518 usage(1+*argv);
519 }
520 } else {
521 if ((rtm_addrs & RTA_DST) == 0) {
522 dest = *argv;
523 ishost = getaddr(RTA_DST, *argv, &hp);
524 } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
525 gateway = *argv;
526 (void) getaddr(RTA_GATEWAY, *argv, &hp);
527 } else {
528 int ret = atoi(*argv);
529 if (ret == 0) {
530 printf("%s,%s", "old usage of trailing 0",
531 "assuming route to if\n");
532 iflag = 1;
533 continue;
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 continue;
539 }
540 (void) getaddr(RTA_NETMASK, *argv, 0);
541 }
542 }
543 }
b3933da8
MK
544 if (forcehost)
545 ishost = 1;
546 if (forcenet)
547 ishost = 0;
7cd60aa5 548 flags |= RTF_UP;
6edb1941 549 if (ishost)
7d5f817b 550 flags |= RTF_HOST;
57cacc90 551 if (iflag == 0)
7d5f817b 552 flags |= RTF_GATEWAY;
792b0612
MK
553 for (attempts = 1; ; attempts++) {
554 errno = 0;
31bd2db6 555 if (Cflag && (af == AF_INET || af == AF_NS)) {
7d5f817b
KS
556 route.rt_flags = flags;
557 route.rt_dst = so_dst.sa;
558 route.rt_gateway = so_gate.sa;
57cacc90
KS
559 if ((ret = ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT,
560 (caddr_t)&route)) == 0)
561 break;
562 } else {
ac62fbdc 563 if ((ret = rtmsg(*cmd, flags)) == 0)
57cacc90
KS
564 break;
565 }
792b0612
MK
566 if (errno != ENETUNREACH && errno != ESRCH)
567 break;
ac62fbdc 568 if (af == AF_INET && hp && hp->h_addr_list[1]) {
792b0612 569 hp->h_addr_list++;
7d5f817b 570 bcopy(hp->h_addr_list[0], (caddr_t)&so_dst.sin.sin_addr,
792b0612
MK
571 hp->h_length);
572 } else
573 break;
574 }
ac62fbdc
KS
575 if (*cmd == 'g')
576 exit(0);
792b0612 577 oerrno = errno;
9494af5d 578 (void) printf("%s %s %s: gateway %s", cmd, ishost? "host" : "net",
792b0612
MK
579 dest, gateway);
580 if (attempts > 1 && ret == 0)
9494af5d 581 (void) printf(" (%s)",
792b0612
MK
582 inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
583 if (ret == 0)
9494af5d 584 (void) printf("\n");
792b0612 585 else {
9494af5d
CT
586 switch (oerrno) {
587 case ESRCH:
588 err = "not in table";
589 break;
590 case EBUSY:
591 err = "entry in use";
592 break;
593 case ENOBUFS:
594 err = "routing table overflow";
595 break;
596 default:
597 err = strerror(oerrno);
598 break;
599 }
600 (void) printf(": %s\n", err);
792b0612 601 }
31bd2db6 602 exit(0);
9494af5d 603 /* NOTREACHED */
4bec325f
BJ
604}
605
9494af5d 606void
31bd2db6 607inet_makenetandmask(net, sin)
9494af5d
CT
608 u_long net;
609 register struct sockaddr_in *sin;
57cacc90 610{
9494af5d 611 u_long addr, mask = 0;
31bd2db6 612 register char *cp;
57cacc90 613
31bd2db6 614 rtm_addrs |= RTA_NETMASK;
57cacc90 615 if (net == 0)
5c7868a2 616 mask = addr = 0;
57cacc90
KS
617 else if (net < 128) {
618 addr = net << IN_CLASSA_NSHIFT;
5c7868a2 619 mask = IN_CLASSA_NET;
57cacc90
KS
620 } else if (net < 65536) {
621 addr = net << IN_CLASSB_NSHIFT;
5c7868a2 622 mask = IN_CLASSB_NET;
57cacc90
KS
623 } else if (net < 16777216L) {
624 addr = net << IN_CLASSC_NSHIFT;
5c7868a2 625 mask = IN_CLASSC_NET;
57cacc90
KS
626 } else {
627 addr = net;
628 if ((addr & IN_CLASSA_HOST) == 0)
5c7868a2 629 mask = IN_CLASSA_NET;
57cacc90 630 else if ((addr & IN_CLASSB_HOST) == 0)
5c7868a2 631 mask = IN_CLASSB_NET;
57cacc90 632 else if ((addr & IN_CLASSC_HOST) == 0)
5c7868a2 633 mask = IN_CLASSC_NET;
57cacc90 634 else
5c7868a2
KS
635 mask = -1;
636 }
31bd2db6
KS
637 sin->sin_addr.s_addr = htonl(addr);
638 sin = &so_mask.sin;
639 sin->sin_addr.s_addr = htonl(mask);
640 sin->sin_len = 0;
641 sin->sin_family = 0;
9494af5d 642 cp = (char *)(&sin->sin_addr + 1);
31bd2db6
KS
643 while (*--cp == 0 && cp > (char *)sin)
644 ;
645 sin->sin_len = 1 + cp - (char *)sin;
57cacc90
KS
646}
647
6edb1941
MK
648/*
649 * Interpret an argument as a network address of some kind,
650 * returning 1 if a host address, 0 if a network address.
651 */
9494af5d 652int
31bd2db6 653getaddr(which, s, hpp)
9494af5d 654 int which;
4bec325f 655 char *s;
792b0612 656 struct hostent **hpp;
4bec325f 657{
ac62fbdc 658 register sup su;
9494af5d 659 struct ns_addr ns_addr();
eb03b231 660 struct iso_addr *iso_addr();
accbc2e3 661 struct hostent *hp;
379dcc38 662 struct netent *np;
31bd2db6 663 u_long val;
accbc2e3 664
eb03b231 665 if (af == 0) {
31bd2db6 666 af = AF_INET;
eb03b231
KS
667 aflen = sizeof(struct sockaddr_in);
668 }
669 rtm_addrs |= which;
31bd2db6 670 switch (which) {
eb03b231
KS
671 case RTA_DST: su = so_addrs[0]; su->sa.sa_family = af; break;
672 case RTA_GATEWAY: su = so_addrs[1]; su->sa.sa_family = af; break;
673 case RTA_NETMASK: su = so_addrs[2]; break;
31bd2db6 674 case RTA_GENMASK: su = so_addrs[3]; break;
ac62fbdc
KS
675 case RTA_IFP: su = so_addrs[4]; su->sa.sa_family = af; break;
676 case RTA_IFA: su = so_addrs[5]; su->sa.sa_family = af; break;
31bd2db6
KS
677 default: usage("Internal Error"); /*NOTREACHED*/
678 }
eb03b231 679 su->sa.sa_len = aflen;
7d5f817b 680 if (strcmp(s, "default") == 0) {
eb03b231
KS
681 switch (which) {
682 case RTA_DST:
683 forcenet++;
9494af5d 684 (void) getaddr(RTA_NETMASK, s, 0);
eb03b231
KS
685 break;
686 case RTA_NETMASK:
687 case RTA_GENMASK:
688 su->sa.sa_len = 0;
689 }
31bd2db6 690 return 0;
7d5f817b 691 }
31bd2db6 692 if (af == AF_NS)
b268b889 693 goto do_xns;
31bd2db6 694 if (af == AF_OSI)
7d5f817b 695 goto do_osi;
31bd2db6
KS
696 if (af == AF_LINK)
697 goto do_link;
9494af5d
CT
698 if (hpp == NULL)
699 hpp = &hp;
700 *hpp = NULL;
85e467b1
KS
701 if (((val = inet_addr(s)) != -1) &&
702 (which != RTA_DST || forcenet == 0)) {
31bd2db6
KS
703 su->sin.sin_addr.s_addr = val;
704 if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
705 return (1);
706 else {
707 val = ntohl(val);
708 out: if (which == RTA_DST)
709 inet_makenetandmask(val, &su->sin);
710 return (0);
a2280e64 711 }
792b0612
MK
712 }
713 val = inet_network(s);
714 if (val != -1) {
5c7868a2 715 goto out;
792b0612 716 }
379dcc38
SL
717 np = getnetbyname(s);
718 if (np) {
5c7868a2 719 val = np->n_net;
5c7868a2 720 goto out;
379dcc38 721 }
78160c55
MK
722 hp = gethostbyname(s);
723 if (hp) {
792b0612 724 *hpp = hp;
31bd2db6 725 su->sin.sin_family = hp->h_addrtype;
9494af5d 726 bcopy(hp->h_addr, (char *)&su->sin.sin_addr, hp->h_length);
57cacc90 727 return (1);
78160c55 728 }
9494af5d 729 (void) fprintf(stderr, "%s: bad value\n", s);
379dcc38 730 exit(1);
b268b889 731do_xns:
31bd2db6 732 if (which == RTA_DST) {
57cacc90 733 extern short ns_bh[3];
31bd2db6
KS
734 struct sockaddr_ns *sms = &(so_mask.sns);
735 bzero((char *)sms, sizeof(*sms));
57cacc90
KS
736 sms->sns_family = 0;
737 sms->sns_len = 6;
738 sms->sns_addr.x_net = *(union ns_net *)ns_bh;
31bd2db6 739 rtm_addrs |= RTA_NETMASK;
57cacc90 740 }
31bd2db6
KS
741 su->sns.sns_addr = ns_addr(s);
742 return (!ns_nullhost(su->sns.sns_addr));
7d5f817b 743do_osi:
eb03b231
KS
744 su->siso.siso_addr = *iso_addr(s);
745 if (which == RTA_NETMASK || which == RTA_GENMASK) {
746 register char *cp = (char *)TSEL(&su->siso);
747 su->siso.siso_nlen = 0;
748 do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
749 su->siso.siso_len = 1 + cp - (char *)su;
750 }
31bd2db6
KS
751 return (1);
752do_link:
31bd2db6 753 link_addr(s, &su->sdl);
7d5f817b 754 return (1);
183ef13b 755}
eac76d14
MK
756
757short ns_nullh[] = {0,0,0};
758short ns_bh[] = {-1,-1,-1};
759
760char *
761ns_print(sns)
9494af5d 762 struct sockaddr_ns *sns;
eac76d14
MK
763{
764 struct ns_addr work;
765 union { union ns_net net_e; u_long long_e; } net;
766 u_short port;
767 static char mybuf[50], cport[10], chost[25];
768 char *host = "";
9494af5d
CT
769 register char *p;
770 register u_char *q;
eac76d14
MK
771
772 work = sns->sns_addr;
773 port = ntohs(work.x_port);
774 work.x_port = 0;
775 net.net_e = work.x_net;
776 if (ns_nullhost(work) && net.long_e == 0) {
9494af5d
CT
777 if (!port)
778 return ("*.*");
779 (void) sprintf(mybuf, "*.%XH", port);
eac76d14
MK
780 return (mybuf);
781 }
782
9494af5d 783 if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0)
eac76d14 784 host = "any";
9494af5d 785 else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0)
eac76d14 786 host = "*";
9494af5d 787 else {
eac76d14 788 q = work.x_host.c_host;
9494af5d 789 (void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
eac76d14 790 q[0], q[1], q[2], q[3], q[4], q[5]);
9494af5d
CT
791 for (p = chost; *p == '0' && p < chost + 12; p++)
792 /* void */;
eac76d14
MK
793 host = p;
794 }
795 if (port)
9494af5d 796 (void) sprintf(cport, ".%XH", htons(port));
eac76d14
MK
797 else
798 *cport = 0;
799
9494af5d
CT
800 (void) sprintf(mybuf,"%XH.%s%s", ntohl(net.long_e), host, cport);
801 return (mybuf);
eac76d14 802}
57cacc90 803
9494af5d 804void
57cacc90
KS
805monitor()
806{
807 int n;
808 char msg[2048];
9494af5d 809
9eb5d442 810 verbose = 1;
57cacc90
KS
811 for(;;) {
812 n = read(s, msg, 2048);
9494af5d 813 (void) printf("got message of size %d\n", n);
31bd2db6 814 print_rtmsg((struct rt_msghdr *)msg);
57cacc90
KS
815 }
816}
817
818struct {
819 struct rt_msghdr m_rtm;
9494af5d 820 char m_space[512];
57cacc90
KS
821} m_rtmsg;
822
9494af5d 823int
31bd2db6 824rtmsg(cmd, flags)
9494af5d 825 int cmd, flags;
57cacc90
KS
826{
827 static int seq;
85e467b1 828 int rlen;
31bd2db6
KS
829 register char *cp = m_rtmsg.m_space;
830 register int l;
57cacc90 831
c64fbe35
KS
832#define NEXTADDR(w, u) \
833 if (rtm_addrs & (w)) {\
834 l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
835 if (verbose) sodump(&(u),"u");\
836 }
ac62fbdc 837
57cacc90
KS
838 errno = 0;
839 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
840 if (cmd == 'a')
841 cmd = RTM_ADD;
842 else if (cmd == 'c')
843 cmd = RTM_CHANGE;
ac62fbdc
KS
844 else if (cmd == 'g')
845 cmd = RTM_GET;
57cacc90
KS
846 else
847 cmd = RTM_DELETE;
ac62fbdc
KS
848#define rtm m_rtmsg.m_rtm
849 rtm.rtm_type = cmd;
850 rtm.rtm_flags = flags;
851 rtm.rtm_version = RTM_VERSION;
852 rtm.rtm_seq = ++seq;
853 rtm.rtm_addrs = rtm_addrs;
854 rtm.rtm_rmx = rt_metrics;
855 rtm.rtm_inits = rtm_inits;
31bd2db6
KS
856
857 NEXTADDR(RTA_DST, so_dst);
858 NEXTADDR(RTA_GATEWAY, so_gate);
859 NEXTADDR(RTA_NETMASK, so_mask);
860 NEXTADDR(RTA_GENMASK, so_genmask);
ac62fbdc
KS
861 NEXTADDR(RTA_IFP, so_ifp);
862 NEXTADDR(RTA_IFA, so_ifa);
863 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
31bd2db6 864 if (verbose)
ac62fbdc 865 print_rtmsg(&rtm, l);
7cd60aa5
KS
866 if (debugonly)
867 return 0;
85e467b1 868 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
57cacc90 869 perror("writing to routing socket");
7d5f817b 870 return (-1);
57cacc90 871 }
ac62fbdc
KS
872 if (cmd == RTM_GET) {
873 do {
874 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
875 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
876 if (l < 0)
9494af5d
CT
877 (void) fprintf(stderr,
878 "route: read from routing socket: %s\n",
879 strerror(errno));
ac62fbdc
KS
880 else
881 print_getmsg(&rtm, l);
882 }
883#undef rtm
57cacc90
KS
884 return (0);
885}
886
887char *msgtypes[] = {
9494af5d
CT
888 "",
889 "RTM_ADD: Add Route",
890 "RTM_DELETE: Delete Route",
891 "RTM_CHANGE: Change Metrics or flags",
892 "RTM_GET: Report Metrics",
893 "RTM_LOSING: Kernel Suspects Partitioning",
894 "RTM_REDIRECT: Told to use different route",
895 "RTM_MISS: Lookup failed on this address",
896 "RTM_LOCK: fix specified metrics",
897 "RTM_OLDADD: caused by SIOCADDRT",
898 "RTM_OLDDEL: caused by SIOCDELRT",
899 0,
900};
57cacc90
KS
901
902char metricnames[] =
7cd60aa5
KS
903"\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
904char routeflags[] =
039256d2 905"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE";
57cacc90 906
57cacc90 907
9494af5d 908void
ac62fbdc 909print_rtmsg(rtm, msglen)
9494af5d
CT
910 register struct rt_msghdr *rtm;
911 int msglen;
57cacc90 912{
7d5f817b
KS
913 if (verbose == 0)
914 return;
a387100b 915 if (rtm->rtm_version != RTM_VERSION) {
9494af5d
CT
916 (void) printf("routing message version %d not understood\n",
917 rtm->rtm_version);
918 return;
57cacc90 919 }
9494af5d 920 (void) printf("%s\npid: %d, len %d, seq %d, errno %d, flags:",
ac62fbdc
KS
921 msgtypes[rtm->rtm_type], rtm->rtm_pid, rtm->rtm_msglen,
922 rtm->rtm_seq, rtm->rtm_errno);
923 bprintf(stdout, rtm->rtm_flags, routeflags);
924 pmsg_common(rtm);
925}
926
9494af5d 927void
ac62fbdc 928print_getmsg(rtm, msglen)
9494af5d
CT
929 register struct rt_msghdr *rtm;
930 int msglen;
ac62fbdc
KS
931{
932 if (rtm->rtm_version != RTM_VERSION) {
9494af5d
CT
933 (void)printf("routing message version %d not understood\n",
934 rtm->rtm_version);
ac62fbdc
KS
935 return;
936 }
c64fbe35 937 if (rtm->rtm_msglen > msglen) {
9494af5d
CT
938 (void)printf("get length mismatch, in packet %d, returned %d\n",
939 rtm->rtm_msglen, msglen);
ac62fbdc 940 }
9494af5d 941 (void) printf("RTM_GET: errno %d, flags:", rtm->rtm_errno);
ac62fbdc 942 bprintf(stdout, rtm->rtm_flags, routeflags);
9494af5d 943 (void) printf("\nmetric values:\n\n");
ac62fbdc
KS
944#define metric(f, e) printf("\t%s:\t%d\n", "f", rtm->rtm_rmx.e)
945 metric(RTV_RPIPE, rmx_recvpipe);
946 metric(RTV_SPIPE, rmx_sendpipe);
947 metric(RTV_SSTHRESH, rmx_ssthresh);
948 metric(RTV_RTT, rmx_rtt);
949 metric(RTV_RTTVAR, rmx_rttvar);
950 metric(RTV_HOPCOUNT, rmx_hopcount);
951 metric(RTV_MTU, rmx_mtu);
952 metric(RTV_EXPIRE, rmx_expire);
953#undef metric
954 pmsg_common(rtm);
955}
956
9494af5d 957void
ac62fbdc 958pmsg_common(rtm)
9494af5d 959 register struct rt_msghdr *rtm;
ac62fbdc
KS
960{
961 char *cp;
962 register struct sockaddr *sa;
963 int i;
964
9494af5d
CT
965 (void) printf("\nlocks: ");
966 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
967 (void) printf(" inits: ");
968 bprintf(stdout, rtm->rtm_inits, metricnames);
969 (void) printf("\nsockaddrs: ");
ac62fbdc
KS
970 bprintf(stdout, rtm->rtm_addrs,
971 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR");
9494af5d 972 (void) putchar('\n');
ac62fbdc
KS
973 cp = ((char *)(rtm + 1));
974 if (rtm->rtm_addrs)
9494af5d
CT
975 for (i = 1; i; i <<= 1)
976 if (i & rtm->rtm_addrs) {
977 sa = (struct sockaddr *)cp;
978 (void) printf(" %s", routename(sa));
979 ADVANCE(cp, sa);
980 }
981 (void) putchar('\n');
982 (void) fflush(stdout);
57cacc90
KS
983}
984
9494af5d 985void
57cacc90 986bprintf(fp, b, s)
9494af5d
CT
987 register FILE *fp;
988 register int b;
989 register u_char *s;
57cacc90
KS
990{
991 register int i;
992 int gotsome = 0;
993
994 if (b == 0)
995 return;
996 while (i = *s++) {
997 if (b & (1 << (i-1))) {
9494af5d
CT
998 if (gotsome == 0)
999 i = '<';
1000 else
1001 i = ',';
1002 (void) putc(i, fp);
57cacc90
KS
1003 gotsome = 1;
1004 for (; (i = *s) > 32; s++)
9494af5d 1005 (void) putc(i, fp);
57cacc90
KS
1006 } else
1007 while (*s > 32)
1008 s++;
1009 }
1010 if (gotsome)
9494af5d 1011 (void) putc('>', fp);
57cacc90 1012}
9494af5d 1013
31bd2db6
KS
1014int
1015keyword(cp)
9494af5d 1016 char *cp;
31bd2db6
KS
1017{
1018 register struct keytab *kt = keywords;
9494af5d 1019
31bd2db6
KS
1020 while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1021 kt++;
1022 return kt->kt_i;
1023}
1024
9494af5d 1025void
31bd2db6 1026sodump(su, which)
9494af5d
CT
1027 register sup su;
1028 char *which;
31bd2db6
KS
1029{
1030 switch (su->sa.sa_family) {
1031 case AF_LINK:
9494af5d
CT
1032 (void) printf("%s: link %s; ",
1033 which, link_ntoa(&su->sdl));
31bd2db6
KS
1034 break;
1035 case AF_ISO:
9494af5d
CT
1036 (void) printf("%s: iso %s; ",
1037 which, iso_ntoa(&su->siso.siso_addr));
31bd2db6
KS
1038 break;
1039 case AF_INET:
9494af5d
CT
1040 (void) printf("%s: inet %s; ",
1041 which, inet_ntoa(su->sin.sin_addr));
31bd2db6
KS
1042 break;
1043 case AF_NS:
9494af5d
CT
1044 (void) printf("%s: xns %s; ",
1045 which, ns_ntoa(su->sns.sns_addr));
31bd2db6
KS
1046 break;
1047 }
9494af5d 1048 (void) fflush(stdout);
31bd2db6 1049}