Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/netinet/libalias/2_natout.c
39488 views
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
549