xref: /freebsd/tests/sys/netinet/libalias/perf.c (revision 6e87898a2c7e99937656a0c12d03333a43a10c5e)
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