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