xref: /netbsd-src/usr.sbin/npf/npftest/libnpftest/npf_state_test.c (revision b899bfd96fd2cbaf2befc9ce4aaed9b9c230837a)
179afee64Srmind /*
23d9a792dSrmind  * NPF state tracking tests.
379afee64Srmind  *
479afee64Srmind  * Public Domain.
579afee64Srmind  */
679afee64Srmind 
7f75d79ebSchristos #ifdef _KERNEL
879afee64Srmind #include <sys/types.h>
979afee64Srmind #include <sys/kmem.h>
10f75d79ebSchristos #endif
1179afee64Srmind 
1279afee64Srmind #include "npf_impl.h"
1379afee64Srmind #include "npf_test.h"
1479afee64Srmind 
1579afee64Srmind typedef struct {
1679afee64Srmind 	int		tcpfl;		/* TCP flags. */
1779afee64Srmind 	int		tlen;		/* TCP data length. */
1879afee64Srmind 	uint32_t	seq;		/* SEQ number. */
1979afee64Srmind 	uint32_t	ack;		/* ACK number. */
2079afee64Srmind 	uint32_t	win;		/* TCP Window. */
2179afee64Srmind 	int		flags;		/* Direction et al. */
2279afee64Srmind } tcp_meta_t;
2379afee64Srmind 
2479afee64Srmind #define	S	TH_SYN
2579afee64Srmind #define	A	TH_ACK
2679afee64Srmind #define	F	TH_FIN
2779afee64Srmind #define	OUT	0x1
2879afee64Srmind #define	IN	0x2
2979afee64Srmind #define	ERR	0x4
3079afee64Srmind #define	CLEAR	.flags = 0
3179afee64Srmind 
3279afee64Srmind static const tcp_meta_t packet_sequence[] = {
3379afee64Srmind 	/*
3479afee64Srmind 	 *	TCP data	SEQ	ACK		WIN
3579afee64Srmind 	 */
3679afee64Srmind 
3779afee64Srmind 	/* Out of order ACK. */
3879afee64Srmind 	{ S,	0,		9999,	0,		4096,	OUT	},
3979afee64Srmind 	{ S|A,	0,		9,	10000,		2048,	IN	},
4079afee64Srmind 	{ A,	0,		10000,	10,		4096,	OUT	},
4179afee64Srmind 	/* --- */
4279afee64Srmind 	{ A,	0,		10,	10000,		2048,	IN	},
4379afee64Srmind 	{ A,	1000,		10000,	10,		4096,	OUT	},
4479afee64Srmind 	{ A,	1000,		11000,	10,		4096,	OUT	},
4579afee64Srmind 	{ A,	0,		10,	12000,		2048,	IN	},
4679afee64Srmind 	{ A,	0,		10,	13000,		2048,	IN	},
4779afee64Srmind 	{ A,	1000,		12000,	10,		4096,	OUT	},
4879afee64Srmind 	{ A,	0,		10,	11000,		1048,	IN	},
4979afee64Srmind 	/* --- */
5079afee64Srmind 	{ A,	1000,		14000,	10,		4096,	OUT	},
5179afee64Srmind 	{ A,	0,		10,	13000,		2048,	IN	},
5279afee64Srmind 	{ CLEAR },
5379afee64Srmind 
5479afee64Srmind 	/* Retransmission after out of order ACK and missing ACK. */
5579afee64Srmind 	{ S,	0,		9999,	0,		1000,	OUT	},
5679afee64Srmind 	{ S|A,	0,		9,	10000,		4000,	IN	},
5779afee64Srmind 	{ A,	0,		10000,	10,		1000,	OUT	},
5879afee64Srmind 	/* --- */
5979afee64Srmind 	{ A,	1000,		10000,	10,		1000,	OUT	},
6079afee64Srmind 	{ A,	0,		10,	11000,		4000,	IN	},
6179afee64Srmind 	{ A,	1000,		11000,	10,		1000,	OUT	},
6279afee64Srmind 	{ A,	1000,		12000,	10,		1000,	OUT	},
6379afee64Srmind 	{ A,	1000,		13000,	10,		1000,	OUT	},
6479afee64Srmind 	{ A,	1000,		14000,	10,		1000,	OUT	},
6579afee64Srmind 	/* --- Assume the first was delayed; second was lost after us. */
6679afee64Srmind 	{ A,	0,		10,	15000,		4000,	IN	},
6779afee64Srmind 	{ A,	0,		10,	15000,		2000,	IN	},
6879afee64Srmind 	/* --- */
6979afee64Srmind 	{ A,	1000,		12000,	10,		1000,	OUT	},
7079afee64Srmind 	{ CLEAR },
7179afee64Srmind 
7233b678d7Srmind 	/* FIN exchange with retransmit. */
7333b678d7Srmind 	{ S,	0,		999,	0,		1000,	OUT	},
7433b678d7Srmind 	{ S|A,	0,		9,	1000,		2000,	IN	},
7533b678d7Srmind 	{ A,	0,		1000,	10,		1000,	OUT	},
7633b678d7Srmind 	/* --- */
7733b678d7Srmind 	{ F,	0,		10,	1000,		2000,	IN	},
7833b678d7Srmind 	{ F,	0,		1000,	10,		1000,	OUT	},
7933b678d7Srmind 	{ A,	0,		1000,	11,		1000,	OUT	},
8033b678d7Srmind 	/* --- */
8133b678d7Srmind 	{ F,	0,		1000,	11,		1000,	OUT	},
8233b678d7Srmind 	{ F,	0,		1000,	11,		1000,	OUT	},
8333b678d7Srmind 	{ A,	0,		11,	1001,		2000,	OUT	},
8433b678d7Srmind 	{ CLEAR },
8533b678d7Srmind 
8679afee64Srmind 	/* Out of window. */
8779afee64Srmind 	{ S,	0,		9,	0,		8760,	OUT	},
8879afee64Srmind 	{ S|A,	0,		9999,	10,		1000,	IN	},
8979afee64Srmind 	{ A,	0,		10,	10000,		8760,	OUT	},
9079afee64Srmind 	/* --- */
9179afee64Srmind 	{ A,	1460,		10000,	10,		1000,	IN	},
9279afee64Srmind 	{ A,	1460,		11460,	10,		1000,	IN	},
9379afee64Srmind 	{ A,	0,		10,	12920,		8760,	OUT	},
9479afee64Srmind 	{ A,	1460,		12920,	10,		1000,	IN	},
9579afee64Srmind 	{ A,	0,		10,	14380,		8760,	OUT	},
9679afee64Srmind 	{ A,	1460,		17300,	10,		1000,	IN	},
9779afee64Srmind 	{ A,	0,		10,	14380,		8760,	OUT	},
9879afee64Srmind 	{ A,	1460,		18760,	10,		1000,	IN	},
9979afee64Srmind 	{ A,	0,		10,	14380,		8760,	OUT	},
10079afee64Srmind 	{ A,	1460,		20220,	10,		1000,	IN	},
10179afee64Srmind 	{ A,	0,		10,	14380,		8760,	OUT	},
10279afee64Srmind 	{ A,	1460,		21680,	10,		1000,	IN	},
10379afee64Srmind 	{ A,	0,		10,	14380,		8760,	OUT	},
10479afee64Srmind 	/* --- */
10579afee64Srmind 	{ A,	1460,		14380,	10,		1000,	IN	},
10679afee64Srmind 	{ A,	1460,		23140,	10,		1000,	IN|ERR	},
10779afee64Srmind 	{ CLEAR },
10879afee64Srmind 
10979afee64Srmind };
11079afee64Srmind 
11179afee64Srmind #undef S
11279afee64Srmind #undef A
11379afee64Srmind #undef F
11479afee64Srmind 
11579afee64Srmind static struct mbuf *
construct_packet(const tcp_meta_t * p)11679afee64Srmind construct_packet(const tcp_meta_t *p)
11779afee64Srmind {
11879afee64Srmind 	struct mbuf *m = mbuf_construct(IPPROTO_TCP);
11979afee64Srmind 	struct ip *ip;
12079afee64Srmind 	struct tcphdr *th;
12179afee64Srmind 
12279afee64Srmind 	th = mbuf_return_hdrs(m, false, &ip);
12379afee64Srmind 
12479afee64Srmind 	/* Imitate TCP payload, set TCP sequence numbers, flags and window. */
12579afee64Srmind 	ip->ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr) + p->tlen);
12679afee64Srmind 	th->th_seq = htonl(p->seq);
12779afee64Srmind 	th->th_ack = htonl(p->ack);
12879afee64Srmind 	th->th_flags = p->tcpfl;
12979afee64Srmind 	th->th_win = htons(p->win);
13079afee64Srmind 	return m;
13179afee64Srmind }
13279afee64Srmind 
13379afee64Srmind static bool
process_packet(const int i,npf_state_t * nst,bool * snew)13479afee64Srmind process_packet(const int i, npf_state_t *nst, bool *snew)
13579afee64Srmind {
13679afee64Srmind 	const tcp_meta_t *p = &packet_sequence[i];
137dadc88e3Srmind 	npf_cache_t *npc;
13879afee64Srmind 	int ret;
13979afee64Srmind 
14079afee64Srmind 	if (p->flags == 0) {
14179afee64Srmind 		npf_state_destroy(nst);
14279afee64Srmind 		*snew = true;
14379afee64Srmind 		return true;
14479afee64Srmind 	}
14579afee64Srmind 
146dadc88e3Srmind 	npc = get_cached_pkt(construct_packet(p), NULL);
14779afee64Srmind 	if (*snew) {
148dadc88e3Srmind 		ret = npf_state_init(npc, nst);
14979afee64Srmind 		KASSERT(ret == true);
15079afee64Srmind 		*snew = false;
15179afee64Srmind 	}
152*b899bfd9Srmind 	ret = npf_state_inspect(npc, nst,
153*b899bfd9Srmind 	    (p->flags == OUT) ? NPF_FLOW_FORW : NPF_FLOW_BACK);
154dadc88e3Srmind 	put_cached_pkt(npc);
15579afee64Srmind 
15679afee64Srmind 	return ret ? true : (p->flags & ERR) != 0;
15779afee64Srmind }
15879afee64Srmind 
15979afee64Srmind bool
npf_state_test(bool verbose)16079afee64Srmind npf_state_test(bool verbose)
16179afee64Srmind {
16279afee64Srmind 	npf_state_t nst;
16379afee64Srmind 	bool snew = true;
164b8c27e4aSrmind 	bool ok = true;
16579afee64Srmind 
166dadc88e3Srmind 	for (unsigned i = 0; i < __arraycount(packet_sequence); i++) {
16779afee64Srmind 		if (process_packet(i, &nst, &snew)) {
16879afee64Srmind 			continue;
16979afee64Srmind 		}
17079afee64Srmind 		if (verbose) {
17179afee64Srmind 			printf("Failed on packet %d, state dump:\n", i);
17279afee64Srmind 			npf_state_dump(&nst);
17379afee64Srmind 		}
174b8c27e4aSrmind 		ok = false;
17579afee64Srmind 	}
176b8c27e4aSrmind 	return ok;
17779afee64Srmind }
178