npf_ext_test.c revision 1.1 1
2
3
4 #ifdef _KERNEL
5 #include <sys/types.h>
6 #endif
7
8 #include "npf_impl.h"
9 #include "npf_test.h"
10
11 static const struct test_case {
12 const char * src;
13 in_port_t sport;
14 const char * dst;
15 in_port_t dport;
16 const char * ifname;
17 int di;
18 int af;
19 } test_cases[] = {
20 {
21 LOCAL_IP60, 15000, LOCAL_IP70, 7000,
22 IFNAME_EXT, PFIL_OUT,
23 AF_INET
24 },
25 {
26 LOCAL_IP60, 15040, LOCAL_IP70, 6000,
27 IFNAME_EXT, PFIL_OUT,
28 AF_INET
29 },
30
31 };
32
33 #define TCP_OPT_LEN 4
34 static struct mbuf *
35 mbuf_get_pkt_with_option(int af, int proto, const char *src, const char *dst,
36 int sport, int dport)
37 {
38 struct mbuf *m;
39 struct ip *ip;
40 struct tcphdr *th;
41 void *ipsrc, *ipdst;
42 int size = 0;
43 uint8_t *opt;
44 uint16_t mss = 1400;
45
46 m = m_gethdr(M_WAITOK, MT_HEADER);
47 ip = mtod(m, struct ip *);
48
49 ip->ip_v = IPVERSION;
50 ip->ip_hl = sizeof(struct ip) >> 2;
51 ip->ip_off = 0;
52 ip->ip_ttl = 64;
53 ip->ip_p = proto;
54
55 ipsrc = &ip->ip_src.s_addr;
56 ipdst = &ip->ip_dst.s_addr;
57
58 npf_inet_pton(af, src, ipsrc);
59 npf_inet_pton(af, dst, ipdst);
60
61 th = mbuf_return_hdrs(m, false, &ip);
62 size = sizeof(struct ip) + sizeof(struct tcphdr) + TCP_OPT_LEN;
63 th->th_flags |= TH_SYN;
64 th->th_off = (sizeof(struct tcphdr) + TCP_OPT_LEN) >> 2;
65 th->th_sport = htons(sport);
66 th->th_dport = htons(dport);
67
68 opt = (uint8_t *)th + sizeof(struct tcphdr);
69 opt[0] = TCPOPT_MAXSEG; /* Kind = 2 */
70 opt[1] = TCPOLEN_MAXSEG; /* Length = 4 */
71 opt[2] = (mss >> 8) & 0xff; /* 0x05 */
72 opt[3] = mss & 0xff; /* 0x29 */
73
74 ip->ip_len = htons(size);
75
76 m->m_pkthdr.len = size;
77 m->m_len = size;
78 m->m_next = NULL;
79 return m;
80 }
81
82 static int
83 run_raw_testcase(npf_cache_t *npc, unsigned i, bool verbose)
84 {
85 const struct test_case *t = &test_cases[i];
86 npf_t *npf = npf_getkernctx();
87 int slock, error;
88 npf_rproc_t *rp;
89 npf_rule_t *rl;
90 npf_match_info_t mi;
91 int decision = 1;
92
93 slock = npf_config_read_enter(npf);
94 rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_RULE_LAYER_3);
95 if (rl) {
96 error = npf_rule_conclude(rl, &mi);
97 } else {
98 error = ENOENT;
99 return error;
100 }
101 npf_config_read_exit(npf, slock);
102
103 rp = npf_rule_getrproc(rl);
104 assert(rp != NULL);
105
106 error = npf_rproc_run(npc, rp, &mi, &decision);
107
108 if (error == 1) {
109 npf_rproc_release(rp);
110 }
111
112 return error;
113 }
114
115 static void
116 npf_get_normalize_params(npf_cache_t *npc, uint16_t *ip_ttl, uint8_t *ip_id, int *df, uint16_t *maxmss)
117 {
118 int wscale;
119 struct ip *ip = npc->npc_ip.v4;
120 *ip_id = ip->ip_id;
121 *ip_ttl = ip->ip_ttl;
122 *df = ip->ip_off & IP_DF;
123 npf_fetch_tcpopts(npc, maxmss, &wscale);
124 }
125
126 bool
127 npf_procedure_test(bool verbose)
128 {
129 int ret;
130 for (unsigned i = 0; i < __arraycount(test_cases); i++) {
131 const struct test_case *t = &test_cases[i];
132 npf_cache_t *npc;
133 struct mbuf *m;
134 uint16_t ip_ttl;
135 uint8_t ip_id;
136 int df;
137 uint16_t maxmss;
138
139 if (npf_test_getif(t->ifname) == NULL) {
140 printf("Interface %s is not configured.\n", t->ifname);
141 return false;
142 }
143
144 m = mbuf_get_pkt_with_option(t->af, IPPROTO_TCP, t->src, t->dst, 9000, 9000);
145 npc = get_cached_pkt(m, t->ifname, NPF_RULE_LAYER_3);
146
147 ret = run_raw_testcase(npc, i, verbose);
148 if (verbose) {
149 printf("%s: expected return in raw testcase 1, returned %d\n", __func__, ret);
150 }
151 CHECK_TRUE(ret == 1);
152
153 npf_get_normalize_params(npc, &ip_ttl, &ip_id, &df, &maxmss);
154 maxmss = ntohs(maxmss);
155
156 if (verbose) {
157 printf("Normalization:\texpected 164 ttl but got %u\n", ip_ttl);
158 printf("Normalization:\texpected 1321 maxmss but got %u\n", maxmss);
159 }
160 CHECK_TRUE((df & IP_DF) == 0);
161 CHECK_TRUE(maxmss == 1321);
162 CHECK_TRUE(ip_ttl == 164);
163 put_cached_pkt(npc);
164 }
165
166 return true;
167 }
168