main.c revision 263335
1189251Ssam/*- 2252726Srpaulo * Copyright (c) 1983, 1988, 1993 3252726Srpaulo * Regents of the University of California. All rights reserved. 4189251Ssam * 5252726Srpaulo * Redistribution and use in source and binary forms, with or without 6252726Srpaulo * modification, are permitted provided that the following conditions 7189251Ssam * are met: 8189251Ssam * 1. Redistributions of source code must retain the above copyright 9189251Ssam * notice, this list of conditions and the following disclaimer. 10189251Ssam * 2. Redistributions in binary form must reproduce the above copyright 11189251Ssam * notice, this list of conditions and the following disclaimer in the 12214734Srpaulo * documentation and/or other materials provided with the distribution. 13214734Srpaulo * 4. Neither the name of the University nor the names of its contributors 14189251Ssam * may be used to endorse or promote products derived from this software 15189251Ssam * without specific prior written permission. 16189251Ssam * 17189251Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18189251Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19189251Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20189251Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21189251Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22189251Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23189251Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24189251Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25189251Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26189251Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27189251Ssam * SUCH DAMAGE. 28189251Ssam */ 29189251Ssam 30189251Ssam#ifndef lint 31189251Ssamchar const copyright[] = 32189251Ssam"@(#) Copyright (c) 1983, 1988, 1993\n\ 33189251Ssam Regents of the University of California. All rights reserved.\n"; 34189251Ssam#endif /* not lint */ 35189251Ssam 36189251Ssam#if 0 37189251Ssam#ifndef lint 38189251Ssamstatic char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94"; 39189251Ssam#endif /* not lint */ 40189251Ssam#endif 41189251Ssam 42189251Ssam#include <sys/cdefs.h> 43189251Ssam__FBSDID("$FreeBSD: stable/10/usr.bin/netstat/main.c 263335 2014-03-19 09:36:29Z glebius $"); 44189251Ssam 45189251Ssam#include <sys/param.h> 46252726Srpaulo#include <sys/file.h> 47252726Srpaulo#include <sys/protosw.h> 48189251Ssam#include <sys/socket.h> 49189251Ssam#include <sys/socketvar.h> 50189251Ssam 51189251Ssam#include <netinet/in.h> 52189251Ssam 53189251Ssam#ifdef NETGRAPH 54189251Ssam#include <netgraph/ng_socket.h> 55189251Ssam#endif 56189251Ssam 57189251Ssam#include <ctype.h> 58189251Ssam#include <err.h> 59189251Ssam#include <errno.h> 60189251Ssam#include <kvm.h> 61189251Ssam#include <limits.h> 62252726Srpaulo#include <netdb.h> 63252726Srpaulo#include <nlist.h> 64189251Ssam#include <paths.h> 65189251Ssam#include <stdint.h> 66189251Ssam#include <stdio.h> 67189251Ssam#include <stdlib.h> 68189251Ssam#include <string.h> 69189251Ssam#include <unistd.h> 70189251Ssam#include "netstat.h" 71189251Ssam 72189251Ssamstatic struct nlist nl[] = { 73189251Ssam#define N_IFNET 0 74189251Ssam { .n_name = "_ifnet" }, /* XXXGL: can be deleted */ 75189251Ssam#define N_RTSTAT 1 76189251Ssam { .n_name = "_rtstat" }, 77189251Ssam#define N_RTREE 2 78189251Ssam { .n_name = "_rt_tables"}, 79189251Ssam#define N_MRTSTAT 3 80189251Ssam { .n_name = "_mrtstat" }, 81189251Ssam#define N_MFCHASHTBL 4 82189251Ssam { .n_name = "_mfchashtbl" }, 83189251Ssam#define N_VIFTABLE 5 84189251Ssam { .n_name = "_viftable" }, 85189251Ssam#define N_IPX 6 86189251Ssam { .n_name = "_ipxpcb_list"}, 87189251Ssam#define N_IPXSTAT 7 88189251Ssam { .n_name = "_ipxstat"}, 89189251Ssam#define N_SPXSTAT 8 90189251Ssam { .n_name = "_spx_istat"}, 91189251Ssam#define N_DDPSTAT 9 92189251Ssam { .n_name = "_ddpstat"}, 93189251Ssam#define N_DDPCB 10 94189251Ssam { .n_name = "_ddpcb"}, 95189251Ssam#define N_NGSOCKS 11 96189251Ssam { .n_name = "_ngsocklist"}, 97189251Ssam#define N_IP6STAT 12 98189251Ssam { .n_name = "_ip6stat" }, 99189251Ssam#define N_ICMP6STAT 13 100189251Ssam { .n_name = "_icmp6stat" }, 101189251Ssam#define N_IPSECSTAT 14 102189251Ssam { .n_name = "_ipsec4stat" }, 103189251Ssam#define N_IPSEC6STAT 15 104189251Ssam { .n_name = "_ipsec6stat" }, 105189251Ssam#define N_PIM6STAT 16 106189251Ssam { .n_name = "_pim6stat" }, 107189251Ssam#define N_MRT6STAT 17 108189251Ssam { .n_name = "_mrt6stat" }, 109189251Ssam#define N_MF6CTABLE 18 110189251Ssam { .n_name = "_mf6ctable" }, 111189251Ssam#define N_MIF6TABLE 19 112189251Ssam { .n_name = "_mif6table" }, 113189251Ssam#define N_PFKEYSTAT 20 114252726Srpaulo { .n_name = "_pfkeystat" }, 115189251Ssam#define N_RTTRASH 21 116189251Ssam { .n_name = "_rttrash" }, 117189251Ssam#define N_CARPSTAT 22 118189251Ssam { .n_name = "_carpstats" }, 119189251Ssam#define N_PFSYNCSTAT 23 120189251Ssam { .n_name = "_pfsyncstats" }, 121189251Ssam#define N_AHSTAT 24 122189251Ssam { .n_name = "_ahstat" }, 123189251Ssam#define N_ESPSTAT 25 124189251Ssam { .n_name = "_espstat" }, 125189251Ssam#define N_IPCOMPSTAT 26 126189251Ssam { .n_name = "_ipcompstat" }, 127189251Ssam#define N_TCPSTAT 27 128189251Ssam { .n_name = "_tcpstat" }, 129189251Ssam#define N_UDPSTAT 28 130252726Srpaulo { .n_name = "_udpstat" }, 131252726Srpaulo#define N_IPSTAT 29 132252726Srpaulo { .n_name = "_ipstat" }, 133189251Ssam#define N_ICMPSTAT 30 134189251Ssam { .n_name = "_icmpstat" }, 135189251Ssam#define N_IGMPSTAT 31 136189251Ssam { .n_name = "_igmpstat" }, 137189251Ssam#define N_PIMSTAT 32 138252726Srpaulo { .n_name = "_pimstat" }, 139252726Srpaulo#define N_TCBINFO 33 140252726Srpaulo { .n_name = "_tcbinfo" }, 141252726Srpaulo#define N_UDBINFO 34 142252726Srpaulo { .n_name = "_udbinfo" }, 143252726Srpaulo#define N_DIVCBINFO 35 144252726Srpaulo { .n_name = "_divcbinfo" }, 145189251Ssam#define N_RIPCBINFO 36 146189251Ssam { .n_name = "_ripcbinfo" }, 147189251Ssam#define N_UNP_COUNT 37 148189251Ssam { .n_name = "_unp_count" }, 149189251Ssam#define N_UNP_GENCNT 38 150189251Ssam { .n_name = "_unp_gencnt" }, 151189251Ssam#define N_UNP_DHEAD 39 152189251Ssam { .n_name = "_unp_dhead" }, 153189251Ssam#define N_UNP_SHEAD 40 154189251Ssam { .n_name = "_unp_shead" }, 155189251Ssam#define N_RIP6STAT 41 156189251Ssam { .n_name = "_rip6stat" }, 157189251Ssam#define N_SCTPSTAT 42 158189251Ssam { .n_name = "_sctpstat" }, 159189251Ssam#define N_MFCTABLESIZE 43 160252726Srpaulo { .n_name = "_mfctablesize" }, 161189251Ssam#define N_ARPSTAT 44 162189251Ssam { .n_name = "_arpstat" }, 163189251Ssam#define N_UNP_SPHEAD 45 164189251Ssam { .n_name = "unp_sphead" }, 165189251Ssam#define N_SFSTAT 46 166189251Ssam { .n_name = "_sfstat"}, 167189251Ssam { .n_name = NULL }, 168189251Ssam}; 169189251Ssam 170189251Ssamstruct protox { 171189251Ssam int pr_index; /* index into nlist of cb head */ 172189251Ssam int pr_sindex; /* index into nlist of stat block */ 173189251Ssam u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 174189251Ssam void (*pr_cblocks)(u_long, const char *, int, int); 175189251Ssam /* control blocks printing routine */ 176189251Ssam void (*pr_stats)(u_long, const char *, int, int); 177189251Ssam /* statistics printing routine */ 178189251Ssam void (*pr_istats)(char *); /* per/if statistics printing routine */ 179189251Ssam const char *pr_name; /* well-known name */ 180189251Ssam int pr_usesysctl; /* non-zero if we use sysctl, not kvm */ 181189251Ssam int pr_protocol; 182189251Ssam} protox[] = { 183189251Ssam { N_TCBINFO, N_TCPSTAT, 1, protopr, 184189251Ssam tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, 185189251Ssam { N_UDBINFO, N_UDPSTAT, 1, protopr, 186189251Ssam udp_stats, NULL, "udp", 1, IPPROTO_UDP }, 187189251Ssam#ifdef SCTP 188189251Ssam { -1, N_SCTPSTAT, 1, sctp_protopr, 189189251Ssam sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP }, 190189251Ssam#endif 191189251Ssam#ifdef SDP 192189251Ssam { -1, -1, 1, protopr, 193189251Ssam NULL, NULL, "sdp", 1, IPPROTO_TCP }, 194189251Ssam#endif 195189251Ssam { N_DIVCBINFO, -1, 1, protopr, 196189251Ssam NULL, NULL, "divert", 1, IPPROTO_DIVERT }, 197189251Ssam { N_RIPCBINFO, N_IPSTAT, 1, protopr, 198189251Ssam ip_stats, NULL, "ip", 1, IPPROTO_RAW }, 199189251Ssam { N_RIPCBINFO, N_ICMPSTAT, 1, protopr, 200189251Ssam icmp_stats, NULL, "icmp", 1, IPPROTO_ICMP }, 201189251Ssam { N_RIPCBINFO, N_IGMPSTAT, 1, protopr, 202189251Ssam igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP }, 203189251Ssam#ifdef IPSEC 204189251Ssam { -1, N_IPSECSTAT, 1, NULL, /* keep as compat */ 205189251Ssam ipsec_stats, NULL, "ipsec", 0, 0}, 206189251Ssam { -1, N_AHSTAT, 1, NULL, 207189251Ssam ah_stats, NULL, "ah", 0, 0}, 208189251Ssam { -1, N_ESPSTAT, 1, NULL, 209189251Ssam esp_stats, NULL, "esp", 0, 0}, 210252726Srpaulo { -1, N_IPCOMPSTAT, 1, NULL, 211189251Ssam ipcomp_stats, NULL, "ipcomp", 0, 0}, 212189251Ssam#endif 213189251Ssam { N_RIPCBINFO, N_PIMSTAT, 1, protopr, 214189251Ssam pim_stats, NULL, "pim", 1, IPPROTO_PIM }, 215189251Ssam { -1, N_CARPSTAT, 1, NULL, 216189251Ssam carp_stats, NULL, "carp", 1, 0 }, 217189251Ssam#ifdef PF 218189251Ssam { -1, N_PFSYNCSTAT, 1, NULL, 219189251Ssam pfsync_stats, NULL, "pfsync", 1, 0 }, 220189251Ssam#endif 221189251Ssam { -1, N_ARPSTAT, 1, NULL, 222189251Ssam arp_stats, NULL, "arp", 1, 0 }, 223189251Ssam { -1, -1, 0, NULL, 224189251Ssam NULL, NULL, NULL, 0, 0 } 225189251Ssam}; 226189251Ssam 227189251Ssam#ifdef INET6 228189251Ssamstruct protox ip6protox[] = { 229189251Ssam { N_TCBINFO, N_TCPSTAT, 1, protopr, 230189251Ssam tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, 231189251Ssam { N_UDBINFO, N_UDPSTAT, 1, protopr, 232189251Ssam udp_stats, NULL, "udp", 1, IPPROTO_UDP }, 233189251Ssam { N_RIPCBINFO, N_IP6STAT, 1, protopr, 234189251Ssam ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW }, 235189251Ssam { N_RIPCBINFO, N_ICMP6STAT, 1, protopr, 236189251Ssam icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 }, 237189251Ssam#ifdef SDP 238252726Srpaulo { -1, -1, 1, protopr, 239252726Srpaulo NULL, NULL, "sdp", 1, IPPROTO_TCP }, 240189251Ssam#endif 241189251Ssam#ifdef IPSEC 242189251Ssam { -1, N_IPSEC6STAT, 1, NULL, 243189251Ssam ipsec_stats, NULL, "ipsec6", 0, 0 }, 244189251Ssam#endif 245189251Ssam#ifdef notyet 246189251Ssam { -1, N_PIM6STAT, 1, NULL, 247189251Ssam pim6_stats, NULL, "pim6", 1, 0 }, 248252726Srpaulo#endif 249252726Srpaulo { -1, N_RIP6STAT, 1, NULL, 250252726Srpaulo rip6_stats, NULL, "rip6", 1, 0 }, 251252726Srpaulo { -1, -1, 0, NULL, 252252726Srpaulo NULL, NULL, NULL, 0, 0 } 253252726Srpaulo}; 254252726Srpaulo#endif /*INET6*/ 255252726Srpaulo 256252726Srpaulo#ifdef IPSEC 257252726Srpaulostruct protox pfkeyprotox[] = { 258252726Srpaulo { -1, N_PFKEYSTAT, 1, NULL, 259252726Srpaulo pfkey_stats, NULL, "pfkey", 0, 0 }, 260252726Srpaulo { -1, -1, 0, NULL, 261252726Srpaulo NULL, NULL, NULL, 0, 0 } 262252726Srpaulo}; 263252726Srpaulo#endif 264252726Srpaulo 265252726Srpaulostruct protox atalkprotox[] = { 266252726Srpaulo { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, 267252726Srpaulo ddp_stats, NULL, "ddp", 0, 0 }, 268252726Srpaulo { -1, -1, 0, NULL, 269252726Srpaulo NULL, NULL, NULL, 0, 0 } 270252726Srpaulo}; 271252726Srpaulo#ifdef NETGRAPH 272252726Srpaulostruct protox netgraphprotox[] = { 273252726Srpaulo { N_NGSOCKS, -1, 1, netgraphprotopr, 274252726Srpaulo NULL, NULL, "ctrl", 0, 0 }, 275252726Srpaulo { N_NGSOCKS, -1, 1, netgraphprotopr, 276252726Srpaulo NULL, NULL, "data", 0, 0 }, 277252726Srpaulo { -1, -1, 0, NULL, 278252726Srpaulo NULL, NULL, NULL, 0, 0 } 279252726Srpaulo}; 280252726Srpaulo#endif 281252726Srpaulo#ifdef IPX 282252726Srpaulostruct protox ipxprotox[] = { 283252726Srpaulo { N_IPX, N_IPXSTAT, 1, ipxprotopr, 284252726Srpaulo ipx_stats, NULL, "ipx", 0, 0 }, 285252726Srpaulo { N_IPX, N_SPXSTAT, 1, ipxprotopr, 286252726Srpaulo spx_stats, NULL, "spx", 0, 0 }, 287252726Srpaulo { -1, -1, 0, NULL, 288189251Ssam NULL, NULL, 0, 0, 0 } 289189251Ssam}; 290189251Ssam#endif 291189251Ssam 292189251Ssamstruct protox *protoprotox[] = { 293189251Ssam protox, 294189251Ssam#ifdef INET6 295189251Ssam ip6protox, 296189251Ssam#endif 297189251Ssam#ifdef IPSEC 298189251Ssam pfkeyprotox, 299189251Ssam#endif 300189251Ssam#ifdef IPX 301189251Ssam ipxprotox, 302189251Ssam#endif 303189251Ssam atalkprotox, NULL }; 304252726Srpaulo 305189251Ssamstatic void printproto(struct protox *, const char *); 306189251Ssamstatic void usage(void); 307189251Ssamstatic struct protox *name2protox(const char *); 308189251Ssamstatic struct protox *knownname(const char *); 309189251Ssam 310189251Ssamstatic kvm_t *kvmd; 311189251Ssamstatic char *nlistf = NULL, *memf = NULL; 312189251Ssam 313189251Ssamint Aflag; /* show addresses of protocol control block */ 314189251Ssamint aflag; /* show all sockets (including servers) */ 315189251Ssamint Bflag; /* show information about bpf consumers */ 316189251Ssamint bflag; /* show i/f total bytes in/out */ 317189251Ssamint dflag; /* show i/f dropped packets */ 318189251Ssamint gflag; /* show group (multicast) routing or stats */ 319189251Ssamint hflag; /* show counters in human readable format */ 320189251Ssamint iflag; /* show interfaces */ 321189251Ssamint Lflag; /* show size of listen queues */ 322189251Ssamint mflag; /* show memory stats */ 323189251Ssamint noutputs = 0; /* how much outputs before we exit */ 324189251Ssamint numeric_addr; /* show addresses numerically */ 325189251Ssamint numeric_port; /* show ports numerically */ 326189251Ssamstatic int pflag; /* show given protocol */ 327189251Ssamint Qflag; /* show netisr information */ 328189251Ssamint rflag; /* show routing tables (or routing stats) */ 329189251Ssamint sflag; /* show protocol statistics */ 330189251Ssamint Wflag; /* wide display */ 331189251Ssamint Tflag; /* TCP Information */ 332189251Ssamint xflag; /* extra information, includes all socket buffer info */ 333189251Ssamint zflag; /* zero stats */ 334189251Ssam 335189251Ssamint interval; /* repeat interval for i/f stats */ 336189251Ssam 337189251Ssamchar *interface; /* desired i/f for stats, or NULL for all i/fs */ 338189251Ssamint unit; /* unit number for above */ 339189251Ssam 340189251Ssamint af; /* address family */ 341189251Ssamint live; /* true if we are examining a live system */ 342189251Ssam 343189251Ssamint 344189251Ssammain(int argc, char *argv[]) 345189251Ssam{ 346189251Ssam struct protox *tp = NULL; /* for printing cblocks & stats */ 347189251Ssam int ch; 348189251Ssam int fib = -1; 349189251Ssam char *endptr; 350189251Ssam 351189251Ssam af = AF_UNSPEC; 352189251Ssam 353189251Ssam while ((ch = getopt(argc, argv, "AaBbdF:f:ghI:iLlM:mN:np:Qq:rSTsuWw:xz")) 354189251Ssam != -1) 355189251Ssam switch(ch) { 356189251Ssam case 'A': 357189251Ssam Aflag = 1; 358189251Ssam break; 359189251Ssam case 'a': 360189251Ssam aflag = 1; 361189251Ssam break; 362189251Ssam case 'B': 363189251Ssam Bflag = 1; 364189251Ssam break; 365189251Ssam case 'b': 366189251Ssam bflag = 1; 367189251Ssam break; 368189251Ssam case 'd': 369189251Ssam dflag = 1; 370189251Ssam break; 371189251Ssam case 'F': 372189251Ssam fib = strtol(optarg, &endptr, 0); 373189251Ssam if (*endptr != '\0' || 374189251Ssam (fib == 0 && (errno == EINVAL || errno == ERANGE))) 375189251Ssam errx(1, "%s: invalid fib", optarg); 376189251Ssam break; 377189251Ssam case 'f': 378189251Ssam if (strcmp(optarg, "ipx") == 0) 379189251Ssam af = AF_IPX; 380189251Ssam else if (strcmp(optarg, "inet") == 0) 381189251Ssam af = AF_INET; 382189251Ssam#ifdef INET6 383189251Ssam else if (strcmp(optarg, "inet6") == 0) 384189251Ssam af = AF_INET6; 385189251Ssam#endif 386189251Ssam#ifdef IPSEC 387189251Ssam else if (strcmp(optarg, "pfkey") == 0) 388189251Ssam af = PF_KEY; 389189251Ssam#endif 390189251Ssam else if (strcmp(optarg, "unix") == 0) 391189251Ssam af = AF_UNIX; 392189251Ssam else if (strcmp(optarg, "atalk") == 0) 393189251Ssam af = AF_APPLETALK; 394189251Ssam#ifdef NETGRAPH 395189251Ssam else if (strcmp(optarg, "ng") == 0 396189251Ssam || strcmp(optarg, "netgraph") == 0) 397189251Ssam af = AF_NETGRAPH; 398189251Ssam#endif 399189251Ssam else if (strcmp(optarg, "link") == 0) 400189251Ssam af = AF_LINK; 401189251Ssam else { 402189251Ssam errx(1, "%s: unknown address family", optarg); 403189251Ssam } 404189251Ssam break; 405189251Ssam case 'g': 406189251Ssam gflag = 1; 407189251Ssam break; 408189251Ssam case 'h': 409189251Ssam hflag = 1; 410189251Ssam break; 411189251Ssam case 'I': { 412189251Ssam char *cp; 413189251Ssam 414189251Ssam iflag = 1; 415189251Ssam for (cp = interface = optarg; isalpha(*cp); cp++) 416189251Ssam continue; 417189251Ssam unit = atoi(cp); 418189251Ssam break; 419189251Ssam } 420189251Ssam case 'i': 421189251Ssam iflag = 1; 422189251Ssam break; 423189251Ssam case 'L': 424189251Ssam Lflag = 1; 425189251Ssam break; 426189251Ssam case 'M': 427189251Ssam memf = optarg; 428189251Ssam break; 429189251Ssam case 'm': 430189251Ssam mflag = 1; 431189251Ssam break; 432189251Ssam case 'N': 433189251Ssam nlistf = optarg; 434189251Ssam break; 435189251Ssam case 'n': 436189251Ssam numeric_addr = numeric_port = 1; 437189251Ssam break; 438189251Ssam case 'p': 439189251Ssam if ((tp = name2protox(optarg)) == NULL) { 440189251Ssam errx(1, 441189251Ssam "%s: unknown or uninstrumented protocol", 442189251Ssam optarg); 443189251Ssam } 444189251Ssam pflag = 1; 445189251Ssam break; 446252726Srpaulo case 'Q': 447252726Srpaulo Qflag = 1; 448189251Ssam break; 449189251Ssam case 'q': 450189251Ssam noutputs = atoi(optarg); 451189251Ssam if (noutputs != 0) 452189251Ssam noutputs++; 453189251Ssam break; 454189251Ssam case 'r': 455189251Ssam rflag = 1; 456189251Ssam break; 457189251Ssam case 's': 458189251Ssam ++sflag; 459189251Ssam break; 460189251Ssam case 'S': 461189251Ssam numeric_addr = 1; 462189251Ssam break; 463189251Ssam case 'u': 464189251Ssam af = AF_UNIX; 465189251Ssam break; 466189251Ssam case 'W': 467189251Ssam case 'l': 468189251Ssam Wflag = 1; 469189251Ssam break; 470189251Ssam case 'w': 471189251Ssam interval = atoi(optarg); 472189251Ssam iflag = 1; 473189251Ssam break; 474189251Ssam case 'T': 475189251Ssam Tflag = 1; 476189251Ssam break; 477189251Ssam case 'x': 478189251Ssam xflag = 1; 479189251Ssam break; 480189251Ssam case 'z': 481189251Ssam zflag = 1; 482189251Ssam break; 483189251Ssam case '?': 484189251Ssam default: 485189251Ssam usage(); 486189251Ssam } 487189251Ssam argv += optind; 488189251Ssam argc -= optind; 489189251Ssam 490189251Ssam#define BACKWARD_COMPATIBILITY 491189251Ssam#ifdef BACKWARD_COMPATIBILITY 492189251Ssam if (*argv) { 493189251Ssam if (isdigit(**argv)) { 494189251Ssam interval = atoi(*argv); 495189251Ssam if (interval <= 0) 496189251Ssam usage(); 497189251Ssam ++argv; 498189251Ssam iflag = 1; 499189251Ssam } 500189251Ssam if (*argv) { 501189251Ssam nlistf = *argv; 502189251Ssam if (*++argv) 503189251Ssam memf = *argv; 504189251Ssam } 505189251Ssam } 506189251Ssam#endif 507189251Ssam 508189251Ssam /* 509189251Ssam * Discard setgid privileges if not the running kernel so that bad 510189251Ssam * guys can't print interesting stuff from kernel memory. 511189251Ssam */ 512189251Ssam live = (nlistf == NULL && memf == NULL); 513189251Ssam if (!live) 514189251Ssam setgid(getgid()); 515189251Ssam 516189251Ssam if (xflag && Tflag) 517189251Ssam errx(1, "-x and -T are incompatible, pick one."); 518189251Ssam 519189251Ssam if (Bflag) { 520189251Ssam if (!live) 521189251Ssam usage(); 522189251Ssam bpf_stats(interface); 523189251Ssam exit(0); 524189251Ssam } 525189251Ssam if (mflag) { 526189251Ssam if (!live) { 527189251Ssam if (kread(0, NULL, 0) == 0) 528189251Ssam mbpr(kvmd, nl[N_SFSTAT].n_value); 529189251Ssam } else 530189251Ssam mbpr(NULL, 0); 531189251Ssam exit(0); 532189251Ssam } 533189251Ssam if (Qflag) { 534189251Ssam if (!live) { 535189251Ssam if (kread(0, NULL, 0) == 0) 536189251Ssam netisr_stats(kvmd); 537189251Ssam } else 538189251Ssam netisr_stats(NULL); 539189251Ssam exit(0); 540189251Ssam } 541189251Ssam#if 0 542189251Ssam /* 543189251Ssam * Keep file descriptors open to avoid overhead 544189251Ssam * of open/close on each call to get* routines. 545189251Ssam */ 546189251Ssam sethostent(1); 547189251Ssam setnetent(1); 548189251Ssam#else 549189251Ssam /* 550189251Ssam * This does not make sense any more with DNS being default over 551189251Ssam * the files. Doing a setXXXXent(1) causes a tcp connection to be 552189251Ssam * used for the queries, which is slower. 553189251Ssam */ 554189251Ssam#endif 555189251Ssam if (iflag && !sflag) { 556189251Ssam intpr(interval, NULL, af); 557189251Ssam exit(0); 558189251Ssam } 559189251Ssam if (rflag) { 560189251Ssam if (sflag) { 561189251Ssam rt_stats(); 562189251Ssam flowtable_stats(); 563189251Ssam } else 564189251Ssam routepr(fib, af); 565189251Ssam exit(0); 566189251Ssam } 567189251Ssam 568189251Ssam if (gflag) { 569189251Ssam if (sflag) { 570189251Ssam if (af == AF_INET || af == AF_UNSPEC) 571189251Ssam mrt_stats(); 572189251Ssam#ifdef INET6 573189251Ssam if (af == AF_INET6 || af == AF_UNSPEC) 574189251Ssam mrt6_stats(); 575189251Ssam#endif 576189251Ssam } else { 577189251Ssam if (af == AF_INET || af == AF_UNSPEC) 578189251Ssam mroutepr(); 579189251Ssam#ifdef INET6 580189251Ssam if (af == AF_INET6 || af == AF_UNSPEC) 581189251Ssam mroute6pr(); 582189251Ssam#endif 583189251Ssam } 584189251Ssam exit(0); 585189251Ssam } 586189251Ssam 587189251Ssam /* Load all necessary kvm symbols */ 588189251Ssam kresolve_list(nl); 589189251Ssam 590189251Ssam if (tp) { 591189251Ssam printproto(tp, tp->pr_name); 592189251Ssam exit(0); 593189251Ssam } 594189251Ssam if (af == AF_INET || af == AF_UNSPEC) 595189251Ssam for (tp = protox; tp->pr_name; tp++) 596189251Ssam printproto(tp, tp->pr_name); 597189251Ssam#ifdef INET6 598189251Ssam if (af == AF_INET6 || af == AF_UNSPEC) 599189251Ssam for (tp = ip6protox; tp->pr_name; tp++) 600189251Ssam printproto(tp, tp->pr_name); 601189251Ssam#endif /*INET6*/ 602189251Ssam#ifdef IPSEC 603189251Ssam if (af == PF_KEY || af == AF_UNSPEC) 604189251Ssam for (tp = pfkeyprotox; tp->pr_name; tp++) 605189251Ssam printproto(tp, tp->pr_name); 606189251Ssam#endif /*IPSEC*/ 607189251Ssam#ifdef IPX 608189251Ssam if (af == AF_IPX || af == AF_UNSPEC) { 609189251Ssam for (tp = ipxprotox; tp->pr_name; tp++) 610189251Ssam printproto(tp, tp->pr_name); 611189251Ssam } 612189251Ssam#endif /* IPX */ 613189251Ssam if (af == AF_APPLETALK || af == AF_UNSPEC) 614189251Ssam for (tp = atalkprotox; tp->pr_name; tp++) 615189251Ssam printproto(tp, tp->pr_name); 616189251Ssam#ifdef NETGRAPH 617189251Ssam if (af == AF_NETGRAPH || af == AF_UNSPEC) 618189251Ssam for (tp = netgraphprotox; tp->pr_name; tp++) 619189251Ssam printproto(tp, tp->pr_name); 620189251Ssam#endif /* NETGRAPH */ 621 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 622 unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value, 623 nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value, 624 nl[N_UNP_SPHEAD].n_value); 625 exit(0); 626} 627 628/* 629 * Print out protocol statistics or control blocks (per sflag). 630 * If the interface was not specifically requested, and the symbol 631 * is not in the namelist, ignore this one. 632 */ 633static void 634printproto(struct protox *tp, const char *name) 635{ 636 void (*pr)(u_long, const char *, int, int); 637 u_long off; 638 639 if (sflag) { 640 if (iflag) { 641 if (tp->pr_istats) 642 intpr(interval, tp->pr_istats, af); 643 else if (pflag) 644 printf("%s: no per-interface stats routine\n", 645 tp->pr_name); 646 return; 647 } else { 648 pr = tp->pr_stats; 649 if (!pr) { 650 if (pflag) 651 printf("%s: no stats routine\n", 652 tp->pr_name); 653 return; 654 } 655 if (tp->pr_usesysctl && live) 656 off = 0; 657 else if (tp->pr_sindex < 0) { 658 if (pflag) 659 printf( 660 "%s: stats routine doesn't work on cores\n", 661 tp->pr_name); 662 return; 663 } else 664 off = nl[tp->pr_sindex].n_value; 665 } 666 } else { 667 pr = tp->pr_cblocks; 668 if (!pr) { 669 if (pflag) 670 printf("%s: no PCB routine\n", tp->pr_name); 671 return; 672 } 673 if (tp->pr_usesysctl && live) 674 off = 0; 675 else if (tp->pr_index < 0) { 676 if (pflag) 677 printf( 678 "%s: PCB routine doesn't work on cores\n", 679 tp->pr_name); 680 return; 681 } else 682 off = nl[tp->pr_index].n_value; 683 } 684 if (pr != NULL && (off || (live && tp->pr_usesysctl) || 685 af != AF_UNSPEC)) 686 (*pr)(off, name, af, tp->pr_protocol); 687} 688 689static int 690kvmd_init(void) 691{ 692 char errbuf[_POSIX2_LINE_MAX]; 693 694 if (kvmd != NULL) 695 return (0); 696 697 kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 698 setgid(getgid()); 699 700 if (kvmd == NULL) { 701 warnx("kvm not available: %s", errbuf); 702 return (-1); 703 } 704 705 return (0); 706} 707 708/* 709 * Resolve symbol list, return 0 on success. 710 */ 711int 712kresolve_list(struct nlist *_nl) 713{ 714 715 if ((kvmd == NULL) && (kvmd_init() != 0)) 716 return (-1); 717 718 if (_nl[0].n_type != 0) 719 return (0); 720 721 if (kvm_nlist(kvmd, _nl) < 0) { 722 if (nlistf) 723 errx(1, "%s: kvm_nlist: %s", nlistf, 724 kvm_geterr(kvmd)); 725 else 726 errx(1, "kvm_nlist: %s", kvm_geterr(kvmd)); 727 } 728 729 return (0); 730} 731 732/* 733 * Read kernel memory, return 0 on success. 734 */ 735int 736kread(u_long addr, void *buf, size_t size) 737{ 738 739 if (kvmd_init() < 0) 740 return (-1); 741 742 if (!buf) 743 return (0); 744 if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) { 745 warnx("%s", kvm_geterr(kvmd)); 746 return (-1); 747 } 748 return (0); 749} 750 751/* 752 * Read an array of N counters in kernel memory into array of N uint64_t's. 753 */ 754int 755kread_counters(u_long addr, void *buf, size_t size) 756{ 757 uint64_t *c = buf; 758 759 if (kvmd_init() < 0) 760 return (-1); 761 762 if (kread(addr, buf, size) < 0) 763 return (-1); 764 765 while (size != 0) { 766 *c = kvm_counter_u64_fetch(kvmd, *c); 767 size -= sizeof(*c); 768 c++; 769 } 770 return (0); 771} 772 773const char * 774plural(uintmax_t n) 775{ 776 return (n != 1 ? "s" : ""); 777} 778 779const char * 780plurales(uintmax_t n) 781{ 782 return (n != 1 ? "es" : ""); 783} 784 785const char * 786pluralies(uintmax_t n) 787{ 788 return (n != 1 ? "ies" : "y"); 789} 790 791/* 792 * Find the protox for the given "well-known" name. 793 */ 794static struct protox * 795knownname(const char *name) 796{ 797 struct protox **tpp, *tp; 798 799 for (tpp = protoprotox; *tpp; tpp++) 800 for (tp = *tpp; tp->pr_name; tp++) 801 if (strcmp(tp->pr_name, name) == 0) 802 return (tp); 803 return (NULL); 804} 805 806/* 807 * Find the protox corresponding to name. 808 */ 809static struct protox * 810name2protox(const char *name) 811{ 812 struct protox *tp; 813 char **alias; /* alias from p->aliases */ 814 struct protoent *p; 815 816 /* 817 * Try to find the name in the list of "well-known" names. If that 818 * fails, check if name is an alias for an Internet protocol. 819 */ 820 if ((tp = knownname(name)) != NULL) 821 return (tp); 822 823 setprotoent(1); /* make protocol lookup cheaper */ 824 while ((p = getprotoent()) != NULL) { 825 /* assert: name not same as p->name */ 826 for (alias = p->p_aliases; *alias; alias++) 827 if (strcmp(name, *alias) == 0) { 828 endprotoent(); 829 return (knownname(p->p_name)); 830 } 831 } 832 endprotoent(); 833 return (NULL); 834} 835 836static void 837usage(void) 838{ 839 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 840"usage: netstat [-AaLnSTWx] [-f protocol_family | -p protocol]\n" 841" [-M core] [-N system]", 842" netstat -i | -I interface [-abdhnW] [-f address_family]\n" 843" [-M core] [-N system]", 844" netstat -w wait [-I interface] [-d] [-M core] [-N system] [-q howmany]", 845" netstat -s [-s] [-z] [-f protocol_family | -p protocol]\n" 846" [-M core] [-N system]", 847" netstat -i | -I interface -s [-f protocol_family | -p protocol]\n" 848" [-M core] [-N system]", 849" netstat -m [-M core] [-N system]", 850" netstat -B [-I interface]", 851" netstat -r [-AanW] [-f address_family] [-M core] [-N system]", 852" netstat -rs [-s] [-M core] [-N system]", 853" netstat -g [-W] [-f address_family] [-M core] [-N system]", 854" netstat -gs [-s] [-f address_family] [-M core] [-N system]", 855" netstat -Q"); 856 exit(1); 857} 858