route.c revision 83200
1133808Spjd/* 2133808Spjd * Copyright (c) 1983, 1988, 1993 3133808Spjd * The Regents of the University of California. All rights reserved. 4133808Spjd * 5133808Spjd * Redistribution and use in source and binary forms, with or without 6133808Spjd * modification, are permitted provided that the following conditions 7133808Spjd * are met: 8133808Spjd * 1. Redistributions of source code must retain the above copyright 9133808Spjd * notice, this list of conditions and the following disclaimer. 10133808Spjd * 2. Redistributions in binary form must reproduce the above copyright 11133808Spjd * notice, this list of conditions and the following disclaimer in the 12133808Spjd * documentation and/or other materials provided with the distribution. 13133808Spjd * 3. All advertising materials mentioning features or use of this software 14133808Spjd * must display the following acknowledgement: 15133808Spjd * This product includes software developed by the University of 16133808Spjd * California, Berkeley and its contributors. 17133808Spjd * 4. Neither the name of the University nor the names of its contributors 18133808Spjd * may be used to endorse or promote products derived from this software 19133808Spjd * without specific prior written permission. 20133808Spjd * 21133808Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22133808Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23133808Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24133808Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25133808Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26133808Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27133808Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28133808Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29133808Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30133808Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31133808Spjd * SUCH DAMAGE. 32133808Spjd */ 33133808Spjd 34133808Spjd#ifndef lint 35133808Spjd#if 0 36133808Spjdstatic char sccsid[] = "From: @(#)route.c 8.6 (Berkeley) 4/28/95"; 37133808Spjd#endif 38133808Spjdstatic const char rcsid[] = 39133808Spjd "$FreeBSD: head/usr.bin/netstat/route.c 83200 2001-09-07 12:00:50Z ru $"; 40137257Spjd#endif /* not lint */ 41133808Spjd 42133808Spjd#include <sys/param.h> 43133808Spjd#include <sys/protosw.h> 44133808Spjd#include <sys/socket.h> 45133808Spjd#include <sys/time.h> 46133808Spjd 47133808Spjd#include <net/if.h> 48133808Spjd#include <net/if_var.h> 49133808Spjd#include <net/if_dl.h> 50133808Spjd#include <net/if_types.h> 51133808Spjd#include <net/route.h> 52133808Spjd 53133825Spjd#include <netinet/in.h> 54134528Spjd#include <netipx/ipx.h> 55133808Spjd#include <netatalk/at.h> 56133808Spjd#include <netgraph/ng_socket.h> 57135866Spjd 58137258Spjd#ifdef NS 59133808Spjd#include <netns/ns.h> 60133808Spjd#endif 61137258Spjd 62137258Spjd#include <sys/sysctl.h> 63137258Spjd 64137258Spjd#include <arpa/inet.h> 65133808Spjd#include <libutil.h> 66133808Spjd#include <netdb.h> 67133808Spjd#include <stdio.h> 68133808Spjd#include <stdlib.h> 69133808Spjd#include <string.h> 70133808Spjd#include <unistd.h> 71133808Spjd#include <err.h> 72133808Spjd#include <time.h> 73133808Spjd#include "netstat.h" 74133808Spjd 75133808Spjd#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d))) 76133808Spjd 77133808Spjd 78133808Spjd/* alignment constraint for routing socket */ 79133808Spjd#define ROUNDUP(a) \ 80133808Spjd ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 81133808Spjd#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 82133808Spjd 83133808Spjd/* 84133808Spjd * Definitions for showing gateway flags. 85133808Spjd */ 86133808Spjdstruct bits { 87133808Spjd u_long b_mask; 88133808Spjd char b_val; 89134168Spjd} bits[] = { 90134168Spjd { RTF_UP, 'U' }, 91134168Spjd { RTF_GATEWAY, 'G' }, 92133808Spjd { RTF_HOST, 'H' }, 93133808Spjd { RTF_REJECT, 'R' }, 94133808Spjd { RTF_DYNAMIC, 'D' }, 95133808Spjd { RTF_MODIFIED, 'M' }, 96133808Spjd { RTF_DONE, 'd' }, /* Completed -- for routing messages only */ 97133808Spjd { RTF_CLONING, 'C' }, 98133808Spjd { RTF_XRESOLVE, 'X' }, 99133808Spjd { RTF_LLINFO, 'L' }, 100133808Spjd { RTF_STATIC, 'S' }, 101133808Spjd { RTF_PROTO1, '1' }, 102133808Spjd { RTF_PROTO2, '2' }, 103133808Spjd { RTF_WASCLONED,'W' }, 104133808Spjd { RTF_PRCLONING,'c' }, 105133808Spjd { RTF_PROTO3, '3' }, 106133808Spjd { RTF_BLACKHOLE,'B' }, 107133808Spjd { RTF_BROADCAST,'b' }, 108133808Spjd { 0 } 109133808Spjd}; 110133808Spjd 111133808Spjdtypedef union { 112133808Spjd long dummy; /* Helps align structure. */ 113133808Spjd struct sockaddr u_sa; 114133808Spjd u_short u_data[128]; 115133808Spjd} sa_u; 116133808Spjd 117137257Spjdstatic sa_u pt_u; 118133808Spjd 119133808Spjdint do_rtent = 0; 120133808Spjdstruct rtentry rtentry; 121133808Spjdstruct radix_node rnode; 122137257Spjdstruct radix_mask rmask; 123137257Spjdstruct radix_node_head *rt_tables[AF_MAX+1]; 124133808Spjd 125133808Spjdint NewTree = 0; 126133808Spjd 127133808Spjdstatic struct sockaddr *kgetsa (struct sockaddr *); 128133808Spjdstatic void p_tree (struct radix_node *); 129133808Spjdstatic void p_rtnode (void); 130137257Spjdstatic void ntreestuff (void); 131137257Spjdstatic void np_rtentry (struct rt_msghdr *); 132137257Spjdstatic void p_sockaddr (struct sockaddr *, struct sockaddr *, int, int); 133133808Spjdstatic void p_flags (int, char *); 134133808Spjdstatic void p_rtentry (struct rtentry *); 135133808Spjdstatic u_long forgemask (u_long); 136133808Spjdstatic void domask (char *, u_long, u_long); 137139144Spjd 138139144Spjd/* 139133808Spjd * Print routing tables. 140133808Spjd */ 141133808Spjdvoid 142133808Spjdroutepr(u_long rtree) 143133808Spjd{ 144133808Spjd struct radix_node_head *rnh, head; 145133808Spjd int i; 146133808Spjd 147133808Spjd printf("Routing tables\n"); 148133808Spjd 149133808Spjd if (Aflag == 0 && NewTree) 150133808Spjd ntreestuff(); 151133808Spjd else { 152133808Spjd if (rtree == 0) { 153133808Spjd printf("rt_tables: symbol not in namelist\n"); 154133808Spjd return; 155133808Spjd } 156133808Spjd 157133808Spjd kget(rtree, rt_tables); 158133808Spjd for (i = 0; i <= AF_MAX; i++) { 159133808Spjd if ((rnh = rt_tables[i]) == 0) 160133808Spjd continue; 161133808Spjd kget(rnh, head); 162133808Spjd if (i == AF_UNSPEC) { 163133808Spjd if (Aflag && af == 0) { 164133808Spjd printf("Netmasks:\n"); 165133808Spjd p_tree(head.rnh_treetop); 166133808Spjd } 167133808Spjd } else if (af == AF_UNSPEC || af == i) { 168133808Spjd pr_family(i); 169133808Spjd do_rtent = 1; 170133808Spjd pr_rthdr(i); 171133808Spjd p_tree(head.rnh_treetop); 172133808Spjd } 173133808Spjd } 174133808Spjd } 175133808Spjd} 176133808Spjd 177133808Spjd/* 178133808Spjd * Print address family header before a section of the routing table. 179133808Spjd */ 180133808Spjdvoid 181133808Spjdpr_family(int af) 182133808Spjd{ 183133808Spjd char *afname; 184133808Spjd 185133808Spjd switch (af) { 186133808Spjd case AF_INET: 187133808Spjd afname = "Internet"; 188133808Spjd break; 189133808Spjd#ifdef INET6 190133808Spjd case AF_INET6: 191133808Spjd afname = "Internet6"; 192133808Spjd break; 193133808Spjd#endif /*INET6*/ 194133808Spjd case AF_IPX: 195133808Spjd afname = "IPX"; 196133808Spjd break; 197133808Spjd#ifdef NS 198133808Spjd case AF_NS: 199133808Spjd afname = "XNS"; 200133808Spjd break; 201133808Spjd#endif 202133808Spjd case AF_ISO: 203133808Spjd afname = "ISO"; 204133808Spjd break; 205133808Spjd case AF_APPLETALK: 206133808Spjd afname = "AppleTalk"; 207133808Spjd break; 208133808Spjd case AF_CCITT: 209133808Spjd afname = "X.25"; 210133808Spjd break; 211133808Spjd case AF_NETGRAPH: 212133808Spjd afname = "Netgraph"; 213133808Spjd break; 214133808Spjd default: 215133808Spjd afname = NULL; 216133808Spjd break; 217133808Spjd } 218133808Spjd if (afname) 219133808Spjd printf("\n%s:\n", afname); 220133808Spjd else 221134168Spjd printf("\nProtocol Family %d:\n", af); 222134168Spjd} 223134168Spjd 224134168Spjd/* column widths; each followed by one space */ 225134168Spjd#ifndef INET6 226134168Spjd#define WID_DST(af) 18 /* width of destination column */ 227134168Spjd#define WID_GW(af) 18 /* width of gateway column */ 228134168Spjd#define WID_IF(af) 6 /* width of netif column */ 229134168Spjd#else 230134168Spjd#define WID_DST(af) \ 231134168Spjd ((af) == AF_INET6 ? (Wflag ? 39 : (numeric_addr ? 33: 18)) : 18) 232134168Spjd#define WID_GW(af) \ 233134168Spjd ((af) == AF_INET6 ? (Wflag ? 31 : (numeric_addr ? 29 : 18)) : 18) 234134168Spjd#define WID_IF(af) ((af) == AF_INET6 ? 8 : 6) 235134168Spjd#endif /*INET6*/ 236134168Spjd 237134168Spjd/* 238134168Spjd * Print header for routing table columns. 239133808Spjd */ 240133808Spjdvoid 241133808Spjdpr_rthdr(int af) 242133808Spjd{ 243133808Spjd 244133808Spjd if (Aflag) 245133808Spjd printf("%-8.8s ","Address"); 246133808Spjd if (af == AF_INET || Wflag) 247133808Spjd if (Wflag) 248133808Spjd printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %6.6s %*.*s %6s\n", 249133808Spjd WID_DST(af), WID_DST(af), "Destination", 250133808Spjd WID_GW(af), WID_GW(af), "Gateway", 251133808Spjd "Flags", "Refs", "Use", "Mtu", 252133808Spjd WID_IF(af), WID_IF(af), "Netif", "Expire"); 253133808Spjd else 254133808Spjd printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %*.*s %6s\n", 255133808Spjd WID_DST(af), WID_DST(af), "Destination", 256133808Spjd WID_GW(af), WID_GW(af), "Gateway", 257133808Spjd "Flags", "Refs", "Use", 258133808Spjd WID_IF(af), WID_IF(af), "Netif", "Expire"); 259133808Spjd else 260133808Spjd printf("%-*.*s %-*.*s %-6.6s %8.8s %6s\n", 261133808Spjd WID_DST(af), WID_DST(af), "Destination", 262133808Spjd WID_GW(af), WID_GW(af), "Gateway", 263133808Spjd "Flags", "Netif", "Expire"); 264133808Spjd} 265133808Spjd 266133808Spjdstatic struct sockaddr * 267133808Spjdkgetsa(struct sockaddr *dst) 268133808Spjd{ 269133808Spjd 270133808Spjd kget(dst, pt_u.u_sa); 271133808Spjd if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) 272133808Spjd kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len); 273133808Spjd return (&pt_u.u_sa); 274133808Spjd} 275133808Spjd 276133808Spjdstatic void 277133808Spjdp_tree(struct radix_node *rn) 278133808Spjd{ 279133808Spjd 280133808Spjdagain: 281133808Spjd kget(rn, rnode); 282133808Spjd if (rnode.rn_bit < 0) { 283133808Spjd if (Aflag) 284133808Spjd printf("%-8.8lx ", (u_long)rn); 285133808Spjd if (rnode.rn_flags & RNF_ROOT) { 286133808Spjd if (Aflag) 287133808Spjd printf("(root node)%s", 288133808Spjd rnode.rn_dupedkey ? " =>\n" : "\n"); 289133808Spjd } else if (do_rtent) { 290133808Spjd kget(rn, rtentry); 291133808Spjd p_rtentry(&rtentry); 292133808Spjd if (Aflag) 293133808Spjd p_rtnode(); 294133808Spjd } else { 295133808Spjd p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), 296133808Spjd NULL, 0, 44); 297133808Spjd putchar('\n'); 298133808Spjd } 299133808Spjd if ((rn = rnode.rn_dupedkey)) 300133808Spjd goto again; 301133808Spjd } else { 302133808Spjd if (Aflag && do_rtent) { 303133808Spjd printf("%-8.8lx ", (u_long)rn); 304133808Spjd p_rtnode(); 305133808Spjd } 306133808Spjd rn = rnode.rn_right; 307133808Spjd p_tree(rnode.rn_left); 308133808Spjd p_tree(rn); 309139144Spjd } 310139144Spjd} 311139144Spjd 312139144Spjdchar nbuf[20]; 313139144Spjd 314139144Spjdstatic void 315139144Spjdp_rtnode(void) 316139144Spjd{ 317139144Spjd struct radix_mask *rm = rnode.rn_mklist; 318133808Spjd 319133808Spjd if (rnode.rn_bit < 0) { 320133808Spjd if (rnode.rn_mask) { 321133808Spjd printf("\t mask "); 322133808Spjd p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), 323133808Spjd NULL, 0, -1); 324133808Spjd } else if (rm == 0) 325133808Spjd return; 326133808Spjd } else { 327133808Spjd sprintf(nbuf, "(%d)", rnode.rn_bit); 328133808Spjd printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long)rnode.rn_left, (u_long)rnode.rn_right); 329133808Spjd } 330133808Spjd while (rm) { 331133808Spjd kget(rm, rmask); 332133808Spjd sprintf(nbuf, " %d refs, ", rmask.rm_refs); 333133808Spjd printf(" mk = %8.8lx {(%d),%s", 334133808Spjd (u_long)rm, -1 - rmask.rm_bit, rmask.rm_refs ? nbuf : " "); 335133808Spjd if (rmask.rm_flags & RNF_NORMAL) { 336133808Spjd struct radix_node rnode_aux; 337133808Spjd printf(" <normal>, "); 338133808Spjd kget(rmask.rm_leaf, rnode_aux); 339133808Spjd p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask), 340133808Spjd NULL, 0, -1); 341133808Spjd } else 342133808Spjd p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 343133808Spjd NULL, 0, -1); 344133808Spjd putchar('}'); 345133808Spjd if ((rm = rmask.rm_mklist)) 346133808Spjd printf(" ->"); 347133808Spjd } 348133808Spjd putchar('\n'); 349133808Spjd} 350133808Spjd 351133839Sobrienstatic void 352133808Spjdntreestuff(void) 353133839Sobrien{ 354133808Spjd size_t needed; 355133808Spjd int mib[6]; 356133808Spjd char *buf, *next, *lim; 357133808Spjd register struct rt_msghdr *rtm; 358133808Spjd 359133808Spjd mib[0] = CTL_NET; 360133808Spjd mib[1] = PF_ROUTE; 361133808Spjd mib[2] = 0; 362133808Spjd mib[3] = 0; 363133808Spjd mib[4] = NET_RT_DUMP; 364133808Spjd mib[5] = 0; 365133808Spjd if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 366133808Spjd err(1, "sysctl: net.route.0.0.dump estimate"); 367133808Spjd } 368133808Spjd 369133808Spjd if ((buf = malloc(needed)) == 0) { 370133808Spjd err(2, "malloc(%lu)", (unsigned long)needed); 371133808Spjd } 372133808Spjd if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 373133808Spjd err(1, "sysctl: net.route.0.0.dump"); 374133808Spjd } 375133808Spjd lim = buf + needed; 376133808Spjd for (next = buf; next < lim; next += rtm->rtm_msglen) { 377133808Spjd rtm = (struct rt_msghdr *)next; 378133808Spjd np_rtentry(rtm); 379133808Spjd } 380133808Spjd} 381133808Spjd 382137256Spjdstatic void 383133808Spjdnp_rtentry(struct rt_msghdr *rtm) 384133808Spjd{ 385133808Spjd register struct sockaddr *sa = (struct sockaddr *)(rtm + 1); 386133808Spjd#ifdef notdef 387133808Spjd static int masks_done, banner_printed; 388133808Spjd#endif 389133808Spjd static int old_af; 390133808Spjd int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST; 391133808Spjd 392133808Spjd#ifdef notdef 393133808Spjd /* for the moment, netmasks are skipped over */ 394133808Spjd if (!banner_printed) { 395133808Spjd printf("Netmasks:\n"); 396133808Spjd banner_printed = 1; 397133808Spjd } 398139144Spjd if (masks_done == 0) { 399139144Spjd if (rtm->rtm_addrs != RTA_DST ) { 400139144Spjd masks_done = 1; 401139144Spjd af = sa->sa_family; 402139144Spjd } 403139144Spjd } else 404139144Spjd#endif 405139144Spjd af = sa->sa_family; 406139144Spjd if (af != old_af) { 407139144Spjd pr_family(af); 408139144Spjd old_af = af; 409133808Spjd } 410133808Spjd if (rtm->rtm_addrs == RTA_DST) 411139144Spjd p_sockaddr(sa, NULL, 0, 36); 412139144Spjd else { 413133808Spjd p_sockaddr(sa, NULL, rtm->rtm_flags, 16); 414133808Spjd sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); 415133808Spjd p_sockaddr(sa, NULL, 0, 18); 416133808Spjd } 417133808Spjd p_flags(rtm->rtm_flags & interesting, "%-6.6s "); 418133808Spjd putchar('\n'); 419133808Spjd} 420139144Spjd 421139144Spjdstatic void 422139144Spjdp_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width) 423139144Spjd{ 424139144Spjd char workbuf[128], *cplim; 425139144Spjd register char *cp = workbuf; 426139144Spjd 427139144Spjd switch(sa->sa_family) { 428139144Spjd case AF_INET: 429139144Spjd { 430139144Spjd register struct sockaddr_in *sin = (struct sockaddr_in *)sa; 431139144Spjd 432139144Spjd if ((sin->sin_addr.s_addr == INADDR_ANY) && 433139144Spjd mask && 434139144Spjd ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) 435139144Spjd ==0L) 436139144Spjd cp = "default" ; 437139144Spjd else if (flags & RTF_HOST) 438139144Spjd cp = routename(sin->sin_addr.s_addr); 439139144Spjd else if (mask) 440139144Spjd cp = netname(sin->sin_addr.s_addr, 441139144Spjd ntohl(((struct sockaddr_in *)mask) 442139144Spjd ->sin_addr.s_addr)); 443139144Spjd else 444133808Spjd cp = netname(sin->sin_addr.s_addr, 0L); 445133808Spjd break; 446133808Spjd } 447133808Spjd 448133808Spjd#ifdef INET6 449133808Spjd case AF_INET6: 450133808Spjd { 451133808Spjd struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; 452133808Spjd struct in6_addr *in6 = &sa6->sin6_addr; 453133808Spjd 454133808Spjd /* 455133808Spjd * XXX: This is a special workaround for KAME kernels. 456133808Spjd * sin6_scope_id field of SA should be set in the future. 457133808Spjd */ 458133808Spjd if (IN6_IS_ADDR_LINKLOCAL(in6) || 459137256Spjd IN6_IS_ADDR_MC_LINKLOCAL(in6)) { 460133808Spjd /* XXX: override is ok? */ 461133808Spjd sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]); 462133808Spjd *(u_short *)&in6->s6_addr[2] = 0; 463139144Spjd } 464139144Spjd 465139144Spjd if (flags & RTF_HOST) 466139144Spjd cp = routename6(sa6); 467139144Spjd else if (mask) 468139144Spjd cp = netname6(sa6, 469133808Spjd &((struct sockaddr_in6 *)mask)->sin6_addr); 470133808Spjd else { 471133808Spjd cp = netname6(sa6, NULL); 472133808Spjd } 473133808Spjd break; 474133808Spjd } 475133808Spjd#endif /*INET6*/ 476133808Spjd 477133808Spjd case AF_IPX: 478133808Spjd { 479133808Spjd struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr; 480133808Spjd if (ipx_nullnet(satoipx_addr(work))) 481139144Spjd cp = "default"; 482133808Spjd else 483139144Spjd cp = ipx_print(sa); 484133808Spjd break; 485133808Spjd } 486133808Spjd case AF_APPLETALK: 487133808Spjd { 488133808Spjd if (!(flags & RTF_HOST) && mask) 489133808Spjd cp = atalk_print2(sa,mask,9); 490133808Spjd else 491133808Spjd cp = atalk_print(sa,11); 492133808Spjd break; 493133808Spjd } 494133808Spjd case AF_NETGRAPH: 495133808Spjd { 496133808Spjd printf("%s", ((struct sockaddr_ng *)sa)->sg_data); 497133808Spjd break; 498133808Spjd } 499133808Spjd#ifdef NS 500133808Spjd case AF_NS: 501133808Spjd cp = ns_print(sa); 502133808Spjd break; 503133808Spjd#endif 504133808Spjd 505133808Spjd case AF_LINK: 506133808Spjd { 507133808Spjd register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 508133808Spjd 509135863Spjd if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && 510139295Spjd sdl->sdl_slen == 0) 511133808Spjd (void) sprintf(workbuf, "link#%d", sdl->sdl_index); 512133808Spjd else 513133808Spjd switch (sdl->sdl_type) { 514133808Spjd 515133808Spjd case IFT_ETHER: 516133808Spjd { 517133808Spjd register int i; 518133808Spjd register u_char *lla = (u_char *)sdl->sdl_data + 519133808Spjd sdl->sdl_nlen; 520133808Spjd 521133808Spjd cplim = ""; 522133808Spjd for (i = 0; i < sdl->sdl_alen; i++, lla++) { 523133808Spjd cp += sprintf(cp, "%s%x", cplim, *lla); 524133808Spjd cplim = ":"; 525133808Spjd } 526133808Spjd cp = workbuf; 527133808Spjd break; 528133808Spjd } 529133808Spjd 530133808Spjd default: 531133808Spjd cp = link_ntoa(sdl); 532133808Spjd break; 533133808Spjd } 534133808Spjd break; 535133808Spjd } 536133808Spjd 537133808Spjd default: 538133808Spjd { 539133808Spjd register u_char *s = (u_char *)sa->sa_data, *slim; 540133808Spjd 541133808Spjd slim = sa->sa_len + (u_char *) sa; 542133808Spjd cplim = cp + sizeof(workbuf) - 6; 543133808Spjd cp += sprintf(cp, "(%d)", sa->sa_family); 544133808Spjd while (s < slim && cp < cplim) { 545133808Spjd cp += sprintf(cp, " %02x", *s++); 546133808Spjd if (s < slim) 547133808Spjd cp += sprintf(cp, "%02x", *s++); 548133808Spjd } 549133808Spjd cp = workbuf; 550133808Spjd } 551133808Spjd } 552133808Spjd if (width < 0 ) 553133808Spjd printf("%s ", cp); 554133808Spjd else { 555133808Spjd if (numeric_addr) 556133808Spjd printf("%-*s ", width, cp); 557137257Spjd else 558133808Spjd printf("%-*.*s ", width, width, cp); 559133808Spjd } 560133808Spjd} 561133808Spjd 562133808Spjdstatic void 563133808Spjdp_flags(int f, char *format) 564133808Spjd{ 565133808Spjd char name[33], *flags; 566133808Spjd register struct bits *p = bits; 567137257Spjd 568137257Spjd for (flags = name; p->b_mask; p++) 569139144Spjd if (p->b_mask & f) 570139144Spjd *flags++ = p->b_val; 571139144Spjd *flags = '\0'; 572139144Spjd printf(format, name); 573139144Spjd} 574137257Spjd 575133808Spjdstatic void 576139144Spjdp_rtentry(struct rtentry *rt) 577133808Spjd{ 578133808Spjd static struct ifnet ifnet, *lastif; 579133808Spjd struct rtentry parent; 580133808Spjd static char name[16]; 581133808Spjd static char prettyname[9]; 582133808Spjd struct sockaddr *sa; 583133808Spjd sa_u addr, mask; 584133808Spjd 585133808Spjd /* 586133808Spjd * Don't print protocol-cloned routes unless -a. 587133808Spjd */ 588133808Spjd if (rt->rt_flags & RTF_WASCLONED && !aflag) { 589133808Spjd kget(rt->rt_parent, parent); 590133808Spjd if (parent.rt_flags & RTF_PRCLONING) 591133808Spjd return; 592133808Spjd } 593133808Spjd 594133808Spjd bzero(&addr, sizeof(addr)); 595133808Spjd if ((sa = kgetsa(rt_key(rt)))) 596133808Spjd bcopy(sa, &addr, sa->sa_len); 597133808Spjd bzero(&mask, sizeof(mask)); 598133808Spjd if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt)))) 599133808Spjd bcopy(sa, &mask, sa->sa_len); 600133808Spjd p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, 601133808Spjd WID_DST(addr.u_sa.sa_family)); 602133808Spjd p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, 603133808Spjd WID_GW(addr.u_sa.sa_family)); 604133808Spjd p_flags(rt->rt_flags, "%-6.6s "); 605133808Spjd if (addr.u_sa.sa_family == AF_INET || Wflag) { 606133808Spjd printf("%6ld %8ld ", rt->rt_refcnt, rt->rt_use); 607133808Spjd if (Wflag) { 608133808Spjd if (rt->rt_rmx.rmx_mtu != 0) 609133808Spjd printf("%6lu ", rt->rt_rmx.rmx_mtu); 610133808Spjd else 611133808Spjd printf("%6s ", ""); 612133808Spjd } 613133808Spjd } 614139295Spjd if (rt->rt_ifp) { 615133808Spjd if (rt->rt_ifp != lastif) { 616133808Spjd kget(rt->rt_ifp, ifnet); 617133808Spjd kread((u_long)ifnet.if_name, name, 16); 618133808Spjd lastif = rt->rt_ifp; 619133808Spjd snprintf(prettyname, sizeof prettyname, 620133808Spjd "%s%d", name, ifnet.if_unit); 621133808Spjd } 622133808Spjd printf("%*.*s", WID_IF(addr.u_sa.sa_family), 623133808Spjd WID_IF(addr.u_sa.sa_family), prettyname); 624133808Spjd if (rt->rt_rmx.rmx_expire) { 625133808Spjd time_t expire_time; 626133808Spjd 627133808Spjd if ((expire_time = 628133808Spjd rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0) 629139295Spjd printf(" %6d", (int)expire_time); 630133808Spjd } 631133808Spjd if (rt->rt_nodes[0].rn_dupedkey) 632133808Spjd printf(" =>"); 633133808Spjd } 634133808Spjd putchar('\n'); 635133808Spjd} 636133808Spjd 637133808Spjdchar * 638133808Spjdroutename(u_long in) 639133808Spjd{ 640133808Spjd register char *cp; 641139144Spjd static char line[MAXHOSTNAMELEN]; 642133808Spjd struct hostent *hp; 643133808Spjd 644133808Spjd cp = 0; 645133808Spjd if (!numeric_addr) { 646133808Spjd hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), 647133808Spjd AF_INET); 648133808Spjd if (hp) { 649139144Spjd cp = hp->h_name; 650139144Spjd trimdomain(cp, strlen(cp)); 651139144Spjd } 652133808Spjd } 653133808Spjd if (cp) { 654133808Spjd strncpy(line, cp, sizeof(line) - 1); 655139144Spjd line[sizeof(line) - 1] = '\0'; 656139144Spjd } else { 657139144Spjd#define C(x) ((x) & 0xff) 658139144Spjd in = ntohl(in); 659139144Spjd sprintf(line, "%lu.%lu.%lu.%lu", 660133808Spjd C(in >> 24), C(in >> 16), C(in >> 8), C(in)); 661133808Spjd } 662139295Spjd return (line); 663133808Spjd} 664133808Spjd 665133808Spjdstatic u_long 666133808Spjdforgemask(u_long a) 667133808Spjd{ 668133808Spjd u_long m; 669133808Spjd 670133808Spjd if (IN_CLASSA(a)) 671133808Spjd m = IN_CLASSA_NET; 672133808Spjd else if (IN_CLASSB(a)) 673133808Spjd m = IN_CLASSB_NET; 674133808Spjd else 675133808Spjd m = IN_CLASSC_NET; 676133808Spjd return (m); 677133808Spjd} 678133808Spjd 679133808Spjdstatic void 680133808Spjddomask(char *dst, u_long addr, u_long mask) 681133808Spjd{ 682133808Spjd register int b, i; 683133808Spjd 684133808Spjd if (!mask || (forgemask(addr) == mask)) { 685133808Spjd *dst = '\0'; 686133808Spjd return; 687133808Spjd } 688133808Spjd i = 0; 689133808Spjd for (b = 0; b < 32; b++) 690133808Spjd if (mask & (1 << b)) { 691133808Spjd register int bb; 692133808Spjd 693133808Spjd i = b; 694133808Spjd for (bb = b+1; bb < 32; bb++) 695133808Spjd if (!(mask & (1 << bb))) { 696133808Spjd i = -1; /* noncontig */ 697133808Spjd break; 698139295Spjd } 699133808Spjd break; 700133808Spjd } 701133808Spjd if (i == -1) 702133808Spjd sprintf(dst, "&0x%lx", mask); 703133808Spjd else 704133808Spjd sprintf(dst, "/%d", 32-i); 705133808Spjd} 706133808Spjd 707133808Spjd/* 708133808Spjd * Return the name of the network whose address is given. 709133808Spjd * The address is assumed to be that of a net or subnet, not a host. 710133808Spjd */ 711133808Spjdchar * 712133808Spjdnetname(u_long in, u_long mask) 713133808Spjd{ 714133808Spjd char *cp = 0; 715133808Spjd static char line[MAXHOSTNAMELEN]; 716133808Spjd struct netent *np = 0; 717133808Spjd u_long net, omask, dmask; 718133808Spjd register u_long i; 719133808Spjd 720133808Spjd i = ntohl(in); 721133808Spjd dmask = forgemask(i); 722133808Spjd omask = mask; 723133808Spjd if (!numeric_addr && i) { 724133808Spjd net = i & dmask; 725133808Spjd if (!(np = getnetbyaddr(i, AF_INET)) && net != i) 726133808Spjd np = getnetbyaddr(net, AF_INET); 727133808Spjd if (np) { 728133808Spjd cp = np->n_name; 729133808Spjd trimdomain(cp, strlen(cp)); 730133808Spjd } 731133808Spjd } 732133808Spjd if (cp) 733133808Spjd strncpy(line, cp, sizeof(line) - 1); 734133808Spjd else { 735133808Spjd switch (dmask) { 736133808Spjd case IN_CLASSA_NET: 737133808Spjd if ((i & IN_CLASSA_HOST) == 0) { 738139144Spjd sprintf(line, "%lu", C(i >> 24)); 739133808Spjd break; 740133808Spjd } 741133808Spjd /* FALLTHROUGH */ 742133808Spjd case IN_CLASSB_NET: 743133808Spjd if ((i & IN_CLASSB_HOST) == 0) { 744133808Spjd sprintf(line, "%lu.%lu", 745133808Spjd C(i >> 24), C(i >> 16)); 746133808Spjd break; 747133808Spjd } 748133808Spjd /* FALLTHROUGH */ 749139295Spjd case IN_CLASSC_NET: 750139295Spjd if ((i & IN_CLASSC_HOST) == 0) { 751133808Spjd sprintf(line, "%lu.%lu.%lu", 752133808Spjd C(i >> 24), C(i >> 16), C(i >> 8)); 753133808Spjd break; 754133808Spjd } 755133808Spjd /* FALLTHROUGH */ 756133808Spjd default: 757133808Spjd sprintf(line, "%lu.%lu.%lu.%lu", 758133808Spjd C(i >> 24), C(i >> 16), C(i >> 8), C(i)); 759133808Spjd break; 760133808Spjd } 761137258Spjd } 762139295Spjd domask(line+strlen(line), i, omask); 763139295Spjd return (line); 764139295Spjd} 765139295Spjd 766139295Spjd#ifdef INET6 767139295Spjdchar * 768139295Spjdnetname6(struct sockaddr_in6 *sa6, struct in6_addr *mask) 769139295Spjd{ 770139295Spjd static char line[MAXHOSTNAMELEN]; 771139295Spjd u_char *p = (u_char *)mask; 772139295Spjd u_char *lim; 773139295Spjd int masklen, illegal = 0, flag = NI_WITHSCOPEID; 774139295Spjd 775139295Spjd if (mask) { 776139295Spjd for (masklen = 0, lim = p + 16; p < lim; p++) { 777139295Spjd switch (*p) { 778139295Spjd case 0xff: 779139295Spjd masklen += 8; 780139295Spjd break; 781139295Spjd case 0xfe: 782139295Spjd masklen += 7; 783139295Spjd break; 784139295Spjd case 0xfc: 785139295Spjd masklen += 6; 786137258Spjd break; 787137258Spjd case 0xf8: 788137258Spjd masklen += 5; 789137258Spjd break; 790137258Spjd case 0xf0: 791137258Spjd masklen += 4; 792137258Spjd break; 793137258Spjd case 0xe0: 794137258Spjd masklen += 3; 795137258Spjd break; 796137258Spjd case 0xc0: 797137258Spjd masklen += 2; 798137258Spjd break; 799137258Spjd case 0x80: 800137258Spjd masklen += 1; 801137258Spjd break; 802137258Spjd case 0x00: 803137258Spjd break; 804137258Spjd default: 805137258Spjd illegal ++; 806137258Spjd break; 807137258Spjd } 808137258Spjd } 809137258Spjd if (illegal) 810137258Spjd fprintf(stderr, "illegal prefixlen\n"); 811137258Spjd } 812137258Spjd else 813137258Spjd masklen = 128; 814137258Spjd 815137258Spjd if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) 816137258Spjd return("default"); 817137258Spjd 818137258Spjd if (numeric_addr) 819137258Spjd flag |= NI_NUMERICHOST; 820137258Spjd getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), 821137258Spjd NULL, 0, flag); 822137258Spjd 823137258Spjd if (numeric_addr) 824137258Spjd sprintf(&line[strlen(line)], "/%d", masklen); 825137258Spjd 826137258Spjd return line; 827137259Spjd} 828137259Spjd 829137259Spjdchar * 830137259Spjdroutename6(struct sockaddr_in6 *sa6) 831137259Spjd{ 832137259Spjd static char line[MAXHOSTNAMELEN]; 833137259Spjd int flag = NI_WITHSCOPEID; 834137259Spjd /* use local variable for safety */ 835137259Spjd struct sockaddr_in6 sa6_local = {AF_INET6, sizeof(sa6_local),}; 836137259Spjd 837137259Spjd sa6_local.sin6_addr = sa6->sin6_addr; 838137259Spjd sa6_local.sin6_scope_id = sa6->sin6_scope_id; 839137259Spjd 840137259Spjd if (numeric_addr) 841137259Spjd flag |= NI_NUMERICHOST; 842137259Spjd 843137259Spjd getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len, 844137259Spjd line, sizeof(line), NULL, 0, flag); 845137259Spjd 846137259Spjd return line; 847137259Spjd} 848137259Spjd#endif /*INET6*/ 849137259Spjd 850137259Spjd/* 851137259Spjd * Print routing statistics 852137259Spjd */ 853133808Spjdvoid 854133808Spjdrt_stats(u_long rtsaddr, u_long rttaddr) 855133808Spjd{ 856133808Spjd struct rtstat rtstat; 857133808Spjd int rttrash; 858133808Spjd 859133808Spjd if (rtsaddr == 0) { 860133808Spjd printf("rtstat: symbol not in namelist\n"); 861133808Spjd return; 862133808Spjd } 863133808Spjd if (rttaddr == 0) { 864133808Spjd printf("rttrash: symbol not in namelist\n"); 865133808Spjd return; 866133808Spjd } 867133808Spjd kread(rtsaddr, (char *)&rtstat, sizeof (rtstat)); 868133808Spjd kread(rttaddr, (char *)&rttrash, sizeof (rttrash)); 869133808Spjd printf("routing:\n"); 870133808Spjd 871133808Spjd#define p(f, m) if (rtstat.f || sflag <= 1) \ 872133808Spjd printf(m, rtstat.f, plural(rtstat.f)) 873133808Spjd 874133808Spjd p(rts_badredirect, "\t%u bad routing redirect%s\n"); 875133808Spjd p(rts_dynamic, "\t%u dynamically created route%s\n"); 876133808Spjd p(rts_newgateway, "\t%u new gateway%s due to redirects\n"); 877133808Spjd p(rts_unreach, "\t%u destination%s found unreachable\n"); 878134168Spjd p(rts_wildcard, "\t%u use%s of a wildcard route\n"); 879134168Spjd#undef p 880134168Spjd 881134168Spjd if (rttrash || sflag <= 1) 882134168Spjd printf("\t%u route%s not in table but not freed\n", 883134168Spjd rttrash, plural(rttrash)); 884134168Spjd} 885134168Spjd 886134168Spjdchar * 887134168Spjdipx_print(struct sockaddr *sa) 888134168Spjd{ 889134168Spjd u_short port; 890134168Spjd struct servent *sp = 0; 891134168Spjd char *net = "", *host = ""; 892134168Spjd register char *p; 893134168Spjd register u_char *q; 894134168Spjd struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr; 895134168Spjd static char mybuf[50]; 896134168Spjd char cport[10], chost[15], cnet[15]; 897134168Spjd 898134168Spjd port = ntohs(work.x_port); 899134168Spjd 900134168Spjd if (ipx_nullnet(work) && ipx_nullhost(work)) { 901134168Spjd 902134168Spjd if (port) { 903134168Spjd if (sp) 904134168Spjd sprintf(mybuf, "*.%s", sp->s_name); 905134168Spjd else 906134168Spjd sprintf(mybuf, "*.%x", port); 907134168Spjd } else 908134168Spjd sprintf(mybuf, "*.*"); 909134168Spjd 910134168Spjd return (mybuf); 911134168Spjd } 912134168Spjd 913134168Spjd if (ipx_wildnet(work)) 914134168Spjd net = "any"; 915134168Spjd else if (ipx_nullnet(work)) 916134168Spjd net = "*"; 917134168Spjd else { 918133808Spjd q = work.x_net.c_net; 919133808Spjd sprintf(cnet, "%02x%02x%02x%02x", 920133808Spjd q[0], q[1], q[2], q[3]); 921133808Spjd for (p = cnet; *p == '0' && p < cnet + 8; p++) 922133808Spjd continue; 923133808Spjd net = p; 924133808Spjd } 925133808Spjd 926133808Spjd if (ipx_wildhost(work)) 927133808Spjd host = "any"; 928133808Spjd else if (ipx_nullhost(work)) 929133808Spjd host = "*"; 930133808Spjd else { 931133808Spjd q = work.x_host.c_host; 932133808Spjd sprintf(chost, "%02x%02x%02x%02x%02x%02x", 933133808Spjd q[0], q[1], q[2], q[3], q[4], q[5]); 934133808Spjd for (p = chost; *p == '0' && p < chost + 12; p++) 935133808Spjd continue; 936133808Spjd host = p; 937133808Spjd } 938133808Spjd 939133808Spjd if (port) { 940133808Spjd if (strcmp(host, "*") == 0) 941133808Spjd host = ""; 942134168Spjd if (sp) 943134168Spjd snprintf(cport, sizeof(cport), 944134168Spjd "%s%s", *host ? "." : "", sp->s_name); 945134168Spjd else 946134168Spjd snprintf(cport, sizeof(cport), 947134168Spjd "%s%x", *host ? "." : "", port); 948133808Spjd } else 949133808Spjd *cport = 0; 950133808Spjd 951133808Spjd snprintf(mybuf, sizeof(mybuf), "%s.%s%s", net, host, cport); 952133808Spjd return(mybuf); 953133808Spjd} 954133808Spjd 955133808Spjdchar * 956133808Spjdipx_phost(struct sockaddr *sa) 957133808Spjd{ 958133808Spjd register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa; 959133808Spjd struct sockaddr_ipx work; 960133808Spjd static union ipx_net ipx_zeronet; 961133808Spjd char *p; 962133808Spjd struct ipx_addr in; 963133808Spjd 964133808Spjd work = *sipx; 965133808Spjd in = work.sipx_addr; 966133808Spjd 967133808Spjd work.sipx_addr.x_port = 0; 968133808Spjd work.sipx_addr.x_net = ipx_zeronet; 969133808Spjd p = ipx_print((struct sockaddr *)&work); 970133808Spjd if (strncmp("*.", p, 2) == 0) p += 2; 971133808Spjd 972133808Spjd return(p); 973133808Spjd} 974133808Spjd 975133808Spjd#ifdef NS 976133808Spjdshort ns_nullh[] = {0,0,0}; 977133808Spjdshort ns_bh[] = {-1,-1,-1}; 978133808Spjd 979133808Spjdchar * 980133808Spjdns_print(struct sockaddr *sa) 981133808Spjd{ 982133808Spjd register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa; 983133808Spjd struct ns_addr work; 984133808Spjd union { union ns_net net_e; u_long long_e; } net; 985133808Spjd u_short port; 986133808Spjd static char mybuf[50], cport[10], chost[25]; 987133808Spjd char *host = ""; 988133808Spjd register char *p; register u_char *q; 989133808Spjd 990133808Spjd work = sns->sns_addr; 991133808Spjd port = ntohs(work.x_port); 992133808Spjd work.x_port = 0; 993133808Spjd net.net_e = work.x_net; 994133808Spjd if (ns_nullhost(work) && net.long_e == 0) { 995133808Spjd if (port ) { 996133808Spjd sprintf(mybuf, "*.%xH", port); 997133808Spjd upHex(mybuf); 998133808Spjd } else 999133808Spjd sprintf(mybuf, "*.*"); 1000133808Spjd return (mybuf); 1001133808Spjd } 1002133808Spjd 1003133808Spjd if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { 1004133808Spjd host = "any"; 1005133808Spjd } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { 1006133808Spjd host = "*"; 1007133808Spjd } else { 1008133808Spjd q = work.x_host.c_host; 1009133808Spjd sprintf(chost, "%02x%02x%02x%02x%02x%02xH", 1010133808Spjd q[0], q[1], q[2], q[3], q[4], q[5]); 1011133808Spjd for (p = chost; *p == '0' && p < chost + 12; p++) 1012133808Spjd continue; 1013133808Spjd host = p; 1014133808Spjd } 1015133808Spjd if (port) 1016133808Spjd sprintf(cport, ".%xH", htons(port)); 1017133808Spjd else 1018133808Spjd *cport = 0; 1019133808Spjd 1020133808Spjd sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); 1021133808Spjd upHex(mybuf); 1022133808Spjd return(mybuf); 1023133808Spjd} 1024133808Spjd 1025133808Spjdchar * 1026133808Spjdns_phost(struct sockaddr *sa) 1027133808Spjd{ 1028133808Spjd register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa; 1029133808Spjd struct sockaddr_ns work; 1030133808Spjd static union ns_net ns_zeronet; 1031133808Spjd char *p; 1032133808Spjd 1033133808Spjd work = *sns; 1034133808Spjd work.sns_addr.x_port = 0; 1035133808Spjd work.sns_addr.x_net = ns_zeronet; 1036133808Spjd 1037133808Spjd p = ns_print((struct sockaddr *)&work); 1038133808Spjd if (strncmp("0H.", p, 3) == 0) 1039133808Spjd p += 3; 1040133808Spjd return(p); 1041133808Spjd} 1042133808Spjd#endif 1043133808Spjd 1044133808Spjdvoid 1045133808SpjdupHex(char *p0) 1046133808Spjd{ 1047133808Spjd register char *p = p0; 1048133808Spjd 1049133808Spjd for (; *p; p++) 1050133808Spjd switch (*p) { 1051133808Spjd 1052133808Spjd case 'a': 1053139144Spjd case 'b': 1054139144Spjd case 'c': 1055139144Spjd case 'd': 1056137256Spjd case 'e': 1057133808Spjd case 'f': 1058133808Spjd *p += ('A' - 'a'); 1059133808Spjd break; 1060133808Spjd } 1061133808Spjd} 1062133808Spjd