diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-01-30 06:10:39 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-01-30 06:10:39 +0100 |
commit | 31f4c60c63dbd3958da7aac32f81cb20770eab97 (patch) | |
tree | 2f26734a1575395113fca3db137b99122e33d793 /src/transport | |
parent | 4781fabceb3530e976c27ea37999c8eaa3165612 (diff) | |
download | gnunet-31f4c60c63dbd3958da7aac32f81cb20770eab97.tar.gz gnunet-31f4c60c63dbd3958da7aac32f81cb20770eab97.zip |
adding broadcast support
Diffstat (limited to 'src/transport')
-rw-r--r-- | src/transport/gnunet-communicator-udp.c | 391 |
1 files changed, 388 insertions, 3 deletions
diff --git a/src/transport/gnunet-communicator-udp.c b/src/transport/gnunet-communicator-udp.c index d464cd0d1..bbfe2ebec 100644 --- a/src/transport/gnunet-communicator-udp.c +++ b/src/transport/gnunet-communicator-udp.c | |||
@@ -34,7 +34,7 @@ | |||
34 | * - add and use util/ check for IPv6 availability (#V6) | 34 | * - add and use util/ check for IPv6 availability (#V6) |
35 | * - consider imposing transmission limits in the absence | 35 | * - consider imposing transmission limits in the absence |
36 | * of ACKs; or: maybe this should be done at TNG service level? | 36 | * of ACKs; or: maybe this should be done at TNG service level? |
37 | * - support broadcasting for neighbour discovery (#) | 37 | * - handle addresses discovered fro broadcasts (#) |
38 | * (think: what was the story again on address validation? | 38 | * (think: what was the story again on address validation? |
39 | * where is the API for that!?!) | 39 | * where is the API for that!?!) |
40 | * - support DNS names in BINDTO option (#5528) | 40 | * - support DNS names in BINDTO option (#5528) |
@@ -62,6 +62,16 @@ | |||
62 | #define PROTO_QUEUE_TIMEOUT GNUNET_TIME_UNIT_MINUTES | 62 | #define PROTO_QUEUE_TIMEOUT GNUNET_TIME_UNIT_MINUTES |
63 | 63 | ||
64 | /** | 64 | /** |
65 | * How often do we broadcast our presence on the LAN? | ||
66 | */ | ||
67 | #define BROADCAST_FREQUENCY GNUNET_TIME_UNIT_MINUTES | ||
68 | |||
69 | /** | ||
70 | * How often do we scan for changes to our network interfaces? | ||
71 | */ | ||
72 | #define INTERFACE_SCAN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) | ||
73 | |||
74 | /** | ||
65 | * AES key size. | 75 | * AES key size. |
66 | */ | 76 | */ |
67 | #define AES_KEY_SIZE (256/8) | 77 | #define AES_KEY_SIZE (256/8) |
@@ -574,6 +584,60 @@ struct ReceiverAddress | |||
574 | 584 | ||
575 | 585 | ||
576 | /** | 586 | /** |
587 | * Interface we broadcast our presence on. | ||
588 | */ | ||
589 | struct BroadcastInterface | ||
590 | { | ||
591 | |||
592 | /** | ||
593 | * Kept in a DLL. | ||
594 | */ | ||
595 | struct BroadcastInterface *next; | ||
596 | |||
597 | /** | ||
598 | * Kept in a DLL. | ||
599 | */ | ||
600 | struct BroadcastInterface *prev; | ||
601 | |||
602 | /** | ||
603 | * Task for this broadcast interface. | ||
604 | */ | ||
605 | struct GNUNET_SCHEDULER_Task *broadcast_task; | ||
606 | |||
607 | /** | ||
608 | * Sender's address of the interface. | ||
609 | */ | ||
610 | struct sockaddr *sa; | ||
611 | |||
612 | /** | ||
613 | * Broadcast address to use on the interface. | ||
614 | */ | ||
615 | struct sockaddr *ba; | ||
616 | |||
617 | /** | ||
618 | * Message we broadcast on this interface. | ||
619 | */ | ||
620 | struct UDPBroadcast bcm; | ||
621 | |||
622 | /** | ||
623 | * If this is an IPv6 interface, this is the request | ||
624 | * we use to join/leave the group. | ||
625 | */ | ||
626 | struct ipv6_mreq mcreq; | ||
627 | |||
628 | /** | ||
629 | * Number of bytes in @e sa. | ||
630 | */ | ||
631 | socklen_t salen; | ||
632 | |||
633 | /** | ||
634 | * Was this interface found in the last #iface_proc() scan? | ||
635 | */ | ||
636 | int found; | ||
637 | }; | ||
638 | |||
639 | |||
640 | /** | ||
577 | * Cache of pre-generated key IDs. | 641 | * Cache of pre-generated key IDs. |
578 | */ | 642 | */ |
579 | static struct GNUNET_CONTAINER_MultiShortmap *key_cache; | 643 | static struct GNUNET_CONTAINER_MultiShortmap *key_cache; |
@@ -589,6 +653,11 @@ static struct GNUNET_SCHEDULER_Task *read_task; | |||
589 | static struct GNUNET_SCHEDULER_Task *timeout_task; | 653 | static struct GNUNET_SCHEDULER_Task *timeout_task; |
590 | 654 | ||
591 | /** | 655 | /** |
656 | * ID of master broadcast task | ||
657 | */ | ||
658 | static struct GNUNET_SCHEDULER_Task *broadcast_task; | ||
659 | |||
660 | /** | ||
592 | * For logging statistics. | 661 | * For logging statistics. |
593 | */ | 662 | */ |
594 | static struct GNUNET_STATISTICS_Handle *stats; | 663 | static struct GNUNET_STATISTICS_Handle *stats; |
@@ -619,10 +688,25 @@ static struct GNUNET_CONTAINER_Heap *senders_heap; | |||
619 | static struct GNUNET_CONTAINER_Heap *receivers_heap; | 688 | static struct GNUNET_CONTAINER_Heap *receivers_heap; |
620 | 689 | ||
621 | /** | 690 | /** |
691 | * Broadcast interface tasks. Kept in a DLL. | ||
692 | */ | ||
693 | static struct BroadcastInterface *bi_head; | ||
694 | |||
695 | /** | ||
696 | * Broadcast interface tasks. Kept in a DLL. | ||
697 | */ | ||
698 | static struct BroadcastInterface *bi_tail; | ||
699 | |||
700 | /** | ||
622 | * Our socket. | 701 | * Our socket. |
623 | */ | 702 | */ |
624 | static struct GNUNET_NETWORK_Handle *udp_sock; | 703 | static struct GNUNET_NETWORK_Handle *udp_sock; |
625 | 704 | ||
705 | /** | ||
706 | * #GNUNET_YES if #udp_sock supports IPv6. | ||
707 | */ | ||
708 | static int have_v6_socket; | ||
709 | |||
626 | /** | 710 | /** |
627 | * Our public key. | 711 | * Our public key. |
628 | */ | 712 | */ |
@@ -648,10 +732,47 @@ static struct GNUNET_NT_InterfaceScanner *is; | |||
648 | */ | 732 | */ |
649 | static struct GNUNET_NAT_Handle *nat; | 733 | static struct GNUNET_NAT_Handle *nat; |
650 | 734 | ||
735 | /** | ||
736 | * Port number to which we are actually bound. | ||
737 | */ | ||
738 | static uint16_t my_port; | ||
739 | |||
651 | 740 | ||
652 | /** | 741 | /** |
653 | * Functions with this signature are called whenever we need | 742 | * An interface went away, stop broadcasting on it. |
654 | * to close a receiving state due to timeout. | 743 | * |
744 | * @param bi entity to close down | ||
745 | */ | ||
746 | static void | ||
747 | bi_destroy (struct BroadcastInterface *bi) | ||
748 | { | ||
749 | if (AF_INET6 == bi->sa->sa_family) | ||
750 | { | ||
751 | /* Leave the multicast group */ | ||
752 | if (GNUNET_OK != | ||
753 | GNUNET_NETWORK_socket_setsockopt | ||
754 | (udp_sock, | ||
755 | IPPROTO_IPV6, | ||
756 | IPV6_LEAVE_GROUP, | ||
757 | &bi->mcreq, | ||
758 | sizeof (bi->mcreq))) | ||
759 | { | ||
760 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
761 | "setsockopt"); | ||
762 | } | ||
763 | } | ||
764 | GNUNET_CONTAINER_DLL_remove (bi_head, | ||
765 | bi_tail, | ||
766 | bi); | ||
767 | GNUNET_SCHEDULER_cancel (bi->broadcast_task); | ||
768 | GNUNET_free (bi->sa); | ||
769 | GNUNET_free_non_null (bi->ba); | ||
770 | GNUNET_free (bi); | ||
771 | } | ||
772 | |||
773 | |||
774 | /** | ||
775 | * Destroys a receiving state due to timeout or shutdown. | ||
655 | * | 776 | * |
656 | * @param receiver entity to close down | 777 | * @param receiver entity to close down |
657 | */ | 778 | */ |
@@ -2106,6 +2227,13 @@ do_shutdown (void *cls) | |||
2106 | GNUNET_NAT_unregister (nat); | 2227 | GNUNET_NAT_unregister (nat); |
2107 | nat = NULL; | 2228 | nat = NULL; |
2108 | } | 2229 | } |
2230 | while (NULL != bi_head) | ||
2231 | bi_destroy (bi_head); | ||
2232 | if (NULL != broadcast_task) | ||
2233 | { | ||
2234 | GNUNET_SCHEDULER_cancel (broadcast_task); | ||
2235 | broadcast_task = NULL; | ||
2236 | } | ||
2109 | if (NULL != read_task) | 2237 | if (NULL != read_task) |
2110 | { | 2238 | { |
2111 | GNUNET_SCHEDULER_cancel (read_task); | 2239 | GNUNET_SCHEDULER_cancel (read_task); |
@@ -2236,6 +2364,240 @@ nat_address_cb (void *cls, | |||
2236 | 2364 | ||
2237 | 2365 | ||
2238 | /** | 2366 | /** |
2367 | * Broadcast our presence on one of our interfaces. | ||
2368 | * | ||
2369 | * @param cls a `struct BroadcastInterface` | ||
2370 | */ | ||
2371 | static void | ||
2372 | ifc_broadcast (void *cls) | ||
2373 | { | ||
2374 | struct BroadcastInterface *bi = cls; | ||
2375 | struct GNUNET_TIME_Relative delay; | ||
2376 | |||
2377 | delay = BROADCAST_FREQUENCY; | ||
2378 | delay.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
2379 | delay.rel_value_us); | ||
2380 | bi->broadcast_task | ||
2381 | = GNUNET_SCHEDULER_add_delayed (INTERFACE_SCAN_FREQUENCY, | ||
2382 | &ifc_broadcast, | ||
2383 | bi); | ||
2384 | |||
2385 | switch (bi->sa->sa_family) { | ||
2386 | case AF_INET: | ||
2387 | { | ||
2388 | static int yes = 1; | ||
2389 | static int no = 0; | ||
2390 | ssize_t sent; | ||
2391 | |||
2392 | if (GNUNET_OK != | ||
2393 | GNUNET_NETWORK_socket_setsockopt (udp_sock, | ||
2394 | SOL_SOCKET, | ||
2395 | SO_BROADCAST, | ||
2396 | &yes, | ||
2397 | sizeof (int))) | ||
2398 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
2399 | "setsockopt"); | ||
2400 | sent = GNUNET_NETWORK_socket_sendto (udp_sock, | ||
2401 | &bi->bcm, | ||
2402 | sizeof (bi->bcm), | ||
2403 | bi->ba, | ||
2404 | bi->salen); | ||
2405 | if (-1 == sent) | ||
2406 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
2407 | "sendto"); | ||
2408 | if (GNUNET_OK != | ||
2409 | GNUNET_NETWORK_socket_setsockopt (udp_sock, | ||
2410 | SOL_SOCKET, | ||
2411 | SO_BROADCAST, | ||
2412 | &no, | ||
2413 | sizeof (int))) | ||
2414 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
2415 | "setsockopt"); | ||
2416 | break; | ||
2417 | } | ||
2418 | case AF_INET6: | ||
2419 | { | ||
2420 | ssize_t sent; | ||
2421 | struct sockaddr_in6 dst; | ||
2422 | |||
2423 | dst.sin6_family = AF_INET6; | ||
2424 | dst.sin6_port = htons (my_port); | ||
2425 | dst.sin6_addr = bi->mcreq.ipv6mr_multiaddr; | ||
2426 | dst.sin6_scope_id = ((struct sockaddr_in6*) bi->ba)->sin6_scope_id; | ||
2427 | |||
2428 | sent = GNUNET_NETWORK_socket_sendto (udp_sock, | ||
2429 | &bi->bcm, | ||
2430 | sizeof (bi->bcm), | ||
2431 | (const struct sockaddr *) | ||
2432 | &dst, | ||
2433 | sizeof (dst)); | ||
2434 | if (-1 == sent) | ||
2435 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
2436 | "sendto"); | ||
2437 | break; | ||
2438 | } | ||
2439 | default: | ||
2440 | GNUNET_break (0); | ||
2441 | break; | ||
2442 | } | ||
2443 | } | ||
2444 | |||
2445 | |||
2446 | /** | ||
2447 | * Callback function invoked for each interface found. | ||
2448 | * Activates/deactivates broadcast interfaces. | ||
2449 | * | ||
2450 | * @param cls NULL | ||
2451 | * @param name name of the interface (can be NULL for unknown) | ||
2452 | * @param isDefault is this presumably the default interface | ||
2453 | * @param addr address of this interface (can be NULL for unknown or unassigned) | ||
2454 | * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) | ||
2455 | * @param netmask the network mask (can be NULL for unknown or unassigned) | ||
2456 | * @param addrlen length of the address | ||
2457 | * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort | ||
2458 | */ | ||
2459 | static int | ||
2460 | iface_proc (void *cls, | ||
2461 | const char *name, | ||
2462 | int isDefault, | ||
2463 | const struct sockaddr *addr, | ||
2464 | const struct sockaddr *broadcast_addr, | ||
2465 | const struct sockaddr *netmask, socklen_t addrlen) | ||
2466 | { | ||
2467 | struct BroadcastInterface *bi; | ||
2468 | enum GNUNET_NetworkType network; | ||
2469 | struct UdpBroadcastSignature ubs; | ||
2470 | |||
2471 | (void) cls; | ||
2472 | (void) netmask; | ||
2473 | network = GNUNET_NT_scanner_get_type (is, | ||
2474 | addr, | ||
2475 | addrlen); | ||
2476 | if (GNUNET_NT_LOOPBACK == network) | ||
2477 | { | ||
2478 | /* Broadcasting on loopback does not make sense */ | ||
2479 | return GNUNET_YES; | ||
2480 | } | ||
2481 | if (NULL == addr) | ||
2482 | return GNUNET_YES; /* need to know our address! */ | ||
2483 | for (bi = bi_head; NULL != bi; bi = bi->next) | ||
2484 | { | ||
2485 | if ( (bi->salen == addrlen) && | ||
2486 | (0 == memcmp (addr, | ||
2487 | bi->sa, | ||
2488 | addrlen)) ) | ||
2489 | { | ||
2490 | bi->found = GNUNET_YES; | ||
2491 | return GNUNET_OK; | ||
2492 | } | ||
2493 | } | ||
2494 | |||
2495 | if ( (AF_INET6 == addr->sa_family) && | ||
2496 | (NULL == broadcast_addr) ) | ||
2497 | return GNUNET_OK; /* broadcast_addr is required for IPv6! */ | ||
2498 | if ( (AF_INET6 == addr->sa_family) && | ||
2499 | (GNUNET_YES != have_v6_socket) ) | ||
2500 | return GNUNET_OK; /* not using IPv6 */ | ||
2501 | |||
2502 | bi = GNUNET_new (struct BroadcastInterface); | ||
2503 | bi->sa = GNUNET_memdup (addr, | ||
2504 | addrlen); | ||
2505 | if (NULL != broadcast_addr) | ||
2506 | bi->ba = GNUNET_memdup (broadcast_addr, | ||
2507 | addrlen); | ||
2508 | bi->salen = addrlen; | ||
2509 | bi->found = GNUNET_YES; | ||
2510 | bi->bcm.sender = my_identity; | ||
2511 | ubs.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_UDP_BROADCAST); | ||
2512 | ubs.purpose.size = htonl (sizeof (ubs)); | ||
2513 | ubs.sender = my_identity; | ||
2514 | GNUNET_CRYPTO_hash (addr, | ||
2515 | addrlen, | ||
2516 | &ubs.h_address); | ||
2517 | GNUNET_assert (GNUNET_OK == | ||
2518 | GNUNET_CRYPTO_eddsa_sign (my_private_key, | ||
2519 | &ubs.purpose, | ||
2520 | &bi->bcm.sender_sig)); | ||
2521 | bi->broadcast_task = GNUNET_SCHEDULER_add_now (&ifc_broadcast, | ||
2522 | bi); | ||
2523 | GNUNET_CONTAINER_DLL_insert (bi_head, | ||
2524 | bi_tail, | ||
2525 | bi); | ||
2526 | if ( (AF_INET6 == addr->sa_family) && | ||
2527 | (NULL != broadcast_addr) ) | ||
2528 | { | ||
2529 | /* Create IPv6 multicast request */ | ||
2530 | const struct sockaddr_in6 *s6 | ||
2531 | = (const struct sockaddr_in6 *) broadcast_addr; | ||
2532 | |||
2533 | GNUNET_assert (1 == | ||
2534 | inet_pton (AF_INET6, | ||
2535 | "FF05::13B", | ||
2536 | &bi->mcreq.ipv6mr_multiaddr)); | ||
2537 | |||
2538 | /* http://tools.ietf.org/html/rfc2553#section-5.2: | ||
2539 | * | ||
2540 | * IPV6_JOIN_GROUP | ||
2541 | * | ||
2542 | * Join a multicast group on a specified local interface. If the | ||
2543 | * interface index is specified as 0, the kernel chooses the local | ||
2544 | * interface. For example, some kernels look up the multicast | ||
2545 | * group in the normal IPv6 routing table and using the resulting | ||
2546 | * interface; we do this for each interface, so no need to use | ||
2547 | * zero (anymore...). | ||
2548 | */ | ||
2549 | bi->mcreq.ipv6mr_interface = s6->sin6_scope_id; | ||
2550 | |||
2551 | /* Join the multicast group */ | ||
2552 | if (GNUNET_OK != | ||
2553 | GNUNET_NETWORK_socket_setsockopt | ||
2554 | (udp_sock, | ||
2555 | IPPROTO_IPV6, | ||
2556 | IPV6_JOIN_GROUP, | ||
2557 | &bi->mcreq, | ||
2558 | sizeof (bi->mcreq))) | ||
2559 | { | ||
2560 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
2561 | "setsockopt"); | ||
2562 | } | ||
2563 | } | ||
2564 | return GNUNET_OK; | ||
2565 | } | ||
2566 | |||
2567 | |||
2568 | /** | ||
2569 | * Scan interfaces to broadcast our presence on the LAN. | ||
2570 | * | ||
2571 | * @param cls NULL, unused | ||
2572 | */ | ||
2573 | static void | ||
2574 | do_broadcast (void *cls) | ||
2575 | { | ||
2576 | struct BroadcastInterface *bin; | ||
2577 | |||
2578 | (void) cls; | ||
2579 | for (struct BroadcastInterface *bi = bi_head; | ||
2580 | NULL != bi; | ||
2581 | bi = bi->next) | ||
2582 | bi->found = GNUNET_NO; | ||
2583 | GNUNET_OS_network_interfaces_list (&iface_proc, | ||
2584 | NULL); | ||
2585 | for (struct BroadcastInterface *bi = bi_head; | ||
2586 | NULL != bi; | ||
2587 | bi = bin) | ||
2588 | { | ||
2589 | bin = bi->next; | ||
2590 | if (GNUNET_NO == bi->found) | ||
2591 | bi_destroy (bi); | ||
2592 | } | ||
2593 | broadcast_task | ||
2594 | = GNUNET_SCHEDULER_add_delayed (INTERFACE_SCAN_FREQUENCY, | ||
2595 | &do_broadcast, | ||
2596 | NULL); | ||
2597 | } | ||
2598 | |||
2599 | |||
2600 | /** | ||
2239 | * Setup communicator and launch network interactions. | 2601 | * Setup communicator and launch network interactions. |
2240 | * | 2602 | * |
2241 | * @param cls NULL (always) | 2603 | * @param cls NULL (always) |
@@ -2290,6 +2652,8 @@ run (void *cls, | |||
2290 | GNUNET_free (bindto); | 2652 | GNUNET_free (bindto); |
2291 | return; | 2653 | return; |
2292 | } | 2654 | } |
2655 | if (AF_INET6 == in->sa_family) | ||
2656 | have_v6_socket = GNUNET_YES; | ||
2293 | if (GNUNET_OK != | 2657 | if (GNUNET_OK != |
2294 | GNUNET_NETWORK_socket_bind (udp_sock, | 2658 | GNUNET_NETWORK_socket_bind (udp_sock, |
2295 | in, | 2659 | in, |
@@ -2324,6 +2688,18 @@ run (void *cls, | |||
2324 | "Bound to `%s'\n", | 2688 | "Bound to `%s'\n", |
2325 | GNUNET_a2s ((const struct sockaddr *) &in_sto, | 2689 | GNUNET_a2s ((const struct sockaddr *) &in_sto, |
2326 | sto_len)); | 2690 | sto_len)); |
2691 | switch (in->sa_family) | ||
2692 | { | ||
2693 | case AF_INET: | ||
2694 | my_port = ntohs (((struct sockaddr_in *) in)->sin_port); | ||
2695 | break; | ||
2696 | case AF_INET6: | ||
2697 | my_port = ntohs (((struct sockaddr_in6 *) in)->sin6_port); | ||
2698 | break; | ||
2699 | default: | ||
2700 | GNUNET_break (0); | ||
2701 | my_port = 0; | ||
2702 | } | ||
2327 | stats = GNUNET_STATISTICS_create ("C-UDP", | 2703 | stats = GNUNET_STATISTICS_create ("C-UDP", |
2328 | cfg); | 2704 | cfg); |
2329 | senders = GNUNET_CONTAINER_multipeermap_create (32, | 2705 | senders = GNUNET_CONTAINER_multipeermap_create (32, |
@@ -2366,6 +2742,15 @@ run (void *cls, | |||
2366 | GNUNET_SCHEDULER_shutdown (); | 2742 | GNUNET_SCHEDULER_shutdown (); |
2367 | return; | 2743 | return; |
2368 | } | 2744 | } |
2745 | /* start broadcasting */ | ||
2746 | if (GNUNET_YES != | ||
2747 | GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
2748 | COMMUNICATOR_CONFIG_SECTION, | ||
2749 | "DISABLE_BROADCAST")) | ||
2750 | { | ||
2751 | broadcast_task = GNUNET_SCHEDULER_add_now (&do_broadcast, | ||
2752 | NULL); | ||
2753 | } | ||
2369 | nat = GNUNET_NAT_register (cfg, | 2754 | nat = GNUNET_NAT_register (cfg, |
2370 | COMMUNICATOR_CONFIG_SECTION, | 2755 | COMMUNICATOR_CONFIG_SECTION, |
2371 | IPPROTO_UDP, | 2756 | IPPROTO_UDP, |