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