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