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