Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / network / common / C / route.c
blob0d323ad9f2030a6e4fae2d0535f2c98eaaf67a74
1 /*
2 * Copyright © 1983, 1989 The Regents of the University of California.
3 * All rights reserved.
4 * Copyright © 2005 Pavel Fedin
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #if 0
36 static char sccsid[] = "@(#)route.c 5.35 (Berkeley) 6/27/91";
37 #endif
39 /****** netutil.doc/route ***************************************************
41 * NAME
42 * route - manually manipulate the routing tables
44 * SYNOPSIS
45 * route [-n] [-q] [-v] command [modifiers] destination gateway
47 * DESCRIPTION
48 * Route is a program used to manually manipulate the network routing
49 * tables.
51 * Options supported by route:
53 * -n Prevent attempts to print host and network names
54 * symbolically when reporting actions.
56 * -v (verbose) Print additional details.
58 * -q Suppress all output.
60 * Commands accepted by route:
62 * add Add a route.
63 * delete Delete a specific route.
65 * The destination is the destination host or network, gateway is the
66 * next-hop gateway to which packets should be addressed. Routes to a
67 * particular host are distinguished from those to a network by
68 * interpreting the Internet address associated with destination. The
69 * optional modifiers -net and -host force the destination to be
70 * interpreted as a network or a host, respectively. Otherwise, if the
71 * destination has a ``local address part'' of INADDR_ANY, or if the
72 * destination is the symbolic name of a network, then the route is
73 * assumed to be to a network; otherwise, it is presumed to be a route
74 * to a host.
76 * For example, 128.32 is interpreted as -host 128.0.0.32; 128.32.130
77 * is interpreted as -host 128.32.0.130; -net 128.32 is interpreted as
78 * 128.32.0.0; and -net 128.32.130 is interpreted as 128.32.130.0.
80 * To add a default route, give the destination as 'default'.
82 * If the route is via an interface rather than via a gateway, the
83 * -interface modifier should be specified; the gateway given is the
84 * address of this host on the common network, indicating the interface
85 * to be used for transmission.
87 * The optional -netmask qualifier is used to specify the netmask of
88 * the interface. One specifies an additional ensuing address parameter
89 * (to be interpreted as a network mask). The implicit network mask
90 * generated can be overridden by making sure this option follows the
91 * destination parameter.
93 * All symbolic names specified for a destination or gateway are looked
94 * up first as a host name using gethostbyname(). If this lookup fails,
95 * getnetbyname() is then used to interpret the name as that of a
96 * network.
98 * DIAGNOSTICS
99 * add [host | network ] %s: gateway %s flags %x
100 * The specified route is being added to the tables. The values
101 * printed are from the routing table entry supplied in the
102 * IoctlSocket() call. If the gateway address used was not the
103 * primary address of the gateway (the first one returned by
104 * gethostbyname()), the gateway address is printed numerically
105 * as well as symbolically.
107 * delete [ host | network ] %s: gateway %s flags %x
108 * As above, but when deleting an entry.
110 * Network is unreachable
111 * An attempt to add a route failed because the gateway listed
112 * was not on a directly-connected network. The next-hop
113 * gateway must be given.
115 * not in table
116 * A delete operation was attempted for an entry which wasn't
117 * present in the tables.
119 * routing table overflow
120 * An add operation was attempted, but the system was low on
121 * resources and was unable to allocate memory to create the
122 * new entry.
124 * SEE ALSO
125 * ifconfig, protocols/routing
127 * HISTORY
128 * The route command appeared in 4.2BSD.
130 *****************************************************************************
133 #define D(x)
135 #include <stdio.h>
136 #include <sys/errno.h>
137 #include <ctype.h>
138 #include <stdlib.h>
139 #include <string.h>
141 #include <stdio.h> /* NC */
142 #include <sys/param.h>
143 #include <sys/socket.h>
144 #include <sys/sockio.h>
146 #include <net/route.h>
147 #include <netinet/in.h>
148 #include <arpa/inet.h>
149 #include <netdb.h>
151 #include <dos/dos.h>
153 #include <proto/socket.h>
154 #include <proto/exec.h>
155 #define herror(x) perror(x)
156 #define ioctl IoctlSocket
157 /*#include <clib/netlib_protos.h>*/
159 struct keytab {
160 char *kt_cp;
161 int kt_i;
162 } keywords[] = {
163 #include "keywords.h"
164 {0, 0}
167 struct ortentry route;
168 union sockunion {
169 struct sockaddr sa;
170 struct sockaddr_in s_in;
171 #if 0
172 struct sockaddr_ns sns;
173 struct sockaddr_iso siso;
174 struct sockaddr_dl sdl;
175 struct sockaddr_x25 sx25;
176 #endif
177 } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
179 union sockunion *so_addrs[] =
180 { &so_dst, &so_gate, &so_mask, &so_genmask, &so_ifp, &so_ifa, 0};
182 typedef union sockunion *sup;
183 int rtm_addrs;
184 int s;
185 int forcehost, forcenet, doflush, nflag, af, qflag, tflag, Cflag,
186 keyword(char *cp);
187 int iflag, verbose, aflen = sizeof (struct sockaddr_in);
188 int locking, lockrest, debugonly;
189 struct sockaddr_in s_in = { sizeof(s_in), AF_INET };
190 struct rt_metrics rt_metrics;
191 u_long rtm_inits;
192 #if 0
193 struct in_addr inet_makeaddr();
194 #endif
195 char *routename(struct sockaddr *sa), *netname(struct sockaddr *sa);
196 void flushroutes(int argc, char *argv[]),
197 newroute(int argc, char **argv), monitor(void), sockaddr();
198 void print_getmsg(), print_rtmsg(), pmsg_common(), sodump(), bprintf();
199 int getaddr(int which, char *s, struct hostent **hpp), rtmsg();
200 int GetOpt(int argc, char **argv, char *opts);
201 VOID CleanUpExit(LONG error);
202 #if 0
203 extern char *inet_ntoa(), *iso_ntoa(), *link_ntoa();
204 #endif
206 #define SOCKET_VERSION 3
207 struct Library *SocketBase;
208 const TEXT version[] = "route 3.4 (14.10.2005)";
209 const TEXT socket_name[] = "bsdsocket.library";
211 void
212 usage(char *cp)
214 if (cp)
215 (void) fprintf(stderr, "route: botched keyword: %s\n", cp);
216 (void) fprintf(stderr,
217 "usage: route [ -Cnqv ] cmd [[ -<qualifers> ] args ]\n");
218 CleanUpExit(1);
219 /* NOTREACHED */
222 void
223 quit(char *s)
225 int sverrno = errno;
227 (void) fprintf(stderr, "route: ");
228 if (s)
229 (void) fprintf(stderr, "%s: ", s);
230 (void) fprintf(stderr, "%s\n", strerror(sverrno));
231 CleanUpExit(1);
232 /* NOTREACHED */
235 #define ROUNDUP(a) \
236 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
237 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
239 int main(argc, argv)
240 int argc;
241 char **argv;
243 extern int optind;
244 int ch;
245 // char *argvp;
247 SocketBase = OpenLibrary(socket_name, SOCKET_VERSION);
248 if(SocketBase == NULL) {
249 fprintf(stderr, "route: cannot open bsdsocket.library version 3\n");
250 return RETURN_FAIL;
252 SetErrnoPtr(&errno, sizeof(errno));
254 if (argc < 2)
255 usage(NULL);
257 while ((ch = GetOpt(argc, argv, "Cnqtv")) != EOF)
258 switch(ch) {
259 case 'C':
260 Cflag = 1; /* Use old ioctls. */
261 break;
262 case 'n':
263 nflag = 1;
264 break;
265 case 'q':
266 qflag = 1;
267 break;
268 case 'v':
269 verbose = 1;
270 break;
271 case 't':
272 tflag = 1;
273 break;
274 case '?':
275 default:
276 usage(NULL);
278 argc -= optind;
279 argv += optind;
281 Cflag = 1; /* Force old ioctls. */
283 if (Cflag)
284 s = socket(AF_INET, SOCK_RAW, 0);
285 if (s < 0)
286 quit("socket");
287 if (*argv)
288 switch (keyword(*argv)) {
289 case K_GET:
290 #if 0
291 uid = 0;
292 #endif
293 /* FALLTHROUGH */
295 case K_CHANGE:
296 if (Cflag)
297 usage("change or get with -C");
298 /* FALLTHROUGH */
300 case K_ADD:
301 case K_DELETE:
302 newroute(argc, argv);
303 CleanUpExit(0);
304 /* NOTREACHED */
306 case K_MONITOR:
307 monitor();
308 /* NOTREACHED */
310 case K_FLUSH:
311 flushroutes(argc, argv);
312 CleanUpExit(0);
313 /* NOTREACHED */
315 usage(*argv);
316 /* NOTREACHED */
318 return 0;
322 * Purge all entries in the routing tables not
323 * associated with network interfaces.
325 void
326 flushroutes(argc, argv)
327 int argc;
328 char *argv[];
330 #if 0
331 int needed, seqno, rlen;
332 char *buf, *next, *lim;
333 register struct rt_msghdr *rtm;
335 if (uid)
336 quit("must be root to alter routing table");
337 shutdown(s, 0); /* Don't want to read back our messages */
338 if (argc > 1) {
339 argv++;
340 if (argc == 2 && **argv == '-')
341 switch (keyword(*argv + 1)) {
342 case K_INET:
343 af = AF_INET;
344 break;
345 case K_XNS:
346 af = AF_NS;
347 break;
348 case K_LINK:
349 af = AF_LINK;
350 break;
351 case K_ISO:
352 case K_OSI:
353 af = AF_ISO;
354 break;
355 case K_X25:
356 af = AF_CCITT;
357 default:
358 goto bad;
359 } else
360 bad: usage(*argv);
362 if ((needed = getkerninfo(KINFO_RT_DUMP, 0, 0, 0)) < 0)
363 quit("route-getkerninfo-estimate");
364 if ((buf = malloc(needed)) == NULL)
365 quit("malloc");
366 if ((rlen = getkerninfo(KINFO_RT_DUMP, buf, &needed, 0)) < 0)
367 quit("actual retrieval of routing table");
368 lim = buf + rlen;
369 seqno = 0; /* ??? */
370 for (next = buf; next < lim; next += rtm->rtm_msglen) {
371 rtm = (struct rt_msghdr *)next;
372 if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
373 continue;
374 if (af) {
375 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
377 if (sa->sa_family != af)
378 continue;
380 rtm->rtm_type = RTM_DELETE;
381 rtm->rtm_seq = seqno;
382 rlen = write(s, next, rtm->rtm_msglen);
383 if (rlen < (int)rtm->rtm_msglen) {
384 (void) fprintf(stderr,
385 "route: write to routing socket: %s\n",
386 strerror(errno));
387 (void) printf("got only %d for rlen\n", rlen);
388 break;
390 seqno++;
391 if (qflag)
392 continue;
393 if (verbose)
394 print_rtmsg(rtm, rlen);
395 else {
396 struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
397 (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
398 routename(sa) : netname(sa));
399 sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
400 (void) printf("%-20.20s ", routename(sa));
401 (void) printf("done\n");
404 #endif /* 0 */
407 char *
408 routename(sa)
409 struct sockaddr *sa;
411 register char *cp;
412 static char line[50];
413 struct hostent *hp;
414 static char domain[MAXHOSTNAMELEN + 1];
415 static int first = 1;
416 char *ns_print();
418 if (first) {
419 first = 0;
420 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
421 (cp = index(domain, '.')))
422 (void) strcpy(domain, cp + 1);
423 else
424 domain[0] = 0;
426 switch (sa->sa_family) {
428 case AF_INET:
429 { struct in_addr in;
430 in = ((struct sockaddr_in *)sa)->sin_addr;
432 cp = 0;
433 if (in.s_addr == INADDR_ANY)
434 cp = "default";
435 if (cp == 0 && !nflag) {
436 hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
437 AF_INET);
438 if (hp) {
439 if ((cp = index(hp->h_name, '.')) &&
440 !strcmp(cp + 1, domain))
441 *cp = 0;
442 cp = hp->h_name;
445 if (cp)
446 strcpy(line, cp);
447 else {
448 #define C(x) ((unsigned int)((x) & 0xff))
449 in.s_addr = ntohl(in.s_addr);
450 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
451 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
453 break;
455 #if 0
456 case AF_NS:
457 return (ns_print((struct sockaddr_ns *)sa));
459 case AF_LINK:
460 return (link_ntoa((struct sockaddr_dl *)sa));
462 case AF_ISO:
463 (void) sprintf(line, "iso %s",
464 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
465 break;
466 #endif
467 default:
468 { u_short *s = (u_short *)sa->sa_data;
469 u_short *slim = s + ((sa->sa_len + 1) >> 1);
470 char *cp = line + sprintf(line, "(%d)", sa->sa_family);
472 while (s < slim)
473 cp += sprintf(cp, " %x", *s++);
474 break;
477 return (line);
481 * Return the name of the network whose address is given.
482 * The address is assumed to be that of a net or subnet, not a host.
484 char *
485 netname(sa)
486 struct sockaddr *sa;
488 char *cp = 0;
489 static char line[50];
490 struct netent *np = 0;
491 u_long net, mask;
492 register u_long i;
493 int subnetshift;
494 char *ns_print();
496 switch (sa->sa_family) {
498 case AF_INET:
499 { struct in_addr in;
500 in = ((struct sockaddr_in *)sa)->sin_addr;
502 i = in.s_addr = ntohl(in.s_addr);
503 if (in.s_addr == 0)
504 cp = "default";
505 else if (!nflag) {
506 if (IN_CLASSA(i)) {
507 mask = IN_CLASSA_NET;
508 subnetshift = 8;
509 } else if (IN_CLASSB(i)) {
510 mask = IN_CLASSB_NET;
511 subnetshift = 8;
512 } else {
513 mask = IN_CLASSC_NET;
514 subnetshift = 4;
517 * If there are more bits than the standard mask
518 * would suggest, subnets must be in use.
519 * Guess at the subnet mask, assuming reasonable
520 * width subnet fields.
522 while (in.s_addr &~ mask)
523 mask = (long)mask >> subnetshift;
524 net = in.s_addr & mask;
525 while ((mask & 1) == 0)
526 mask >>= 1, net >>= 1;
527 np = getnetbyaddr(net, AF_INET);
528 if (np)
529 cp = np->n_name;
531 if (cp)
532 strcpy(line, cp);
533 else if ((in.s_addr & 0xffffff) == 0)
534 (void) sprintf(line, "%u", C(in.s_addr >> 24));
535 else if ((in.s_addr & 0xffff) == 0)
536 (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
537 C(in.s_addr >> 16));
538 else if ((in.s_addr & 0xff) == 0)
539 (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
540 C(in.s_addr >> 16), C(in.s_addr >> 8));
541 else
542 (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
543 C(in.s_addr >> 16), C(in.s_addr >> 8),
544 C(in.s_addr));
545 break;
547 #if 0
548 case AF_NS:
549 return (ns_print((struct sockaddr_ns *)sa));
550 break;
552 case AF_LINK:
553 return (link_ntoa((struct sockaddr_dl *)sa));
555 case AF_ISO:
556 (void) sprintf(line, "iso %s",
557 iso_ntoa(&((struct sockaddr_iso *)sa)->siso_addr));
558 break;
559 #endif
560 default:
561 { u_short *s = (u_short *)sa->sa_data;
562 u_short *slim = s + ((sa->sa_len + 1)>>1);
563 char *cp = line + sprintf(line, "af %d:", sa->sa_family);
565 while (s < slim)
566 cp += sprintf(cp, " %x", *s++);
567 break;
570 return (line);
573 void
574 set_metric(char *value, int key)
576 #if 0
577 int flag = 0;
578 u_long noval, *valp = &noval;
580 switch (key) {
581 #define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
582 caseof(K_MTU, RTV_MTU, rmx_mtu);
583 caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
584 caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
585 caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
586 caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
587 caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
588 caseof(K_RTT, RTV_RTT, rmx_rtt);
589 caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
591 rtm_inits |= flag;
592 if (lockrest || locking)
593 rt_metrics.rmx_locks |= flag;
594 if (locking)
595 locking = 0;
596 *valp = atoi(value);
597 #endif
600 void
601 newroute(argc, argv)
602 int argc;
603 register char **argv;
605 char *cmd, *dest = "", *gateway = "", *err;
606 int ishost = 0, ret, attempts, oerrno, flags = 0;
607 int key;
608 struct hostent *hp = 0;
610 #if 0
611 if (uid)
612 quit("must be root to alter routing table");
613 #endif
614 cmd = argv[0];
615 if (*cmd != 'g')
616 shutdown(s, 0); /* Don't want to read back our messages */
617 while (--argc > 0) {
618 if (**(++argv)== '-') {
619 switch (key = keyword(1 + *argv)) {
620 #if 0
621 case K_LINK:
622 af = AF_LINK;
623 aflen = sizeof(struct sockaddr_dl);
624 break;
625 case K_OSI:
626 case K_ISO:
627 af = AF_ISO;
628 aflen = sizeof(struct sockaddr_iso);
629 break;
630 #endif
631 case K_INET:
632 af = AF_INET;
633 aflen = sizeof(struct sockaddr_in);
634 break;
635 #if 0
636 case K_X25:
637 af = AF_CCITT;
638 aflen = sizeof(struct sockaddr_x25);
639 break;
640 case K_SA:
641 af = 0;
642 aflen = sizeof(union sockunion);
643 break;
644 case K_XNS:
645 af = AF_NS;
646 aflen = sizeof(struct sockaddr_ns);
647 break;
648 #endif
649 case K_IFACE:
650 case K_INTERFACE:
651 iflag++;
652 break;
653 case K_LOCK:
654 locking = 1;
655 break;
656 case K_LOCKREST:
657 lockrest = 1;
658 break;
659 case K_HOST:
660 forcehost++;
661 break;
662 case K_REJECT:
663 flags |= RTF_REJECT;
664 break;
665 case K_PROTO1:
666 flags |= RTF_PROTO1;
667 break;
668 case K_PROTO2:
669 flags |= RTF_PROTO2;
670 break;
671 case K_CLONING:
672 flags |= RTF_CLONING;
673 break;
674 case K_XRESOLVE:
675 flags |= RTF_XRESOLVE;
676 break;
677 case K_IFA:
678 argc--;
679 (void) getaddr(RTA_IFA, *++argv, 0);
680 break;
681 case K_IFP:
682 argc--;
683 (void) getaddr(RTA_IFP, *++argv, 0);
684 break;
685 case K_GENMASK:
686 argc--;
687 (void) getaddr(RTA_GENMASK, *++argv, 0);
688 break;
689 case K_GATEWAY:
690 argc--;
691 (void) getaddr(RTA_GATEWAY, *++argv, 0);
692 break;
693 case K_DST:
694 argc--;
695 ishost = getaddr(RTA_DST, *++argv, &hp);
696 dest = *argv;
697 break;
698 case K_NETMASK:
699 argc--;
700 (void) getaddr(RTA_NETMASK, *++argv, 0);
701 /* FALLTHROUGH */
702 case K_NET:
703 forcenet++;
704 break;
705 case K_MTU:
706 case K_HOPCOUNT:
707 case K_EXPIRE:
708 case K_RECVPIPE:
709 case K_SENDPIPE:
710 case K_SSTHRESH:
711 case K_RTT:
712 case K_RTTVAR:
713 argc--;
714 set_metric(*++argv, key);
715 break;
716 default:
717 usage(1+*argv);
719 } else {
720 if ((rtm_addrs & RTA_DST) == 0) {
721 dest = *argv;
722 ishost = getaddr(RTA_DST, *argv, &hp);
723 } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
724 gateway = *argv;
725 (void) getaddr(RTA_GATEWAY, *argv, &hp);
726 } else {
727 int ret = atoi(*argv);
728 if (ret == 0) {
729 printf("%s,%s", "old usage of trailing 0",
730 "assuming route to if\n");
731 iflag = 1;
732 continue;
733 } else if (ret > 0 && ret < 10) {
734 printf("old usage of trailing digit, ");
735 printf("assuming route via gateway\n");
736 iflag = 0;
737 continue;
739 (void) getaddr(RTA_NETMASK, *argv, 0);
743 if (forcehost)
744 ishost = 1;
745 if (forcenet)
746 ishost = 0;
747 flags |= RTF_UP;
748 if (ishost)
749 flags |= RTF_HOST;
750 if (iflag == 0)
751 flags |= RTF_GATEWAY;
752 for (attempts = 1; ; attempts++) {
753 errno = 0;
754 if (Cflag && (af == AF_INET || af == AF_NS)) {
755 D(printf ("Flags: 0x%08lx\n", flags);)
756 D(printf ("Dst = 0x%08lx\n", so_dst.s_in.sin_addr.s_addr);)
757 D(printf ("Gate = 0x%08lx\n", so_gate.s_in.sin_addr.s_addr);)
758 route.rt_flags = flags;
759 route.rt_dst = so_dst.sa;
760 route.rt_gateway = so_gate.sa;
761 if ((ret = ioctl(s, *cmd == 'a' ? SIOCADDRT : SIOCDELRT,
762 (caddr_t)&route)) == 0)
763 break;
764 #if 0
765 } else {
766 if ((ret = rtmsg(*cmd, flags)) == 0)
767 break;
768 #endif
770 if (errno != ENETUNREACH && errno != ESRCH)
771 break;
772 if (af == AF_INET && hp && hp->h_addr_list[1]) {
773 hp->h_addr_list++;
774 bcopy(hp->h_addr_list[0], (caddr_t)&so_dst.s_in.sin_addr,
775 hp->h_length);
776 } else
777 break;
779 if (*cmd == 'g')
780 CleanUpExit(0);
781 oerrno = errno;
782 (void) printf("%s %s %s: gateway %s", cmd, ishost? "host" : "net",
783 dest, gateway);
784 if (attempts > 1 && ret == 0)
786 struct sockaddr_in *route_sin = (struct sockaddr_in *)&route.rt_gateway;
787 (void) printf(" (%s)",
788 Inet_NtoA(route_sin->sin_addr.s_addr));
790 if (ret == 0)
791 (void) printf("\n");
792 else {
793 switch (oerrno) {
794 case ESRCH:
795 err = "not in table";
796 break;
797 case EBUSY:
798 err = "entry in use";
799 break;
800 case ENOBUFS:
801 err = "routing table overflow";
802 break;
803 default:
804 err = strerror(oerrno);
805 break;
807 (void) printf(": %s\n", err);
811 void
812 inet_makenetandmask(u_long net, register struct sockaddr_in *s_in)
814 u_long addr, mask = 0;
815 register char *cp;
817 rtm_addrs |= RTA_NETMASK;
818 if (net == 0)
819 mask = addr = 0;
820 else if (net < 128) {
821 addr = net << IN_CLASSA_NSHIFT;
822 mask = IN_CLASSA_NET;
823 } else if (net < 65536) {
824 addr = net << IN_CLASSB_NSHIFT;
825 mask = IN_CLASSB_NET;
826 } else if (net < 16777216L) {
827 addr = net << IN_CLASSC_NSHIFT;
828 mask = IN_CLASSC_NET;
829 } else {
830 addr = net;
831 if ((addr & IN_CLASSA_HOST) == 0)
832 mask = IN_CLASSA_NET;
833 else if ((addr & IN_CLASSB_HOST) == 0)
834 mask = IN_CLASSB_NET;
835 else if ((addr & IN_CLASSC_HOST) == 0)
836 mask = IN_CLASSC_NET;
837 else
838 mask = -1;
840 s_in->sin_addr.s_addr = htonl(addr);
841 s_in = &so_mask.s_in;
842 s_in->sin_addr.s_addr = htonl(mask);
843 s_in->sin_len = 0;
844 s_in->sin_family = 0;
845 cp = (char *)(&s_in->sin_addr + 1);
846 while (*--cp == 0 && cp > (char *)s_in)
848 s_in->sin_len = 1 + cp - (char *)s_in;
852 * Interpret an argument as a network address of some kind,
853 * returning 1 if a host address, 0 if a network address.
856 getaddr(which, s, hpp)
857 int which;
858 char *s;
859 struct hostent **hpp;
861 register sup su;
862 #if 0
863 struct ns_addr ns_addr();
864 struct iso_addr *iso_addr();
865 #endif
866 struct hostent *hp;
867 struct netent *np;
868 u_long val;
870 if (af == 0) {
871 af = AF_INET;
872 aflen = sizeof(struct sockaddr_in);
874 rtm_addrs |= which;
875 switch (which) {
876 case RTA_DST: su = so_addrs[0]; su->sa.sa_family = af; break;
877 case RTA_GATEWAY: su = so_addrs[1]; su->sa.sa_family = af; break;
878 case RTA_NETMASK: su = so_addrs[2]; break;
879 case RTA_GENMASK: su = so_addrs[3]; break;
880 case RTA_IFP: su = so_addrs[4]; su->sa.sa_family = af; break;
881 case RTA_IFA: su = so_addrs[5]; su->sa.sa_family = af; break;
882 default: usage("Internal Error"); /*NOTREACHED*/
884 su->sa.sa_len = aflen;
885 if (strcmp(s, "default") == 0) {
886 switch (which) {
887 case RTA_DST:
888 forcenet++;
889 (void) getaddr(RTA_NETMASK, s, 0);
890 break;
891 case RTA_NETMASK:
892 case RTA_GENMASK:
893 su->sa.sa_len = 0;
895 return 0;
897 #if 0
898 if (af == AF_NS)
899 goto do_xns;
900 if (af == AF_OSI)
901 goto do_osi;
902 if (af == AF_LINK)
903 goto do_link;
904 if (af == AF_CCITT)
905 goto do_ccitt;
906 if (af == 0)
907 goto do_sa;
908 #endif
909 if (hpp == NULL)
910 hpp = &hp;
911 *hpp = NULL;
912 if (((val = inet_addr(s)) != -1) &&
913 (which != RTA_DST || forcenet == 0)) {
914 su->s_in.sin_addr.s_addr = val;
915 if (Inet_LnaOf(su->s_in.sin_addr.s_addr) != INADDR_ANY)
916 return (1);
917 else {
918 val = ntohl(val);
919 out: if (which == RTA_DST)
920 inet_makenetandmask(val, &su->s_in);
921 return (0);
924 val = inet_network(s);
925 if (val != -1) {
926 goto out;
928 np = getnetbyname(s);
929 if (np) {
930 val = np->n_net;
931 goto out;
933 hp = gethostbyname(s);
934 if (hp) {
935 *hpp = hp;
936 su->s_in.sin_family = hp->h_addrtype;
937 bcopy(hp->h_addr, (char *)&su->s_in.sin_addr, hp->h_length);
938 return (1);
940 (void) fprintf(stderr, "%s: bad value\n", s);
941 CleanUpExit(1);
942 #if 0
943 do_xns:
944 if (which == RTA_DST) {
945 extern short ns_bh[3];
946 struct sockaddr_ns *sms = &(so_mask.sns);
947 bzero((char *)sms, sizeof(*sms));
948 sms->sns_family = 0;
949 sms->sns_len = 6;
950 sms->sns_addr.x_net = *(union ns_net *)ns_bh;
951 rtm_addrs |= RTA_NETMASK;
953 su->sns.sns_addr = ns_addr(s);
954 return (!ns_nullhost(su->sns.sns_addr));
955 do_osi:
956 su->siso.siso_addr = *iso_addr(s);
957 if (which == RTA_NETMASK || which == RTA_GENMASK) {
958 register char *cp = (char *)TSEL(&su->siso);
959 su->siso.siso_nlen = 0;
960 do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
961 su->siso.siso_len = 1 + cp - (char *)su;
963 return (1);
964 do_ccitt:
965 ccitt_addr(s, &su->sx25);
966 return (1);
967 do_link:
968 link_addr(s, &su->sdl);
969 return (1);
970 do_sa:
971 su->sa.sa_len = sizeof(*su);
972 sockaddr(s, &su->sa);
973 return (1);
974 #endif
976 return 0;
979 short ns_nullh[] = {0,0,0};
980 short ns_bh[] = {-1,-1,-1};
982 #if 0
983 char *
984 ns_print(sns)
985 struct sockaddr_ns *sns;
987 struct ns_addr work;
988 union { union ns_net net_e; u_long long_e; } net;
989 u_short port;
990 static char mybuf[50], cport[10], chost[25];
991 char *host = "";
992 register char *p;
993 register u_char *q;
995 work = sns->sns_addr;
996 port = ntohs(work.x_port);
997 work.x_port = 0;
998 net.net_e = work.x_net;
999 if (ns_nullhost(work) && net.long_e == 0) {
1000 if (!port)
1001 return ("*.*");
1002 (void) sprintf(mybuf, "*.%XH", port);
1003 return (mybuf);
1006 if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0)
1007 host = "any";
1008 else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0)
1009 host = "*";
1010 else {
1011 q = work.x_host.c_host;
1012 (void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
1013 q[0], q[1], q[2], q[3], q[4], q[5]);
1014 for (p = chost; *p == '0' && p < chost + 12; p++)
1015 /* void */;
1016 host = p;
1018 if (port)
1019 (void) sprintf(cport, ".%XH", htons(port));
1020 else
1021 *cport = 0;
1023 (void) sprintf(mybuf,"%XH.%s%s", ntohl(net.long_e), host, cport);
1024 return (mybuf);
1026 #endif
1028 void
1029 monitor(void)
1031 #if 0
1032 int n;
1033 char msg[2048];
1035 verbose = 1;
1036 for(;;) {
1037 n = read(s, msg, 2048);
1038 (void) printf("got message of size %d\n", n);
1039 print_rtmsg((struct rt_msghdr *)msg);
1041 #endif
1044 #if 0
1045 struct {
1046 struct rt_msghdr m_rtm;
1047 char m_space[512];
1048 } m_rtmsg;
1051 rtmsg(cmd, flags)
1052 int cmd, flags;
1054 static int seq;
1055 int rlen;
1056 register char *cp = m_rtmsg.m_space;
1057 register int l;
1059 #define NEXTADDR(w, u) \
1060 if (rtm_addrs & (w)) {\
1061 l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
1062 if (verbose) sodump(&(u),"u");\
1065 errno = 0;
1066 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
1067 if (cmd == 'a')
1068 cmd = RTM_ADD;
1069 else if (cmd == 'c')
1070 cmd = RTM_CHANGE;
1071 else if (cmd == 'g')
1072 cmd = RTM_GET;
1073 else
1074 cmd = RTM_DELETE;
1075 #define rtm m_rtmsg.m_rtm
1076 rtm.rtm_type = cmd;
1077 rtm.rtm_flags = flags;
1078 rtm.rtm_version = RTM_VERSION;
1079 rtm.rtm_seq = ++seq;
1080 rtm.rtm_addrs = rtm_addrs;
1081 rtm.rtm_rmx = rt_metrics;
1082 rtm.rtm_inits = rtm_inits;
1084 if (rtm_addrs & RTA_NETMASK)
1085 mask_addr();
1086 NEXTADDR(RTA_DST, so_dst);
1087 NEXTADDR(RTA_GATEWAY, so_gate);
1088 NEXTADDR(RTA_NETMASK, so_mask);
1089 NEXTADDR(RTA_GENMASK, so_genmask);
1090 NEXTADDR(RTA_IFP, so_ifp);
1091 NEXTADDR(RTA_IFA, so_ifa);
1092 rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1093 if (verbose)
1094 print_rtmsg(&rtm, l);
1095 if (debugonly)
1096 return 0;
1097 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1098 perror("writing to routing socket");
1099 return (-1);
1101 if (cmd == RTM_GET) {
1102 do {
1103 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
1104 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1105 if (l < 0)
1106 (void) fprintf(stderr,
1107 "route: read from routing socket: %s\n",
1108 strerror(errno));
1109 else
1110 print_getmsg(&rtm, l);
1112 #undef rtm
1113 return (0);
1115 #endif
1117 #if 0
1118 mask_addr() {
1119 register char *cp1, *cp2;
1120 int olen;
1122 if ((rtm_addrs & RTA_DST) == 0)
1123 return;
1124 switch(so_dst.sa.sa_family) {
1125 case AF_NS: case AF_INET: case 0:
1126 return;
1127 case AF_ISO:
1128 olen = MIN(so_dst.siso.siso_nlen, so_mask.sa.sa_len - 6);
1130 cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1131 cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1132 while (cp2 > cp1)
1133 *--cp2 = 0;
1134 cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1135 while (cp1 > so_dst.sa.sa_data)
1136 *--cp1 &= *--cp2;
1137 switch(so_dst.sa.sa_family) {
1138 case AF_ISO:
1139 so_dst.siso.siso_nlen = olen;
1143 char *msgtypes[] = {
1145 "RTM_ADD: Add Route",
1146 "RTM_DELETE: Delete Route",
1147 "RTM_CHANGE: Change Metrics or flags",
1148 "RTM_GET: Report Metrics",
1149 "RTM_LOSING: Kernel Suspects Partitioning",
1150 "RTM_REDIRECT: Told to use different route",
1151 "RTM_MISS: Lookup failed on this address",
1152 "RTM_LOCK: fix specified metrics",
1153 "RTM_OLDADD: caused by SIOCADDRT",
1154 "RTM_OLDDEL: caused by SIOCDELRT",
1158 char metricnames[] =
1159 "\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1160 char routeflags[] =
1161 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\017PROTO2\020PROTO1";
1164 void
1165 print_rtmsg(rtm, msglen)
1166 register struct rt_msghdr *rtm;
1167 int msglen;
1169 if (verbose == 0)
1170 return;
1171 if (rtm->rtm_version != RTM_VERSION) {
1172 (void) printf("routing message version %d not understood\n",
1173 rtm->rtm_version);
1174 return;
1176 (void) printf("%s\npid: %d, len %d, seq %d, errno %d, flags:",
1177 msgtypes[rtm->rtm_type], rtm->rtm_pid, rtm->rtm_msglen,
1178 rtm->rtm_seq, rtm->rtm_errno);
1179 bprintf(stdout, rtm->rtm_flags, routeflags);
1180 pmsg_common(rtm);
1183 void
1184 print_getmsg(rtm, msglen)
1185 register struct rt_msghdr *rtm;
1186 int msglen;
1188 if (rtm->rtm_version != RTM_VERSION) {
1189 (void)printf("routing message version %d not understood\n",
1190 rtm->rtm_version);
1191 return;
1193 if (rtm->rtm_msglen > msglen) {
1194 (void)printf("get length mismatch, in packet %d, returned %d\n",
1195 rtm->rtm_msglen, msglen);
1197 (void) printf("RTM_GET: errno %d, flags:", rtm->rtm_errno);
1198 bprintf(stdout, rtm->rtm_flags, routeflags);
1199 (void) printf("\nmetric values:\n ");
1200 #define metric(f, e)\
1201 printf("%s: %d%s", __STRING(f), rtm->rtm_rmx.__CONCAT(rmx_,f), e)
1202 metric(recvpipe, ", ");
1203 metric(sendpipe, ", ");
1204 metric(ssthresh, ", ");
1205 metric(rtt, "\n ");
1206 metric(rttvar, ", ");
1207 metric(hopcount, ", ");
1208 metric(mtu, ", ");
1209 metric(expire, "\n");
1210 #undef metric
1211 pmsg_common(rtm);
1214 void
1215 pmsg_common(rtm)
1216 register struct rt_msghdr *rtm;
1218 char *cp;
1219 register struct sockaddr *sa;
1220 int i;
1222 (void) printf("\nlocks: ");
1223 bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1224 (void) printf(" inits: ");
1225 bprintf(stdout, rtm->rtm_inits, metricnames);
1226 (void) printf("\nsockaddrs: ");
1227 bprintf(stdout, rtm->rtm_addrs,
1228 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR");
1229 (void) putchar('\n');
1230 cp = ((char *)(rtm + 1));
1231 if (rtm->rtm_addrs)
1232 for (i = 1; i; i <<= 1)
1233 if (i & rtm->rtm_addrs) {
1234 sa = (struct sockaddr *)cp;
1235 (void) printf(" %s", routename(sa));
1236 ADVANCE(cp, sa);
1238 (void) putchar('\n');
1239 (void) fflush(stdout);
1242 void
1243 bprintf(fp, b, s)
1244 register FILE *fp;
1245 register int b;
1246 register u_char *s;
1248 register int i;
1249 int gotsome = 0;
1251 if (b == 0)
1252 return;
1253 while (i = *s++) {
1254 if (b & (1 << (i-1))) {
1255 if (gotsome == 0)
1256 i = '<';
1257 else
1258 i = ',';
1259 (void) putc(i, fp);
1260 gotsome = 1;
1261 for (; (i = *s) > 32; s++)
1262 (void) putc(i, fp);
1263 } else
1264 while (*s > 32)
1265 s++;
1267 if (gotsome)
1268 (void) putc('>', fp);
1270 #endif
1273 keyword(cp)
1274 char *cp;
1276 register struct keytab *kt = keywords;
1278 while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1279 kt++;
1280 return kt->kt_i;
1282 #if 0
1283 void
1284 sodump(su, which)
1285 register sup su;
1286 char *which;
1288 switch (su->sa.sa_family) {
1289 case AF_LINK:
1290 (void) printf("%s: link %s; ",
1291 which, link_ntoa(&su->sdl));
1292 break;
1293 case AF_ISO:
1294 (void) printf("%s: iso %s; ",
1295 which, iso_ntoa(&su->siso.siso_addr));
1296 break;
1297 case AF_INET:
1298 (void) printf("%s: inet %s; ",
1299 which, inet_ntoa(su->s_in.sin_addr));
1300 break;
1301 case AF_NS:
1302 (void) printf("%s: xns %s; ",
1303 which, ns_ntoa(su->sns.sns_addr));
1304 break;
1306 (void) fflush(stdout);
1308 /* States*/
1309 #define VIRGIN 0
1310 #define GOTONE 1
1311 #define GOTTWO 2
1312 /* Inputs */
1313 #define DIGIT (4*0)
1314 #define END (4*1)
1315 #define DELIM (4*2)
1317 void
1318 sockaddr(addr, sa)
1319 register char *addr;
1320 register struct sockaddr *sa;
1322 register char *cp = (char *)sa;
1323 int size = sa->sa_len;
1324 char *cplim = cp + size;
1325 register int byte = 0, state = VIRGIN, new;
1327 bzero(cp, size);
1328 do {
1329 if ((*addr >= '0') && (*addr <= '9')) {
1330 new = *addr - '0';
1331 } else if ((*addr >= 'a') && (*addr <= 'f')) {
1332 new = *addr - 'a' + 10;
1333 } else if ((*addr >= 'A') && (*addr <= 'F')) {
1334 new = *addr - 'A' + 10;
1335 } else if (*addr == 0)
1336 state |= END;
1337 else
1338 state |= DELIM;
1339 addr++;
1340 switch (state /* | INPUT */) {
1341 case GOTTWO | DIGIT:
1342 *cp++ = byte; /*FALLTHROUGH*/
1343 case VIRGIN | DIGIT:
1344 state = GOTONE; byte = new; continue;
1345 case GOTONE | DIGIT:
1346 state = GOTTWO; byte = new + (byte << 4); continue;
1347 default: /* | DELIM */
1348 state = VIRGIN; *cp++ = byte; byte = 0; continue;
1349 case GOTONE | END:
1350 case GOTTWO | END:
1351 *cp++ = byte; /* FALLTHROUGH */
1352 case VIRGIN | END:
1353 break;
1355 break;
1356 } while (cp < cplim);
1357 sa->sa_len = cp - (char *)sa;
1359 #endif
1363 #if 1
1364 #include <stdlib.h>
1365 #include <string.h>
1366 #include <stdio.h>
1368 /*LINTLIBRARY*/
1369 #define EOF (-1)
1370 #define ERR(s, c)\
1371 if(opterr) { fprintf(stderr, "%s%s%lc\n", argv[0], s, c); }
1373 int opterr = 1;
1374 int optind = 1;
1375 int optopt;
1376 char *optarg;
1378 int GetOpt(int argc, char **argv, char *opts)
1380 static int sp = 1;
1381 register int c;
1382 register char *cp;
1384 if(sp == 1)
1385 if(optind >= argc ||
1386 argv[optind][0] != '-' || argv[optind][1] == '\0')
1387 return(EOF);
1388 else if(strcmp(argv[optind], "--") == 0) {
1389 optind++;
1390 return(EOF);
1392 optopt = c = argv[optind][sp];
1393 if(c == ':' || (cp=index(opts, c)) == NULL) {
1394 ERR(": illegal option -- ", c);
1395 if(argv[optind][++sp] == '\0') {
1396 optind++;
1397 sp = 1;
1399 return('?');
1401 if(*++cp == ':') {
1402 if(argv[optind][sp+1] != '\0')
1403 optarg = &argv[optind++][sp+1];
1404 else if(++optind >= argc) {
1405 ERR(": option requires an argument -- ", c);
1406 sp = 1;
1407 return('?');
1408 } else
1409 optarg = argv[optind++];
1410 sp = 1;
1411 } else {
1412 if(argv[optind][++sp] == '\0') {
1413 sp = 1;
1414 optind++;
1416 optarg = NULL;
1418 return(c);
1420 #endif
1422 VOID CleanUpExit(LONG error)
1424 CloseLibrary(SocketBase);
1425 exit(error);