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
usage(void)61 usage(void) {
62 printf("Usage: perf [max_seconds [batch_size [random_size [attack_size [redir_size]]]]]\n");
63 exit(1);
64 }
65
main(int argc,char ** argv)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