Home | History | Annotate | Line # | Download | only in npftest
npfstream.c revision 1.6
      1 /*	$NetBSD: npfstream.c,v 1.6 2013/11/08 00:38:26 rmind Exp $	*/
      2 
      3 /*
      4  * NPF stream processor.
      5  *
      6  * Public Domain.
      7  */
      8 
      9 #include <stdio.h>
     10 #include <stdlib.h>
     11 #include <stdbool.h>
     12 #include <string.h>
     13 #include <inttypes.h>
     14 #include <err.h>
     15 #include <pcap.h>
     16 
     17 #include <arpa/inet.h>
     18 
     19 #include <net/if.h>
     20 #include <net/ethertypes.h>
     21 #include <net/if_ether.h>
     22 #include <netinet/in_systm.h>
     23 #include <netinet/ip.h>
     24 #include <netinet/ip.h>
     25 #include <netinet/tcp.h>
     26 
     27 #include <rump/rump.h>
     28 
     29 #include "npftest.h"
     30 
     31 static struct in_addr	initial_ip;
     32 static int		snd_packet_no = 0;
     33 static int		rcv_packet_no = 0;
     34 
     35 static void
     36 process_tcpip(const void *data, size_t len, FILE *fp, ifnet_t *ifp)
     37 {
     38 	const struct ether_header *eth = data;
     39 	const struct ip *ip;
     40 	const struct tcphdr *th;
     41 	unsigned hlen, tcpdlen;
     42 	int error, packetno;
     43 	tcp_seq seq;
     44 	bool forw;
     45 
     46 	if (ntohs(eth->ether_type) != ETHERTYPE_IP) {
     47 		ip = (const struct ip *)((const char *)data + 4);
     48 	} else {
     49 		ip = (const struct ip *)(eth + 1);
     50 	}
     51 	hlen = ip->ip_hl << 2;
     52 	th = (const struct tcphdr *)((const uint8_t *)ip + hlen);
     53 
     54 	tcpdlen = ntohs(ip->ip_len) - hlen - (th->th_off << 2);
     55 	if (th->th_flags & TH_SYN) {
     56 		tcpdlen++;
     57 	}
     58 	if (th->th_flags & TH_FIN) {
     59 		tcpdlen++;
     60 	}
     61 	seq = ntohl(th->th_seq);
     62 
     63 	if (snd_packet_no == 0) {
     64 		memcpy(&initial_ip, &ip->ip_src, sizeof(struct in_addr));
     65 	}
     66 
     67 	forw = (initial_ip.s_addr == ip->ip_src.s_addr);
     68 	packetno = forw ? ++snd_packet_no : ++rcv_packet_no;
     69 
     70 	int64_t result[11];
     71 	memset(result, 0, sizeof(result));
     72 
     73 	len = ntohs(ip->ip_len);
     74 	error = rumpns_npf_test_statetrack(ip, len, ifp, forw, result);
     75 
     76 	fprintf(fp, "%s%2x %5d %3d %11u %11u %11u %11u %12" PRIxPTR,
     77 	    forw ? ">" : "<", (th->th_flags & (TH_SYN | TH_ACK | TH_FIN)),
     78 	    packetno, error, (u_int)seq, (u_int)ntohl(th->th_ack),
     79 	    tcpdlen, ntohs(th->th_win), (uintptr_t)result[0]);
     80 
     81 	for (unsigned i = 1; i < __arraycount(result); i++) {
     82 		fprintf(fp, "%11" PRIu64 " ", result[i]);
     83 	}
     84 	fputs("\n", fp);
     85 }
     86 
     87 int
     88 process_stream(const char *input, const char *output, ifnet_t *ifp)
     89 {
     90 	pcap_t *pcap;
     91 	char pcap_errbuf[PCAP_ERRBUF_SIZE];
     92 	struct pcap_pkthdr *phdr;
     93 	const uint8_t *data;
     94 	FILE *fp;
     95 
     96 	pcap = pcap_open_offline(input, pcap_errbuf);
     97 	if (pcap == NULL) {
     98 		errx(EXIT_FAILURE, "pcap_open_offline failed: %s", pcap_errbuf);
     99 	}
    100 	fp = output ? fopen(output, "w") : stdout;
    101 	if (fp == NULL) {
    102 		err(EXIT_FAILURE, "fopen");
    103 	}
    104 	fprintf(fp, "#FL %5s %3s %11s %11s %11s %11s %11s %11s %11s "
    105 	    "%11s %11s %11s %5s %11s %11s %11s %5s\n",
    106 	    "No", "Err", "Seq", "Ack", "TCP Len", "Win",
    107 	    "Stream", "RetVal", "State",
    108 	    "F.END", "F.MAXEND", "F.MAXWIN", "F.WSC",
    109 	    "T.END", "T.MAXEND", "T.MAXWIN", "T.WSC");
    110 	while (pcap_next_ex(pcap, &phdr, &data) > 0) {
    111 		if (phdr->len != phdr->caplen) {
    112 			warnx("process_stream: truncated packet");
    113 		}
    114 		process_tcpip(data, phdr->caplen, fp, ifp);
    115 	}
    116 	pcap_close(pcap);
    117 	fclose(fp);
    118 
    119 	return 0;
    120 }
    121