xref: /freebsd/tests/sys/netinet/libalias/2_natout.c (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright 2021 Lutz Donnerhacke
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above
13  *    copyright notice, this list of conditions and the following
14  *    disclaimer in the documentation and/or other materials provided
15  *    with the distribution.
16  * 3. Neither the name of the copyright holder nor the names of its
17  *    contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
21  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
22  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
31  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 #include <atf-c.h>
35 #include <alias.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 
39 #include "util.h"
40 
41 ATF_TC_WITHOUT_HEAD(1_simplemasq);
42 ATF_TC_BODY(1_simplemasq, dummy)
43 {
44 	struct libalias *la = LibAliasInit(NULL);
45 	struct ip *pip;
46 
47 	ATF_REQUIRE(la != NULL);
48 	LibAliasSetAddress(la, masq);
49 	LibAliasSetMode(la, 0, ~0);
50 
51 	pip = ip_packet(254, 64);
52 	NAT_CHECK(pip, prv1, ext, masq);
53 	NAT_CHECK(pip, prv2, ext, masq);
54 	NAT_CHECK(pip, prv3, ext, masq);
55 	NAT_CHECK(pip, cgn,  ext, masq);
56 	NAT_CHECK(pip, pub,  ext, masq);
57 
58 	free(pip);
59 	LibAliasUninit(la);
60 }
61 
62 ATF_TC_WITHOUT_HEAD(2_unregistered);
63 ATF_TC_BODY(2_unregistered, dummy)
64 {
65 	struct libalias *la = LibAliasInit(NULL);
66 	struct ip *pip;
67 
68 	ATF_REQUIRE(la != NULL);
69 	LibAliasSetAddress(la, masq);
70 	LibAliasSetMode(la, PKT_ALIAS_UNREGISTERED_ONLY, ~0);
71 
72 	pip = ip_packet(254, 64);
73 	NAT_CHECK(pip, prv1, ext, masq);
74 	NAT_CHECK(pip, prv2, ext, masq);
75 	NAT_CHECK(pip, prv3, ext, masq);
76 	NAT_CHECK(pip, cgn,  ext, cgn);
77 	NAT_CHECK(pip, pub,  ext, pub);
78 
79 	/*
80 	 * State is only for new connections
81 	 * Because they are now active,
82 	 * the mode setting should be ignored
83 	 */
84 	LibAliasSetMode(la, 0, PKT_ALIAS_UNREGISTERED_ONLY);
85 	NAT_CHECK(pip, prv1, ext, masq);
86 	NAT_CHECK(pip, prv2, ext, masq);
87 	NAT_CHECK(pip, prv3, ext, masq);
88 	NAT_CHECK(pip, cgn,  ext, cgn);
89 	NAT_CHECK(pip, pub,  ext, pub);
90 
91 	free(pip);
92 	LibAliasUninit(la);
93 }
94 
95 ATF_TC_WITHOUT_HEAD(3_cgn);
96 ATF_TC_BODY(3_cgn, dummy)
97 {
98 	struct libalias *la = LibAliasInit(NULL);
99 	struct ip *pip;
100 
101 	ATF_REQUIRE(la != NULL);
102 	LibAliasSetAddress(la, masq);
103 	LibAliasSetMode(la, PKT_ALIAS_UNREGISTERED_CGN, ~0);
104 
105 	pip = ip_packet(254, 64);
106 	NAT_CHECK(pip, prv1, ext, masq);
107 	NAT_CHECK(pip, prv2, ext, masq);
108 	NAT_CHECK(pip, prv3, ext, masq);
109 	NAT_CHECK(pip, cgn,  ext, masq);
110 	NAT_CHECK(pip, pub,  ext, pub);
111 
112 	/*
113 	 * State is only for new connections
114 	 * Because they are now active,
115 	 * the mode setting should be ignored
116 	 */
117 	LibAliasSetMode(la, 0, PKT_ALIAS_UNREGISTERED_CGN);
118 	NAT_CHECK(pip, prv1, ext, masq);
119 	NAT_CHECK(pip, prv2, ext, masq);
120 	NAT_CHECK(pip, prv3, ext, masq);
121 	NAT_CHECK(pip, cgn,  ext, masq);
122 	NAT_CHECK(pip, pub,  ext, pub);
123 
124 	free(pip);
125 	LibAliasUninit(la);
126 }
127 
128 ATF_TC_WITHOUT_HEAD(4_udp);
129 ATF_TC_BODY(4_udp, dummy)
130 {
131 	struct libalias *la = LibAliasInit(NULL);
132 	struct ip  *po, *pi;
133 	struct udphdr *ui, *uo;
134 	uint16_t sport = 0x1234;
135 	uint16_t dport = 0x5678;
136 	uint16_t aport;
137 
138 	ATF_REQUIRE(la != NULL);
139 	LibAliasSetAddress(la, masq);
140 	LibAliasSetMode(la, 0, ~0);
141 
142 	/* Query from prv1 */
143 	po = ip_packet(0, 64);
144 	UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);
145 	aport = ntohs(uo->uh_sport);
146 	/* should use a different external port */
147 	ATF_CHECK(aport != sport);
148 
149 	/* Response */
150 	pi = ip_packet(0, 64);
151 	UDP_UNNAT_CHECK(pi, ui, ext, dport, masq, aport, prv1, sport);
152 
153 	/* Query from different source with same ports */
154 	UDP_NAT_CHECK(po, uo, prv2, sport, ext, dport, masq);
155 	/* should use a different external port */
156 	ATF_CHECK(uo->uh_sport != htons(aport));
157 
158 	/* Response to prv2 */
159 	ui->uh_dport = uo->uh_sport;
160 	UDP_UNNAT_CHECK(pi, ui, ext, dport, masq, htons(uo->uh_sport), prv2, sport);
161 
162 	/* Response to prv1 again */
163 	UDP_UNNAT_CHECK(pi, ui, ext, dport, masq, aport, prv1, sport);
164 
165 	free(pi);
166 	free(po);
167 	LibAliasUninit(la);
168 }
169 
170 ATF_TC_WITHOUT_HEAD(5_sameport);
171 ATF_TC_BODY(5_sameport, dummy)
172 {
173 	struct libalias *la = LibAliasInit(NULL);
174 	struct ip  *p;
175 	struct udphdr *u;
176 	uint16_t sport = 0x1234;
177 	uint16_t dport = 0x5678;
178 	uint16_t aport;
179 
180 	ATF_REQUIRE(la != NULL);
181 	LibAliasSetAddress(la, masq);
182 	LibAliasSetMode(la, PKT_ALIAS_SAME_PORTS, ~0);
183 
184 	/* Query from prv1 */
185 	p = ip_packet(0, 64);
186 	UDP_NAT_CHECK(p, u, prv1, sport, ext, dport, masq);
187 	aport = ntohs(u->uh_sport);
188 	/* should use the same external port */
189 	ATF_CHECK(aport == sport);
190 
191 	/* Query from different source with same ports */
192 	UDP_NAT_CHECK(p, u, prv2, sport, ext, dport, masq);
193 	/* should use a different external port */
194 	ATF_CHECK(u->uh_sport != htons(aport));
195 
196 	free(p);
197 	LibAliasUninit(la);
198 }
199 
200 ATF_TC_WITHOUT_HEAD(6_cleartable);
201 ATF_TC_BODY(6_cleartable, dummy)
202 {
203 	struct libalias *la = LibAliasInit(NULL);
204 	struct ip  *po, *pi;
205 	struct udphdr *ui __unused, *uo;
206 	uint16_t sport = 0x1234;
207 	uint16_t dport = 0x5678;
208 	uint16_t aport;
209 
210 	ATF_REQUIRE(la != NULL);
211 	LibAliasSetAddress(la, masq);
212 	LibAliasSetMode(la, PKT_ALIAS_RESET_ON_ADDR_CHANGE, ~0);
213 	LibAliasSetMode(la, PKT_ALIAS_SAME_PORTS, PKT_ALIAS_SAME_PORTS);
214 	LibAliasSetMode(la, PKT_ALIAS_DENY_INCOMING, PKT_ALIAS_DENY_INCOMING);
215 
216 	/* Query from prv1 */
217 	po = ip_packet(0, 64);
218 	UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);
219 	aport = ntohs(uo->uh_sport);
220 	/* should use the same external port */
221 	ATF_CHECK(aport == sport);
222 
223 	/* Response */
224 	pi = ip_packet(0, 64);
225 	UDP_UNNAT_CHECK(po, uo, ext, dport, masq, aport, prv1, sport);
226 
227 	/* clear table by keeping the address */
228 	LibAliasSetAddress(la, ext);
229 	LibAliasSetAddress(la, masq);
230 
231 	/* Response to prv1 again -> DENY_INCOMING */
232 	UDP_UNNAT_FAIL(pi, ui, ext, dport, masq, aport);
233 
234 	/* Query from different source with same ports */
235 	UDP_NAT_CHECK(po, uo, prv2, sport, ext, dport, masq);
236 	/* should use the same external port, because it's free */
237 	ATF_CHECK(uo->uh_sport == htons(aport));
238 
239 	/* Response to prv2 */
240 	UDP_UNNAT_CHECK(po, uo, ext, dport, masq, htons(uo->uh_sport), prv2, sport);
241 
242 	free(pi);
243 	free(po);
244 	LibAliasUninit(la);
245 }
246 
247 ATF_TC_WITHOUT_HEAD(7_stress);
248 ATF_TC_BODY(7_stress, dummy)
249 {
250 	struct libalias *la = LibAliasInit(NULL);
251 	struct ip *p;
252 	struct udphdr *u;
253 	struct {
254 		struct in_addr src, dst;
255 		uint16_t sport, dport, aport;
256 	} *batch;
257 	size_t const batch_size = 1200;
258 	size_t const rounds = 25;
259 	size_t i, j;
260 
261 	ATF_REQUIRE(la != NULL);
262 	LibAliasSetAddress(la, masq);
263 
264 	p = ip_packet(0, 64);
265 
266 	batch = calloc(batch_size, sizeof(*batch));
267 	ATF_REQUIRE(batch != NULL);
268 	for (j = 0; j < rounds; j++) {
269 		for (i = 0; i < batch_size; i++) {
270 			struct in_addr s, d;
271 			switch (i&3) {
272 			case 0: s = prv1; d = ext; break;
273 			case 1: s = prv2; d = pub; break;
274 			case 2: s = prv3; d = ext; break;
275 			case 3: s = cgn;  d = pub; break;
276 			}
277 			s.s_addr &= htonl(0xffff0000);
278 			d.s_addr &= htonl(0xffff0000);
279 			batch[i].src.s_addr = s.s_addr | htonl(rand_range(0, 0xffff));
280 			batch[i].dst.s_addr = d.s_addr | htonl(rand_range(0, 0xffff));
281 			batch[i].sport = rand_range(1000, 60000);
282 			batch[i].dport = rand_range(1000, 60000);
283 		}
284 
285 		for (i = 0; i < batch_size; i++) {
286 			UDP_NAT_CHECK(p, u,
287 			    batch[i].src, batch[i].sport,
288 			    batch[i].dst, batch[i].dport,
289 			    masq);
290 			batch[i].aport = htons(u->uh_sport);
291 		}
292 
293 		qsort(batch, batch_size, sizeof(*batch), randcmp);
294 
295 		for (i = 0; i < batch_size; i++) {
296 			UDP_UNNAT_CHECK(p, u,
297 			    batch[i].dst,  batch[i].dport,
298 			    masq, batch[i].aport,
299 			    batch[i].src, batch[i].sport);
300 		}
301 	}
302 
303 	free(batch);
304 	free(p);
305 	LibAliasUninit(la);
306 }
307 
308 ATF_TC_WITHOUT_HEAD(8_portrange);
309 ATF_TC_BODY(8_portrange, dummy)
310 {
311 	struct libalias *la = LibAliasInit(NULL);
312 	struct ip  *po;
313 	struct udphdr *uo;
314 	uint16_t sport = 0x1234;
315 	uint16_t dport = 0x5678;
316 	uint16_t aport;
317 
318 	ATF_REQUIRE(la != NULL);
319 	LibAliasSetAddress(la, masq);
320 	LibAliasSetMode(la, 0, ~0);
321 	po = ip_packet(0, 64);
322 
323 	LibAliasSetAliasPortRange(la, 0, 0); /* reinit like ipfw */
324 	UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);
325 	aport = ntohs(uo->uh_sport);
326 	ATF_CHECK(aport >= 0x8000);
327 
328 	/* Different larger range */
329 	LibAliasSetAliasPortRange(la, 2000, 3000);
330 	dport++;
331 	UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);
332 	aport = ntohs(uo->uh_sport);
333 	ATF_CHECK(aport >= 2000 && aport < 3000);
334 
335 	/* Different small range (contains two ports) */
336 	LibAliasSetAliasPortRange(la, 4000, 4001);
337 	dport++;
338 	UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);
339 	aport = ntohs(uo->uh_sport);
340 	ATF_CHECK(aport >= 4000 && aport <= 4001);
341 
342 	sport++;
343 	UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);
344 	aport = ntohs(uo->uh_sport);
345 	ATF_CHECK(aport >= 4000 && aport <= 4001);
346 
347 	/* Third port not available in the range */
348 	sport++;
349 	UDP_NAT_FAIL(po, uo, prv1, sport, ext, dport);
350 
351 	/* Back to normal */
352 	LibAliasSetAliasPortRange(la, 0, 0);
353 	dport++;
354 	UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);
355 	aport = ntohs(uo->uh_sport);
356 	ATF_CHECK(aport >= 0x8000);
357 
358 	free(po);
359 	LibAliasUninit(la);
360 }
361 
362 ATF_TC_WITHOUT_HEAD(9_udp_eim_mapping);
363 ATF_TC_BODY(9_udp_eim_mapping, dummy)
364 {
365 	struct libalias *la = LibAliasInit(NULL);
366 	struct ip  *po, *po2, *po3;
367 	struct udphdr *uo, *uo2, *uo3;
368 	uint16_t sport = 0x1234;
369 	uint16_t dport = 0x5678;
370 	uint16_t dport2 = 0x6789;
371 	uint16_t aport, aport2, aport3;
372 
373 	ATF_REQUIRE(la != NULL);
374 	LibAliasSetAddress(la, masq);
375 	LibAliasSetMode(la, PKT_ALIAS_UDP_EIM, ~0);
376 
377 	po = ip_packet(0, 64);
378 	UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);
379 	aport = ntohs(uo->uh_sport);
380 
381 	/* Change of dst port shouldn't change alias port */
382 	po2 = ip_packet(0, 64);
383 	UDP_NAT_CHECK(po2, uo2, prv1, sport, ext, dport2, masq);
384 	aport2 = ntohs(uo2->uh_sport);
385 	ATF_CHECK_EQ_MSG(aport, aport2,
386 	    "NAT uses address- and port-dependent mapping (%uh -> %uh)",
387 	    aport, aport2);
388 
389 	/* Change of dst address shouldn't change alias port */
390 	po3 = ip_packet(0, 64);
391 	UDP_NAT_CHECK(po3, uo3, prv1, sport, pub, dport, masq);
392 	aport3 = ntohs(uo3->uh_sport);
393 	ATF_CHECK_EQ_MSG(aport, aport3, "NAT uses address-dependent mapping");
394 
395 	free(po);
396 	free(po2);
397 	free(po3);
398 	LibAliasUninit(la);
399 }
400 
401 ATF_TC_WITHOUT_HEAD(10_udp_eim_out_in);
402 ATF_TC_BODY(10_udp_eim_out_in, dummy)
403 {
404 	struct libalias *la = LibAliasInit(NULL);
405 	struct ip *po, *po2, *po3;
406 	struct udphdr *uo, *uo2, *uo3;
407 	uint16_t sport = 0x1234;
408 	uint16_t dport = 0x5678;
409 	uint16_t dport2 = 0x6789;
410 	uint16_t aport;
411 
412 	ATF_REQUIRE(la != NULL);
413 	LibAliasSetAddress(la, masq);
414 	LibAliasSetMode(la, PKT_ALIAS_UDP_EIM, ~0);
415 
416 	po = ip_packet(0, 64);
417 	UDP_NAT_CHECK(po, uo, prv1, sport, pub, dport, masq);
418 	aport = ntohs(uo->uh_sport);
419 
420 	/* Accepts inbound packets from different port */
421 	po2 = ip_packet(0, 64);
422 	UDP_UNNAT_CHECK(po2, uo2, pub, dport2, masq, aport, prv1, sport);
423 
424 	/* Accepts inbound packets from differerent host and port */
425 	po3 = ip_packet(0, 64);
426 	UDP_UNNAT_CHECK(po3, uo3, pub2, dport2, masq, aport, prv1, sport);
427 
428 	free(po);
429 	free(po2);
430 	free(po3);
431 	LibAliasUninit(la);
432 }
433 
434 ATF_TC_WITHOUT_HEAD(11_udp_eim_with_deny_incoming);
435 ATF_TC_BODY(11_udp_eim_with_deny_incoming, dummy)
436 {
437 	struct libalias *la = LibAliasInit(NULL);
438 	struct ip *po, *po2, *po3, *po4;
439 	struct udphdr *uo;
440 	uint16_t sport = 0x1234;
441 	uint16_t dport = 0x5678;
442 	uint16_t dport2 = 0x6789;
443 	uint16_t aport;
444 	int ret;
445 
446 	ATF_REQUIRE(la != NULL);
447 	LibAliasSetAddress(la, masq);
448 	LibAliasSetMode(la,
449 	    PKT_ALIAS_UDP_EIM | PKT_ALIAS_DENY_INCOMING,
450 	    ~0);
451 
452 	po = ip_packet(0, 64);
453 	UDP_NAT_CHECK(po, uo, prv1, sport, pub, dport, masq);
454 	aport = ntohs(uo->uh_sport);
455 
456 	po2 = ip_packet(0, 64);
457 	po2->ip_src = pub;
458 	po2->ip_dst = masq;
459 	set_udp(po2, dport, aport);
460 	ret = LibAliasIn(la, po2, 64);
461 	ATF_CHECK_EQ_MSG(PKT_ALIAS_OK, ret,
462 	    "LibAliasIn failed with error %d\n", ret);
463 
464 	po3 = ip_packet(0, 64);
465 	po3->ip_src = pub;
466 	po3->ip_dst = masq;
467 	set_udp(po3, dport2, aport);
468 	ret = LibAliasIn(la, po3, 64);
469 	ATF_CHECK_EQ_MSG(PKT_ALIAS_IGNORED, ret,
470 	    "incoming packet from different port not ignored "
471 	    "with PKT_ALIAS_DENY_INCOMING");
472 
473 	po4 = ip_packet(0, 64);
474 	po4->ip_src = pub2;
475 	po4->ip_dst = masq;
476 	set_udp(po4, dport2, aport);
477 	ret = LibAliasIn(la, po4, 64);
478 	ATF_CHECK_EQ_MSG(PKT_ALIAS_IGNORED, ret,
479 	    "incoming packet from different address and port not ignored "
480 	    "with PKT_ALIAS_DENY_INCOMING");
481 
482 	free(po);
483 	free(po2);
484 	free(po3);
485 	free(po4);
486 	LibAliasUninit(la);
487 }
488 
489 ATF_TC_WITHOUT_HEAD(12_udp_eim_hairpinning);
490 ATF_TC_BODY(12_udp_eim_hairpinning, dummy)
491 {
492 	struct libalias *la = LibAliasInit(NULL);
493 	struct ip *po, *po2, *po3;
494 	struct udphdr *uo, *uo2, *uo3;
495 	uint16_t sport1 = 0x1234;
496 	uint16_t sport2 = 0x2345;
497 	uint16_t dport = 0x5678;
498 	uint16_t extport1, extport2;
499 
500 	ATF_REQUIRE(la != NULL);
501 	LibAliasSetAddress(la, masq);
502 	LibAliasSetMode(la, PKT_ALIAS_UDP_EIM, ~0);
503 
504 	/* prv1 sends out somewhere (eg. a STUN server) */
505 	po = ip_packet(0, 64);
506 	UDP_NAT_CHECK(po, uo, prv1, sport1, pub, dport, masq);
507 	extport1 = ntohs(uo->uh_sport);
508 
509 	/* prv2, behind the same NAT as prv1, also sends out somewhere */
510 	po2 = ip_packet(0, 64);
511 	UDP_NAT_CHECK(po2, uo2, prv2, sport2, pub, dport, masq);
512 	extport2 = ntohs(uo2->uh_sport);
513 
514 	/* hairpin: prv1 sends to prv2's external NAT mapping
515 	 * (unaware it could address it internally instead).
516 	 */
517 	po3 = ip_packet(0, 64);
518 	UDP_NAT_CHECK(po3, uo3, prv1, sport1, masq, extport2, masq);
519 	UDP_UNNAT_CHECK(po3, uo3, masq, extport1, masq, extport2,
520 	    prv2, sport2);
521 
522 	free(po);
523 	free(po2);
524 	free(po3);
525 	LibAliasUninit(la);
526 }
527 
528 ATF_TP_ADD_TCS(natout)
529 {
530 	/* Use "dd if=/dev/random bs=2 count=1 | od -x" to reproduce */
531 	srand(0x0b61);
532 
533 	ATF_TP_ADD_TC(natout, 1_simplemasq);
534 	ATF_TP_ADD_TC(natout, 2_unregistered);
535 	ATF_TP_ADD_TC(natout, 3_cgn);
536 	ATF_TP_ADD_TC(natout, 4_udp);
537 	ATF_TP_ADD_TC(natout, 5_sameport);
538 	ATF_TP_ADD_TC(natout, 6_cleartable);
539 	ATF_TP_ADD_TC(natout, 7_stress);
540 	ATF_TP_ADD_TC(natout, 8_portrange);
541 	ATF_TP_ADD_TC(natout, 9_udp_eim_mapping);
542 	ATF_TP_ADD_TC(natout, 10_udp_eim_out_in);
543 	ATF_TP_ADD_TC(natout, 11_udp_eim_with_deny_incoming);
544 	ATF_TP_ADD_TC(natout, 12_udp_eim_hairpinning);
545 
546 	return atf_no_error();
547 }
548