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 <stdio.h> 35 #include <stdlib.h> 36 #include <strings.h> 37 #include <sys/time.h> 38 #include "util.h" 39 #include <alias.h> 40 41 #define timevalcmp(tv, uv, cmp) \ 42 (((tv).tv_sec == (uv).tv_sec) \ 43 ? ((tv).tv_usec cmp (uv).tv_usec) \ 44 : ((tv).tv_sec cmp (uv).tv_sec)) 45 46 #define timevaldiff(n, o) (float) \ 47 (((n).tv_sec - (o).tv_sec)*1000000l + \ 48 ((n).tv_usec - (o).tv_usec)) 49 50 #define check_timeout() do { \ 51 if (check_timeout_cnt++ > 1000) { \ 52 check_timeout_cnt = 0; \ 53 gettimeofday(&now, NULL); \ 54 if (timevalcmp(now, timeout, >=)) \ 55 goto out; \ 56 } } while(0) 57 58 59 int main(int argc, char ** argv) 60 { 61 struct libalias *la; 62 struct timeval timeout; 63 struct ip *p; 64 struct udphdr *u; 65 struct { 66 struct in_addr src, dst; 67 uint16_t sport, dport, aport; 68 } *batch; 69 struct { 70 unsigned long ok, fail; 71 } nat, usenat, unnat, random, attack; 72 int max_seconds, batch_size, random_size, attack_length, round; 73 int check_timeout_cnt = 0; 74 75 if(argc != 5 || 76 0 > (max_seconds = atoi(argv[1])) || 77 0 >= (batch_size = atoi(argv[2])) || 78 0 >= (random_size = atoi(argv[3])) || 79 0 >= (attack_length = atoi(argv[4]))) { 80 printf("Usage: %s max_seconds batch_size random_size attack_length\n", argv[0]); 81 return 1; 82 } 83 if (NULL == (la = LibAliasInit(NULL))) { 84 perror("LibAliasInit"); 85 return -1; 86 } 87 88 bzero(&nat, sizeof(nat)); 89 bzero(&usenat, sizeof(usenat)); 90 bzero(&unnat, sizeof(unnat)); 91 bzero(&random, sizeof(random)); 92 bzero(&attack, sizeof(attack)); 93 94 LibAliasSetAddress(la, masq); 95 LibAliasSetMode(la, PKT_ALIAS_DENY_INCOMING, PKT_ALIAS_DENY_INCOMING); 96 97 prv1.s_addr &= htonl(0xffff0000); 98 ext.s_addr &= htonl(0xffff0000); 99 100 p = ip_packet(0, 64); 101 u = set_udp(p, 0, 0); 102 103 if (NULL == (batch = calloc(batch_size, sizeof(*batch)))) { 104 perror("calloc(batch)"); 105 return -1; 106 } 107 108 gettimeofday(&timeout, NULL); 109 timeout.tv_sec += max_seconds; 110 111 printf("RND SECOND newNAT RANDOM ATTACK useNAT\n"); 112 for (round = 0; ; round++) { 113 int i, res, cnt; 114 struct timeval now, start; 115 116 printf("%3d ", round+1); 117 118 gettimeofday(&start, NULL); 119 printf("%6.1f ", max_seconds - timevaldiff(timeout, start)/1000000.0f); 120 for (cnt = i = 0; i < batch_size; i++, cnt++) { 121 batch[i].src.s_addr = prv1.s_addr | htonl(rand_range(0, 0xffff)); 122 batch[i].dst.s_addr = ext.s_addr | htonl(rand_range(0, 0xffff)); 123 batch[i].sport = rand_range(1000, 60000); 124 batch[i].dport = rand_range(1000, 60000); 125 126 p->ip_src = batch[i].src; 127 p->ip_dst = batch[i].dst; 128 u = set_udp(p, batch[i].sport, batch[i].dport); 129 130 res = LibAliasOut(la, p, 64); 131 batch[i].aport = htons(u->uh_sport); 132 133 if (res == PKT_ALIAS_OK && 134 u->uh_dport == htons(batch[i].dport) && 135 addr_eq(p->ip_dst, batch[i].dst) && 136 addr_eq(p->ip_src, masq)) 137 nat.ok++; 138 else 139 nat.fail++; 140 141 check_timeout(); 142 } 143 gettimeofday(&now, NULL); 144 if (cnt > 0) 145 printf("%6.2f ", timevaldiff(now, start) / cnt); 146 147 start = now; 148 for (cnt = i = 0; i < random_size; i++, cnt++) { 149 p->ip_src.s_addr = ext.s_addr & htonl(0xfff00000); 150 p->ip_src.s_addr |= htonl(rand_range(0, 0xffff)); 151 p->ip_dst = masq; 152 u = set_udp(p, rand_range(1, 0xffff), rand_range(1, 0xffff)); 153 154 res = LibAliasIn(la, p, 64); 155 156 if (res == PKT_ALIAS_OK) 157 random.ok++; 158 else 159 random.fail++; 160 161 check_timeout(); 162 } 163 gettimeofday(&now, NULL); 164 if (cnt > 0) 165 printf("%6.2f ", timevaldiff(now, start) / cnt); 166 167 start = now; 168 p->ip_src.s_addr = ext.s_addr & htonl(0xfff00000); 169 p->ip_src.s_addr |= htonl(rand_range(0, 0xffff)); 170 p->ip_dst = masq; 171 u = set_udp(p, rand_range(1, 0xffff), rand_range(1, 0xffff)); 172 for (cnt = i = 0; i < attack_length; i++, cnt++) { 173 res = LibAliasIn(la, p, 64); 174 175 if (res == PKT_ALIAS_OK) 176 attack.ok++; 177 else 178 attack.fail++; 179 180 check_timeout(); 181 } 182 gettimeofday(&now, NULL); 183 if (cnt > 0) 184 printf("%6.2f ", timevaldiff(now, start) / cnt); 185 186 qsort(batch, batch_size, sizeof(*batch), randcmp); 187 188 gettimeofday(&start, NULL); 189 for (cnt = i = 0; i < batch_size; i++) { 190 int j; 191 192 /* random communication length */ 193 for(j = rand_range(1, 150); j-- > 0; cnt++) { 194 int k; 195 196 /* a random flow out of rolling window */ 197 k = rand_range(i, i + 25); 198 if (k >= batch_size) 199 k = i; 200 201 /* 10% outgoing, 90% incoming */ 202 if (rand_range(0, 100) > 10) { 203 p->ip_src = batch[k].dst; 204 p->ip_dst = masq; 205 u = set_udp(p, batch[k].dport, batch[k].aport); 206 207 res = LibAliasIn(la, p, 64); 208 if (res == PKT_ALIAS_OK && 209 u->uh_sport == htons(batch[k].dport) && 210 u->uh_dport == htons(batch[k].sport) && 211 addr_eq(p->ip_dst, batch[k].src) && 212 addr_eq(p->ip_src, batch[k].dst)) 213 unnat.ok++; 214 else 215 unnat.fail++; 216 } else { 217 p->ip_src = batch[k].src; 218 p->ip_dst = batch[k].dst; 219 u = set_udp(p, batch[k].sport, batch[k].dport); 220 221 res = LibAliasOut(la, p, 64); 222 if (res == PKT_ALIAS_OK && 223 u->uh_sport == htons(batch[k].aport) && 224 u->uh_dport == htons(batch[k].dport) && 225 addr_eq(p->ip_dst, batch[k].dst) && 226 addr_eq(p->ip_src, masq)) 227 usenat.ok++; 228 else 229 usenat.fail++; 230 } 231 check_timeout(); 232 } 233 } 234 gettimeofday(&now, NULL); 235 if (cnt > 0) 236 printf("%6.2f ", timevaldiff(now, start) / cnt); 237 238 printf("\n"); 239 } 240 out: 241 printf("\n\n"); 242 free(batch); 243 free(p); 244 LibAliasUninit(la); 245 246 printf("Results\n"); 247 printf(" Rounds : %9u\n", round); 248 printf("newNAT ok : %9lu\n", nat.ok); 249 printf("newNAT fail: %9lu\n", nat.fail); 250 printf("useNAT ok : %9lu (out)\n", usenat.ok); 251 printf("useNAT fail: %9lu (out)\n", usenat.fail); 252 printf("useNAT ok : %9lu (in)\n", unnat.ok); 253 printf("useNAT fail: %9lu (in)\n", unnat.fail); 254 printf("RANDOM ok : %9lu\n", random.ok); 255 printf("RANDOM fail: %9lu\n", random.fail); 256 printf("ATTACK ok : %9lu\n", attack.ok); 257 printf("ATTACK fail: %9lu\n", attack.fail); 258 printf(" ---------\n"); 259 printf(" Total: %9lu\n", 260 nat.ok + nat.fail + 261 unnat.ok + unnat.fail + 262 usenat.ok + usenat.fail + 263 random.ok + random.fail + 264 attack.ok + attack.fail); 265 return (0); 266 } 267