BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file dostest-attacker.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include <stdlib.h>
34  
35 #include <misc/debug.h>
36 #include <misc/version.h>
37 #include <misc/offset.h>
38 #include <misc/open_standard_streams.h>
39 #include <misc/balloc.h>
40 #include <misc/loglevel.h>
41 #include <misc/minmax.h>
42 #include <structure/LinkedList1.h>
43 #include <base/BLog.h>
44 #include <system/BAddr.h>
45 #include <system/BReactor.h>
46 #include <system/BNetwork.h>
47 #include <system/BConnection.h>
48 #include <system/BSignal.h>
49  
50 #include <generated/blog_channel_dostest_attacker.h>
51  
52 #define PROGRAM_NAME "dostest-attacker"
53  
54 // connection structure
55 struct connection {
56 int connected;
57 BConnector connector;
58 BConnection con;
59 StreamRecvInterface *recv_if;
60 uint8_t buf[512];
61 LinkedList1Node connections_list_node;
62 };
63  
64 // command-line options
65 static struct {
66 int help;
67 int version;
68 char *connect_addr;
69 int max_connections;
70 int max_connecting;
71 int loglevel;
72 int loglevels[BLOG_NUM_CHANNELS];
73 } options;
74  
75 // connect address
76 static BAddr connect_addr;
77  
78 // reactor
79 static BReactor reactor;
80  
81 // connections
82 static LinkedList1 connections_list;
83 static int num_connections;
84 static int num_connecting;
85  
86 // timer for scheduling creation of more connections
87 static BTimer make_connections_timer;
88  
89 static void print_help (const char *name);
90 static void print_version (void);
91 static int parse_arguments (int argc, char *argv[]);
92 static int process_arguments (void);
93 static void signal_handler (void *unused);
94 static int connection_new (void);
95 static void connection_free (struct connection *conn);
96 static void connection_logfunc (struct connection *conn);
97 static void connection_log (struct connection *conn, int level, const char *fmt, ...);
98 static void connection_connector_handler (struct connection *conn, int is_error);
99 static void connection_connection_handler (struct connection *conn, int event);
100 static void connection_recv_handler_done (struct connection *conn, int data_len);
101 static void make_connections_timer_handler (void *unused);
102  
103 int main (int argc, char **argv)
104 {
105 if (argc <= 0) {
106 return 1;
107 }
108  
109 // open standard streams
110 open_standard_streams();
111  
112 // parse command-line arguments
113 if (!parse_arguments(argc, argv)) {
114 fprintf(stderr, "Failed to parse arguments\n");
115 print_help(argv[0]);
116 goto fail0;
117 }
118  
119 // handle --help and --version
120 if (options.help) {
121 print_version();
122 print_help(argv[0]);
123 return 0;
124 }
125 if (options.version) {
126 print_version();
127 return 0;
128 }
129  
130 // init loger
131 BLog_InitStderr();
132  
133 // configure logger channels
134 for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
135 if (options.loglevels[i] >= 0) {
136 BLog_SetChannelLoglevel(i, options.loglevels[i]);
137 }
138 else if (options.loglevel >= 0) {
139 BLog_SetChannelLoglevel(i, options.loglevel);
140 }
141 }
142  
143 BLog(BLOG_NOTICE, "initializing "GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION);
144  
145 // initialize network
146 if (!BNetwork_GlobalInit()) {
147 BLog(BLOG_ERROR, "BNetwork_GlobalInit failed");
148 goto fail1;
149 }
150  
151 // process arguments
152 if (!process_arguments()) {
153 BLog(BLOG_ERROR, "Failed to process arguments");
154 goto fail1;
155 }
156  
157 // init time
158 BTime_Init();
159  
160 // init reactor
161 if (!BReactor_Init(&reactor)) {
162 BLog(BLOG_ERROR, "BReactor_Init failed");
163 goto fail1;
164 }
165  
166 // setup signal handler
167 if (!BSignal_Init(&reactor, signal_handler, NULL)) {
168 BLog(BLOG_ERROR, "BSignal_Init failed");
169 goto fail2;
170 }
171  
172 // init connections list
173 LinkedList1_Init(&connections_list);
174 num_connections = 0;
175 num_connecting = 0;
176  
177 // init make connections timer
178 BTimer_Init(&make_connections_timer, 0, make_connections_timer_handler, NULL);
179 BReactor_SetTimer(&reactor, &make_connections_timer);
180  
181 // enter event loop
182 BLog(BLOG_NOTICE, "entering event loop");
183 BReactor_Exec(&reactor);
184  
185 // free connections
186 while (!LinkedList1_IsEmpty(&connections_list)) {
187 struct connection *conn = UPPER_OBJECT(LinkedList1_GetFirst(&connections_list), struct connection, connections_list_node);
188 connection_free(conn);
189 }
190 // free make connections timer
191 BReactor_RemoveTimer(&reactor, &make_connections_timer);
192 // free signal
193 BSignal_Finish();
194 fail2:
195 // free reactor
196 BReactor_Free(&reactor);
197 fail1:
198 // free logger
199 BLog(BLOG_NOTICE, "exiting");
200 BLog_Free();
201 fail0:
202 // finish debug objects
203 DebugObjectGlobal_Finish();
204  
205 return 1;
206 }
207  
208 void print_help (const char *name)
209 {
210 printf(
211 "Usage:\n"
212 " %s\n"
213 " [--help]\n"
214 " [--version]\n"
215 " --connect-addr <addr>\n"
216 " --max-connections <number>\n"
217 " --max-connecting <number>\n"
218 " [--loglevel <0-5/none/error/warning/notice/info/debug>]\n"
219 " [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n"
220 "Address format is a.b.c.d:port (IPv4) or [addr]:port (IPv6).\n",
221 name
222 );
223 }
224  
225 void print_version (void)
226 {
227 printf(GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION"\n"GLOBAL_COPYRIGHT_NOTICE"\n");
228 }
229  
230 int parse_arguments (int argc, char *argv[])
231 {
232 options.help = 0;
233 options.version = 0;
234 options.connect_addr = NULL;
235 options.max_connections = -1;
236 options.max_connecting = -1;
237 options.loglevel = -1;
238 for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
239 options.loglevels[i] = -1;
240 }
241  
242 int i;
243 for (i = 1; i < argc; i++) {
244 char *arg = argv[i];
245 if (!strcmp(arg, "--help")) {
246 options.help = 1;
247 }
248 else if (!strcmp(arg, "--version")) {
249 options.version = 1;
250 }
251 else if (!strcmp(arg, "--connect-addr")) {
252 if (1 >= argc - i) {
253 fprintf(stderr, "%s: requires an argument\n", arg);
254 return 0;
255 }
256 options.connect_addr = argv[i + 1];
257 i++;
258 }
259 else if (!strcmp(arg, "--max-connections")) {
260 if (1 >= argc - i) {
261 fprintf(stderr, "%s: requires an argument\n", arg);
262 return 0;
263 }
264 if ((options.max_connections = atoi(argv[i + 1])) <= 0) {
265 fprintf(stderr, "%s: wrong argument\n", arg);
266 return 0;
267 }
268 i++;
269 }
270 else if (!strcmp(arg, "--max-connecting")) {
271 if (1 >= argc - i) {
272 fprintf(stderr, "%s: requires an argument\n", arg);
273 return 0;
274 }
275 if ((options.max_connecting = atoi(argv[i + 1])) <= 0) {
276 fprintf(stderr, "%s: wrong argument\n", arg);
277 return 0;
278 }
279 i++;
280 }
281 else if (!strcmp(arg, "--loglevel")) {
282 if (1 >= argc - i) {
283 fprintf(stderr, "%s: requires an argument\n", arg);
284 return 0;
285 }
286 if ((options.loglevel = parse_loglevel(argv[i + 1])) < 0) {
287 fprintf(stderr, "%s: wrong argument\n", arg);
288 return 0;
289 }
290 i++;
291 }
292 else if (!strcmp(arg, "--channel-loglevel")) {
293 if (2 >= argc - i) {
294 fprintf(stderr, "%s: requires two arguments\n", arg);
295 return 0;
296 }
297 int channel = BLogGlobal_GetChannelByName(argv[i + 1]);
298 if (channel < 0) {
299 fprintf(stderr, "%s: wrong channel argument\n", arg);
300 return 0;
301 }
302 int loglevel = parse_loglevel(argv[i + 2]);
303 if (loglevel < 0) {
304 fprintf(stderr, "%s: wrong loglevel argument\n", arg);
305 return 0;
306 }
307 options.loglevels[channel] = loglevel;
308 i += 2;
309 }
310 else {
311 fprintf(stderr, "unknown option: %s\n", arg);
312 return 0;
313 }
314 }
315  
316 if (options.help || options.version) {
317 return 1;
318 }
319  
320 if (!options.connect_addr) {
321 fprintf(stderr, "--connect-addr missing\n");
322 return 0;
323 }
324  
325 if (options.max_connections == -1) {
326 fprintf(stderr, "--max-connections missing\n");
327 return 0;
328 }
329  
330 if (options.max_connecting == -1) {
331 fprintf(stderr, "--max-connecting missing\n");
332 return 0;
333 }
334  
335 return 1;
336 }
337  
338 int process_arguments (void)
339 {
340 // resolve listen address
341 if (!BAddr_Parse(&connect_addr, options.connect_addr, NULL, 0)) {
342 BLog(BLOG_ERROR, "connect addr: BAddr_Parse failed");
343 return 0;
344 }
345  
346 return 1;
347 }
348  
349 void signal_handler (void *unused)
350 {
351 BLog(BLOG_NOTICE, "termination requested");
352  
353 // exit event loop
354 BReactor_Quit(&reactor, 1);
355 }
356  
357 int connection_new (void)
358 {
359 // allocate structure
360 struct connection *conn = (struct connection *)malloc(sizeof(*conn));
361 if (!conn) {
362 BLog(BLOG_ERROR, "malloc failed");
363 goto fail0;
364 }
365  
366 // set not connected
367 conn->connected = 0;
368  
369 // init connector
370 if (!BConnector_Init(&conn->connector, connect_addr, &reactor, conn, (BConnector_handler)connection_connector_handler)) {
371 BLog(BLOG_ERROR, "BConnector_Init failed");
372 goto fail1;
373 }
374  
375 // add to connections list
376 LinkedList1_Append(&connections_list, &conn->connections_list_node);
377 num_connections++;
378 num_connecting++;
379  
380 return 1;
381  
382 fail1:
383 free(conn);
384 fail0:
385 return 0;
386 }
387  
388 void connection_free (struct connection *conn)
389 {
390 // remove from connections list
391 LinkedList1_Remove(&connections_list, &conn->connections_list_node);
392 num_connections--;
393 if (!conn->connected) {
394 num_connecting--;
395 }
396  
397 if (conn->connected) {
398 // free receive interface
399 BConnection_RecvAsync_Free(&conn->con);
400  
401 // free connection
402 BConnection_Free(&conn->con);
403 }
404  
405 // free connector
406 BConnector_Free(&conn->connector);
407  
408 // free structure
409 free(conn);
410 }
411  
412 void connection_logfunc (struct connection *conn)
413 {
414 BLog_Append("%d connection (%p): ", num_connecting, (void *)conn);
415 }
416  
417 void connection_log (struct connection *conn, int level, const char *fmt, ...)
418 {
419 va_list vl;
420 va_start(vl, fmt);
421 BLog_LogViaFuncVarArg((BLog_logfunc)connection_logfunc, conn, BLOG_CURRENT_CHANNEL, level, fmt, vl);
422 va_end(vl);
423 }
424  
425 void connection_connector_handler (struct connection *conn, int is_error)
426 {
427 ASSERT(!conn->connected)
428  
429 // check for connection error
430 if (is_error) {
431 connection_log(conn, BLOG_INFO, "failed to connect");
432 goto fail0;
433 }
434  
435 // init connection from connector
436 if (!BConnection_Init(&conn->con, BConnection_source_connector(&conn->connector), &reactor, conn, (BConnection_handler)connection_connection_handler)) {
437 connection_log(conn, BLOG_INFO, "BConnection_Init failed");
438 goto fail0;
439 }
440  
441 // init receive interface
442 BConnection_RecvAsync_Init(&conn->con);
443 conn->recv_if = BConnection_RecvAsync_GetIf(&conn->con);
444 StreamRecvInterface_Receiver_Init(conn->recv_if, (StreamRecvInterface_handler_done)connection_recv_handler_done, conn);
445  
446 // start receiving
447 StreamRecvInterface_Receiver_Recv(conn->recv_if, conn->buf, sizeof(conn->buf));
448  
449 // no longer connecting
450 conn->connected = 1;
451 num_connecting--;
452  
453 connection_log(conn, BLOG_INFO, "connected");
454  
455 // schedule making connections (because of connecting limit)
456 BReactor_SetTimer(&reactor, &make_connections_timer);
457 return;
458  
459 fail0:
460 // free connection
461 connection_free(conn);
462  
463 // schedule making connections
464 BReactor_SetTimer(&reactor, &make_connections_timer);
465 }
466  
467 void connection_connection_handler (struct connection *conn, int event)
468 {
469 ASSERT(conn->connected)
470  
471 if (event == BCONNECTION_EVENT_RECVCLOSED) {
472 connection_log(conn, BLOG_INFO, "connection closed");
473 } else {
474 connection_log(conn, BLOG_INFO, "connection error");
475 }
476  
477 // free connection
478 connection_free(conn);
479  
480 // schedule making connections
481 BReactor_SetTimer(&reactor, &make_connections_timer);
482 }
483  
484 void connection_recv_handler_done (struct connection *conn, int data_len)
485 {
486 ASSERT(conn->connected)
487  
488 // receive more
489 StreamRecvInterface_Receiver_Recv(conn->recv_if, conn->buf, sizeof(conn->buf));
490  
491 connection_log(conn, BLOG_INFO, "received %d bytes", data_len);
492 }
493  
494 void make_connections_timer_handler (void *unused)
495 {
496 int make_num = bmin_int(options.max_connections - num_connections, options.max_connecting - num_connecting);
497  
498 if (make_num <= 0) {
499 return;
500 }
501  
502 BLog(BLOG_INFO, "making %d connections", make_num);
503  
504 for (int i = 0; i < make_num; i++) {
505 if (!connection_new()) {
506 // can happen if fd limit is reached
507 BLog(BLOG_ERROR, "failed to make connection, waiting");
508 BReactor_SetTimerAfter(&reactor, &make_connections_timer, 10);
509 return;
510 }
511 }
512 }