xref: /freebsd/tests/sys/netinet/libalias/2_natout.c (revision d7d962ead0b6e5e8a39202d0590022082bf5bfb6)
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, *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_TP_ADD_TCS(natout)
309 {
310 	/* Use "dd if=/dev/random bs=2 count=1 | od -x" to reproduce */
311 	srand(0x0b61);
312 
313 	ATF_TP_ADD_TC(natout, 1_simplemasq);
314 	ATF_TP_ADD_TC(natout, 2_unregistered);
315 	ATF_TP_ADD_TC(natout, 3_cgn);
316 	ATF_TP_ADD_TC(natout, 4_udp);
317 	ATF_TP_ADD_TC(natout, 5_sameport);
318 	ATF_TP_ADD_TC(natout, 6_cleartable);
319 	ATF_TP_ADD_TC(natout, 7_stress);
320 
321 	return atf_no_error();
322 }
323