BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file client.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 <stdint.h> |
||
31 | #include <stdlib.h> |
||
32 | #include <string.h> |
||
33 | #include <limits.h> |
||
34 | |||
35 | #include <protocol/msgproto.h> |
||
36 | #include <protocol/addr.h> |
||
37 | #include <protocol/dataproto.h> |
||
38 | #include <misc/version.h> |
||
39 | #include <misc/debug.h> |
||
40 | #include <misc/offset.h> |
||
41 | #include <misc/byteorder.h> |
||
42 | #include <misc/nsskey.h> |
||
43 | #include <misc/loglevel.h> |
||
44 | #include <misc/loggers_string.h> |
||
45 | #include <misc/string_begins_with.h> |
||
46 | #include <misc/open_standard_streams.h> |
||
47 | #include <structure/LinkedList1.h> |
||
48 | #include <base/DebugObject.h> |
||
49 | #include <base/BLog.h> |
||
50 | #include <security/BSecurity.h> |
||
51 | #include <security/BRandom.h> |
||
52 | #include <system/BSignal.h> |
||
53 | #include <system/BTime.h> |
||
54 | #include <system/BNetwork.h> |
||
55 | #include <nspr_support/DummyPRFileDesc.h> |
||
56 | #include <nspr_support/BSSLConnection.h> |
||
57 | #include <server_connection/ServerConnection.h> |
||
58 | #include <tuntap/BTap.h> |
||
59 | #include <threadwork/BThreadWork.h> |
||
60 | |||
61 | #ifndef BADVPN_USE_WINAPI |
||
62 | #include <base/BLog_syslog.h> |
||
63 | #endif |
||
64 | |||
65 | #include <client/client.h> |
||
66 | |||
67 | #include <generated/blog_channel_client.h> |
||
68 | |||
69 | #define TRANSPORT_MODE_UDP 0 |
||
70 | #define TRANSPORT_MODE_TCP 1 |
||
71 | |||
72 | #define LOGGER_STDOUT 1 |
||
73 | #define LOGGER_SYSLOG 2 |
||
74 | |||
75 | // command-line options |
||
76 | struct ext_addr_option { |
||
77 | char *addr; |
||
78 | char *scope; |
||
79 | }; |
||
80 | struct bind_addr_option { |
||
81 | char *addr; |
||
82 | int num_ports; |
||
83 | int num_ext_addrs; |
||
84 | struct ext_addr_option ext_addrs[MAX_EXT_ADDRS]; |
||
85 | }; |
||
86 | struct { |
||
87 | int help; |
||
88 | int version; |
||
89 | int logger; |
||
90 | #ifndef BADVPN_USE_WINAPI |
||
91 | char *logger_syslog_facility; |
||
92 | char *logger_syslog_ident; |
||
93 | #endif |
||
94 | int loglevel; |
||
95 | int loglevels[BLOG_NUM_CHANNELS]; |
||
96 | int threads; |
||
97 | int use_threads_for_ssl_handshake; |
||
98 | int use_threads_for_ssl_data; |
||
99 | int ssl; |
||
100 | char *nssdb; |
||
101 | char *client_cert_name; |
||
102 | char *server_name; |
||
103 | char *server_addr; |
||
104 | char *tapdev; |
||
105 | int num_scopes; |
||
106 | char *scopes[MAX_SCOPES]; |
||
107 | int num_bind_addrs; |
||
108 | struct bind_addr_option bind_addrs[MAX_BIND_ADDRS]; |
||
109 | int transport_mode; |
||
110 | int encryption_mode; |
||
111 | int hash_mode; |
||
112 | int otp_mode; |
||
113 | int otp_num; |
||
114 | int otp_num_warn; |
||
115 | int fragmentation_latency; |
||
116 | int peer_ssl; |
||
117 | int peer_tcp_socket_sndbuf; |
||
118 | int send_buffer_size; |
||
119 | int send_buffer_relay_size; |
||
120 | int max_macs; |
||
121 | int max_groups; |
||
122 | int igmp_group_membership_interval; |
||
123 | int igmp_last_member_query_time; |
||
124 | int allow_peer_talk_without_ssl; |
||
125 | int max_peers; |
||
126 | } options; |
||
127 | |||
128 | // bind addresses |
||
129 | struct ext_addr { |
||
130 | int server_reported_port; |
||
131 | BAddr addr; // if server_reported_port>=0, defined only after hello received |
||
132 | char scope[64]; |
||
133 | }; |
||
134 | struct bind_addr { |
||
135 | BAddr addr; |
||
136 | int num_ports; |
||
137 | int num_ext_addrs; |
||
138 | struct ext_addr ext_addrs[MAX_EXT_ADDRS]; |
||
139 | }; |
||
140 | int num_bind_addrs; |
||
141 | struct bind_addr bind_addrs[MAX_BIND_ADDRS]; |
||
142 | |||
143 | // TCP listeners |
||
144 | PasswordListener listeners[MAX_BIND_ADDRS]; |
||
145 | |||
146 | // SPProto parameters (UDP only) |
||
147 | struct spproto_security_params sp_params; |
||
148 | |||
149 | // server address we connect to |
||
150 | BAddr server_addr; |
||
151 | |||
152 | // server name to use for SSL |
||
153 | char server_name[256]; |
||
154 | |||
155 | // reactor |
||
156 | BReactor ss; |
||
157 | |||
158 | // thread work dispatcher |
||
159 | BThreadWorkDispatcher twd; |
||
160 | |||
161 | // client certificate if using SSL |
||
162 | CERTCertificate *client_cert; |
||
163 | |||
164 | // client private key if using SSL |
||
165 | SECKEYPrivateKey *client_key; |
||
166 | |||
167 | // device |
||
168 | BTap device; |
||
169 | int device_mtu; |
||
170 | |||
171 | // DataProtoSource for device input (reading) |
||
172 | DataProtoSource device_dpsource; |
||
173 | |||
174 | // DPReceiveDevice for device output (writing) |
||
175 | DPReceiveDevice device_output_dprd; |
||
176 | |||
177 | // data communication MTU |
||
178 | int data_mtu; |
||
179 | |||
180 | // peers list |
||
181 | LinkedList1 peers; |
||
182 | int num_peers; |
||
183 | |||
184 | // frame decider |
||
185 | FrameDecider frame_decider; |
||
186 | |||
187 | // peers that can be user as relays |
||
188 | LinkedList1 relays; |
||
189 | |||
190 | // peers than need a relay |
||
191 | LinkedList1 waiting_relay_peers; |
||
192 | |||
193 | // server connection |
||
194 | ServerConnection server; |
||
195 | |||
196 | // my ID, defined only after server_ready |
||
197 | peerid_t my_id; |
||
198 | |||
199 | // fair queue for sending peer messages to the server |
||
200 | PacketPassFairQueue server_queue; |
||
201 | |||
202 | // whether server is ready |
||
203 | int server_ready; |
||
204 | |||
205 | // dying server flow |
||
206 | struct server_flow *dying_server_flow; |
||
207 | |||
208 | // stops event processing, causing the program to exit |
||
209 | static void terminate (void); |
||
210 | |||
211 | // prints program name and version to standard output |
||
212 | static void print_help (const char *name); |
||
213 | |||
214 | // prints program name and version to standard output |
||
215 | static void print_version (void); |
||
216 | |||
217 | // parses the command line |
||
218 | static int parse_arguments (int argc, char *argv[]); |
||
219 | |||
220 | // processes certain command line options |
||
221 | static int process_arguments (void); |
||
222 | |||
223 | static int ssl_flags (void); |
||
224 | |||
225 | // handler for program termination request |
||
226 | static void signal_handler (void *unused); |
||
227 | |||
228 | // adds a new peer |
||
229 | static void peer_add (peerid_t id, int flags, const uint8_t *cert, int cert_len); |
||
230 | |||
231 | // removes a peer |
||
232 | static void peer_remove (struct peer_data *peer, int exiting); |
||
233 | |||
234 | // appends the peer log prefix to the logger |
||
235 | static void peer_logfunc (struct peer_data *peer); |
||
236 | |||
237 | // passes a message to the logger, prepending it info about the peer |
||
238 | static void peer_log (struct peer_data *peer, int level, const char *fmt, ...); |
||
239 | |||
240 | // see if we are the master relative to this peer |
||
241 | static int peer_am_master (struct peer_data *peer); |
||
242 | |||
243 | // frees PeerChat, disconnecting it from the server flow |
||
244 | static void peer_free_chat (struct peer_data *peer); |
||
245 | |||
246 | // initializes the link |
||
247 | static int peer_init_link (struct peer_data *peer); |
||
248 | |||
249 | // frees link resources |
||
250 | static void peer_free_link (struct peer_data *peer); |
||
251 | |||
252 | // frees link, relaying, waiting relaying |
||
253 | static void peer_cleanup_connections (struct peer_data *peer); |
||
254 | |||
255 | // registers the peer as a relay provider |
||
256 | static void peer_enable_relay_provider (struct peer_data *peer); |
||
257 | |||
258 | // unregisters the peer as a relay provider |
||
259 | static void peer_disable_relay_provider (struct peer_data *peer); |
||
260 | |||
261 | // install relaying for a peer |
||
262 | static void peer_install_relaying (struct peer_data *peer, struct peer_data *relay); |
||
263 | |||
264 | // uninstall relaying for a peer |
||
265 | static void peer_free_relaying (struct peer_data *peer); |
||
266 | |||
267 | // handle a peer that needs a relay |
||
268 | static void peer_need_relay (struct peer_data *peer); |
||
269 | |||
270 | // inserts the peer into the need relay list |
||
271 | static void peer_register_need_relay (struct peer_data *peer); |
||
272 | |||
273 | // removes the peer from the need relay list |
||
274 | static void peer_unregister_need_relay (struct peer_data *peer); |
||
275 | |||
276 | // handle a link setup failure |
||
277 | static void peer_reset (struct peer_data *peer); |
||
278 | |||
279 | // fees chat and sends resetpeer |
||
280 | static void peer_resetpeer (struct peer_data *peer); |
||
281 | |||
282 | // chat handlers |
||
283 | static void peer_chat_handler_error (struct peer_data *peer); |
||
284 | static void peer_chat_handler_message (struct peer_data *peer, uint8_t *data, int data_len); |
||
285 | |||
286 | // handlers for different message types |
||
287 | static void peer_msg_youconnect (struct peer_data *peer, uint8_t *data, int data_len); |
||
288 | static void peer_msg_cannotconnect (struct peer_data *peer, uint8_t *data, int data_len); |
||
289 | static void peer_msg_cannotbind (struct peer_data *peer, uint8_t *data, int data_len); |
||
290 | static void peer_msg_seed (struct peer_data *peer, uint8_t *data, int data_len); |
||
291 | static void peer_msg_confirmseed (struct peer_data *peer, uint8_t *data, int data_len); |
||
292 | static void peer_msg_youretry (struct peer_data *peer, uint8_t *data, int data_len); |
||
293 | |||
294 | // handler from DatagramPeerIO when we should generate a new OTP send seed |
||
295 | static void peer_udp_pio_handler_seed_warning (struct peer_data *peer); |
||
296 | |||
297 | // handler from DatagramPeerIO when a new OTP seed can be recognized once it was provided to it |
||
298 | static void peer_udp_pio_handler_seed_ready (struct peer_data *peer); |
||
299 | |||
300 | // handler from DatagramPeerIO when an error occurs on the connection |
||
301 | static void peer_udp_pio_handler_error (struct peer_data *peer); |
||
302 | |||
303 | // handler from StreamPeerIO when an error occurs on the connection |
||
304 | static void peer_tcp_pio_handler_error (struct peer_data *peer); |
||
305 | |||
306 | // peer retry timer handler. The timer is used only on the master side, |
||
307 | // wither when we detect an error, or the peer reports an error. |
||
308 | static void peer_reset_timer_handler (struct peer_data *peer); |
||
309 | |||
310 | // start binding, according to the protocol |
||
311 | static void peer_start_binding (struct peer_data *peer); |
||
312 | |||
313 | // tries binding on one address, according to the protocol |
||
314 | static void peer_bind (struct peer_data *peer); |
||
315 | |||
316 | static void peer_bind_one_address (struct peer_data *peer, int addr_index, int *cont); |
||
317 | |||
318 | static void peer_connect (struct peer_data *peer, BAddr addr, uint8_t *encryption_key, uint64_t password); |
||
319 | |||
320 | static int peer_start_msg (struct peer_data *peer, void **data, int type, int len); |
||
321 | |||
322 | static void peer_end_msg (struct peer_data *peer); |
||
323 | |||
324 | // sends a message with no payload to the peer |
||
325 | static void peer_send_simple (struct peer_data *peer, int msgid); |
||
326 | |||
327 | static void peer_send_conectinfo (struct peer_data *peer, int addr_index, int port_adjust, uint8_t *enckey, uint64_t pass); |
||
328 | |||
329 | static void peer_send_confirmseed (struct peer_data *peer, uint16_t seed_id); |
||
330 | |||
331 | // handler for peer DataProto up state changes |
||
332 | static void peer_dataproto_handler (struct peer_data *peer, int up); |
||
333 | |||
334 | // looks for a peer with the given ID |
||
335 | static struct peer_data * find_peer_by_id (peerid_t id); |
||
336 | |||
337 | // device error handler |
||
338 | static void device_error_handler (void *unused); |
||
339 | |||
340 | // DataProtoSource handler for packets from the device |
||
341 | static void device_dpsource_handler (void *unused, const uint8_t *frame, int frame_len); |
||
342 | |||
343 | // assign relays to clients waiting for them |
||
344 | static void assign_relays (void); |
||
345 | |||
346 | // checks if the given address scope is known (i.e. we can connect to an address in it) |
||
347 | static char * address_scope_known (uint8_t *name, int name_len); |
||
348 | |||
349 | // handlers for server messages |
||
350 | static void server_handler_error (void *user); |
||
351 | static void server_handler_ready (void *user, peerid_t param_my_id, uint32_t ext_ip); |
||
352 | static void server_handler_newclient (void *user, peerid_t peer_id, int flags, const uint8_t *cert, int cert_len); |
||
353 | static void server_handler_endclient (void *user, peerid_t peer_id); |
||
354 | static void server_handler_message (void *user, peerid_t peer_id, uint8_t *data, int data_len); |
||
355 | |||
356 | // jobs |
||
357 | static void peer_job_send_seed (struct peer_data *peer); |
||
358 | static void peer_job_init (struct peer_data *peer); |
||
359 | |||
360 | // server flows |
||
361 | static struct server_flow * server_flow_init (void); |
||
362 | static void server_flow_free (struct server_flow *flow); |
||
363 | static void server_flow_die (struct server_flow *flow); |
||
364 | static void server_flow_qflow_handler_busy (struct server_flow *flow); |
||
365 | static void server_flow_connect (struct server_flow *flow, PacketRecvInterface *input); |
||
366 | static void server_flow_disconnect (struct server_flow *flow); |
||
367 | |||
368 | int main (int argc, char *argv[]) |
||
369 | { |
||
370 | if (argc <= 0) { |
||
371 | return 1; |
||
372 | } |
||
373 | |||
374 | // open standard streams |
||
375 | open_standard_streams(); |
||
376 | |||
377 | // parse command-line arguments |
||
378 | if (!parse_arguments(argc, argv)) { |
||
379 | fprintf(stderr, "Failed to parse arguments\n"); |
||
380 | print_help(argv[0]); |
||
381 | goto fail0; |
||
382 | } |
||
383 | |||
384 | // handle --help and --version |
||
385 | if (options.help) { |
||
386 | print_version(); |
||
387 | print_help(argv[0]); |
||
388 | return 0; |
||
389 | } |
||
390 | if (options.version) { |
||
391 | print_version(); |
||
392 | return 0; |
||
393 | } |
||
394 | |||
395 | // initialize logger |
||
396 | switch (options.logger) { |
||
397 | case LOGGER_STDOUT: |
||
398 | BLog_InitStdout(); |
||
399 | break; |
||
400 | #ifndef BADVPN_USE_WINAPI |
||
401 | case LOGGER_SYSLOG: |
||
402 | if (!BLog_InitSyslog(options.logger_syslog_ident, options.logger_syslog_facility)) { |
||
403 | fprintf(stderr, "Failed to initialize syslog logger\n"); |
||
404 | goto fail0; |
||
405 | } |
||
406 | break; |
||
407 | #endif |
||
408 | default: |
||
409 | ASSERT(0); |
||
410 | } |
||
411 | |||
412 | // configure logger channels |
||
413 | for (int i = 0; i < BLOG_NUM_CHANNELS; i++) { |
||
414 | if (options.loglevels[i] >= 0) { |
||
415 | BLog_SetChannelLoglevel(i, options.loglevels[i]); |
||
416 | } |
||
417 | else if (options.loglevel >= 0) { |
||
418 | BLog_SetChannelLoglevel(i, options.loglevel); |
||
419 | } |
||
420 | } |
||
421 | |||
422 | BLog(BLOG_NOTICE, "initializing "GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION); |
||
423 | |||
424 | if (options.ssl) { |
||
425 | // init NSPR |
||
426 | PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); |
||
427 | |||
428 | // register local NSPR file types |
||
429 | if (!DummyPRFileDesc_GlobalInit()) { |
||
430 | BLog(BLOG_ERROR, "DummyPRFileDesc_GlobalInit failed"); |
||
431 | goto fail01; |
||
432 | } |
||
433 | if (!BSSLConnection_GlobalInit()) { |
||
434 | BLog(BLOG_ERROR, "BSSLConnection_GlobalInit failed"); |
||
435 | goto fail01; |
||
436 | } |
||
437 | |||
438 | // init NSS |
||
439 | if (NSS_Init(options.nssdb) != SECSuccess) { |
||
440 | BLog(BLOG_ERROR, "NSS_Init failed (%d)", (int)PR_GetError()); |
||
441 | goto fail01; |
||
442 | } |
||
443 | |||
444 | // set cipher policy |
||
445 | if (NSS_SetDomesticPolicy() != SECSuccess) { |
||
446 | BLog(BLOG_ERROR, "NSS_SetDomesticPolicy failed (%d)", (int)PR_GetError()); |
||
447 | goto fail02; |
||
448 | } |
||
449 | |||
450 | // init server cache |
||
451 | if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL) != SECSuccess) { |
||
452 | BLog(BLOG_ERROR, "SSL_ConfigServerSessionIDCache failed (%d)", (int)PR_GetError()); |
||
453 | goto fail02; |
||
454 | } |
||
455 | |||
456 | // open server certificate and private key |
||
457 | if (!open_nss_cert_and_key(options.client_cert_name, &client_cert, &client_key)) { |
||
458 | BLog(BLOG_ERROR, "Cannot open certificate and key"); |
||
459 | goto fail03; |
||
460 | } |
||
461 | } |
||
462 | |||
463 | // initialize network |
||
464 | if (!BNetwork_GlobalInit()) { |
||
465 | BLog(BLOG_ERROR, "BNetwork_GlobalInit failed"); |
||
466 | goto fail1; |
||
467 | } |
||
468 | |||
469 | // init time |
||
470 | BTime_Init(); |
||
471 | |||
472 | // process arguments |
||
473 | if (!process_arguments()) { |
||
474 | BLog(BLOG_ERROR, "Failed to process arguments"); |
||
475 | goto fail1; |
||
476 | } |
||
477 | |||
478 | // init reactor |
||
479 | if (!BReactor_Init(&ss)) { |
||
480 | BLog(BLOG_ERROR, "BReactor_Init failed"); |
||
481 | goto fail1; |
||
482 | } |
||
483 | |||
484 | // setup signal handler |
||
485 | if (!BSignal_Init(&ss, signal_handler, NULL)) { |
||
486 | BLog(BLOG_ERROR, "BSignal_Init failed"); |
||
487 | goto fail2; |
||
488 | } |
||
489 | |||
490 | // init thread work dispatcher |
||
491 | if (!BThreadWorkDispatcher_Init(&twd, &ss, options.threads)) { |
||
492 | BLog(BLOG_ERROR, "BThreadWorkDispatcher_Init failed"); |
||
493 | goto fail3; |
||
494 | } |
||
495 | |||
496 | // init BSecurity |
||
497 | if (BThreadWorkDispatcher_UsingThreads(&twd)) { |
||
498 | if (!BSecurity_GlobalInitThreadSafe()) { |
||
499 | BLog(BLOG_ERROR, "BSecurity_GlobalInitThreadSafe failed"); |
||
500 | goto fail4; |
||
501 | } |
||
502 | } |
||
503 | |||
504 | // init listeners |
||
505 | int num_listeners = 0; |
||
506 | if (options.transport_mode == TRANSPORT_MODE_TCP) { |
||
507 | while (num_listeners < num_bind_addrs) { |
||
508 | struct bind_addr *addr = &bind_addrs[num_listeners]; |
||
509 | if (!PasswordListener_Init(&listeners[num_listeners], &ss, &twd, addr->addr, TCP_MAX_PASSWORD_LISTENER_CLIENTS, options.peer_ssl, ssl_flags(), client_cert, client_key)) { |
||
510 | BLog(BLOG_ERROR, "PasswordListener_Init failed"); |
||
511 | goto fail8; |
||
512 | } |
||
513 | num_listeners++; |
||
514 | } |
||
515 | } |
||
516 | |||
517 | // init device |
||
518 | if (!BTap_Init(&device, &ss, options.tapdev, device_error_handler, NULL, 0)) { |
||
519 | BLog(BLOG_ERROR, "BTap_Init failed"); |
||
520 | goto fail8; |
||
521 | } |
||
522 | |||
523 | // remember device MTU |
||
524 | device_mtu = BTap_GetMTU(&device); |
||
525 | |||
526 | BLog(BLOG_INFO, "device MTU is %d", device_mtu); |
||
527 | |||
528 | // calculate data MTU |
||
529 | if (device_mtu > INT_MAX - DATAPROTO_MAX_OVERHEAD) { |
||
530 | BLog(BLOG_ERROR, "Device MTU is too large"); |
||
531 | goto fail9; |
||
532 | } |
||
533 | data_mtu = DATAPROTO_MAX_OVERHEAD + device_mtu; |
||
534 | |||
535 | // init device input |
||
536 | if (!DataProtoSource_Init(&device_dpsource, BTap_GetOutput(&device), device_dpsource_handler, NULL, &ss)) { |
||
537 | BLog(BLOG_ERROR, "DataProtoSource_Init failed"); |
||
538 | goto fail9; |
||
539 | } |
||
540 | |||
541 | // init device output |
||
542 | if (!DPReceiveDevice_Init(&device_output_dprd, device_mtu, (DPReceiveDevice_output_func)BTap_Send, &device, &ss, options.send_buffer_relay_size, PEER_RELAY_FLOW_INACTIVITY_TIME)) { |
||
543 | BLog(BLOG_ERROR, "DPReceiveDevice_Init failed"); |
||
544 | goto fail10; |
||
545 | } |
||
546 | |||
547 | // init peers list |
||
548 | LinkedList1_Init(&peers); |
||
549 | num_peers = 0; |
||
550 | |||
551 | // init frame decider |
||
552 | FrameDecider_Init(&frame_decider, options.max_macs, options.max_groups, options.igmp_group_membership_interval, options.igmp_last_member_query_time, &ss); |
||
553 | |||
554 | // init relays list |
||
555 | LinkedList1_Init(&relays); |
||
556 | |||
557 | // init need relay list |
||
558 | LinkedList1_Init(&waiting_relay_peers); |
||
559 | |||
560 | // start connecting to server |
||
561 | if (!ServerConnection_Init(&server, &ss, &twd, server_addr, SC_KEEPALIVE_INTERVAL, SERVER_BUFFER_MIN_PACKETS, options.ssl, ssl_flags(), client_cert, client_key, server_name, NULL, |
||
562 | server_handler_error, server_handler_ready, server_handler_newclient, server_handler_endclient, server_handler_message |
||
563 | )) { |
||
564 | BLog(BLOG_ERROR, "ServerConnection_Init failed"); |
||
565 | goto fail11; |
||
566 | } |
||
567 | |||
568 | // set server not ready |
||
569 | server_ready = 0; |
||
570 | |||
571 | // set no dying flow |
||
572 | dying_server_flow = NULL; |
||
573 | |||
574 | // enter event loop |
||
575 | BLog(BLOG_NOTICE, "entering event loop"); |
||
576 | BReactor_Exec(&ss); |
||
577 | |||
578 | if (server_ready) { |
||
579 | // allow freeing server queue flows |
||
580 | PacketPassFairQueue_PrepareFree(&server_queue); |
||
581 | |||
582 | // make ServerConnection stop using buffers from peers before they are freed |
||
583 | ServerConnection_ReleaseBuffers(&server); |
||
584 | } |
||
585 | |||
586 | // free peers |
||
587 | LinkedList1Node *node; |
||
588 | while (node = LinkedList1_GetFirst(&peers)) { |
||
589 | struct peer_data *peer = UPPER_OBJECT(node, struct peer_data, list_node); |
||
590 | peer_remove(peer, 1); |
||
591 | } |
||
592 | |||
593 | // free dying server flow |
||
594 | if (dying_server_flow) { |
||
595 | server_flow_free(dying_server_flow); |
||
596 | } |
||
597 | |||
598 | if (server_ready) { |
||
599 | PacketPassFairQueue_Free(&server_queue); |
||
600 | } |
||
601 | ServerConnection_Free(&server); |
||
602 | fail11: |
||
603 | FrameDecider_Free(&frame_decider); |
||
604 | DPReceiveDevice_Free(&device_output_dprd); |
||
605 | fail10: |
||
606 | DataProtoSource_Free(&device_dpsource); |
||
607 | fail9: |
||
608 | BTap_Free(&device); |
||
609 | fail8: |
||
610 | if (options.transport_mode == TRANSPORT_MODE_TCP) { |
||
611 | while (num_listeners-- > 0) { |
||
612 | PasswordListener_Free(&listeners[num_listeners]); |
||
613 | } |
||
614 | } |
||
615 | if (BThreadWorkDispatcher_UsingThreads(&twd)) { |
||
616 | BSecurity_GlobalFreeThreadSafe(); |
||
617 | } |
||
618 | fail4: |
||
619 | // NOTE: BThreadWorkDispatcher must be freed before NSPR and stuff |
||
620 | BThreadWorkDispatcher_Free(&twd); |
||
621 | fail3: |
||
622 | BSignal_Finish(); |
||
623 | fail2: |
||
624 | BReactor_Free(&ss); |
||
625 | fail1: |
||
626 | if (options.ssl) { |
||
627 | CERT_DestroyCertificate(client_cert); |
||
628 | SECKEY_DestroyPrivateKey(client_key); |
||
629 | fail03: |
||
630 | ASSERT_FORCE(SSL_ShutdownServerSessionIDCache() == SECSuccess) |
||
631 | fail02: |
||
632 | SSL_ClearSessionCache(); |
||
633 | ASSERT_FORCE(NSS_Shutdown() == SECSuccess) |
||
634 | fail01: |
||
635 | ASSERT_FORCE(PR_Cleanup() == PR_SUCCESS) |
||
636 | PL_ArenaFinish(); |
||
637 | } |
||
638 | BLog(BLOG_NOTICE, "exiting"); |
||
639 | BLog_Free(); |
||
640 | fail0: |
||
641 | // finish objects |
||
642 | DebugObjectGlobal_Finish(); |
||
643 | return 1; |
||
644 | } |
||
645 | |||
646 | void terminate (void) |
||
647 | { |
||
648 | BLog(BLOG_NOTICE, "tearing down"); |
||
649 | |||
650 | // exit event loop |
||
651 | BReactor_Quit(&ss, 0); |
||
652 | } |
||
653 | |||
654 | void print_help (const char *name) |
||
655 | { |
||
656 | printf( |
||
657 | "Usage:\n" |
||
658 | " %s\n" |
||
659 | " [--help]\n" |
||
660 | " [--version]\n" |
||
661 | " [--logger <"LOGGERS_STRING">]\n" |
||
662 | #ifndef BADVPN_USE_WINAPI |
||
663 | " (logger=syslog?\n" |
||
664 | " [--syslog-facility <string>]\n" |
||
665 | " [--syslog-ident <string>]\n" |
||
666 | " )\n" |
||
667 | #endif |
||
668 | " [--loglevel <0-5/none/error/warning/notice/info/debug>]\n" |
||
669 | " [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n" |
||
670 | " [--threads <integer>]\n" |
||
671 | " [--use-threads-for-ssl-handshake]\n" |
||
672 | " [--use-threads-for-ssl-data]\n" |
||
673 | " [--ssl --nssdb <string> --client-cert-name <string>]\n" |
||
674 | " [--server-name <string>]\n" |
||
675 | " --server-addr <addr>\n" |
||
676 | " [--tapdev <name>]\n" |
||
677 | " [--scope <scope_name>] ...\n" |
||
678 | " [\n" |
||
679 | " --bind-addr <addr>\n" |
||
680 | " (transport-mode=udp? --num-ports <num>)\n" |
||
681 | " [--ext-addr <addr / {server_reported}:port> <scope_name>] ...\n" |
||
682 | " ] ...\n" |
||
683 | " --transport-mode <udp/tcp>\n" |
||
684 | " (transport-mode=udp?\n" |
||
685 | " --encryption-mode <blowfish/aes/none>\n" |
||
686 | " --hash-mode <md5/sha1/none>\n" |
||
687 | " [--otp <blowfish/aes> <num> <num-warn>]\n" |
||
688 | " [--fragmentation-latency <milliseconds>]\n" |
||
689 | " )\n" |
||
690 | " (transport-mode=tcp?\n" |
||
691 | " (ssl? [--peer-ssl])\n" |
||
692 | " [--peer-tcp-socket-sndbuf <bytes / 0>]\n" |
||
693 | " )\n" |
||
694 | " [--send-buffer-size <num-packets>]\n" |
||
695 | " [--send-buffer-relay-size <num-packets>]\n" |
||
696 | " [--max-macs <num>]\n" |
||
697 | " [--max-groups <num>]\n" |
||
698 | " [--igmp-group-membership-interval <ms>]\n" |
||
699 | " [--igmp-last-member-query-time <ms>]\n" |
||
700 | " [--allow-peer-talk-without-ssl]\n" |
||
701 | " [--max-peers <number>]\n" |
||
702 | "Address format is a.b.c.d:port (IPv4) or [addr]:port (IPv6).\n", |
||
703 | name |
||
704 | ); |
||
705 | } |
||
706 | |||
707 | void print_version (void) |
||
708 | { |
||
709 | printf(GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION"\n"GLOBAL_COPYRIGHT_NOTICE"\n"); |
||
710 | } |
||
711 | |||
712 | int parse_arguments (int argc, char *argv[]) |
||
713 | { |
||
714 | if (argc <= 0) { |
||
715 | return 0; |
||
716 | } |
||
717 | |||
718 | options.help = 0; |
||
719 | options.version = 0; |
||
720 | options.logger = LOGGER_STDOUT; |
||
721 | #ifndef BADVPN_USE_WINAPI |
||
722 | options.logger_syslog_facility = "daemon"; |
||
723 | options.logger_syslog_ident = argv[0]; |
||
724 | #endif |
||
725 | options.loglevel = -1; |
||
726 | for (int i = 0; i < BLOG_NUM_CHANNELS; i++) { |
||
727 | options.loglevels[i] = -1; |
||
728 | } |
||
729 | options.threads = 0; |
||
730 | options.use_threads_for_ssl_handshake = 0; |
||
731 | options.use_threads_for_ssl_data = 0; |
||
732 | options.ssl = 0; |
||
733 | options.nssdb = NULL; |
||
734 | options.client_cert_name = NULL; |
||
735 | options.server_name = NULL; |
||
736 | options.server_addr = NULL; |
||
737 | options.tapdev = NULL; |
||
738 | options.num_scopes = 0; |
||
739 | options.num_bind_addrs = 0; |
||
740 | options.transport_mode = -1; |
||
741 | options.encryption_mode = -1; |
||
742 | options.hash_mode = -1; |
||
743 | options.otp_mode = SPPROTO_OTP_MODE_NONE; |
||
744 | options.fragmentation_latency = PEER_DEFAULT_UDP_FRAGMENTATION_LATENCY; |
||
745 | options.peer_ssl = 0; |
||
746 | options.peer_tcp_socket_sndbuf = -1; |
||
747 | options.send_buffer_size = PEER_DEFAULT_SEND_BUFFER_SIZE; |
||
748 | options.send_buffer_relay_size = PEER_DEFAULT_SEND_BUFFER_RELAY_SIZE; |
||
749 | options.max_macs = PEER_DEFAULT_MAX_MACS; |
||
750 | options.max_groups = PEER_DEFAULT_MAX_GROUPS; |
||
751 | options.igmp_group_membership_interval = DEFAULT_IGMP_GROUP_MEMBERSHIP_INTERVAL; |
||
752 | options.igmp_last_member_query_time = DEFAULT_IGMP_LAST_MEMBER_QUERY_TIME; |
||
753 | options.allow_peer_talk_without_ssl = 0; |
||
754 | options.max_peers = DEFAULT_MAX_PEERS; |
||
755 | |||
756 | int have_fragmentation_latency = 0; |
||
757 | |||
758 | int i; |
||
759 | for (i = 1; i < argc; i++) { |
||
760 | char *arg = argv[i]; |
||
761 | if (!strcmp(arg, "--help")) { |
||
762 | options.help = 1; |
||
763 | } |
||
764 | else if (!strcmp(arg, "--version")) { |
||
765 | options.version = 1; |
||
766 | } |
||
767 | else if (!strcmp(arg, "--logger")) { |
||
768 | if (1 >= argc - i) { |
||
769 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
770 | return 0; |
||
771 | } |
||
772 | char *arg2 = argv[i + 1]; |
||
773 | if (!strcmp(arg2, "stdout")) { |
||
774 | options.logger = LOGGER_STDOUT; |
||
775 | } |
||
776 | #ifndef BADVPN_USE_WINAPI |
||
777 | else if (!strcmp(arg2, "syslog")) { |
||
778 | options.logger = LOGGER_SYSLOG; |
||
779 | } |
||
780 | #endif |
||
781 | else { |
||
782 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
783 | return 0; |
||
784 | } |
||
785 | i++; |
||
786 | } |
||
787 | #ifndef BADVPN_USE_WINAPI |
||
788 | else if (!strcmp(arg, "--syslog-facility")) { |
||
789 | if (1 >= argc - i) { |
||
790 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
791 | return 0; |
||
792 | } |
||
793 | options.logger_syslog_facility = argv[i + 1]; |
||
794 | i++; |
||
795 | } |
||
796 | else if (!strcmp(arg, "--syslog-ident")) { |
||
797 | if (1 >= argc - i) { |
||
798 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
799 | return 0; |
||
800 | } |
||
801 | options.logger_syslog_ident = argv[i + 1]; |
||
802 | i++; |
||
803 | } |
||
804 | #endif |
||
805 | else if (!strcmp(arg, "--loglevel")) { |
||
806 | if (1 >= argc - i) { |
||
807 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
808 | return 0; |
||
809 | } |
||
810 | if ((options.loglevel = parse_loglevel(argv[i + 1])) < 0) { |
||
811 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
812 | return 0; |
||
813 | } |
||
814 | i++; |
||
815 | } |
||
816 | else if (!strcmp(arg, "--channel-loglevel")) { |
||
817 | if (2 >= argc - i) { |
||
818 | fprintf(stderr, "%s: requires two arguments\n", arg); |
||
819 | return 0; |
||
820 | } |
||
821 | int channel = BLogGlobal_GetChannelByName(argv[i + 1]); |
||
822 | if (channel < 0) { |
||
823 | fprintf(stderr, "%s: wrong channel argument\n", arg); |
||
824 | return 0; |
||
825 | } |
||
826 | int loglevel = parse_loglevel(argv[i + 2]); |
||
827 | if (loglevel < 0) { |
||
828 | fprintf(stderr, "%s: wrong loglevel argument\n", arg); |
||
829 | return 0; |
||
830 | } |
||
831 | options.loglevels[channel] = loglevel; |
||
832 | i += 2; |
||
833 | } |
||
834 | else if (!strcmp(arg, "--threads")) { |
||
835 | if (1 >= argc - i) { |
||
836 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
837 | return 0; |
||
838 | } |
||
839 | options.threads = atoi(argv[i + 1]); |
||
840 | i++; |
||
841 | } |
||
842 | else if (!strcmp(arg, "--use-threads-for-ssl-handshake")) { |
||
843 | options.use_threads_for_ssl_handshake = 1; |
||
844 | } |
||
845 | else if (!strcmp(arg, "--use-threads-for-ssl-data")) { |
||
846 | options.use_threads_for_ssl_data = 1; |
||
847 | } |
||
848 | else if (!strcmp(arg, "--ssl")) { |
||
849 | options.ssl = 1; |
||
850 | } |
||
851 | else if (!strcmp(arg, "--nssdb")) { |
||
852 | if (1 >= argc - i) { |
||
853 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
854 | return 0; |
||
855 | } |
||
856 | options.nssdb = argv[i + 1]; |
||
857 | i++; |
||
858 | } |
||
859 | else if (!strcmp(arg, "--client-cert-name")) { |
||
860 | if (1 >= argc - i) { |
||
861 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
862 | return 0; |
||
863 | } |
||
864 | options.client_cert_name = argv[i + 1]; |
||
865 | i++; |
||
866 | } |
||
867 | else if (!strcmp(arg, "--server-name")) { |
||
868 | if (1 >= argc - i) { |
||
869 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
870 | return 0; |
||
871 | } |
||
872 | options.server_name = argv[i + 1]; |
||
873 | i++; |
||
874 | } |
||
875 | else if (!strcmp(arg, "--server-addr")) { |
||
876 | if (1 >= argc - i) { |
||
877 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
878 | return 0; |
||
879 | } |
||
880 | options.server_addr = argv[i + 1]; |
||
881 | i++; |
||
882 | } |
||
883 | else if (!strcmp(arg, "--tapdev")) { |
||
884 | if (1 >= argc - i) { |
||
885 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
886 | return 0; |
||
887 | } |
||
888 | options.tapdev = argv[i + 1]; |
||
889 | i++; |
||
890 | } |
||
891 | else if (!strcmp(arg, "--scope")) { |
||
892 | if (1 >= argc - i) { |
||
893 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
894 | return 0; |
||
895 | } |
||
896 | if (options.num_scopes == MAX_SCOPES) { |
||
897 | fprintf(stderr, "%s: too many\n", arg); |
||
898 | return 0; |
||
899 | } |
||
900 | options.scopes[options.num_scopes] = argv[i + 1]; |
||
901 | options.num_scopes++; |
||
902 | i++; |
||
903 | } |
||
904 | else if (!strcmp(arg, "--bind-addr")) { |
||
905 | if (1 >= argc - i) { |
||
906 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
907 | return 0; |
||
908 | } |
||
909 | if (options.num_bind_addrs == MAX_BIND_ADDRS) { |
||
910 | fprintf(stderr, "%s: too many\n", arg); |
||
911 | return 0; |
||
912 | } |
||
913 | struct bind_addr_option *addr = &options.bind_addrs[options.num_bind_addrs]; |
||
914 | addr->addr = argv[i + 1]; |
||
915 | addr->num_ports = -1; |
||
916 | addr->num_ext_addrs = 0; |
||
917 | options.num_bind_addrs++; |
||
918 | i++; |
||
919 | } |
||
920 | else if (!strcmp(arg, "--num-ports")) { |
||
921 | if (1 >= argc - i) { |
||
922 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
923 | return 0; |
||
924 | } |
||
925 | if (options.num_bind_addrs == 0) { |
||
926 | fprintf(stderr, "%s: must folow --bind-addr\n", arg); |
||
927 | return 0; |
||
928 | } |
||
929 | struct bind_addr_option *addr = &options.bind_addrs[options.num_bind_addrs - 1]; |
||
930 | if ((addr->num_ports = atoi(argv[i + 1])) < 0) { |
||
931 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
932 | return 0; |
||
933 | } |
||
934 | i++; |
||
935 | } |
||
936 | else if (!strcmp(arg, "--ext-addr")) { |
||
937 | if (2 >= argc - i) { |
||
938 | fprintf(stderr, "%s: requires two arguments\n", arg); |
||
939 | return 0; |
||
940 | } |
||
941 | if (options.num_bind_addrs == 0) { |
||
942 | fprintf(stderr, "%s: must folow --bind-addr\n", arg); |
||
943 | return 0; |
||
944 | } |
||
945 | struct bind_addr_option *addr = &options.bind_addrs[options.num_bind_addrs - 1]; |
||
946 | if (addr->num_ext_addrs == MAX_EXT_ADDRS) { |
||
947 | fprintf(stderr, "%s: too many\n", arg); |
||
948 | return 0; |
||
949 | } |
||
950 | struct ext_addr_option *eaddr = &addr->ext_addrs[addr->num_ext_addrs]; |
||
951 | eaddr->addr = argv[i + 1]; |
||
952 | eaddr->scope = argv[i + 2]; |
||
953 | addr->num_ext_addrs++; |
||
954 | i += 2; |
||
955 | } |
||
956 | else if (!strcmp(arg, "--transport-mode")) { |
||
957 | if (1 >= argc - i) { |
||
958 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
959 | return 0; |
||
960 | } |
||
961 | char *arg2 = argv[i + 1]; |
||
962 | if (!strcmp(arg2, "udp")) { |
||
963 | options.transport_mode = TRANSPORT_MODE_UDP; |
||
964 | } |
||
965 | else if (!strcmp(arg2, "tcp")) { |
||
966 | options.transport_mode = TRANSPORT_MODE_TCP; |
||
967 | } |
||
968 | else { |
||
969 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
970 | return 0; |
||
971 | } |
||
972 | i++; |
||
973 | } |
||
974 | else if (!strcmp(arg, "--encryption-mode")) { |
||
975 | if (1 >= argc - i) { |
||
976 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
977 | return 0; |
||
978 | } |
||
979 | char *arg2 = argv[i + 1]; |
||
980 | if (!strcmp(arg2, "none")) { |
||
981 | options.encryption_mode = SPPROTO_ENCRYPTION_MODE_NONE; |
||
982 | } |
||
983 | else if (!strcmp(arg2, "blowfish")) { |
||
984 | options.encryption_mode = BENCRYPTION_CIPHER_BLOWFISH; |
||
985 | } |
||
986 | else if (!strcmp(arg2, "aes")) { |
||
987 | options.encryption_mode = BENCRYPTION_CIPHER_AES; |
||
988 | } |
||
989 | else { |
||
990 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
991 | return 0; |
||
992 | } |
||
993 | i++; |
||
994 | } |
||
995 | else if (!strcmp(arg, "--hash-mode")) { |
||
996 | if (1 >= argc - i) { |
||
997 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
998 | return 0; |
||
999 | } |
||
1000 | char *arg2 = argv[i + 1]; |
||
1001 | if (!strcmp(arg2, "none")) { |
||
1002 | options.hash_mode = SPPROTO_HASH_MODE_NONE; |
||
1003 | } |
||
1004 | else if (!strcmp(arg2, "md5")) { |
||
1005 | options.hash_mode = BHASH_TYPE_MD5; |
||
1006 | } |
||
1007 | else if (!strcmp(arg2, "sha1")) { |
||
1008 | options.hash_mode = BHASH_TYPE_SHA1; |
||
1009 | } |
||
1010 | else { |
||
1011 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
1012 | return 0; |
||
1013 | } |
||
1014 | i++; |
||
1015 | } |
||
1016 | else if (!strcmp(arg, "--otp")) { |
||
1017 | if (3 >= argc - i) { |
||
1018 | fprintf(stderr, "%s: requires three arguments\n", arg); |
||
1019 | return 0; |
||
1020 | } |
||
1021 | char *otp_mode = argv[i + 1]; |
||
1022 | char *otp_num = argv[i + 2]; |
||
1023 | char *otp_num_warn = argv[i + 3]; |
||
1024 | if (!strcmp(otp_mode, "blowfish")) { |
||
1025 | options.otp_mode = BENCRYPTION_CIPHER_BLOWFISH; |
||
1026 | } |
||
1027 | else if (!strcmp(otp_mode, "aes")) { |
||
1028 | options.otp_mode = BENCRYPTION_CIPHER_AES; |
||
1029 | } |
||
1030 | else { |
||
1031 | fprintf(stderr, "%s: wrong mode\n", arg); |
||
1032 | return 0; |
||
1033 | } |
||
1034 | if ((options.otp_num = atoi(otp_num)) <= 0) { |
||
1035 | fprintf(stderr, "%s: wrong num\n", arg); |
||
1036 | return 0; |
||
1037 | } |
||
1038 | options.otp_num_warn = atoi(otp_num_warn); |
||
1039 | if (options.otp_num_warn <= 0 || options.otp_num_warn > options.otp_num) { |
||
1040 | fprintf(stderr, "%s: wrong num warn\n", arg); |
||
1041 | return 0; |
||
1042 | } |
||
1043 | i += 3; |
||
1044 | } |
||
1045 | else if (!strcmp(arg, "--fragmentation-latency")) { |
||
1046 | if (1 >= argc - i) { |
||
1047 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
1048 | return 0; |
||
1049 | } |
||
1050 | options.fragmentation_latency = atoi(argv[i + 1]); |
||
1051 | have_fragmentation_latency = 1; |
||
1052 | i++; |
||
1053 | } |
||
1054 | else if (!strcmp(arg, "--peer-ssl")) { |
||
1055 | options.peer_ssl = 1; |
||
1056 | } |
||
1057 | else if (!strcmp(arg, "--peer-tcp-socket-sndbuf")) { |
||
1058 | if (1 >= argc - i) { |
||
1059 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
1060 | return 0; |
||
1061 | } |
||
1062 | if ((options.peer_tcp_socket_sndbuf = atoi(argv[i + 1])) < 0) { |
||
1063 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
1064 | return 0; |
||
1065 | } |
||
1066 | i++; |
||
1067 | } |
||
1068 | else if (!strcmp(arg, "--send-buffer-size")) { |
||
1069 | if (1 >= argc - i) { |
||
1070 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
1071 | return 0; |
||
1072 | } |
||
1073 | if ((options.send_buffer_size = atoi(argv[i + 1])) <= 0) { |
||
1074 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
1075 | return 0; |
||
1076 | } |
||
1077 | i++; |
||
1078 | } |
||
1079 | else if (!strcmp(arg, "--send-buffer-relay-size")) { |
||
1080 | if (1 >= argc - i) { |
||
1081 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
1082 | return 0; |
||
1083 | } |
||
1084 | if ((options.send_buffer_relay_size = atoi(argv[i + 1])) <= 0) { |
||
1085 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
1086 | return 0; |
||
1087 | } |
||
1088 | i++; |
||
1089 | } |
||
1090 | else if (!strcmp(arg, "--max-macs")) { |
||
1091 | if (1 >= argc - i) { |
||
1092 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
1093 | return 0; |
||
1094 | } |
||
1095 | if ((options.max_macs = atoi(argv[i + 1])) <= 0) { |
||
1096 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
1097 | return 0; |
||
1098 | } |
||
1099 | i++; |
||
1100 | } |
||
1101 | else if (!strcmp(arg, "--max-groups")) { |
||
1102 | if (1 >= argc - i) { |
||
1103 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
1104 | return 0; |
||
1105 | } |
||
1106 | if ((options.max_groups = atoi(argv[i + 1])) <= 0) { |
||
1107 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
1108 | return 0; |
||
1109 | } |
||
1110 | i++; |
||
1111 | } |
||
1112 | else if (!strcmp(arg, "--igmp-group-membership-interval")) { |
||
1113 | if (1 >= argc - i) { |
||
1114 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
1115 | return 0; |
||
1116 | } |
||
1117 | if ((options.igmp_group_membership_interval = atoi(argv[i + 1])) <= 0) { |
||
1118 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
1119 | return 0; |
||
1120 | } |
||
1121 | i++; |
||
1122 | } |
||
1123 | else if (!strcmp(arg, "--igmp-last-member-query-time")) { |
||
1124 | if (1 >= argc - i) { |
||
1125 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
1126 | return 0; |
||
1127 | } |
||
1128 | if ((options.igmp_last_member_query_time = atoi(argv[i + 1])) <= 0) { |
||
1129 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
1130 | return 0; |
||
1131 | } |
||
1132 | i++; |
||
1133 | } |
||
1134 | else if (!strcmp(arg, "--max-peers")) { |
||
1135 | if (1 >= argc - i) { |
||
1136 | fprintf(stderr, "%s: requires an argument\n", arg); |
||
1137 | return 0; |
||
1138 | } |
||
1139 | if ((options.max_peers = atoi(argv[i + 1])) <= 0) { |
||
1140 | fprintf(stderr, "%s: wrong argument\n", arg); |
||
1141 | return 0; |
||
1142 | } |
||
1143 | i++; |
||
1144 | } |
||
1145 | else if (!strcmp(arg, "--allow-peer-talk-without-ssl")) { |
||
1146 | options.allow_peer_talk_without_ssl = 1; |
||
1147 | } |
||
1148 | else { |
||
1149 | fprintf(stderr, "unknown option: %s\n", arg); |
||
1150 | return 0; |
||
1151 | } |
||
1152 | } |
||
1153 | |||
1154 | if (options.help || options.version) { |
||
1155 | return 1; |
||
1156 | } |
||
1157 | |||
1158 | if (options.ssl != !!options.nssdb) { |
||
1159 | fprintf(stderr, "False: --ssl <=> --nssdb\n"); |
||
1160 | return 0; |
||
1161 | } |
||
1162 | |||
1163 | if (options.ssl != !!options.client_cert_name) { |
||
1164 | fprintf(stderr, "False: --ssl <=> --client-cert-name\n"); |
||
1165 | return 0; |
||
1166 | } |
||
1167 | |||
1168 | if (!options.server_addr) { |
||
1169 | fprintf(stderr, "False: --server-addr\n"); |
||
1170 | return 0; |
||
1171 | } |
||
1172 | |||
1173 | if (options.transport_mode < 0) { |
||
1174 | fprintf(stderr, "False: --transport-mode\n"); |
||
1175 | return 0; |
||
1176 | } |
||
1177 | |||
1178 | if ((options.transport_mode == TRANSPORT_MODE_UDP) != (options.encryption_mode >= 0)) { |
||
1179 | fprintf(stderr, "False: UDP <=> --encryption-mode\n"); |
||
1180 | return 0; |
||
1181 | } |
||
1182 | |||
1183 | if ((options.transport_mode == TRANSPORT_MODE_UDP) != (options.hash_mode >= 0)) { |
||
1184 | fprintf(stderr, "False: UDP <=> --hash-mode\n"); |
||
1185 | return 0; |
||
1186 | } |
||
1187 | |||
1188 | if (!(!(options.otp_mode != SPPROTO_OTP_MODE_NONE) || (options.transport_mode == TRANSPORT_MODE_UDP))) { |
||
1189 | fprintf(stderr, "False: --otp => UDP\n"); |
||
1190 | return 0; |
||
1191 | } |
||
1192 | |||
1193 | if (!(!have_fragmentation_latency || (options.transport_mode == TRANSPORT_MODE_UDP))) { |
||
1194 | fprintf(stderr, "False: --fragmentation-latency => UDP\n"); |
||
1195 | return 0; |
||
1196 | } |
||
1197 | |||
1198 | if (!(!options.peer_ssl || (options.ssl && options.transport_mode == TRANSPORT_MODE_TCP))) { |
||
1199 | fprintf(stderr, "False: --peer-ssl => (--ssl && TCP)\n"); |
||
1200 | return 0; |
||
1201 | } |
||
1202 | |||
1203 | if (!(!(options.peer_tcp_socket_sndbuf >= 0) || options.transport_mode == TRANSPORT_MODE_TCP)) { |
||
1204 | fprintf(stderr, "False: --peer-tcp-socket-sndbuf => TCP\n"); |
||
1205 | return 0; |
||
1206 | } |
||
1207 | |||
1208 | return 1; |
||
1209 | } |
||
1210 | |||
1211 | int process_arguments (void) |
||
1212 | { |
||
1213 | // resolve server address |
||
1214 | ASSERT(options.server_addr) |
||
1215 | if (!BAddr_Parse(&server_addr, options.server_addr, server_name, sizeof(server_name))) { |
||
1216 | BLog(BLOG_ERROR, "server addr: BAddr_Parse failed"); |
||
1217 | return 0; |
||
1218 | } |
||
1219 | |||
1220 | // override server name if requested |
||
1221 | if (options.server_name) { |
||
1222 | if (strlen(options.server_name) >= sizeof(server_name)) { |
||
1223 | BLog(BLOG_ERROR, "server name: too long"); |
||
1224 | return 0; |
||
1225 | } |
||
1226 | strcpy(server_name, options.server_name); |
||
1227 | } |
||
1228 | |||
1229 | // resolve bind addresses and external addresses |
||
1230 | num_bind_addrs = 0; |
||
1231 | for (int i = 0; i < options.num_bind_addrs; i++) { |
||
1232 | struct bind_addr_option *addr = &options.bind_addrs[i]; |
||
1233 | struct bind_addr *out = &bind_addrs[num_bind_addrs]; |
||
1234 | |||
1235 | // read addr |
||
1236 | if (!BAddr_Parse(&out->addr, addr->addr, NULL, 0)) { |
||
1237 | BLog(BLOG_ERROR, "bind addr: BAddr_Parse failed"); |
||
1238 | return 0; |
||
1239 | } |
||
1240 | |||
1241 | // read num ports |
||
1242 | if (options.transport_mode == TRANSPORT_MODE_UDP) { |
||
1243 | if (addr->num_ports < 0) { |
||
1244 | BLog(BLOG_ERROR, "bind addr: num ports missing"); |
||
1245 | return 0; |
||
1246 | } |
||
1247 | out->num_ports = addr->num_ports; |
||
1248 | } |
||
1249 | else if (addr->num_ports >= 0) { |
||
1250 | BLog(BLOG_ERROR, "bind addr: num ports given, but not using UDP"); |
||
1251 | return 0; |
||
1252 | } |
||
1253 | |||
1254 | // read ext addrs |
||
1255 | out->num_ext_addrs = 0; |
||
1256 | for (int j = 0; j < addr->num_ext_addrs; j++) { |
||
1257 | struct ext_addr_option *eaddr = &addr->ext_addrs[j]; |
||
1258 | struct ext_addr *eout = &out->ext_addrs[out->num_ext_addrs]; |
||
1259 | |||
1260 | // read addr |
||
1261 | if (string_begins_with(eaddr->addr, "{server_reported}:")) { |
||
1262 | char *colon = strstr(eaddr->addr, ":"); |
||
1263 | if ((eout->server_reported_port = atoi(colon + 1)) < 0) { |
||
1264 | BLog(BLOG_ERROR, "ext addr: wrong port"); |
||
1265 | return 0; |
||
1266 | } |
||
1267 | } else { |
||
1268 | eout->server_reported_port = -1; |
||
1269 | if (!BAddr_Parse(&eout->addr, eaddr->addr, NULL, 0)) { |
||
1270 | BLog(BLOG_ERROR, "ext addr: BAddr_Parse failed"); |
||
1271 | return 0; |
||
1272 | } |
||
1273 | if (!addr_supported(eout->addr)) { |
||
1274 | BLog(BLOG_ERROR, "ext addr: addr_supported failed"); |
||
1275 | return 0; |
||
1276 | } |
||
1277 | } |
||
1278 | |||
1279 | // read scope |
||
1280 | if (strlen(eaddr->scope) >= sizeof(eout->scope)) { |
||
1281 | BLog(BLOG_ERROR, "ext addr: too long"); |
||
1282 | return 0; |
||
1283 | } |
||
1284 | strcpy(eout->scope, eaddr->scope); |
||
1285 | |||
1286 | out->num_ext_addrs++; |
||
1287 | } |
||
1288 | |||
1289 | num_bind_addrs++; |
||
1290 | } |
||
1291 | |||
1292 | // initialize SPProto parameters |
||
1293 | if (options.transport_mode == TRANSPORT_MODE_UDP) { |
||
1294 | sp_params.encryption_mode = options.encryption_mode; |
||
1295 | sp_params.hash_mode = options.hash_mode; |
||
1296 | sp_params.otp_mode = options.otp_mode; |
||
1297 | if (options.otp_mode > 0) { |
||
1298 | sp_params.otp_num = options.otp_num; |
||
1299 | } |
||
1300 | } |
||
1301 | |||
1302 | return 1; |
||
1303 | } |
||
1304 | |||
1305 | int ssl_flags (void) |
||
1306 | { |
||
1307 | int flags = 0; |
||
1308 | if (options.use_threads_for_ssl_handshake) { |
||
1309 | flags |= BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE; |
||
1310 | } |
||
1311 | if (options.use_threads_for_ssl_data) { |
||
1312 | flags |= BSSLCONNECTION_FLAG_THREADWORK_IO; |
||
1313 | } |
||
1314 | return flags; |
||
1315 | } |
||
1316 | |||
1317 | void signal_handler (void *unused) |
||
1318 | { |
||
1319 | BLog(BLOG_NOTICE, "termination requested"); |
||
1320 | |||
1321 | terminate(); |
||
1322 | } |
||
1323 | |||
1324 | void peer_add (peerid_t id, int flags, const uint8_t *cert, int cert_len) |
||
1325 | { |
||
1326 | ASSERT(server_ready) |
||
1327 | ASSERT(num_peers < options.max_peers) |
||
1328 | ASSERT(!find_peer_by_id(id)) |
||
1329 | ASSERT(id != my_id) |
||
1330 | ASSERT(cert_len >= 0) |
||
1331 | ASSERT(cert_len <= SCID_NEWCLIENT_MAX_CERT_LEN) |
||
1332 | |||
1333 | // allocate structure |
||
1334 | struct peer_data *peer = (struct peer_data *)malloc(sizeof(*peer)); |
||
1335 | if (!peer) { |
||
1336 | BLog(BLOG_ERROR, "peer %d: failed to allocate memory", (int)id); |
||
1337 | goto fail0; |
||
1338 | } |
||
1339 | |||
1340 | // remember id |
||
1341 | peer->id = id; |
||
1342 | |||
1343 | // remember flags |
||
1344 | peer->flags = flags; |
||
1345 | |||
1346 | // set no common name |
||
1347 | peer->common_name = NULL; |
||
1348 | |||
1349 | if (options.ssl) { |
||
1350 | // remember certificate |
||
1351 | memcpy(peer->cert, cert, cert_len); |
||
1352 | peer->cert_len = cert_len; |
||
1353 | |||
1354 | // make sure that CERT_DecodeCertFromPackage will interpretet the input as raw DER and not base64, |
||
1355 | // in which case following workaroud wouldn't help |
||
1356 | if (!(cert_len > 0 && (cert[0] & 0x1f) == 0x10)) { |
||
1357 | peer_log(peer, BLOG_ERROR, "certificate does not look like DER"); |
||
1358 | goto fail1; |
||
1359 | } |
||
1360 | |||
1361 | // copy the certificate and append it a good load of zero bytes, |
||
1362 | // hopefully preventing the crappy CERT_DecodeCertFromPackage from crashing |
||
1363 | // by reading past the of its input |
||
1364 | uint8_t *certbuf = (uint8_t *)malloc(cert_len + 100); |
||
1365 | if (!certbuf) { |
||
1366 | peer_log(peer, BLOG_ERROR, "malloc failed"); |
||
1367 | goto fail1; |
||
1368 | } |
||
1369 | memcpy(certbuf, cert, cert_len); |
||
1370 | memset(certbuf + cert_len, 0, 100); |
||
1371 | |||
1372 | // decode certificate, so we can extract the common name |
||
1373 | CERTCertificate *nsscert = CERT_DecodeCertFromPackage((char *)certbuf, cert_len); |
||
1374 | if (!nsscert) { |
||
1375 | peer_log(peer, BLOG_ERROR, "CERT_DecodeCertFromPackage failed (%d)", PORT_GetError()); |
||
1376 | free(certbuf); |
||
1377 | goto fail1; |
||
1378 | } |
||
1379 | |||
1380 | free(certbuf); |
||
1381 | |||
1382 | // remember common name |
||
1383 | if (!(peer->common_name = CERT_GetCommonName(&nsscert->subject))) { |
||
1384 | peer_log(peer, BLOG_ERROR, "CERT_GetCommonName failed"); |
||
1385 | CERT_DestroyCertificate(nsscert); |
||
1386 | goto fail1; |
||
1387 | } |
||
1388 | |||
1389 | CERT_DestroyCertificate(nsscert); |
||
1390 | } |
||
1391 | |||
1392 | // init and set init job (must be before initing server flow so we can send) |
||
1393 | BPending_Init(&peer->job_init, BReactor_PendingGroup(&ss), (BPending_handler)peer_job_init, peer); |
||
1394 | BPending_Set(&peer->job_init); |
||
1395 | |||
1396 | // init server flow |
||
1397 | if (!(peer->server_flow = server_flow_init())) { |
||
1398 | peer_log(peer, BLOG_ERROR, "server_flow_init failed"); |
||
1399 | goto fail2; |
||
1400 | } |
||
1401 | |||
1402 | if ((peer->flags & SCID_NEWCLIENT_FLAG_SSL) && !options.ssl) { |
||
1403 | peer_log(peer, BLOG_ERROR, "peer requires talking with SSL, but we're not using SSL!?"); |
||
1404 | goto fail3; |
||
1405 | } |
||
1406 | |||
1407 | if (options.ssl && !(peer->flags & SCID_NEWCLIENT_FLAG_SSL) && !options.allow_peer_talk_without_ssl) { |
||
1408 | peer_log(peer, BLOG_ERROR, "peer requires talking without SSL, but we don't allow that"); |
||
1409 | goto fail3; |
||
1410 | } |
||
1411 | |||
1412 | // choose chat SSL mode |
||
1413 | int chat_ssl_mode = PEERCHAT_SSL_NONE; |
||
1414 | if ((peer->flags & SCID_NEWCLIENT_FLAG_SSL)) { |
||
1415 | chat_ssl_mode = (peer_am_master(peer) ? PEERCHAT_SSL_SERVER : PEERCHAT_SSL_CLIENT); |
||
1416 | } |
||
1417 | |||
1418 | // init chat |
||
1419 | if (!PeerChat_Init(&peer->chat, peer->id, chat_ssl_mode, ssl_flags(), client_cert, client_key, peer->cert, peer->cert_len, BReactor_PendingGroup(&ss), &twd, peer, |
||
1420 | (BLog_logfunc)peer_logfunc, |
||
1421 | (PeerChat_handler_error)peer_chat_handler_error, |
||
1422 | (PeerChat_handler_message)peer_chat_handler_message |
||
1423 | )) { |
||
1424 | peer_log(peer, BLOG_ERROR, "PeerChat_Init failed"); |
||
1425 | goto fail3; |
||
1426 | } |
||
1427 | |||
1428 | // set no message |
||
1429 | peer->chat_send_msg_len = -1; |
||
1430 | |||
1431 | // connect server flow to chat |
||
1432 | server_flow_connect(peer->server_flow, PeerChat_GetSendOutput(&peer->chat)); |
||
1433 | |||
1434 | // set have chat |
||
1435 | peer->have_chat = 1; |
||
1436 | |||
1437 | // set have no resetpeer |
||
1438 | peer->have_resetpeer = 0; |
||
1439 | |||
1440 | // init local flow |
||
1441 | if (!DataProtoFlow_Init(&peer->local_dpflow, &device_dpsource, my_id, peer->id, options.send_buffer_size, -1, NULL, NULL)) { |
||
1442 | peer_log(peer, BLOG_ERROR, "DataProtoFlow_Init failed"); |
||
1443 | goto fail4; |
||
1444 | } |
||
1445 | |||
1446 | // init frame decider peer |
||
1447 | if (!FrameDeciderPeer_Init(&peer->decider_peer, &frame_decider, peer, (BLog_logfunc)peer_logfunc)) { |
||
1448 | peer_log(peer, BLOG_ERROR, "FrameDeciderPeer_Init failed"); |
||
1449 | goto fail5; |
||
1450 | } |
||
1451 | |||
1452 | // init receive peer |
||
1453 | DPReceivePeer_Init(&peer->receive_peer, &device_output_dprd, peer->id, &peer->decider_peer, !!(peer->flags & SCID_NEWCLIENT_FLAG_RELAY_CLIENT)); |
||
1454 | |||
1455 | // have no link |
||
1456 | peer->have_link = 0; |
||
1457 | |||
1458 | // have no relaying |
||
1459 | peer->relaying_peer = NULL; |
||
1460 | |||
1461 | // not waiting for relay |
||
1462 | peer->waiting_relay = 0; |
||
1463 | |||
1464 | // init reset timer |
||
1465 | BTimer_Init(&peer->reset_timer, PEER_RETRY_TIME, (BTimer_handler)peer_reset_timer_handler, peer); |
||
1466 | |||
1467 | // is not relay server |
||
1468 | peer->is_relay = 0; |
||
1469 | |||
1470 | // init binding |
||
1471 | peer->binding = 0; |
||
1472 | |||
1473 | // add to peers list |
||
1474 | LinkedList1_Append(&peers, &peer->list_node); |
||
1475 | num_peers++; |
||
1476 | |||
1477 | switch (chat_ssl_mode) { |
||
1478 | case PEERCHAT_SSL_NONE: |
||
1479 | peer_log(peer, BLOG_INFO, "initialized; talking to peer in plaintext mode"); |
||
1480 | break; |
||
1481 | case PEERCHAT_SSL_CLIENT: |
||
1482 | peer_log(peer, BLOG_INFO, "initialized; talking to peer in SSL client mode"); |
||
1483 | break; |
||
1484 | case PEERCHAT_SSL_SERVER: |
||
1485 | peer_log(peer, BLOG_INFO, "initialized; talking to peer in SSL server mode"); |
||
1486 | break; |
||
1487 | } |
||
1488 | |||
1489 | return; |
||
1490 | |||
1491 | fail5: |
||
1492 | DataProtoFlow_Free(&peer->local_dpflow); |
||
1493 | fail4: |
||
1494 | server_flow_disconnect(peer->server_flow); |
||
1495 | PeerChat_Free(&peer->chat); |
||
1496 | fail3: |
||
1497 | server_flow_free(peer->server_flow); |
||
1498 | fail2: |
||
1499 | BPending_Free(&peer->job_init); |
||
1500 | if (peer->common_name) { |
||
1501 | PORT_Free(peer->common_name); |
||
1502 | } |
||
1503 | fail1: |
||
1504 | free(peer); |
||
1505 | fail0: |
||
1506 | return; |
||
1507 | } |
||
1508 | |||
1509 | void peer_remove (struct peer_data *peer, int exiting) |
||
1510 | { |
||
1511 | peer_log(peer, BLOG_INFO, "removing"); |
||
1512 | |||
1513 | // cleanup connections |
||
1514 | peer_cleanup_connections(peer); |
||
1515 | |||
1516 | ASSERT(!peer->have_link) |
||
1517 | ASSERT(!peer->relaying_peer) |
||
1518 | ASSERT(!peer->waiting_relay) |
||
1519 | ASSERT(!peer->is_relay) |
||
1520 | |||
1521 | // remove from peers list |
||
1522 | LinkedList1_Remove(&peers, &peer->list_node); |
||
1523 | num_peers--; |
||
1524 | |||
1525 | // free reset timer |
||
1526 | BReactor_RemoveTimer(&ss, &peer->reset_timer); |
||
1527 | |||
1528 | // free receive peer |
||
1529 | DPReceivePeer_Free(&peer->receive_peer); |
||
1530 | |||
1531 | // free frame decider |
||
1532 | FrameDeciderPeer_Free(&peer->decider_peer); |
||
1533 | |||
1534 | // free local flow |
||
1535 | DataProtoFlow_Free(&peer->local_dpflow); |
||
1536 | |||
1537 | // free chat |
||
1538 | if (peer->have_chat) { |
||
1539 | peer_free_chat(peer); |
||
1540 | } |
||
1541 | |||
1542 | // free resetpeer |
||
1543 | if (peer->have_resetpeer) { |
||
1544 | // disconnect resetpeer source from server flow |
||
1545 | server_flow_disconnect(peer->server_flow); |
||
1546 | |||
1547 | // free resetpeer source |
||
1548 | SinglePacketSource_Free(&peer->resetpeer_source); |
||
1549 | } |
||
1550 | |||
1551 | // free/die server flow |
||
1552 | if (exiting || !PacketPassFairQueueFlow_IsBusy(&peer->server_flow->qflow)) { |
||
1553 | server_flow_free(peer->server_flow); |
||
1554 | } else { |
||
1555 | server_flow_die(peer->server_flow); |
||
1556 | } |
||
1557 | |||
1558 | // free jobs |
||
1559 | BPending_Free(&peer->job_init); |
||
1560 | |||
1561 | // free common name |
||
1562 | if (peer->common_name) { |
||
1563 | PORT_Free(peer->common_name); |
||
1564 | } |
||
1565 | |||
1566 | // free peer structure |
||
1567 | free(peer); |
||
1568 | } |
||
1569 | |||
1570 | void peer_logfunc (struct peer_data *peer) |
||
1571 | { |
||
1572 | BLog_Append("peer %d", (int)peer->id); |
||
1573 | if (peer->common_name) { |
||
1574 | BLog_Append(" (%s)", peer->common_name); |
||
1575 | } |
||
1576 | BLog_Append(": "); |
||
1577 | } |
||
1578 | |||
1579 | void peer_log (struct peer_data *peer, int level, const char *fmt, ...) |
||
1580 | { |
||
1581 | va_list vl; |
||
1582 | va_start(vl, fmt); |
||
1583 | BLog_LogViaFuncVarArg((BLog_logfunc)peer_logfunc, peer, BLOG_CURRENT_CHANNEL, level, fmt, vl); |
||
1584 | va_end(vl); |
||
1585 | } |
||
1586 | |||
1587 | int peer_am_master (struct peer_data *peer) |
||
1588 | { |
||
1589 | return (my_id > peer->id); |
||
1590 | } |
||
1591 | |||
1592 | void peer_free_chat (struct peer_data *peer) |
||
1593 | { |
||
1594 | ASSERT(peer->have_chat) |
||
1595 | |||
1596 | // disconnect chat from server flow |
||
1597 | server_flow_disconnect(peer->server_flow); |
||
1598 | |||
1599 | // free chat |
||
1600 | PeerChat_Free(&peer->chat); |
||
1601 | |||
1602 | // set have no chat |
||
1603 | peer->have_chat = 0; |
||
1604 | } |
||
1605 | |||
1606 | int peer_init_link (struct peer_data *peer) |
||
1607 | { |
||
1608 | ASSERT(!peer->have_link) |
||
1609 | ASSERT(!peer->relaying_peer) |
||
1610 | ASSERT(!peer->waiting_relay) |
||
1611 | |||
1612 | ASSERT(!peer->is_relay) |
||
1613 | |||
1614 | // init receive receiver |
||
1615 | DPReceiveReceiver_Init(&peer->receive_receiver, &peer->receive_peer); |
||
1616 | PacketPassInterface *recv_if = DPReceiveReceiver_GetInput(&peer->receive_receiver); |
||
1617 | |||
1618 | // init transport-specific link objects |
||
1619 | PacketPassInterface *link_if; |
||
1620 | if (options.transport_mode == TRANSPORT_MODE_UDP) { |
||
1621 | // init DatagramPeerIO |
||
1622 | if (!DatagramPeerIO_Init( |
||
1623 | &peer->pio.udp.pio, &ss, data_mtu, CLIENT_UDP_MTU, sp_params, |
||
1624 | options.fragmentation_latency, PEER_UDP_ASSEMBLER_NUM_FRAMES, recv_if, |
||
1625 | options.otp_num_warn, &twd, peer, |
||
1626 | (BLog_logfunc)peer_logfunc, |
||
1627 | (DatagramPeerIO_handler_error)peer_udp_pio_handler_error, |
||
1628 | (DatagramPeerIO_handler_otp_warning)peer_udp_pio_handler_seed_warning, |
||
1629 | (DatagramPeerIO_handler_otp_ready)peer_udp_pio_handler_seed_ready |
||
1630 | )) { |
||
1631 | peer_log(peer, BLOG_ERROR, "DatagramPeerIO_Init failed"); |
||
1632 | goto fail1; |
||
1633 | } |
||
1634 | |||
1635 | if (SPPROTO_HAVE_OTP(sp_params)) { |
||
1636 | // init send seed state |
||
1637 | peer->pio.udp.sendseed_nextid = 0; |
||
1638 | peer->pio.udp.sendseed_sent = 0; |
||
1639 | |||
1640 | // init send seed job |
||
1641 | BPending_Init(&peer->pio.udp.job_send_seed, BReactor_PendingGroup(&ss), (BPending_handler)peer_job_send_seed, peer); |
||
1642 | } |
||
1643 | |||
1644 | link_if = DatagramPeerIO_GetSendInput(&peer->pio.udp.pio); |
||
1645 | } else { |
||
1646 | // init StreamPeerIO |
||
1647 | if (!StreamPeerIO_Init( |
||
1648 | &peer->pio.tcp.pio, &ss, &twd, options.peer_ssl, ssl_flags(), |
||
1649 | (options.peer_ssl ? peer->cert : NULL), |
||
1650 | (options.peer_ssl ? peer->cert_len : -1), |
||
1651 | data_mtu, |
||
1652 | (options.peer_tcp_socket_sndbuf >= 0 ? options.peer_tcp_socket_sndbuf : PEER_DEFAULT_TCP_SOCKET_SNDBUF), |
||
1653 | recv_if, |
||
1654 | (BLog_logfunc)peer_logfunc, |
||
1655 | (StreamPeerIO_handler_error)peer_tcp_pio_handler_error, peer |
||
1656 | )) { |
||
1657 | peer_log(peer, BLOG_ERROR, "StreamPeerIO_Init failed"); |
||
1658 | goto fail1; |
||
1659 | } |
||
1660 | |||
1661 | link_if = StreamPeerIO_GetSendInput(&peer->pio.tcp.pio); |
||
1662 | } |
||
1663 | |||
1664 | // init sending |
||
1665 | if (!DataProtoSink_Init(&peer->send_dp, &ss, link_if, PEER_KEEPALIVE_INTERVAL, PEER_KEEPALIVE_RECEIVE_TIMER, (DataProtoSink_handler)peer_dataproto_handler, peer)) { |
||
1666 | peer_log(peer, BLOG_ERROR, "DataProto_Init failed"); |
||
1667 | goto fail2; |
||
1668 | } |
||
1669 | |||
1670 | // attach local flow to our DataProtoSink |
||
1671 | DataProtoFlow_Attach(&peer->local_dpflow, &peer->send_dp); |
||
1672 | |||
1673 | // attach receive peer to our DataProtoSink |
||
1674 | DPReceivePeer_AttachSink(&peer->receive_peer, &peer->send_dp); |
||
1675 | |||
1676 | // set have link |
||
1677 | peer->have_link = 1; |
||
1678 | |||
1679 | return 1; |
||
1680 | |||
1681 | fail2: |
||
1682 | if (options.transport_mode == TRANSPORT_MODE_UDP) { |
||
1683 | if (SPPROTO_HAVE_OTP(sp_params)) { |
||
1684 | BPending_Free(&peer->pio.udp.job_send_seed); |
||
1685 | } |
||
1686 | DatagramPeerIO_Free(&peer->pio.udp.pio); |
||
1687 | } else { |
||
1688 | StreamPeerIO_Free(&peer->pio.tcp.pio); |
||
1689 | } |
||
1690 | fail1: |
||
1691 | DPReceiveReceiver_Free(&peer->receive_receiver); |
||
1692 | return 0; |
||
1693 | } |
||
1694 | |||
1695 | void peer_free_link (struct peer_data *peer) |
||
1696 | { |
||
1697 | ASSERT(peer->have_link) |
||
1698 | ASSERT(!peer->is_relay) |
||
1699 | |||
1700 | ASSERT(!peer->relaying_peer) |
||
1701 | ASSERT(!peer->waiting_relay) |
||
1702 | |||
1703 | // detach receive peer from our DataProtoSink |
||
1704 | DPReceivePeer_DetachSink(&peer->receive_peer); |
||
1705 | |||
1706 | // detach local flow from our DataProtoSink |
||
1707 | DataProtoFlow_Detach(&peer->local_dpflow); |
||
1708 | |||
1709 | // free sending |
||
1710 | DataProtoSink_Free(&peer->send_dp); |
||
1711 | |||
1712 | // free transport-specific link objects |
||
1713 | if (options.transport_mode == TRANSPORT_MODE_UDP) { |
||
1714 | if (SPPROTO_HAVE_OTP(sp_params)) { |
||
1715 | BPending_Free(&peer->pio.udp.job_send_seed); |
||
1716 | } |
||
1717 | DatagramPeerIO_Free(&peer->pio.udp.pio); |
||
1718 | } else { |
||
1719 | StreamPeerIO_Free(&peer->pio.tcp.pio); |
||
1720 | } |
||
1721 | |||
1722 | // free receive receiver |
||
1723 | DPReceiveReceiver_Free(&peer->receive_receiver); |
||
1724 | |||
1725 | // set have no link |
||
1726 | peer->have_link = 0; |
||
1727 | } |
||
1728 | |||
1729 | void peer_cleanup_connections (struct peer_data *peer) |
||
1730 | { |
||
1731 | if (peer->have_link) { |
||
1732 | if (peer->is_relay) { |
||
1733 | peer_disable_relay_provider(peer); |
||
1734 | } |
||
1735 | peer_free_link(peer); |
||
1736 | } |
||
1737 | else if (peer->relaying_peer) { |
||
1738 | peer_free_relaying(peer); |
||
1739 | } |
||
1740 | else if (peer->waiting_relay) { |
||
1741 | peer_unregister_need_relay(peer); |
||
1742 | } |
||
1743 | |||
1744 | ASSERT(!peer->have_link) |
||
1745 | ASSERT(!peer->relaying_peer) |
||
1746 | ASSERT(!peer->waiting_relay) |
||
1747 | ASSERT(!peer->is_relay) |
||
1748 | } |
||
1749 | |||
1750 | void peer_enable_relay_provider (struct peer_data *peer) |
||
1751 | { |
||
1752 | ASSERT(peer->have_link) |
||
1753 | ASSERT(!peer->is_relay) |
||
1754 | |||
1755 | ASSERT(!peer->relaying_peer) |
||
1756 | ASSERT(!peer->waiting_relay) |
||
1757 | |||
1758 | // add to relays list |
||
1759 | LinkedList1_Append(&relays, &peer->relay_list_node); |
||
1760 | |||
1761 | // init users list |
||
1762 | LinkedList1_Init(&peer->relay_users); |
||
1763 | |||
1764 | // set is relay |
||
1765 | peer->is_relay = 1; |
||
1766 | |||
1767 | // assign relays |
||
1768 | assign_relays(); |
||
1769 | } |
||
1770 | |||
1771 | void peer_disable_relay_provider (struct peer_data *peer) |
||
1772 | { |
||
1773 | ASSERT(peer->is_relay) |
||
1774 | |||
1775 | ASSERT(peer->have_link) |
||
1776 | ASSERT(!peer->relaying_peer) |
||
1777 | ASSERT(!peer->waiting_relay) |
||
1778 | |||
1779 | // disconnect relay users |
||
1780 | LinkedList1Node *list_node; |
||
1781 | while (list_node = LinkedList1_GetFirst(&peer->relay_users)) { |
||
1782 | struct peer_data *relay_user = UPPER_OBJECT(list_node, struct peer_data, relaying_list_node); |
||
1783 | ASSERT(relay_user->relaying_peer == peer) |
||
1784 | |||
1785 | // disconnect relay user |
||
1786 | peer_free_relaying(relay_user); |
||
1787 | |||
1788 | // add it to need relay list |
||
1789 | peer_register_need_relay(relay_user); |
||
1790 | } |
||
1791 | |||
1792 | // remove from relays list |
||
1793 | LinkedList1_Remove(&relays, &peer->relay_list_node); |
||
1794 | |||
1795 | // set is not relay |
||
1796 | peer->is_relay = 0; |
||
1797 | |||
1798 | // assign relays |
||
1799 | assign_relays(); |
||
1800 | } |
||
1801 | |||
1802 | void peer_install_relaying (struct peer_data *peer, struct peer_data *relay) |
||
1803 | { |
||
1804 | ASSERT(!peer->relaying_peer) |
||
1805 | ASSERT(!peer->have_link) |
||
1806 | ASSERT(!peer->waiting_relay) |
||
1807 | ASSERT(relay->is_relay) |
||
1808 | |||
1809 | ASSERT(!peer->is_relay) |
||
1810 | ASSERT(relay->have_link) |
||
1811 | |||
1812 | peer_log(peer, BLOG_INFO, "installing relaying through %d", (int)relay->id); |
||
1813 | |||
1814 | // add to relay's users list |
||
1815 | LinkedList1_Append(&relay->relay_users, &peer->relaying_list_node); |
||
1816 | |||
1817 | // attach local flow to relay |
||
1818 | DataProtoFlow_Attach(&peer->local_dpflow, &relay->send_dp); |
||
1819 | |||
1820 | // set relaying |
||
1821 | peer->relaying_peer = relay; |
||
1822 | } |
||
1823 | |||
1824 | void peer_free_relaying (struct peer_data *peer) |
||
1825 | { |
||
1826 | ASSERT(peer->relaying_peer) |
||
1827 | |||
1828 | ASSERT(!peer->have_link) |
||
1829 | ASSERT(!peer->waiting_relay) |
||
1830 | |||
1831 | struct peer_data *relay = peer->relaying_peer; |
||
1832 | ASSERT(relay->is_relay) |
||
1833 | ASSERT(relay->have_link) |
||
1834 | |||
1835 | peer_log(peer, BLOG_INFO, "uninstalling relaying through %d", (int)relay->id); |
||
1836 | |||
1837 | // detach local flow from relay |
||
1838 | DataProtoFlow_Detach(&peer->local_dpflow); |
||
1839 | |||
1840 | // remove from relay's users list |
||
1841 | LinkedList1_Remove(&relay->relay_users, &peer->relaying_list_node); |
||
1842 | |||
1843 | // set not relaying |
||
1844 | peer->relaying_peer = NULL; |
||
1845 | } |
||
1846 | |||
1847 | void peer_need_relay (struct peer_data *peer) |
||
1848 | { |
||
1849 | ASSERT(!peer->is_relay) |
||
1850 | |||
1851 | if (peer->waiting_relay) { |
||
1852 | // already waiting for relay, do nothing |
||
1853 | return; |
||
1854 | } |
||
1855 | |||
1856 | if (peer->have_link) { |
||
1857 | peer_free_link(peer); |
||
1858 | } |
||
1859 | else if (peer->relaying_peer) { |
||
1860 | peer_free_relaying(peer); |
||
1861 | } |
||
1862 | |||
1863 | // register the peer as needing a relay |
||
1864 | peer_register_need_relay(peer); |
||
1865 | |||
1866 | // assign relays |
||
1867 | assign_relays(); |
||
1868 | } |
||
1869 | |||
1870 | void peer_register_need_relay (struct peer_data *peer) |
||
1871 | { |
||
1872 | ASSERT(!peer->waiting_relay) |
||
1873 | ASSERT(!peer->have_link) |
||
1874 | ASSERT(!peer->relaying_peer) |
||
1875 | |||
1876 | ASSERT(!peer->is_relay) |
||
1877 | |||
1878 | // add to need relay list |
||
1879 | LinkedList1_Append(&waiting_relay_peers, &peer->waiting_relay_list_node); |
||
1880 | |||
1881 | // set waiting relay |
||
1882 | peer->waiting_relay = 1; |
||
1883 | } |
||
1884 | |||
1885 | void peer_unregister_need_relay (struct peer_data *peer) |
||
1886 | { |
||
1887 | ASSERT(peer->waiting_relay) |
||
1888 | |||
1889 | ASSERT(!peer->have_link) |
||
1890 | ASSERT(!peer->relaying_peer) |
||
1891 | ASSERT(!peer->is_relay) |
||
1892 | |||
1893 | // remove from need relay list |
||
1894 | LinkedList1_Remove(&waiting_relay_peers, &peer->waiting_relay_list_node); |
||
1895 | |||
1896 | // set not waiting relay |
||
1897 | peer->waiting_relay = 0; |
||
1898 | } |
||
1899 | |||
1900 | void peer_reset (struct peer_data *peer) |
||
1901 | { |
||
1902 | peer_log(peer, BLOG_NOTICE, "resetting"); |
||
1903 | |||
1904 | // cleanup connections |
||
1905 | peer_cleanup_connections(peer); |
||
1906 | |||
1907 | if (peer_am_master(peer)) { |
||
1908 | // if we're the master, schedule retry |
||
1909 | BReactor_SetTimer(&ss, &peer->reset_timer); |
||
1910 | } else { |
||
1911 | // if we're the slave, report to master |
||
1912 | peer_send_simple(peer, MSGID_YOURETRY); |
||
1913 | } |
||
1914 | } |
||
1915 | |||
1916 | void peer_resetpeer (struct peer_data *peer) |
||
1917 | { |
||
1918 | ASSERT(peer->have_chat) |
||
1919 | ASSERT(!peer->have_resetpeer) |
||
1920 | |||
1921 | // free chat |
||
1922 | peer_free_chat(peer); |
||
1923 | |||
1924 | // build resetpeer packet |
||
1925 | struct packetproto_header pp_header; |
||
1926 | struct sc_header sc_header; |
||
1927 | struct sc_client_resetpeer sc_resetpeer; |
||
1928 | pp_header.len = htol16(sizeof(struct sc_header) + sizeof(struct sc_client_resetpeer)); |
||
1929 | sc_header.type = htol8(SCID_RESETPEER); |
||
1930 | sc_resetpeer.clientid = htol16(peer->id); |
||
1931 | memcpy(peer->resetpeer_packet, &pp_header, sizeof(pp_header)); |
||
1932 | memcpy(peer->resetpeer_packet + sizeof(pp_header), &sc_header, sizeof(sc_header)); |
||
1933 | memcpy(peer->resetpeer_packet + sizeof(pp_header) + sizeof(sc_header), &sc_resetpeer, sizeof(sc_resetpeer)); |
||
1934 | |||
1935 | // init resetpeer sourse |
||
1936 | SinglePacketSource_Init(&peer->resetpeer_source, peer->resetpeer_packet, sizeof(peer->resetpeer_packet), BReactor_PendingGroup(&ss)); |
||
1937 | |||
1938 | // connect server flow to resetpeer source |
||
1939 | server_flow_connect(peer->server_flow, SinglePacketSource_GetOutput(&peer->resetpeer_source)); |
||
1940 | |||
1941 | // set have resetpeer |
||
1942 | peer->have_resetpeer = 1; |
||
1943 | } |
||
1944 | |||
1945 | void peer_chat_handler_error (struct peer_data *peer) |
||
1946 | { |
||
1947 | ASSERT(peer->have_chat) |
||
1948 | ASSERT(!peer->have_resetpeer) |
||
1949 | |||
1950 | peer_log(peer, BLOG_ERROR, "chat error, sending resetpeer"); |
||
1951 | |||
1952 | peer_resetpeer(peer); |
||
1953 | } |
||
1954 | |||
1955 | void peer_chat_handler_message (struct peer_data *peer, uint8_t *data, int data_len) |
||
1956 | { |
||
1957 | ASSERT(peer->have_chat) |
||
1958 | ASSERT(data_len >= 0) |
||
1959 | ASSERT(data_len <= SC_MAX_MSGLEN) |
||
1960 | |||
1961 | // parse message |
||
1962 | msgParser parser; |
||
1963 | if (!msgParser_Init(&parser, data, data_len)) { |
||
1964 | peer_log(peer, BLOG_NOTICE, "msg: failed to parse"); |
||
1965 | return; |
||
1966 | } |
||
1967 | |||
1968 | // read message |
||
1969 | uint16_t type = 0; // to remove warning |
||
1970 | ASSERT_EXECUTE(msgParser_Gettype(&parser, &type)) |
||
1971 | uint8_t *payload = NULL; // to remove warning |
||
1972 | int payload_len = 0; // to remove warning |
||
1973 | ASSERT_EXECUTE(msgParser_Getpayload(&parser, &payload, &payload_len)) |
||
1974 | |||
1975 | // dispatch according to message type |
||
1976 | switch (type) { |
||
1977 | case MSGID_YOUCONNECT: |
||
1978 | peer_msg_youconnect(peer, payload, payload_len); |
||
1979 | return; |
||
1980 | case MSGID_CANNOTCONNECT: |
||
1981 | peer_msg_cannotconnect(peer, payload, payload_len); |
||
1982 | return; |
||
1983 | case MSGID_CANNOTBIND: |
||
1984 | peer_msg_cannotbind(peer, payload, payload_len); |
||
1985 | return; |
||
1986 | case MSGID_YOURETRY: |
||
1987 | peer_msg_youretry(peer, payload, payload_len); |
||
1988 | return; |
||
1989 | case MSGID_SEED: |
||
1990 | peer_msg_seed(peer, payload, payload_len); |
||
1991 | return; |
||
1992 | case MSGID_CONFIRMSEED: |
||
1993 | peer_msg_confirmseed(peer, payload, payload_len); |
||
1994 | return; |
||
1995 | default: |
||
1996 | BLog(BLOG_NOTICE, "msg: unknown type"); |
||
1997 | return; |
||
1998 | } |
||
1999 | } |
||
2000 | |||
2001 | void peer_msg_youconnect (struct peer_data *peer, uint8_t *data, int data_len) |
||
2002 | { |
||
2003 | // init parser |
||
2004 | msg_youconnectParser parser; |
||
2005 | if (!msg_youconnectParser_Init(&parser, data, data_len)) { |
||
2006 | peer_log(peer, BLOG_WARNING, "msg_youconnect: failed to parse"); |
||
2007 | return; |
||
2008 | } |
||
2009 | |||
2010 | // try addresses |
||
2011 | BAddr addr; |
||
2012 | while (1) { |
||
2013 | // get address message |
||
2014 | uint8_t *addrmsg_data; |
||
2015 | int addrmsg_len; |
||
2016 | if (!msg_youconnectParser_Getaddr(&parser, &addrmsg_data, &addrmsg_len)) { |
||
2017 | peer_log(peer, BLOG_NOTICE, "msg_youconnect: no usable addresses"); |
||
2018 | peer_send_simple(peer, MSGID_CANNOTCONNECT); |
||
2019 | return; |
||
2020 | } |
||
2021 | |||
2022 | // parse address message |
||
2023 | msg_youconnect_addrParser aparser; |
||
2024 | if (!msg_youconnect_addrParser_Init(&aparser, addrmsg_data, addrmsg_len)) { |
||
2025 | peer_log(peer, BLOG_WARNING, "msg_youconnect: failed to parse address message"); |
||
2026 | return; |
||
2027 | } |
||
2028 | |||
2029 | // check if the address scope is known |
||
2030 | uint8_t *name_data = NULL; // to remove warning |
||
2031 | int name_len = 0; // to remove warning |
||
2032 | ASSERT_EXECUTE(msg_youconnect_addrParser_Getname(&aparser, &name_data, &name_len)) |
||
2033 | char *name; |
||
2034 | if (!(name = address_scope_known(name_data, name_len))) { |
||
2035 | continue; |
||
2036 | } |
||
2037 | |||
2038 | // read address |
||
2039 | uint8_t *addr_data = NULL; // to remove warning |
||
2040 | int addr_len = 0; // to remove warning |
||
2041 | ASSERT_EXECUTE(msg_youconnect_addrParser_Getaddr(&aparser, &addr_data, &addr_len)) |
||
2042 | if (!addr_read(addr_data, addr_len, &addr)) { |
||
2043 | peer_log(peer, BLOG_WARNING, "msg_youconnect: failed to read address"); |
||
2044 | continue; |
||
2045 | } |
||
2046 | |||
2047 | peer_log(peer, BLOG_NOTICE, "msg_youconnect: using address in scope '%s'", name); |
||
2048 | break; |
||
2049 | } |
||
2050 | |||
2051 | // discard further addresses |
||
2052 | msg_youconnectParser_Forwardaddr(&parser); |
||
2053 | |||
2054 | uint8_t *key = NULL; |
||
2055 | uint64_t password = 0; |
||
2056 | |||
2057 | // read additonal parameters |
||
2058 | if (options.transport_mode == TRANSPORT_MODE_UDP) { |
||
2059 | if (SPPROTO_HAVE_ENCRYPTION(sp_params)) { |
||
2060 | int key_len; |
||
2061 | if (!msg_youconnectParser_Getkey(&parser, &key, &key_len)) { |
||
2062 | peer_log(peer, BLOG_WARNING, "msg_youconnect: no key"); |
||
2063 | return; |
||
2064 | } |
||
2065 | if (key_len != BEncryption_cipher_key_size(sp_params.encryption_mode)) { |
||
2066 | peer_log(peer, BLOG_WARNING, "msg_youconnect: wrong key size"); |
||
2067 | return; |
||
2068 | } |
||
2069 | } |
||
2070 | } else { |
||
2071 | if (!msg_youconnectParser_Getpassword(&parser, &password)) { |
||
2072 | peer_log(peer, BLOG_WARNING, "msg_youconnect: no password"); |
||
2073 | return; |
||
2074 | } |
||
2075 | } |
||
2076 | |||
2077 | if (!msg_youconnectParser_GotEverything(&parser)) { |
||
2078 | peer_log(peer, BLOG_WARNING, "msg_youconnect: stray data"); |
||
2079 | return; |
||
2080 | } |
||
2081 | |||
2082 | peer_log(peer, BLOG_INFO, "connecting"); |
||
2083 | |||
2084 | peer_connect(peer, addr, key, password); |
||
2085 | } |
||
2086 | |||
2087 | void peer_msg_cannotconnect (struct peer_data *peer, uint8_t *data, int data_len) |
||
2088 | { |
||
2089 | if (data_len != 0) { |
||
2090 | peer_log(peer, BLOG_WARNING, "msg_cannotconnect: invalid length"); |
||
2091 | return; |
||
2092 | } |
||
2093 | |||
2094 | if (!peer->binding) { |
||
2095 | peer_log(peer, BLOG_WARNING, "msg_cannotconnect: not binding"); |
||
2096 | return; |
||
2097 | } |
||
2098 | |||
2099 | peer_log(peer, BLOG_INFO, "peer could not connect"); |
||
2100 | |||
2101 | // continue trying bind addresses |
||
2102 | peer_bind(peer); |
||
2103 | return; |
||
2104 | } |
||
2105 | |||
2106 | void peer_msg_cannotbind (struct peer_data *peer, uint8_t *data, int data_len) |
||
2107 | { |
||
2108 | if (data_len != 0) { |
||
2109 | peer_log(peer, BLOG_WARNING, "msg_cannotbind: invalid length"); |
||
2110 | return; |
||
2111 | } |
||
2112 | |||
2113 | peer_log(peer, BLOG_INFO, "peer cannot bind"); |
||
2114 | |||
2115 | if (!peer_am_master(peer)) { |
||
2116 | peer_start_binding(peer); |
||
2117 | } else { |
||
2118 | if (!peer->is_relay) { |
||
2119 | peer_need_relay(peer); |
||
2120 | } |
||
2121 | } |
||
2122 | } |
||
2123 | |||
2124 | void peer_msg_seed (struct peer_data *peer, uint8_t *data, int data_len) |
||
2125 | { |
||
2126 | msg_seedParser parser; |
||
2127 | if (!msg_seedParser_Init(&parser, data, data_len)) { |
||
2128 | peer_log(peer, BLOG_WARNING, "msg_seed: failed to parse"); |
||
2129 | return; |
||
2130 | } |
||
2131 | |||
2132 | // read message |
||
2133 | uint16_t seed_id = 0; // to remove warning |
||
2134 | ASSERT_EXECUTE(msg_seedParser_Getseed_id(&parser, &seed_id)) |
||
2135 | uint8_t *key = NULL; // to remove warning |
||
2136 | int key_len = 0; // to remove warning |
||
2137 | ASSERT_EXECUTE(msg_seedParser_Getkey(&parser, &key, &key_len)) |
||
2138 | uint8_t *iv = NULL; // to remove warning |
||
2139 | int iv_len = 0; // to remove warning |
||
2140 | ASSERT_EXECUTE(msg_seedParser_Getiv(&parser, &iv, &iv_len)) |
||
2141 | |||
2142 | if (options.transport_mode != TRANSPORT_MODE_UDP) { |
||
2143 | peer_log(peer, BLOG_WARNING, "msg_seed: not in UDP mode"); |
||
2144 | return; |
||
2145 | } |
||
2146 | |||
2147 | if (!SPPROTO_HAVE_OTP(sp_params)) { |
||
2148 | peer_log(peer, BLOG_WARNING, "msg_seed: OTPs disabled"); |
||
2149 | return; |
||
2150 | } |
||
2151 | |||
2152 | if (key_len != BEncryption_cipher_key_size(sp_params.otp_mode)) { |
||
2153 | peer_log(peer, BLOG_WARNING, "msg_seed: wrong key length"); |
||
2154 | return; |
||
2155 | } |
||
2156 | |||
2157 | if (iv_len != BEncryption_cipher_block_size(sp_params.otp_mode)) { |
||
2158 | peer_log(peer, BLOG_WARNING, "msg_seed: wrong IV length"); |
||
2159 | return; |
||
2160 | } |
||
2161 | |||
2162 | if (!peer->have_link) { |
||
2163 | peer_log(peer, BLOG_WARNING, "msg_seed: have no link"); |
||
2164 | return; |
||
2165 | } |
||
2166 | |||
2167 | peer_log(peer, BLOG_DEBUG, "received OTP receive seed"); |
||
2168 | |||
2169 | // add receive seed |
||
2170 | DatagramPeerIO_AddOTPRecvSeed(&peer->pio.udp.pio, seed_id, key, iv); |
||
2171 | |||
2172 | // remember seed ID so we can confirm it from peer_udp_pio_handler_seed_ready |
||
2173 | peer->pio.udp.pending_recvseed_id = seed_id; |
||
2174 | } |
||
2175 | |||
2176 | void peer_msg_confirmseed (struct peer_data *peer, uint8_t *data, int data_len) |
||
2177 | { |
||
2178 | msg_confirmseedParser parser; |
||
2179 | if (!msg_confirmseedParser_Init(&parser, data, data_len)) { |
||
2180 | peer_log(peer, BLOG_WARNING, "msg_confirmseed: failed to parse"); |
||
2181 | return; |
||
2182 | } |
||
2183 | |||
2184 | // read message |
||
2185 | uint16_t seed_id = 0; // to remove warning |
||
2186 | ASSERT_EXECUTE(msg_confirmseedParser_Getseed_id(&parser, &seed_id)) |
||
2187 | |||
2188 | if (options.transport_mode != TRANSPORT_MODE_UDP) { |
||
2189 | peer_log(peer, BLOG_WARNING, "msg_confirmseed: not in UDP mode"); |
||
2190 | return; |
||
2191 | } |
||
2192 | |||
2193 | if (!SPPROTO_HAVE_OTP(sp_params)) { |
||
2194 | peer_log(peer, BLOG_WARNING, "msg_confirmseed: OTPs disabled"); |
||
2195 | return; |
||
2196 | } |
||
2197 | |||
2198 | if (!peer->have_link) { |
||
2199 | peer_log(peer, BLOG_WARNING, "msg_confirmseed: have no link"); |
||
2200 | return; |
||
2201 | } |
||
2202 | |||
2203 | if (!peer->pio.udp.sendseed_sent) { |
||
2204 | peer_log(peer, BLOG_WARNING, "msg_confirmseed: no seed has been sent"); |
||
2205 | return; |
||
2206 | } |
||
2207 | |||
2208 | if (seed_id != peer->pio.udp.sendseed_sent_id) { |
||
2209 | peer_log(peer, BLOG_WARNING, "msg_confirmseed: invalid seed: expecting %d, received %d", (int)peer->pio.udp.sendseed_sent_id, (int)seed_id); |
||
2210 | return; |
||
2211 | } |
||
2212 | |||
2213 | peer_log(peer, BLOG_DEBUG, "OTP send seed confirmed"); |
||
2214 | |||
2215 | // no longer waiting for confirmation |
||
2216 | peer->pio.udp.sendseed_sent = 0; |
||
2217 | |||
2218 | // start using the seed |
||
2219 | DatagramPeerIO_SetOTPSendSeed(&peer->pio.udp.pio, peer->pio.udp.sendseed_sent_id, peer->pio.udp.sendseed_sent_key, peer->pio.udp.sendseed_sent_iv); |
||
2220 | } |
||
2221 | |||
2222 | void peer_msg_youretry (struct peer_data *peer, uint8_t *data, int data_len) |
||
2223 | { |
||
2224 | if (data_len != 0) { |
||
2225 | peer_log(peer, BLOG_WARNING, "msg_youretry: invalid length"); |
||
2226 | return; |
||
2227 | } |
||
2228 | |||
2229 | if (!peer_am_master(peer)) { |
||
2230 | peer_log(peer, BLOG_WARNING, "msg_youretry: we are not master"); |
||
2231 | return; |
||
2232 | } |
||
2233 | |||
2234 | peer_log(peer, BLOG_NOTICE, "requests reset"); |
||
2235 | |||
2236 | peer_reset(peer); |
||
2237 | } |
||
2238 | |||
2239 | void peer_udp_pio_handler_seed_warning (struct peer_data *peer) |
||
2240 | { |
||
2241 | ASSERT(options.transport_mode == TRANSPORT_MODE_UDP) |
||
2242 | ASSERT(SPPROTO_HAVE_OTP(sp_params)) |
||
2243 | ASSERT(peer->have_link) |
||
2244 | |||
2245 | // generate and send a new seed |
||
2246 | if (!peer->pio.udp.sendseed_sent) { |
||
2247 | BPending_Set(&peer->pio.udp.job_send_seed); |
||
2248 | } |
||
2249 | } |
||
2250 | |||
2251 | void peer_udp_pio_handler_seed_ready (struct peer_data *peer) |
||
2252 | { |
||
2253 | ASSERT(options.transport_mode == TRANSPORT_MODE_UDP) |
||
2254 | ASSERT(SPPROTO_HAVE_OTP(sp_params)) |
||
2255 | ASSERT(peer->have_link) |
||
2256 | |||
2257 | // send confirmation |
||
2258 | peer_send_confirmseed(peer, peer->pio.udp.pending_recvseed_id); |
||
2259 | } |
||
2260 | |||
2261 | void peer_udp_pio_handler_error (struct peer_data *peer) |
||
2262 | { |
||
2263 | ASSERT(options.transport_mode == TRANSPORT_MODE_UDP) |
||
2264 | ASSERT(peer->have_link) |
||
2265 | |||
2266 | peer_log(peer, BLOG_NOTICE, "UDP connection failed"); |
||
2267 | |||
2268 | peer_reset(peer); |
||
2269 | return; |
||
2270 | } |
||
2271 | |||
2272 | void peer_tcp_pio_handler_error (struct peer_data *peer) |
||
2273 | { |
||
2274 | ASSERT(options.transport_mode == TRANSPORT_MODE_TCP) |
||
2275 | ASSERT(peer->have_link) |
||
2276 | |||
2277 | peer_log(peer, BLOG_NOTICE, "TCP connection failed"); |
||
2278 | |||
2279 | peer_reset(peer); |
||
2280 | return; |
||
2281 | } |
||
2282 | |||
2283 | void peer_reset_timer_handler (struct peer_data *peer) |
||
2284 | { |
||
2285 | ASSERT(peer_am_master(peer)) |
||
2286 | |||
2287 | BLog(BLOG_NOTICE, "retry timer expired"); |
||
2288 | |||
2289 | // start setup process |
||
2290 | peer_start_binding(peer); |
||
2291 | } |
||
2292 | |||
2293 | void peer_start_binding (struct peer_data *peer) |
||
2294 | { |
||
2295 | peer->binding = 1; |
||
2296 | peer->binding_addrpos = 0; |
||
2297 | |||
2298 | peer_bind(peer); |
||
2299 | } |
||
2300 | |||
2301 | void peer_bind (struct peer_data *peer) |
||
2302 | { |
||
2303 | ASSERT(peer->binding) |
||
2304 | ASSERT(peer->binding_addrpos >= 0) |
||
2305 | ASSERT(peer->binding_addrpos <= num_bind_addrs) |
||
2306 | |||
2307 | while (peer->binding_addrpos < num_bind_addrs) { |
||
2308 | // if there are no external addresses, skip bind address |
||
2309 | if (bind_addrs[peer->binding_addrpos].num_ext_addrs == 0) { |
||
2310 | peer->binding_addrpos++; |
||
2311 | continue; |
||
2312 | } |
||
2313 | |||
2314 | // try to bind |
||
2315 | int cont; |
||
2316 | peer_bind_one_address(peer, peer->binding_addrpos, &cont); |
||
2317 | |||
2318 | // increment address counter |
||
2319 | peer->binding_addrpos++; |
||
2320 | |||
2321 | if (!cont) { |
||
2322 | return; |
||
2323 | } |
||
2324 | } |
||
2325 | |||
2326 | peer_log(peer, BLOG_NOTICE, "no more addresses to bind to"); |
||
2327 | |||
2328 | // no longer binding |
||
2329 | peer->binding = 0; |
||
2330 | |||
2331 | // tell the peer we failed to bind |
||
2332 | peer_send_simple(peer, MSGID_CANNOTBIND); |
||
2333 | |||
2334 | // if we are the slave, setup relaying |
||
2335 | if (!peer_am_master(peer)) { |
||
2336 | if (!peer->is_relay) { |
||
2337 | peer_need_relay(peer); |
||
2338 | } |
||
2339 | } |
||
2340 | } |
||
2341 | |||
2342 | void peer_bind_one_address (struct peer_data *peer, int addr_index, int *cont) |
||
2343 | { |
||
2344 | ASSERT(addr_index >= 0) |
||
2345 | ASSERT(addr_index < num_bind_addrs) |
||
2346 | ASSERT(bind_addrs[addr_index].num_ext_addrs > 0) |
||
2347 | |||
2348 | // get a fresh link |
||
2349 | peer_cleanup_connections(peer); |
||
2350 | if (!peer_init_link(peer)) { |
||
2351 | peer_log(peer, BLOG_ERROR, "cannot get link"); |
||
2352 | *cont = 0; |
||
2353 | peer_reset(peer); |
||
2354 | return; |
||
2355 | } |
||
2356 | |||
2357 | if (options.transport_mode == TRANSPORT_MODE_UDP) { |
||
2358 | // get addr |
||
2359 | struct bind_addr *addr = &bind_addrs[addr_index]; |
||
2360 | |||
2361 | // try binding to all ports in the range |
||
2362 | int port_add; |
||
2363 | for (port_add = 0; port_add < addr->num_ports; port_add++) { |
||
2364 | BAddr tryaddr = addr->addr; |
||
2365 | BAddr_SetPort(&tryaddr, hton16(ntoh16(BAddr_GetPort(&tryaddr)) + port_add)); |
||
2366 | if (DatagramPeerIO_Bind(&peer->pio.udp.pio, tryaddr)) { |
||
2367 | break; |
||
2368 | } |
||
2369 | } |
||
2370 | if (port_add == addr->num_ports) { |
||
2371 | BLog(BLOG_NOTICE, "failed to bind to any port"); |
||
2372 | *cont = 1; |
||
2373 | return; |
||
2374 | } |
||
2375 | |||
2376 | uint8_t key[BENCRYPTION_MAX_KEY_SIZE]; |
||
2377 | |||
2378 | // generate and set encryption key |
||
2379 | if (SPPROTO_HAVE_ENCRYPTION(sp_params)) { |
||
2380 | BRandom_randomize(key, BEncryption_cipher_key_size(sp_params.encryption_mode)); |
||
2381 | DatagramPeerIO_SetEncryptionKey(&peer->pio.udp.pio, key); |
||
2382 | } |
||
2383 | |||
2384 | // schedule sending OTP seed |
||
2385 | if (SPPROTO_HAVE_OTP(sp_params)) { |
||
2386 | BPending_Set(&peer->pio.udp.job_send_seed); |
||
2387 | } |
||
2388 | |||
2389 | // send connectinfo |
||
2390 | peer_send_conectinfo(peer, addr_index, port_add, key, 0); |
||
2391 | } else { |
||
2392 | // order StreamPeerIO to listen |
||
2393 | uint64_t pass; |
||
2394 | StreamPeerIO_Listen(&peer->pio.tcp.pio, &listeners[addr_index], &pass); |
||
2395 | |||
2396 | // send connectinfo |
||
2397 | peer_send_conectinfo(peer, addr_index, 0, NULL, pass); |
||
2398 | } |
||
2399 | |||
2400 | peer_log(peer, BLOG_NOTICE, "bound to address number %d", addr_index); |
||
2401 | |||
2402 | *cont = 0; |
||
2403 | } |
||
2404 | |||
2405 | void peer_connect (struct peer_data *peer, BAddr addr, uint8_t* encryption_key, uint64_t password) |
||
2406 | { |
||
2407 | // get a fresh link |
||
2408 | peer_cleanup_connections(peer); |
||
2409 | if (!peer_init_link(peer)) { |
||
2410 | peer_log(peer, BLOG_ERROR, "cannot get link"); |
||
2411 | peer_reset(peer); |
||
2412 | return; |
||
2413 | } |
||
2414 | |||
2415 | if (options.transport_mode == TRANSPORT_MODE_UDP) { |
||
2416 | // order DatagramPeerIO to connect |
||
2417 | if (!DatagramPeerIO_Connect(&peer->pio.udp.pio, addr)) { |
||
2418 | peer_log(peer, BLOG_NOTICE, "DatagramPeerIO_Connect failed"); |
||
2419 | peer_reset(peer); |
||
2420 | return; |
||
2421 | } |
||
2422 | |||
2423 | // set encryption key |
||
2424 | if (SPPROTO_HAVE_ENCRYPTION(sp_params)) { |
||
2425 | DatagramPeerIO_SetEncryptionKey(&peer->pio.udp.pio, encryption_key); |
||
2426 | } |
||
2427 | |||
2428 | // generate and send a send seed |
||
2429 | if (SPPROTO_HAVE_OTP(sp_params)) { |
||
2430 | BPending_Set(&peer->pio.udp.job_send_seed); |
||
2431 | } |
||
2432 | } else { |
||
2433 | // order StreamPeerIO to connect |
||
2434 | if (!StreamPeerIO_Connect(&peer->pio.tcp.pio, addr, password, client_cert, client_key)) { |
||
2435 | peer_log(peer, BLOG_NOTICE, "StreamPeerIO_Connect failed"); |
||
2436 | peer_reset(peer); |
||
2437 | return; |
||
2438 | } |
||
2439 | } |
||
2440 | } |
||
2441 | |||
2442 | static int peer_start_msg (struct peer_data *peer, void **data, int type, int len) |
||
2443 | { |
||
2444 | ASSERT(len >= 0) |
||
2445 | ASSERT(len <= MSG_MAX_PAYLOAD) |
||
2446 | ASSERT(!(len > 0) || data) |
||
2447 | ASSERT(peer->chat_send_msg_len == -1) |
||
2448 | |||
2449 | // make sure we have chat |
||
2450 | if (!peer->have_chat) { |
||
2451 | peer_log(peer, BLOG_ERROR, "cannot send message, chat is down"); |
||
2452 | return 0; |
||
2453 | } |
||
2454 | |||
2455 | #ifdef SIMULATE_PEER_OUT_OF_BUFFER |
||
2456 | uint8_t x; |
||
2457 | BRandom_randomize(&x, sizeof(x)); |
||
2458 | if (x < SIMULATE_PEER_OUT_OF_BUFFER) { |
||
2459 | peer_log(peer, BLOG_ERROR, "simulating out of buffer, sending resetpeer"); |
||
2460 | peer_resetpeer(peer); |
||
2461 | return 0; |
||
2462 | } |
||
2463 | #endif |
||
2464 | |||
2465 | // obtain buffer location |
||
2466 | uint8_t *packet; |
||
2467 | if (!PeerChat_StartMessage(&peer->chat, &packet)) { |
||
2468 | peer_log(peer, BLOG_ERROR, "cannot send message, out of buffer, sending resetpeer"); |
||
2469 | peer_resetpeer(peer); |
||
2470 | return 0; |
||
2471 | } |
||
2472 | |||
2473 | // write fields |
||
2474 | msgWriter writer; |
||
2475 | msgWriter_Init(&writer, packet); |
||
2476 | msgWriter_Addtype(&writer, type); |
||
2477 | uint8_t *payload_dst = msgWriter_Addpayload(&writer, len); |
||
2478 | msgWriter_Finish(&writer); |
||
2479 | |||
2480 | // set have message |
||
2481 | peer->chat_send_msg_len = len; |
||
2482 | |||
2483 | if (data) { |
||
2484 | *data = payload_dst; |
||
2485 | } |
||
2486 | return 1; |
||
2487 | } |
||
2488 | |||
2489 | static void peer_end_msg (struct peer_data *peer) |
||
2490 | { |
||
2491 | ASSERT(peer->chat_send_msg_len >= 0) |
||
2492 | ASSERT(peer->have_chat) |
||
2493 | |||
2494 | // submit packet to buffer |
||
2495 | PeerChat_EndMessage(&peer->chat, msg_SIZEtype + msg_SIZEpayload(peer->chat_send_msg_len)); |
||
2496 | |||
2497 | // set no message |
||
2498 | peer->chat_send_msg_len = -1; |
||
2499 | } |
||
2500 | |||
2501 | void peer_send_simple (struct peer_data *peer, int msgid) |
||
2502 | { |
||
2503 | if (!peer_start_msg(peer, NULL, msgid, 0)) { |
||
2504 | return; |
||
2505 | } |
||
2506 | peer_end_msg(peer); |
||
2507 | } |
||
2508 | |||
2509 | void peer_send_conectinfo (struct peer_data *peer, int addr_index, int port_adjust, uint8_t *enckey, uint64_t pass) |
||
2510 | { |
||
2511 | ASSERT(addr_index >= 0) |
||
2512 | ASSERT(addr_index < num_bind_addrs) |
||
2513 | ASSERT(bind_addrs[addr_index].num_ext_addrs > 0) |
||
2514 | |||
2515 | // get address |
||
2516 | struct bind_addr *bind_addr = &bind_addrs[addr_index]; |
||
2517 | |||
2518 | // remember encryption key size |
||
2519 | int key_size = 0; // to remove warning |
||
2520 | if (options.transport_mode == TRANSPORT_MODE_UDP && SPPROTO_HAVE_ENCRYPTION(sp_params)) { |
||
2521 | key_size = BEncryption_cipher_key_size(sp_params.encryption_mode); |
||
2522 | } |
||
2523 | |||
2524 | // calculate message length .. |
||
2525 | int msg_len = 0; |
||
2526 | |||
2527 | // addresses |
||
2528 | for (int i = 0; i < bind_addr->num_ext_addrs; i++) { |
||
2529 | int addrmsg_len = |
||
2530 | msg_youconnect_addr_SIZEname(strlen(bind_addr->ext_addrs[i].scope)) + |
||
2531 | msg_youconnect_addr_SIZEaddr(addr_size(bind_addr->ext_addrs[i].addr)); |
||
2532 | msg_len += msg_youconnect_SIZEaddr(addrmsg_len); |
||
2533 | } |
||
2534 | |||
2535 | // encryption key |
||
2536 | if (options.transport_mode == TRANSPORT_MODE_UDP && SPPROTO_HAVE_ENCRYPTION(sp_params)) { |
||
2537 | msg_len += msg_youconnect_SIZEkey(key_size); |
||
2538 | } |
||
2539 | |||
2540 | // password |
||
2541 | if (options.transport_mode == TRANSPORT_MODE_TCP) { |
||
2542 | msg_len += msg_youconnect_SIZEpassword; |
||
2543 | } |
||
2544 | |||
2545 | // check if it's too big (because of the addresses) |
||
2546 | if (msg_len > MSG_MAX_PAYLOAD) { |
||
2547 | BLog(BLOG_ERROR, "cannot send too big youconnect message"); |
||
2548 | return; |
||
2549 | } |
||
2550 | |||
2551 | // start message |
||
2552 | uint8_t *msg; |
||
2553 | if (!peer_start_msg(peer, (void **)&msg, MSGID_YOUCONNECT, msg_len)) { |
||
2554 | return; |
||
2555 | } |
||
2556 | |||
2557 | // init writer |
||
2558 | msg_youconnectWriter writer; |
||
2559 | msg_youconnectWriter_Init(&writer, msg); |
||
2560 | |||
2561 | // write addresses |
||
2562 | for (int i = 0; i < bind_addr->num_ext_addrs; i++) { |
||
2563 | int name_len = strlen(bind_addr->ext_addrs[i].scope); |
||
2564 | int addr_len = addr_size(bind_addr->ext_addrs[i].addr); |
||
2565 | |||
2566 | // get a pointer for writing the address |
||
2567 | int addrmsg_len = |
||
2568 | msg_youconnect_addr_SIZEname(name_len) + |
||
2569 | msg_youconnect_addr_SIZEaddr(addr_len); |
||
2570 | uint8_t *addrmsg_dst = msg_youconnectWriter_Addaddr(&writer, addrmsg_len); |
||
2571 | |||
2572 | // init address writer |
||
2573 | msg_youconnect_addrWriter awriter; |
||
2574 | msg_youconnect_addrWriter_Init(&awriter, addrmsg_dst); |
||
2575 | |||
2576 | // write scope |
||
2577 | uint8_t *name_dst = msg_youconnect_addrWriter_Addname(&awriter, name_len); |
||
2578 | memcpy(name_dst, bind_addr->ext_addrs[i].scope, name_len); |
||
2579 | |||
2580 | // write address with adjusted port |
||
2581 | BAddr addr = bind_addr->ext_addrs[i].addr; |
||
2582 | BAddr_SetPort(&addr, hton16(ntoh16(BAddr_GetPort(&addr)) + port_adjust)); |
||
2583 | uint8_t *addr_dst = msg_youconnect_addrWriter_Addaddr(&awriter, addr_len); |
||
2584 | addr_write(addr_dst, addr); |
||
2585 | |||
2586 | // finish address writer |
||
2587 | msg_youconnect_addrWriter_Finish(&awriter); |
||
2588 | } |
||
2589 | |||
2590 | // write encryption key |
||
2591 | if (options.transport_mode == TRANSPORT_MODE_UDP && SPPROTO_HAVE_ENCRYPTION(sp_params)) { |
||
2592 | uint8_t *key_dst = msg_youconnectWriter_Addkey(&writer, key_size); |
||
2593 | memcpy(key_dst, enckey, key_size); |
||
2594 | } |
||
2595 | |||
2596 | // write password |
||
2597 | if (options.transport_mode == TRANSPORT_MODE_TCP) { |
||
2598 | msg_youconnectWriter_Addpassword(&writer, pass); |
||
2599 | } |
||
2600 | |||
2601 | // finish writer |
||
2602 | msg_youconnectWriter_Finish(&writer); |
||
2603 | |||
2604 | // end message |
||
2605 | peer_end_msg(peer); |
||
2606 | } |
||
2607 | |||
2608 | void peer_send_confirmseed (struct peer_data *peer, uint16_t seed_id) |
||
2609 | { |
||
2610 | ASSERT(options.transport_mode == TRANSPORT_MODE_UDP) |
||
2611 | ASSERT(SPPROTO_HAVE_OTP(sp_params)) |
||
2612 | |||
2613 | // send confirmation |
||
2614 | int msg_len = msg_confirmseed_SIZEseed_id; |
||
2615 | uint8_t *msg; |
||
2616 | if (!peer_start_msg(peer, (void **)&msg, MSGID_CONFIRMSEED, msg_len)) { |
||
2617 | return; |
||
2618 | } |
||
2619 | msg_confirmseedWriter writer; |
||
2620 | msg_confirmseedWriter_Init(&writer, msg); |
||
2621 | msg_confirmseedWriter_Addseed_id(&writer, seed_id); |
||
2622 | msg_confirmseedWriter_Finish(&writer); |
||
2623 | peer_end_msg(peer); |
||
2624 | } |
||
2625 | |||
2626 | void peer_dataproto_handler (struct peer_data *peer, int up) |
||
2627 | { |
||
2628 | ASSERT(peer->have_link) |
||
2629 | |||
2630 | if (up) { |
||
2631 | peer_log(peer, BLOG_INFO, "up"); |
||
2632 | |||
2633 | // if it can be a relay provided, enable it |
||
2634 | if ((peer->flags & SCID_NEWCLIENT_FLAG_RELAY_SERVER) && !peer->is_relay) { |
||
2635 | peer_enable_relay_provider(peer); |
||
2636 | } |
||
2637 | } else { |
||
2638 | peer_log(peer, BLOG_INFO, "down"); |
||
2639 | |||
2640 | // if it is a relay provider, disable it |
||
2641 | if (peer->is_relay) { |
||
2642 | peer_disable_relay_provider(peer); |
||
2643 | } |
||
2644 | } |
||
2645 | } |
||
2646 | |||
2647 | struct peer_data * find_peer_by_id (peerid_t id) |
||
2648 | { |
||
2649 | for (LinkedList1Node *node = LinkedList1_GetFirst(&peers); node; node = LinkedList1Node_Next(node)) { |
||
2650 | struct peer_data *peer = UPPER_OBJECT(node, struct peer_data, list_node); |
||
2651 | if (peer->id == id) { |
||
2652 | return peer; |
||
2653 | } |
||
2654 | } |
||
2655 | |||
2656 | return NULL; |
||
2657 | } |
||
2658 | |||
2659 | void device_error_handler (void *unused) |
||
2660 | { |
||
2661 | BLog(BLOG_ERROR, "device error"); |
||
2662 | |||
2663 | terminate(); |
||
2664 | } |
||
2665 | |||
2666 | void device_dpsource_handler (void *unused, const uint8_t *frame, int frame_len) |
||
2667 | { |
||
2668 | ASSERT(frame_len >= 0) |
||
2669 | ASSERT(frame_len <= device_mtu) |
||
2670 | |||
2671 | // give frame to decider |
||
2672 | FrameDecider_AnalyzeAndDecide(&frame_decider, frame, frame_len); |
||
2673 | |||
2674 | // forward frame to peers |
||
2675 | FrameDeciderPeer *decider_peer = FrameDecider_NextDestination(&frame_decider); |
||
2676 | while (decider_peer) { |
||
2677 | FrameDeciderPeer *next = FrameDecider_NextDestination(&frame_decider); |
||
2678 | struct peer_data *peer = UPPER_OBJECT(decider_peer, struct peer_data, decider_peer); |
||
2679 | DataProtoFlow_Route(&peer->local_dpflow, !!next); |
||
2680 | decider_peer = next; |
||
2681 | } |
||
2682 | } |
||
2683 | |||
2684 | void assign_relays (void) |
||
2685 | { |
||
2686 | LinkedList1Node *list_node; |
||
2687 | while (list_node = LinkedList1_GetFirst(&waiting_relay_peers)) { |
||
2688 | struct peer_data *peer = UPPER_OBJECT(list_node, struct peer_data, waiting_relay_list_node); |
||
2689 | ASSERT(peer->waiting_relay) |
||
2690 | |||
2691 | ASSERT(!peer->relaying_peer) |
||
2692 | ASSERT(!peer->have_link) |
||
2693 | |||
2694 | // get a relay |
||
2695 | LinkedList1Node *list_node2 = LinkedList1_GetFirst(&relays); |
||
2696 | if (!list_node2) { |
||
2697 | BLog(BLOG_NOTICE, "no relays"); |
||
2698 | return; |
||
2699 | } |
||
2700 | struct peer_data *relay = UPPER_OBJECT(list_node2, struct peer_data, relay_list_node); |
||
2701 | ASSERT(relay->is_relay) |
||
2702 | |||
2703 | // no longer waiting for relay |
||
2704 | peer_unregister_need_relay(peer); |
||
2705 | |||
2706 | // install the relay |
||
2707 | peer_install_relaying(peer, relay); |
||
2708 | } |
||
2709 | } |
||
2710 | |||
2711 | char * address_scope_known (uint8_t *name, int name_len) |
||
2712 | { |
||
2713 | ASSERT(name_len >= 0) |
||
2714 | |||
2715 | for (int i = 0; i < options.num_scopes; i++) { |
||
2716 | if (name_len == strlen(options.scopes[i]) && !memcmp(name, options.scopes[i], name_len)) { |
||
2717 | return options.scopes[i]; |
||
2718 | } |
||
2719 | } |
||
2720 | |||
2721 | return NULL; |
||
2722 | } |
||
2723 | |||
2724 | void server_handler_error (void *user) |
||
2725 | { |
||
2726 | BLog(BLOG_ERROR, "server connection failed, exiting"); |
||
2727 | |||
2728 | terminate(); |
||
2729 | } |
||
2730 | |||
2731 | void server_handler_ready (void *user, peerid_t param_my_id, uint32_t ext_ip) |
||
2732 | { |
||
2733 | ASSERT(!server_ready) |
||
2734 | |||
2735 | // remember our ID |
||
2736 | my_id = param_my_id; |
||
2737 | |||
2738 | // store server reported addresses |
||
2739 | for (int i = 0; i < num_bind_addrs; i++) { |
||
2740 | struct bind_addr *addr = &bind_addrs[i]; |
||
2741 | for (int j = 0; j < addr->num_ext_addrs; j++) { |
||
2742 | struct ext_addr *eaddr = &addr->ext_addrs[j]; |
||
2743 | if (eaddr->server_reported_port >= 0) { |
||
2744 | if (ext_ip == 0) { |
||
2745 | BLog(BLOG_ERROR, "server did not provide our address"); |
||
2746 | terminate(); |
||
2747 | return; |
||
2748 | } |
||
2749 | BAddr_InitIPv4(&eaddr->addr, ext_ip, hton16(eaddr->server_reported_port)); |
||
2750 | char str[BADDR_MAX_PRINT_LEN]; |
||
2751 | BAddr_Print(&eaddr->addr, str); |
||
2752 | BLog(BLOG_INFO, "external address (%d,%d): server reported %s", i, j, str); |
||
2753 | } |
||
2754 | } |
||
2755 | } |
||
2756 | |||
2757 | // give receive device the ID |
||
2758 | DPReceiveDevice_SetPeerID(&device_output_dprd, my_id); |
||
2759 | |||
2760 | // init server queue |
||
2761 | if (!PacketPassFairQueue_Init(&server_queue, ServerConnection_GetSendInterface(&server), BReactor_PendingGroup(&ss), 0, 1)) { |
||
2762 | BLog(BLOG_ERROR, "PacketPassFairQueue_Init failed"); |
||
2763 | terminate(); |
||
2764 | return; |
||
2765 | } |
||
2766 | |||
2767 | // set server ready |
||
2768 | server_ready = 1; |
||
2769 | |||
2770 | BLog(BLOG_INFO, "server: ready, my ID is %d", (int)my_id); |
||
2771 | } |
||
2772 | |||
2773 | void server_handler_newclient (void *user, peerid_t peer_id, int flags, const uint8_t *cert, int cert_len) |
||
2774 | { |
||
2775 | ASSERT(server_ready) |
||
2776 | ASSERT(cert_len >= 0) |
||
2777 | ASSERT(cert_len <= SCID_NEWCLIENT_MAX_CERT_LEN) |
||
2778 | |||
2779 | // check if the peer already exists |
||
2780 | if (find_peer_by_id(peer_id)) { |
||
2781 | BLog(BLOG_WARNING, "server: newclient: peer already known"); |
||
2782 | return; |
||
2783 | } |
||
2784 | |||
2785 | // make sure it's not the same ID as us |
||
2786 | if (peer_id == my_id) { |
||
2787 | BLog(BLOG_WARNING, "server: newclient: peer has our ID"); |
||
2788 | return; |
||
2789 | } |
||
2790 | |||
2791 | // check if there is spece for the peer |
||
2792 | if (num_peers >= options.max_peers) { |
||
2793 | BLog(BLOG_WARNING, "server: newclient: no space for new peer (maximum number reached)"); |
||
2794 | return; |
||
2795 | } |
||
2796 | |||
2797 | if (!options.ssl && cert_len > 0) { |
||
2798 | BLog(BLOG_WARNING, "server: newclient: certificate supplied, but not using TLS"); |
||
2799 | return; |
||
2800 | } |
||
2801 | |||
2802 | peer_add(peer_id, flags, cert, cert_len); |
||
2803 | } |
||
2804 | |||
2805 | void server_handler_endclient (void *user, peerid_t peer_id) |
||
2806 | { |
||
2807 | ASSERT(server_ready) |
||
2808 | |||
2809 | // find peer |
||
2810 | struct peer_data *peer = find_peer_by_id(peer_id); |
||
2811 | if (!peer) { |
||
2812 | BLog(BLOG_WARNING, "server: endclient: peer %d not known", (int)peer_id); |
||
2813 | return; |
||
2814 | } |
||
2815 | |||
2816 | // remove peer |
||
2817 | peer_remove(peer, 0); |
||
2818 | } |
||
2819 | |||
2820 | void server_handler_message (void *user, peerid_t peer_id, uint8_t *data, int data_len) |
||
2821 | { |
||
2822 | ASSERT(server_ready) |
||
2823 | ASSERT(data_len >= 0) |
||
2824 | ASSERT(data_len <= SC_MAX_MSGLEN) |
||
2825 | |||
2826 | // find peer |
||
2827 | struct peer_data *peer = find_peer_by_id(peer_id); |
||
2828 | if (!peer) { |
||
2829 | BLog(BLOG_WARNING, "server: message: peer not known"); |
||
2830 | return; |
||
2831 | } |
||
2832 | |||
2833 | // make sure we have chat |
||
2834 | if (!peer->have_chat) { |
||
2835 | peer_log(peer, BLOG_ERROR, "cannot process message, chat is down"); |
||
2836 | return; |
||
2837 | } |
||
2838 | |||
2839 | // pass message to chat |
||
2840 | PeerChat_InputReceived(&peer->chat, data, data_len); |
||
2841 | } |
||
2842 | |||
2843 | void peer_job_send_seed (struct peer_data *peer) |
||
2844 | { |
||
2845 | ASSERT(options.transport_mode == TRANSPORT_MODE_UDP) |
||
2846 | ASSERT(SPPROTO_HAVE_OTP(sp_params)) |
||
2847 | ASSERT(peer->have_link) |
||
2848 | ASSERT(!peer->pio.udp.sendseed_sent) |
||
2849 | |||
2850 | peer_log(peer, BLOG_DEBUG, "sending OTP send seed"); |
||
2851 | |||
2852 | int key_len = BEncryption_cipher_key_size(sp_params.otp_mode); |
||
2853 | int iv_len = BEncryption_cipher_block_size(sp_params.otp_mode); |
||
2854 | |||
2855 | // generate seed |
||
2856 | peer->pio.udp.sendseed_sent_id = peer->pio.udp.sendseed_nextid; |
||
2857 | BRandom_randomize(peer->pio.udp.sendseed_sent_key, key_len); |
||
2858 | BRandom_randomize(peer->pio.udp.sendseed_sent_iv, iv_len); |
||
2859 | |||
2860 | // set as sent, increment next seed ID |
||
2861 | peer->pio.udp.sendseed_sent = 1; |
||
2862 | peer->pio.udp.sendseed_nextid++; |
||
2863 | |||
2864 | // send seed to the peer |
||
2865 | int msg_len = msg_seed_SIZEseed_id + msg_seed_SIZEkey(key_len) + msg_seed_SIZEiv(iv_len); |
||
2866 | if (msg_len > MSG_MAX_PAYLOAD) { |
||
2867 | peer_log(peer, BLOG_ERROR, "OTP send seed message too big"); |
||
2868 | return; |
||
2869 | } |
||
2870 | uint8_t *msg; |
||
2871 | if (!peer_start_msg(peer, (void **)&msg, MSGID_SEED, msg_len)) { |
||
2872 | return; |
||
2873 | } |
||
2874 | msg_seedWriter writer; |
||
2875 | msg_seedWriter_Init(&writer, msg); |
||
2876 | msg_seedWriter_Addseed_id(&writer, peer->pio.udp.sendseed_sent_id); |
||
2877 | uint8_t *key_dst = msg_seedWriter_Addkey(&writer, key_len); |
||
2878 | memcpy(key_dst, peer->pio.udp.sendseed_sent_key, key_len); |
||
2879 | uint8_t *iv_dst = msg_seedWriter_Addiv(&writer, iv_len); |
||
2880 | memcpy(iv_dst, peer->pio.udp.sendseed_sent_iv, iv_len); |
||
2881 | msg_seedWriter_Finish(&writer); |
||
2882 | peer_end_msg(peer); |
||
2883 | } |
||
2884 | |||
2885 | void peer_job_init (struct peer_data *peer) |
||
2886 | { |
||
2887 | // start setup process |
||
2888 | if (peer_am_master(peer)) { |
||
2889 | peer_start_binding(peer); |
||
2890 | } |
||
2891 | } |
||
2892 | |||
2893 | struct server_flow * server_flow_init (void) |
||
2894 | { |
||
2895 | ASSERT(server_ready) |
||
2896 | |||
2897 | // allocate structure |
||
2898 | struct server_flow *flow = (struct server_flow *)malloc(sizeof(*flow)); |
||
2899 | if (!flow) { |
||
2900 | BLog(BLOG_ERROR, "malloc failed"); |
||
2901 | goto fail0; |
||
2902 | } |
||
2903 | |||
2904 | // init queue flow |
||
2905 | PacketPassFairQueueFlow_Init(&flow->qflow, &server_queue); |
||
2906 | |||
2907 | // init connector |
||
2908 | PacketRecvConnector_Init(&flow->connector, sizeof(struct packetproto_header) + SC_MAX_ENC, BReactor_PendingGroup(&ss)); |
||
2909 | |||
2910 | // init encoder buffer |
||
2911 | if (!SinglePacketBuffer_Init(&flow->encoder_buffer, PacketRecvConnector_GetOutput(&flow->connector), PacketPassFairQueueFlow_GetInput(&flow->qflow), BReactor_PendingGroup(&ss))) { |
||
2912 | BLog(BLOG_ERROR, "SinglePacketBuffer_Init failed"); |
||
2913 | goto fail1; |
||
2914 | } |
||
2915 | |||
2916 | // set not connected |
||
2917 | flow->connected = 0; |
||
2918 | |||
2919 | return flow; |
||
2920 | |||
2921 | fail1: |
||
2922 | PacketRecvConnector_Free(&flow->connector); |
||
2923 | PacketPassFairQueueFlow_Free(&flow->qflow); |
||
2924 | free(flow); |
||
2925 | fail0: |
||
2926 | return NULL; |
||
2927 | } |
||
2928 | |||
2929 | void server_flow_free (struct server_flow *flow) |
||
2930 | { |
||
2931 | PacketPassFairQueueFlow_AssertFree(&flow->qflow); |
||
2932 | ASSERT(!flow->connected) |
||
2933 | |||
2934 | // remove dying flow reference |
||
2935 | if (flow == dying_server_flow) { |
||
2936 | dying_server_flow = NULL; |
||
2937 | } |
||
2938 | |||
2939 | // free encoder buffer |
||
2940 | SinglePacketBuffer_Free(&flow->encoder_buffer); |
||
2941 | |||
2942 | // free connector |
||
2943 | PacketRecvConnector_Free(&flow->connector); |
||
2944 | |||
2945 | // free queue flow |
||
2946 | PacketPassFairQueueFlow_Free(&flow->qflow); |
||
2947 | |||
2948 | // free structure |
||
2949 | free(flow); |
||
2950 | } |
||
2951 | |||
2952 | void server_flow_die (struct server_flow *flow) |
||
2953 | { |
||
2954 | ASSERT(PacketPassFairQueueFlow_IsBusy(&flow->qflow)) |
||
2955 | ASSERT(!flow->connected) |
||
2956 | ASSERT(!dying_server_flow) |
||
2957 | |||
2958 | // request notification when flow is done |
||
2959 | PacketPassFairQueueFlow_SetBusyHandler(&flow->qflow, (PacketPassFairQueue_handler_busy)server_flow_qflow_handler_busy, flow); |
||
2960 | |||
2961 | // set dying flow |
||
2962 | dying_server_flow = flow; |
||
2963 | } |
||
2964 | |||
2965 | void server_flow_qflow_handler_busy (struct server_flow *flow) |
||
2966 | { |
||
2967 | ASSERT(flow == dying_server_flow) |
||
2968 | ASSERT(!flow->connected) |
||
2969 | PacketPassFairQueueFlow_AssertFree(&flow->qflow); |
||
2970 | |||
2971 | // finally free flow |
||
2972 | server_flow_free(flow); |
||
2973 | } |
||
2974 | |||
2975 | void server_flow_connect (struct server_flow *flow, PacketRecvInterface *input) |
||
2976 | { |
||
2977 | ASSERT(!flow->connected) |
||
2978 | ASSERT(flow != dying_server_flow) |
||
2979 | |||
2980 | // connect input |
||
2981 | PacketRecvConnector_ConnectInput(&flow->connector, input); |
||
2982 | |||
2983 | // set connected |
||
2984 | flow->connected = 1; |
||
2985 | } |
||
2986 | |||
2987 | void server_flow_disconnect (struct server_flow *flow) |
||
2988 | { |
||
2989 | ASSERT(flow->connected) |
||
2990 | ASSERT(flow != dying_server_flow) |
||
2991 | |||
2992 | // disconnect input |
||
2993 | PacketRecvConnector_DisconnectInput(&flow->connector); |
||
2994 | |||
2995 | // set not connected |
||
2996 | flow->connected = 0; |
||
2997 | } |