NetBSD/usr.sbin/npf/npftest/npfstream.c
rmind a79812ea10 NPF: add support for specifying the interfaces before they are attached.
If an interface is or gets detached, all associated rules and connections
will be deactivated (it might be useful to have an option to invalidate
the associated connections).  Once the interface is reattached they will
become active.

Bump NPF_VERSION.
2013-11-08 00:38:26 +00:00

121 lines
2.8 KiB
C

/* $NetBSD: npfstream.c,v 1.6 2013/11/08 00:38:26 rmind Exp $ */
/*
* NPF stream processor.
*
* Public Domain.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#include <err.h>
#include <pcap.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/ethertypes.h>
#include <net/if_ether.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <rump/rump.h>
#include "npftest.h"
static struct in_addr initial_ip;
static int snd_packet_no = 0;
static int rcv_packet_no = 0;
static void
process_tcpip(const void *data, size_t len, FILE *fp, ifnet_t *ifp)
{
const struct ether_header *eth = data;
const struct ip *ip;
const struct tcphdr *th;
unsigned hlen, tcpdlen;
int error, packetno;
tcp_seq seq;
bool forw;
if (ntohs(eth->ether_type) != ETHERTYPE_IP) {
ip = (const struct ip *)((const char *)data + 4);
} else {
ip = (const struct ip *)(eth + 1);
}
hlen = ip->ip_hl << 2;
th = (const struct tcphdr *)((const uint8_t *)ip + hlen);
tcpdlen = ntohs(ip->ip_len) - hlen - (th->th_off << 2);
if (th->th_flags & TH_SYN) {
tcpdlen++;
}
if (th->th_flags & TH_FIN) {
tcpdlen++;
}
seq = ntohl(th->th_seq);
if (snd_packet_no == 0) {
memcpy(&initial_ip, &ip->ip_src, sizeof(struct in_addr));
}
forw = (initial_ip.s_addr == ip->ip_src.s_addr);
packetno = forw ? ++snd_packet_no : ++rcv_packet_no;
int64_t result[11];
memset(result, 0, sizeof(result));
len = ntohs(ip->ip_len);
error = rumpns_npf_test_statetrack(ip, len, ifp, forw, result);
fprintf(fp, "%s%2x %5d %3d %11u %11u %11u %11u %12" PRIxPTR,
forw ? ">" : "<", (th->th_flags & (TH_SYN | TH_ACK | TH_FIN)),
packetno, error, (u_int)seq, (u_int)ntohl(th->th_ack),
tcpdlen, ntohs(th->th_win), (uintptr_t)result[0]);
for (unsigned i = 1; i < __arraycount(result); i++) {
fprintf(fp, "%11" PRIu64 " ", result[i]);
}
fputs("\n", fp);
}
int
process_stream(const char *input, const char *output, ifnet_t *ifp)
{
pcap_t *pcap;
char pcap_errbuf[PCAP_ERRBUF_SIZE];
struct pcap_pkthdr *phdr;
const uint8_t *data;
FILE *fp;
pcap = pcap_open_offline(input, pcap_errbuf);
if (pcap == NULL) {
errx(EXIT_FAILURE, "pcap_open_offline failed: %s", pcap_errbuf);
}
fp = output ? fopen(output, "w") : stdout;
if (fp == NULL) {
err(EXIT_FAILURE, "fopen");
}
fprintf(fp, "#FL %5s %3s %11s %11s %11s %11s %11s %11s %11s "
"%11s %11s %11s %5s %11s %11s %11s %5s\n",
"No", "Err", "Seq", "Ack", "TCP Len", "Win",
"Stream", "RetVal", "State",
"F.END", "F.MAXEND", "F.MAXWIN", "F.WSC",
"T.END", "T.MAXEND", "T.MAXWIN", "T.WSC");
while (pcap_next_ex(pcap, &phdr, &data) > 0) {
if (phdr->len != phdr->caplen) {
warnx("process_stream: truncated packet");
}
process_tcpip(data, phdr->caplen, fp, ifp);
}
pcap_close(pcap);
fclose(fp);
return 0;
}