aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-01-30 06:10:39 +0100
committerChristian Grothoff <christian@grothoff.org>2019-01-30 06:10:39 +0100
commit31f4c60c63dbd3958da7aac32f81cb20770eab97 (patch)
tree2f26734a1575395113fca3db137b99122e33d793
parent4781fabceb3530e976c27ea37999c8eaa3165612 (diff)
downloadgnunet-31f4c60c63dbd3958da7aac32f81cb20770eab97.tar.gz
gnunet-31f4c60c63dbd3958da7aac32f81cb20770eab97.zip
adding broadcast support
-rw-r--r--src/transport/gnunet-communicator-udp.c391
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 */
589struct 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 */
579static struct GNUNET_CONTAINER_MultiShortmap *key_cache; 643static struct GNUNET_CONTAINER_MultiShortmap *key_cache;
@@ -589,6 +653,11 @@ static struct GNUNET_SCHEDULER_Task *read_task;
589static struct GNUNET_SCHEDULER_Task *timeout_task; 653static struct GNUNET_SCHEDULER_Task *timeout_task;
590 654
591/** 655/**
656 * ID of master broadcast task
657 */
658static struct GNUNET_SCHEDULER_Task *broadcast_task;
659
660/**
592 * For logging statistics. 661 * For logging statistics.
593 */ 662 */
594static struct GNUNET_STATISTICS_Handle *stats; 663static struct GNUNET_STATISTICS_Handle *stats;
@@ -619,10 +688,25 @@ static struct GNUNET_CONTAINER_Heap *senders_heap;
619static struct GNUNET_CONTAINER_Heap *receivers_heap; 688static struct GNUNET_CONTAINER_Heap *receivers_heap;
620 689
621/** 690/**
691 * Broadcast interface tasks. Kept in a DLL.
692 */
693static struct BroadcastInterface *bi_head;
694
695/**
696 * Broadcast interface tasks. Kept in a DLL.
697 */
698static struct BroadcastInterface *bi_tail;
699
700/**
622 * Our socket. 701 * Our socket.
623 */ 702 */
624static struct GNUNET_NETWORK_Handle *udp_sock; 703static struct GNUNET_NETWORK_Handle *udp_sock;
625 704
705/**
706 * #GNUNET_YES if #udp_sock supports IPv6.
707 */
708static 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 */
649static struct GNUNET_NAT_Handle *nat; 733static struct GNUNET_NAT_Handle *nat;
650 734
735/**
736 * Port number to which we are actually bound.
737 */
738static 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 */
746static void
747bi_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 */
2371static void
2372ifc_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 */
2459static int
2460iface_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 */
2573static void
2574do_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,