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