npfstream.c revision 1.3 1 /* $NetBSD: npfstream.c,v 1.3 2012/08/12 03:35:14 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, 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 %12lx",
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