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