]> git.saurik.com Git - apple/network_cmds.git/blobdiff - netstat.tproj/route.c
network_cmds-596.100.2.tar.gz
[apple/network_cmds.git] / netstat.tproj / route.c
index 84b945a652c990d99ba237920fb4eae19070dc4b..6f727ad2fd4d49ca08f80b19e31ff348a070dcae 100644 (file)
@@ -1,25 +1,29 @@
 /*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2008-2017 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, 1988, 1993
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-#if 0
-static char sccsid[] = "From: @(#)route.c      8.6 (Berkeley) 4/28/95";
-#endif
-static const char rcsid[] =
-       "$Id: route.c,v 1.1.1.2 2000/01/11 01:48:53 wsanchez Exp $";
-#endif /* not lint */
-
+#include <stdint.h>
 #include <sys/param.h>
-#include <sys/protosw.h>
 #include <sys/socket.h>
 #include <sys/time.h>
 
@@ -72,20 +68,13 @@ static const char rcsid[] =
 #include <net/if_dl.h>
 #include <net/if_types.h>
 #include <net/route.h>
+#include <net/radix.h>
 
 #include <netinet/in.h>
 
-#ifdef IPX
-#include <netipx/ipx.h>
-#include <netatalk/at.h>
-#endif
-
-#ifdef NS
-#include <netns/ns.h>
-#endif
-
 #include <sys/sysctl.h>
 
+#include <arpa/inet.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -95,13 +84,16 @@ static const char rcsid[] =
 #include <time.h>
 #include "netstat.h"
 
-#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d)))
+/* alignment constraint for routing socket */
+#define ROUNDUP(a) \
+       ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
 
 /*
  * Definitions for showing gateway flags.
  */
 struct bits {
-       u_long  b_mask;
+       uint32_t        b_mask;
        char    b_val;
 } bits[] = {
        { RTF_UP,       'U' },
@@ -110,6 +102,7 @@ struct bits {
        { RTF_REJECT,   'R' },
        { RTF_DYNAMIC,  'D' },
        { RTF_MODIFIED, 'M' },
+       { RTF_MULTICAST,'m' },
        { RTF_DONE,     'd' }, /* Completed -- for routing messages only */
        { RTF_CLONING,  'C' },
        { RTF_XRESOLVE, 'X' },
@@ -122,82 +115,30 @@ struct bits {
        { RTF_PROTO3,   '3' },
        { RTF_BLACKHOLE,'B' },
        { RTF_BROADCAST,'b' },
+       { RTF_IFSCOPE,  'I' },
+       { RTF_IFREF,    'i' },
+       { RTF_PROXY,    'Y' },
+       { RTF_ROUTER,   'r' },
        { 0 }
 };
 
 typedef union {
-       long    dummy;          /* Helps align structure. */
+       uint32_t dummy;         /* Helps align structure. */
        struct  sockaddr u_sa;
        u_short u_data[128];
 } sa_u;
 
-static sa_u pt_u;
-
-int    do_rtent = 0;
-struct rtentry rtentry;
-struct radix_node rnode;
-struct radix_mask rmask;
-struct radix_node_head *rt_tables[AF_MAX+1];
-
-int    NewTree = 0;
-
-static struct sockaddr *kgetsa __P((struct sockaddr *));
-static void p_tree __P((struct radix_node *));
-static void p_rtnode __P((void));
-static void ntreestuff __P((void));
-static void np_rtentry __P((struct rt_msghdr *));
+static void np_rtentry __P((struct rt_msghdr2 *));
 static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int));
 static void p_flags __P((int, char *));
-static void p_rtentry __P((struct rtentry *));
-static u_long forgemask __P((u_long));
-static void domask __P((char *, u_long, u_long));
-
-/*
- * Print routing tables.
- */
-void
-routepr(rtree)
-       u_long rtree;
-{
-       struct radix_node_head *rnh, head;
-       int i;
-
-       printf("Routing tables\n");
-
-       if (Aflag == 0 && NewTree)
-               ntreestuff();
-       else {
-               if (rtree == 0) {
-                       printf("rt_tables: symbol not in namelist\n");
-                       return;
-               }
-
-               kget(rtree, rt_tables);
-               for (i = 0; i <= AF_MAX; i++) {
-                       if ((rnh = rt_tables[i]) == 0)
-                               continue;
-                       kget(rnh, head);
-                       if (i == AF_UNSPEC) {
-                               if (Aflag && af == 0) {
-                                       printf("Netmasks:\n");
-                                       p_tree(head.rnh_treetop);
-                               }
-                       } else if (af == AF_UNSPEC || af == i) {
-                               pr_family(i);
-                               do_rtent = 1;
-                               pr_rthdr();
-                               p_tree(head.rnh_treetop);
-                       }
-               }
-       }
-}
+static uint32_t forgemask __P((uint32_t));
+static void domask __P((char *, uint32_t, uint32_t));
 
 /*
  * Print address family header before a section of the routing table.
  */
 void
-pr_family(af)
-       int af;
+pr_family(int af)
 {
        char *afname;
 
@@ -205,27 +146,14 @@ pr_family(af)
        case AF_INET:
                afname = "Internet";
                break;
-
-#ifdef IPX
+#ifdef INET6
+       case AF_INET6:
+               afname = "Internet6";
+               break;
+#endif /*INET6*/
        case AF_IPX:
                afname = "IPX";
                break;
-#endif
-
-#ifdef NS
-       case AF_NS:
-               afname = "XNS";
-               break;
-#endif
-       case AF_ISO:
-               afname = "ISO";
-               break;
-       case AF_APPLETALK:
-               afname = "AppleTalk";
-               break;
-       case AF_CCITT:
-               afname = "X.25";
-               break;
        default:
                afname = NULL;
                break;
@@ -237,123 +165,79 @@ pr_family(af)
 }
 
 /* column widths; each followed by one space */
-#define        WID_DST         18      /* width of destination column */
-#define        WID_GW          18      /* width of gateway column */
+#ifndef INET6
+#define        WID_DST(af)     18      /* width of destination column */
+#define        WID_GW(af)      18      /* width of gateway column */
+#define        WID_RT_IFA(af)  18      /* width of source column */
+#define        WID_IF(af)      7       /* width of netif column */
+#else
+#define        WID_DST(af) \
+       ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39: 18)) : 18)
+#define        WID_GW(af) \
+       ((af) == AF_INET6 ? (lflag ? 31 : (nflag ? 31 : 18)) : 18)
+#define        WID_RT_IFA(af) \
+       ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39 : 18)) : 18)
+#define        WID_IF(af)      ((af) == AF_INET6 ? 8 : 7)
+#endif /*INET6*/
 
 /*
  * Print header for routing table columns.
  */
 void
-pr_rthdr()
-{
-       if (Aflag)
-               printf("%-8.8s ","Address");
-       printf("%-*.*s %-*.*s %-6.6s  %6.6s%8.8s  %8.8s %6s\n",
-               WID_DST, WID_DST, "Destination",
-               WID_GW, WID_GW, "Gateway",
-               "Flags", "Refs", "Use", "Netif", "Expire");
-}
-
-static struct sockaddr *
-kgetsa(dst)
-       register struct sockaddr *dst;
+pr_rthdr(int af)
 {
-
-       kget(dst, pt_u.u_sa);
-       if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa))
-               kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len);
-       return (&pt_u.u_sa);
-}
-
-static void
-p_tree(rn)
-       struct radix_node *rn;
-{
-
-again:
-       kget(rn, rnode);
-       if (rnode.rn_b < 0) {
-               if (Aflag)
-                       printf("%-8.8lx ", (u_long)rn);
-               if (rnode.rn_flags & RNF_ROOT) {
-                       if (Aflag)
-                               printf("(root node)%s",
-                                   rnode.rn_dupedkey ? " =>\n" : "\n");
-               } else if (do_rtent) {
-                       kget(rn, rtentry);
-                       p_rtentry(&rtentry);
-                       if (Aflag)
-                               p_rtnode();
-               } else {
-                       p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key),
-                                  NULL, 0, 44);
-                       putchar('\n');
-               }
-               if ((rn = rnode.rn_dupedkey))
-                       goto again;
-       } else {
-               if (Aflag && do_rtent) {
-                       printf("%-8.8lx ", (u_long)rn);
-                       p_rtnode();
-               }
-               rn = rnode.rn_r;
-               p_tree(rnode.rn_l);
-               p_tree(rn);
-       }
-}
-
-char   nbuf[20];
-
-static void
-p_rtnode()
-{
-       struct radix_mask *rm = rnode.rn_mklist;
-
-       if (rnode.rn_b < 0) {
-               if (rnode.rn_mask) {
-                       printf("\t  mask ");
-                       p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask),
-                                  NULL, 0, -1);
-               } else if (rm == 0)
-                       return;
-       } else {
-               sprintf(nbuf, "(%d)", rnode.rn_b);
-               printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long)rnode.rn_l, (u_long)rnode.rn_r);
-       }
-       while (rm) {
-               kget(rm, rmask);
-               sprintf(nbuf, " %d refs, ", rmask.rm_refs);
-               printf(" mk = %8.8lx {(%d),%s",
-                       (u_long)rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " ");
-               if (rmask.rm_flags & RNF_NORMAL) {
-                       struct radix_node rnode_aux;
-                       printf(" <normal>, ");
-                       kget(rmask.rm_leaf, rnode_aux);
-                       p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask),
-                                   NULL, 0, -1);
-               } else
-                   p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask),
-                               NULL, 0, -1);
-               putchar('}');
-               if ((rm = rmask.rm_mklist))
-                       printf(" ->");
+       if (lflag) {
+               if (lflag > 2)
+                       printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s "
+                               "%10s %10s %8s %8s %8s\n",
+                               WID_DST(af), WID_DST(af), "Destination",
+                               WID_GW(af), WID_GW(af), "Gateway",
+                               WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+                               "Flags", "Refs", "Use", "Mtu",
+                               WID_IF(af), WID_IF(af), "Netif", "Expire",
+                               "rtt(ms)", "rttvar(ms)", "recvpipe", "sendpipe", "ssthresh");
+               else if (lflag > 1)
+                       printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s "
+                               "%10s %10s\n",
+                               WID_DST(af), WID_DST(af), "Destination",
+                               WID_GW(af), WID_GW(af), "Gateway",
+                               WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+                               "Flags", "Refs", "Use", "Mtu",
+                               WID_IF(af), WID_IF(af), "Netif", "Expire",
+                               "rtt(ms)", "rttvar(ms)");
+               else
+                       printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s\n",
+                               WID_DST(af), WID_DST(af), "Destination",
+                               WID_GW(af), WID_GW(af), "Gateway",
+                               WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+                               "Flags", "Refs", "Use", "Mtu",
+                               WID_IF(af), WID_IF(af), "Netif", "Expire");
+    }  else {
+               printf("%-*.*s %-*.*s %-10.10s %*.*s %6s\n",
+                       WID_DST(af), WID_DST(af), "Destination",
+                       WID_GW(af), WID_GW(af), "Gateway",
+                       "Flags", WID_IF(af), WID_IF(af), "Netif", "Expire");
        }
-       putchar('\n');
 }
 
-static void
-ntreestuff()
+/*
+ * Print routing tables.
+ */
+void
+routepr(void)
 {
        size_t needed;
        int mib[6];
        char *buf, *next, *lim;
-       register struct rt_msghdr *rtm;
+       struct rt_msghdr2 *rtm;
+
+       printf("Routing tables\n");
 
        mib[0] = CTL_NET;
        mib[1] = PF_ROUTE;
        mib[2] = 0;
        mib[3] = 0;
-       mib[4] = NET_RT_DUMP;
+       mib[4] = NET_RT_DUMP2;
        mib[5] = 0;
        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
                err(1, "sysctl: net.route.0.0.dump estimate");
@@ -367,126 +251,200 @@ ntreestuff()
        }
        lim  = buf + needed;
        for (next = buf; next < lim; next += rtm->rtm_msglen) {
-               rtm = (struct rt_msghdr *)next;
+               rtm = (struct rt_msghdr2 *)next;
                np_rtentry(rtm);
        }
 }
 
 static void
-np_rtentry(rtm)
-       register struct rt_msghdr *rtm;
+get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+        int i;
+        
+        for (i = 0; i < RTAX_MAX; i++) {
+                if (addrs & (1 << i)) {
+                        rti_info[i] = sa;
+                                               sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
+               } else {
+                        rti_info[i] = NULL;
+        }
+}
+}
+
+static void
+np_rtentry(struct rt_msghdr2 *rtm)
 {
-       register struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
-#ifdef notdef
-       static int masks_done, banner_printed;
-#endif
-       static int old_af;
-       int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST;
-
-#ifdef notdef
-       /* for the moment, netmasks are skipped over */
-       if (!banner_printed) {
-               printf("Netmasks:\n");
-               banner_printed = 1;
+       struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
+       struct sockaddr *rti_info[RTAX_MAX];
+       static int old_fam;
+       int fam = 0;
+       u_short lastindex = 0xffff;
+       static char ifname[IFNAMSIZ + 1];
+       sa_u addr, mask;
+
+       /*
+        * Don't print protocol-cloned routes unless -a.
+        */
+       if ((rtm->rtm_flags & RTF_WASCLONED) &&
+           (rtm->rtm_parentflags & RTF_PRCLONING) &&
+           !aflag) {
+                       return;
        }
-       if (masks_done == 0) {
-               if (rtm->rtm_addrs != RTA_DST ) {
-                       masks_done = 1;
-                       af = sa->sa_family;
-               }
-       } else
-#endif
-               af = sa->sa_family;
-       if (af != old_af) {
-               pr_family(af);
-               old_af = af;
+
+       if (lflag > 1 && zflag != 0 && rtm->rtm_rmx.rmx_rtt == 0 && rtm->rtm_rmx.rmx_rttvar == 0)
+               return;
+       fam = sa->sa_family;
+       if (af != AF_UNSPEC && af != fam)
+               return;
+       if (fam != old_fam) {
+               pr_family(fam);
+               pr_rthdr(fam);
+               old_fam = fam;
        }
-       if (rtm->rtm_addrs == RTA_DST)
-               p_sockaddr(sa, NULL, 0, 36);
-       else {
-               p_sockaddr(sa, NULL, rtm->rtm_flags, 16);
-               if (sa->sa_len == 0)
-                       sa->sa_len = sizeof(long);
-               sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
-               p_sockaddr(sa, NULL, 0, 18);
+       get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+       bzero(&addr, sizeof(addr));
+       if ((rtm->rtm_addrs & RTA_DST))
+               bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len);
+       bzero(&mask, sizeof(mask));
+       if ((rtm->rtm_addrs & RTA_NETMASK))
+               bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len);
+       p_sockaddr(&addr.u_sa, &mask.u_sa, rtm->rtm_flags,
+           WID_DST(addr.u_sa.sa_family));
+
+       p_sockaddr(rti_info[RTAX_GATEWAY], NULL, RTF_HOST,
+           WID_GW(addr.u_sa.sa_family));
+
+       if (lflag && (rtm->rtm_addrs & RTA_IFA)) {
+               p_sockaddr(rti_info[RTAX_IFA], NULL, RTF_HOST,
+                   WID_RT_IFA(addr.u_sa.sa_family));
+       }
+       
+       p_flags(rtm->rtm_flags, "%-10.10s ");
+
+       if (lflag) {
+               printf("%6u %8u ", rtm->rtm_refcnt, (unsigned int)rtm->rtm_use);
+               if (rtm->rtm_rmx.rmx_mtu != 0)
+                       printf("%6u ", rtm->rtm_rmx.rmx_mtu);
+               else
+                       printf("%6s ", "");
+       }
+
+       if (rtm->rtm_index != lastindex) {
+               if_indextoname(rtm->rtm_index, ifname);
+               lastindex = rtm->rtm_index;
+       }
+       printf("%*.*s", WID_IF(addr.u_sa.sa_family),
+               WID_IF(addr.u_sa.sa_family), ifname);
+
+       if (rtm->rtm_rmx.rmx_expire) {
+               time_t expire_time;
+
+               if ((expire_time =
+                       rtm->rtm_rmx.rmx_expire - time((time_t *)0)) > 0)
+                       printf(" %6d", (int)expire_time);
+               else
+                       printf(" %6s", "!");
+       } else {
+               printf(" %6s", "");
+       }
+       if (lflag > 1) {
+               if (rtm->rtm_rmx.rmx_rtt != 0)
+                       printf(" %6u.%03u", rtm->rtm_rmx.rmx_rtt / 1000,
+                              rtm->rtm_rmx.rmx_rtt % 1000);
+               else
+                       printf(" %10s", "");
+               if (rtm->rtm_rmx.rmx_rttvar != 0)
+                       printf(" %6u.%03u", rtm->rtm_rmx.rmx_rttvar / 1000,
+                              rtm->rtm_rmx.rmx_rttvar % 1000);
+               else
+                       printf(" %10s", "");
+               if (lflag > 2) {
+                       if (rtm->rtm_rmx.rmx_recvpipe != 0)
+                               printf(" %8u", rtm->rtm_rmx.rmx_recvpipe);
+                       else
+                               printf(" %8s", "");
+                       if (rtm->rtm_rmx.rmx_sendpipe != 0)
+                               printf(" %8u", rtm->rtm_rmx.rmx_sendpipe);
+                       else
+                               printf(" %8s", "");
+                       if (rtm->rtm_rmx.rmx_ssthresh != 0)
+                               printf(" %8u", rtm->rtm_rmx.rmx_ssthresh);
+                       else
+                               printf(" %8s", "");
+               }
        }
-       p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
        putchar('\n');
 }
 
 static void
-p_sockaddr(sa, mask, flags, width)
-       struct sockaddr *sa, *mask;
-       int flags, width;
+p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width)
 {
        char workbuf[128], *cplim;
-       register char *cp = workbuf;
+       char *cp = workbuf;
 
        switch(sa->sa_family) {
-       case AF_INET:
-           {
-               register struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+       case AF_INET: {
+               struct sockaddr_in *sin = (struct sockaddr_in *)sa;
 
-               if (sin->sin_addr.s_addr == INADDR_ANY)
-                       cp = "default";
+               if ((sin->sin_addr.s_addr == INADDR_ANY) &&
+                       mask &&
+                   (ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) == 0L || mask->sa_len == 0))
+                               cp = "default" ;
                else if (flags & RTF_HOST)
                        cp = routename(sin->sin_addr.s_addr);
                else if (mask)
                        cp = netname(sin->sin_addr.s_addr,
-                                    ntohl(((struct sockaddr_in *)mask)
-                                          ->sin_addr.s_addr));
+                           ntohl(((struct sockaddr_in *)mask)->
+                           sin_addr.s_addr));
                else
                        cp = netname(sin->sin_addr.s_addr, 0L);
                break;
            }
-#ifdef IPX
-       case AF_IPX:
-           {
-               struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
-               if (ipx_nullnet(satoipx_addr(work)))
-                       cp = "default";
-               else
-                       cp = ipx_print(sa);
-               break;
-           }
-#endif
 
-#if 0
-       case AF_APPLETALK:
-           {
-               if (!(flags & RTF_HOST) && mask)
-                       cp = atalk_print2(sa,mask,9);
+#ifdef INET6
+       case AF_INET6: {
+               struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
+               struct in6_addr *in6 = &sa6->sin6_addr;
+
+               /*
+                * XXX: This is a special workaround for KAME kernels.
+                * sin6_scope_id field of SA should be set in the future.
+                */
+               if (IN6_IS_ADDR_LINKLOCAL(in6) ||
+                   IN6_IS_ADDR_MC_NODELOCAL(in6) ||
+                   IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
+                   /* XXX: override is ok? */
+                   sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
+                   *(u_short *)&in6->s6_addr[2] = 0;
+               }
+
+               if (flags & RTF_HOST)
+                   cp = routename6(sa6);
+               else if (mask)
+                   cp = netname6(sa6, mask);
                else
-                       cp = atalk_print(sa,11);
+                   cp = netname6(sa6, NULL);
                break;
            }
-#endif
+#endif /*INET6*/
 
-#ifdef NS
-       case AF_NS:
-               cp = ns_print(sa);
-               break;
-#endif
-
-       case AF_LINK:
-           {
-               register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
+       case AF_LINK: {
+               struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
 
                if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
-                   sdl->sdl_slen == 0)
-                       (void) sprintf(workbuf, "link#%d", sdl->sdl_index);
-               else
+                   sdl->sdl_slen == 0) {
+                       (void) snprintf(workbuf, sizeof(workbuf), "link#%d", sdl->sdl_index);
+               } else {
                        switch (sdl->sdl_type) {
 
-                       case IFT_ETHER:
-                           {
-                               register int i;
-                               register u_char *lla = (u_char *)sdl->sdl_data +
+                       case IFT_ETHER: {
+                               int i;
+                               u_char *lla = (u_char *)sdl->sdl_data +
                                    sdl->sdl_nlen;
 
                                cplim = "";
                                for (i = 0; i < sdl->sdl_alen; i++, lla++) {
-                                       cp += sprintf(cp, "%s%x", cplim, *lla);
+                                       cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%s%x", cplim, *lla);
                                        cplim = ":";
                                }
                                cp = workbuf;
@@ -497,27 +455,27 @@ p_sockaddr(sa, mask, flags, width)
                                cp = link_ntoa(sdl);
                                break;
                        }
+               }
                break;
            }
 
-       default:
-           {
-               register u_char *s = (u_char *)sa->sa_data, *slim;
+       default: {
+               u_char *s = (u_char *)sa->sa_data, *slim;
 
                slim =  sa->sa_len + (u_char *) sa;
                cplim = cp + sizeof(workbuf) - 6;
-               cp += sprintf(cp, "(%d)", sa->sa_family);
+               cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "(%d)", sa->sa_family);
                while (s < slim && cp < cplim) {
-                       cp += sprintf(cp, " %02x", *s++);
+                       cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), " %02x", *s++);
                        if (s < slim)
-                           cp += sprintf(cp, "%02x", *s++);
+                           cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%02x", *s++);
                }
                cp = workbuf;
            }
        }
-       if (width < 0 )
+       if (width < 0 ) {
                printf("%s ", cp);
-       else {
+       else {
                if (nflag)
                        printf("%-*s ", width, cp);
                else
@@ -526,12 +484,10 @@ p_sockaddr(sa, mask, flags, width)
 }
 
 static void
-p_flags(f, format)
-       register int f;
-       char *format;
+p_flags(int f, char *format)
 {
        char name[33], *flags;
-       register struct bits *p = bits;
+       struct bits *p = bits;
 
        for (flags = name; p->b_mask; p++)
                if (p->b_mask & f)
@@ -540,62 +496,11 @@ p_flags(f, format)
        printf(format, name);
 }
 
-static void
-p_rtentry(rt)
-       register struct rtentry *rt;
-{
-       static struct ifnet ifnet, *lastif;
-       static char name[16];
-       static char prettyname[9];
-       struct sockaddr *sa;
-       sa_u addr, mask;
-
-       /*
-        * Don't print protocol-cloned routes unless -a.
-        */
-       if (rt->rt_parent && !aflag)
-               return;
-
-       bzero(&addr, sizeof(addr));
-       if ((sa = kgetsa(rt_key(rt))))
-               bcopy(sa, &addr, sa->sa_len);
-       bzero(&mask, sizeof(mask));
-       if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt))))
-               bcopy(sa, &mask, sa->sa_len);
-       p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, WID_DST);
-       p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, WID_GW);
-       p_flags(rt->rt_flags, "%-6.6s ");
-       printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use);
-       if (rt->rt_ifp) {
-               if (rt->rt_ifp != lastif) {
-                       kget(rt->rt_ifp, ifnet);
-                       kread((u_long)ifnet.if_name, name, 16);
-                       lastif = rt->rt_ifp;
-                       snprintf(prettyname, sizeof prettyname,
-                                "%.6s%d", name, ifnet.if_unit);
-               }
-               printf("%8.8s", prettyname);
-               if (rt->rt_rmx.rmx_expire) {
-                       time_t expire_time;
-
-                       if ((expire_time =
-                           rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0)
-                               printf(" %6d%s", (int)expire_time,
-                                   rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
-               } else if (rt->rt_nodes[0].rn_dupedkey) {
-                       printf(" =>");
-               }
-
-       }
-       putchar('\n');
-}
-
 char *
-routename(in)
-       u_long in;
+routename(uint32_t in)
 {
-       register char *cp;
-       static char line[MAXHOSTNAMELEN + 1];
+       char *cp;
+       static char line[MAXHOSTNAMELEN];
        struct hostent *hp;
 
        cp = 0;
@@ -604,26 +509,24 @@ routename(in)
                        AF_INET);
                if (hp) {
                        cp = hp->h_name;
-                       trimdomain(cp);
+                        //### trimdomain(cp, strlen(cp));
                }
        }
        if (cp) {
-               strncpy(line, cp, sizeof(line) - 1);
-               line[sizeof(line) - 1] = '\0';
+               strlcpy(line, cp, sizeof(line));
        } else {
 #define C(x)   ((x) & 0xff)
                in = ntohl(in);
-               sprintf(line, "%lu.%lu.%lu.%lu",
+               snprintf(line, sizeof(line), "%u.%u.%u.%u",
                    C(in >> 24), C(in >> 16), C(in >> 8), C(in));
        }
        return (line);
 }
 
-static u_long
-forgemask(a)
-       u_long a;
+static uint32_t
+forgemask(uint32_t a)
 {
-       u_long m;
+       uint32_t m;
 
        if (IN_CLASSA(a))
                m = IN_CLASSA_NET;
@@ -635,11 +538,9 @@ forgemask(a)
 }
 
 static void
-domask(dst, addr, mask)
-       char *dst;
-       u_long addr, mask;
+domask(char *dst, uint32_t addr, uint32_t mask)
 {
-       register int b, i;
+       int b, i;
 
        if (!mask || (forgemask(addr) == mask)) {
                *dst = '\0';
@@ -648,7 +549,7 @@ domask(dst, addr, mask)
        i = 0;
        for (b = 0; b < 32; b++)
                if (mask & (1 << b)) {
-                       register int bb;
+                       int bb;
 
                        i = b;
                        for (bb = b+1; bb < 32; bb++)
@@ -659,9 +560,9 @@ domask(dst, addr, mask)
                        break;
                }
        if (i == -1)
-               sprintf(dst, "&0x%lx", mask);
+               snprintf(dst, sizeof(dst), "&0x%x", mask);
        else
-               sprintf(dst, "/%d", 32-i);
+               snprintf(dst, sizeof(dst), "/%d", 32-i);
 }
 
 /*
@@ -669,239 +570,200 @@ domask(dst, addr, mask)
  * The address is assumed to be that of a net or subnet, not a host.
  */
 char *
-netname(in, mask)
-       u_long in, mask;
+netname(uint32_t in, uint32_t mask)
 {
        char *cp = 0;
-       static char line[MAXHOSTNAMELEN + 1];
+       static char line[MAXHOSTNAMELEN];
        struct netent *np = 0;
-       u_long net, omask, dmask;
-       register u_long i;
+       uint32_t net, omask, dmask;
+       uint32_t i;
 
        i = ntohl(in);
+       dmask = forgemask(i);
        omask = mask;
        if (!nflag && i) {
-               dmask = forgemask(i);
                net = i & dmask;
                if (!(np = getnetbyaddr(i, AF_INET)) && net != i)
                        np = getnetbyaddr(net, AF_INET);
                if (np) {
                        cp = np->n_name;
-                       trimdomain(cp);
+                        //### trimdomain(cp, strlen(cp));
                }
        }
        if (cp)
-               strncpy(line, cp, sizeof(line) - 1);
-       else if ((i & 0xffffff) == 0)
-               sprintf(line, "%lu", C(i >> 24));
-       else if ((i & 0xffff) == 0)
-               sprintf(line, "%lu.%lu", C(i >> 24) , C(i >> 16));
-       else if ((i & 0xff) == 0)
-               sprintf(line, "%lu.%lu.%lu", C(i >> 24), C(i >> 16), C(i >> 8));
-       else
-               sprintf(line, "%lu.%lu.%lu.%lu", C(i >> 24),
-                       C(i >> 16), C(i >> 8), C(i));
+               strlcpy(line, cp, sizeof(line));
+       else {
+               switch (dmask) {
+               case IN_CLASSA_NET:
+                       if ((i & IN_CLASSA_HOST) == 0) {
+                               snprintf(line, sizeof(line), "%u", C(i >> 24));
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               case IN_CLASSB_NET:
+                       if ((i & IN_CLASSB_HOST) == 0) {
+                               snprintf(line, sizeof(line), "%u.%u",
+                                       C(i >> 24), C(i >> 16));
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               case IN_CLASSC_NET:
+                       if ((i & IN_CLASSC_HOST) == 0) {
+                               snprintf(line, sizeof(line), "%u.%u.%u",
+                                       C(i >> 24), C(i >> 16), C(i >> 8));
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               default:
+                       snprintf(line, sizeof(line), "%u.%u.%u.%u",
+                               C(i >> 24), C(i >> 16), C(i >> 8), C(i));
+                       break;
+               }
+       }
        domask(line+strlen(line), i, omask);
        return (line);
 }
 
-/*
- * Print routing statistics
- */
-void
-rt_stats(off)
-       u_long off;
-{
-       struct rtstat rtstat;
-
-       if (off == 0) {
-               printf("rtstat: symbol not in namelist\n");
-               return;
-       }
-       kread(off, (char *)&rtstat, sizeof (rtstat));
-       printf("routing:\n");
-       printf("\t%u bad routing redirect%s\n",
-               rtstat.rts_badredirect, plural(rtstat.rts_badredirect));
-       printf("\t%u dynamically created route%s\n",
-               rtstat.rts_dynamic, plural(rtstat.rts_dynamic));
-       printf("\t%u new gateway%s due to redirects\n",
-               rtstat.rts_newgateway, plural(rtstat.rts_newgateway));
-       printf("\t%u destination%s found unreachable\n",
-               rtstat.rts_unreach, plural(rtstat.rts_unreach));
-       printf("\t%u use%s of a wildcard route\n",
-               rtstat.rts_wildcard, plural(rtstat.rts_wildcard));
-}
-
-#ifdef IPX
-
+#ifdef INET6
 char *
-ipx_print(sa)
-       register struct sockaddr *sa;
+netname6(struct sockaddr_in6 *sa6, struct sockaddr *sam)
 {
-       u_short port;
-       struct servent *sp = 0;
-       char *net = "", *host = "";
-       register char *p;
-       register u_char *q;
-       struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
-       static char mybuf[50];
-       char cport[10], chost[15], cnet[15];
-
-       port = ntohs(work.x_port);
-
-       if (ipx_nullnet(work) && ipx_nullhost(work)) {
-
-               if (port) {
-                       if (sp)
-                               sprintf(mybuf, "*.%s", sp->s_name);
-                       else
-                               sprintf(mybuf, "*.%x", port);
-               } else
-                       sprintf(mybuf, "*.*");
-
-               return (mybuf);
+       static char line[MAXHOSTNAMELEN];
+       u_char *lim;
+       int masklen, illegal = 0, flag = NI_WITHSCOPEID;
+       struct in6_addr *mask = sam ? &((struct sockaddr_in6 *)sam)->sin6_addr : 0;
+
+       if (sam && sam->sa_len == 0) {
+               masklen = 0;
+       } else if (mask) {
+               u_char *p = (u_char *)mask;
+               for (masklen = 0, lim = p + 16; p < lim; p++) {
+                       switch (*p) {
+                        case 0xff:
+                                masklen += 8;
+                                break;
+                        case 0xfe:
+                                masklen += 7;
+                                break;
+                        case 0xfc:
+                                masklen += 6;
+                                break;
+                        case 0xf8:
+                                masklen += 5;
+                                break;
+                        case 0xf0:
+                                masklen += 4;
+                                break;
+                        case 0xe0:
+                                masklen += 3;
+                                break;
+                        case 0xc0:
+                                masklen += 2;
+                                break;
+                        case 0x80:
+                                masklen += 1;
+                                break;
+                        case 0x00:
+                                break;
+                        default:
+                                illegal ++;
+                                break;
+                       }
+               }
+               if (illegal)
+                       fprintf(stderr, "illegal prefixlen\n");
+       } else {
+               masklen = 128;
        }
+       if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
+               return("default");
 
-       if (ipx_wildnet(work))
-               net = "any";
-       else if (ipx_nullnet(work))
-               net = "*";
-       else {
-               q = work.x_net.c_net;
-               sprintf(cnet, "%02x%02x%02x%02x",
-                       q[0], q[1], q[2], q[3]);
-               for (p = cnet; *p == '0' && p < cnet + 8; p++)
-                       continue;
-               net = p;
-       }
+       if (nflag)
+               flag |= NI_NUMERICHOST;
+       getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line),
+                   NULL, 0, flag);
 
-       if (ipx_wildhost(work))
-               host = "any";
-       else if (ipx_nullhost(work))
-               host = "*";
-       else {
-               q = work.x_host.c_host;
-               sprintf(chost, "%02x%02x%02x%02x%02x%02x",
-                       q[0], q[1], q[2], q[3], q[4], q[5]);
-               for (p = chost; *p == '0' && p < chost + 12; p++)
-                       continue;
-               host = p;
-       }
+       if (nflag)
+               snprintf(&line[strlen(line)], sizeof(line) - strlen(line), "/%d", masklen);
 
-       if (port) {
-               if (strcmp(host, "*") == 0)
-                       host = "";
-               if (sp) 
-                       snprintf(cport, sizeof(cport),
-                               "%s%s", *host ? "." : "", sp->s_name);
-               else    
-                       snprintf(cport, sizeof(cport),
-                               "%s%x", *host ? "." : "", port);
-       } else
-               *cport = 0;
-
-       snprintf(mybuf, sizeof(mybuf), "%s.%s%s", net, host, cport);
-       return(mybuf);
+       return line;
 }
 
 char *
-ipx_phost(sa)
-       struct sockaddr *sa;
+routename6(struct sockaddr_in6 *sa6)
 {
-       register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa;
-       struct sockaddr_ipx work;
-       static union ipx_net ipx_zeronet;
-       char *p;
-       struct ipx_addr in;
+       static char line[MAXHOSTNAMELEN];
+       int flag = NI_WITHSCOPEID;
+       /* use local variable for safety */
+       struct sockaddr_in6 sa6_local = {sizeof(sa6_local), AF_INET6, };
 
-       work = *sipx;
-       in = work.sipx_addr;
+       sa6_local.sin6_addr = sa6->sin6_addr;
+       sa6_local.sin6_scope_id = sa6->sin6_scope_id;
 
-       work.sipx_addr.x_port = 0;
-       work.sipx_addr.x_net = ipx_zeronet;
-       p = ipx_print((struct sockaddr *)&work);
-       if (strncmp("*.", p, 2) == 0) p += 2;
+       if (nflag)
+               flag |= NI_NUMERICHOST;
 
-       return(p);
-}
-#endif
+       getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len,
+                   line, sizeof(line), NULL, 0, flag);
 
-#ifdef NS
-short ns_nullh[] = {0,0,0};
-short ns_bh[] = {-1,-1,-1};
+       return line;
+}
+#endif /*INET6*/
 
-char *
-ns_print(sa)
-       register struct sockaddr *sa;
+/*
+ * Print routing statistics
+ */
+void
+rt_stats(void)
 {
-       register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa;
-       struct ns_addr work;
-       union { union ns_net net_e; u_long long_e; } net;
-       u_short port;
-       static char mybuf[50], 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 ) {
-                       sprintf(mybuf, "*.%xH", port);
-                       upHex(mybuf);
-               } else
-                       sprintf(mybuf, "*.*");
-               return (mybuf);
-       }
+       struct rtstat rtstat;
+       int rttrash;
+       int mib[6];
+       size_t len;
 
-       if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) {
-               host = "any";
-       } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) {
-               host = "*";
-       } else {
-               q = work.x_host.c_host;
-               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++)
-                       continue;
-               host = p;
-       }
-       if (port)
-               sprintf(cport, ".%xH", htons(port));
-       else
-               *cport = 0;
+       mib[0] = CTL_NET;
+       mib[1] = AF_ROUTE;
+       mib[2] = 0;
+       mib[3] = 0;
+       mib[4] = NET_RT_STAT;
+       mib[5] = 0;
+       len = sizeof(struct rtstat);
+       if (sysctl(mib, 6, &rtstat, &len, 0, 0) == -1)
+               return;
+               
+       mib[0] = CTL_NET;
+       mib[1] = AF_ROUTE;
+       mib[2] = 0;
+       mib[3] = 0;
+       mib[4] = NET_RT_TRASH;
+       mib[5] = 0;
+       len = sizeof(rttrash);
+       if (sysctl(mib, 6, &rttrash, &len, 0, 0) == -1)
+               return;
 
-       sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport);
-       upHex(mybuf);
-       return(mybuf);
-}
+       printf("routing:\n");
 
-char *
-ns_phost(sa)
-       struct sockaddr *sa;
-{
-       register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa;
-       struct sockaddr_ns work;
-       static union ns_net ns_zeronet;
-       char *p;
-
-       work = *sns;
-       work.sns_addr.x_port = 0;
-       work.sns_addr.x_net = ns_zeronet;
-
-       p = ns_print((struct sockaddr *)&work);
-       if (strncmp("0H.", p, 3) == 0)
-               p += 3;
-       return(p);
+#define        p(f, m) if (rtstat.f || sflag <= 1) \
+       printf(m, rtstat.f, plural(rtstat.f))
+
+       p(rts_badredirect, "\t%u bad routing redirect%s\n");
+       p(rts_dynamic, "\t%u dynamically created route%s\n");
+       p(rts_newgateway, "\t%u new gateway%s due to redirects\n");
+       p(rts_unreach, "\t%u destination%s found unreachable\n");
+       p(rts_wildcard, "\t%u use%s of a wildcard route\n");
+       p(rts_badrtgwroute, "\t%u lookup%s returned indirect "
+           "routes pointing to indirect gateway route\n");
+#undef p
+
+       if (rttrash || sflag <= 1)
+               printf("\t%u route%s not in table but not freed\n",
+                   rttrash, plural(rttrash));
 }
-#endif
 
 void
-upHex(p0)
-       char *p0;
+upHex(char *p0)
 {
-       register char *p = p0;
+       char *p = p0;
 
        for (; *p; p++)
                switch (*p) {