/* * SPDX-License-Identifier: BSD-3-Clause * * Copyright 2021 Lutz Donnerhacke * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "util.h" #include static void usage(void); #define timevalcmp(tv, uv, cmp) \ (((tv).tv_sec == (uv).tv_sec) \ ? ((tv).tv_usec cmp (uv).tv_usec) \ : ((tv).tv_sec cmp (uv).tv_sec)) #define timevaldiff(n, o) (float) \ (((n).tv_sec - (o).tv_sec)*1000000l + \ ((n).tv_usec - (o).tv_usec)) #define check_timeout() do { \ if (check_timeout_cnt++ > 1000) { \ check_timeout_cnt = 0; \ gettimeofday(&now, NULL); \ if (timevalcmp(now, timeout, >=)) \ goto out; \ } } while(0) static void usage(void) { printf("Usage: perf [max_seconds [batch_size [random_size [attack_size [redir_size]]]]]\n"); exit(1); } int main(int argc, char ** argv) { struct libalias *la; struct timeval timeout, now, start; struct ip *p; struct udphdr *u; struct { struct in_addr src, dst; uint16_t sport, dport, aport; } *batch; struct { unsigned long ok, fail; } nat, usenat, unnat, random, attack; int i, round, check_timeout_cnt = 0; int max_seconds = 90, batch_size = 2000, random_size = 1000, attack_size = 1000, redir_size = 2000; if (argc >= 2) { char * end; max_seconds = strtol(argv[1], &end, 10); if (max_seconds < 2 || end[0] != '\0') usage(); } if (argc > 2 && (batch_size = atoi(argv[2])) < 0) usage(); if (argc > 3 && (random_size = atoi(argv[3])) < 0) usage(); if (argc > 4 && (attack_size = atoi(argv[4])) < 0) usage(); if (argc > 5 && (redir_size = atoi(argv[5])) < 0) usage(); printf("Running perfomance test with parameters:\n"); printf(" Maximum Runtime (max_seconds) = %d\n", max_seconds); printf(" Amount of valid connections (batch_size) = %d\n", batch_size); printf(" Amount of random, incoming packets (batch_size) = %d\n", random_size); printf(" Repeat count of a random, incoming packet (attack_size) = %d\n", attack_size); printf(" Amount of open port forwardings (redir_size) = %d\n", redir_size); printf("\n"); if (NULL == (la = LibAliasInit(NULL))) { perror("LibAliasInit"); return -1; } bzero(&nat, sizeof(nat)); bzero(&usenat, sizeof(usenat)); bzero(&unnat, sizeof(unnat)); bzero(&random, sizeof(random)); bzero(&attack, sizeof(attack)); LibAliasSetAddress(la, masq); LibAliasSetMode(la, PKT_ALIAS_SAME_PORTS | PKT_ALIAS_DENY_INCOMING, ~0); prv1.s_addr &= htonl(0xffff0000); ext.s_addr &= htonl(0xffff0000); for (i = 0; i < redir_size; i++) { int aport = htons(rand_range(1000, 2000)); int sport = htons(rand_range(1000, 2000)); prv2.s_addr &= htonl(0xffff0000); prv2.s_addr |= rand_range(0, 0xffff); LibAliasRedirectPort(la, prv2, sport, ANY_ADDR, 0, masq, aport, IPPROTO_UDP); } p = ip_packet(0, 64); u = set_udp(p, 0, 0); if (NULL == (batch = calloc(batch_size, sizeof(*batch)))) { perror("calloc(batch)"); return -1; } gettimeofday(&timeout, NULL); timeout.tv_sec += max_seconds; printf("RND SECOND newNAT RANDOM ATTACK useNAT\n"); for (round = 0; ; round++) { int res, cnt; printf("%3d ", round+1); gettimeofday(&start, NULL); printf("%6.1f ", max_seconds - timevaldiff(timeout, start)/1000000.0f); for (cnt = i = 0; i < batch_size; i++, cnt++) { batch[i].src.s_addr = prv1.s_addr | htonl(rand_range(0, 0xffff)); batch[i].dst.s_addr = ext.s_addr | htonl(rand_range(0, 0xffff)); batch[i].sport = rand_range(1000, 60000); batch[i].dport = rand_range(1000, 60000); p->ip_src = batch[i].src; p->ip_dst = batch[i].dst; u = set_udp(p, batch[i].sport, batch[i].dport); res = LibAliasOut(la, p, 64); batch[i].aport = htons(u->uh_sport); if (res == PKT_ALIAS_OK && u->uh_dport == htons(batch[i].dport) && addr_eq(p->ip_dst, batch[i].dst) && addr_eq(p->ip_src, masq)) nat.ok++; else nat.fail++; check_timeout(); } gettimeofday(&now, NULL); if (cnt > 0) printf("%6.2f ", timevaldiff(now, start) / cnt); else printf("------ "); start = now; for (cnt = i = 0; i < random_size; i++, cnt++) { p->ip_src.s_addr = ext.s_addr & htonl(0xfff00000); p->ip_src.s_addr |= htonl(rand_range(0, 0xffff)); p->ip_dst = masq; u = set_udp(p, rand_range(1, 0xffff), rand_range(1, 0xffff)); res = LibAliasIn(la, p, 64); if (res == PKT_ALIAS_OK) random.ok++; else random.fail++; check_timeout(); } gettimeofday(&now, NULL); if (cnt > 0) printf("%6.2f ", timevaldiff(now, start) / cnt); else printf("------ "); start = now; p->ip_src.s_addr = ext.s_addr & htonl(0xfff00000); p->ip_src.s_addr |= htonl(rand_range(0, 0xffff)); p->ip_dst = masq; u = set_udp(p, rand_range(1, 0xffff), rand_range(1, 0xffff)); for (cnt = i = 0; i < attack_size; i++, cnt++) { res = LibAliasIn(la, p, 64); if (res == PKT_ALIAS_OK) attack.ok++; else attack.fail++; check_timeout(); } gettimeofday(&now, NULL); if (cnt > 0) printf("%6.2f ", timevaldiff(now, start) / cnt); else printf("------ "); qsort(batch, batch_size, sizeof(*batch), randcmp); gettimeofday(&start, NULL); for (cnt = i = 0; i < batch_size; i++) { int j; /* random communication length */ for(j = rand_range(1, 150); j-- > 0; cnt++) { int k; /* a random flow out of rolling window */ k = rand_range(i, i + 25); if (k >= batch_size) k = i; /* 10% outgoing, 90% incoming */ if (rand_range(0, 100) > 10) { p->ip_src = batch[k].dst; p->ip_dst = masq; u = set_udp(p, batch[k].dport, batch[k].aport); res = LibAliasIn(la, p, 64); if (res == PKT_ALIAS_OK && u->uh_sport == htons(batch[k].dport) && u->uh_dport == htons(batch[k].sport) && addr_eq(p->ip_dst, batch[k].src) && addr_eq(p->ip_src, batch[k].dst)) unnat.ok++; else unnat.fail++; } else { p->ip_src = batch[k].src; p->ip_dst = batch[k].dst; u = set_udp(p, batch[k].sport, batch[k].dport); res = LibAliasOut(la, p, 64); if (res == PKT_ALIAS_OK && u->uh_sport == htons(batch[k].aport) && u->uh_dport == htons(batch[k].dport) && addr_eq(p->ip_dst, batch[k].dst) && addr_eq(p->ip_src, masq)) usenat.ok++; else usenat.fail++; } check_timeout(); } } gettimeofday(&now, NULL); if (cnt > 0) printf("%6.2f ", timevaldiff(now, start) / cnt); else printf("------ "); printf("\n"); } out: printf("\n\n"); free(batch); free(p); printf("Results\n"); printf(" Rounds : %9u\n", round); printf("newNAT ok : %9lu\n", nat.ok); printf("newNAT fail: %9lu\n", nat.fail); printf("useNAT ok : %9lu (out)\n", usenat.ok); printf("useNAT fail: %9lu (out)\n", usenat.fail); printf("useNAT ok : %9lu (in)\n", unnat.ok); printf("useNAT fail: %9lu (in)\n", unnat.fail); printf("RANDOM ok : %9lu\n", random.ok); printf("RANDOM fail: %9lu\n", random.fail); printf("ATTACK ok : %9lu\n", attack.ok); printf("ATTACK fail: %9lu\n", attack.fail); printf(" ---------\n"); printf(" Total: %9lu\n", nat.ok + nat.fail + unnat.ok + unnat.fail + usenat.ok + usenat.fail + random.ok + random.fail + attack.ok + attack.fail); gettimeofday(&start, NULL); printf("\n Cleanup : "); LibAliasUninit(la); gettimeofday(&now, NULL); printf("%.2fs\n", timevaldiff(now, start)/1000000l); return (0); }