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