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