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