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 18791
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
match_addr(int af,const char * saddr,const npf_addr_t * addr2)153 match_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
checkresult(bool verbose,unsigned i,struct mbuf * m,ifnet_t * ifp,int error)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 const int af = t->af;
168 npf_cache_t npc;
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 memset(&npc, 0, sizeof(npf_cache_t));
180 npc.npc_ctx = npf_getkernctx();
181 npc.npc_nbuf = &nbuf;
182
183 if (!npf_cache_all(&npc)) {
184 printf("error: could not fetch the packet data");
185 return false;
186 }
187
188 const struct udphdr *uh = npc.npc_l4.udp;
189
190 if (verbose) {
191 char sbuf[64], dbuf[64];
192
193 npf_inet_ntop(af, npc.npc_ips[NPF_SRC], sbuf, sizeof(sbuf));
194 npf_inet_ntop(af, npc.npc_ips[NPF_DST], dbuf, sizeof(dbuf));
195
196 printf("\tpost-translation: ");
197 printf("src %s (%d) ", sbuf, ntohs(uh->uh_sport));
198 printf("dst %s (%d)\n", dbuf, ntohs(uh->uh_dport));
199 }
200 if (error != t->ret) {
201 return false;
202 }
203
204 const bool forw = t->di == PFIL_OUT;
205 const char *saddr = forw ? t->taddr : t->src;
206 const char *daddr = forw ? t->dst : t->taddr;
207 in_addr_t sport = forw ? t->tport : t->sport;
208 in_addr_t dport = forw ? t->dport : t->tport;
209
210 CHECK_TRUE(match_addr(af, saddr, npc.npc_ips[NPF_SRC]));
211 CHECK_TRUE(sport == ntohs(uh->uh_sport));
212 CHECK_TRUE(match_addr(af, daddr, npc.npc_ips[NPF_DST]));
213 CHECK_TRUE(dport == ntohs(uh->uh_dport));
214
215 return true;
216 }
217
218 bool
npf_nat_test(bool verbose)219 npf_nat_test(bool verbose)
220 {
221 npf_t *npf = npf_getkernctx();
222
223 for (unsigned i = 0; i < __arraycount(test_cases); i++) {
224 const struct test_case *t = &test_cases[i];
225 ifnet_t *ifp = npf_test_getif(t->ifname);
226 struct mbuf *m;
227 int error;
228 bool ret;
229
230 if (ifp == NULL) {
231 printf("Interface %s is not configured.\n", t->ifname);
232 return false;
233 }
234 m = mbuf_get_pkt(t->af, IPPROTO_UDP,
235 t->src, t->dst, t->sport, t->dport);
236 error = npfk_packet_handler(npf, &m, ifp, t->di);
237 ret = checkresult(verbose, i, m, ifp, error);
238 if (m) {
239 m_freem(m);
240 }
241 CHECK_TRUE(ret);
242 }
243 return true;
244 }
245