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