diff options
-rw-r--r-- | src/nat/gnunet-service-nat.c | 224 |
1 files changed, 216 insertions, 8 deletions
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c index 5ae24c456..bf82ce7eb 100644 --- a/src/nat/gnunet-service-nat.c +++ b/src/nat/gnunet-service-nat.c | |||
@@ -57,6 +57,24 @@ | |||
57 | */ | 57 | */ |
58 | #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | 58 | #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) |
59 | 59 | ||
60 | /** | ||
61 | * How long do we wait until we re-try running `external-ip` if the | ||
62 | * command failed to terminate nicely? | ||
63 | */ | ||
64 | #define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
65 | |||
66 | /** | ||
67 | * How long do we wait until we re-try running `external-ip` if the | ||
68 | * command failed (but terminated)? | ||
69 | */ | ||
70 | #define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) | ||
71 | |||
72 | /** | ||
73 | * How long do we wait until we re-try running `external-ip` if the | ||
74 | * command succeeded? | ||
75 | */ | ||
76 | #define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) | ||
77 | |||
60 | 78 | ||
61 | /** | 79 | /** |
62 | * Internal data structure we track for each of our clients. | 80 | * Internal data structure we track for each of our clients. |
@@ -322,6 +340,22 @@ static struct StunExternalIP *se_tail; | |||
322 | */ | 340 | */ |
323 | static int enable_upnp; | 341 | static int enable_upnp; |
324 | 342 | ||
343 | /** | ||
344 | * Task run to obtain our external IP (if #enable_upnp is set | ||
345 | * and if we find we have a NATed IP address). | ||
346 | */ | ||
347 | static struct GNUNET_SCHEDULER_Task *probe_external_ip_task; | ||
348 | |||
349 | /** | ||
350 | * Handle to our operation to run `external-ip`. | ||
351 | */ | ||
352 | static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op; | ||
353 | |||
354 | /** | ||
355 | * What is our external IP address as claimed by `external-ip`? | ||
356 | * 0 for unknown. | ||
357 | */ | ||
358 | static struct in_addr mini_external_ipv4; | ||
325 | 359 | ||
326 | /** | 360 | /** |
327 | * Free the DLL starting at #lal_head. | 361 | * Free the DLL starting at #lal_head. |
@@ -604,14 +638,14 @@ ifc_proc (void *cls, | |||
604 | * Notify client about a change in the list of addresses this peer | 638 | * Notify client about a change in the list of addresses this peer |
605 | * has. | 639 | * has. |
606 | * | 640 | * |
607 | * @param delta the entry in the list that changed | 641 | * @param ac address class of the entry in the list that changed |
608 | * @param ch client to contact | 642 | * @param ch client to contact |
609 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | 643 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove |
610 | * @param addr the address that changed | 644 | * @param addr the address that changed |
611 | * @param addr_len number of bytes in @a addr | 645 | * @param addr_len number of bytes in @a addr |
612 | */ | 646 | */ |
613 | static void | 647 | static void |
614 | notify_client (struct LocalAddressList *delta, | 648 | notify_client (enum GNUNET_NAT_AddressClass ac, |
615 | struct ClientHandle *ch, | 649 | struct ClientHandle *ch, |
616 | int add, | 650 | int add, |
617 | const void *addr, | 651 | const void *addr, |
@@ -624,7 +658,7 @@ notify_client (struct LocalAddressList *delta, | |||
624 | addr_len, | 658 | addr_len, |
625 | GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); | 659 | GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); |
626 | msg->add_remove = htonl (add); | 660 | msg->add_remove = htonl (add); |
627 | msg->addr_class = htonl (delta->ac); | 661 | msg->addr_class = htonl (ac); |
628 | GNUNET_memcpy (&msg[1], | 662 | GNUNET_memcpy (&msg[1], |
629 | addr, | 663 | addr, |
630 | addr_len); | 664 | addr_len); |
@@ -667,7 +701,7 @@ check_notify_client (struct LocalAddressList *delta, | |||
667 | return; /* IPv4 not relevant */ | 701 | return; /* IPv4 not relevant */ |
668 | c4 = (const struct sockaddr_in *) ch->addrs[i]; | 702 | c4 = (const struct sockaddr_in *) ch->addrs[i]; |
669 | v4.sin_port = c4->sin_port; | 703 | v4.sin_port = c4->sin_port; |
670 | notify_client (delta, | 704 | notify_client (delta->ac, |
671 | ch, | 705 | ch, |
672 | add, | 706 | add, |
673 | &v4, | 707 | &v4, |
@@ -687,7 +721,7 @@ check_notify_client (struct LocalAddressList *delta, | |||
687 | return; /* IPv4 not relevant */ | 721 | return; /* IPv4 not relevant */ |
688 | c6 = (const struct sockaddr_in6 *) ch->addrs[i]; | 722 | c6 = (const struct sockaddr_in6 *) ch->addrs[i]; |
689 | v6.sin6_port = c6->sin6_port; | 723 | v6.sin6_port = c6->sin6_port; |
690 | notify_client (delta, | 724 | notify_client (delta->ac, |
691 | ch, | 725 | ch, |
692 | add, | 726 | add, |
693 | &v6, | 727 | &v6, |
@@ -722,6 +756,142 @@ notify_clients (struct LocalAddressList *delta, | |||
722 | 756 | ||
723 | 757 | ||
724 | /** | 758 | /** |
759 | * Tell relevant client about a change in our external | ||
760 | * IPv4 address. | ||
761 | * | ||
762 | * @param v4 the external address that changed | ||
763 | * @param ch client to check if it cares and possibly notify | ||
764 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
765 | */ | ||
766 | static void | ||
767 | check_notify_client_external_ipv4_change (const struct in_addr *v4, | ||
768 | struct ClientHandle *ch, | ||
769 | int add) | ||
770 | { | ||
771 | struct sockaddr_in sa; | ||
772 | |||
773 | // FIXME: (1) check if client cares; | ||
774 | GNUNET_break (0); // FIXME: implement! | ||
775 | |||
776 | /* (2) figure out external port, build sockaddr */ | ||
777 | memset (&sa, | ||
778 | 0, | ||
779 | sizeof (sa)); | ||
780 | sa.sin_family = AF_INET; | ||
781 | sa.sin_addr = *v4; | ||
782 | sa.sin_port = 42; // FIXME | ||
783 | |||
784 | /* (3) notify client of change */ | ||
785 | |||
786 | // FIXME: handle case where 'v4' is still in the NAT range | ||
787 | // (in case of double-NAT!) | ||
788 | notify_client (GNUNET_NAT_AC_GLOBAL_EXTERN, | ||
789 | ch, | ||
790 | add, | ||
791 | &sa, | ||
792 | sizeof (sa)); | ||
793 | } | ||
794 | |||
795 | |||
796 | /** | ||
797 | * Tell relevant clients about a change in our external | ||
798 | * IPv4 address. | ||
799 | * | ||
800 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
801 | * @param v4 the external address that changed | ||
802 | */ | ||
803 | static void | ||
804 | notify_clients_external_ipv4_change (int add, | ||
805 | const struct in_addr *v4) | ||
806 | { | ||
807 | for (struct ClientHandle *ch = ch_head; | ||
808 | NULL != ch; | ||
809 | ch = ch->next) | ||
810 | check_notify_client_external_ipv4_change (v4, | ||
811 | ch, | ||
812 | add); | ||
813 | } | ||
814 | |||
815 | |||
816 | /** | ||
817 | * Task used to run `external-ip` to get our external IPv4 | ||
818 | * address and pass it to NATed clients if possible. | ||
819 | * | ||
820 | * @param cls NULL | ||
821 | */ | ||
822 | static void | ||
823 | run_external_ip (void *cls); | ||
824 | |||
825 | |||
826 | /** | ||
827 | * We learn our current external IP address. If it changed, | ||
828 | * notify all of our applicable clients. Also re-schedule | ||
829 | * #run_external_ip with an appropriate timeout. | ||
830 | * | ||
831 | * @param cls NULL | ||
832 | * @param addr the address, NULL on errors | ||
833 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code | ||
834 | */ | ||
835 | static void | ||
836 | handle_external_ip (void *cls, | ||
837 | const struct in_addr *addr, | ||
838 | enum GNUNET_NAT_StatusCode result) | ||
839 | { | ||
840 | probe_external_ip_op = NULL; | ||
841 | GNUNET_SCHEDULER_cancel (probe_external_ip_task); | ||
842 | probe_external_ip_task | ||
843 | = GNUNET_SCHEDULER_add_delayed ((NULL == addr) | ||
844 | ? EXTERN_IP_RETRY_FAILURE | ||
845 | : EXTERN_IP_RETRY_SUCCESS, | ||
846 | &run_external_ip, | ||
847 | NULL); | ||
848 | switch (result) | ||
849 | { | ||
850 | case GNUNET_NAT_ERROR_SUCCESS: | ||
851 | if (addr->s_addr == mini_external_ipv4.s_addr) | ||
852 | return; /* not change */ | ||
853 | if (0 != mini_external_ipv4.s_addr) | ||
854 | notify_clients_external_ipv4_change (GNUNET_NO, | ||
855 | &mini_external_ipv4); | ||
856 | mini_external_ipv4 = *addr; | ||
857 | notify_clients_external_ipv4_change (GNUNET_YES, | ||
858 | &mini_external_ipv4); | ||
859 | break; | ||
860 | default: | ||
861 | if (0 != mini_external_ipv4.s_addr) | ||
862 | notify_clients_external_ipv4_change (GNUNET_NO, | ||
863 | &mini_external_ipv4); | ||
864 | mini_external_ipv4.s_addr = 0; | ||
865 | break; | ||
866 | } | ||
867 | } | ||
868 | |||
869 | |||
870 | /** | ||
871 | * Task used to run `external-ip` to get our external IPv4 | ||
872 | * address and pass it to NATed clients if possible. | ||
873 | * | ||
874 | * @param cls NULL | ||
875 | */ | ||
876 | static void | ||
877 | run_external_ip (void *cls) | ||
878 | { | ||
879 | probe_external_ip_task | ||
880 | = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT, | ||
881 | &run_external_ip, | ||
882 | NULL); | ||
883 | if (NULL != probe_external_ip_op) | ||
884 | { | ||
885 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op); | ||
886 | probe_external_ip_op = NULL; | ||
887 | } | ||
888 | probe_external_ip_op | ||
889 | = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip, | ||
890 | NULL); | ||
891 | } | ||
892 | |||
893 | |||
894 | /** | ||
725 | * Task we run periodically to scan for network interfaces. | 895 | * Task we run periodically to scan for network interfaces. |
726 | * | 896 | * |
727 | * @param cls NULL | 897 | * @param cls NULL |
@@ -731,6 +901,7 @@ run_scan (void *cls) | |||
731 | { | 901 | { |
732 | struct IfcProcContext ifc_ctx; | 902 | struct IfcProcContext ifc_ctx; |
733 | int found; | 903 | int found; |
904 | int have_nat; | ||
734 | 905 | ||
735 | scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ, | 906 | scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ, |
736 | &run_scan, | 907 | &run_scan, |
@@ -764,11 +935,14 @@ run_scan (void *cls) | |||
764 | } | 935 | } |
765 | 936 | ||
766 | /* add addresses that appeared */ | 937 | /* add addresses that appeared */ |
938 | have_nat = GNUNET_NO; | ||
767 | for (struct LocalAddressList *pos = ifc_ctx.lal_head; | 939 | for (struct LocalAddressList *pos = ifc_ctx.lal_head; |
768 | NULL != pos; | 940 | NULL != pos; |
769 | pos = pos->next) | 941 | pos = pos->next) |
770 | { | 942 | { |
771 | found = GNUNET_NO; | 943 | found = GNUNET_NO; |
944 | if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac)) | ||
945 | have_nat = GNUNET_YES; | ||
772 | for (struct LocalAddressList *lal = lal_head; | 946 | for (struct LocalAddressList *lal = lal_head; |
773 | NULL != lal; | 947 | NULL != lal; |
774 | lal = lal->next) | 948 | lal = lal->next) |
@@ -785,7 +959,30 @@ run_scan (void *cls) | |||
785 | notify_clients (pos, | 959 | notify_clients (pos, |
786 | GNUNET_YES); | 960 | GNUNET_YES); |
787 | } | 961 | } |
788 | 962 | if ( (GNUNET_YES == have_nat) && | |
963 | (GNUNET_YES == enable_upnp) && | ||
964 | (NULL == probe_external_ip_task) && | ||
965 | (NULL == probe_external_ip_op) ) | ||
966 | { | ||
967 | probe_external_ip_task | ||
968 | = GNUNET_SCHEDULER_add_now (&run_external_ip, | ||
969 | NULL); | ||
970 | } | ||
971 | if ( (GNUNET_NO == have_nat) && | ||
972 | (GNUNET_YES == enable_upnp) ) | ||
973 | { | ||
974 | if (NULL != probe_external_ip_task) | ||
975 | { | ||
976 | GNUNET_SCHEDULER_cancel (probe_external_ip_task); | ||
977 | probe_external_ip_task = NULL; | ||
978 | } | ||
979 | if (NULL != probe_external_ip_op) | ||
980 | { | ||
981 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op); | ||
982 | probe_external_ip_op = NULL; | ||
983 | } | ||
984 | } | ||
985 | |||
789 | destroy_lal (); | 986 | destroy_lal (); |
790 | lal_head = ifc_ctx.lal_head; | 987 | lal_head = ifc_ctx.lal_head; |
791 | lal_tail = ifc_ctx.lal_tail; | 988 | lal_tail = ifc_ctx.lal_tail; |
@@ -882,6 +1079,13 @@ handle_register (void *cls, | |||
882 | ch, | 1079 | ch, |
883 | GNUNET_YES); | 1080 | GNUNET_YES); |
884 | } | 1081 | } |
1082 | /* Also consider IPv4 determined by `external-ip` */ | ||
1083 | if (0 != mini_external_ipv4.s_addr) | ||
1084 | { | ||
1085 | check_notify_client_external_ipv4_change (&mini_external_ipv4, | ||
1086 | ch, | ||
1087 | GNUNET_YES); | ||
1088 | } | ||
885 | GNUNET_SERVICE_client_continue (ch->client); | 1089 | GNUNET_SERVICE_client_continue (ch->client); |
886 | } | 1090 | } |
887 | 1091 | ||
@@ -1318,13 +1522,13 @@ update_enable_upnpc_option (struct AutoconfigContext *ac) | |||
1318 | case GNUNET_YES: | 1522 | case GNUNET_YES: |
1319 | GNUNET_CONFIGURATION_set_value_string (ac->c, | 1523 | GNUNET_CONFIGURATION_set_value_string (ac->c, |
1320 | "NAT", | 1524 | "NAT", |
1321 | "ENABLE_UPNPC", | 1525 | "ENABLE_UPNP", |
1322 | "YES"); | 1526 | "YES"); |
1323 | break; | 1527 | break; |
1324 | case GNUNET_NO: | 1528 | case GNUNET_NO: |
1325 | GNUNET_CONFIGURATION_set_value_string (ac->c, | 1529 | GNUNET_CONFIGURATION_set_value_string (ac->c, |
1326 | "NAT", | 1530 | "NAT", |
1327 | "ENABLE_UPNPC", | 1531 | "ENABLE_UPNP", |
1328 | "NO"); | 1532 | "NO"); |
1329 | break; | 1533 | break; |
1330 | case GNUNET_SYSERR: | 1534 | case GNUNET_SYSERR: |
@@ -1358,6 +1562,9 @@ auto_external_result_cb (void *cls, | |||
1358 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID: | 1562 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID: |
1359 | case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID: | 1563 | case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID: |
1360 | case GNUNET_NAT_ERROR_IPC_FAILURE: | 1564 | case GNUNET_NAT_ERROR_IPC_FAILURE: |
1565 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1566 | "Disabling UPNPC: %d\n", | ||
1567 | (int) result); | ||
1361 | ac->enable_upnpc = GNUNET_NO; /* did not work */ | 1568 | ac->enable_upnpc = GNUNET_NO; /* did not work */ |
1362 | break; | 1569 | break; |
1363 | default: | 1570 | default: |
@@ -1387,6 +1594,7 @@ handle_autoconfig_request (void *cls, | |||
1387 | struct AutoconfigContext *ac; | 1594 | struct AutoconfigContext *ac; |
1388 | 1595 | ||
1389 | ac = GNUNET_new (struct AutoconfigContext); | 1596 | ac = GNUNET_new (struct AutoconfigContext); |
1597 | ac->status_code = GNUNET_NAT_ERROR_SUCCESS; | ||
1390 | ac->ch = ch; | 1598 | ac->ch = ch; |
1391 | ac->c = GNUNET_CONFIGURATION_create (); | 1599 | ac->c = GNUNET_CONFIGURATION_create (); |
1392 | if (GNUNET_OK != | 1600 | if (GNUNET_OK != |