npf_state_test.c revision 1.8 1 /*
2 * NPF state tracking tests.
3 *
4 * Public Domain.
5 */
6
7 #ifdef _KERNEL
8 #include <sys/types.h>
9 #include <sys/kmem.h>
10 #endif
11
12 #include "npf_impl.h"
13 #include "npf_test.h"
14
15 typedef struct {
16 int tcpfl; /* TCP flags. */
17 int tlen; /* TCP data length. */
18 uint32_t seq; /* SEQ number. */
19 uint32_t ack; /* ACK number. */
20 uint32_t win; /* TCP Window. */
21 int flags; /* Direction et al. */
22 } tcp_meta_t;
23
24 #define S TH_SYN
25 #define A TH_ACK
26 #define F TH_FIN
27 #define OUT 0x1
28 #define IN 0x2
29 #define ERR 0x4
30 #define CLEAR .flags = 0
31
32 static const tcp_meta_t packet_sequence[] = {
33 /*
34 * TCP data SEQ ACK WIN
35 */
36
37 /* Out of order ACK. */
38 { S, 0, 9999, 0, 4096, OUT },
39 { S|A, 0, 9, 10000, 2048, IN },
40 { A, 0, 10000, 10, 4096, OUT },
41 /* --- */
42 { A, 0, 10, 10000, 2048, IN },
43 { A, 1000, 10000, 10, 4096, OUT },
44 { A, 1000, 11000, 10, 4096, OUT },
45 { A, 0, 10, 12000, 2048, IN },
46 { A, 0, 10, 13000, 2048, IN },
47 { A, 1000, 12000, 10, 4096, OUT },
48 { A, 0, 10, 11000, 1048, IN },
49 /* --- */
50 { A, 1000, 14000, 10, 4096, OUT },
51 { A, 0, 10, 13000, 2048, IN },
52 { CLEAR },
53
54 /* Retransmission after out of order ACK and missing ACK. */
55 { S, 0, 9999, 0, 1000, OUT },
56 { S|A, 0, 9, 10000, 4000, IN },
57 { A, 0, 10000, 10, 1000, OUT },
58 /* --- */
59 { A, 1000, 10000, 10, 1000, OUT },
60 { A, 0, 10, 11000, 4000, IN },
61 { A, 1000, 11000, 10, 1000, OUT },
62 { A, 1000, 12000, 10, 1000, OUT },
63 { A, 1000, 13000, 10, 1000, OUT },
64 { A, 1000, 14000, 10, 1000, OUT },
65 /* --- Assume the first was delayed; second was lost after us. */
66 { A, 0, 10, 15000, 4000, IN },
67 { A, 0, 10, 15000, 2000, IN },
68 /* --- */
69 { A, 1000, 12000, 10, 1000, OUT },
70 { CLEAR },
71
72 /* FIN exchange with retransmit. */
73 { S, 0, 999, 0, 1000, OUT },
74 { S|A, 0, 9, 1000, 2000, IN },
75 { A, 0, 1000, 10, 1000, OUT },
76 /* --- */
77 { F, 0, 10, 1000, 2000, IN },
78 { F, 0, 1000, 10, 1000, OUT },
79 { A, 0, 1000, 11, 1000, OUT },
80 /* --- */
81 { F, 0, 1000, 11, 1000, OUT },
82 { F, 0, 1000, 11, 1000, OUT },
83 { A, 0, 11, 1001, 2000, OUT },
84 { CLEAR },
85
86 /* Out of window. */
87 { S, 0, 9, 0, 8760, OUT },
88 { S|A, 0, 9999, 10, 1000, IN },
89 { A, 0, 10, 10000, 8760, OUT },
90 /* --- */
91 { A, 1460, 10000, 10, 1000, IN },
92 { A, 1460, 11460, 10, 1000, IN },
93 { A, 0, 10, 12920, 8760, OUT },
94 { A, 1460, 12920, 10, 1000, IN },
95 { A, 0, 10, 14380, 8760, OUT },
96 { A, 1460, 17300, 10, 1000, IN },
97 { A, 0, 10, 14380, 8760, OUT },
98 { A, 1460, 18760, 10, 1000, IN },
99 { A, 0, 10, 14380, 8760, OUT },
100 { A, 1460, 20220, 10, 1000, IN },
101 { A, 0, 10, 14380, 8760, OUT },
102 { A, 1460, 21680, 10, 1000, IN },
103 { A, 0, 10, 14380, 8760, OUT },
104 /* --- */
105 { A, 1460, 14380, 10, 1000, IN },
106 { A, 1460, 23140, 10, 1000, IN|ERR },
107 { CLEAR },
108
109 };
110
111 #undef S
112 #undef A
113 #undef F
114
115 static struct mbuf *
116 construct_packet(const tcp_meta_t *p)
117 {
118 struct mbuf *m = mbuf_construct(IPPROTO_TCP);
119 struct ip *ip;
120 struct tcphdr *th;
121
122 th = mbuf_return_hdrs(m, false, &ip);
123
124 /* Imitate TCP payload, set TCP sequence numbers, flags and window. */
125 ip->ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr) + p->tlen);
126 th->th_seq = htonl(p->seq);
127 th->th_ack = htonl(p->ack);
128 th->th_flags = p->tcpfl;
129 th->th_win = htons(p->win);
130 return m;
131 }
132
133 static bool
134 process_packet(const int i, npf_state_t *nst, bool *snew)
135 {
136 ifnet_t *dummy_ifp = npf_test_addif(IFNAME_TEST, false, false);
137 const tcp_meta_t *p = &packet_sequence[i];
138 npf_cache_t npc = { .npc_info = 0, .npc_ctx = npf_getkernctx() };
139 nbuf_t nbuf;
140 int ret;
141
142 if (p->flags == 0) {
143 npf_state_destroy(nst);
144 *snew = true;
145 return true;
146 }
147
148 nbuf_init(npf_getkernctx(), &nbuf, construct_packet(p), dummy_ifp);
149 npc.npc_nbuf = &nbuf;
150 ret = npf_cache_all(&npc);
151 KASSERT((ret & NPC_IPFRAG) == 0);
152
153 if (*snew) {
154 ret = npf_state_init(&npc, nst);
155 KASSERT(ret == true);
156 *snew = false;
157 }
158 ret = npf_state_inspect(&npc, nst, p->flags == OUT);
159 m_freem(nbuf.nb_mbuf);
160
161 return ret ? true : (p->flags & ERR) != 0;
162 }
163
164 bool
165 npf_state_test(bool verbose)
166 {
167 npf_state_t nst;
168 bool snew = true;
169 bool ok = true;
170
171 for (u_int i = 0; i < __arraycount(packet_sequence); i++) {
172 if (process_packet(i, &nst, &snew)) {
173 continue;
174 }
175 if (verbose) {
176 printf("Failed on packet %d, state dump:\n", i);
177 npf_state_dump(&nst);
178 }
179 ok = false;
180 }
181 return ok;
182 }
183