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
41ATF_TC_WITHOUT_HEAD(1_portforward);
42ATF_TC_BODY(1_portforward, dummy)
43{
44	struct libalias *la = LibAliasInit(NULL);
45	struct alias_link *pf1, *pf2, *pf3, *pf4;
46	struct ip *p;
47	struct udphdr *u;
48
49	ATF_REQUIRE(la != NULL);
50	LibAliasSetAddress(la, masq);
51	LibAliasSetMode(la, PKT_ALIAS_RESET_ON_ADDR_CHANGE, ~0);
52	LibAliasSetMode(la, PKT_ALIAS_DENY_INCOMING, PKT_ALIAS_DENY_INCOMING);
53
54	/*
55	 * Fully specified
56	 */
57	pf1 = LibAliasRedirectPort(la, prv1, ntohs(0x1234), ext, ntohs(0x5678), masq, ntohs(0xabcd), IPPROTO_UDP);
58	ATF_REQUIRE(pf1 != NULL);
59
60	p = ip_packet(0, 64);
61	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv1, 0x1234);
62	/* try again */
63	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv1, 0x1234);
64	/* different source */
65	UDP_UNNAT_FAIL(p, u, pub, 0x5678, masq, 0xabcd);
66	UDP_UNNAT_FAIL(p, u, ext, 0xdead, masq, 0xabcd);
67
68	/* clear table by keeping the address */
69	LibAliasSetAddress(la, ext);
70	LibAliasSetAddress(la, masq);
71
72	/* delete and try again */
73	LibAliasRedirectDelete(la, pf1);
74	UDP_UNNAT_FAIL(p, u, ext, 0x5678, masq, 0xabcd);
75
76	/*
77	 * Any external port
78	 */
79	pf2 = LibAliasRedirectPort(la, prv2, ntohs(0x1234), ext, ntohs(0), masq, ntohs(0xabcd), IPPROTO_UDP);
80	ATF_REQUIRE(pf2 != NULL);
81
82	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv2, 0x1234);
83	/* try again */
84	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv2, 0x1234);
85	/* different source */
86	UDP_UNNAT_FAIL(p, u, pub, 0x5678, masq, 0xabcd);
87	UDP_UNNAT_CHECK(p, u, ext, 0xdead, masq, 0xabcd, prv2, 0x1234);
88
89	/* clear table by keeping the address */
90	LibAliasSetAddress(la, ext);
91	LibAliasSetAddress(la, masq);
92
93	/* delete and try again */
94	LibAliasRedirectDelete(la, pf2);
95	UDP_UNNAT_FAIL(p, u, ext, 0x5678, masq, 0xabcd);
96
97	/*
98	 * Any external host
99	 */
100	pf3 = LibAliasRedirectPort(la, prv3, ntohs(0x1234), ANY_ADDR, ntohs(0x5678), masq, ntohs(0xabcd), IPPROTO_UDP);
101	ATF_REQUIRE(pf3 != NULL);
102
103	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv3, 0x1234);
104	/* try again */
105	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv3, 0x1234);
106	/* different source */
107	UDP_UNNAT_CHECK(p, u, pub, 0x5678, masq, 0xabcd, prv3, 0x1234);
108	UDP_UNNAT_FAIL(p, u, ext, 0xdead, masq, 0xabcd);
109
110	/* clear table by keeping the address */
111	LibAliasSetAddress(la, ext);
112	LibAliasSetAddress(la, masq);
113
114	/* delete and try again */
115	LibAliasRedirectDelete(la, pf3);
116	UDP_UNNAT_FAIL(p, u, ext, 0x5678, masq, 0xabcd);
117
118	/*
119	 * Any external host, any port
120	 */
121	pf4 = LibAliasRedirectPort(la, cgn, ntohs(0x1234), ANY_ADDR, ntohs(0), masq, ntohs(0xabcd), IPPROTO_UDP);
122	ATF_REQUIRE(pf4 != NULL);
123
124	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, cgn, 0x1234);
125	/* try again */
126	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, cgn, 0x1234);
127	/* different source */
128	UDP_UNNAT_CHECK(p, u, pub, 0x5678, masq, 0xabcd, cgn, 0x1234);
129	UDP_UNNAT_CHECK(p, u, ext, 0xdead, masq, 0xabcd, cgn, 0x1234);
130
131	/* clear table by keeping the address */
132	LibAliasSetAddress(la, ext);
133	LibAliasSetAddress(la, masq);
134
135	/* delete and try again */
136	LibAliasRedirectDelete(la, pf4);
137	UDP_UNNAT_FAIL(p, u, ext, 0x5678, masq, 0xabcd);
138
139	free(p);
140	LibAliasUninit(la);
141}
142
143ATF_TC_WITHOUT_HEAD(2_portoverlap);
144ATF_TC_BODY(2_portoverlap, dummy)
145{
146	struct libalias *la = LibAliasInit(NULL);
147	struct alias_link *pf1, *pf2, *pf3, *pf4;
148	struct ip *p;
149	struct udphdr *u;
150
151	ATF_REQUIRE(la != NULL);
152	LibAliasSetAddress(la, masq);
153	LibAliasSetMode(la, PKT_ALIAS_RESET_ON_ADDR_CHANGE, ~0);
154	LibAliasSetMode(la, PKT_ALIAS_DENY_INCOMING, PKT_ALIAS_DENY_INCOMING);
155
156	/*
157	 * Fully specified
158	 */
159	pf1 = LibAliasRedirectPort(la, prv2, ntohs(0x1234), ext, ntohs(0x5678), masq, ntohs(0xabcd), IPPROTO_UDP);
160	ATF_REQUIRE(pf1 != NULL);
161
162	p = ip_packet(0, 64);
163	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv2, 0x1234);
164
165	/* clear table by keeping the address */
166	LibAliasSetAddress(la, ext);
167	LibAliasSetAddress(la, masq);
168
169	/*
170	 * Fully specified (override)
171	 */
172	pf1 = LibAliasRedirectPort(la, prv1, ntohs(0x1234), ext, ntohs(0x5678), masq, ntohs(0xabcd), IPPROTO_UDP);
173	ATF_REQUIRE(pf1 != NULL);
174
175	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv1, 0x1234);
176
177	/* clear table by keeping the address */
178	LibAliasSetAddress(la, ext);
179	LibAliasSetAddress(la, masq);
180
181	/*
182	 * Any external port
183	 */
184	pf2 = LibAliasRedirectPort(la, prv2, ntohs(0x1234), ext, ntohs(0), masq, ntohs(0xabcd), IPPROTO_UDP);
185	ATF_REQUIRE(pf2 != NULL);
186
187	UDP_UNNAT_CHECK(p, u, ext, 0x5679, masq, 0xabcd, prv2, 0x1234);
188	/* more specific rule wins */
189	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv1, 0x1234);
190
191	/* clear table by keeping the address */
192	LibAliasSetAddress(la, ext);
193	LibAliasSetAddress(la, masq);
194
195	/*
196	 * Any external host
197	 */
198	pf3 = LibAliasRedirectPort(la, prv3, ntohs(0x1234), ANY_ADDR, ntohs(0x5678), masq, ntohs(0xabcd), IPPROTO_UDP);
199	ATF_REQUIRE(pf3 != NULL);
200
201	UDP_UNNAT_CHECK(p, u, pub, 0x5678, masq, 0xabcd, prv3, 0x1234);
202	/* more specific rule wins */
203	UDP_UNNAT_CHECK(p, u, ext, 0x5679, masq, 0xabcd, prv2, 0x1234);
204	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv1, 0x1234);
205
206	/* clear table by keeping the address */
207	LibAliasSetAddress(la, ext);
208	LibAliasSetAddress(la, masq);
209
210	/*
211	 * Any external host, any port
212	 */
213	pf4 = LibAliasRedirectPort(la, cgn, ntohs(0x1234), ANY_ADDR, ntohs(0), masq, ntohs(0xabcd), IPPROTO_UDP);
214	ATF_REQUIRE(pf4 != NULL);
215
216	UDP_UNNAT_CHECK(p, u, prv1, 0x5679, masq, 0xabcd, cgn, 0x1234);
217	/* more specific rule wins */
218	UDP_UNNAT_CHECK(p, u, pub, 0x5678, masq, 0xabcd, prv3, 0x1234);
219	UDP_UNNAT_CHECK(p, u, ext, 0x5679, masq, 0xabcd, prv2, 0x1234);
220	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv1, 0x1234);
221
222	free(p);
223	LibAliasUninit(la);
224}
225
226ATF_TC_WITHOUT_HEAD(3_redirectany);
227ATF_TC_BODY(3_redirectany, dummy)
228{
229	struct libalias *la = LibAliasInit(NULL);
230	struct alias_link *pf;
231	struct ip *p;
232	struct udphdr *u;
233
234	ATF_REQUIRE(la != NULL);
235	LibAliasSetMode(la, PKT_ALIAS_DENY_INCOMING, ~0);
236	p = ip_packet(0, 64);
237
238	pf = LibAliasRedirectPort(la, prv1, ntohs(0x1234), ANY_ADDR, 0, ANY_ADDR, ntohs(0xabcd), IPPROTO_UDP);
239	ATF_REQUIRE(pf != NULL);
240
241	LibAliasSetAddress(la, masq);
242	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv1, 0x1234);
243	UDP_UNNAT_FAIL(p, u, pub, 0x5678, pub, 0xabcd);
244
245	LibAliasSetAddress(la, pub);
246	UDP_UNNAT_CHECK(p, u, pub, 0x5679, pub, 0xabcd, prv1, 0x1234);
247	UDP_UNNAT_FAIL(p, u, ext, 0x5679, masq, 0xabcd);
248
249	free(p);
250	LibAliasUninit(la);
251}
252
253ATF_TC_WITHOUT_HEAD(4_redirectaddr);
254ATF_TC_BODY(4_redirectaddr, dummy)
255{
256	struct libalias *la = LibAliasInit(NULL);
257	struct alias_link *pf1, *pf2;
258	struct ip *p;
259
260	ATF_REQUIRE(la != NULL);
261	LibAliasSetAddress(la, masq);
262	pf1 = LibAliasRedirectAddr(la, prv1, pub);
263	ATF_REQUIRE(pf1 != NULL);
264
265	p = ip_packet(254, 64);
266	UNNAT_CHECK(p, ext, pub, prv1);
267	UNNAT_CHECK(p, ext, masq, masq);
268
269	pf2 = LibAliasRedirectAddr(la, prv2, pub);
270	ATF_REQUIRE(pf2 != NULL);
271	UNNAT_CHECK(p, ext, pub, prv1);
272	p->ip_p = 253;		       /* new flows */
273	UNNAT_CHECK(p, ext, pub, prv2);
274	UNNAT_CHECK(p, ext, masq, masq);
275
276	p->ip_p = 252;		       /* new flows */
277	NAT_CHECK(p, prv1, ext, pub);
278	NAT_CHECK(p, prv2, ext, pub);
279	NAT_CHECK(p, prv3, ext, masq);
280
281	LibAliasSetMode(la, PKT_ALIAS_DENY_INCOMING, ~0);
282	p->ip_p = 251;		       /* new flows */
283	UNNAT_FAIL(p, ext, pub);
284	UNNAT_FAIL(p, ext, masq);
285
286	/* unhide older version */
287	LibAliasRedirectDelete(la, pf2);
288	LibAliasSetMode(la, 0, ~0);
289	p->ip_p = 250;		       /* new flows */
290	UNNAT_CHECK(p, ext, pub, prv1);
291
292	p->ip_p = 249;		       /* new flows */
293	NAT_CHECK(p, prv1, ext, pub);
294	NAT_CHECK(p, prv2, ext, masq);
295	NAT_CHECK(p, prv3, ext, masq);
296
297	free(p);
298	LibAliasUninit(la);
299}
300
301ATF_TC_WITHOUT_HEAD(5_lsnat);
302ATF_TC_BODY(5_lsnat, dummy)
303{
304	struct libalias *la = LibAliasInit(NULL);
305	struct alias_link *pf;
306	struct ip *p;
307	struct udphdr *u;
308
309	ATF_REQUIRE(la != NULL);
310	LibAliasSetMode(la, 0, ~0);
311	p = ip_packet(0, 64);
312
313	pf = LibAliasRedirectPort(la, cgn, ntohs(0xdead), ANY_ADDR, 0, masq, ntohs(0xabcd), IPPROTO_UDP);
314	ATF_REQUIRE(pf != NULL);
315
316	ATF_REQUIRE(0 == LibAliasAddServer(la, pf, prv1, ntohs(0x1234)));
317	ATF_REQUIRE(0 == LibAliasAddServer(la, pf, prv2, ntohs(0x2345)));
318	ATF_REQUIRE(0 == LibAliasAddServer(la, pf, prv3, ntohs(0x3456)));
319
320	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv3, 0x3456);
321	UDP_UNNAT_CHECK(p, u, ext, 0x5679, masq, 0xabcd, prv2, 0x2345);
322	UDP_UNNAT_CHECK(p, u, ext, 0x567a, masq, 0xabcd, prv1, 0x1234);
323	UDP_UNNAT_CHECK(p, u, ext, 0x567b, masq, 0xabcd, prv3, 0x3456);
324	UDP_UNNAT_CHECK(p, u, ext, 0x567c, masq, 0xabcd, prv2, 0x2345);
325	UDP_UNNAT_CHECK(p, u, ext, 0x567d, masq, 0xabcd, prv1, 0x1234);
326
327	free(p);
328	LibAliasUninit(la);
329}
330
331ATF_TC_WITHOUT_HEAD(6_oneshot);
332ATF_TC_BODY(6_oneshot, dummy)
333{
334	struct libalias *la = LibAliasInit(NULL);
335	struct alias_link *pf;
336	struct ip *p;
337	struct udphdr *u;
338
339	ATF_REQUIRE(la != NULL);
340	LibAliasSetMode(la, 0, ~0);
341	LibAliasSetMode(la, PKT_ALIAS_RESET_ON_ADDR_CHANGE, ~0);
342	LibAliasSetMode(la, PKT_ALIAS_DENY_INCOMING, PKT_ALIAS_DENY_INCOMING);
343
344	pf = LibAliasRedirectPort(la, prv1, ntohs(0x1234), ANY_ADDR, 0, masq, ntohs(0xabcd), IPPROTO_UDP);
345	ATF_REQUIRE(pf != NULL);
346	/* only for fully specified links */
347	ATF_CHECK(-1 == LibAliasRedirectDynamic(la, pf));
348	LibAliasRedirectDelete(la, pf);
349
350	pf = LibAliasRedirectPort(la, prv1, ntohs(0x1234), ext, ntohs(0x5678), masq, ntohs(0xabcd), IPPROTO_UDP);
351	ATF_REQUIRE(pf != NULL);
352	ATF_CHECK(0 == LibAliasRedirectDynamic(la, pf));
353
354	p = ip_packet(0, 64);
355	UDP_UNNAT_CHECK(p, u, ext, 0x5678, masq, 0xabcd, prv1, 0x1234);
356
357	/* clear table by keeping the address */
358	LibAliasSetAddress(la, ext);
359	LibAliasSetAddress(la, masq);
360
361	/* does not work anymore */
362	UDP_UNNAT_FAIL(p, u, ext, 0x5678, masq, 0xabcd);
363
364	free(p);
365	LibAliasUninit(la);
366}
367
368ATF_TP_ADD_TCS(natin)
369{
370	/* Use "dd if=/dev/random bs=2 count=1 | od -x" to reproduce */
371	srand(0xe859);
372
373	ATF_TP_ADD_TC(natin, 1_portforward);
374	ATF_TP_ADD_TC(natin, 2_portoverlap);
375	ATF_TP_ADD_TC(natin, 3_redirectany);
376	ATF_TP_ADD_TC(natin, 4_redirectaddr);
377	ATF_TP_ADD_TC(natin, 5_lsnat);
378	ATF_TP_ADD_TC(natin, 6_oneshot);
379
380	return atf_no_error();
381}
382