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