xref: /netbsd-src/usr.sbin/npf/npftest/npfstream.c (revision a536ee5124e62c9a0051a252f7833dc8f50f44c9)
1 /*	$NetBSD: npfstream.c,v 1.4 2012/09/12 16:26:02 martin 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, unsigned idx)
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_handlepkt(ip, len, idx, 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, unsigned idx)
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, idx);
115 	}
116 	pcap_close(pcap);
117 	fclose(fp);
118 
119 	return 0;
120 }
121