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