diff --git a/usr.sbin/npf/npftest/libnpftest/Makefile b/usr.sbin/npf/npftest/libnpftest/Makefile index 63177254b104..de19f6b6166c 100644 --- a/usr.sbin/npf/npftest/libnpftest/Makefile +++ b/usr.sbin/npf/npftest/libnpftest/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.2 2012/05/30 21:38:04 rmind Exp $ +# $NetBSD: Makefile,v 1.3 2012/06/04 00:28:34 rmind Exp $ # # Public Domain # @@ -14,6 +14,7 @@ SRCS+= npf_mbuf_subr.c SRCS+= npf_nbuf_test.c SRCS+= npf_processor_test.c SRCS+= npf_table_test.c +SRCS+= npf_state_test.c CPPFLAGS+= -D_NPF_TESTING CPPFLAGS+= -I${.CURDIR}/../../../../sys/net/npf diff --git a/usr.sbin/npf/npftest/libnpftest/npf_state_test.c b/usr.sbin/npf/npftest/libnpftest/npf_state_test.c new file mode 100644 index 000000000000..4f7fd864b09d --- /dev/null +++ b/usr.sbin/npf/npftest/libnpftest/npf_state_test.c @@ -0,0 +1,165 @@ +/* $NetBSD: npf_state_test.c,v 1.1 2012/06/04 00:28:34 rmind Exp $ */ + +/* + * NPF state tracking test. + * + * Public Domain. + */ + +#include +#include + +#include "npf_impl.h" +#include "npf_test.h" + +typedef struct { + int tcpfl; /* TCP flags. */ + int tlen; /* TCP data length. */ + uint32_t seq; /* SEQ number. */ + uint32_t ack; /* ACK number. */ + uint32_t win; /* TCP Window. */ + int flags; /* Direction et al. */ +} tcp_meta_t; + +#define S TH_SYN +#define A TH_ACK +#define F TH_FIN +#define OUT 0x1 +#define IN 0x2 +#define ERR 0x4 +#define CLEAR .flags = 0 + +static const tcp_meta_t packet_sequence[] = { + /* + * TCP data SEQ ACK WIN + */ + + /* Out of order ACK. */ + { S, 0, 9999, 0, 4096, OUT }, + { S|A, 0, 9, 10000, 2048, IN }, + { A, 0, 10000, 10, 4096, OUT }, + /* --- */ + { A, 0, 10, 10000, 2048, IN }, + { A, 1000, 10000, 10, 4096, OUT }, + { A, 1000, 11000, 10, 4096, OUT }, + { A, 0, 10, 12000, 2048, IN }, + { A, 0, 10, 13000, 2048, IN }, + { A, 1000, 12000, 10, 4096, OUT }, + { A, 0, 10, 11000, 1048, IN }, + /* --- */ + { A, 1000, 14000, 10, 4096, OUT }, + { A, 0, 10, 13000, 2048, IN }, + { CLEAR }, + + /* Retransmission after out of order ACK and missing ACK. */ + { S, 0, 9999, 0, 1000, OUT }, + { S|A, 0, 9, 10000, 4000, IN }, + { A, 0, 10000, 10, 1000, OUT }, + /* --- */ + { A, 1000, 10000, 10, 1000, OUT }, + { A, 0, 10, 11000, 4000, IN }, + { A, 1000, 11000, 10, 1000, OUT }, + { A, 1000, 12000, 10, 1000, OUT }, + { A, 1000, 13000, 10, 1000, OUT }, + { A, 1000, 14000, 10, 1000, OUT }, + /* --- Assume the first was delayed; second was lost after us. */ + { A, 0, 10, 15000, 4000, IN }, + { A, 0, 10, 15000, 2000, IN }, + /* --- */ + { A, 1000, 12000, 10, 1000, OUT }, + { CLEAR }, + + /* Out of window. */ + { S, 0, 9, 0, 8760, OUT }, + { S|A, 0, 9999, 10, 1000, IN }, + { A, 0, 10, 10000, 8760, OUT }, + /* --- */ + { A, 1460, 10000, 10, 1000, IN }, + { A, 1460, 11460, 10, 1000, IN }, + { A, 0, 10, 12920, 8760, OUT }, + { A, 1460, 12920, 10, 1000, IN }, + { A, 0, 10, 14380, 8760, OUT }, + { A, 1460, 17300, 10, 1000, IN }, + { A, 0, 10, 14380, 8760, OUT }, + { A, 1460, 18760, 10, 1000, IN }, + { A, 0, 10, 14380, 8760, OUT }, + { A, 1460, 20220, 10, 1000, IN }, + { A, 0, 10, 14380, 8760, OUT }, + { A, 1460, 21680, 10, 1000, IN }, + { A, 0, 10, 14380, 8760, OUT }, + /* --- */ + { A, 1460, 14380, 10, 1000, IN }, + { A, 1460, 23140, 10, 1000, IN|ERR }, + { CLEAR }, + +}; + +#undef S +#undef A +#undef F + +static struct mbuf * +construct_packet(const tcp_meta_t *p) +{ + struct mbuf *m = mbuf_construct(IPPROTO_TCP); + struct ip *ip; + struct tcphdr *th; + + th = mbuf_return_hdrs(m, false, &ip); + + /* Imitate TCP payload, set TCP sequence numbers, flags and window. */ + ip->ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr) + p->tlen); + th->th_seq = htonl(p->seq); + th->th_ack = htonl(p->ack); + th->th_flags = p->tcpfl; + th->th_win = htons(p->win); + return m; +} + +static bool +process_packet(const int i, npf_state_t *nst, bool *snew) +{ + const tcp_meta_t *p = &packet_sequence[i]; + npf_cache_t npc = { .npc_info = 0 }; + nbuf_t *nbuf; + int ret; + + if (p->flags == 0) { + npf_state_destroy(nst); + *snew = true; + return true; + } + + nbuf = (nbuf_t *)construct_packet(p); + ret = npf_cache_all(&npc, nbuf); + KASSERT((ret & NPC_IPFRAG) == 0); + + if (*snew) { + ret = npf_state_init(&npc, nbuf, nst); + KASSERT(ret == true); + *snew = false; + } + ret = npf_state_inspect(&npc, nbuf, nst, p->flags == OUT); + m_freem(nbuf); + + return ret ? true : (p->flags & ERR) != 0; +} + +bool +npf_state_test(bool verbose) +{ + npf_state_t nst; + bool snew = true; + + for (u_int i = 0; i < __arraycount(packet_sequence); i++) { + if (process_packet(i, &nst, &snew)) { + continue; + } + if (verbose) { + printf("Failed on packet %d, state dump:\n", i); + npf_state_dump(&nst); + } + return false; + } + return true; +} diff --git a/usr.sbin/npf/npftest/libnpftest/npf_test.h b/usr.sbin/npf/npftest/libnpftest/npf_test.h index fcb0d83b5817..4cb07ca0f74c 100644 --- a/usr.sbin/npf/npftest/libnpftest/npf_test.h +++ b/usr.sbin/npf/npftest/libnpftest/npf_test.h @@ -1,4 +1,4 @@ -/* $NetBSD: npf_test.h,v 1.2 2012/05/30 21:38:04 rmind Exp $ */ +/* $NetBSD: npf_test.h,v 1.3 2012/06/04 00:28:34 rmind Exp $ */ /* * Public Domain. @@ -37,5 +37,6 @@ void mbuf_icmp_append(struct mbuf *, struct mbuf *); bool npf_nbuf_test(bool); bool npf_processor_test(bool); bool npf_table_test(bool); +bool npf_state_test(bool); #endif diff --git a/usr.sbin/npf/npftest/npftest.c b/usr.sbin/npf/npftest/npftest.c index cfd4ed54798b..a0b7a3424f04 100644 --- a/usr.sbin/npf/npftest/npftest.c +++ b/usr.sbin/npf/npftest/npftest.c @@ -1,4 +1,4 @@ -/* $NetBSD: npftest.c,v 1.2 2012/05/30 21:38:04 rmind Exp $ */ +/* $NetBSD: npftest.c,v 1.3 2012/06/04 00:28:34 rmind Exp $ */ /* * NPF testing framework. @@ -179,6 +179,9 @@ main(int argc, char **argv) ok = rumpns_npf_table_test(verbose); result("table", ok); + + ok = rumpns_npf_state_test(verbose); + result("state", ok); } if (stream) { diff --git a/usr.sbin/npf/npftest/npftest.h b/usr.sbin/npf/npftest/npftest.h index ee104fd8ec1f..147f9bad891f 100644 --- a/usr.sbin/npf/npftest/npftest.h +++ b/usr.sbin/npf/npftest/npftest.h @@ -1,4 +1,4 @@ -/* $NetBSD: npftest.h,v 1.2 2012/05/30 21:38:04 rmind Exp $ */ +/* $NetBSD: npftest.h,v 1.3 2012/06/04 00:28:34 rmind Exp $ */ /* * Public Domain. @@ -17,6 +17,7 @@ int rumpns_npf_test_handlepkt(const void *, size_t, bool rumpns_npf_nbuf_test(bool); bool rumpns_npf_processor_test(bool); bool rumpns_npf_table_test(bool); +bool rumpns_npf_state_test(bool); int process_stream(const char *, const char *, unsigned);