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