138589Sabial/*-
238589Sabial * Copyright (c) 1998 Andrzej Bialecki
338589Sabial * All rights reserved.
438589Sabial *
538589Sabial * Redistribution and use in source and binary forms, with or without
638589Sabial * modification, are permitted provided that the following conditions
738589Sabial * are met:
838589Sabial * 1. Redistributions of source code must retain the above copyright
938589Sabial *    notice, this list of conditions and the following disclaimer.
1038589Sabial * 2. Redistributions in binary form must reproduce the above copyright
1138589Sabial *    notice, this list of conditions and the following disclaimer in the
1238589Sabial *    documentation and/or other materials provided with the distribution.
1338589Sabial *
1438589Sabial * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538589Sabial * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638589Sabial * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738589Sabial * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838589Sabial * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938589Sabial * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038589Sabial * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138589Sabial * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238589Sabial * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338589Sabial * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438589Sabial * SUCH DAMAGE.
2538589Sabial *
2650479Speter * $FreeBSD$
2738589Sabial */
2838589Sabial
2938589Sabial
3038589Sabial/*
3138589Sabial * Small replacement for netstat. Uses only sysctl(3) to get the info.
3238589Sabial */
3338589Sabial
3438589Sabial#include <sys/types.h>
3538589Sabial#include <sys/time.h>
3638589Sabial#include <sys/sysctl.h>
3738589Sabial#include <sys/socket.h>
3875878Sjoe#include <sys/un.h>
3975878Sjoe
4038589Sabial#include <net/if.h>
4175878Sjoe#include <net/route.h>
4275878Sjoe#include <net/if_dl.h>
4338589Sabial#include <netinet/in_systm.h>
4438589Sabial#include <netinet/in.h>
4538589Sabial#include <netinet/ip.h>
4638589Sabial#include <netinet/ip_icmp.h>
4738589Sabial#include <netinet/icmp_var.h>
4838589Sabial#include <netinet/ip_var.h>
4938589Sabial#include <netinet/tcp.h>
5038589Sabial#include <netinet/tcp_timer.h>
5138589Sabial#include <netinet/tcp_var.h>
5238589Sabial#include <netinet/udp.h>
5338589Sabial#include <netinet/udp_var.h>
54191565Sluigi#include <arpa/inet.h>
5538589Sabial
5675878Sjoe#include <err.h>
5775878Sjoe#include <errno.h>
5875878Sjoe#include <osreldate.h>
5975878Sjoe#include <stdio.h>
60191565Sluigi#include <stdlib.h>
61191565Sluigi#include <string.h>
6275878Sjoe#include <unistd.h>
6375878Sjoe
6438589Sabialchar *progname;
6575878Sjoeint iflag = 0;
6687832Sluigiint lflag = 0;			/* print cpu load info */
6775878Sjoeint rflag = 0;
6875878Sjoeint sflag = 0;
6975878Sjoeint pflag = 0;
7075878Sjoeint wflag = 0;			/* repeat every wait seconds */
7184769Sluigiint delta = 0 ;
7238589Sabial
7338589Sabialextern char *optarg;
7438589Sabialextern int optind;
7538589Sabial
76191565Sluigivoid print_load_stats(void);
77191565Sluigi
7838589Sabialvoid
7938589Sabialusage()
8038589Sabial{
8187832Sluigi	fprintf(stderr, "\n%s [-nrsil] [-p proto] [-w wait]\n", progname);
8275878Sjoe	fprintf(stderr, "  proto: {ip|tcp|udp|icmp}\n\n");
8338589Sabial}
8438589Sabial
8538589Sabial
8638589Sabial/*
8738589Sabial * The following parts related to retrieving the routing table and
8838589Sabial * interface information, were borrowed from R. Stevens' code examples
8938589Sabial * accompanying his excellent book. Thanks!
9038589Sabial */
9138589Sabialchar *
9238589Sabialsock_ntop(const struct sockaddr *sa, size_t salen)
9338589Sabial{
9475878Sjoe	char	portstr[7];
9575878Sjoe	static	char str[128];	/* Unix domain is largest */
9638589Sabial
9738589Sabial	switch (sa->sa_family) {
9838589Sabial	case 255: {
9975878Sjoe		int	i = 0;
10075878Sjoe		u_long	mask;
10175878Sjoe		u_int	index = 1 << 31;
10275878Sjoe		u_short	new_mask = 0;
10338589Sabial
10470911Sabial		mask = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
10575878Sjoe
10675878Sjoe		while (mask & index) {
10770911Sabial			new_mask++;
10870911Sabial			index >>= 1;
10970911Sabial		}
11075878Sjoe		sprintf(str, "/%hu", new_mask);
11175878Sjoe		return (str);
11238589Sabial	}
11375878Sjoe	case AF_UNSPEC:
11438589Sabial	case AF_INET: {
11575878Sjoe		struct	sockaddr_in *sin = (struct sockaddr_in *)sa;
11638589Sabial
11775878Sjoe		if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))
11875878Sjoe		    == NULL)
11975878Sjoe			return (NULL);
12075878Sjoe		if (ntohs(sin->sin_port) != 0) {
12175878Sjoe			snprintf(portstr, sizeof(portstr), ".%d",
12275878Sjoe			    ntohs(sin->sin_port));
12338589Sabial			strcat(str, portstr);
12438589Sabial		}
12575878Sjoe		if (strcmp(str, "0.0.0.0") == 0)
12675878Sjoe			sprintf(str, "default");
12775878Sjoe		return (str);
12838589Sabial	}
12975878Sjoe
13038589Sabial	case AF_UNIX: {
13175878Sjoe		struct	sockaddr_un *unp = (struct sockaddr_un *)sa;
13238589Sabial
13375878Sjoe		/*
13475878Sjoe		 * OK to have no pathname bound to the socket:
13575878Sjoe		 * happens on every connect() unless client calls
13675878Sjoe		 * bind() first.
13775878Sjoe		 */
13838589Sabial		if (unp->sun_path[0] == 0)
13938589Sabial			strcpy(str, "(no pathname bound)");
14038589Sabial		else
14138589Sabial			snprintf(str, sizeof(str), "%s", unp->sun_path);
14275878Sjoe		return (str);
14338589Sabial	}
14475878Sjoe
14538589Sabial	case AF_LINK: {
14675878Sjoe		struct	sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
14738589Sabial
14858423Sluigi		if (sdl->sdl_nlen > 0) {
14958423Sluigi			bcopy(&sdl->sdl_data[0], str, sdl->sdl_nlen);
15075878Sjoe			str[sdl->sdl_nlen] = '\0';
15158423Sluigi		} else
15238589Sabial			snprintf(str, sizeof(str), "link#%d", sdl->sdl_index);
15375878Sjoe		return (str);
15438589Sabial	}
15575878Sjoe
15638589Sabial	default:
15775878Sjoe		snprintf(str, sizeof(str),
15875878Sjoe		    "sock_ntop: unknown AF_xxx: %d, len %d", sa->sa_family,
15975878Sjoe		    salen);
16075878Sjoe		return (str);
16138589Sabial	}
16275878Sjoe	return (NULL);
16338589Sabial}
16438589Sabial
16538589Sabialchar *
16638589SabialSock_ntop(const struct sockaddr *sa, size_t salen)
16738589Sabial{
16838589Sabial	char	*ptr;
16938589Sabial
17075878Sjoe	if ((ptr = sock_ntop(sa, salen)) == NULL)
17175878Sjoe		err(1, "sock_ntop error");	/* inet_ntop() sets errno */
17275878Sjoe	return (ptr);
17338589Sabial}
17438589Sabial
17538589Sabial
17638589Sabial#define ROUNDUP(a,size) (((a) & ((size)-1))?(1+((a)|((size)-1))):(a))
17738589Sabial
17875878Sjoe#define NEXT_SA(ap) 							\
17975878Sjoe	ap=(struct sockaddr *)						\
18075878Sjoe	    ((caddr_t)ap+(ap->sa_len?ROUNDUP(ap->sa_len,sizeof(u_long)):\
18175878Sjoe	    sizeof(u_long)))
18238589Sabial
18338589Sabialvoid
18438589Sabialget_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
18538589Sabial{
18675878Sjoe	int	i;
18775878Sjoe
18875878Sjoe	for (i = 0; i < RTAX_MAX; i++) {
18975878Sjoe		if (addrs & (1 << i)) {
19075878Sjoe			rti_info[i] = sa;
19138589Sabial			NEXT_SA(sa);
19238589Sabial		} else
19375878Sjoe			rti_info[i] = NULL;
19438589Sabial	}
19538589Sabial}
19638589Sabial
19738589Sabialvoid
19838589Sabialget_flags(char *buf, int flags)
19938589Sabial{
20075878Sjoe	if (flags & 0x1)
20175878Sjoe		strcat(buf, "U");
20275878Sjoe	if (flags & 0x2)
20375878Sjoe		strcat(buf, "G");
20475878Sjoe	if (flags & 0x4)
20575878Sjoe		strcat(buf, "H");
20675878Sjoe	if (flags & 0x8)
20775878Sjoe		strcat(buf, "r");
20875878Sjoe	if (flags & 0x10)
20975878Sjoe		strcat(buf, "d");
21075878Sjoe#ifdef NEVER
21175878Sjoe	if (flags & 0x20)
21275878Sjoe		strcat(buf, "mod,");
21375878Sjoe#endif /*NEVER*/
21475878Sjoe	if (flags & 0x100)
21575878Sjoe		strcat(buf, "C");
21675878Sjoe	if (flags & 0x400)
21775878Sjoe		strcat(buf, "L");
21875878Sjoe	if (flags & 0x800)
21975878Sjoe		strcat(buf, "S");
22075878Sjoe	if (flags & 0x10000)
22175878Sjoe		strcat(buf, "c");
22275878Sjoe	if (flags & 0x20000)
22375878Sjoe		strcat(buf, "W");
22475878Sjoe#ifdef NEVER
22575878Sjoe	if (flags & 0x200000)
22675878Sjoe		strcat(buf, ",LOC");
22775878Sjoe#endif /*NEVER*/
22875878Sjoe	if (flags & 0x400000)
22975878Sjoe		strcat(buf, "b");
23075878Sjoe#ifdef NEVER
23175878Sjoe	if (flags & 0x800000)
23275878Sjoe		strcat(buf, ",MCA");
23375878Sjoe#endif /*NEVER*/
23438589Sabial}
23538589Sabial
236191565Sluigivoid
23738745Sabialprint_routing(char *proto)
23838589Sabial{
23975878Sjoe	int	mib[6];
24075878Sjoe	int	i = 0;
24175878Sjoe	int	rt_len;
24275878Sjoe	int	if_len;
24375878Sjoe	int	if_num;
24475878Sjoe	char	*rt_buf;
24575878Sjoe	char	*if_buf;
24675878Sjoe	char	*next;
24775878Sjoe	char	*lim;
24875878Sjoe	struct	rt_msghdr *rtm;
24975878Sjoe	struct	if_msghdr *ifm;
25075878Sjoe	struct	if_msghdr **ifm_table;
25175878Sjoe	struct	ifa_msghdr *ifam;
25275878Sjoe	struct	sockaddr *sa;
25375878Sjoe	struct	sockaddr *sa1;
25475878Sjoe	struct	sockaddr *rti_info[RTAX_MAX];
25575878Sjoe	struct	sockaddr **if_table;
25675878Sjoe	struct	rt_metrics rm;
25775878Sjoe	char	fbuf[50];
25838589Sabial
25984769Sluigi	/* keep a copy of statistics here for future use */
26084769Sluigi	static unsigned *base_stats = NULL ;
26184769Sluigi	static unsigned base_len = 0 ;
26284769Sluigi
26338589Sabial	/* Get the routing table */
26475878Sjoe	mib[0] = CTL_NET;
26575878Sjoe	mib[1] = PF_ROUTE;
26675878Sjoe	mib[2] = 0;
26775878Sjoe	mib[3] = 0;
26875878Sjoe	mib[4] = NET_RT_DUMP;
26975878Sjoe	mib[5] = 0;
27075878Sjoe
27175878Sjoe	/*Estimate the size of table */
27275878Sjoe	if (sysctl(mib, 6, NULL, &rt_len, NULL, 0) == -1) {
27338589Sabial		perror("sysctl size");
27438589Sabial		exit(-1);
27538589Sabial	}
27675878Sjoe	if ((rt_buf = (char *)malloc(rt_len)) == NULL) {
27738589Sabial		perror("malloc");
27838589Sabial		exit(-1);
27938589Sabial	}
28075878Sjoe
28138589Sabial	/* Now get it. */
28275878Sjoe	if (sysctl(mib, 6, rt_buf, &rt_len, NULL, 0) == -1) {
28338589Sabial		perror("sysctl get");
28438589Sabial		exit(-1);
28538589Sabial	}
28675878Sjoe
28738589Sabial	/* Get the interfaces table */
28875878Sjoe	mib[0] = CTL_NET;
28975878Sjoe	mib[1] = PF_ROUTE;
29075878Sjoe	mib[2] = 0;
29175878Sjoe	mib[3] = 0;
29275878Sjoe	mib[4] = NET_RT_IFLIST;
29375878Sjoe	mib[5] = 0;
29475878Sjoe
29538589Sabial	/* Estimate the size of table */
29675878Sjoe	if (sysctl(mib, 6, NULL, &if_len, NULL, 0) == -1) {
29738589Sabial		perror("sysctl size");
29838589Sabial		exit(-1);
29938589Sabial	}
30075878Sjoe	if ((if_buf = (char *)malloc(if_len)) == NULL) {
30138589Sabial		perror("malloc");
30238589Sabial		exit(-1);
30338589Sabial	}
30475878Sjoe
30538589Sabial	/* Now get it. */
30675878Sjoe	if (sysctl(mib, 6, if_buf, &if_len, NULL, 0) == -1) {
30738589Sabial		perror("sysctl get");
30838589Sabial		exit(-1);
30938589Sabial	}
31075878Sjoe	lim = if_buf + if_len;
31175878Sjoe	i = 0;
31275878Sjoe	for (next = if_buf, i = 0; next < lim; next += ifm->ifm_msglen) {
31375878Sjoe		ifm = (struct if_msghdr *)next;
31438589Sabial		i++;
31538589Sabial	}
31675878Sjoe	if_num = i;
31775878Sjoe	if_table = (struct sockaddr **)calloc(i, sizeof(struct sockaddr));
31875878Sjoe	ifm_table = (struct if_msghdr **)calloc(i, sizeof(struct if_msghdr));
31938745Sabial	if (iflag) {
32075878Sjoe		printf("\nInterface table:\n");
32175878Sjoe		printf("----------------\n");
32275878Sjoe		printf("Name  Mtu   Network       Address            "
32338745Sabial		    "Ipkts Ierrs    Opkts Oerrs  Coll\n");
32450186Sdwhite	}
32584769Sluigi        /* scan the list and store base values */
32684769Sluigi	i = 0 ;
32784769Sluigi	for (next = if_buf; next < lim; next += ifm->ifm_msglen) {
32884769Sluigi		ifm = (struct if_msghdr *)next;
32984769Sluigi		i++ ;
33084769Sluigi	}
33184769Sluigi	if (base_stats == NULL || i != base_len) {
33284769Sluigi		base_stats = calloc(i*5, sizeof(unsigned));
33384769Sluigi		base_len = i ;
33484769Sluigi	}
33575878Sjoe	i = 0;
33675878Sjoe	for (next = if_buf; next < lim; next += ifm->ifm_msglen) {
33775878Sjoe		ifm = (struct if_msghdr *)next;
33875878Sjoe		if_table[i] = (struct sockaddr *)(ifm + 1);
33975878Sjoe		ifm_table[i] = ifm;
34038745Sabial
34138745Sabial		sa = if_table[i];
34250186Sdwhite		if (iflag && sa->sa_family == AF_LINK) {
34375878Sjoe			struct	sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
34484769Sluigi			unsigned *bp = &base_stats[i*5];
34538745Sabial
34675878Sjoe			printf("%-4s  %-5d <Link>   ",
34775878Sjoe			    sock_ntop(if_table[i], if_table[i]->sa_len),
34875878Sjoe			    ifm->ifm_data.ifi_mtu);
34975878Sjoe			if (sdl->sdl_alen == 6) {
35075878Sjoe				unsigned char *p =
35175878Sjoe				    sdl->sdl_data + sdl->sdl_nlen;
35275878Sjoe				printf("%02x:%02x:%02x:%02x:%02x:%02x   ",
35375878Sjoe				    p[0], p[1], p[2], p[3], p[4], p[5]);
35475878Sjoe			} else
35575878Sjoe				printf("                    ");
35675878Sjoe			printf("%9d%6d%9d%6d%6d\n",
35784769Sluigi			    ifm->ifm_data.ifi_ipackets - bp[0],
35884769Sluigi			    ifm->ifm_data.ifi_ierrors - bp[1],
35984769Sluigi			    ifm->ifm_data.ifi_opackets - bp[2],
36084769Sluigi			    ifm->ifm_data.ifi_oerrors - bp[3],
36184769Sluigi			    ifm->ifm_data.ifi_collisions -bp[4]);
36284769Sluigi			if (delta > 0) {
36384769Sluigi			    bp[0] = ifm->ifm_data.ifi_ipackets ;
36484769Sluigi			    bp[1] = ifm->ifm_data.ifi_ierrors ;
36584769Sluigi			    bp[2] = ifm->ifm_data.ifi_opackets ;
36684769Sluigi			    bp[3] = ifm->ifm_data.ifi_oerrors ;
36784769Sluigi			    bp[4] = ifm->ifm_data.ifi_collisions ;
36884769Sluigi			}
36938745Sabial		}
37038589Sabial		i++;
37138589Sabial	}
37238900Sabial	if (!rflag) {
37338900Sabial		free(rt_buf);
37438900Sabial		free(if_buf);
37538900Sabial		free(if_table);
37638900Sabial		free(ifm_table);
37793287Sabial		return;
37838900Sabial	}
37975878Sjoe
38038589Sabial	/* Now dump the routing table */
38138589Sabial	printf("\nRouting table:\n");
38238589Sabial	printf("--------------\n");
38375878Sjoe	printf
38475878Sjoe	    ("Destination        Gateway            Flags       Netif  Use\n");
38575878Sjoe	lim = rt_buf + rt_len;
38675878Sjoe	for (next = rt_buf; next < lim; next += rtm->rtm_msglen) {
38775878Sjoe		rtm = (struct rt_msghdr *)next;
38875878Sjoe		sa = (struct sockaddr *)(rtm + 1);
38975878Sjoe		get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
39075878Sjoe		if ((sa = rti_info[RTAX_DST]) != NULL) {
39175878Sjoe			sprintf(fbuf, "%s", sock_ntop(sa, sa->sa_len));
39275878Sjoe			if (((sa1 = rti_info[RTAX_NETMASK]) != NULL)
39375878Sjoe			    && sa1->sa_family == 255) {
39475878Sjoe				strcat(fbuf, sock_ntop(sa1, sa1->sa_len));
39538589Sabial			}
39675878Sjoe			printf("%-19s", fbuf);
39738589Sabial		}
39875878Sjoe		if ((sa = rti_info[RTAX_GATEWAY]) != NULL) {
39975878Sjoe			printf("%-19s", sock_ntop(sa, sa->sa_len));
40038589Sabial		}
40175878Sjoe		memset(fbuf, 0, sizeof(fbuf));
40275878Sjoe		get_flags(fbuf, rtm->rtm_flags);
40375878Sjoe		printf("%-10s", fbuf);
40475878Sjoe		for (i = 0; i < if_num; i++) {
40575878Sjoe			ifm = ifm_table[i];
40675878Sjoe			if ((ifm->ifm_index == rtm->rtm_index) &&
40775878Sjoe			    (ifm->ifm_data.ifi_type > 0)) {
40875878Sjoe				sa = if_table[i];
40938589Sabial				break;
41038589Sabial			}
41138589Sabial		}
41275878Sjoe		if (ifm->ifm_type == RTM_IFINFO) {
41375878Sjoe			get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
41475878Sjoe			printf("  %s", Sock_ntop(sa, sa->sa_len));
41575878Sjoe		} else if (ifm->ifm_type == RTM_NEWADDR) {
41675878Sjoe			ifam =
41775878Sjoe			    (struct ifa_msghdr *)ifm_table[rtm->rtm_index - 1];
41875878Sjoe			sa = (struct sockaddr *)(ifam + 1);
41975878Sjoe			get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
42075878Sjoe			printf("  %s", Sock_ntop(sa, sa->sa_len));
42138589Sabial		}
422191565Sluigi		/* printf("    %u", rtm->rtm_use); */
42338589Sabial		printf("\n");
42438589Sabial	}
42538900Sabial	free(rt_buf);
42638900Sabial	free(if_buf);
42738900Sabial	free(if_table);
42838900Sabial	free(ifm_table);
42938589Sabial}
43038589Sabial
431191565Sluigivoid
432191565Sluigiprint_ip_stats(void)
43338589Sabial{
43475878Sjoe	int	mib[4];
43575878Sjoe	int	len;
43675878Sjoe	struct	ipstat s;
43738589Sabial
43875878Sjoe	mib[0] = CTL_NET;
43975878Sjoe	mib[1] = PF_INET;
44075878Sjoe	mib[2] = IPPROTO_IP;
44138745Sabial#ifndef IPCTL_STATS
44238745Sabial	printf("sorry, ip stats not available\n");
44375878Sjoe	return -1;
44438745Sabial#else
44575878Sjoe	mib[3] = IPCTL_STATS;
44675878Sjoe	len = sizeof(struct ipstat);
44775878Sjoe	if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) {
44838589Sabial		perror("sysctl");
449191565Sluigi		return;
45038589Sabial	}
45138589Sabial	printf("\nIP statistics:\n");
45238589Sabial	printf("--------------\n");
45375878Sjoe	printf("  %10lu total packets received\n", s.ips_total);
45438589Sabial	printf("* Packets ok:\n");
45575878Sjoe	printf("  %10lu fragments received\n", s.ips_fragments);
45675878Sjoe	printf("  %10lu forwarded\n", s.ips_forward);
45738746Sabial#if __FreeBSD_version > 300001
45875878Sjoe	printf("  %10lu fast forwarded\n", s.ips_fastforward);
45938745Sabial#endif
46075878Sjoe	printf("  %10lu forwarded on same net (redirect)\n",
46175878Sjoe	    s.ips_redirectsent);
46275878Sjoe	printf("  %10lu delivered to upper level\n", s.ips_delivered);
46375878Sjoe	printf("  %10lu total ip packets generated here\n", s.ips_localout);
46475878Sjoe	printf("  %10lu total packets reassembled ok\n", s.ips_reassembled);
46575878Sjoe	printf("  %10lu total datagrams successfully fragmented\n",
46675878Sjoe	    s.ips_fragmented);
46775878Sjoe	printf("  %10lu output fragments created\n", s.ips_ofragments);
46875878Sjoe	printf("  %10lu total raw IP packets generated\n", s.ips_rawout);
46938589Sabial	printf("\n* Bad packets:\n");
47075878Sjoe	printf("  %10lu bad checksum\n", s.ips_badsum);
47175878Sjoe	printf("  %10lu too short\n", s.ips_tooshort);
47275878Sjoe	printf("  %10lu not enough data (too small)\n", s.ips_toosmall);
47375878Sjoe	printf("  %10lu more data than declared in header\n", s.ips_badhlen);
47475878Sjoe	printf("  %10lu less data than declared in header\n", s.ips_badlen);
47575878Sjoe	printf("  %10lu fragments dropped (dups, no mbuf)\n",
47675878Sjoe	    s.ips_fragdropped);
47775878Sjoe	printf("  %10lu fragments timed out in reassembly\n",
47875878Sjoe	    s.ips_fragtimeout);
47975878Sjoe	printf("  %10lu received for unreachable dest.\n", s.ips_cantforward);
48075878Sjoe	printf("  %10lu unknown or unsupported protocol\n", s.ips_noproto);
48175878Sjoe	printf("  %10lu lost due to no bufs etc.\n", s.ips_odropped);
48275878Sjoe	printf("  %10lu couldn't fragment (DF set, etc.)\n", s.ips_cantfrag);
48375878Sjoe	printf("  %10lu error in IP options processing\n", s.ips_badoptions);
48475878Sjoe	printf("  %10lu dropped due to no route\n", s.ips_noroute);
48575878Sjoe	printf("  %10lu bad IP version\n", s.ips_badvers);
48675878Sjoe	printf("  %10lu too long (more than max IP size)\n", s.ips_toolong);
48738746Sabial#if __FreeBSD_version > 300001
48875878Sjoe	printf("  %10lu multicast for unregistered groups\n", s.ips_notmember);
48938745Sabial#endif
49038745Sabial#endif
49138589Sabial}
49238589Sabial
493191565Sluigivoid
494191565Sluigiprint_tcp_stats(void)
49538589Sabial{
49675878Sjoe	int	mib[4];
49775878Sjoe	int	len;
49875878Sjoe	struct	tcpstat s;
49938589Sabial
50075878Sjoe	mib[0] = CTL_NET;
50175878Sjoe	mib[1] = PF_INET;
50275878Sjoe	mib[2] = IPPROTO_TCP;
50338745Sabial#ifndef TCPCTL_STATS
50438745Sabial	printf("sorry, tcp stats not available\n");
505191565Sluigi	return;
50638745Sabial#else
50775878Sjoe	mib[3] = TCPCTL_STATS;
50875878Sjoe	len = sizeof(struct tcpstat);
50975878Sjoe	if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) {
51038589Sabial		perror("sysctl");
511191565Sluigi		return;
51238589Sabial	}
51338589Sabial	printf("\nTCP statistics:\n");
51438589Sabial	printf("---------------\n");
51538589Sabial	printf("* Connections:\n");
51675878Sjoe	printf("  %10lu initiated\n", s.tcps_connattempt);
51775878Sjoe	printf("  %10lu accepted\n", s.tcps_accepts);
51875878Sjoe	printf("  %10lu established\n", s.tcps_connects);
51975878Sjoe	printf("  %10lu dropped\n", s.tcps_drops);
52075878Sjoe	printf("  %10lu embryonic connections dropped\n", s.tcps_conndrops);
52175878Sjoe	printf("  %10lu closed (includes dropped)\n", s.tcps_closed);
52275878Sjoe	printf("  %10lu segments where we tried to get RTT\n",
52375878Sjoe	    s.tcps_segstimed);
52475878Sjoe	printf("  %10lu times RTT successfully updated\n", s.tcps_rttupdated);
52575878Sjoe	printf("  %10lu delayed ACKs sent\n", s.tcps_delack);
52675878Sjoe	printf("  %10lu dropped in rxmt timeout\n", s.tcps_timeoutdrop);
52775878Sjoe	printf("  %10lu retrasmit timeouts\n", s.tcps_rexmttimeo);
52875878Sjoe	printf("  %10lu persist timeouts\n", s.tcps_persisttimeo);
52975878Sjoe	printf("  %10lu keepalive timeouts\n", s.tcps_keeptimeo);
53075878Sjoe	printf("  %10lu keepalive probes sent\n", s.tcps_keepprobe);
53175878Sjoe	printf("  %10lu dropped in keepalive\n", s.tcps_keepdrops);
53238589Sabial
53338589Sabial	printf("* Packets sent:\n");
53475878Sjoe	printf("  %10lu total packets sent\n", s.tcps_sndtotal);
53575878Sjoe	printf("  %10lu data packets sent\n", s.tcps_sndpack);
53675878Sjoe	printf("  %10lu data bytes sent\n", s.tcps_sndbyte);
53775878Sjoe	printf("  %10lu data packets retransmitted\n", s.tcps_sndrexmitpack);
53875878Sjoe	printf("  %10lu data bytes retransmitted\n", s.tcps_sndrexmitbyte);
53975878Sjoe	printf("  %10lu ACK-only packets sent\n", s.tcps_sndacks);
54075878Sjoe	printf("  %10lu window probes sent\n", s.tcps_sndprobe);
54175878Sjoe	printf("  %10lu URG-only packets sent\n", s.tcps_sndurg);
54275878Sjoe	printf("  %10lu window update-only packets sent\n", s.tcps_sndwinup);
54375878Sjoe	printf("  %10lu control (SYN,FIN,RST) packets sent\n", s.tcps_sndctrl);
54438589Sabial	printf("* Packets received:\n");
54575878Sjoe	printf("  %10lu total packets received\n", s.tcps_rcvtotal);
54675878Sjoe	printf("  %10lu packets in sequence\n", s.tcps_rcvpack);
54775878Sjoe	printf("  %10lu bytes in sequence\n", s.tcps_rcvbyte);
54875878Sjoe	printf("  %10lu packets with bad checksum\n", s.tcps_rcvbadsum);
54975878Sjoe	printf("  %10lu packets with bad offset\n", s.tcps_rcvbadoff);
55075878Sjoe	printf("  %10lu packets too short\n", s.tcps_rcvshort);
55175878Sjoe	printf("  %10lu duplicate-only packets\n", s.tcps_rcvduppack);
55275878Sjoe	printf("  %10lu duplicate-only bytes\n", s.tcps_rcvdupbyte);
55375878Sjoe	printf("  %10lu packets with some duplicate data\n",
55475878Sjoe	    s.tcps_rcvpartduppack);
55575878Sjoe	printf("  %10lu duplicate bytes in partially dup. packets\n",
55675878Sjoe	    s.tcps_rcvpartdupbyte);
55775878Sjoe	printf("  %10lu out-of-order packets\n", s.tcps_rcvoopack);
55875878Sjoe	printf("  %10lu out-of-order bytes\n", s.tcps_rcvoobyte);
55975878Sjoe	printf("  %10lu packets with data after window\n",
56075878Sjoe	    s.tcps_rcvpackafterwin);
56175878Sjoe	printf("  %10lu bytes received after window\n",
56275878Sjoe	    s.tcps_rcvbyteafterwin);
56375878Sjoe	printf("  %10lu packets received after 'close'\n",
56475878Sjoe	    s.tcps_rcvafterclose);
56575878Sjoe	printf("  %10lu window probe packets\n", s.tcps_rcvwinprobe);
56675878Sjoe	printf("  %10lu duplicate ACKs\n", s.tcps_rcvdupack);
56775878Sjoe	printf("  %10lu ACKs for unsent data\n", s.tcps_rcvacktoomuch);
56875878Sjoe	printf("  %10lu ACK packets\n", s.tcps_rcvackpack);
56975878Sjoe	printf("  %10lu bytes ACKed by received ACKs\n", s.tcps_rcvackbyte);
57075878Sjoe	printf("  %10lu window update packets\n", s.tcps_rcvwinupd);
57175878Sjoe	printf("  %10lu segments dropped due to PAWS\n", s.tcps_pawsdrop);
57275878Sjoe	printf("  %10lu times header predict ok for ACKs\n", s.tcps_predack);
57375878Sjoe	printf("  %10lu times header predict ok for data packets\n",
57475878Sjoe	    s.tcps_preddat);
57575878Sjoe	printf("  %10lu PCB cache misses\n", s.tcps_pcbcachemiss);
57675878Sjoe	printf("  %10lu times cached RTT in route updated\n",
57775878Sjoe	    s.tcps_cachedrtt);
57875878Sjoe	printf("  %10lu times cached RTTVAR updated\n", s.tcps_cachedrttvar);
57975878Sjoe	printf("  %10lu times ssthresh updated\n", s.tcps_cachedssthresh);
58075878Sjoe	printf("  %10lu times RTT initialized from route\n", s.tcps_usedrtt);
58175878Sjoe	printf("  %10lu times RTTVAR initialized from route\n",
58275878Sjoe	    s.tcps_usedrttvar);
58375878Sjoe	printf("  %10lu times ssthresh initialized from route\n",
58475878Sjoe	    s.tcps_usedssthresh);
58575878Sjoe	printf("  %10lu timeout in persist state\n", s.tcps_persistdrop);
58675878Sjoe	printf("  %10lu bogus SYN, e.g. premature ACK\n", s.tcps_badsyn);
58775878Sjoe	printf("  %10lu resends due to MTU discovery\n", s.tcps_mturesent);
58875878Sjoe	printf("  %10lu listen queue overflows\n", s.tcps_listendrop);
58938745Sabial#endif
59038589Sabial}
59138589Sabial
592191565Sluigivoid
593191565Sluigiprint_udp_stats(void)
59438589Sabial{
59575878Sjoe	int	mib[4];
59675878Sjoe	int	len;
59775878Sjoe	struct	udpstat s;
59838589Sabial
59975878Sjoe	mib[0] = CTL_NET;
60075878Sjoe	mib[1] = PF_INET;
60175878Sjoe	mib[2] = IPPROTO_UDP;
60275878Sjoe	mib[3] = UDPCTL_STATS;
60375878Sjoe	len = sizeof(struct udpstat);
60475878Sjoe	if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) {
60538589Sabial		perror("sysctl");
606191565Sluigi		return;
60738589Sabial	}
60838589Sabial	printf("\nUDP statistics:\n");
60938589Sabial	printf("---------------\n");
61038589Sabial	printf("* Packets received:\n");
61175878Sjoe	printf("  %10lu total input packets\n", s.udps_ipackets);
61275878Sjoe	printf("  %10lu packets shorter than header (dropped)\n",
61375878Sjoe	    s.udps_hdrops);
61475878Sjoe	printf("  %10lu bad checksum\n", s.udps_badsum);
61575878Sjoe	printf("  %10lu data length larger than packet\n", s.udps_badlen);
61675878Sjoe	printf("  %10lu no socket on specified port\n", s.udps_noport);
61775878Sjoe	printf("  %10lu of above, arrived as broadcast\n", s.udps_noportbcast);
61875878Sjoe	printf("  %10lu not delivered, input socket full\n", s.udps_fullsock);
61975878Sjoe	printf("  %10lu packets missing PCB cache\n", s.udpps_pcbcachemiss);
62075878Sjoe	printf("  %10lu packets not for hashed PCBs\n", s.udpps_pcbhashmiss);
62138589Sabial	printf("* Packets sent:\n");
62275878Sjoe	printf("  %10lu total output packets\n", s.udps_opackets);
62338746Sabial#if __FreeBSD_version > 300001
62475878Sjoe	printf("  %10lu output packets on fast path\n", s.udps_fastout);
62538745Sabial#endif
62638589Sabial}
62738589Sabial
62875878Sjoechar *icmp_names[] = {
62938589Sabial	"echo reply",
63038589Sabial	"#1",
63138589Sabial	"#2",
63238589Sabial	"destination unreachable",
63338589Sabial	"source quench",
63438589Sabial	"routing redirect",
63538589Sabial	"#6",
63638589Sabial	"#7",
63738589Sabial	"echo",
63838589Sabial	"router advertisement",
63938589Sabial	"router solicitation",
64038589Sabial	"time exceeded",
64138589Sabial	"parameter problem",
64238589Sabial	"time stamp",
64338589Sabial	"time stamp reply",
64438589Sabial	"information request",
64538589Sabial	"information request reply",
64638589Sabial	"address mask request",
64738589Sabial	"address mask reply",
64838589Sabial};
64938589Sabial
65038589Sabialprint_icmp_stats()
65138589Sabial{
65275878Sjoe	int	mib[4];
65375878Sjoe	int	len;
65475878Sjoe	int	i;
65575878Sjoe	struct	icmpstat s;
65638589Sabial
65775878Sjoe	mib[0] = CTL_NET;
65875878Sjoe	mib[1] = PF_INET;
65975878Sjoe	mib[2] = IPPROTO_ICMP;
66075878Sjoe	mib[3] = ICMPCTL_STATS;
66175878Sjoe	len = sizeof(struct icmpstat);
66275878Sjoe	if (sysctl(mib, 4, &s, &len, NULL, 0) < 0) {
66338589Sabial		perror("sysctl");
66475878Sjoe		return (-1);
66538589Sabial	}
66638589Sabial	printf("\nICMP statistics:\n");
66738589Sabial	printf("----------------\n");
66838589Sabial	printf("* Output histogram:\n");
66975878Sjoe	for (i = 0; i < (ICMP_MAXTYPE + 1); i++) {
67075878Sjoe		if (s.icps_outhist[i] > 0)
67138589Sabial			printf("\t%10lu %s\n",
67275878Sjoe			    s.icps_outhist[i], icmp_names[i]);
67338589Sabial	}
67438589Sabial	printf("* Input histogram:\n");
67575878Sjoe	for (i = 0; i < (ICMP_MAXTYPE + 1); i++) {
67675878Sjoe		if (s.icps_inhist[i] > 0)
67738589Sabial			printf("\t%10lu %s\n",
67875878Sjoe			    s.icps_inhist[i], icmp_names[i]);
67938589Sabial	}
68038589Sabial	printf("* Other stats:\n");
68175878Sjoe	printf("  %10lu calls to icmp_error\n", s.icps_error);
68275878Sjoe	printf("  %10lu no error 'cuz old ip too short\n", s.icps_oldshort);
68375878Sjoe	printf("  %10lu no error 'cuz old was icmp\n", s.icps_oldicmp);
68438589Sabial
68575878Sjoe	printf("  %10lu icmp code out of range\n", s.icps_badcode);
68675878Sjoe	printf("  %10lu packets shorter than min length\n", s.icps_tooshort);
68775878Sjoe	printf("  %10lu bad checksum\n", s.icps_checksum);
68875878Sjoe	printf("  %10lu calculated bound mismatch\n", s.icps_badlen);
68975878Sjoe	printf("  %10lu number of responses\n", s.icps_reflect);
69075878Sjoe	printf("  %10lu broad/multi-cast echo requests dropped\n",
69175878Sjoe	    s.icps_bmcastecho);
69275878Sjoe	printf("  %10lu broad/multi-cast timestamp requests dropped\n",
69375878Sjoe	    s.icps_bmcasttstamp);
69438589Sabial}
69538589Sabial
69638589Sabialint
69738589Sabialstats(char *proto)
69838589Sabial{
69938745Sabial	if (!sflag)
70075878Sjoe		return 0;
70175878Sjoe	if (pflag) {
70275878Sjoe		if (proto == NULL) {
70375878Sjoe			fprintf(stderr, "Option '-p' requires paramter.\n");
70438589Sabial			usage();
70538589Sabial			exit(-1);
70638589Sabial		}
70775878Sjoe		if (strcmp(proto, "ip") == 0)
70875878Sjoe			print_ip_stats();
70975878Sjoe		if (strcmp(proto, "icmp") == 0)
71075878Sjoe			print_icmp_stats();
71175878Sjoe		if (strcmp(proto, "udp") == 0)
71275878Sjoe			print_udp_stats();
71375878Sjoe		if (strcmp(proto, "tcp") == 0)
71475878Sjoe			print_tcp_stats();
71575878Sjoe		return (0);
71638589Sabial	}
71738589Sabial	print_ip_stats();
71838589Sabial	print_icmp_stats();
71938589Sabial	print_udp_stats();
72038589Sabial	print_tcp_stats();
72175878Sjoe	return (0);
72238589Sabial}
72338589Sabial
72438589Sabialint
72538589Sabialmain(int argc, char *argv[])
72638589Sabial{
72775878Sjoe	char	c;
72875878Sjoe	char	*proto = NULL;
72938589Sabial
73075878Sjoe	progname = argv[0];
73138589Sabial
73287832Sluigi	while ((c = getopt(argc, argv, "dilnrsp:w:")) != -1) {
73375878Sjoe		switch (c) {
73484769Sluigi		case 'd': /* print deltas in stats every w seconds */
73584769Sluigi			delta++ ;
73684769Sluigi			break;
73738900Sabial		case 'w':
73875878Sjoe			wflag = atoi(optarg);
73938900Sabial			break;
74075876Sjoe		case 'n': /* ignored, just for compatibility with std netstat */
74175876Sjoe			break;
74238589Sabial		case 'r':
74338589Sabial			rflag++;
74438589Sabial			break;
74538745Sabial		case 'i':
74638745Sabial			iflag++;
74738745Sabial			break;
74887832Sluigi		case 'l':
74987832Sluigi			lflag++;
75087832Sluigi			break;
75138589Sabial		case 's':
75238589Sabial			sflag++;
75375878Sjoe			rflag = 0;
75438589Sabial			break;
75538589Sabial		case 'p':
75638589Sabial			pflag++;
75738745Sabial			sflag++;
75875878Sjoe			proto = optarg;
75938589Sabial			break;
76038589Sabial		case '?':
76138589Sabial		default:
76238589Sabial			usage();
76338589Sabial			exit(0);
76438589Sabial			break;
76538589Sabial		}
76638589Sabial	}
76738745Sabial	if (rflag == 0 && sflag == 0 && iflag == 0)
76875878Sjoe		rflag = 1;
76975878Sjoe	argc -= optind;
77075878Sjoe
77175878Sjoe	if (argc > 0) {
77238589Sabial		usage();
77338589Sabial		exit(-1);
77438589Sabial	}
77538900Sabial	if (wflag)
77675878Sjoe		printf("\033[H\033[J");
77738900Sabialagain:
77838900Sabial	if (wflag) {
77975878Sjoe		struct timeval t;
78075878Sjoe
78175878Sjoe		gettimeofday(&t, NULL);
78275878Sjoe		printf("\033[H%s", ctime(&t.tv_sec));
78338900Sabial	}
78438745Sabial	print_routing(proto);
78587832Sluigi	print_load_stats();
78638745Sabial	stats(proto);
78738900Sabial	if (wflag) {
78838900Sabial		sleep(wflag);
78975878Sjoe		goto again;
79038900Sabial	}
79138589Sabial	exit(0);
79238589Sabial}
79338745Sabial
794191565Sluigivoid
79587832Sluigiprint_load_stats(void)
79687832Sluigi{
79787832Sluigi	static u_int32_t cp_time[5];
79887832Sluigi	u_int32_t new_cp_time[5];
79987832Sluigi	int l;
80087832Sluigi	int shz;
80187832Sluigi	static int stathz ;
80287832Sluigi
80387832Sluigi	if (!lflag || !wflag)
804191565Sluigi		return;
80587832Sluigi	l = sizeof(new_cp_time) ;
80687832Sluigi	bzero(new_cp_time, l);
80787832Sluigi	if (sysctlbyname("kern.cp_time", new_cp_time, &l, NULL, 0) < 0) {
80887832Sluigi		warn("sysctl: retrieving cp_time length");
809191565Sluigi		return;
81087832Sluigi	}
81187832Sluigi	if (stathz == 0) {
81287832Sluigi		struct clockinfo ci;
81387832Sluigi
81487832Sluigi		bzero (&ci, sizeof(ci));
81587832Sluigi		l = sizeof(ci) ;
81687832Sluigi		if (sysctlbyname("kern.clockrate", &ci, &l, NULL, 0) < 0) {
81787832Sluigi			warn("sysctl: retrieving clockinfo length");
818191565Sluigi			return;
81987832Sluigi		}
82087832Sluigi		stathz = ci.stathz ;
82187832Sluigi		bcopy(new_cp_time, cp_time, sizeof(cp_time));
82287832Sluigi	}
82387832Sluigi	shz = stathz * wflag ;
82487832Sluigi	if (shz == 0)
82587832Sluigi		shz = 1;
82687832Sluigi#define X(i)   ( (double)(new_cp_time[i] - cp_time[i])*100/shz )
82787832Sluigi	printf("\nUSER %5.2f%% NICE %5.2f%% SYS %5.2f%% "
82887832Sluigi			"INTR %5.2f%% IDLE %5.2f%%\n",
82987832Sluigi		X(0), X(1), X(2), X(3), X(4) );
83087832Sluigi	bcopy(new_cp_time, cp_time, sizeof(cp_time));
831191565Sluigi}
832