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