BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (C) Ambroz Bizjak <ambrop7@gmail.com> |
||
3 | * Contributions: |
||
4 | * Transparent DNS: Copyright (C) Kerem Hadimli <kerem.hadimli@gmail.com> |
||
5 | * |
||
6 | * Redistribution and use in source and binary forms, with or without |
||
7 | * modification, are permitted provided that the following conditions are met: |
||
8 | * 1. Redistributions of source code must retain the above copyright |
||
9 | * notice, this list of conditions and the following disclaimer. |
||
10 | * 2. Redistributions in binary form must reproduce the above copyright |
||
11 | * notice, this list of conditions and the following disclaimer in the |
||
12 | * documentation and/or other materials provided with the distribution. |
||
13 | * 3. Neither the name of the author nor the |
||
14 | * names of its contributors may be used to endorse or promote products |
||
15 | * derived from this software without specific prior written permission. |
||
16 | * |
||
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||
20 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
27 | */ |
||
28 | |||
29 | #include <stdio.h> |
||
30 | #include <string.h> |
||
31 | #include <stdarg.h> |
||
32 | #include <stdlib.h> |
||
33 | #include <limits.h> |
||
34 | |||
35 | #include <protocol/udpgw_proto.h> |
||
36 | #include <misc/debug.h> |
||
37 | #include <misc/version.h> |
||
38 | #include <misc/loggers_string.h> |
||
39 | #include <misc/loglevel.h> |
||
40 | #include <misc/offset.h> |
||
41 | #include <misc/byteorder.h> |
||
42 | #include <misc/bsize.h> |
||
43 | #include <misc/open_standard_streams.h> |
||
44 | #include <misc/balloc.h> |
||
45 | #include <misc/compare.h> |
||
46 | #include <misc/print_macros.h> |
||
47 | #include <structure/LinkedList1.h> |
||
48 | #include <structure/BAVL.h> |
||
49 | #include <base/BLog.h> |
||
50 | #include <system/BReactor.h> |
||
51 | #include <system/BNetwork.h> |
||
52 | #include <system/BConnection.h> |
||
53 | #include <system/BDatagram.h> |
||
54 | #include <system/BSignal.h> |
||
55 | #include <flow/PacketProtoDecoder.h> |
||
56 | #include <flow/PacketPassFairQueue.h> |
||
57 | #include <flow/PacketStreamSender.h> |
||
58 | #include <flow/PacketProtoFlow.h> |
||
59 | #include <flow/SinglePacketBuffer.h> |
||
60 | |||
61 | #ifndef BADVPN_USE_WINAPI |
||
62 | #include <base/BLog_syslog.h> |
||
63 | #include <arpa/nameser.h> |
||
64 | #include <resolv.h> |
||
65 | #endif |
||
66 | |||
67 | #include <udpgw/udpgw.h> |
||
68 | |||
69 | #include <generated/blog_channel_udpgw.h> |
||
70 | |||
71 | #define LOGGER_STDOUT 1 |
||
72 | #define LOGGER_SYSLOG 2 |
||
73 | |||
74 | #define DNS_UPDATE_TIME 2000 |
||
75 | |||
76 | struct client { |
||
77 | BConnection con; |
||
78 | BAddr addr; |
||
79 | BTimer disconnect_timer; |
||
80 | PacketProtoDecoder recv_decoder; |
||
81 | PacketPassInterface recv_if; |
||
82 | PacketPassFairQueue send_queue; |
||
83 | PacketStreamSender send_sender; |
||
84 | BAVL connections_tree; |
||
85 | LinkedList1 connections_list; |
||
86 | int num_connections; |
||
87 | LinkedList1 closing_connections_list; |
||
88 | LinkedList1Node clients_list_node; |
||
89 | }; |
||
90 | |||
91 | struct connection { |
||
92 | struct client *client; |
||
93 | uint16_t conid; |
||
94 | BAddr addr; |
||
95 | BAddr orig_addr; |
||
96 | const uint8_t *first_data; |
||
97 | int first_data_len; |
||
98 | btime_t last_use_time; |
||
99 | int closing; |
||
100 | BPending first_job; |
||
101 | BufferWriter *send_if; |
||
102 | PacketProtoFlow send_ppflow; |
||
103 | PacketPassFairQueueFlow send_qflow; |
||
104 | union { |
||
105 | struct { |
||
106 | BDatagram udp_dgram; |
||
107 | int local_port_index; |
||
108 | BufferWriter udp_send_writer; |
||
109 | PacketBuffer udp_send_buffer; |
||
110 | SinglePacketBuffer udp_recv_buffer; |
||
111 | PacketPassInterface udp_recv_if; |
||
112 | BAVLNode connections_tree_node; |
||
113 | LinkedList1Node connections_list_node; |
||
114 | }; |
||
115 | struct { |
||
116 | LinkedList1Node closing_connections_list_node; |
||
117 | }; |
||
118 | }; |
||
119 | }; |
||
120 | |||
121 | // command-line options |
||
122 | struct { |
||
123 | int help; |
||
124 | int version; |
||
125 | int logger; |
||
126 | #ifndef BADVPN_USE_WINAPI |
||
127 | char *logger_syslog_facility; |
||
128 | char *logger_syslog_ident; |
||
129 | #endif |
||
130 | int loglevel; |
||
131 | int loglevels[BLOG_NUM_CHANNELS]; |
||
132 | char *listen_addrs[MAX_LISTEN_ADDRS]; |
||
133 | int num_listen_addrs; |
||
134 | int udp_mtu; |
||
135 | int max_clients; |
||
136 | int max_connections_for_client; |
||
137 | int client_socket_sndbuf; |
||
138 | int local_udp_num_ports; |
||
139 | char *local_udp_addr; |
||
140 | int local_udp_ip6_num_ports; |
||
141 | char *local_udp_ip6_addr; |
||
142 | int unique_local_ports; |
||
143 | } options; |
||
144 | |||
145 | // MTUs |
||
146 | int udpgw_mtu; |
||
147 | int pp_mtu; |
||
148 | |||
149 | // listen addresses |
||
150 | BAddr listen_addrs[MAX_LISTEN_ADDRS]; |
||
151 | int num_listen_addrs; |
||
152 | |||
153 | // local UDP port range, if options.local_udp_num_ports>=0 |
||
154 | BAddr local_udp_addr; |
||
155 | |||
156 | // local UDP/IPv6 port range, if options.local_udp_ip6_num_ports>=0 |
||
157 | BAddr local_udp_ip6_addr; |
||
158 | |||
159 | // DNS forwarding |
||
160 | BAddr dns_addr; |
||
161 | btime_t last_dns_update_time; |
||
162 | |||
163 | // reactor |
||
164 | BReactor ss; |
||
165 | |||
166 | // listeners |
||
167 | BListener listeners[MAX_LISTEN_ADDRS]; |
||
168 | int num_listeners; |
||
169 | |||
170 | // clients |
||
171 | LinkedList1 clients_list; |
||
172 | int num_clients; |
||
173 | |||
174 | static void print_help (const char *name); |
||
175 | static void print_version (void); |
||
176 | static int parse_arguments (int argc, char *argv[]); |
||
177 | static int process_arguments (void); |
||
178 | static void signal_handler (void *unused); |
||
179 | static void listener_handler (BListener *listener); |
||
180 | static void client_free (struct client *client); |
||
181 | static void client_logfunc (struct client *client); |
||
182 | static void client_log (struct client *client, int level, const char *fmt, ...); |
||
183 | static void client_disconnect_timer_handler (struct client *client); |
||
184 | static void client_connection_handler (struct client *client, int event); |
||
185 | static void client_decoder_handler_error (struct client *client); |
||
186 | static void client_recv_if_handler_send (struct client *client, uint8_t *data, int data_len); |
||
187 | static int get_local_num_ports (int addr_type); |
||
188 | static BAddr get_local_addr (int addr_type); |
||
189 | static uint8_t * build_port_usage_array_and_find_least_used_connection (BAddr remote_addr, struct connection **out_con); |
||
190 | static void connection_init (struct client *client, uint16_t conid, BAddr addr, BAddr orig_addr, const uint8_t *data, int data_len); |
||
191 | static void connection_free (struct connection *con); |
||
192 | static void connection_logfunc (struct connection *con); |
||
193 | static void connection_log (struct connection *con, int level, const char *fmt, ...); |
||
194 | static void connection_free_udp (struct connection *con); |
||
195 | static void connection_first_job_handler (struct connection *con); |
||
196 | static void connection_send_to_client (struct connection *con, uint8_t flags, const uint8_t *data, int data_len); |
||
197 | static int connection_send_to_udp (struct connection *con, const uint8_t *data, int data_len); |
||
198 | static void connection_close (struct connection *con); |
||
199 | static void connection_send_qflow_busy_handler (struct connection *con); |
||
200 | static void connection_dgram_handler_event (struct connection *con, int event); |
||
201 | static void connection_udp_recv_if_handler_send (struct connection *con, uint8_t *data, int data_len); |
||
202 | static struct connection * find_connection (struct client *client, uint16_t conid); |
||
203 | static int uint16_comparator (void *unused, uint16_t *v1, uint16_t *v2); |
||
204 | static void maybe_update_dns (void); |
||
205 | |||
206 | int main (int argc, char **argv) |
||
207 | { |
||
208 | if (argc <= 0) { |
||
209 | return 1; |
||
210 | } |
||
211 | |||
212 | // open standard streams |
||
213 | open_standard_streams(); |
||
214 | |||
215 | // parse command-line arguments |
||
216 | if (!parse_arguments(argc, argv)) { |
||
217 | fprintf(stderr, "Failed to parse arguments\n"); |
||
218 | print_help(argv[0]); |
||
219 | goto fail0; |
||
220 | } |
||
221 | |||
222 | // handle --help and --version |
||
223 | if (options.help) { |
||
224 | print_version(); |
||
225 | print_help(argv[0]); |
||
226 | return 0; |
||
227 | } |
||
228 | if (options.version) { |
||
229 | print_version(); |
||
230 | return 0; |
||
231 | } |
||
232 | |||
233 | // initialize logger |
||
234 | switch (options.logger) { |
||
235 | case LOGGER_STDOUT: |
||
236 | BLog_InitStdout(); |
||
237 | break; |
||
238 | #ifndef BADVPN_USE_WINAPI |
||
239 | case LOGGER_SYSLOG: |
||
240 | if (!BLog_InitSyslog(options.logger_syslog_ident, options.logger_syslog_facility)) { |
||
241 | fprintf(stderr, "Failed to initialize syslog logger\n"); |
||
242 | goto fail0; |
||
243 | } |
||
244 | break; |
||
245 | #endif |
||
246 | default: |
||
247 | ASSERT(0); |
||
248 | } |
||
249 | |||
250 | // configure logger channels |
||
251 | for (int i = 0; i < BLOG_NUM_CHANNELS; i++) { |
||
252 | if (options.loglevels[i] >= 0) { |
||
253 | BLog_SetChannelLoglevel(i, options.loglevels[i]); |
||
254 | } |
||
255 | else if (options.loglevel >= 0) { |
||
256 | BLog_SetChannelLoglevel(i, options.loglevel); |
||
257 | } |
||
258 | } |
||
259 | |||
260 | BLog(BLOG_NOTICE, "initializing "GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION); |
||
261 | |||
262 | // initialize network |
||
263 | if (!BNetwork_GlobalInit()) { |
||
264 | BLog(BLOG_ERROR, "BNetwork_GlobalInit failed"); |
||
265 | goto fail1; |
||
266 | } |
||
267 | |||
268 | // process arguments |
||
269 | if (!process_arguments()) { |
||
270 | BLog(BLOG_ERROR, "Failed to process arguments"); |
||
271 | goto fail1; |
||
272 | } |
||
273 | |||
274 | // compute MTUs |
||
275 | udpgw_mtu = udpgw_compute_mtu(options.udp_mtu); |
||
276 | if (udpgw_mtu < 0 || udpgw_mtu > PACKETPROTO_MAXPAYLOAD) { |
||
277 | udpgw_mtu = PACKETPROTO_MAXPAYLOAD; |
||
278 | } |
||
279 | pp_mtu = udpgw_mtu + sizeof(struct packetproto_header); |
||
280 | |||
281 | // init time |
||
282 | BTime_Init(); |
||
283 | |||
284 | // init DNS forwarding |
||
285 | BAddr_InitNone(&dns_addr); |
||
286 | last_dns_update_time = INT64_MIN; |
||
287 | maybe_update_dns(); |
||
288 | |||
289 | // init reactor |
||
290 | if (!BReactor_Init(&ss)) { |
||
291 | BLog(BLOG_ERROR, "BReactor_Init failed"); |
||
292 | goto fail1; |
||
293 | } |
||
294 | |||
295 | // setup signal handler |
||
296 | if (!BSignal_Init(&ss, signal_handler, NULL)) { |
||
297 | BLog(BLOG_ERROR, "BSignal_Init failed"); |
||
298 | goto fail2; |
||
299 | } |
||
300 | |||
301 | // initialize listeners |
||
302 | num_listeners = 0; |
||
303 | while (num_listeners < num_listen_addrs) { |
||
304 | if (!BListener_Init(&listeners[num_listeners], listen_addrs[num_listeners], &ss, &listeners[num_listeners], (BListener_handler)listener_handler)) { |
||
305 | BLog(BLOG_ERROR, "Listener_Init failed"); |
||
306 | goto fail3; |
||
307 | } |
||
308 | num_listeners++; |
||
309 | } |
||
310 | |||
311 | // init clients list |
||
312 | LinkedList1_Init(&clients_list); |
||
313 | num_clients = 0; |
||
314 | |||
315 | // enter event loop |
||
316 | BLog(BLOG_NOTICE, "entering event loop"); |
||
317 | BReactor_Exec(&ss); |
||
318 | |||
319 | // free clients |
||
320 | while (!LinkedList1_IsEmpty(&clients_list)) { |
||
321 | struct client *client = UPPER_OBJECT(LinkedList1_GetFirst(&clients_list), struct client, clients_list_node); |
||
322 | client_free(client); |
||
323 | } |
||
324 | fail3: |
||
325 | // free listeners |
||
326 | while (num_listeners > 0) { |
||
327 | num_listeners--; |
||
328 | BListener_Free(&listeners[num_listeners]); |
||
329 | } |
||
330 | // finish signal handling |
||
331 | BSignal_Finish(); |
||
332 | fail2: |
||
333 | // free reactor |
||
334 | BReactor_Free(&ss); |
||
335 | fail1: |
||
336 | // free logger |
||
337 | BLog(BLOG_NOTICE, "exiting"); |
||
338 | BLog_Free(); |
||
339 | fail0: |
||
340 | // finish debug objects |
||
341 | DebugObjectGlobal_Finish(); |
||
342 | |||
343 | return 1; |
||
344 | } |
||
345 | |||
346 | void print_help (const char *name) |
||
347 | { |
||
348 | printf( |
||
349 | "Usage:\n" |
||
350 | " %s\n" |
||
351 | " [--help]\n" |
||
352 | " [--version]\n" |
||
353 | " [--logger <"LOGGERS_STRING">]\n" |
||
354 | #ifndef BADVPN_USE_WINAPI |
||
355 | " (logger=syslog?\n" |
||
356 | " [--syslog-facility <string>]\n" |
||
357 | " [--syslog-ident <string>]\n" |
||
358 | " )\n" |
||
359 | #endif |
||
360 | " [--loglevel <0-5/none/error/warning/notice/info/debug>]\n" |
||
361 | " [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n" |
||
362 | " [--listen-addr <addr>] ...\n" |
||
363 | " [--udp-mtu <bytes>]\n" |
||
364 | " [--max-clients <number>]\n" |
||
365 | " [--max-connections-for-client <number>]\n" |
||
366 | " [--client-socket-sndbuf <bytes / 0>]\n" |
||
367 | " [--local-udp-addrs <addr> <num_ports>]\n" |
||
368 | " [--local-udp-ip6-addrs <addr> <num_ports>]\n" |
||
369 | " [--unique-local-ports]\n" |
||
370 | "Address format is a.b.c.d:port (IPv4) or [addr]:port (IPv6).\n", |
||
371 | name |
||
372 | ); |
||
373 | } |
||
374 | |||
375 | void print_version (void) |
||
376 | { |
||
377 | printf(GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION"\n"GLOBAL_COPYRIGHT_NOTICE"\n"); |
||
378 | } |
||
379 | |||
380 | int parse_arguments (int argc, char *argv[]) |
||
381 | { |
||
382 | if (argc <= 0) { |
||
383 | return 0; |
||
384 | } |
||
385 | |||
386 | options.help = 0; |
||
387 | options.version = 0; |
||
388 | options.logger = LOGGER_STDOUT; |
||
389 | #ifndef BADVPN_USE_WINAPI |
||
390 | options.logger_syslog_facility = "daemon"; |
||
391 | options.logger_syslog_ident = argv[0]; |
||
392 | #endif |
||
393 | options.loglevel = -1; |
||
394 | for (int i = 0; i < BLOG_NUM_CHANNELS; i++) { |
||
395 | options.loglevels[i] = -1; |
||
396 | } |
||
397 | options.num_listen_addrs = 0; |
||
398 | options.udp_mtu = DEFAULT_UDP_MTU; |
||
399 | options.max_clients = DEFAULT_MAX_CLIENTS; |
||
400 | options.max_connections_for_client = DEFAULT_MAX_CONNECTIONS_FOR_CLIENT; |
||
401 | options.client_socket_sndbuf = CLIENT_DEFAULT_SOCKET_SEND_BUFFER; |
||
402 | options.local_udp_num_ports = -1; |
||
403 | options.local_udp_ip6_num_ports = -1; |
||
404 | options.unique_local_ports = 0; |
||
405 | |||
406 | int i; |
||
407 | for (i = 1; i < argc; i++) { |
||
408 | char *arg = argv[i]; |
||
409 | if (!strcmp(arg, "--help")) { |
||
410 | options.help = 1; |
||
411 | } |
||
412 | else if (!strcmp(arg, "--version")) { |
||
413 | options.version = 1; |
||
414 | } |
||
415 | else if (!strcmp(arg, "--logger")) { |
||
416 | if (1 >= argc - i) { |
||
417 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
418 | return 0; |
||
419 | } |
||
420 | char *arg2 = argv[i + 1]; |
||
421 | if (!strcmp(arg2, "stdout")) { |
||
422 | options.logger = LOGGER_STDOUT; |
||
423 | } |
||
424 | #ifndef BADVPN_USE_WINAPI |
||
425 | else if (!strcmp(arg2, "syslog")) { |
||
426 | options.logger = LOGGER_SYSLOG; |
||
427 | } |
||
428 | #endif |
||
429 | else { |
||
430 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
431 | return 0; |
||
432 | } |
||
433 | i++; |
||
434 | } |
||
435 | #ifndef BADVPN_USE_WINAPI |
||
436 | else if (!strcmp(arg, "--syslog-facility")) { |
||
437 | if (1 >= argc - i) { |
||
438 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
439 | return 0; |
||
440 | } |
||
441 | options.logger_syslog_facility = argv[i + 1]; |
||
442 | i++; |
||
443 | } |
||
444 | else if (!strcmp(arg, "--syslog-ident")) { |
||
445 | if (1 >= argc - i) { |
||
446 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
447 | return 0; |
||
448 | } |
||
449 | options.logger_syslog_ident = argv[i + 1]; |
||
450 | i++; |
||
451 | } |
||
452 | #endif |
||
453 | else if (!strcmp(arg, "--loglevel")) { |
||
454 | if (1 >= argc - i) { |
||
455 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
456 | return 0; |
||
457 | } |
||
458 | if ((options.loglevel = parse_loglevel(argv[i + 1])) < 0) { |
||
459 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
460 | return 0; |
||
461 | } |
||
462 | i++; |
||
463 | } |
||
464 | else if (!strcmp(arg, "--channel-loglevel")) { |
||
465 | if (2 >= argc - i) { |
||
466 | fprintf(stderr, "%s: requires two arguments\n", arg); |
||
467 | return 0; |
||
468 | } |
||
469 | int channel = BLogGlobal_GetChannelByName(argv[i + 1]); |
||
470 | if (channel < 0) { |
||
471 | fprintf(stderr, "%s: wrong channel argument\n", arg); |
||
472 | return 0; |
||
473 | } |
||
474 | int loglevel = parse_loglevel(argv[i + 2]); |
||
475 | if (loglevel < 0) { |
||
476 | fprintf(stderr, "%s: wrong loglevel argument\n", arg); |
||
477 | return 0; |
||
478 | } |
||
479 | options.loglevels[channel] = loglevel; |
||
480 | i += 2; |
||
481 | } |
||
482 | else if (!strcmp(arg, "--listen-addr")) { |
||
483 | if (1 >= argc - i) { |
||
484 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
485 | return 0; |
||
486 | } |
||
487 | if (options.num_listen_addrs == MAX_LISTEN_ADDRS) { |
||
488 | fprintf(stderr, "%s: too many\n", arg); |
||
489 | return 0; |
||
490 | } |
||
491 | options.listen_addrs[options.num_listen_addrs] = argv[i + 1]; |
||
492 | options.num_listen_addrs++; |
||
493 | i++; |
||
494 | } |
||
495 | else if (!strcmp(arg, "--udp-mtu")) { |
||
496 | if (1 >= argc - i) { |
||
497 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
498 | return 0; |
||
499 | } |
||
500 | if ((options.udp_mtu = atoi(argv[i + 1])) < 0) { |
||
501 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
502 | return 0; |
||
503 | } |
||
504 | i++; |
||
505 | } |
||
506 | else if (!strcmp(arg, "--max-clients")) { |
||
507 | if (1 >= argc - i) { |
||
508 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
509 | return 0; |
||
510 | } |
||
511 | if ((options.max_clients = atoi(argv[i + 1])) <= 0) { |
||
512 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
513 | return 0; |
||
514 | } |
||
515 | i++; |
||
516 | } |
||
517 | else if (!strcmp(arg, "--max-connections-for-client")) { |
||
518 | if (1 >= argc - i) { |
||
519 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
520 | return 0; |
||
521 | } |
||
522 | if ((options.max_connections_for_client = atoi(argv[i + 1])) <= 0) { |
||
523 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
524 | return 0; |
||
525 | } |
||
526 | i++; |
||
527 | } |
||
528 | else if (!strcmp(arg, "--client-socket-sndbuf")) { |
||
529 | if (1 >= argc - i) { |
||
530 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
531 | return 0; |
||
532 | } |
||
533 | if ((options.client_socket_sndbuf = atoi(argv[i + 1])) < 0) { |
||
534 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
535 | return 0; |
||
536 | } |
||
537 | i++; |
||
538 | } |
||
539 | else if (!strcmp(arg, "--local-udp-addrs")) { |
||
540 | if (2 >= argc - i) { |
||
541 | fprintf(stderr, "%s: requires two arguments\n", arg); |
||
542 | return 0; |
||
543 | } |
||
544 | options.local_udp_addr = argv[i + 1]; |
||
545 | if ((options.local_udp_num_ports = atoi(argv[i + 2])) < 0) { |
||
546 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
547 | return 0; |
||
548 | } |
||
549 | i += 2; |
||
550 | } |
||
551 | else if (!strcmp(arg, "--local-udp-ip6-addrs")) { |
||
552 | if (2 >= argc - i) { |
||
553 | fprintf(stderr, "%s: requires two arguments\n", arg); |
||
554 | return 0; |
||
555 | } |
||
556 | options.local_udp_ip6_addr = argv[i + 1]; |
||
557 | if ((options.local_udp_ip6_num_ports = atoi(argv[i + 2])) < 0) { |
||
558 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
559 | return 0; |
||
560 | } |
||
561 | i += 2; |
||
562 | } |
||
563 | else if (!strcmp(arg, "--unique-local-ports")) { |
||
564 | options.unique_local_ports = 1; |
||
565 | } |
||
566 | else { |
||
567 | fprintf(stderr, "unknown option: %s\n", arg); |
||
568 | return 0; |
||
569 | } |
||
570 | } |
||
571 | |||
572 | if (options.help || options.version) { |
||
573 | return 1; |
||
574 | } |
||
575 | |||
576 | return 1; |
||
577 | } |
||
578 | |||
579 | int process_arguments (void) |
||
580 | { |
||
581 | // resolve listen addresses |
||
582 | num_listen_addrs = 0; |
||
583 | while (num_listen_addrs < options.num_listen_addrs) { |
||
584 | if (!BAddr_Parse(&listen_addrs[num_listen_addrs], options.listen_addrs[num_listen_addrs], NULL, 0)) { |
||
585 | BLog(BLOG_ERROR, "listen addr: BAddr_Parse failed"); |
||
586 | return 0; |
||
587 | } |
||
588 | num_listen_addrs++; |
||
589 | } |
||
590 | |||
591 | // resolve local UDP address |
||
592 | if (options.local_udp_num_ports >= 0) { |
||
593 | if (!BAddr_Parse(&local_udp_addr, options.local_udp_addr, NULL, 0)) { |
||
594 | BLog(BLOG_ERROR, "local udp addr: BAddr_Parse failed"); |
||
595 | return 0; |
||
596 | } |
||
597 | if (local_udp_addr.type != BADDR_TYPE_IPV4) { |
||
598 | BLog(BLOG_ERROR, "local udp addr: must be an IPv4 address"); |
||
599 | return 0; |
||
600 | } |
||
601 | } |
||
602 | |||
603 | // resolve local UDP/IPv6 address |
||
604 | if (options.local_udp_ip6_num_ports >= 0) { |
||
605 | if (!BAddr_Parse(&local_udp_ip6_addr, options.local_udp_ip6_addr, NULL, 0)) { |
||
606 | BLog(BLOG_ERROR, "local udp ip6 addr: BAddr_Parse failed"); |
||
607 | return 0; |
||
608 | } |
||
609 | if (local_udp_ip6_addr.type != BADDR_TYPE_IPV6) { |
||
610 | BLog(BLOG_ERROR, "local udp ip6 addr: must be an IPv6 address"); |
||
611 | return 0; |
||
612 | } |
||
613 | } |
||
614 | |||
615 | return 1; |
||
616 | } |
||
617 | |||
618 | void signal_handler (void *unused) |
||
619 | { |
||
620 | BLog(BLOG_NOTICE, "termination requested"); |
||
621 | |||
622 | // exit event loop |
||
623 | BReactor_Quit(&ss, 1); |
||
624 | } |
||
625 | |||
626 | void listener_handler (BListener *listener) |
||
627 | { |
||
628 | if (num_clients == options.max_clients) { |
||
629 | BLog(BLOG_ERROR, "maximum number of clients reached"); |
||
630 | goto fail0; |
||
631 | } |
||
632 | |||
633 | // allocate structure |
||
634 | struct client *client = (struct client *)malloc(sizeof(*client)); |
||
635 | if (!client) { |
||
636 | BLog(BLOG_ERROR, "malloc failed"); |
||
637 | goto fail0; |
||
638 | } |
||
639 | |||
640 | // accept client |
||
641 | if (!BConnection_Init(&client->con, BConnection_source_listener(listener, &client->addr), &ss, client, (BConnection_handler)client_connection_handler)) { |
||
642 | BLog(BLOG_ERROR, "BConnection_Init failed"); |
||
643 | goto fail1; |
||
644 | } |
||
645 | |||
646 | // limit socket send buffer, else our scheduling is pointless |
||
647 | if (options.client_socket_sndbuf > 0) { |
||
648 | if (!BConnection_SetSendBuffer(&client->con, options.client_socket_sndbuf)) { |
||
649 | BLog(BLOG_WARNING, "BConnection_SetSendBuffer failed"); |
||
650 | } |
||
651 | } |
||
652 | |||
653 | // init connection interfaces |
||
654 | BConnection_SendAsync_Init(&client->con); |
||
655 | BConnection_RecvAsync_Init(&client->con); |
||
656 | |||
657 | // init disconnect timer |
||
658 | BTimer_Init(&client->disconnect_timer, CLIENT_DISCONNECT_TIMEOUT, (BTimer_handler)client_disconnect_timer_handler, client); |
||
659 | BReactor_SetTimer(&ss, &client->disconnect_timer); |
||
660 | |||
661 | // init recv interface |
||
662 | PacketPassInterface_Init(&client->recv_if, udpgw_mtu, (PacketPassInterface_handler_send)client_recv_if_handler_send, client, BReactor_PendingGroup(&ss)); |
||
663 | |||
664 | // init recv decoder |
||
665 | if (!PacketProtoDecoder_Init(&client->recv_decoder, BConnection_RecvAsync_GetIf(&client->con), &client->recv_if, BReactor_PendingGroup(&ss), client, |
||
666 | (PacketProtoDecoder_handler_error)client_decoder_handler_error |
||
667 | )) { |
||
668 | BLog(BLOG_ERROR, "PacketProtoDecoder_Init failed"); |
||
669 | goto fail2; |
||
670 | } |
||
671 | |||
672 | // init send sender |
||
673 | PacketStreamSender_Init(&client->send_sender, BConnection_SendAsync_GetIf(&client->con), pp_mtu, BReactor_PendingGroup(&ss)); |
||
674 | |||
675 | // init send queue |
||
676 | if (!PacketPassFairQueue_Init(&client->send_queue, PacketStreamSender_GetInput(&client->send_sender), BReactor_PendingGroup(&ss), 0, 1)) { |
||
677 | BLog(BLOG_ERROR, "PacketPassFairQueue_Init failed"); |
||
678 | goto fail3; |
||
679 | } |
||
680 | |||
681 | // init connections tree |
||
682 | BAVL_Init(&client->connections_tree, OFFSET_DIFF(struct connection, conid, connections_tree_node), (BAVL_comparator)uint16_comparator, NULL); |
||
683 | |||
684 | // init connections list |
||
685 | LinkedList1_Init(&client->connections_list); |
||
686 | |||
687 | // set zero connections |
||
688 | client->num_connections = 0; |
||
689 | |||
690 | // init closing connections list |
||
691 | LinkedList1_Init(&client->closing_connections_list); |
||
692 | |||
693 | // insert to clients list |
||
694 | LinkedList1_Append(&clients_list, &client->clients_list_node); |
||
695 | num_clients++; |
||
696 | |||
697 | client_log(client, BLOG_INFO, "connected"); |
||
698 | |||
699 | return; |
||
700 | |||
701 | fail3: |
||
702 | PacketStreamSender_Free(&client->send_sender); |
||
703 | PacketProtoDecoder_Free(&client->recv_decoder); |
||
704 | fail2: |
||
705 | PacketPassInterface_Free(&client->recv_if); |
||
706 | BReactor_RemoveTimer(&ss, &client->disconnect_timer); |
||
707 | BConnection_RecvAsync_Free(&client->con); |
||
708 | BConnection_SendAsync_Free(&client->con); |
||
709 | BConnection_Free(&client->con); |
||
710 | fail1: |
||
711 | free(client); |
||
712 | fail0: |
||
713 | return; |
||
714 | } |
||
715 | |||
716 | void client_free (struct client *client) |
||
717 | { |
||
718 | // allow freeing send queue flows |
||
719 | PacketPassFairQueue_PrepareFree(&client->send_queue); |
||
720 | |||
721 | // free connections |
||
722 | while (!LinkedList1_IsEmpty(&client->connections_list)) { |
||
723 | struct connection *con = UPPER_OBJECT(LinkedList1_GetFirst(&client->connections_list), struct connection, connections_list_node); |
||
724 | connection_free(con); |
||
725 | } |
||
726 | |||
727 | // free closing connections |
||
728 | while (!LinkedList1_IsEmpty(&client->closing_connections_list)) { |
||
729 | struct connection *con = UPPER_OBJECT(LinkedList1_GetFirst(&client->closing_connections_list), struct connection, closing_connections_list_node); |
||
730 | connection_free(con); |
||
731 | } |
||
732 | |||
733 | // remove from clients list |
||
734 | LinkedList1_Remove(&clients_list, &client->clients_list_node); |
||
735 | num_clients--; |
||
736 | |||
737 | // free send queue |
||
738 | PacketPassFairQueue_Free(&client->send_queue); |
||
739 | |||
740 | // free send sender |
||
741 | PacketStreamSender_Free(&client->send_sender); |
||
742 | |||
743 | // free recv decoder |
||
744 | PacketProtoDecoder_Free(&client->recv_decoder); |
||
745 | |||
746 | // free recv interface |
||
747 | PacketPassInterface_Free(&client->recv_if); |
||
748 | |||
749 | // free disconnect timer |
||
750 | BReactor_RemoveTimer(&ss, &client->disconnect_timer); |
||
751 | |||
752 | // free connection interfaces |
||
753 | BConnection_RecvAsync_Free(&client->con); |
||
754 | BConnection_SendAsync_Free(&client->con); |
||
755 | |||
756 | // free connection |
||
757 | BConnection_Free(&client->con); |
||
758 | |||
759 | // free structure |
||
760 | free(client); |
||
761 | } |
||
762 | |||
763 | void client_logfunc (struct client *client) |
||
764 | { |
||
765 | char addr[BADDR_MAX_PRINT_LEN]; |
||
766 | BAddr_Print(&client->addr, addr); |
||
767 | |||
768 | BLog_Append("client (%s): ", addr); |
||
769 | } |
||
770 | |||
771 | void client_log (struct client *client, int level, const char *fmt, ...) |
||
772 | { |
||
773 | va_list vl; |
||
774 | va_start(vl, fmt); |
||
775 | BLog_LogViaFuncVarArg((BLog_logfunc)client_logfunc, client, BLOG_CURRENT_CHANNEL, level, fmt, vl); |
||
776 | va_end(vl); |
||
777 | } |
||
778 | |||
779 | void client_disconnect_timer_handler (struct client *client) |
||
780 | { |
||
781 | client_log(client, BLOG_INFO, "timed out, disconnecting"); |
||
782 | |||
783 | // free client |
||
784 | client_free(client); |
||
785 | } |
||
786 | |||
787 | void client_connection_handler (struct client *client, int event) |
||
788 | { |
||
789 | if (event == BCONNECTION_EVENT_RECVCLOSED) { |
||
790 | client_log(client, BLOG_INFO, "client closed"); |
||
791 | } else { |
||
792 | client_log(client, BLOG_INFO, "client error"); |
||
793 | } |
||
794 | |||
795 | // free client |
||
796 | client_free(client); |
||
797 | } |
||
798 | |||
799 | void client_decoder_handler_error (struct client *client) |
||
800 | { |
||
801 | client_log(client, BLOG_ERROR, "decoder error"); |
||
802 | |||
803 | // free client |
||
804 | client_free(client); |
||
805 | } |
||
806 | |||
807 | void client_recv_if_handler_send (struct client *client, uint8_t *data, int data_len) |
||
808 | { |
||
809 | ASSERT(data_len >= 0) |
||
810 | ASSERT(data_len <= udpgw_mtu) |
||
811 | |||
812 | // accept packet |
||
813 | PacketPassInterface_Done(&client->recv_if); |
||
814 | |||
815 | // parse header |
||
816 | if (data_len < sizeof(struct udpgw_header)) { |
||
817 | client_log(client, BLOG_ERROR, "missing header"); |
||
818 | return; |
||
819 | } |
||
820 | struct udpgw_header header; |
||
821 | memcpy(&header, data, sizeof(header)); |
||
822 | data += sizeof(header); |
||
823 | data_len -= sizeof(header); |
||
824 | uint8_t flags = ltoh8(header.flags); |
||
825 | uint16_t conid = ltoh16(header.conid); |
||
826 | |||
827 | // reset disconnect timer |
||
828 | BReactor_SetTimer(&ss, &client->disconnect_timer); |
||
829 | |||
830 | // if this is keepalive, ignore any payload |
||
831 | if ((flags & UDPGW_CLIENT_FLAG_KEEPALIVE)) { |
||
832 | client_log(client, BLOG_DEBUG, "received keepalive"); |
||
833 | return; |
||
834 | } |
||
835 | |||
836 | // parse address |
||
837 | BAddr orig_addr; |
||
838 | if ((flags & UDPGW_CLIENT_FLAG_IPV6)) { |
||
839 | if (data_len < sizeof(struct udpgw_addr_ipv6)) { |
||
840 | client_log(client, BLOG_ERROR, "missing ipv6 address"); |
||
841 | return; |
||
842 | } |
||
843 | struct udpgw_addr_ipv6 addr_ipv6; |
||
844 | memcpy(&addr_ipv6, data, sizeof(addr_ipv6)); |
||
845 | data += sizeof(addr_ipv6); |
||
846 | data_len -= sizeof(addr_ipv6); |
||
847 | BAddr_InitIPv6(&orig_addr, addr_ipv6.addr_ip, addr_ipv6.addr_port); |
||
848 | } else { |
||
849 | if (data_len < sizeof(struct udpgw_addr_ipv4)) { |
||
850 | client_log(client, BLOG_ERROR, "missing ipv4 address"); |
||
851 | return; |
||
852 | } |
||
853 | struct udpgw_addr_ipv4 addr_ipv4; |
||
854 | memcpy(&addr_ipv4, data, sizeof(addr_ipv4)); |
||
855 | data += sizeof(addr_ipv4); |
||
856 | data_len -= sizeof(addr_ipv4); |
||
857 | BAddr_InitIPv4(&orig_addr, addr_ipv4.addr_ip, addr_ipv4.addr_port); |
||
858 | } |
||
859 | |||
860 | // check payload length |
||
861 | if (data_len > options.udp_mtu) { |
||
862 | client_log(client, BLOG_ERROR, "too much data"); |
||
863 | return; |
||
864 | } |
||
865 | |||
866 | // find connection |
||
867 | struct connection *con = find_connection(client, conid); |
||
868 | ASSERT(!con || !con->closing) |
||
869 | |||
870 | // if connection exists, close it if needed |
||
871 | if (con && ((flags & UDPGW_CLIENT_FLAG_REBIND) || !BAddr_Compare(&con->orig_addr, &orig_addr))) { |
||
872 | connection_log(con, BLOG_DEBUG, "close old"); |
||
873 | connection_close(con); |
||
874 | con = NULL; |
||
875 | } |
||
876 | |||
877 | // if connection doesn't exists, create it |
||
878 | if (!con) { |
||
879 | // check number of connections |
||
880 | if (client->num_connections == options.max_connections_for_client) { |
||
881 | // close least recently used connection |
||
882 | con = UPPER_OBJECT(LinkedList1_GetFirst(&client->connections_list), struct connection, connections_list_node); |
||
883 | connection_close(con); |
||
884 | } |
||
885 | |||
886 | // if this is DNS, replace actual address, but keep still remember the orig_addr |
||
887 | BAddr addr = orig_addr; |
||
888 | if ((flags & UDPGW_CLIENT_FLAG_DNS)) { |
||
889 | maybe_update_dns(); |
||
890 | if (dns_addr.type == BADDR_TYPE_NONE) { |
||
891 | client_log(client, BLOG_WARNING, "received DNS packet, but no DNS server available"); |
||
892 | } else { |
||
893 | client_log(client, BLOG_DEBUG, "received DNS"); |
||
894 | addr = dns_addr; |
||
895 | } |
||
896 | } |
||
897 | |||
898 | // create new connection |
||
899 | connection_init(client, conid, addr, orig_addr, data, data_len); |
||
900 | } else { |
||
901 | // submit packet to existing connection |
||
902 | connection_send_to_udp(con, data, data_len); |
||
903 | } |
||
904 | } |
||
905 | |||
906 | int get_local_num_ports (int addr_type) |
||
907 | { |
||
908 | switch (addr_type) { |
||
909 | case BADDR_TYPE_IPV4: return options.local_udp_num_ports; |
||
910 | case BADDR_TYPE_IPV6: return options.local_udp_ip6_num_ports; |
||
911 | default: ASSERT(0); return 0; |
||
912 | } |
||
913 | } |
||
914 | |||
915 | BAddr get_local_addr (int addr_type) |
||
916 | { |
||
917 | ASSERT(get_local_num_ports(addr_type) >= 0) |
||
918 | |||
919 | switch (addr_type) { |
||
920 | case BADDR_TYPE_IPV4: return local_udp_addr; |
||
921 | case BADDR_TYPE_IPV6: return local_udp_ip6_addr; |
||
922 | default: ASSERT(0); return BAddr_MakeNone(); |
||
923 | } |
||
924 | } |
||
925 | |||
926 | uint8_t * build_port_usage_array_and_find_least_used_connection (BAddr remote_addr, struct connection **out_con) |
||
927 | { |
||
928 | ASSERT(remote_addr.type == BADDR_TYPE_IPV4 || remote_addr.type == BADDR_TYPE_IPV6) |
||
929 | ASSERT(get_local_num_ports(remote_addr.type) >= 0) |
||
930 | |||
931 | int local_num_ports = get_local_num_ports(remote_addr.type); |
||
932 | |||
933 | // allocate port usage array |
||
934 | uint8_t *port_usage = (uint8_t *)BAllocSize(bsize_fromint(local_num_ports)); |
||
935 | if (!port_usage) { |
||
936 | return NULL; |
||
937 | } |
||
938 | |||
939 | // zero array |
||
940 | memset(port_usage, 0, local_num_ports); |
||
941 | |||
942 | struct connection *least_con = NULL; |
||
943 | |||
944 | // flag inappropriate ports (those with the same remote address) |
||
945 | for (LinkedList1Node *ln = LinkedList1_GetFirst(&clients_list); ln; ln = LinkedList1Node_Next(ln)) { |
||
946 | struct client *client = UPPER_OBJECT(ln, struct client, clients_list_node); |
||
947 | |||
948 | for (LinkedList1Node *ln2 = LinkedList1_GetFirst(&client->connections_list); ln2; ln2 = LinkedList1Node_Next(ln2)) { |
||
949 | struct connection *con = UPPER_OBJECT(ln2, struct connection, connections_list_node); |
||
950 | ASSERT(con->client == client) |
||
951 | ASSERT(!con->closing) |
||
952 | |||
953 | if (con->addr.type != remote_addr.type || con->local_port_index < 0) { |
||
954 | continue; |
||
955 | } |
||
956 | ASSERT(con->local_port_index < local_num_ports) |
||
957 | |||
958 | if (options.unique_local_ports) { |
||
959 | BIPAddr ip1; |
||
960 | BIPAddr ip2; |
||
961 | BAddr_GetIPAddr(&con->addr, &ip1); |
||
962 | BAddr_GetIPAddr(&remote_addr, &ip2); |
||
963 | if (!BIPAddr_Compare(&ip1, &ip2)) { |
||
964 | continue; |
||
965 | } |
||
966 | } else { |
||
967 | if (!BAddr_Compare(&con->addr, &remote_addr)) { |
||
968 | continue; |
||
969 | } |
||
970 | } |
||
971 | |||
972 | port_usage[con->local_port_index] = 1; |
||
973 | |||
974 | if (!PacketPassFairQueueFlow_IsBusy(&con->send_qflow)) { |
||
975 | if (!least_con || con->last_use_time < least_con->last_use_time) { |
||
976 | least_con = con; |
||
977 | } |
||
978 | } |
||
979 | } |
||
980 | } |
||
981 | |||
982 | *out_con = least_con; |
||
983 | return port_usage; |
||
984 | } |
||
985 | |||
986 | void connection_init (struct client *client, uint16_t conid, BAddr addr, BAddr orig_addr, const uint8_t *data, int data_len) |
||
987 | { |
||
988 | ASSERT(client->num_connections < options.max_connections_for_client) |
||
989 | ASSERT(!find_connection(client, conid)) |
||
990 | BAddr_Assert(&addr); |
||
991 | ASSERT(addr.type == BADDR_TYPE_IPV4 || addr.type == BADDR_TYPE_IPV6) |
||
992 | ASSERT(orig_addr.type == BADDR_TYPE_IPV4 || orig_addr.type == BADDR_TYPE_IPV6) |
||
993 | ASSERT(data_len >= 0) |
||
994 | ASSERT(data_len <= options.udp_mtu) |
||
995 | |||
996 | // allocate structure |
||
997 | struct connection *con = (struct connection *)malloc(sizeof(*con)); |
||
998 | if (!con) { |
||
999 | client_log(client, BLOG_ERROR, "malloc failed"); |
||
1000 | goto fail0; |
||
1001 | } |
||
1002 | |||
1003 | // init arguments |
||
1004 | con->client = client; |
||
1005 | con->conid = conid; |
||
1006 | con->addr = addr; |
||
1007 | con->orig_addr = orig_addr; |
||
1008 | con->first_data = data; |
||
1009 | con->first_data_len = data_len; |
||
1010 | |||
1011 | // set last use time |
||
1012 | con->last_use_time = btime_gettime(); |
||
1013 | |||
1014 | // set not closing |
||
1015 | con->closing = 0; |
||
1016 | |||
1017 | // init first job |
||
1018 | BPending_Init(&con->first_job, BReactor_PendingGroup(&ss), (BPending_handler)connection_first_job_handler, con); |
||
1019 | BPending_Set(&con->first_job); |
||
1020 | |||
1021 | // init send queue flow |
||
1022 | PacketPassFairQueueFlow_Init(&con->send_qflow, &client->send_queue); |
||
1023 | |||
1024 | // init send PacketProtoFlow |
||
1025 | if (!PacketProtoFlow_Init(&con->send_ppflow, udpgw_mtu, CONNECTION_CLIENT_BUFFER_SIZE, PacketPassFairQueueFlow_GetInput(&con->send_qflow), BReactor_PendingGroup(&ss))) { |
||
1026 | client_log(client, BLOG_ERROR, "PacketProtoFlow_Init failed"); |
||
1027 | goto fail1; |
||
1028 | } |
||
1029 | con->send_if = PacketProtoFlow_GetInput(&con->send_ppflow); |
||
1030 | |||
1031 | // init UDP dgram |
||
1032 | if (!BDatagram_Init(&con->udp_dgram, addr.type, &ss, con, (BDatagram_handler)connection_dgram_handler_event)) { |
||
1033 | client_log(client, BLOG_ERROR, "BDatagram_Init failed"); |
||
1034 | goto fail2; |
||
1035 | } |
||
1036 | |||
1037 | con->local_port_index = -1; |
||
1038 | |||
1039 | int local_num_ports = get_local_num_ports(addr.type); |
||
1040 | |||
1041 | if (local_num_ports >= 0) { |
||
1042 | // build port usage array, find least used connection |
||
1043 | struct connection *least_con; |
||
1044 | uint8_t *port_usage = build_port_usage_array_and_find_least_used_connection(addr, &least_con); |
||
1045 | if (!port_usage) { |
||
1046 | client_log(client, BLOG_ERROR, "build_port_usage_array failed"); |
||
1047 | goto failed; |
||
1048 | } |
||
1049 | |||
1050 | // set SO_REUSEADDR |
||
1051 | if (!BDatagram_SetReuseAddr(&con->udp_dgram, 1)) { |
||
1052 | client_log(client, BLOG_ERROR, "set SO_REUSEADDR failed"); |
||
1053 | goto failed; |
||
1054 | } |
||
1055 | |||
1056 | // get starting local address |
||
1057 | BAddr local_addr = get_local_addr(addr.type); |
||
1058 | |||
1059 | // try different ports |
||
1060 | for (int i = 0; i < local_num_ports; i++) { |
||
1061 | // skip inappropriate ports |
||
1062 | if (port_usage[i]) { |
||
1063 | continue; |
||
1064 | } |
||
1065 | |||
1066 | BAddr bind_addr = local_addr; |
||
1067 | BAddr_SetPort(&bind_addr, hton16(ntoh16(BAddr_GetPort(&bind_addr)) + (uint16_t)i)); |
||
1068 | if (BDatagram_Bind(&con->udp_dgram, bind_addr)) { |
||
1069 | // remember which port we're using |
||
1070 | con->local_port_index = i; |
||
1071 | goto cont; |
||
1072 | } |
||
1073 | } |
||
1074 | |||
1075 | // try closing an unused connection with the same remote addr |
||
1076 | if (!least_con) { |
||
1077 | goto failed; |
||
1078 | } |
||
1079 | |||
1080 | ASSERT(least_con->addr.type == addr.type) |
||
1081 | ASSERT(least_con->local_port_index >= 0) |
||
1082 | ASSERT(least_con->local_port_index < local_num_ports) |
||
1083 | ASSERT(!PacketPassFairQueueFlow_IsBusy(&least_con->send_qflow)) |
||
1084 | |||
1085 | int i = least_con->local_port_index; |
||
1086 | |||
1087 | BLog(BLOG_INFO, "closing connection for its remote address"); |
||
1088 | |||
1089 | // close the offending connection |
||
1090 | connection_close(least_con); |
||
1091 | |||
1092 | // try binding to its port |
||
1093 | BAddr bind_addr = local_addr; |
||
1094 | BAddr_SetPort(&bind_addr, hton16(ntoh16(BAddr_GetPort(&bind_addr)) + (uint16_t)i)); |
||
1095 | if (BDatagram_Bind(&con->udp_dgram, bind_addr)) { |
||
1096 | // remember which port we're using |
||
1097 | con->local_port_index = i; |
||
1098 | goto cont; |
||
1099 | } |
||
1100 | |||
1101 | failed: |
||
1102 | client_log(client, BLOG_WARNING, "failed to bind to any local address; proceeding regardless"); |
||
1103 | cont:; |
||
1104 | BFree(port_usage); |
||
1105 | } |
||
1106 | |||
1107 | // set UDP dgram send address |
||
1108 | BIPAddr ipaddr; |
||
1109 | BIPAddr_InitInvalid(&ipaddr); |
||
1110 | BDatagram_SetSendAddrs(&con->udp_dgram, addr, ipaddr); |
||
1111 | |||
1112 | // init UDP dgram interfaces |
||
1113 | BDatagram_SendAsync_Init(&con->udp_dgram, options.udp_mtu); |
||
1114 | BDatagram_RecvAsync_Init(&con->udp_dgram, options.udp_mtu); |
||
1115 | |||
1116 | // init UDP writer |
||
1117 | BufferWriter_Init(&con->udp_send_writer, options.udp_mtu, BReactor_PendingGroup(&ss)); |
||
1118 | |||
1119 | // init UDP buffer |
||
1120 | if (!PacketBuffer_Init(&con->udp_send_buffer, BufferWriter_GetOutput(&con->udp_send_writer), BDatagram_SendAsync_GetIf(&con->udp_dgram), CONNECTION_UDP_BUFFER_SIZE, BReactor_PendingGroup(&ss))) { |
||
1121 | client_log(client, BLOG_ERROR, "PacketBuffer_Init failed"); |
||
1122 | goto fail4; |
||
1123 | } |
||
1124 | |||
1125 | // init UDP recv interface |
||
1126 | PacketPassInterface_Init(&con->udp_recv_if, options.udp_mtu, (PacketPassInterface_handler_send)connection_udp_recv_if_handler_send, con, BReactor_PendingGroup(&ss)); |
||
1127 | |||
1128 | // init UDP recv buffer |
||
1129 | if (!SinglePacketBuffer_Init(&con->udp_recv_buffer, BDatagram_RecvAsync_GetIf(&con->udp_dgram), &con->udp_recv_if, BReactor_PendingGroup(&ss))) { |
||
1130 | client_log(client, BLOG_ERROR, "SinglePacketBuffer_Init failed"); |
||
1131 | goto fail5; |
||
1132 | } |
||
1133 | |||
1134 | // insert to client's connections tree |
||
1135 | ASSERT_EXECUTE(BAVL_Insert(&client->connections_tree, &con->connections_tree_node, NULL)) |
||
1136 | |||
1137 | // insert to client's connections list |
||
1138 | LinkedList1_Append(&client->connections_list, &con->connections_list_node); |
||
1139 | |||
1140 | // increment number of connections |
||
1141 | client->num_connections++; |
||
1142 | |||
1143 | connection_log(con, BLOG_DEBUG, "initialized"); |
||
1144 | |||
1145 | return; |
||
1146 | |||
1147 | fail5: |
||
1148 | PacketPassInterface_Free(&con->udp_recv_if); |
||
1149 | PacketBuffer_Free(&con->udp_send_buffer); |
||
1150 | fail4: |
||
1151 | BufferWriter_Free(&con->udp_send_writer); |
||
1152 | BDatagram_RecvAsync_Free(&con->udp_dgram); |
||
1153 | BDatagram_SendAsync_Free(&con->udp_dgram); |
||
1154 | BDatagram_Free(&con->udp_dgram); |
||
1155 | fail2: |
||
1156 | PacketProtoFlow_Free(&con->send_ppflow); |
||
1157 | fail1: |
||
1158 | PacketPassFairQueueFlow_Free(&con->send_qflow); |
||
1159 | BPending_Free(&con->first_job); |
||
1160 | free(con); |
||
1161 | fail0: |
||
1162 | return; |
||
1163 | } |
||
1164 | |||
1165 | void connection_free (struct connection *con) |
||
1166 | { |
||
1167 | struct client *client = con->client; |
||
1168 | PacketPassFairQueueFlow_AssertFree(&con->send_qflow); |
||
1169 | |||
1170 | if (con->closing) { |
||
1171 | // remove from client's closing connections list |
||
1172 | LinkedList1_Remove(&client->closing_connections_list, &con->closing_connections_list_node); |
||
1173 | } else { |
||
1174 | // decrement number of connections |
||
1175 | client->num_connections--; |
||
1176 | |||
1177 | // remove from client's connections list |
||
1178 | LinkedList1_Remove(&client->connections_list, &con->connections_list_node); |
||
1179 | |||
1180 | // remove from client's connections tree |
||
1181 | BAVL_Remove(&client->connections_tree, &con->connections_tree_node); |
||
1182 | |||
1183 | // free UDP |
||
1184 | connection_free_udp(con); |
||
1185 | } |
||
1186 | |||
1187 | // free send PacketProtoFlow |
||
1188 | PacketProtoFlow_Free(&con->send_ppflow); |
||
1189 | |||
1190 | // free send queue flow |
||
1191 | PacketPassFairQueueFlow_Free(&con->send_qflow); |
||
1192 | |||
1193 | // free first job |
||
1194 | BPending_Free(&con->first_job); |
||
1195 | |||
1196 | // free structure |
||
1197 | free(con); |
||
1198 | } |
||
1199 | |||
1200 | void connection_logfunc (struct connection *con) |
||
1201 | { |
||
1202 | client_logfunc(con->client); |
||
1203 | |||
1204 | if (con->closing) { |
||
1205 | BLog_Append("old connection %"PRIu16": ", con->conid); |
||
1206 | } else { |
||
1207 | BLog_Append("connection %"PRIu16": ", con->conid); |
||
1208 | } |
||
1209 | } |
||
1210 | |||
1211 | void connection_log (struct connection *con, int level, const char *fmt, ...) |
||
1212 | { |
||
1213 | va_list vl; |
||
1214 | va_start(vl, fmt); |
||
1215 | BLog_LogViaFuncVarArg((BLog_logfunc)connection_logfunc, con, BLOG_CURRENT_CHANNEL, level, fmt, vl); |
||
1216 | va_end(vl); |
||
1217 | } |
||
1218 | |||
1219 | void connection_free_udp (struct connection *con) |
||
1220 | { |
||
1221 | // free UDP receive buffer |
||
1222 | SinglePacketBuffer_Free(&con->udp_recv_buffer); |
||
1223 | |||
1224 | // free UDP receive interface |
||
1225 | PacketPassInterface_Free(&con->udp_recv_if); |
||
1226 | |||
1227 | // free UDP buffer |
||
1228 | PacketBuffer_Free(&con->udp_send_buffer); |
||
1229 | |||
1230 | // free UDP writer |
||
1231 | BufferWriter_Free(&con->udp_send_writer); |
||
1232 | |||
1233 | // free UDP dgram interfaces |
||
1234 | BDatagram_RecvAsync_Free(&con->udp_dgram); |
||
1235 | BDatagram_SendAsync_Free(&con->udp_dgram); |
||
1236 | |||
1237 | // free UDP dgram |
||
1238 | BDatagram_Free(&con->udp_dgram); |
||
1239 | } |
||
1240 | |||
1241 | void connection_first_job_handler (struct connection *con) |
||
1242 | { |
||
1243 | ASSERT(!con->closing) |
||
1244 | |||
1245 | connection_send_to_udp(con, con->first_data, con->first_data_len); |
||
1246 | } |
||
1247 | |||
1248 | void connection_send_to_client (struct connection *con, uint8_t flags, const uint8_t *data, int data_len) |
||
1249 | { |
||
1250 | ASSERT(data_len >= 0) |
||
1251 | ASSERT(data_len <= options.udp_mtu) |
||
1252 | |||
1253 | size_t addr_len = (con->orig_addr.type == BADDR_TYPE_IPV6) ? sizeof(struct udpgw_addr_ipv6) : |
||
1254 | (con->orig_addr.type == BADDR_TYPE_IPV4) ? sizeof(struct udpgw_addr_ipv4) : 0; |
||
1255 | if (data_len > udpgw_mtu - (int)(sizeof(struct udpgw_header) + addr_len)) { |
||
1256 | connection_log(con, BLOG_WARNING, "packet is too large, cannot send to client"); |
||
1257 | return; |
||
1258 | } |
||
1259 | |||
1260 | // get buffer location |
||
1261 | uint8_t *out; |
||
1262 | if (!BufferWriter_StartPacket(con->send_if, &out)) { |
||
1263 | connection_log(con, BLOG_ERROR, "out of client buffer"); |
||
1264 | return; |
||
1265 | } |
||
1266 | int out_pos = 0; |
||
1267 | |||
1268 | if (con->orig_addr.type == BADDR_TYPE_IPV6) { |
||
1269 | flags |= UDPGW_CLIENT_FLAG_IPV6; |
||
1270 | } |
||
1271 | |||
1272 | // write header |
||
1273 | struct udpgw_header header; |
||
1274 | header.flags = htol8(flags); |
||
1275 | header.conid = htol16(con->conid); |
||
1276 | memcpy(out + out_pos, &header, sizeof(header)); |
||
1277 | out_pos += sizeof(header); |
||
1278 | |||
1279 | // write address |
||
1280 | switch (con->orig_addr.type) { |
||
1281 | case BADDR_TYPE_IPV4: { |
||
1282 | struct udpgw_addr_ipv4 addr_ipv4; |
||
1283 | addr_ipv4.addr_ip = con->orig_addr.ipv4.ip; |
||
1284 | addr_ipv4.addr_port = con->orig_addr.ipv4.port; |
||
1285 | memcpy(out + out_pos, &addr_ipv4, sizeof(addr_ipv4)); |
||
1286 | out_pos += sizeof(addr_ipv4); |
||
1287 | } break; |
||
1288 | case BADDR_TYPE_IPV6: { |
||
1289 | struct udpgw_addr_ipv6 addr_ipv6; |
||
1290 | memcpy(addr_ipv6.addr_ip, con->orig_addr.ipv6.ip, sizeof(addr_ipv6.addr_ip)); |
||
1291 | addr_ipv6.addr_port = con->orig_addr.ipv6.port; |
||
1292 | memcpy(out + out_pos, &addr_ipv6, sizeof(addr_ipv6)); |
||
1293 | out_pos += sizeof(addr_ipv6); |
||
1294 | } break; |
||
1295 | } |
||
1296 | |||
1297 | // write message |
||
1298 | memcpy(out + out_pos, data, data_len); |
||
1299 | out_pos += data_len; |
||
1300 | |||
1301 | // submit written message |
||
1302 | ASSERT(out_pos <= udpgw_mtu) |
||
1303 | BufferWriter_EndPacket(con->send_if, out_pos); |
||
1304 | } |
||
1305 | |||
1306 | int connection_send_to_udp (struct connection *con, const uint8_t *data, int data_len) |
||
1307 | { |
||
1308 | struct client *client = con->client; |
||
1309 | ASSERT(!con->closing) |
||
1310 | ASSERT(data_len >= 0) |
||
1311 | ASSERT(data_len <= options.udp_mtu) |
||
1312 | |||
1313 | connection_log(con, BLOG_DEBUG, "from client %d bytes", data_len); |
||
1314 | |||
1315 | // set last use time |
||
1316 | con->last_use_time = btime_gettime(); |
||
1317 | |||
1318 | // move connection to front |
||
1319 | LinkedList1_Remove(&client->connections_list, &con->connections_list_node); |
||
1320 | LinkedList1_Append(&client->connections_list, &con->connections_list_node); |
||
1321 | |||
1322 | // get buffer location |
||
1323 | uint8_t *out; |
||
1324 | if (!BufferWriter_StartPacket(&con->udp_send_writer, &out)) { |
||
1325 | connection_log(con, BLOG_ERROR, "out of UDP buffer"); |
||
1326 | return 0; |
||
1327 | } |
||
1328 | |||
1329 | // write message |
||
1330 | memcpy(out, data, data_len); |
||
1331 | |||
1332 | // submit written message |
||
1333 | BufferWriter_EndPacket(&con->udp_send_writer, data_len); |
||
1334 | |||
1335 | return 1; |
||
1336 | } |
||
1337 | |||
1338 | void connection_close (struct connection *con) |
||
1339 | { |
||
1340 | struct client *client = con->client; |
||
1341 | ASSERT(!con->closing) |
||
1342 | |||
1343 | // if possible, free connection immediately |
||
1344 | if (!PacketPassFairQueueFlow_IsBusy(&con->send_qflow)) { |
||
1345 | connection_free(con); |
||
1346 | return; |
||
1347 | } |
||
1348 | |||
1349 | connection_log(con, BLOG_DEBUG, "closing later"); |
||
1350 | |||
1351 | // decrement number of connections |
||
1352 | client->num_connections--; |
||
1353 | |||
1354 | // remove from client's connections list |
||
1355 | LinkedList1_Remove(&client->connections_list, &con->connections_list_node); |
||
1356 | |||
1357 | // remove from client's connections tree |
||
1358 | BAVL_Remove(&client->connections_tree, &con->connections_tree_node); |
||
1359 | |||
1360 | // free UDP |
||
1361 | connection_free_udp(con); |
||
1362 | |||
1363 | // insert to client's closing connections list |
||
1364 | LinkedList1_Append(&client->closing_connections_list, &con->closing_connections_list_node); |
||
1365 | |||
1366 | // set busy handler |
||
1367 | PacketPassFairQueueFlow_SetBusyHandler(&con->send_qflow, (PacketPassFairQueue_handler_busy)connection_send_qflow_busy_handler, con); |
||
1368 | |||
1369 | // unset first job |
||
1370 | BPending_Unset(&con->first_job); |
||
1371 | |||
1372 | // set closing |
||
1373 | con->closing = 1; |
||
1374 | } |
||
1375 | |||
1376 | void connection_send_qflow_busy_handler (struct connection *con) |
||
1377 | { |
||
1378 | ASSERT(con->closing) |
||
1379 | PacketPassFairQueueFlow_AssertFree(&con->send_qflow); |
||
1380 | |||
1381 | connection_log(con, BLOG_DEBUG, "closing finally"); |
||
1382 | |||
1383 | // free connection |
||
1384 | connection_free(con); |
||
1385 | } |
||
1386 | |||
1387 | void connection_dgram_handler_event (struct connection *con, int event) |
||
1388 | { |
||
1389 | ASSERT(!con->closing) |
||
1390 | |||
1391 | connection_log(con, BLOG_INFO, "UDP error"); |
||
1392 | |||
1393 | // close connection |
||
1394 | connection_close(con); |
||
1395 | } |
||
1396 | |||
1397 | void connection_udp_recv_if_handler_send (struct connection *con, uint8_t *data, int data_len) |
||
1398 | { |
||
1399 | struct client *client = con->client; |
||
1400 | ASSERT(!con->closing) |
||
1401 | ASSERT(data_len >= 0) |
||
1402 | ASSERT(data_len <= options.udp_mtu) |
||
1403 | |||
1404 | connection_log(con, BLOG_DEBUG, "from UDP %d bytes", data_len); |
||
1405 | |||
1406 | // set last use time |
||
1407 | con->last_use_time = btime_gettime(); |
||
1408 | |||
1409 | // move connection to front |
||
1410 | LinkedList1_Remove(&client->connections_list, &con->connections_list_node); |
||
1411 | LinkedList1_Append(&client->connections_list, &con->connections_list_node); |
||
1412 | |||
1413 | // accept packet |
||
1414 | PacketPassInterface_Done(&con->udp_recv_if); |
||
1415 | |||
1416 | // send packet to client |
||
1417 | connection_send_to_client(con, 0, data, data_len); |
||
1418 | } |
||
1419 | |||
1420 | struct connection * find_connection (struct client *client, uint16_t conid) |
||
1421 | { |
||
1422 | BAVLNode *tree_node = BAVL_LookupExact(&client->connections_tree, &conid); |
||
1423 | if (!tree_node) { |
||
1424 | return NULL; |
||
1425 | } |
||
1426 | struct connection *con = UPPER_OBJECT(tree_node, struct connection, connections_tree_node); |
||
1427 | ASSERT(con->conid == conid) |
||
1428 | ASSERT(!con->closing) |
||
1429 | |||
1430 | return con; |
||
1431 | } |
||
1432 | |||
1433 | int uint16_comparator (void *unused, uint16_t *v1, uint16_t *v2) |
||
1434 | { |
||
1435 | return B_COMPARE(*v1, *v2); |
||
1436 | } |
||
1437 | |||
1438 | void maybe_update_dns (void) |
||
1439 | { |
||
1440 | #ifndef BADVPN_USE_WINAPI |
||
1441 | btime_t now = btime_gettime(); |
||
1442 | if (now < btime_add(last_dns_update_time, DNS_UPDATE_TIME)) { |
||
1443 | return; |
||
1444 | } |
||
1445 | last_dns_update_time = now; |
||
1446 | BLog(BLOG_DEBUG, "update dns"); |
||
1447 | |||
1448 | if (res_init() != 0) { |
||
1449 | BLog(BLOG_ERROR, "res_init failed"); |
||
1450 | goto fail; |
||
1451 | } |
||
1452 | |||
1453 | if (_res.nscount == 0) { |
||
1454 | BLog(BLOG_ERROR, "no name servers available"); |
||
1455 | goto fail; |
||
1456 | } |
||
1457 | |||
1458 | BAddr addr; |
||
1459 | BAddr_InitIPv4(&addr, _res.nsaddr_list[0].sin_addr.s_addr, hton16(53)); |
||
1460 | |||
1461 | if (!BAddr_Compare(&addr, &dns_addr)) { |
||
1462 | char str[BADDR_MAX_PRINT_LEN]; |
||
1463 | BAddr_Print(&addr, str); |
||
1464 | BLog(BLOG_INFO, "using DNS server %s", str); |
||
1465 | } |
||
1466 | |||
1467 | dns_addr = addr; |
||
1468 | return; |
||
1469 | |||
1470 | fail: |
||
1471 | BAddr_InitNone(&dns_addr); |
||
1472 | #endif |
||
1473 | } |