1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1983, 1988, 1993
5 * Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <sys/file.h>
34 #ifdef JAIL
35 #include <sys/jail.h>
36 #endif
37 #include <sys/protosw.h>
38 #include <sys/socket.h>
39 #include <sys/socketvar.h>
40 #include <sys/sysctl.h>
41
42 #include <netinet/in.h>
43
44 #ifdef NETGRAPH
45 #include <netgraph/ng_socket.h>
46 #endif
47
48 #include <ctype.h>
49 #include <errno.h>
50 #ifdef JAIL
51 #include <jail.h>
52 #endif
53 #include <kvm.h>
54 #include <limits.h>
55 #include <netdb.h>
56 #include <nlist.h>
57 #include <paths.h>
58 #include <stdint.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <stdbool.h>
62 #include <string.h>
63 #include <sysexits.h>
64 #include <unistd.h>
65 #include "netstat.h"
66 #include "nl_defs.h"
67 #include <libxo/xo.h>
68
69 static struct protox {
70 int pr_index; /* index into nlist of cb head */
71 int pr_sindex; /* index into nlist of stat block */
72 u_char pr_wanted; /* 1 if wanted, 0 otherwise */
73 void (*pr_cblocks)(u_long, const char *, int, int);
74 /* control blocks printing routine */
75 void (*pr_stats)(u_long, const char *, int, int);
76 /* statistics printing routine */
77 void (*pr_istats)(char *); /* per/if statistics printing routine */
78 const char *pr_name; /* well-known name */
79 int pr_usesysctl; /* non-zero if we use sysctl, not kvm */
80 int pr_protocol;
81 } protox[] = {
82 { -1 , N_TCPSTAT, 1, protopr,
83 tcp_stats, NULL, "tcp", 1, IPPROTO_TCP },
84 { -1 , N_UDPSTAT, 1, protopr,
85 udp_stats, NULL, "udp", 1, IPPROTO_UDP },
86 { -1, -1, 1, protopr,
87 NULL, NULL, "udplite", 1, IPPROTO_UDPLITE },
88 #ifdef SCTP
89 { -1, N_SCTPSTAT, 1, sctp_protopr,
90 sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP },
91 #endif
92 #ifdef SDP
93 { -1, -1, 1, protopr,
94 NULL, NULL, "sdp", 1, IPPROTO_TCP },
95 #endif
96 { -1 , -1, 1, protopr,
97 divert_stats, NULL, "divert", 1, 0 },
98 { -1 , N_IPSTAT, 1, protopr,
99 ip_stats, NULL, "ip", 1, IPPROTO_RAW },
100 { -1 , N_ICMPSTAT, 1, protopr,
101 icmp_stats, NULL, "icmp", 1, IPPROTO_ICMP },
102 { -1 , N_IGMPSTAT, 1, protopr,
103 igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP },
104 #ifdef IPSEC
105 { -1, N_IPSEC4STAT, 1, NULL, /* keep as compat */
106 ipsec_stats, NULL, "ipsec", 1, 0},
107 { -1, N_AHSTAT, 1, NULL,
108 ah_stats, NULL, "ah", 1, 0},
109 { -1, N_ESPSTAT, 1, NULL,
110 esp_stats, NULL, "esp", 1, 0},
111 { -1, N_IPCOMPSTAT, 1, NULL,
112 ipcomp_stats, NULL, "ipcomp", 1, 0},
113 #endif
114 { -1 , N_PIMSTAT, 1, protopr,
115 pim_stats, NULL, "pim", 1, IPPROTO_PIM },
116 { -1, N_CARPSTATS, 1, NULL,
117 carp_stats, NULL, "carp", 1, 0 },
118 #ifdef PF
119 { -1, N_PFSYNCSTATS, 1, NULL,
120 pfsync_stats, NULL, "pfsync", 1, 0 },
121 { -1, N_PFLOWSTATS, 1, NULL,
122 pflow_stats, NULL, "pflow", 1, 0 },
123 #endif
124 { -1, N_ARPSTAT, 1, NULL,
125 arp_stats, NULL, "arp", 1, 0 },
126 { -1, -1, 0, NULL,
127 NULL, NULL, NULL, 0, 0 }
128 };
129
130 #ifdef INET6
131 static struct protox ip6protox[] = {
132 { -1 , N_TCPSTAT, 1, protopr,
133 tcp_stats, NULL, "tcp", 1, IPPROTO_TCP },
134 { -1 , N_UDPSTAT, 1, protopr,
135 udp_stats, NULL, "udp", 1, IPPROTO_UDP },
136 { -1, -1, 1, protopr,
137 NULL, NULL, "udplite", 1, IPPROTO_UDPLITE },
138 { -1 , N_IP6STAT, 1, protopr,
139 ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW },
140 { -1 , N_ICMP6STAT, 1, protopr,
141 icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 },
142 #ifdef SDP
143 { -1, -1, 1, protopr,
144 NULL, NULL, "sdp", 1, IPPROTO_TCP },
145 #endif
146 #ifdef IPSEC
147 { -1, N_IPSEC6STAT, 1, NULL,
148 ipsec_stats, NULL, "ipsec6", 1, 0 },
149 #endif
150 #ifdef notyet
151 { -1, N_PIM6STAT, 1, NULL,
152 pim6_stats, NULL, "pim6", 1, 0 },
153 #endif
154 { -1, N_RIP6STAT, 1, NULL,
155 rip6_stats, NULL, "rip6", 1, 0 },
156 { -1, -1, 0, NULL,
157 NULL, NULL, NULL, 0, 0 }
158 };
159 #endif /*INET6*/
160
161 #ifdef IPSEC
162 static struct protox pfkeyprotox[] = {
163 { -1, N_PFKEYSTAT, 1, NULL,
164 pfkey_stats, NULL, "pfkey", 0, 0 },
165 { -1, -1, 0, NULL,
166 NULL, NULL, NULL, 0, 0 }
167 };
168 #endif
169
170 #ifdef NETGRAPH
171 static struct protox netgraphprotox[] = {
172 { N_NGSOCKLIST, -1, 1, netgraphprotopr,
173 NULL, NULL, "ctrl", 0, 0 },
174 { N_NGSOCKLIST, -1, 1, netgraphprotopr,
175 NULL, NULL, "data", 0, 0 },
176 { -1, -1, 0, NULL,
177 NULL, NULL, NULL, 0, 0 }
178 };
179 #endif
180
181 static struct protox *protoprotox[] = {
182 protox,
183 #ifdef INET6
184 ip6protox,
185 #endif
186 #ifdef IPSEC
187 pfkeyprotox,
188 #endif
189 NULL };
190
191 static void printproto(struct protox *, const char *, bool *);
192 static void usage(void) __dead2;
193 static struct protox *name2protox(const char *);
194 static struct protox *knownname(const char *);
195
196 static int kresolve_list(struct nlist *_nl);
197
198 static kvm_t *kvmd;
199 static char *nlistf = NULL, *memf = NULL;
200
201 bool Aflag; /* show addresses of protocol control block */
202 bool aflag; /* show all sockets (including servers) */
203 static bool Bflag; /* show information about bpf consumers */
204 bool bflag; /* show i/f total bytes in/out */
205 bool cflag; /* show TCP congestion control stack */
206 bool Cflag; /* show congestion control algo and vars */
207 bool dflag; /* show i/f dropped packets */
208 bool gflag; /* show group (multicast) routing or stats */
209 bool hflag; /* show counters in human readable format */
210 bool iflag; /* show interfaces */
211 bool Lflag; /* show size of listen queues */
212 bool mflag; /* show memory stats */
213 int noutputs = 0; /* how much outputs before we exit */
214 u_int numeric_addr = 0; /* show addresses numerically */
215 bool numeric_port; /* show ports numerically */
216 bool Oflag; /* show nhgrp objects*/
217 bool oflag; /* show nexthop objects*/
218 bool Pflag; /* show TCP log ID */
219 static bool pflag; /* show given protocol */
220 static bool Qflag; /* show netisr information */
221 bool rflag; /* show routing tables (or routing stats) */
222 bool Rflag; /* show flow / RSS statistics */
223 int sflag; /* show protocol statistics */
224 bool Wflag; /* wide display */
225 bool Tflag; /* TCP Information */
226 bool xflag; /* extra information, includes all socket buffer info */
227 bool zflag; /* zero stats */
228
229 int interval; /* repeat interval for i/f stats */
230
231 char *interface; /* desired i/f for stats, or NULL for all i/fs */
232 int unit; /* unit number for above */
233 #ifdef JAIL
234 char *jail_name; /* desired jail to operate in */
235 #endif
236
237 static int af; /* address family */
238 int live; /* true if we are examining a live system */
239
240 int
main(int argc,char * argv[])241 main(int argc, char *argv[])
242 {
243 struct protox *tp = NULL; /* for printing cblocks & stats */
244 int ch;
245 int fib = -1;
246 char *endptr;
247 bool first = true;
248 #ifdef JAIL
249 int jid;
250 #endif
251
252 af = AF_UNSPEC;
253
254 argc = xo_parse_args(argc, argv);
255 if (argc < 0)
256 exit(EXIT_FAILURE);
257
258 while ((ch = getopt(argc, argv, "46AaBbCcdF:f:ghI:ij:LlM:mN:nOoPp:Qq:RrSTsuWw:xz"))
259 != -1)
260 switch(ch) {
261 case '4':
262 #ifdef INET
263 af = AF_INET;
264 #else
265 xo_errx(EX_UNAVAILABLE, "IPv4 support is not compiled in");
266 #endif
267 break;
268 case '6':
269 #ifdef INET6
270 af = AF_INET6;
271 #else
272 xo_errx(EX_UNAVAILABLE, "IPv6 support is not compiled in");
273 #endif
274 break;
275 case 'A':
276 Aflag = true;
277 break;
278 case 'a':
279 aflag = true;
280 break;
281 case 'B':
282 Bflag = true;
283 break;
284 case 'b':
285 bflag = true;
286 break;
287 case 'c':
288 cflag = true;
289 break;
290 case 'C':
291 Cflag = true;
292 break;
293 case 'd':
294 dflag = true;
295 break;
296 case 'F':
297 fib = strtol(optarg, &endptr, 0);
298 if (*endptr != '\0' ||
299 (fib == 0 && (errno == EINVAL || errno == ERANGE)))
300 xo_errx(EX_DATAERR, "%s: invalid fib", optarg);
301 break;
302 case 'f':
303 if (strcmp(optarg, "inet") == 0)
304 af = AF_INET;
305 #ifdef INET6
306 else if (strcmp(optarg, "inet6") == 0)
307 af = AF_INET6;
308 #endif
309 #ifdef IPSEC
310 else if (strcmp(optarg, "pfkey") == 0)
311 af = PF_KEY;
312 #endif
313 else if (strcmp(optarg, "unix") == 0 ||
314 strcmp(optarg, "local") == 0)
315 af = AF_UNIX;
316 #ifdef NETGRAPH
317 else if (strcmp(optarg, "ng") == 0
318 || strcmp(optarg, "netgraph") == 0)
319 af = AF_NETGRAPH;
320 #endif
321 else if (strcmp(optarg, "link") == 0)
322 af = AF_LINK;
323 else {
324 xo_errx(EX_DATAERR, "%s: unknown address family",
325 optarg);
326 }
327 break;
328 case 'g':
329 gflag = true;
330 break;
331 case 'h':
332 hflag = true;
333 break;
334 case 'I': {
335 char *cp;
336
337 iflag = true;
338 for (cp = interface = optarg; isalpha(*cp); cp++)
339 continue;
340 unit = atoi(cp);
341 break;
342 }
343 case 'i':
344 iflag = true;
345 break;
346 case 'j':
347 #ifdef JAIL
348 if (optarg == NULL)
349 usage();
350 jail_name = optarg;
351 #else
352 xo_errx(EX_UNAVAILABLE, "Jail support is not compiled in");
353 #endif
354 break;
355 case 'L':
356 Lflag = true;
357 break;
358 case 'M':
359 memf = optarg;
360 break;
361 case 'm':
362 mflag = true;
363 break;
364 case 'N':
365 nlistf = optarg;
366 break;
367 case 'n':
368 numeric_addr++;
369 numeric_port = true;
370 break;
371 case 'o':
372 oflag = true;
373 break;
374 case 'O':
375 Oflag = true;
376 break;
377 case 'P':
378 Pflag = true;
379 break;
380 case 'p':
381 if ((tp = name2protox(optarg)) == NULL) {
382 xo_errx(EX_DATAERR, "%s: unknown or uninstrumented "
383 "protocol", optarg);
384 }
385 pflag = true;
386 break;
387 case 'Q':
388 Qflag = true;
389 break;
390 case 'q':
391 noutputs = atoi(optarg);
392 if (noutputs != 0)
393 noutputs++;
394 break;
395 case 'r':
396 rflag = true;
397 break;
398 case 'R':
399 Rflag = true;
400 break;
401 case 's':
402 ++sflag;
403 break;
404 case 'S':
405 numeric_addr = 1;
406 break;
407 case 'u':
408 af = AF_UNIX;
409 break;
410 case 'W':
411 case 'l':
412 Wflag = true;
413 break;
414 case 'w':
415 interval = atoi(optarg);
416 iflag = true;
417 break;
418 case 'T':
419 Tflag = true;
420 break;
421 case 'x':
422 xflag = true;
423 break;
424 case 'z':
425 zflag = true;
426 break;
427 case '?':
428 default:
429 usage();
430 }
431 argv += optind;
432 argc -= optind;
433
434 #define BACKWARD_COMPATIBILITY
435 #ifdef BACKWARD_COMPATIBILITY
436 if (*argv) {
437 if (isdigit(**argv)) {
438 interval = atoi(*argv);
439 if (interval <= 0)
440 usage();
441 ++argv;
442 iflag = true;
443 }
444 if (*argv) {
445 nlistf = *argv;
446 if (*++argv)
447 memf = *argv;
448 }
449 }
450 #endif
451
452 #ifdef JAIL
453 if (jail_name != NULL) {
454 jid = jail_getid(jail_name);
455 if (jid == -1)
456 xo_errx(EX_UNAVAILABLE, "Jail not found");
457 if (jail_attach(jid) != 0)
458 xo_errx(EX_UNAVAILABLE, "Cannot attach to jail");
459 }
460 #endif
461
462 live = (nlistf == NULL && memf == NULL);
463 /* Load all necessary kvm symbols */
464 if (!live)
465 kresolve_list(nl);
466
467 if (xflag && Tflag)
468 xo_errx(EX_USAGE, "-x and -T are incompatible, pick one.");
469
470 if (Bflag) {
471 if (!live)
472 usage();
473 bpf_stats(interface);
474 if (xo_finish() < 0)
475 xo_err(EX_IOERR, "stdout");
476 exit(EX_OK);
477 }
478 if (mflag) {
479 if (!live) {
480 if (kread(0, NULL, 0) == 0)
481 mbpr(kvmd, nl[N_SFSTAT].n_value);
482 } else
483 mbpr(NULL, 0);
484 if (xo_finish() < 0)
485 xo_err(EX_IOERR, "stdout");
486 exit(EX_OK);
487 }
488 if (Qflag) {
489 if (!live) {
490 if (kread(0, NULL, 0) == 0)
491 netisr_stats();
492 } else
493 netisr_stats();
494 if (xo_finish() < 0)
495 xo_err(EX_IOERR, "stdout");
496 exit(EX_OK);
497 }
498 #if 0
499 /*
500 * Keep file descriptors open to avoid overhead
501 * of open/close on each call to get* routines.
502 */
503 sethostent(1);
504 setnetent(1);
505 #else
506 /*
507 * This does not make sense any more with DNS being default over
508 * the files. Doing a setXXXXent(1) causes a tcp connection to be
509 * used for the queries, which is slower.
510 */
511 #endif
512 if (iflag && !sflag) {
513 xo_open_container("statistics");
514 xo_set_version(NETSTAT_XO_VERSION);
515 intpr(NULL, af);
516 xo_close_container("statistics");
517 if (xo_finish() < 0)
518 xo_err(EX_IOERR, "stdout");
519 exit(EX_OK);
520 }
521 if (rflag) {
522 xo_open_container("statistics");
523 xo_set_version(NETSTAT_XO_VERSION);
524 if (sflag)
525 rt_stats();
526 else
527 routepr(fib, af);
528 xo_close_container("statistics");
529 if (xo_finish() < 0)
530 xo_err(EX_IOERR, "stdout");
531 exit(EX_OK);
532 }
533 if (oflag) {
534 xo_open_container("statistics");
535 xo_set_version(NETSTAT_XO_VERSION);
536 nhops_print(fib, af);
537 xo_close_container("statistics");
538 if (xo_finish() < 0)
539 xo_err(EX_IOERR, "stdout");
540 exit(EX_OK);
541 }
542 if (Oflag) {
543 xo_open_container("statistics");
544 xo_set_version(NETSTAT_XO_VERSION);
545 nhgrp_print(fib, af);
546 xo_close_container("statistics");
547 if (xo_finish() < 0)
548 xo_err(EX_IOERR, "stdout");
549 exit(EX_OK);
550 }
551
552
553
554 if (gflag) {
555 xo_open_container("statistics");
556 xo_set_version(NETSTAT_XO_VERSION);
557 if (sflag) {
558 if (af == AF_INET || af == AF_UNSPEC)
559 mrt_stats();
560 #ifdef INET6
561 if (af == AF_INET6 || af == AF_UNSPEC)
562 mrt6_stats();
563 #endif
564 } else {
565 if (af == AF_INET || af == AF_UNSPEC)
566 mroutepr();
567 #ifdef INET6
568 if (af == AF_INET6 || af == AF_UNSPEC)
569 mroute6pr();
570 #endif
571 }
572 xo_close_container("statistics");
573 if (xo_finish() < 0)
574 xo_err(EX_IOERR, "stdout");
575 exit(EX_OK);
576 }
577
578 if (tp) {
579 xo_open_container("statistics");
580 xo_set_version(NETSTAT_XO_VERSION);
581 printproto(tp, tp->pr_name, &first);
582 if (!first)
583 xo_close_list("socket");
584 xo_close_container("statistics");
585 if (xo_finish() < 0)
586 xo_err(EX_IOERR, "stdout");
587 exit(EX_OK);
588 }
589
590 xo_open_container("statistics");
591 xo_set_version(NETSTAT_XO_VERSION);
592 if (af == AF_INET || af == AF_UNSPEC)
593 for (tp = protox; tp->pr_name; tp++)
594 printproto(tp, tp->pr_name, &first);
595 #ifdef INET6
596 if (af == AF_INET6 || af == AF_UNSPEC)
597 for (tp = ip6protox; tp->pr_name; tp++)
598 printproto(tp, tp->pr_name, &first);
599 #endif /*INET6*/
600 #ifdef IPSEC
601 if (af == PF_KEY || af == AF_UNSPEC)
602 for (tp = pfkeyprotox; tp->pr_name; tp++)
603 printproto(tp, tp->pr_name, &first);
604 #endif /*IPSEC*/
605 #ifdef NETGRAPH
606 if (af == AF_NETGRAPH || af == AF_UNSPEC)
607 for (tp = netgraphprotox; tp->pr_name; tp++)
608 printproto(tp, tp->pr_name, &first);
609 #endif /* NETGRAPH */
610 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
611 unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value,
612 nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value,
613 nl[N_UNP_SPHEAD].n_value, &first);
614
615 if (!first)
616 xo_close_list("socket");
617 xo_close_container("statistics");
618 if (xo_finish() < 0)
619 xo_err(EX_IOERR, "stdout");
620 exit(EX_OK);
621 }
622
623 static int
fetch_stats_internal(const char * sysctlname,u_long off,void * stats,size_t len,kreadfn_t kreadfn,int zero)624 fetch_stats_internal(const char *sysctlname, u_long off, void *stats,
625 size_t len, kreadfn_t kreadfn, int zero)
626 {
627 int error;
628
629 if (live) {
630 memset(stats, 0, len);
631 if (zero)
632 error = sysctlbyname(sysctlname, NULL, NULL, stats,
633 len);
634 else
635 error = sysctlbyname(sysctlname, stats, &len, NULL, 0);
636 if (error == -1 && errno != ENOENT)
637 xo_warn("sysctl %s", sysctlname);
638 } else {
639 if (off == 0)
640 return (1);
641 error = kreadfn(off, stats, len);
642 }
643 return (error);
644 }
645
646 int
fetch_stats(const char * sysctlname,u_long off,void * stats,size_t len,kreadfn_t kreadfn)647 fetch_stats(const char *sysctlname, u_long off, void *stats,
648 size_t len, kreadfn_t kreadfn)
649 {
650
651 return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn,
652 zflag));
653 }
654
655 int
fetch_stats_ro(const char * sysctlname,u_long off,void * stats,size_t len,kreadfn_t kreadfn)656 fetch_stats_ro(const char *sysctlname, u_long off, void *stats,
657 size_t len, kreadfn_t kreadfn)
658 {
659
660 return (fetch_stats_internal(sysctlname, off, stats, len, kreadfn, 0));
661 }
662
663 /*
664 * Print out protocol statistics or control blocks (per sflag).
665 * If the interface was not specifically requested, and the symbol
666 * is not in the namelist, ignore this one.
667 */
668 static void
printproto(struct protox * tp,const char * name,bool * first)669 printproto(struct protox *tp, const char *name, bool *first)
670 {
671 void (*pr)(u_long, const char *, int, int);
672 u_long off;
673 bool doingdblocks = false;
674
675 if (sflag) {
676 if (iflag) {
677 if (tp->pr_istats)
678 intpr(tp->pr_istats, af);
679 else if (pflag)
680 xo_message("%s: no per-interface stats routine",
681 tp->pr_name);
682 return;
683 } else {
684 pr = tp->pr_stats;
685 if (!pr) {
686 if (pflag)
687 xo_message("%s: no stats routine",
688 tp->pr_name);
689 return;
690 }
691 if (tp->pr_usesysctl && live)
692 off = 0;
693 else if (tp->pr_sindex < 0) {
694 if (pflag)
695 xo_message("%s: stats routine doesn't "
696 "work on cores", tp->pr_name);
697 return;
698 } else
699 off = nl[tp->pr_sindex].n_value;
700 }
701 } else {
702 doingdblocks = true;
703 pr = tp->pr_cblocks;
704 if (!pr) {
705 if (pflag)
706 xo_message("%s: no PCB routine", tp->pr_name);
707 return;
708 }
709 if (tp->pr_usesysctl && live)
710 off = 0;
711 else if (tp->pr_index < 0) {
712 if (pflag)
713 xo_message("%s: PCB routine doesn't work on "
714 "cores", tp->pr_name);
715 return;
716 } else
717 off = nl[tp->pr_index].n_value;
718 }
719 if (pr != NULL && (off || (live && tp->pr_usesysctl) ||
720 af != AF_UNSPEC)) {
721 if (doingdblocks && *first) {
722 xo_open_list("socket");
723 *first = false;
724 }
725
726 (*pr)(off, name, af, tp->pr_protocol);
727 }
728 }
729
730 static int
kvmd_init(void)731 kvmd_init(void)
732 {
733 char errbuf[_POSIX2_LINE_MAX];
734
735 if (kvmd != NULL)
736 return (0);
737
738 kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
739 if (kvmd == NULL) {
740 xo_warnx("kvm not available: %s", errbuf);
741 return (-1);
742 }
743
744 return (0);
745 }
746
747 /*
748 * Resolve symbol list, return 0 on success.
749 */
750 static int
kresolve_list(struct nlist * _nl)751 kresolve_list(struct nlist *_nl)
752 {
753
754 if ((kvmd == NULL) && (kvmd_init() != 0))
755 return (-1);
756
757 if (_nl[0].n_type != 0)
758 return (0);
759
760 if (kvm_nlist(kvmd, _nl) < 0) {
761 if (nlistf)
762 xo_errx(EX_UNAVAILABLE, "%s: kvm_nlist: %s", nlistf,
763 kvm_geterr(kvmd));
764 else
765 xo_errx(EX_UNAVAILABLE, "kvm_nlist: %s", kvm_geterr(kvmd));
766 }
767
768 return (0);
769 }
770
771 /*
772 * Wrapper of kvm_dpcpu_setcpu().
773 */
774 void
kset_dpcpu(u_int cpuid)775 kset_dpcpu(u_int cpuid)
776 {
777
778 if ((kvmd == NULL) && (kvmd_init() != 0))
779 xo_errx(EX_UNAVAILABLE, "%s: kvm is not available", __func__);
780
781 if (kvm_dpcpu_setcpu(kvmd, cpuid) < 0)
782 xo_errx(EX_UNAVAILABLE, "%s: kvm_dpcpu_setcpu(%u): %s", __func__,
783 cpuid, kvm_geterr(kvmd));
784 return;
785 }
786
787 /*
788 * Read kernel memory, return 0 on success.
789 */
790 int
kread(u_long addr,void * buf,size_t size)791 kread(u_long addr, void *buf, size_t size)
792 {
793
794 if (kvmd_init() < 0)
795 return (-1);
796
797 if (!buf)
798 return (0);
799 if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
800 xo_warnx("%s", kvm_geterr(kvmd));
801 return (-1);
802 }
803 return (0);
804 }
805
806 /*
807 * Read single counter(9).
808 */
809 uint64_t
kread_counter(u_long addr)810 kread_counter(u_long addr)
811 {
812
813 if (kvmd_init() < 0)
814 return (-1);
815
816 return (kvm_counter_u64_fetch(kvmd, addr));
817 }
818
819 /*
820 * Read an array of N counters in kernel memory into array of N uint64_t's.
821 */
822 int
kread_counters(u_long addr,void * buf,size_t size)823 kread_counters(u_long addr, void *buf, size_t size)
824 {
825 uint64_t *c;
826 u_long *counters;
827 size_t i, n;
828
829 if (kvmd_init() < 0)
830 return (-1);
831
832 if (size % sizeof(uint64_t) != 0) {
833 xo_warnx("kread_counters: invalid counter set size");
834 return (-1);
835 }
836
837 n = size / sizeof(uint64_t);
838 if ((counters = malloc(n * sizeof(u_long))) == NULL)
839 xo_err(EX_OSERR, "malloc");
840 if (kread(addr, counters, n * sizeof(u_long)) < 0) {
841 free(counters);
842 return (-1);
843 }
844
845 c = buf;
846 for (i = 0; i < n; i++)
847 c[i] = kvm_counter_u64_fetch(kvmd, counters[i]);
848
849 free(counters);
850 return (0);
851 }
852
853 const char *
plural(uintmax_t n)854 plural(uintmax_t n)
855 {
856 return (n != 1 ? "s" : "");
857 }
858
859 const char *
plurales(uintmax_t n)860 plurales(uintmax_t n)
861 {
862 return (n != 1 ? "es" : "");
863 }
864
865 const char *
pluralies(uintmax_t n)866 pluralies(uintmax_t n)
867 {
868 return (n != 1 ? "ies" : "y");
869 }
870
871 /*
872 * Find the protox for the given "well-known" name.
873 */
874 static struct protox *
knownname(const char * name)875 knownname(const char *name)
876 {
877 struct protox **tpp, *tp;
878
879 for (tpp = protoprotox; *tpp; tpp++)
880 for (tp = *tpp; tp->pr_name; tp++)
881 if (strcmp(tp->pr_name, name) == 0)
882 return (tp);
883 return (NULL);
884 }
885
886 /*
887 * Find the protox corresponding to name.
888 */
889 static struct protox *
name2protox(const char * name)890 name2protox(const char *name)
891 {
892 struct protox *tp;
893 char **alias; /* alias from p->aliases */
894 struct protoent *p;
895
896 /*
897 * Try to find the name in the list of "well-known" names. If that
898 * fails, check if name is an alias for an Internet protocol.
899 */
900 if ((tp = knownname(name)) != NULL)
901 return (tp);
902
903 setprotoent(1); /* make protocol lookup cheaper */
904 while ((p = getprotoent()) != NULL) {
905 /* assert: name not same as p->name */
906 for (alias = p->p_aliases; *alias; alias++)
907 if (strcmp(name, *alias) == 0) {
908 endprotoent();
909 return (knownname(p->p_name));
910 }
911 }
912 endprotoent();
913 return (NULL);
914 }
915
916 static void
usage(void)917 usage(void)
918 {
919 xo_error("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
920 "usage: netstat [-j jail] [-46AaCcLnRSTWx] [-f protocol_family | -p protocol]\n"
921 " [-M core] [-N system]",
922 " netstat [-j jail] -i | -I interface [-46abdhnW] [-f address_family]\n"
923 " [-M core] [-N system]",
924 " netstat [-j jail] -w wait [-I interface] [-46d] [-M core] [-N system]\n"
925 " [-q howmany]",
926 " netstat [-j jail] -s [-46sz] [-f protocol_family | -p protocol]\n"
927 " [-M core] [-N system]",
928 " netstat [-j jail] -i | -I interface -s [-46s]\n"
929 " [-f protocol_family | -p protocol] [-M core] [-N system]",
930 " netstat [-j jail] -m [-M core] [-N system]",
931 " netstat [-j jail] -B [-z] [-I interface]",
932 " netstat [-j jail] -r [-46AnW] [-F fibnum] [-f address_family]\n"
933 " [-M core] [-N system]",
934 " netstat [-j jail] -rs [-s] [-M core] [-N system]",
935 " netstat [-j jail] -g [-46W] [-f address_family] [-M core] [-N system]",
936 " netstat [-j jail] -gs [-46s] [-f address_family] [-M core] [-N system]",
937 " netstat [-j jail] -Q");
938 exit(EX_USAGE);
939 }
940