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