npf_nat_test.c revision 1.11 1 /*
2 * NPF NAT tests.
3 *
4 * Public Domain.
5 */
6
7 #ifdef _KERNEL
8 #include <sys/types.h>
9 #endif
10
11 #include "npf_impl.h"
12 #include "npf_test.h"
13
14 #define RESULT_PASS 0
15 #define RESULT_BLOCK ENETUNREACH
16
17 #define NPF_BINAT (NPF_NATIN | NPF_NATOUT)
18
19 #define RANDOM_PORT 53472
20
21 static const struct test_case {
22 const char * src;
23 in_port_t sport;
24 const char * dst;
25 in_port_t dport;
26 int ttype;
27 const char * ifname;
28 int di;
29 int ret;
30 int af;
31 const char * taddr;
32 in_port_t tport;
33 } test_cases[] = {
34
35 /*
36 * Traditional NAPT (outbound NAT):
37 * map $ext_if dynamic $local_net -> $pub_ip1
38 */
39 {
40 LOCAL_IP1, 15000, REMOTE_IP1, 7000,
41 NPF_NATOUT, IFNAME_EXT, PFIL_OUT,
42 RESULT_PASS, AF_INET, PUB_IP1, RANDOM_PORT
43 },
44 {
45 LOCAL_IP1, 15000, REMOTE_IP1, 7000,
46 NPF_NATOUT, IFNAME_EXT, PFIL_OUT,
47 RESULT_PASS, AF_INET, PUB_IP1, RANDOM_PORT
48 },
49 {
50 LOCAL_IP1, 15000, REMOTE_IP1, 7000,
51 NPF_NATOUT, IFNAME_EXT, PFIL_IN,
52 RESULT_BLOCK, AF_INET, NULL, 0
53 },
54 {
55 REMOTE_IP1, 7000, LOCAL_IP1, 15000,
56 NPF_NATOUT, IFNAME_EXT, PFIL_IN,
57 RESULT_BLOCK, AF_INET, NULL, 0
58 },
59 {
60 REMOTE_IP1, 7000, PUB_IP1, RANDOM_PORT,
61 NPF_NATOUT, IFNAME_INT, PFIL_IN,
62 RESULT_BLOCK, AF_INET, NULL, 0
63 },
64 {
65 REMOTE_IP1, 7000, PUB_IP1, RANDOM_PORT,
66 NPF_NATOUT, IFNAME_EXT, PFIL_IN,
67 RESULT_PASS, AF_INET, LOCAL_IP1, 15000
68 },
69
70 /*
71 * NAT redirect (inbound NAT):
72 * map $ext_if dynamic $local_ip1 port 6000 <- $pub_ip1 port 8000
73 */
74 {
75 REMOTE_IP2, 16000, PUB_IP1, 8000,
76 NPF_NATIN, IFNAME_EXT, PFIL_IN,
77 RESULT_PASS, AF_INET, LOCAL_IP1, 6000
78 },
79 {
80 LOCAL_IP1, 6000, REMOTE_IP2, 16000,
81 NPF_NATIN, IFNAME_EXT, PFIL_OUT,
82 RESULT_PASS, AF_INET, PUB_IP1, 8000
83 },
84
85 /*
86 * Bi-directional NAT (inbound + outbound NAT):
87 * map $ext_if dynamic $local_ip2 <-> $pub_ip2
88 */
89 {
90 REMOTE_IP2, 17000, PUB_IP2, 9000,
91 NPF_BINAT, IFNAME_EXT, PFIL_IN,
92 RESULT_PASS, AF_INET, LOCAL_IP2, 9000
93 },
94 {
95 LOCAL_IP2, 9000, REMOTE_IP2, 17000,
96 NPF_BINAT, IFNAME_EXT, PFIL_OUT,
97 RESULT_PASS, AF_INET, PUB_IP2, 9000
98 },
99 {
100 LOCAL_IP2, 18000, REMOTE_IP2, 9000,
101 NPF_BINAT, IFNAME_EXT, PFIL_OUT,
102 RESULT_PASS, AF_INET, PUB_IP2, 18000
103 },
104 {
105 REMOTE_IP2, 9000, PUB_IP2, 18000,
106 NPF_BINAT, IFNAME_EXT, PFIL_IN,
107 RESULT_PASS, AF_INET, LOCAL_IP2, 18000
108 },
109
110 /*
111 * Static NAT: plain translation both ways.
112 * map $ext_if static $local_ip3 <-> $pub_ip3
113 */
114 {
115 LOCAL_IP3, 19000, REMOTE_IP3, 10000,
116 NPF_BINAT, IFNAME_EXT, PFIL_OUT,
117 RESULT_PASS, AF_INET, PUB_IP3, 19000
118 },
119 {
120 REMOTE_IP3, 10000, PUB_IP3, 19000,
121 NPF_BINAT, IFNAME_EXT, PFIL_IN,
122 RESULT_PASS, AF_INET, LOCAL_IP3, 19000
123 },
124
125 /*
126 * NETMAP case:
127 * map $ext_if static algo netmap $net_a <-> $net_b
128 */
129 {
130 NET_A_IP1, 12345, REMOTE_IP4, 12345,
131 NPF_BINAT, IFNAME_EXT, PFIL_OUT,
132 RESULT_PASS, AF_INET, NET_B_IP1, 12345
133 },
134
135 /*
136 * NPTv6 case:
137 * map $ext_if static algo npt66 $net6_inner <-> $net6_outer
138 */
139 {
140 LOCAL_IP6, 1000, REMOTE_IP6, 1001,
141 NPF_BINAT, IFNAME_EXT, PFIL_OUT,
142 RESULT_PASS, AF_INET6, EXPECTED_IP6, 1000
143 },
144 {
145 REMOTE_IP6, 1001, EXPECTED_IP6, 1000,
146 NPF_BINAT, IFNAME_EXT, PFIL_IN,
147 RESULT_PASS, AF_INET6, LOCAL_IP6, 1000
148 },
149
150 };
151
152 static bool
153 nmatch_addr(int af, const char *saddr, const npf_addr_t *addr2)
154 {
155 npf_addr_t addr1;
156 size_t len;
157
158 npf_inet_pton(af, saddr, &addr1);
159 len = af == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr);
160 return memcmp(&addr1, addr2, len) != 0;
161 }
162
163 static bool
164 checkresult(bool verbose, unsigned i, struct mbuf *m, ifnet_t *ifp, int error)
165 {
166 const struct test_case *t = &test_cases[i];
167 npf_cache_t npc = { .npc_info = 0, .npc_ctx = npf_getkernctx() };
168 const int af = t->af;
169 nbuf_t nbuf;
170
171 if (verbose) {
172 printf("packet %d (expected %d ret %d)\n", i+1, t->ret, error);
173 }
174 if (error) {
175 return error == t->ret;
176 }
177
178 nbuf_init(npf_getkernctx(), &nbuf, m, ifp);
179 npc.npc_nbuf = &nbuf;
180 if (!npf_cache_all(&npc)) {
181 printf("error: could not fetch the packet data");
182 return false;
183 }
184
185 const struct udphdr *uh = npc.npc_l4.udp;
186
187 if (verbose) {
188 char sbuf[64], dbuf[64];
189
190 npf_inet_ntop(af, npc.npc_ips[NPF_SRC], sbuf, sizeof(sbuf));
191 npf_inet_ntop(af, npc.npc_ips[NPF_DST], dbuf, sizeof(dbuf));
192
193 printf("\tpost-translation:");
194 printf("src %s (%d) ", sbuf, ntohs(uh->uh_sport));
195 printf("dst %s (%d)\n", dbuf, ntohs(uh->uh_dport));
196 }
197 if (error != t->ret) {
198 return false;
199 }
200
201 const bool forw = t->di == PFIL_OUT;
202 const char *saddr = forw ? t->taddr : t->src;
203 const char *daddr = forw ? t->dst : t->taddr;
204 in_addr_t sport = forw ? t->tport : t->sport;
205 in_addr_t dport = forw ? t->dport : t->tport;
206
207 bool defect = false;
208 defect |= nmatch_addr(af, saddr, npc.npc_ips[NPF_SRC]);
209 defect |= sport != ntohs(uh->uh_sport);
210 defect |= nmatch_addr(af, daddr, npc.npc_ips[NPF_DST]);
211 defect |= dport != ntohs(uh->uh_dport);
212
213 return !defect;
214 }
215
216 static struct mbuf *
217 fill_packet(const struct test_case *t)
218 {
219 struct mbuf *m;
220 void *ipsrc, *ipdst;
221 struct udphdr *uh;
222
223 if (t->af == AF_INET6) {
224 struct ip6_hdr *ip6;
225
226 m = mbuf_construct6(IPPROTO_UDP);
227 uh = mbuf_return_hdrs6(m, &ip6);
228 ipsrc = &ip6->ip6_src, ipdst = &ip6->ip6_dst;
229 } else {
230 struct ip *ip;
231
232 m = mbuf_construct(IPPROTO_UDP);
233 uh = mbuf_return_hdrs(m, false, &ip);
234 ipsrc = &ip->ip_src.s_addr, ipdst = &ip->ip_dst.s_addr;
235 }
236
237 npf_inet_pton(t->af, t->src, ipsrc);
238 npf_inet_pton(t->af, t->dst, ipdst);
239 uh->uh_sport = htons(t->sport);
240 uh->uh_dport = htons(t->dport);
241 return m;
242 }
243
244 bool
245 npf_nat_test(bool verbose)
246 {
247 npf_t *npf = npf_getkernctx();
248
249 for (unsigned i = 0; i < __arraycount(test_cases); i++) {
250 const struct test_case *t = &test_cases[i];
251 ifnet_t *ifp = npf_test_getif(t->ifname);
252 struct mbuf *m = fill_packet(t);
253 int error;
254 bool ret;
255
256 if (ifp == NULL) {
257 printf("Interface %s is not configured.\n", t->ifname);
258 return false;
259 }
260 error = npf_packet_handler(npf, &m, ifp, t->di);
261 ret = checkresult(verbose, i, m, ifp, error);
262 if (m) {
263 m_freem(m);
264 }
265 if (!ret) {
266 return false;
267 }
268 }
269 return true;
270 }
271