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