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