145501Sjdp/* 262801Sjdp * SPDX-License-Identifier: BSD-3-Clause 345501Sjdp * 445501Sjdp * Copyright 2021 Lutz Donnerhacke 545501Sjdp * 645501Sjdp * Redistribution and use in source and binary forms, with or without 745501Sjdp * modification, are permitted provided that the following conditions 845501Sjdp * are met: 945501Sjdp * 1045501Sjdp * 1. Redistributions of source code must retain the above copyright 1145501Sjdp * notice, this list of conditions and the following disclaimer. 1245501Sjdp * 2. Redistributions in binary form must reproduce the above 1345501Sjdp * copyright notice, this list of conditions and the following 1445501Sjdp * disclaimer in the documentation and/or other materials provided 1545501Sjdp * with the distribution. 1645501Sjdp * 3. Neither the name of the copyright holder nor the names of its 1745501Sjdp * contributors may be used to endorse or promote products derived 1845501Sjdp * from this software without specific prior written permission. 1945501Sjdp * 2045501Sjdp * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 2145501Sjdp * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 2245501Sjdp * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 2345501Sjdp * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2445501Sjdp * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 2545501Sjdp * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 2650476Speter * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2745501Sjdp * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2845501Sjdp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 2945501Sjdp * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 3045501Sjdp * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 3145501Sjdp * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3245501Sjdp * SUCH DAMAGE. 3345501Sjdp */ 3445501Sjdp#include <atf-c.h> 3545501Sjdp#include <alias.h> 3648205Sjdp#include <stdio.h> 3748205Sjdp#include <stdlib.h> 3848205Sjdp 3948205Sjdp#include "util.h" 4048205Sjdp 4148205SjdpATF_TC_WITHOUT_HEAD(1_simplemasq); 4248205SjdpATF_TC_BODY(1_simplemasq, dummy) 4348205Sjdp{ 4462801Sjdp struct libalias *la = LibAliasInit(NULL); 4562801Sjdp struct ip *pip; 4662801Sjdp 4762801Sjdp ATF_REQUIRE(la != NULL); 4862801Sjdp LibAliasSetAddress(la, masq); 4962801Sjdp LibAliasSetMode(la, 0, ~0); 5062801Sjdp 5162801Sjdp pip = ip_packet(254, 64); 5262801Sjdp NAT_CHECK(pip, prv1, ext, masq); 5362801Sjdp NAT_CHECK(pip, prv2, ext, masq); 5462801Sjdp NAT_CHECK(pip, prv3, ext, masq); 5562801Sjdp NAT_CHECK(pip, cgn, ext, masq); 5662801Sjdp NAT_CHECK(pip, pub, ext, masq); 5762801Sjdp 5862801Sjdp free(pip); 5962801Sjdp LibAliasUninit(la); 6062801Sjdp} 6162801Sjdp 6262801SjdpATF_TC_WITHOUT_HEAD(2_unregistered); 6362801SjdpATF_TC_BODY(2_unregistered, dummy) 6462801Sjdp{ 6545501Sjdp 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 95ATF_TC_WITHOUT_HEAD(3_cgn); 96ATF_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 128ATF_TC_WITHOUT_HEAD(4_udp); 129ATF_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 170ATF_TC_WITHOUT_HEAD(5_sameport); 171ATF_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 200ATF_TC_WITHOUT_HEAD(6_cleartable); 201ATF_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 247ATF_TC_WITHOUT_HEAD(7_stress); 248ATF_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 308ATF_TC_WITHOUT_HEAD(8_portrange); 309ATF_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 362ATF_TP_ADD_TCS(natout) 363{ 364 /* Use "dd if=/dev/random bs=2 count=1 | od -x" to reproduce */ 365 srand(0x0b61); 366 367 ATF_TP_ADD_TC(natout, 1_simplemasq); 368 ATF_TP_ADD_TC(natout, 2_unregistered); 369 ATF_TP_ADD_TC(natout, 3_cgn); 370 ATF_TP_ADD_TC(natout, 4_udp); 371 ATF_TP_ADD_TC(natout, 5_sameport); 372 ATF_TP_ADD_TC(natout, 6_cleartable); 373 ATF_TP_ADD_TC(natout, 7_stress); 374 ATF_TP_ADD_TC(natout, 8_portrange); 375 376 return atf_no_error(); 377} 378