Initial import from FreeBSD RELENG_4:
[games.git] / sbin / route / route.c
1 /*
2  * Copyright (c) 1983, 1989, 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)route.c     8.6 (Berkeley) 4/28/95";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD: src/sbin/route/route.c,v 1.40.2.11 2003/02/27 23:10:10 ru Exp $";
46 #endif /* not lint */
47
48 #include <sys/param.h>
49 #include <sys/file.h>
50 #include <sys/socket.h>
51 #include <sys/ioctl.h>
52 #include <sys/sysctl.h>
53 #include <sys/types.h>
54
55 #include <net/if.h>
56 #include <net/route.h>
57 #include <net/if_dl.h>
58 #include <netinet/in.h>
59 #include <netinet/if_ether.h>
60 #include <netatalk/at.h>
61 #ifdef NS
62 #include <netns/ns.h>
63 #endif
64 #include <arpa/inet.h>
65 #include <netdb.h>
66
67 #include <ctype.h>
68 #include <err.h>
69 #include <errno.h>
70 #include <paths.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <sysexits.h>
75 #include <unistd.h>
76 #include <ifaddrs.h>
77
78 struct keytab {
79         char    *kt_cp;
80         int     kt_i;
81 } keywords[] = {
82 #include "keywords.h"
83         {0, 0}
84 };
85
86 struct  ortentry route;
87 union   sockunion {
88         struct  sockaddr sa;
89         struct  sockaddr_in sin;
90 #ifdef INET6
91         struct  sockaddr_in6 sin6;
92 #endif
93         struct  sockaddr_at sat;
94 #ifdef NS
95         struct  sockaddr_ns sns;
96 #endif
97         struct  sockaddr_dl sdl;
98         struct  sockaddr_inarp sinarp;
99         struct  sockaddr_storage ss; /* added to avoid memory overrun */
100 } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
101
102 typedef union sockunion *sup;
103 int     pid, rtm_addrs;
104 int     s;
105 int     forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
106 int     iflag, verbose, aflen = sizeof (struct sockaddr_in);
107 int     locking, lockrest, debugonly;
108 struct  rt_metrics rt_metrics;
109 u_long  rtm_inits;
110 uid_t   uid;
111 int     atalk_aton __P((const char *, struct at_addr *));
112 char    *atalk_ntoa __P((struct at_addr));
113 const char      *routename(), *netname();
114 void    flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
115 void    print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
116 #ifdef INET6
117 static int inet6_makenetandmask __P((struct sockaddr_in6 *, char *));
118 #endif
119 int     getaddr(), rtmsg(), x25_makemask();
120 int     prefixlen();
121 extern  char *iso_ntoa();
122
123 void usage __P((const char *)) __dead2;
124
125 void
126 usage(cp)
127         const char *cp;
128 {
129         if (cp)
130                 warnx("bad keyword: %s", cp);
131         (void) fprintf(stderr,
132             "usage: route [-dnqtv] command [[modifiers] args]\n");
133         exit(EX_USAGE);
134         /* NOTREACHED */
135 }
136
137 #define ROUNDUP(a) \
138         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
139 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
140
141 int
142 main(argc, argv)
143         int argc;
144         char **argv;
145 {
146         int ch;
147
148         if (argc < 2)
149                 usage((char *)NULL);
150
151         while ((ch = getopt(argc, argv, "nqdtv")) != -1)
152                 switch(ch) {
153                 case 'n':
154                         nflag = 1;
155                         break;
156                 case 'q':
157                         qflag = 1;
158                         break;
159                 case 'v':
160                         verbose = 1;
161                         break;
162                 case 't':
163                         tflag = 1;
164                         break;
165                 case 'd':
166                         debugonly = 1;
167                         break;
168                 case '?':
169                 default:
170                         usage((char *)NULL);
171                 }
172         argc -= optind;
173         argv += optind;
174
175         pid = getpid();
176         uid = geteuid();
177         if (tflag)
178                 s = open(_PATH_DEVNULL, O_WRONLY, 0);
179         else
180                 s = socket(PF_ROUTE, SOCK_RAW, 0);
181         if (s < 0)
182                 err(EX_OSERR, "socket");
183         if (*argv)
184                 switch (keyword(*argv)) {
185                 case K_GET:
186                         uid = 0;
187                         /* FALLTHROUGH */
188
189                 case K_CHANGE:
190                 case K_ADD:
191                 case K_DELETE:
192                         newroute(argc, argv);
193                         /* NOTREACHED */
194
195                 case K_MONITOR:
196                         monitor();
197                         /* NOTREACHED */
198
199                 case K_FLUSH:
200                         flushroutes(argc, argv);
201                         exit(0);
202                         /* NOTREACHED */
203                 }
204         usage(*argv);
205         /* NOTREACHED */
206 }
207
208 /*
209  * Purge all entries in the routing tables not
210  * associated with network interfaces.
211  */
212 void
213 flushroutes(argc, argv)
214         int argc;
215         char *argv[];
216 {
217         size_t needed;
218         int mib[6], rlen, seqno;
219         char *buf, *next, *lim;
220         register struct rt_msghdr *rtm;
221
222         if (uid) {
223                 errx(EX_NOPERM, "must be root to alter routing table");
224         }
225         shutdown(s, 0); /* Don't want to read back our messages */
226         if (argc > 1) {
227                 argv++;
228                 if (argc == 2 && **argv == '-')
229                     switch (keyword(*argv + 1)) {
230                         case K_INET:
231                                 af = AF_INET;
232                                 break;
233 #ifdef INET6
234                         case K_INET6:
235                                 af = AF_INET6;
236                                 break;
237 #endif
238                         case K_ATALK:
239                                 af = AF_APPLETALK;
240                                 break;
241 #ifdef NS
242                         case K_XNS:
243                                 af = AF_NS;
244                                 break;
245 #endif
246                         case K_LINK:
247                                 af = AF_LINK;
248                                 break;
249                         default:
250                                 goto bad;
251                 } else
252 bad:                    usage(*argv);
253         }
254         mib[0] = CTL_NET;
255         mib[1] = PF_ROUTE;
256         mib[2] = 0;             /* protocol */
257         mib[3] = 0;             /* wildcard address family */
258         mib[4] = NET_RT_DUMP;
259         mib[5] = 0;             /* no flags */
260         if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
261                 err(EX_OSERR, "route-sysctl-estimate");
262         if ((buf = malloc(needed)) == NULL)
263                 errx(EX_OSERR, "malloc failed");
264         if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
265                 err(EX_OSERR, "route-sysctl-get");
266         lim = buf + needed;
267         if (verbose)
268                 (void) printf("Examining routing table from sysctl\n");
269         seqno = 0;              /* ??? */
270         for (next = buf; next < lim; next += rtm->rtm_msglen) {
271                 rtm = (struct rt_msghdr *)next;
272                 if (verbose)
273                         print_rtmsg(rtm, rtm->rtm_msglen);
274                 if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
275                         continue;
276                 if (af) {
277                         struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
278
279                         if (sa->sa_family != af)
280                                 continue;
281                 }
282                 if (debugonly)
283                         continue;
284                 rtm->rtm_type = RTM_DELETE;
285                 rtm->rtm_seq = seqno;
286                 rlen = write(s, next, rtm->rtm_msglen);
287                 if (rlen < (int)rtm->rtm_msglen) {
288                         warn("write to routing socket");
289                         (void) printf("got only %d for rlen\n", rlen);
290                         break;
291                 }
292                 seqno++;
293                 if (qflag)
294                         continue;
295                 if (verbose)
296                         print_rtmsg(rtm, rlen);
297                 else {
298                         struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
299                         (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
300                             routename(sa) : netname(sa));
301                         sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
302                         (void) printf("%-20.20s ", routename(sa));
303                         (void) printf("done\n");
304                 }
305         }
306 }
307
308 const char *
309 routename(sa)
310         struct sockaddr *sa;
311 {
312         register char *cp;
313         static char line[MAXHOSTNAMELEN + 1];
314         struct hostent *hp;
315         static char domain[MAXHOSTNAMELEN + 1];
316         static int first = 1;
317 #ifdef NS
318         char *ns_print();
319 #endif
320
321         if (first) {
322                 first = 0;
323                 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
324                     (cp = strchr(domain, '.'))) {
325                         domain[MAXHOSTNAMELEN] = '\0';
326                         (void) strcpy(domain, cp + 1);
327                 } else
328                         domain[0] = 0;
329         }
330
331         if (sa->sa_len == 0)
332                 strcpy(line, "default");
333         else switch (sa->sa_family) {
334
335         case AF_INET:
336             {   struct in_addr in;
337                 in = ((struct sockaddr_in *)sa)->sin_addr;
338
339                 cp = 0;
340                 if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
341                         cp = "default";
342                 if (cp == 0 && !nflag) {
343                         hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
344                                 AF_INET);
345                         if (hp) {
346                                 if ((cp = strchr(hp->h_name, '.')) &&
347                                     !strcmp(cp + 1, domain))
348                                         *cp = 0;
349                                 cp = hp->h_name;
350                         }
351                 }
352                 if (cp) {
353                         strncpy(line, cp, sizeof(line) - 1);
354                         line[sizeof(line) - 1] = '\0';
355                 } else
356                         (void) sprintf(line, "%s", inet_ntoa(in));
357                 break;
358             }
359
360 #ifdef INET6
361         case AF_INET6:
362         {
363                 struct sockaddr_in6 sin6; /* use static var for safety */
364                 int niflags = 0;
365 #ifdef NI_WITHSCOPEID
366                 niflags = NI_WITHSCOPEID;
367 #endif
368
369                 memset(&sin6, 0, sizeof(sin6));
370                 memcpy(&sin6, sa, sa->sa_len);
371                 sin6.sin6_len = sizeof(struct sockaddr_in6);
372                 sin6.sin6_family = AF_INET6;
373 #ifdef __KAME__
374                 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
375                     (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
376                      IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
377                     sin6.sin6_scope_id == 0) {
378                         sin6.sin6_scope_id =
379                             ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
380                         sin6.sin6_addr.s6_addr[2] = 0;
381                         sin6.sin6_addr.s6_addr[3] = 0;
382                 }
383 #endif
384                 if (nflag)
385                         niflags |= NI_NUMERICHOST;
386                 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
387                     line, sizeof(line), NULL, 0, niflags) != 0)
388                         strncpy(line, "invalid", sizeof(line));
389
390                 return(line);
391         }
392 #endif
393
394         case AF_APPLETALK:
395                 (void) snprintf(line, sizeof(line), "atalk %s",
396                         atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
397                 break;
398
399 #ifdef NS
400         case AF_NS:
401                 return (ns_print((struct sockaddr_ns *)sa));
402 #endif
403
404         case AF_LINK:
405                 return (link_ntoa((struct sockaddr_dl *)sa));
406
407         default:
408             {   u_short *s = (u_short *)sa;
409                 u_short *slim = s + ((sa->sa_len + 1) >> 1);
410                 char *cp = line + sprintf(line, "(%d)", sa->sa_family);
411                 char *cpe = line + sizeof(line);
412
413                 while (++s < slim && cp < cpe) /* start with sa->sa_data */
414                         cp += snprintf(cp, cpe - cp, " %x", *s);
415                 break;
416             }
417         }
418         return (line);
419 }
420
421 /*
422  * Return the name of the network whose address is given.
423  * The address is assumed to be that of a net or subnet, not a host.
424  */
425 const char *
426 netname(sa)
427         struct sockaddr *sa;
428 {
429         char *cp = 0;
430         static char line[MAXHOSTNAMELEN + 1];
431         struct netent *np = 0;
432         u_long net, mask;
433         register u_long i;
434         int subnetshift;
435 #ifdef NS
436         char *ns_print();
437 #endif
438
439         switch (sa->sa_family) {
440
441         case AF_INET:
442             {   struct in_addr in;
443                 in = ((struct sockaddr_in *)sa)->sin_addr;
444
445                 i = in.s_addr = ntohl(in.s_addr);
446                 if (in.s_addr == 0)
447                         cp = "default";
448                 else if (!nflag) {
449                         if (IN_CLASSA(i)) {
450                                 mask = IN_CLASSA_NET;
451                                 subnetshift = 8;
452                         } else if (IN_CLASSB(i)) {
453                                 mask = IN_CLASSB_NET;
454                                 subnetshift = 8;
455                         } else {
456                                 mask = IN_CLASSC_NET;
457                                 subnetshift = 4;
458                         }
459                         /*
460                          * If there are more bits than the standard mask
461                          * would suggest, subnets must be in use.
462                          * Guess at the subnet mask, assuming reasonable
463                          * width subnet fields.
464                          */
465                         while (in.s_addr &~ mask)
466                                 mask = (long)mask >> subnetshift;
467                         net = in.s_addr & mask;
468                         while ((mask & 1) == 0)
469                                 mask >>= 1, net >>= 1;
470                         np = getnetbyaddr(net, AF_INET);
471                         if (np)
472                                 cp = np->n_name;
473                 }
474 #define C(x)    (unsigned)((x) & 0xff)
475                 if (cp)
476                         strncpy(line, cp, sizeof(line));
477                 else if ((in.s_addr & 0xffffff) == 0)
478                         (void) sprintf(line, "%u", C(in.s_addr >> 24));
479                 else if ((in.s_addr & 0xffff) == 0)
480                         (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
481                             C(in.s_addr >> 16));
482                 else if ((in.s_addr & 0xff) == 0)
483                         (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
484                             C(in.s_addr >> 16), C(in.s_addr >> 8));
485                 else
486                         (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
487                             C(in.s_addr >> 16), C(in.s_addr >> 8),
488                             C(in.s_addr));
489 #undef C
490                 break;
491             }
492
493 #ifdef INET6
494         case AF_INET6:
495         {
496                 struct sockaddr_in6 sin6; /* use static var for safety */
497                 int niflags = 0;
498 #ifdef NI_WITHSCOPEID
499                 niflags = NI_WITHSCOPEID;
500 #endif
501
502                 memset(&sin6, 0, sizeof(sin6));
503                 memcpy(&sin6, sa, sa->sa_len);
504                 sin6.sin6_len = sizeof(struct sockaddr_in6);
505                 sin6.sin6_family = AF_INET6;
506 #ifdef __KAME__
507                 if (sa->sa_len == sizeof(struct sockaddr_in6) &&
508                     (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
509                      IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
510                     sin6.sin6_scope_id == 0) {
511                         sin6.sin6_scope_id =
512                             ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
513                         sin6.sin6_addr.s6_addr[2] = 0;
514                         sin6.sin6_addr.s6_addr[3] = 0;
515                 }
516 #endif
517                 if (nflag)
518                         niflags |= NI_NUMERICHOST;
519                 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
520                     line, sizeof(line), NULL, 0, niflags) != 0)
521                         strncpy(line, "invalid", sizeof(line));
522
523                 return(line);
524         }
525 #endif
526
527         case AF_APPLETALK:
528                 (void) snprintf(line, sizeof(line), "atalk %s",
529                         atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
530                 break;
531
532 #ifdef NS
533         case AF_NS:
534                 return (ns_print((struct sockaddr_ns *)sa));
535                 break;
536 #endif
537
538         case AF_LINK:
539                 return (link_ntoa((struct sockaddr_dl *)sa));
540
541
542         default:
543             {   u_short *s = (u_short *)sa->sa_data;
544                 u_short *slim = s + ((sa->sa_len + 1)>>1);
545                 char *cp = line + sprintf(line, "af %d:", sa->sa_family);
546                 char *cpe = line + sizeof(line);
547
548                 while (s < slim && cp < cpe)
549                         cp += snprintf(cp, cpe - cp, " %x", *s++);
550                 break;
551             }
552         }
553         return (line);
554 }
555
556 void
557 set_metric(value, key)
558         char *value;
559         int key;
560 {
561         int flag = 0;
562         u_long noval, *valp = &noval;
563
564         switch (key) {
565 #define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
566         caseof(K_MTU, RTV_MTU, rmx_mtu);
567         caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
568         caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
569         caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
570         caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
571         caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
572         caseof(K_RTT, RTV_RTT, rmx_rtt);
573         caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
574         }
575         rtm_inits |= flag;
576         if (lockrest || locking)
577                 rt_metrics.rmx_locks |= flag;
578         if (locking)
579                 locking = 0;
580         *valp = atoi(value);
581 }
582
583 void
584 newroute(argc, argv)
585         int argc;
586         register char **argv;
587 {
588         char *cmd, *dest = "", *gateway = "", *err;
589         int ishost = 0, proxy = 0, ret, attempts, oerrno, flags = RTF_STATIC;
590         int key;
591         struct hostent *hp = 0;
592
593         if (uid) {
594                 errx(EX_NOPERM, "must be root to alter routing table");
595         }
596         cmd = argv[0];
597         if (*cmd != 'g')
598                 shutdown(s, 0); /* Don't want to read back our messages */
599         while (--argc > 0) {
600                 if (**(++argv)== '-') {
601                         switch (key = keyword(1 + *argv)) {
602                         case K_LINK:
603                                 af = AF_LINK;
604                                 aflen = sizeof(struct sockaddr_dl);
605                                 break;
606                         case K_INET:
607                                 af = AF_INET;
608                                 aflen = sizeof(struct sockaddr_in);
609                                 break;
610 #ifdef INET6
611                         case K_INET6:
612                                 af = AF_INET6;
613                                 aflen = sizeof(struct sockaddr_in6);
614                                 break;
615 #endif
616                         case K_ATALK:
617                                 af = AF_APPLETALK;
618                                 aflen = sizeof(struct sockaddr_at);
619                                 break;
620                         case K_SA:
621                                 af = PF_ROUTE;
622                                 aflen = sizeof(union sockunion);
623                                 break;
624 #ifdef NS
625                         case K_XNS:
626                                 af = AF_NS;
627                                 aflen = sizeof(struct sockaddr_ns);
628                                 break;
629 #endif
630                         case K_IFACE:
631                         case K_INTERFACE:
632                                 iflag++;
633                                 break;
634                         case K_NOSTATIC:
635                                 flags &= ~RTF_STATIC;
636                                 break;
637                         case K_LLINFO:
638                                 flags |= RTF_LLINFO;
639                                 break;
640                         case K_LOCK:
641                                 locking = 1;
642                                 break;
643                         case K_LOCKREST:
644                                 lockrest = 1;
645                                 break;
646                         case K_HOST:
647                                 forcehost++;
648                                 break;
649                         case K_REJECT:
650                                 flags |= RTF_REJECT;
651                                 break;
652                         case K_BLACKHOLE:
653                                 flags |= RTF_BLACKHOLE;
654                                 break;
655                         case K_PROTO1:
656                                 flags |= RTF_PROTO1;
657                                 break;
658                         case K_PROTO2:
659                                 flags |= RTF_PROTO2;
660                                 break;
661                         case K_PROXY:
662                                 proxy = 1;
663                                 break;
664                         case K_CLONING:
665                                 flags |= RTF_CLONING;
666                                 break;
667                         case K_XRESOLVE:
668                                 flags |= RTF_XRESOLVE;
669                                 break;
670                         case K_STATIC:
671                                 flags |= RTF_STATIC;
672                                 break;
673                         case K_IFA:
674                                 if (!--argc)
675                                         usage((char *)NULL);
676                                 (void) getaddr(RTA_IFA, *++argv, 0);
677                                 break;
678                         case K_IFP:
679                                 if (!--argc)
680                                         usage((char *)NULL);
681                                 (void) getaddr(RTA_IFP, *++argv, 0);
682                                 break;
683                         case K_GENMASK:
684                                 if (!--argc)
685                                         usage((char *)NULL);
686                                 (void) getaddr(RTA_GENMASK, *++argv, 0);
687                                 break;
688                         case K_GATEWAY:
689                                 if (!--argc)
690                                         usage((char *)NULL);
691                                 (void) getaddr(RTA_GATEWAY, *++argv, 0);
692                                 break;
693                         case K_DST:
694                                 if (!--argc)
695                                         usage((char *)NULL);
696                                 ishost = getaddr(RTA_DST, *++argv, &hp);
697                                 dest = *argv;
698                                 break;
699                         case K_NETMASK:
700                                 if (!--argc)
701                                         usage((char *)NULL);
702                                 (void) getaddr(RTA_NETMASK, *++argv, 0);
703                                 /* FALLTHROUGH */
704                         case K_NET:
705                                 forcenet++;
706                                 break;
707                         case K_PREFIXLEN:
708                                 if (!--argc)
709                                         usage((char *)NULL);
710                                 if (prefixlen(*++argv) == -1) {
711                                         forcenet = 0;
712                                         ishost = 1;
713                                 } else {
714                                         forcenet = 1;
715                                         ishost = 0;
716                                 }
717                                 break;
718                         case K_MTU:
719                         case K_HOPCOUNT:
720                         case K_EXPIRE:
721                         case K_RECVPIPE:
722                         case K_SENDPIPE:
723                         case K_SSTHRESH:
724                         case K_RTT:
725                         case K_RTTVAR:
726                                 if (!--argc)
727                                         usage((char *)NULL);
728                                 set_metric(*++argv, key);
729                                 break;
730                         default:
731                                 usage(1+*argv);
732                         }
733                 } else {
734                         if ((rtm_addrs & RTA_DST) == 0) {
735                                 dest = *argv;
736                                 ishost = getaddr(RTA_DST, *argv, &hp);
737                         } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
738                                 gateway = *argv;
739                                 (void) getaddr(RTA_GATEWAY, *argv, &hp);
740                         } else {
741                                 (void) getaddr(RTA_NETMASK, *argv, 0);
742                                 forcenet = 1;
743                         }
744                 }
745         }
746         if (forcehost) {
747                 ishost = 1;
748 #ifdef INET6
749                 if (af == AF_INET6) {
750                         rtm_addrs &= ~RTA_NETMASK;
751                         memset((void *)&so_mask, 0, sizeof(so_mask));
752                 }
753 #endif 
754         }
755         if (forcenet)
756                 ishost = 0;
757         flags |= RTF_UP;
758         if (ishost)
759                 flags |= RTF_HOST;
760         if (iflag == 0)
761                 flags |= RTF_GATEWAY;
762         if (proxy) {
763                 so_dst.sinarp.sin_other = SIN_PROXY;
764                 flags |= RTF_ANNOUNCE;
765         }
766         for (attempts = 1; ; attempts++) {
767                 errno = 0;
768                 if ((ret = rtmsg(*cmd, flags)) == 0)
769                         break;
770                 if (errno != ENETUNREACH && errno != ESRCH)
771                         break;
772                 if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
773                         hp->h_addr_list++;
774                         memmove(&so_gate.sin.sin_addr, hp->h_addr_list[0],
775                             MIN(hp->h_length, sizeof(so_gate.sin.sin_addr)));
776                 } else
777                         break;
778         }
779         if (*cmd == 'g')
780                 exit(0);
781         if (!qflag) {
782                 oerrno = errno;
783                 (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
784                 if (*gateway) {
785                         (void) printf(": gateway %s", gateway);
786                         if (attempts > 1 && ret == 0 && af == AF_INET)
787                             (void) printf(" (%s)",
788                                 inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
789                 }
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                         case EDQUOT: /* handle recursion avoidance in rt_setgate() */
804                                 err = "gateway uses the same route";
805                                 break;
806                         default:
807                                 err = strerror(oerrno);
808                                 break;
809                         }
810                         (void) printf(": %s\n", err);
811                 }
812         }
813         exit(ret != 0);
814 }
815
816 void
817 inet_makenetandmask(net, sin, bits)
818         u_long net, bits;
819         register struct sockaddr_in *sin;
820 {
821         u_long addr, mask = 0;
822         register char *cp;
823
824         rtm_addrs |= RTA_NETMASK;
825         if (net == 0)
826                 mask = addr = 0;
827         else if (net < 128) {
828                 addr = net << IN_CLASSA_NSHIFT;
829                 mask = IN_CLASSA_NET;
830         } else if (net < 65536) {
831                 addr = net << IN_CLASSB_NSHIFT;
832                 mask = IN_CLASSB_NET;
833         } else if (net < 16777216L) {
834                 addr = net << IN_CLASSC_NSHIFT;
835                 mask = IN_CLASSC_NET;
836         } else {
837                 addr = net;
838                 if ((addr & IN_CLASSA_HOST) == 0)
839                         mask =  IN_CLASSA_NET;
840                 else if ((addr & IN_CLASSB_HOST) == 0)
841                         mask =  IN_CLASSB_NET;
842                 else if ((addr & IN_CLASSC_HOST) == 0)
843                         mask =  IN_CLASSC_NET;
844                 else
845                         mask = -1;
846         }
847         if (bits)
848                 mask = 0xffffffff << (32 - bits);
849         sin->sin_addr.s_addr = htonl(addr);
850         sin = &so_mask.sin;
851         sin->sin_addr.s_addr = htonl(mask);
852         sin->sin_len = 0;
853         sin->sin_family = 0;
854         cp = (char *)(&sin->sin_addr + 1);
855         while (*--cp == 0 && cp > (char *)sin)
856                 ;
857         sin->sin_len = 1 + cp - (char *)sin;
858 }
859
860 #ifdef INET6
861 /*
862  * XXX the function may need more improvement...
863  */
864 static int
865 inet6_makenetandmask(sin6, plen)
866         struct sockaddr_in6 *sin6;
867         char *plen;
868 {
869         struct in6_addr in6;
870
871         if (!plen) {
872                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
873                     sin6->sin6_scope_id == 0) {
874                         plen = "0";
875                 } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
876                         /* aggregatable global unicast - RFC2374 */
877                         memset(&in6, 0, sizeof(in6));
878                         if (!memcmp(&sin6->sin6_addr.s6_addr[8],
879                                     &in6.s6_addr[8], 8))
880                                 plen = "64";
881                 }
882         }
883
884         if (!plen || strcmp(plen, "128") == 0)
885                 return 1;
886         rtm_addrs |= RTA_NETMASK;
887         (void)prefixlen(plen);
888         return 0;
889 }
890 #endif
891
892 /*
893  * Interpret an argument as a network address of some kind,
894  * returning 1 if a host address, 0 if a network address.
895  */
896 int
897 getaddr(which, s, hpp)
898         int which;
899         char *s;
900         struct hostent **hpp;
901 {
902         register sup su;
903         struct hostent *hp;
904         struct netent *np;
905         u_long val;
906         char *q;
907         int afamily;  /* local copy of af so we can change it */
908
909         if (af == 0) {
910                 af = AF_INET;
911                 aflen = sizeof(struct sockaddr_in);
912         }
913         afamily = af;
914         rtm_addrs |= which;
915         switch (which) {
916         case RTA_DST:
917                 su = &so_dst;
918                 break;
919         case RTA_GATEWAY:
920                 su = &so_gate;
921                 if (iflag) {
922                         struct ifaddrs *ifap, *ifa;
923                         struct sockaddr_dl *sdl = NULL;
924
925                         if (getifaddrs(&ifap))
926                                 err(1, "getifaddrs");
927
928                         for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
929                                 if (ifa->ifa_addr->sa_family != AF_LINK)
930                                         continue;
931
932                                 if (strcmp(s, ifa->ifa_name))
933                                         continue;
934
935                                 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
936                         }
937                         /* If we found it, then use it */
938                         if (sdl) {
939                                 /*
940                                  * Copy is safe since we have a
941                                  * sockaddr_storage member in sockunion{}.
942                                  * Note that we need to copy before calling
943                                  * freeifaddrs().
944                                  */
945                                 memcpy(&su->sdl, sdl, sdl->sdl_len);
946                         }
947                         freeifaddrs(ifap);
948                         if (sdl)
949                                 return(1);
950                 }
951                 break;
952         case RTA_NETMASK:
953                 su = &so_mask;
954                 break;
955         case RTA_GENMASK:
956                 su = &so_genmask;
957                 break;
958         case RTA_IFP:
959                 su = &so_ifp;
960                 afamily = AF_LINK;
961                 break;
962         case RTA_IFA:
963                 su = &so_ifa;
964                 break;
965         default:
966                 usage("internal error");
967                 /*NOTREACHED*/
968         }
969         su->sa.sa_len = aflen;
970         su->sa.sa_family = afamily; /* cases that don't want it have left already */
971         if (strcmp(s, "default") == 0) {
972                 /*
973                  * Default is net 0.0.0.0/0 
974                  */
975                 switch (which) {
976                 case RTA_DST:
977                         forcenet++;
978                         /* bzero(su, sizeof(*su)); *//* for readability */
979                         (void) getaddr(RTA_NETMASK, s, 0);
980                         break;
981                 case RTA_NETMASK:
982                 case RTA_GENMASK:
983                         /* bzero(su, sizeof(*su)); *//* for readability */
984                 }
985                 return (0);
986         }
987         switch (afamily) {
988 #ifdef INET6
989         case AF_INET6:
990         {
991                 struct addrinfo hints, *res;
992
993                 q = NULL;
994                 if (which == RTA_DST && (q = strchr(s, '/')) != NULL)
995                         *q = '\0';
996                 memset(&hints, 0, sizeof(hints));
997                 hints.ai_family = afamily;      /*AF_INET6*/
998                 hints.ai_flags = AI_NUMERICHOST;
999                 hints.ai_socktype = SOCK_DGRAM;         /*dummy*/
1000                 if (getaddrinfo(s, "0", &hints, &res) != 0 ||
1001                     res->ai_family != AF_INET6 ||
1002                     res->ai_addrlen != sizeof(su->sin6)) {
1003                         (void) fprintf(stderr, "%s: bad value\n", s);
1004                         exit(1);
1005                 }
1006                 memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
1007 #ifdef __KAME__
1008                 if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
1009                      IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr)) &&
1010                     su->sin6.sin6_scope_id) {
1011                         *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
1012                                 htons(su->sin6.sin6_scope_id);
1013                         su->sin6.sin6_scope_id = 0;
1014                 }
1015 #endif
1016                 freeaddrinfo(res);
1017                 if (q != NULL)
1018                         *q++ = '/';
1019                 if (which == RTA_DST)
1020                         return (inet6_makenetandmask(&su->sin6, q));
1021                 return (0);
1022         }
1023 #endif /* INET6 */
1024
1025 #ifdef NS
1026         case AF_NS:
1027                 if (which == RTA_DST) {
1028                         extern short ns_bh[3];
1029                         struct sockaddr_ns *sms = &(so_mask.sns);
1030                         memset(sms, 0, sizeof(*sms));
1031                         sms->sns_family = 0;
1032                         sms->sns_len = 6;
1033                         sms->sns_addr.x_net = *(union ns_net *)ns_bh;
1034                         rtm_addrs |= RTA_NETMASK;
1035                 }
1036                 su->sns.sns_addr = ns_addr(s);
1037                 return (!ns_nullhost(su->sns.sns_addr));
1038 #endif
1039
1040
1041         case AF_APPLETALK:
1042                 if (!atalk_aton(s, &su->sat.sat_addr))
1043                         errx(EX_NOHOST, "bad address: %s", s);
1044                 rtm_addrs |= RTA_NETMASK;
1045                 return(forcehost || su->sat.sat_addr.s_node != 0);
1046
1047         case AF_LINK:
1048                 link_addr(s, &su->sdl);
1049                 return (1);
1050
1051
1052         case PF_ROUTE:
1053                 su->sa.sa_len = sizeof(*su);
1054                 sockaddr(s, &su->sa);
1055                 return (1);
1056
1057         case AF_INET:
1058         default:
1059                 break;
1060         }
1061
1062         if (hpp == NULL)
1063                 hpp = &hp;
1064         *hpp = NULL;
1065
1066         q = strchr(s,'/');
1067         if (q && which == RTA_DST) {
1068                 *q = '\0';
1069                 if ((val = inet_network(s)) != INADDR_NONE) {
1070                         inet_makenetandmask(
1071                                 val, &su->sin, strtoul(q+1, 0, 0));
1072                         return (0);
1073                 }
1074                 *q = '/';
1075         }
1076         if ((which != RTA_DST || forcenet == 0) &&
1077             inet_aton(s, &su->sin.sin_addr)) {
1078                 val = su->sin.sin_addr.s_addr;
1079                 if (which != RTA_DST ||
1080                     inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
1081                         return (1);
1082                 else {
1083                         val = ntohl(val);
1084                         goto netdone;
1085                 }
1086         }
1087         if (which == RTA_DST && forcehost == 0 &&
1088             ((val = inet_network(s)) != INADDR_NONE ||
1089             ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) {
1090 netdone:
1091                 inet_makenetandmask(val, &su->sin, 0);
1092                 return (0);
1093         }
1094         hp = gethostbyname(s);
1095         if (hp) {
1096                 *hpp = hp;
1097                 su->sin.sin_family = hp->h_addrtype;
1098                 memmove((char *)&su->sin.sin_addr, hp->h_addr,
1099                     MIN(hp->h_length, sizeof(su->sin.sin_addr)));
1100                 return (1);
1101         }
1102         errx(EX_NOHOST, "bad address: %s", s);
1103 }
1104
1105 int
1106 prefixlen(s)
1107         char *s;
1108 {
1109         int len = atoi(s), q, r;
1110         int max;
1111         char *p;
1112
1113         rtm_addrs |= RTA_NETMASK;       
1114         switch (af) {
1115 #ifdef INET6
1116         case AF_INET6:
1117                 max = 128;
1118                 p = (char *)&so_mask.sin6.sin6_addr;
1119                 break;
1120 #endif
1121         case AF_INET:
1122                 max = 32;
1123                 p = (char *)&so_mask.sin.sin_addr;
1124                 break;
1125         default:
1126                 (void) fprintf(stderr, "prefixlen not supported in this af\n");
1127                 exit(1);
1128                 /*NOTREACHED*/
1129         }
1130
1131         if (len < 0 || max < len) {
1132                 (void) fprintf(stderr, "%s: bad value\n", s);
1133                 exit(1);
1134         }
1135         
1136         q = len >> 3;
1137         r = len & 7;
1138         so_mask.sa.sa_family = af;
1139         so_mask.sa.sa_len = aflen;
1140         memset((void *)p, 0, max / 8);
1141         if (q > 0)
1142                 memset((void *)p, 0xff, q);
1143         if (r > 0)
1144                 *((u_char *)p + q) = (0xff00 >> r) & 0xff;
1145         if (len == max)
1146                 return -1;
1147         else
1148                 return len;
1149 }
1150
1151 #ifdef NS
1152 short ns_nullh[] = {0,0,0};
1153 short ns_bh[] = {-1,-1,-1};
1154
1155 char *
1156 ns_print(sns)
1157         struct sockaddr_ns *sns;
1158 {
1159         struct ns_addr work;
1160         union { union ns_net net_e; u_long long_e; } net;
1161         u_short port;
1162         static char mybuf[50+MAXHOSTNAMELEN], cport[10], chost[25];
1163         char *host = "";
1164         register char *p;
1165         register u_char *q;
1166
1167         work = sns->sns_addr;
1168         port = ntohs(work.x_port);
1169         work.x_port = 0;
1170         net.net_e  = work.x_net;
1171         if (ns_nullhost(work) && net.long_e == 0) {
1172                 if (!port)
1173                         return ("*.*");
1174                 (void) sprintf(mybuf, "*.%XH", port);
1175                 return (mybuf);
1176         }
1177
1178         if (memcmp(ns_bh, work.x_host.c_host, 6) == 0)
1179                 host = "any";
1180         else if (memcmp(ns_nullh, work.x_host.c_host, 6) == 0)
1181                 host = "*";
1182         else {
1183                 q = work.x_host.c_host;
1184                 (void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
1185                         q[0], q[1], q[2], q[3], q[4], q[5]);
1186                 for (p = chost; *p == '0' && p < chost + 12; p++)
1187                         /* void */;
1188                 host = p;
1189         }
1190         if (port)
1191                 (void) sprintf(cport, ".%XH", htons(port));
1192         else
1193                 *cport = 0;
1194
1195         (void) snprintf(mybuf, sizeof(mybuf), "%lxH.%s%s",
1196                         (unsigned long)ntohl(net.long_e),
1197                         host, cport);
1198         return (mybuf);
1199 }
1200 #endif
1201
1202 void
1203 interfaces()
1204 {
1205         size_t needed;
1206         int mib[6];
1207         char *buf, *lim, *next;
1208         register struct rt_msghdr *rtm;
1209
1210         mib[0] = CTL_NET;
1211         mib[1] = PF_ROUTE;
1212         mib[2] = 0;             /* protocol */
1213         mib[3] = 0;             /* wildcard address family */
1214         mib[4] = NET_RT_IFLIST;
1215         mib[5] = 0;             /* no flags */
1216         if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1217                 err(EX_OSERR, "route-sysctl-estimate");
1218         if ((buf = malloc(needed)) == NULL)
1219                 errx(EX_OSERR, "malloc failed");
1220         if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
1221                 err(EX_OSERR, "actual retrieval of interface table");
1222         lim = buf + needed;
1223         for (next = buf; next < lim; next += rtm->rtm_msglen) {
1224                 rtm = (struct rt_msghdr *)next;
1225                 print_rtmsg(rtm, rtm->rtm_msglen);
1226         }
1227 }
1228
1229 void
1230 monitor()
1231 {
1232         int n;
1233         char msg[2048];
1234
1235         verbose = 1;
1236         if (debugonly) {
1237                 interfaces();
1238                 exit(0);
1239         }
1240         for(;;) {
1241                 time_t now;
1242                 n = read(s, msg, 2048);
1243                 now = time(NULL);
1244                 (void) printf("\ngot message of size %d on %s", n, ctime(&now));
1245                 print_rtmsg((struct rt_msghdr *)msg, n);
1246         }
1247 }
1248
1249 struct {
1250         struct  rt_msghdr m_rtm;
1251         char    m_space[512];
1252 } m_rtmsg;
1253
1254 int
1255 rtmsg(cmd, flags)
1256         int cmd, flags;
1257 {
1258         static int seq;
1259         int rlen;
1260         register char *cp = m_rtmsg.m_space;
1261         register int l;
1262
1263 #define NEXTADDR(w, u) \
1264         if (rtm_addrs & (w)) {\
1265             l = ROUNDUP(u.sa.sa_len); memmove(cp, &(u), l); cp += l;\
1266             if (verbose) sodump(&(u),"u");\
1267         }
1268
1269         errno = 0;
1270         memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1271         if (cmd == 'a')
1272                 cmd = RTM_ADD;
1273         else if (cmd == 'c')
1274                 cmd = RTM_CHANGE;
1275         else if (cmd == 'g') {
1276                 cmd = RTM_GET;
1277                 if (so_ifp.sa.sa_family == 0) {
1278                         so_ifp.sa.sa_family = AF_LINK;
1279                         so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
1280                         rtm_addrs |= RTA_IFP;
1281                 }
1282         } else
1283                 cmd = RTM_DELETE;
1284 #define rtm m_rtmsg.m_rtm
1285         rtm.rtm_type = cmd;
1286         rtm.rtm_flags = flags;
1287         rtm.rtm_version = RTM_VERSION;
1288         rtm.rtm_seq = ++seq;
1289         rtm.rtm_addrs = rtm_addrs;
1290         rtm.rtm_rmx = rt_metrics;
1291         rtm.rtm_inits = rtm_inits;
1292
1293         if (rtm_addrs & RTA_NETMASK)
1294                 mask_addr();
1295         NEXTADDR(RTA_DST, so_dst);
1296         NEXTADDR(RTA_GATEWAY, so_gate);
1297         NEXTADDR(RTA_NETMASK, so_mask);
1298         NEXTADDR(RTA_GENMASK, so_genmask);
1299         NEXTADDR(RTA_IFP, so_ifp);
1300         NEXTADDR(RTA_IFA, so_ifa);
1301         rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1302         if (verbose)
1303                 print_rtmsg(&rtm, l);
1304         if (debugonly)
1305                 return (0);
1306         if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1307                 warn("writing to routing socket");
1308                 return (-1);
1309         }
1310         if (cmd == RTM_GET) {
1311                 do {
1312                         l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
1313                 } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1314                 if (l < 0)
1315                         warn("read from routing socket");
1316                 else
1317                         print_getmsg(&rtm, l);
1318         }
1319 #undef rtm
1320         return (0);
1321 }
1322
1323 void
1324 mask_addr()
1325 {
1326         int olen = so_mask.sa.sa_len;
1327         register char *cp1 = olen + (char *)&so_mask, *cp2;
1328
1329         for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
1330                 if (*--cp1 != 0) {
1331                         so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
1332                         break;
1333                 }
1334         if ((rtm_addrs & RTA_DST) == 0)
1335                 return;
1336         switch (so_dst.sa.sa_family) {
1337 #ifdef NS
1338         case AF_NS:
1339 #endif
1340         case AF_INET:
1341 #ifdef INET6
1342         case AF_INET6:
1343 #endif
1344         case AF_APPLETALK:
1345         case 0:
1346                 return;
1347         }
1348         cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
1349         cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
1350         while (cp2 > cp1)
1351                 *--cp2 = 0;
1352         cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
1353         while (cp1 > so_dst.sa.sa_data)
1354                 *--cp1 &= *--cp2;
1355 }
1356
1357 char *msgtypes[] = {
1358         "",
1359         "RTM_ADD: Add Route",
1360         "RTM_DELETE: Delete Route",
1361         "RTM_CHANGE: Change Metrics or flags",
1362         "RTM_GET: Report Metrics",
1363         "RTM_LOSING: Kernel Suspects Partitioning",
1364         "RTM_REDIRECT: Told to use different route",
1365         "RTM_MISS: Lookup failed on this address",
1366         "RTM_LOCK: fix specified metrics",
1367         "RTM_OLDADD: caused by SIOCADDRT",
1368         "RTM_OLDDEL: caused by SIOCDELRT",
1369         "RTM_RESOLVE: Route created by cloning",
1370         "RTM_NEWADDR: address being added to iface",
1371         "RTM_DELADDR: address being removed from iface",
1372         "RTM_IFINFO: iface status change",
1373         "RTM_NEWMADDR: new multicast group membership on iface",
1374         "RTM_DELMADDR: multicast group membership removed from iface",
1375         "RTM_IFANNOUNCE: interface arrival/departure",
1376         0,
1377 };
1378
1379 char metricnames[] =
1380 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
1381 "\1mtu";
1382 char routeflags[] =
1383 "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
1384 "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
1385 "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
1386 "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
1387 char ifnetflags[] =
1388 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
1389 "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
1390 "\017LINK2\020MULTICAST";
1391 char addrnames[] =
1392 "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
1393
1394 void
1395 print_rtmsg(rtm, msglen)
1396         register struct rt_msghdr *rtm;
1397         int msglen;
1398 {
1399         struct if_msghdr *ifm;
1400         struct ifa_msghdr *ifam;
1401 #ifdef RTM_NEWMADDR
1402         struct ifma_msghdr *ifmam;
1403 #endif
1404         struct if_announcemsghdr *ifan;
1405
1406         if (verbose == 0)
1407                 return;
1408         if (rtm->rtm_version != RTM_VERSION) {
1409                 (void) printf("routing message version %d not understood\n",
1410                     rtm->rtm_version);
1411                 return;
1412         }
1413         if (msgtypes[rtm->rtm_type] != NULL)
1414                 (void)printf("%s: ", msgtypes[rtm->rtm_type]);
1415         else
1416                 (void)printf("#%d: ", rtm->rtm_type);
1417         (void)printf("len %d, ", rtm->rtm_msglen);
1418         switch (rtm->rtm_type) {
1419         case RTM_IFINFO:
1420                 ifm = (struct if_msghdr *)rtm;
1421                 (void) printf("if# %d, flags:", ifm->ifm_index);
1422                 bprintf(stdout, ifm->ifm_flags, ifnetflags);
1423                 pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1424                 break;
1425         case RTM_NEWADDR:
1426         case RTM_DELADDR:
1427                 ifam = (struct ifa_msghdr *)rtm;
1428                 (void) printf("metric %d, flags:", ifam->ifam_metric);
1429                 bprintf(stdout, ifam->ifam_flags, routeflags);
1430                 pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1431                 break;
1432 #ifdef RTM_NEWMADDR
1433         case RTM_NEWMADDR:
1434         case RTM_DELMADDR:
1435                 ifmam = (struct ifma_msghdr *)rtm;
1436                 pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs);
1437                 break;
1438 #endif
1439         case RTM_IFANNOUNCE:
1440                 ifan = (struct if_announcemsghdr *)rtm;
1441                 (void) printf("if# %d, what: ", ifan->ifan_index);
1442                 switch (ifan->ifan_what) {
1443                 case IFAN_ARRIVAL:
1444                         printf("arrival");
1445                         break;
1446                 case IFAN_DEPARTURE:
1447                         printf("departure");
1448                         break;
1449                 default:
1450                         printf("#%d", ifan->ifan_what);
1451                         break;
1452                 }
1453                 printf("\n");
1454                 break;
1455
1456         default:
1457                 (void) printf("pid: %ld, seq %d, errno %d, flags:",
1458                         (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1459                 bprintf(stdout, rtm->rtm_flags, routeflags);
1460                 pmsg_common(rtm);
1461         }
1462 }
1463
1464 void
1465 print_getmsg(rtm, msglen)
1466         register struct rt_msghdr *rtm;
1467         int msglen;
1468 {
1469         struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
1470         struct sockaddr_dl *ifp = NULL;
1471         register struct sockaddr *sa;
1472         register char *cp;
1473         register int i;
1474
1475         (void) printf("   route to: %s\n", routename(&so_dst));
1476         if (rtm->rtm_version != RTM_VERSION) {
1477                 warnx("routing message version %d not understood",
1478                      rtm->rtm_version);
1479                 return;
1480         }
1481         if (rtm->rtm_msglen > msglen) {
1482                 warnx("message length mismatch, in packet %d, returned %d",
1483                       rtm->rtm_msglen, msglen);
1484         }
1485         if (rtm->rtm_errno)  {
1486                 errno = rtm->rtm_errno;
1487                 warn("message indicates error %d", errno);
1488                 return;
1489         }
1490         cp = ((char *)(rtm + 1));
1491         if (rtm->rtm_addrs)
1492                 for (i = 1; i; i <<= 1)
1493                         if (i & rtm->rtm_addrs) {
1494                                 sa = (struct sockaddr *)cp;
1495                                 switch (i) {
1496                                 case RTA_DST:
1497                                         dst = sa;
1498                                         break;
1499                                 case RTA_GATEWAY:
1500                                         gate = sa;
1501                                         break;
1502                                 case RTA_NETMASK:
1503                                         mask = sa;
1504                                         break;
1505                                 case RTA_IFP:
1506                                         if (sa->sa_family == AF_LINK &&
1507                                            ((struct sockaddr_dl *)sa)->sdl_nlen)
1508                                                 ifp = (struct sockaddr_dl *)sa;
1509                                         break;
1510                                 }
1511                                 ADVANCE(cp, sa);
1512                         }
1513         if (dst && mask)
1514                 mask->sa_family = dst->sa_family;       /* XXX */
1515         if (dst)
1516                 (void)printf("destination: %s\n", routename(dst));
1517         if (mask) {
1518                 int savenflag = nflag;
1519
1520                 nflag = 1;
1521                 (void)printf("       mask: %s\n", routename(mask));
1522                 nflag = savenflag;
1523         }
1524         if (gate && rtm->rtm_flags & RTF_GATEWAY)
1525                 (void)printf("    gateway: %s\n", routename(gate));
1526         if (ifp)
1527                 (void)printf("  interface: %.*s\n",
1528                     ifp->sdl_nlen, ifp->sdl_data);
1529         (void)printf("      flags: ");
1530         bprintf(stdout, rtm->rtm_flags, routeflags);
1531
1532 #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1533 #define msec(u) (((u) + 500) / 1000)            /* usec to msec */
1534
1535         (void) printf("\n%s\n", "\
1536  recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire");
1537         printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1538         printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1539         printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1540         printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1541         printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1542         printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1543         printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
1544         if (rtm->rtm_rmx.rmx_expire)
1545                 rtm->rtm_rmx.rmx_expire -= time(0);
1546         printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
1547 #undef lock
1548 #undef msec
1549 #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
1550         if (verbose)
1551                 pmsg_common(rtm);
1552         else if (rtm->rtm_addrs &~ RTA_IGN) {
1553                 (void) printf("sockaddrs: ");
1554                 bprintf(stdout, rtm->rtm_addrs, addrnames);
1555                 putchar('\n');
1556         }
1557 #undef  RTA_IGN
1558 }
1559
1560 void
1561 pmsg_common(rtm)
1562         register struct rt_msghdr *rtm;
1563 {
1564         (void) printf("\nlocks: ");
1565         bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
1566         (void) printf(" inits: ");
1567         bprintf(stdout, rtm->rtm_inits, metricnames);
1568         pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
1569 }
1570
1571 void
1572 pmsg_addrs(cp, addrs)
1573         char    *cp;
1574         int     addrs;
1575 {
1576         register struct sockaddr *sa;
1577         int i;
1578
1579         if (addrs == 0) {
1580                 (void) putchar('\n');
1581                 return;
1582         }
1583         (void) printf("\nsockaddrs: ");
1584         bprintf(stdout, addrs, addrnames);
1585         (void) putchar('\n');
1586         for (i = 1; i; i <<= 1)
1587                 if (i & addrs) {
1588                         sa = (struct sockaddr *)cp;
1589                         (void) printf(" %s", routename(sa));
1590                         ADVANCE(cp, sa);
1591                 }
1592         (void) putchar('\n');
1593         (void) fflush(stdout);
1594 }
1595
1596 void
1597 bprintf(fp, b, s)
1598         register FILE *fp;
1599         register int b;
1600         register u_char *s;
1601 {
1602         register int i;
1603         int gotsome = 0;
1604
1605         if (b == 0)
1606                 return;
1607         while ((i = *s++) != 0) {
1608                 if (b & (1 << (i-1))) {
1609                         if (gotsome == 0)
1610                                 i = '<';
1611                         else
1612                                 i = ',';
1613                         (void) putc(i, fp);
1614                         gotsome = 1;
1615                         for (; (i = *s) > 32; s++)
1616                                 (void) putc(i, fp);
1617                 } else
1618                         while (*s > 32)
1619                                 s++;
1620         }
1621         if (gotsome)
1622                 (void) putc('>', fp);
1623 }
1624
1625 int
1626 keyword(cp)
1627         char *cp;
1628 {
1629         register struct keytab *kt = keywords;
1630
1631         while (kt->kt_cp && strcmp(kt->kt_cp, cp))
1632                 kt++;
1633         return kt->kt_i;
1634 }
1635
1636 void
1637 sodump(su, which)
1638         register sup su;
1639         char *which;
1640 {
1641         switch (su->sa.sa_family) {
1642         case AF_LINK:
1643                 (void) printf("%s: link %s; ",
1644                     which, link_ntoa(&su->sdl));
1645                 break;
1646         case AF_INET:
1647                 (void) printf("%s: inet %s; ",
1648                     which, inet_ntoa(su->sin.sin_addr));
1649                 break;
1650         case AF_APPLETALK:
1651                 (void) printf("%s: atalk %s; ",
1652                     which, atalk_ntoa(su->sat.sat_addr));
1653                 break;
1654 #ifdef NS
1655         case AF_NS:
1656                 (void) printf("%s: xns %s; ",
1657                     which, ns_ntoa(su->sns.sns_addr));
1658                 break;
1659 #endif
1660         }
1661         (void) fflush(stdout);
1662 }
1663
1664 /* States*/
1665 #define VIRGIN  0
1666 #define GOTONE  1
1667 #define GOTTWO  2
1668 /* Inputs */
1669 #define DIGIT   (4*0)
1670 #define END     (4*1)
1671 #define DELIM   (4*2)
1672
1673 void
1674 sockaddr(addr, sa)
1675         register char *addr;
1676         register struct sockaddr *sa;
1677 {
1678         register char *cp = (char *)sa;
1679         int size = sa->sa_len;
1680         char *cplim = cp + size;
1681         register int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
1682
1683         memset(cp, 0, size);
1684         cp++;
1685         do {
1686                 if ((*addr >= '0') && (*addr <= '9')) {
1687                         new = *addr - '0';
1688                 } else if ((*addr >= 'a') && (*addr <= 'f')) {
1689                         new = *addr - 'a' + 10;
1690                 } else if ((*addr >= 'A') && (*addr <= 'F')) {
1691                         new = *addr - 'A' + 10;
1692                 } else if (*addr == 0)
1693                         state |= END;
1694                 else
1695                         state |= DELIM;
1696                 addr++;
1697                 switch (state /* | INPUT */) {
1698                 case GOTTWO | DIGIT:
1699                         *cp++ = byte; /*FALLTHROUGH*/
1700                 case VIRGIN | DIGIT:
1701                         state = GOTONE; byte = new; continue;
1702                 case GOTONE | DIGIT:
1703                         state = GOTTWO; byte = new + (byte << 4); continue;
1704                 default: /* | DELIM */
1705                         state = VIRGIN; *cp++ = byte; byte = 0; continue;
1706                 case GOTONE | END:
1707                 case GOTTWO | END:
1708                         *cp++ = byte; /* FALLTHROUGH */
1709                 case VIRGIN | END:
1710                         break;
1711                 }
1712                 break;
1713         } while (cp < cplim);
1714         sa->sa_len = cp - (char *)sa;
1715 }
1716
1717 int
1718 atalk_aton(const char *text, struct at_addr *addr)
1719 {
1720         u_int net, node;
1721
1722         if (sscanf(text, "%u.%u", &net, &node) != 2
1723             || net > 0xffff || node > 0xff)
1724                 return(0);
1725         addr->s_net = htons(net);
1726         addr->s_node = node;
1727         return(1);
1728 }
1729
1730 char *
1731 atalk_ntoa(struct at_addr at)
1732 {
1733         static char buf[20];
1734
1735         (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node);
1736         return(buf);
1737 }