/*
 * Name: knstat for OpenBSD
 * Date: Mon Feb 28 21:38:57 2000
 * Author: pIGpEN [pigpen@s0ftpj.org, deadhead@sikurezza.org]
 *
 * SoftProject Digital Security for Y2K
 * Sikurezza.org - Italian Security Mailinglist
 *
 * COFFEE-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by
 * Poul-Henning Kamp <phk@FreeBSD.ORG> but you can give me in return a coffee.
 *
 * Tested on: OpenBSD 2.6 kern#0 i386
 *
 * Little revision - Mar 08 2000 ( This code is very simple... ) 
 *
 * $ calendar
 *
 * Mar 08 Ron "Pigpen" McKernan (Grateful Dead) dies in California, 1973
 *
 * :(   
 * 						Let His Memory Shine!
 */

/*
 * This is a simple porting of knstat on your OpenBSD box...
 *
 * compile with: cc filename -lkvm 
 */ 

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <err.h>
#include <sysexits.h>

#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <netinet/tcp.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
#include <netinet/igmp.h>
#include <netinet/igmp_var.h>

#include <nlist.h>
#include <kvm.h>

#define		WAIT
#define		Error(s)	err(EX_UNAVAILABLE, s);
#define		E(s)		if(!strcmp(s, arg[1]))

void		usage		__P((char *));
void		print_ip	__P((kvm_t *));
void		print_udp	__P((kvm_t *));
void		print_tcp	__P((kvm_t *));
void		print_icmp	__P((kvm_t *));
void		print_igmp	__P((kvm_t *));

struct prot {
	char *name;
	void (*funct) (kvm_t *);
};
	

struct prot protos[] = {
	{ "-ip"  , print_ip   },
	{ "-udp" , print_udp  },
	{ "-tcp" , print_tcp  },
	{ "-icmp", print_icmp },
	{ "-igmp", print_igmp },
};

struct nlist list[] = {
 	{"_ipstat"},
	{"_udpstat"},
	{"_tcpstat"},
	{"_icmpstat"},
	{"_igmpstat"},
	{NULL}
};	
	
int main(int narg, char **arg)
{
	kvm_t *kd;
	int i;
	int len = sizeof(protos) / sizeof(struct prot);

	
	if(narg != 2){
		usage(arg[0]);
		exit(0);
	}

	/* Think different */
	
	for(i=0; i < len; i++) 
		E(protos[i].name) {
		  if(!(kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, NULL))) 
			Error("kvm_openfiles()");
		  if(kvm_nlist(kd, list) != 0)
			Error("kvm_nlist()");

  		  (*protos[i].funct) (kd);
		  kvm_close(kd);	
 		  return 1;	
		}

	usage(arg[0]);

	return 0; 
}

void usage(char *cmdname)
{
	printf("Usage:\n"
	       "\t%s -option\n\n"
	       "Option:   -ip\n" 
	       "          -icmp\n"
	       "          -igmp\n"
	       "          -tcp\n"
	       "          -udp\n", cmdname);
}	       



/*
 * You can cover printf() with a macro... but I'm fucking about... so
 * I have time to spend... 
 */

void print_ip(kvm_t *kd)
{
 struct ipstat i_stat;


 if(!list[0].n_value)
	Error("[print_ip] checking nlist");

 kvm_read(kd, list[0].n_value, &i_stat, sizeof i_stat);

 printf("IP Statistics\n\n");
 
 printf("\t\treceived         [ %ld ]\n", i_stat.ips_total);
 printf("\t\tbad checksum     [ %ld ]\n", i_stat.ips_badsum);
 printf("\t\tpkts too short   [ %ld ]\n", i_stat.ips_tooshort);
 printf("\t\tno enough data   [ %ld ]\n", i_stat.ips_toosmall);
 printf("\t\tiph len < data   [ %ld ]\n", i_stat.ips_badhlen);
 printf("\t\tip len < iph len [ %ld ]\n", i_stat.ips_badlen);
 printf("\t\tfragments        [ %ld ]\n", i_stat.ips_fragments);
 printf("\t\tfrags dropped    [ %ld ]\n", i_stat.ips_fragdropped);
 printf("\t\tfrags timeout    [ %ld ]\n", i_stat.ips_fragtimeout);
 printf("\t\tforwarded        [ %ld ]\n", i_stat.ips_forward);
 printf("\t\tcant forward     [ %ld ]\n", i_stat.ips_cantforward);
 printf("\t\tredirect sent    [ %ld ]\n", i_stat.ips_redirectsent);
 printf("\t\tproto unknown    [ %ld ]\n", i_stat.ips_noproto);
 printf("\t\tiplen > maxpksz  [ %ld ]\n", i_stat.ips_toolong);
 printf("\t\tip version != 4  [ %ld ]\n", i_stat.ips_badvers);
 printf("\t\ttotal raw gen    [ %ld ]\n", i_stat.ips_rawout);

}

void print_udp(kvm_t *kd)
{ 
 struct udpstat u_stat;
 

 if(!list[1].n_value)
	Error("[print_udp] checking nlist");

 kvm_read(kd, list[1].n_value, &u_stat, sizeof u_stat); 
 
 printf("UDP Statistics\n\n"); 

 printf("Total input  packets:      %ld\n", 	   u_stat.udps_ipackets);
 printf("\t\t\t\tPacket shorter than header: %ld\n", u_stat.udps_hdrops);
 printf("\t\t\t\tChecksum error:             %ld\n", u_stat.udps_badsum);
 printf("\t\t\t\tData len larger than pkt:   %ld\n", u_stat.udps_badlen);
 printf("\t\t\t\tNo socket on port:          %ld\n", u_stat.udps_noport);
 printf("\t\t\t\tArrived as broadcast:       %ld\n", u_stat.udps_noportbcast);
 printf("\t\t\t\tNot delivered:              %ld\n", u_stat.udps_fullsock);
 printf("Total ouput packets:       %ld\n\n",	   u_stat.udps_opackets);
}	

void print_tcp(kvm_t *kd)
{
 struct tcpstat t_stat;

 
 if(!list[2].n_value)
	Error("[print_tcp] checking nvalue");  
 
 kvm_read(kd, list[2].n_value, &t_stat, sizeof t_stat);

 printf("TCP Statistics\n\n");

 printf("Connection:\n");
 printf("\t\tinitiated:               [ %d ]\n", t_stat.tcps_connattempt);
 printf("\t\taccepted:                [ %d ]\n", t_stat.tcps_accepts);
 printf("\t\testabilished             [ %d ]\n", t_stat.tcps_connects);
 printf("\t\tdropped                  [ %d ]\n", t_stat.tcps_drops);
 printf("\t\tembryonic dropped        [ %d ]\n", t_stat.tcps_conndrops);
 printf("\t\tkeepalive dropped        [ %d ]\n", t_stat.tcps_keepdrops);
 printf("\t\tclosed                   [ %d ]\n", t_stat.tcps_closed);
 printf("\nTimers:\n");
 printf("\t\tsegs timed               [ %d ]\n", t_stat.tcps_segstimed);
 printf("\t\trtt updated              [ %d ]\n", t_stat.tcps_rttupdated);
 printf("\t\tdelayed acks sent        [ %d ]\n", t_stat.tcps_delack);
 printf("\t\tdropped in rxmt timeouts [ %d ]\n", t_stat.tcps_timeoutdrop);
 printf("\t\tretrasmit timeouts       [ %d ]\n", t_stat.tcps_rexmttimeo);
 printf("\t\tpersist timeouts         [ %d ]\n", t_stat.tcps_persisttimeo);
 printf("\t\tkeepalive timeouts       [ %d ]\n", t_stat.tcps_keeptimeo);
 printf("\t\tkeepalive probes sent    [ %d ]\n", t_stat.tcps_keepprobe);
#ifdef	WAIT 
 getchar();
#endif 
 printf("\nPackets\n");
 printf("\t\tsent                     [ %d ]\n", t_stat.tcps_sndtotal);
 printf("\t\tdata pkt                 [ %d ]\n", t_stat.tcps_sndpack);
 printf("\t\tdata bytes               [ %ld ]\n", 
					(long) t_stat.tcps_sndbyte);
 printf("\t\tdata pkt retrasmitted    [ %d ]\n", t_stat.tcps_sndrexmitpack);
 printf("\t\tdata bytes retrasmitted  [ %ld ]\n", 
					(long)t_stat.tcps_sndrexmitbyte);
 printf("\t\tack only pkts            [ %d ]\n", t_stat.tcps_sndacks);
 printf("\t\turg only pkts            [ %d ]\n", t_stat.tcps_sndurg);
 printf("\t\twin update only pkt      [ %d ]\n", t_stat.tcps_sndwinup);
 printf("\t\tsyn|fin|rst pkt          [ %d ]\n", t_stat.tcps_sndctrl);
 printf("\t\twindow probes            [ %d ]\n", t_stat.tcps_sndprobe);
 printf("\n\n");
#ifdef	WAIT 
 getchar();
#endif 
 printf("\t\treceived                 [ %ld ]\n", (long)
						t_stat.tcps_rcvtotal);
 printf("\t\tpkt in sequence          [ %d ]\n", t_stat.tcps_rcvpack);
 printf("\t\tbyte in sequence         [ %ld ]\n", (long) t_stat.tcps_rcvbyte);
 printf("\t\tpkt with checksum errors [ %d ]\n", t_stat.tcps_rcvbadsum);
 printf("\t\tpkt with bad offset      [ %d ]\n", t_stat.tcps_rcvbadoff);
 printf("\t\tpkt received too short   [ %d ]\n", t_stat.tcps_rcvshort);
 printf("\t\tduplicate only pkts      [ %d ]\n", t_stat.tcps_rcvduppack);
 printf("\t\tduplicate only bytes     [ %ld ]\n", 
						(long) t_stat.tcps_rcvdupbyte);
 printf("\t\tpartial duplicate data   [ %d ]\n", t_stat.tcps_rcvpartduppack);
 printf("\t\tpartial duplicate bytes  [ %ld ]\n", 
					(long) t_stat.tcps_rcvpartdupbyte);
 printf("\t\tout of order pkts        [ %d ]\n", t_stat.tcps_rcvoopack);
 printf("\t\tout of order bytes       [ %ld ]\n", 
						(long) t_stat.tcps_rcvoobyte);
 printf("\t\tpkts with data after win [ %d ]\n", t_stat.tcps_rcvpackafterwin);
 printf("\t\tbytes received after win [ %ld ]\n", 
					(long) t_stat.tcps_rcvbyteafterwin);
 printf("\t\tpkts rcvd after close    [ %d ]\n", t_stat.tcps_rcvafterclose);
 printf("\t\tpkts rcvd win probe      [ %d ]\n", t_stat.tcps_rcvwinprobe);
 printf("\t\tduplicate acks           [ %d ]\n", t_stat.tcps_rcvdupack);
 printf("\t\tacks for unsent data     [ %d ]\n", t_stat.tcps_rcvacktoomuch);
 printf("\t\tacks packets             [ %d ]\n", t_stat.tcps_rcvackpack);
 printf("\t\tbytes acked by rcvd acks [ %d ]\n", t_stat.tcps_rcvwinupd);
 printf("\t\tseg dropped due to PAWS  [ %d ]\n", t_stat.tcps_pawsdrop);
 printf("\t\tbogus syn                [ %d ]\n", t_stat.tcps_badsyn);

} 

void print_icmp(kvm_t *kd)
{
 struct icmpstat i_stat;


 if(!list[3].n_value) 
	Error("[print_icmp] checking list n_value");
 
 kvm_read(kd, list[3].n_value, &i_stat, sizeof(i_stat));  

 printf("ICMP Statistics\n");
 printf("\t\tNumber of calls to icmp_error  [ %ld ]\n", i_stat.icps_error);
 printf("\t\ticmp_code out of range         [ %ld ]\n", i_stat.icps_badcode);
 printf("\t\tpkts < ICMP_MINLEN             [ %ld ]\n", i_stat.icps_tooshort);
 printf("\t\tbad checksum                   [ %ld ]\n", i_stat.icps_checksum);
 printf("\t\tbad length                     [ %ld ]\n", i_stat.icps_badlen);
 printf("\t\tnumber of responses            [ %ld ]\n", i_stat.icps_reflect);
 printf("\t\tm/bcast echo requests dropped  [ %ld ]\n", i_stat.icps_bmcastecho);
 printf("Input Packet\n\n");
 printf("\tEcho Reply                         [ %ld ]\n",i_stat.icps_inhist[0]);
 printf("\tDestination Unreachable            [ %ld ]\n",i_stat.icps_inhist[3]); 
 printf("\tSource Quench                      [ %ld ]\n",
						i_stat.icps_inhist[4]);
 printf("\tRedirect                           [ %ld ]\n",
						i_stat.icps_inhist[5]);
 printf("\tEcho                               [ %ld ]\n",
						i_stat.icps_inhist[8]);
 printf("\tRouter Advert                      [ %ld ]\n",
						i_stat.icps_inhist[9]);
 printf("\tRouter Solicitation                [ %ld ]\n",
						i_stat.icps_inhist[10]);
 printf("\tTime Exceed                        [ %ld ]\n",
						i_stat.icps_inhist[11]);
 printf("\tTimestamp Request                  [ %ld ]\n",
						i_stat.icps_inhist[13]);
 printf("\tTimestamp Reply                    [ %ld ]\n",
						i_stat.icps_inhist[14]);
 printf("\tInformation Request                [ %ld ]\n",
						i_stat.icps_inhist[15]);
 printf("\tInformation Reply                  [ %ld ]\n",
						i_stat.icps_inhist[16]);
 printf("\tAddress Mask Request               [ %ld ]\n",
						i_stat.icps_inhist[17]);
 printf("\tAddress Mask Reply                 [ %ld ]\n",
						i_stat.icps_inhist[18]);     
#ifdef WAIT
 getchar(); 
#endif
 printf("Output Packet\n\n");
 printf("\tEcho Reply                        [ %ld ]\n",
						i_stat.icps_outhist[0]);
 printf("\tDestination Unreachable           [ %ld ]\n",
						i_stat.icps_outhist[3]); 
 printf("\tSource Quench                     [ %ld ]\n",
						i_stat.icps_outhist[4]);
 printf("\tRedirect                          [ %ld ]\n",
						i_stat.icps_outhist[5]);
 printf("\tEcho                              [ %ld ]\n",
						i_stat.icps_outhist[8]);
 printf("\tRouter Advert                     [ %ld ]\n",
						i_stat.icps_outhist[9]);
 printf("\tRouter Solicitation               [ %ld ]\n",
						i_stat.icps_outhist[10]);
 printf("\tTime Exceed                       [ %ld ]\n",
						i_stat.icps_outhist[11]);
 printf("\tTime Stamp Request                [ %ld ]\n",
						i_stat.icps_outhist[13]);
 printf("\tTime Stamp Reply                  [ %ld ]\n",
						i_stat.icps_outhist[14]);
 printf("\tInformation Request               [ %ld ]\n",
						i_stat.icps_outhist[15]);
 printf("\tInformation Reply                 [ %ld ]\n",
						i_stat.icps_outhist[16]);
 printf("\tMask Request                      [ %ld ]\n",
						i_stat.icps_outhist[17]);
 printf("\tMask Reply                        [ %ld ]\n",
						i_stat.icps_outhist[18]);
}

void print_igmp(kvm_t *kd)
{
 struct igmpstat i_stat;


 if(!list[4].n_value) 
	Error("[print_igmp] checking list nvalue");

 kvm_read(kd, list[4].n_value, (char *) &i_stat, sizeof i_stat);
	
 printf("IGMP Statistics\n\n");

 printf("\t\tmessages received       [ %ld ]\n", i_stat.igps_rcv_total);
 printf("\t\trcvd with too few bytes [ %ld ]\n", i_stat.igps_rcv_tooshort);
 printf("\t\trcvd with bad checksum  [ %ld ]\n", i_stat.igps_rcv_badsum);
 printf("\t\trcvd membership queries [ %ld ]\n", i_stat.igps_rcv_queries);
 printf("\t\trcvd invalid queries    [ %ld ]\n", i_stat.igps_rcv_badqueries);
 printf("\t\trcvd membership reports [ %ld ]\n", i_stat.igps_rcv_reports);
 printf("\t\trcvd invalid reports    [ %ld ]\n", i_stat.igps_rcv_badreports);
 printf("\t\trcvd rep. for our grps  [ %ld ]\n", i_stat.igps_rcv_ourreports);
 printf("\t\tsent membership reports [ %ld ]\n", i_stat.igps_snd_reports);
}
