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