]> git.saurik.com Git - apple/network_cmds.git/blobdiff - route.tproj/route.c
network_cmds-329.2.1.tar.gz
[apple/network_cmds.git] / route.tproj / route.c
index 9c53a27617e605247ed9929400323be9470e15de..c43f159bf73776465be62ced55b5d37233062bba 100644 (file)
@@ -1,25 +1,29 @@
 /*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
  *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
- * Reserved.  This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License').  You may not use this file
- * except in compliance with the License.  Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- * 
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- * 
- * @APPLE_LICENSE_HEADER_END@
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  * Copyright (c) 1983, 1989, 1991, 1993
@@ -54,8 +58,9 @@
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
-static const char copyright[] =
+__unused static const char copyright[] =
 "@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
        The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
@@ -64,8 +69,8 @@ static const char copyright[] =
 #if 0
 static char sccsid[] = "@(#)route.c    8.3 (Berkeley) 3/19/94";
 #endif
-static const char rcsid[] =
-       "$Id: route.c,v 1.1.1.2 2000/01/11 01:49:18 wsanchez Exp $";
+__unused static const char rcsid[] =
+       "$Id: route.c,v 1.4 2006/02/07 06:22:29 lindak Exp $";
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -73,28 +78,25 @@ static const char rcsid[] =
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <sys/sysctl.h>
+#include <sys/types.h>
 
 #include <net/if.h>
 #include <net/route.h>
 #include <net/if_dl.h>
 #include <netinet/in.h>
-#ifdef AT
-#include <netatalk/at.h>
-#endif
-#ifdef NS
-#include <netns/ns.h>
-#endif
 #include <arpa/inet.h>
 #include <netdb.h>
 
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
+#include <paths.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sysexits.h>
 #include <unistd.h>
+#include <ifaddrs.h>
 
 struct keytab {
        char    *kt_cp;
@@ -104,17 +106,14 @@ struct keytab {
        {0, 0}
 };
 
-struct ortentry route;
 union  sockunion {
        struct  sockaddr sa;
        struct  sockaddr_in sin;
-#ifdef AT
-       struct  sockaddr_at sat;
-#endif
-#ifdef NS
-       struct  sockaddr_ns sns;
+#ifdef INET6
+       struct  sockaddr_in6 sin6;
 #endif
        struct  sockaddr_dl sdl;
+       struct  sockaddr_storage ss; /* added to avoid memory overrun */
 } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
 
 typedef union sockunion *sup;
@@ -125,18 +124,15 @@ int       iflag, verbose, aflen = sizeof (struct sockaddr_in);
 int    locking, lockrest, debugonly;
 struct rt_metrics rt_metrics;
 u_long  rtm_inits;
-struct in_addr inet_makeaddr();
-#ifdef AT
-int    atalk_aton __P((const char *, struct at_addr *));
-char   *atalk_ntoa __P((struct at_addr));
-#endif
-char   *routename(), *netname();
+unsigned int ifscope;
+const char     *routename(), *netname();
 void   flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
 void   print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
 int    getaddr(), rtmsg(), x25_makemask();
-extern char *inet_ntoa(), *iso_ntoa(), *link_ntoa();
+int    prefixlen();
+extern char *iso_ntoa();
 
-void usage __P((const char *));
+void usage __P((const char *)) __dead2;
 
 void
 usage(cp)
@@ -151,7 +147,7 @@ usage(cp)
 }
 
 #define ROUNDUP(a) \
-       ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+       ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
 
 int
@@ -191,7 +187,7 @@ main(argc, argv)
        pid = getpid();
        uid = getuid();
        if (tflag)
-               s = open("/dev/null", O_WRONLY, 0);
+               s = open(_PATH_DEVNULL, O_WRONLY, 0);
        else
                s = socket(PF_ROUTE, SOCK_RAW, 0);
        if (s < 0)
@@ -248,15 +244,9 @@ flushroutes(argc, argv)
                        case K_INET:
                                af = AF_INET;
                                break;
-
-#ifdef
-                       case K_ATALK:
-                               af = AF_APPLETALK;
-                               break;
-#endif
-#ifdef NS
-                       case K_XNS:
-                               af = AF_NS;
+#ifdef INET6
+                       case K_INET6:
+                               af = AF_INET6;
                                break;
 #endif
                        case K_LINK:
@@ -314,14 +304,14 @@ bad:                      usage(*argv);
                        struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
                        (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
                            routename(sa) : netname(sa));
-                       sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
+                       sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
                        (void) printf("%-20.20s ", routename(sa));
                        (void) printf("done\n");
                }
        }
 }
 
-char *
+const char *
 routename(sa)
        struct sockaddr *sa;
 {
@@ -330,9 +320,6 @@ routename(sa)
        struct hostent *hp;
        static char domain[MAXHOSTNAMELEN + 1];
        static int first = 1;
-#ifdef NS
-       char *ns_print();
-#endif
 
        if (first) {
                first = 0;
@@ -377,15 +364,39 @@ routename(sa)
                }
                break;
            }
-#ifdef AT
-       case AF_APPLETALK:
-               (void) snprintf(line, sizeof(line), "atalk %s",
-                       atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
-               break;
+
+#ifdef INET6
+       case AF_INET6:
+       {
+               struct sockaddr_in6 sin6; /* use static var for safety */
+               int niflags = 0;
+#ifdef NI_WITHSCOPEID
+               niflags = NI_WITHSCOPEID;
+#endif
+
+               memset(&sin6, 0, sizeof(sin6));
+               memcpy(&sin6, sa, sa->sa_len);
+               sin6.sin6_len = sizeof(struct sockaddr_in6);
+               sin6.sin6_family = AF_INET6;
+#ifdef __KAME__
+               if (sa->sa_len == sizeof(struct sockaddr_in6) &&
+                   (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+                    IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
+                   sin6.sin6_scope_id == 0) {
+                       sin6.sin6_scope_id =
+                           ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+                       sin6.sin6_addr.s6_addr[2] = 0;
+                       sin6.sin6_addr.s6_addr[3] = 0;
+               }
 #endif
-#ifdef NS
-       case AF_NS:
-               return (ns_print((struct sockaddr_ns *)sa));
+               if (nflag)
+                       niflags |= NI_NUMERICHOST;
+               if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+                   line, sizeof(line), NULL, 0, niflags) != 0)
+                       strncpy(line, "invalid", sizeof(line));
+
+               return(line);
+       }
 #endif
 
        case AF_LINK:
@@ -409,19 +420,16 @@ routename(sa)
  * Return the name of the network whose address is given.
  * The address is assumed to be that of a net or subnet, not a host.
  */
-char *
+const char *
 netname(sa)
        struct sockaddr *sa;
 {
        char *cp = 0;
        static char line[MAXHOSTNAMELEN + 1];
        struct netent *np = 0;
-       u_long net, mask;
-       register u_long i;
+       in_addr_t net, mask;
+       register in_addr_t i;
        int subnetshift;
-#ifdef NS
-       char *ns_print();
-#endif
 
        switch (sa->sa_family) {
 
@@ -450,7 +458,7 @@ netname(sa)
                         * width subnet fields.
                         */
                        while (in.s_addr &~ mask)
-                               mask = (long)mask >> subnetshift;
+                               mask = mask >> subnetshift;
                        net = in.s_addr & mask;
                        while ((mask & 1) == 0)
                                mask >>= 1, net >>= 1;
@@ -474,16 +482,39 @@ netname(sa)
                            C(in.s_addr));
                break;
            }
-#ifdef AT
-       case AF_APPLETALK:
-               (void) snprintf(line, sizeof(line), "atalk %s",
-                       atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
-               break;
+
+#ifdef INET6
+       case AF_INET6:
+       {
+               struct sockaddr_in6 sin6; /* use static var for safety */
+               int niflags = 0;
+#ifdef NI_WITHSCOPEID
+               niflags = NI_WITHSCOPEID;
 #endif
-#ifdef NS
-       case AF_NS:
-               return (ns_print((struct sockaddr_ns *)sa));
-               break;
+
+               memset(&sin6, 0, sizeof(sin6));
+               memcpy(&sin6, sa, sa->sa_len);
+               sin6.sin6_len = sizeof(struct sockaddr_in6);
+               sin6.sin6_family = AF_INET6;
+#ifdef __KAME__
+               if (sa->sa_len == sizeof(struct sockaddr_in6) &&
+                   (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+                    IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
+                   sin6.sin6_scope_id == 0) {
+                       sin6.sin6_scope_id =
+                           ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+                       sin6.sin6_addr.s6_addr[2] = 0;
+                       sin6.sin6_addr.s6_addr[3] = 0;
+               }
+#endif
+               if (nflag)
+                       niflags |= NI_NUMERICHOST;
+               if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+                   line, sizeof(line), NULL, 0, niflags) != 0)
+                       strncpy(line, "invalid", sizeof(line));
+
+               return(line);
+       }
 #endif
 
        case AF_LINK:
@@ -510,10 +541,10 @@ set_metric(value, key)
        int key;
 {
        int flag = 0;
-       u_long noval, *valp = &noval;
+       u_int noval, *valp = &noval;
 
        switch (key) {
-#define caseof(x, y, z)        case x: valp = &rt_metrics.z; flag = y; break
+#define caseof(x, y, z)        case x: valp = (u_int *)&rt_metrics.z; flag = y; break
        caseof(K_MTU, RTV_MTU, rmx_mtu);
        caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
        caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
@@ -558,22 +589,16 @@ newroute(argc, argv)
                                af = AF_INET;
                                aflen = sizeof(struct sockaddr_in);
                                break;
-#ifdef AT
-                       case K_ATALK:
-                               af = AF_APPLETALK;
-                               aflen = sizeof(struct sockaddr_at);
+#ifdef INET6
+                       case K_INET6:
+                               af = AF_INET6;
+                               aflen = sizeof(struct sockaddr_in6);
                                break;
 #endif
                        case K_SA:
                                af = PF_ROUTE;
                                aflen = sizeof(union sockunion);
                                break;
-#ifdef NS
-                       case K_XNS:
-                               af = AF_NS;
-                               aflen = sizeof(struct sockaddr_ns);
-                               break;
-#endif
                        case K_IFACE:
                        case K_INTERFACE:
                                iflag++;
@@ -581,11 +606,9 @@ newroute(argc, argv)
                        case K_NOSTATIC:
                                flags &= ~RTF_STATIC;
                                break;
-
                        case K_LLINFO:
                                flags |= RTF_LLINFO;
                                break;
-
                        case K_LOCK:
                                locking = 1;
                                break;
@@ -617,33 +640,50 @@ newroute(argc, argv)
                                flags |= RTF_STATIC;
                                break;
                        case K_IFA:
-                               argc--;
+                               if (!--argc)
+                                       usage((char *)NULL);
                                (void) getaddr(RTA_IFA, *++argv, 0);
                                break;
                        case K_IFP:
-                               argc--;
+                               if (!--argc)
+                                       usage((char *)NULL);
                                (void) getaddr(RTA_IFP, *++argv, 0);
                                break;
                        case K_GENMASK:
-                               argc--;
+                               if (!--argc)
+                                       usage((char *)NULL);
                                (void) getaddr(RTA_GENMASK, *++argv, 0);
                                break;
                        case K_GATEWAY:
-                               argc--;
+                               if (!--argc)
+                                       usage((char *)NULL);
                                (void) getaddr(RTA_GATEWAY, *++argv, 0);
                                break;
                        case K_DST:
-                               argc--;
+                               if (!--argc)
+                                       usage((char *)NULL);
                                ishost = getaddr(RTA_DST, *++argv, &hp);
                                dest = *argv;
                                break;
                        case K_NETMASK:
-                               argc--;
+                               if (!--argc)
+                                       usage((char *)NULL);
                                (void) getaddr(RTA_NETMASK, *++argv, 0);
                                /* FALLTHROUGH */
                        case K_NET:
                                forcenet++;
                                break;
+                       case K_PREFIXLEN:
+                               if (!--argc)
+                                       usage((char *)NULL);
+                               if (prefixlen(*++argv) == -1) {
+                                       forcenet = 0;
+                                       ishost = 1;
+                               } else {
+                                       forcenet = 1;
+                                       ishost = 0;
+                               }
+                               break;
                        case K_MTU:
                        case K_HOPCOUNT:
                        case K_EXPIRE:
@@ -652,9 +692,18 @@ newroute(argc, argv)
                        case K_SSTHRESH:
                        case K_RTT:
                        case K_RTTVAR:
-                               argc--;
+                               if (!--argc)
+                                       usage((char *)NULL);
                                set_metric(*++argv, key);
                                break;
+                       case K_IFSCOPE:
+                               if (!--argc)
+                                       usage((char *)NULL);
+                               if ((ifscope = if_nametoindex(*++argv)) != 0)
+                                       flags |= RTF_IFSCOPE;
+                               else
+                                       errx(1, "bad interface name");
+                               break;
                        default:
                                usage(1+*argv);
                        }
@@ -670,8 +719,15 @@ newroute(argc, argv)
                        }
                }
        }
-       if (forcehost)
+       if (forcehost) {
                ishost = 1;
+#ifdef INET6
+               if (af == AF_INET6) {
+                       rtm_addrs &= ~RTA_NETMASK;
+                       memset((void *)&so_mask, 0, sizeof(so_mask));
+               }
+#endif 
+       }
        if (forcenet)
                ishost = 0;
        flags |= RTF_UP;
@@ -679,6 +735,16 @@ newroute(argc, argv)
                flags |= RTF_HOST;
        if (iflag == 0)
                flags |= RTF_GATEWAY;
+       if (so_mask.sin.sin_family == AF_INET) {
+               // make sure the mask is contiguous
+               long i;
+               for (i = 0; i < 32; i++)
+                       if (((so_mask.sin.sin_addr.s_addr) & ntohl((1 << i))) != 0)
+                               break;
+               for (; i < 32; i++)
+                       if (((so_mask.sin.sin_addr.s_addr) & ntohl((1 << i))) == 0)
+                               errx(EX_NOHOST, "invalid mask: %s", inet_ntoa(so_mask.sin.sin_addr));
+       }
        for (attempts = 1; ; attempts++) {
                errno = 0;
                if ((ret = rtmsg(*cmd, flags)) == 0)
@@ -699,8 +765,7 @@ newroute(argc, argv)
        if (*gateway) {
                (void) printf(": gateway %s", gateway);
                if (attempts > 1 && ret == 0 && af == AF_INET)
-                   (void) printf(" (%s)",
-                       inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
+                   (void) printf(" (%s)", inet_ntoa(so_gate.sin.sin_addr));
        }
        if (ret == 0)
                (void) printf("\n");
@@ -725,19 +790,19 @@ newroute(argc, argv)
 
 void
 inet_makenetandmask(net, sin, bits)
-       u_long net, bits;
+       in_addr_t net, bits;
        register struct sockaddr_in *sin;
 {
-       u_long addr, mask = 0;
+       in_addr_t addr, mask = 0;
        register char *cp;
 
        rtm_addrs |= RTA_NETMASK;
-       if (net == 0)
-               mask = addr = 0;
-       else if (bits) {
+       if (bits) {
                addr = net;
                mask = 0xffffffff << (32 - bits);
-       } else if (net < 128) {
+       } else if (net == 0)
+               mask = addr = 0;
+       else if (net < 128) {
                addr = net << IN_CLASSA_NSHIFT;
                mask = IN_CLASSA_NET;
        } else if (net < 65536) {
@@ -778,19 +843,18 @@ getaddr(which, s, hpp)
        char *s;
        struct hostent **hpp;
 {
-       register sup su;
-#ifdef NS
-       struct ns_addr ns_addr();
-#endif
+       register sup su = NULL;
        struct hostent *hp;
        struct netent *np;
-       u_long val;
-       char *q,qs;
+       in_addr_t val;
+       char *q;
+       int afamily;  /* local copy of af so we can change it */
 
        if (af == 0) {
                af = AF_INET;
                aflen = sizeof(struct sockaddr_in);
        }
+       afamily = af;
        rtm_addrs |= which;
        switch (which) {
        case RTA_DST:
@@ -799,46 +863,34 @@ getaddr(which, s, hpp)
        case RTA_GATEWAY:
                su = &so_gate;
                if (iflag) {
-                       #define MAX_IFACES      400
-                       int                     sock;
-                       struct ifreq            iflist[MAX_IFACES];
-                       struct ifconf           ifconf;
-                       struct ifreq            *ifr, *ifr_end;
-                       struct sockaddr_dl      *dl, *sdl = NULL;
-
-                       /* Get socket */
-                       if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
-                               err(1, "socket");
-
-                       /* Get interface list */
-                       ifconf.ifc_req = iflist;
-                       ifconf.ifc_len = sizeof(iflist);
-                       if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0)
-                               err(1, "ioctl(SIOCGIFCONF)");
-                       close(sock);
-
-                       /* Look for this interface in the list */
-                       for (ifr = ifconf.ifc_req,
-                           ifr_end = (struct ifreq *)
-                               (ifconf.ifc_buf + ifconf.ifc_len);
-                           ifr < ifr_end;
-                           ifr = (struct ifreq *) ((char *) &ifr->ifr_addr
-                                                   + ifr->ifr_addr.sa_len)) {
-                               dl = (struct sockaddr_dl *)&ifr->ifr_addr;
-                               if (ifr->ifr_addr.sa_family == AF_LINK
-                                   && (ifr->ifr_flags & IFF_POINTOPOINT)
-                                   && !strncmp(s, dl->sdl_data, dl->sdl_nlen)
-                                   && s[dl->sdl_nlen] == 0) {
-                                       sdl = dl;
-                                       break;
-                               }
-                       }
+                       struct ifaddrs *ifap, *ifa;
+                       struct sockaddr_dl *sdl = NULL;
 
+                       if (getifaddrs(&ifap))
+                               err(1, "getifaddrs");
+
+                       for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+                               if (ifa->ifa_addr->sa_family != AF_LINK)
+                                       continue;
+
+                               if (strcmp(s, ifa->ifa_name))
+                                       continue;
+
+                               sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+                       }
                        /* If we found it, then use it */
                        if (sdl) {
-                               su->sdl = *sdl;
-                               return(1);
+                               /*
+                                * Copy is safe since we have a
+                                * sockaddr_storage member in sockunion{}.
+                                * Note that we need to copy before calling
+                                * freeifaddrs().
+                                */
+                               memcpy(&su->sdl, sdl, sdl->sdl_len);
                        }
+                       freeifaddrs(ifap);
+                       if (sdl)
+                               return(1);
                }
                break;
        case RTA_NETMASK:
@@ -849,6 +901,7 @@ getaddr(which, s, hpp)
                break;
        case RTA_IFP:
                su = &so_ifp;
+               afamily = AF_LINK;
                break;
        case RTA_IFA:
                su = &so_ifa;
@@ -858,7 +911,7 @@ getaddr(which, s, hpp)
                /*NOTREACHED*/
        }
        su->sa.sa_len = aflen;
-       su->sa.sa_family = af; /* cases that don't want it have left already */
+       su->sa.sa_family = afamily; /* cases that don't want it have left already */
        if (strcmp(s, "default") == 0) {
                /*
                 * Default is net 0.0.0.0/0 
@@ -869,37 +922,44 @@ getaddr(which, s, hpp)
                        /* bzero(su, sizeof(*su)); *//* for readability */
                        (void) getaddr(RTA_NETMASK, s, 0);
                        break;
-#if 0
                case RTA_NETMASK:
                case RTA_GENMASK:
                        /* bzero(su, sizeof(*su)); *//* for readability */
-#endif
+                       break;
                }
                return (0);
        }
-       switch (af) {
-#ifdef NS
-       case AF_NS:
-               if (which == RTA_DST) {
-                       extern short ns_bh[3];
-                       struct sockaddr_ns *sms = &(so_mask.sns);
-                       bzero((char *)sms, sizeof(*sms));
-                       sms->sns_family = 0;
-                       sms->sns_len = 6;
-                       sms->sns_addr.x_net = *(union ns_net *)ns_bh;
-                       rtm_addrs |= RTA_NETMASK;
+       switch (afamily) {
+#ifdef INET6
+       case AF_INET6:
+       {
+               struct addrinfo hints, *res;
+
+               memset(&hints, 0, sizeof(hints));
+               hints.ai_family = afamily;      /*AF_INET6*/
+               hints.ai_flags = AI_NUMERICHOST;
+               hints.ai_socktype = SOCK_DGRAM;         /*dummy*/
+               if (getaddrinfo(s, "0", &hints, &res) != 0 ||
+                   res->ai_family != AF_INET6 ||
+                   res->ai_addrlen != sizeof(su->sin6)) {
+                       (void) fprintf(stderr, "%s: bad value\n", s);
+                       exit(1);
+               }
+               memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
+#ifdef __KAME__
+               if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
+                    IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr)) &&
+                   su->sin6.sin6_scope_id) {
+                       *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
+                               htons(su->sin6.sin6_scope_id);
+                       su->sin6.sin6_scope_id = 0;
                }
-               su->sns.sns_addr = ns_addr(s);
-               return (!ns_nullhost(su->sns.sns_addr));
 #endif
+               freeaddrinfo(res);
+               return (0);
+       }
+#endif /* INET6 */
 
-#ifdef AT
-       case AF_APPLETALK:
-               if (!atalk_aton(s, &su->sat.sat_addr))
-                       errx(EX_NOHOST, "bad address: %s", s);
-               rtm_addrs |= RTA_NETMASK;
-               return(forcehost || su->sat.sat_addr.s_node != 0);
-#endif
        case AF_LINK:
                link_addr(s, &su->sdl);
                return (1);
@@ -921,31 +981,30 @@ getaddr(which, s, hpp)
 
        q = strchr(s,'/');
        if (q && which == RTA_DST) {
-               qs = *q;
                *q = '\0';
-               if (((val = inet_addr(s)) != INADDR_NONE)) {
+               if ((val = inet_addr(s)) != INADDR_NONE) {
                        inet_makenetandmask(
-                               htonl(val), &su->sin, strtoul(q+1, 0, 0));
+                               ntohl(val), &su->sin, strtoul(q+1, 0, 0));
                        return (0);
                }
-               *q =qs;
+               *q = '/';
        }
-       if (((val = inet_addr(s)) != INADDR_NONE) &&
-           (which != RTA_DST || forcenet == 0)) {
+       if ((which != RTA_DST || forcenet == 0) &&
+           (val = inet_addr(s)) != INADDR_NONE) {
                su->sin.sin_addr.s_addr = val;
-               if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
+               if (which != RTA_DST ||
+                   inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
                        return (1);
                else {
                        val = ntohl(val);
                        goto netdone;
                }
        }
-       if ((val = inet_network(s)) != INADDR_NONE ||
-           (forcehost == 0 && (np = getnetbyname(s)) != NULL &&
-                   (val = np->n_net) != 0)) {
+       if (which == RTA_DST && forcehost == 0 &&
+           ((val = inet_network(s)) != INADDR_NONE ||
+           ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) {
 netdone:
-               if (which == RTA_DST)
-                       inet_makenetandmask(val, &su->sin, 0);
+               inet_makenetandmask(val, &su->sin, 0);
                return (0);
        }
        hp = gethostbyname(s);
@@ -959,57 +1018,51 @@ netdone:
        errx(EX_NOHOST, "bad address: %s", s);
 }
 
-
-#ifdef NS
-short ns_nullh[] = {0,0,0};
-short ns_bh[] = {-1,-1,-1};
-
-char *
-ns_print(sns)
-       struct sockaddr_ns *sns;
+int
+prefixlen(s)
+       char *s;
 {
-       struct ns_addr work;
-       union { union ns_net net_e; u_long long_e; } net;
-       u_short port;
-       static char mybuf[50+MAXHOSTNAMELEN], cport[10], chost[25];
-       char *host = "";
-       register char *p;
-       register u_char *q;
-
-       work = sns->sns_addr;
-       port = ntohs(work.x_port);
-       work.x_port = 0;
-       net.net_e  = work.x_net;
-       if (ns_nullhost(work) && net.long_e == 0) {
-               if (!port)
-                       return ("*.*");
-               (void) sprintf(mybuf, "*.%XH", port);
-               return (mybuf);
+       int len = atoi(s), q, r;
+       int max;
+       char *p;
+
+       rtm_addrs |= RTA_NETMASK;       
+       switch (af) {
+#ifdef INET6
+       case AF_INET6:
+               max = 128;
+               p = (char *)&so_mask.sin6.sin6_addr;
+               break;
+#endif
+       case AF_INET:
+               max = 32;
+               p = (char *)&so_mask.sin.sin_addr;
+               break;
+       default:
+               (void) fprintf(stderr, "prefixlen not supported in this af\n");
+               exit(1);
+               /*NOTREACHED*/
        }
 
-       if (bcmp((char *)ns_bh, (char *)work.x_host.c_host, 6) == 0)
-               host = "any";
-       else if (bcmp((char *)ns_nullh, (char *)work.x_host.c_host, 6) == 0)
-               host = "*";
-       else {
-               q = work.x_host.c_host;
-               (void) sprintf(chost, "%02X%02X%02X%02X%02X%02XH",
-                       q[0], q[1], q[2], q[3], q[4], q[5]);
-               for (p = chost; *p == '0' && p < chost + 12; p++)
-                       /* void */;
-               host = p;
+       if (len < 0 || max < len) {
+               (void) fprintf(stderr, "%s: bad value\n", s);
+               exit(1);
        }
-       if (port)
-               (void) sprintf(cport, ".%XH", htons(port));
+       
+       q = len >> 3;
+       r = len & 7;
+       so_mask.sa.sa_family = af;
+       so_mask.sa.sa_len = aflen;
+       memset((void *)p, 0, max / 8);
+       if (q > 0)
+               memset((void *)p, 0xff, q);
+       if (r > 0)
+               *((u_char *)p + q) = (0xff00 >> r) & 0xff;
+       if (len == max)
+               return -1;
        else
-               *cport = 0;
-
-       (void) snprintf(mybuf, sizeof(mybuf), "%lxH.%s%s", 
-                    (unsigned long)ntohl(net.long_e),
-                      host, cport);
-       return (mybuf);
+               return len;
 }
-#endif
 
 void
 interfaces()
@@ -1050,8 +1103,10 @@ monitor()
                exit(0);
        }
        for(;;) {
+               time_t now;
                n = read(s, msg, 2048);
-               (void) printf("got message of size %d\n", n);
+               now = time(NULL);
+               (void) printf("\ngot message of size %d on %s", n, ctime(&now));
                print_rtmsg((struct rt_msghdr *)msg, n);
        }
 }
@@ -1099,6 +1154,7 @@ rtmsg(cmd, flags)
        rtm.rtm_addrs = rtm_addrs;
        rtm.rtm_rmx = rt_metrics;
        rtm.rtm_inits = rtm_inits;
+       rtm.rtm_index = ifscope;
 
        if (rtm_addrs & RTA_NETMASK)
                mask_addr();
@@ -1144,10 +1200,10 @@ mask_addr()
        if ((rtm_addrs & RTA_DST) == 0)
                return;
        switch (so_dst.sa.sa_family) {
-#ifdef NS
-       case AF_NS:
-#endif
        case AF_INET:
+#ifdef INET6
+       case AF_INET6:
+#endif
        case AF_APPLETALK:
        case 0:
                return;
@@ -1186,10 +1242,11 @@ char metricnames[] =
 "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
 "\1mtu";
 char routeflags[] =
-"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
+"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010DELCLONE"
 "\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
-"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024CHAINDELETE"
-"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST";
+"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024b024"
+"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\031IFSCOPE\032CONDEMNED"
+"\033IFREF";
 char ifnetflags[] =
 "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
 "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
@@ -1238,8 +1295,15 @@ print_rtmsg(rtm, msglen)
                break;
 #endif
        default:
-               (void) printf("pid: %ld, seq %d, errno %d, flags:",
+               (void) printf("pid: %ld, seq %d, errno %d, ",
                        (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
+               if (rtm->rtm_flags & RTF_IFSCOPE)
+                       (void) printf("ifscope %d, ", rtm->rtm_index);
+#ifdef RTF_IFREF
+               if (rtm->rtm_flags & RTF_IFREF)
+                       (void) printf("ifref, ");
+#endif /* RTF_IFREF */
+               (void) printf("flags:");
                bprintf(stdout, rtm->rtm_flags, routeflags);
                pmsg_common(rtm);
        }
@@ -1318,16 +1382,16 @@ print_getmsg(rtm, msglen)
 
        (void) printf("\n%s\n", "\
  recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire");
-       printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
-       printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
-       printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
-       printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
-       printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
-       printf("%8ld%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
-       printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
+       printf("%8u%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
+       printf("%8u%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
+       printf("%8u%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
+       printf("%8u%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
+       printf("%8u%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
+       printf("%8u%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
+       printf("%8u%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
        if (rtm->rtm_rmx.rmx_expire)
                rtm->rtm_rmx.rmx_expire -= time(0);
-       printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
+       printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
 #undef lock
 #undef msec
 #define        RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
@@ -1360,8 +1424,10 @@ pmsg_addrs(cp, addrs)
        register struct sockaddr *sa;
        int i;
 
-       if (addrs == 0)
+       if (addrs == 0) {
+               (void) putchar('\n');
                return;
+       }
        (void) printf("\nsockaddrs: ");
        bprintf(stdout, addrs, addrnames);
        (void) putchar('\n');
@@ -1429,18 +1495,6 @@ sodump(su, which)
                (void) printf("%s: inet %s; ",
                    which, inet_ntoa(su->sin.sin_addr));
                break;
-#ifdef AT
-       case AF_APPLETALK:
-               (void) printf("%s: atalk %s; ",
-                   which, atalk_ntoa(su->sat.sat_addr));
-               break;
-#endif
-#ifdef NS
-       case AF_NS:
-               (void) printf("%s: xns %s; ",
-                   which, ns_ntoa(su->sns.sns_addr));
-               break;
-#endif
        }
        (void) fflush(stdout);
 }
@@ -1497,27 +1551,3 @@ sockaddr(addr, sa)
        } while (cp < cplim);
        sa->sa_len = cp - (char *)sa;
 }
-
-#ifdef AT
-int
-atalk_aton(const char *text, struct at_addr *addr)
-{
-       u_int net, node;
-
-       if (sscanf(text, "%u.%u", &net, &node) != 2
-           || net > 0xffff || node > 0xff)
-               return(0);
-       addr->s_net = htons(net);
-       addr->s_node = node;
-       return(1);
-}
-
-char *
-atalk_ntoa(struct at_addr at)
-{
-       static char buf[20];
-
-       (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node);
-       return(buf);
-}
-#endif