diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-12-18 07:35:34 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-12-18 07:35:34 +0100 |
commit | 605227ee99846471196e222c6c25cafbe0a64232 (patch) | |
tree | c8e018743aeca724111fac8ca5c544984ce303eb /src/nat | |
parent | bc4a5aeac8a6f1a1d25b118a26233d4fe7d23741 (diff) | |
download | gnunet-605227ee99846471196e222c6c25cafbe0a64232.tar.gz gnunet-605227ee99846471196e222c6c25cafbe0a64232.zip |
properly process external IP addresses from upnpc-based hole punching
Diffstat (limited to 'src/nat')
-rw-r--r-- | src/nat/gnunet-service-nat.c | 160 | ||||
-rw-r--r-- | src/nat/gnunet-service-nat_mini.c | 21 |
2 files changed, 147 insertions, 34 deletions
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c index 215c4218f..29df27108 100644 --- a/src/nat/gnunet-service-nat.c +++ b/src/nat/gnunet-service-nat.c | |||
@@ -77,6 +77,26 @@ | |||
77 | 77 | ||
78 | 78 | ||
79 | /** | 79 | /** |
80 | * Information we track per client address. | ||
81 | */ | ||
82 | struct ClientAddress | ||
83 | { | ||
84 | /** | ||
85 | * Network address used by the client. | ||
86 | */ | ||
87 | struct sockaddr_storage ss; | ||
88 | |||
89 | /** | ||
90 | * Handle to active UPnP request where we asked upnpc to open | ||
91 | * a port at the NAT. NULL if we do not have such a request | ||
92 | * pending. | ||
93 | */ | ||
94 | struct GNUNET_NAT_MiniHandle *mh; | ||
95 | |||
96 | }; | ||
97 | |||
98 | |||
99 | /** | ||
80 | * Internal data structure we track for each of our clients. | 100 | * Internal data structure we track for each of our clients. |
81 | */ | 101 | */ |
82 | struct ClientHandle | 102 | struct ClientHandle |
@@ -105,7 +125,7 @@ struct ClientHandle | |||
105 | /** | 125 | /** |
106 | * Array of addresses used by the service. | 126 | * Array of addresses used by the service. |
107 | */ | 127 | */ |
108 | struct sockaddr **addrs; | 128 | struct ClientAddress *caddrs; |
109 | 129 | ||
110 | /** | 130 | /** |
111 | * What does this client care about? | 131 | * What does this client care about? |
@@ -113,7 +133,7 @@ struct ClientHandle | |||
113 | enum GNUNET_NAT_RegisterFlags flags; | 133 | enum GNUNET_NAT_RegisterFlags flags; |
114 | 134 | ||
115 | /** | 135 | /** |
116 | * Is any of the @e addrs in a reserved subnet for NAT? | 136 | * Is any of the @e caddrs in a reserved subnet for NAT? |
117 | */ | 137 | */ |
118 | int natted_address; | 138 | int natted_address; |
119 | 139 | ||
@@ -125,8 +145,9 @@ struct ClientHandle | |||
125 | 145 | ||
126 | /** | 146 | /** |
127 | * Number of addresses that this service is bound to. | 147 | * Number of addresses that this service is bound to. |
148 | * Length of the @e caddrs array. | ||
128 | */ | 149 | */ |
129 | uint16_t num_addrs; | 150 | uint16_t num_caddrs; |
130 | 151 | ||
131 | /** | 152 | /** |
132 | * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP. | 153 | * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP. |
@@ -357,6 +378,7 @@ static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op; | |||
357 | */ | 378 | */ |
358 | static struct in_addr mini_external_ipv4; | 379 | static struct in_addr mini_external_ipv4; |
359 | 380 | ||
381 | |||
360 | /** | 382 | /** |
361 | * Free the DLL starting at #lal_head. | 383 | * Free the DLL starting at #lal_head. |
362 | */ | 384 | */ |
@@ -693,13 +715,13 @@ check_notify_client (struct LocalAddressList *delta, | |||
693 | GNUNET_memcpy (&v4, | 715 | GNUNET_memcpy (&v4, |
694 | &delta->addr, | 716 | &delta->addr, |
695 | alen); | 717 | alen); |
696 | for (unsigned int i=0;i<ch->num_addrs;i++) | 718 | for (unsigned int i=0;i<ch->num_caddrs;i++) |
697 | { | 719 | { |
698 | const struct sockaddr_in *c4; | 720 | const struct sockaddr_in *c4; |
699 | 721 | ||
700 | if (AF_INET != ch->addrs[i]->sa_family) | 722 | if (AF_INET != ch->caddrs[i].ss.ss_family) |
701 | return; /* IPv4 not relevant */ | 723 | return; /* IPv4 not relevant */ |
702 | c4 = (const struct sockaddr_in *) ch->addrs[i]; | 724 | c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss; |
703 | v4.sin_port = c4->sin_port; | 725 | v4.sin_port = c4->sin_port; |
704 | notify_client (delta->ac, | 726 | notify_client (delta->ac, |
705 | ch, | 727 | ch, |
@@ -713,13 +735,13 @@ check_notify_client (struct LocalAddressList *delta, | |||
713 | GNUNET_memcpy (&v6, | 735 | GNUNET_memcpy (&v6, |
714 | &delta->addr, | 736 | &delta->addr, |
715 | alen); | 737 | alen); |
716 | for (unsigned int i=0;i<ch->num_addrs;i++) | 738 | for (unsigned int i=0;i<ch->num_caddrs;i++) |
717 | { | 739 | { |
718 | const struct sockaddr_in6 *c6; | 740 | const struct sockaddr_in6 *c6; |
719 | 741 | ||
720 | if (AF_INET6 != ch->addrs[i]->sa_family) | 742 | if (AF_INET6 != ch->caddrs[i].ss.ss_family) |
721 | return; /* IPv4 not relevant */ | 743 | return; /* IPv4 not relevant */ |
722 | c6 = (const struct sockaddr_in6 *) ch->addrs[i]; | 744 | c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss; |
723 | v6.sin6_port = c6->sin6_port; | 745 | v6.sin6_port = c6->sin6_port; |
724 | notify_client (delta->ac, | 746 | notify_client (delta->ac, |
725 | ch, | 747 | ch, |
@@ -778,13 +800,13 @@ check_notify_client_external_ipv4_change (const struct in_addr *v4, | |||
778 | if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags)) | 800 | if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags)) |
779 | return; | 801 | return; |
780 | bport = 0; | 802 | bport = 0; |
781 | for (unsigned int i=0;i<ch->num_addrs;i++) | 803 | for (unsigned int i=0;i<ch->num_caddrs;i++) |
782 | { | 804 | { |
783 | const struct sockaddr *sa = ch->addrs[i]; | 805 | const struct sockaddr_storage *ss = &ch->caddrs[i].ss; |
784 | 806 | ||
785 | if (AF_INET != sa->sa_family) | 807 | if (AF_INET != ss->ss_family) |
786 | continue; | 808 | continue; |
787 | bport = ntohs (((const struct sockaddr_in *) sa)->sin_port); | 809 | bport = ntohs (((const struct sockaddr_in *) ss)->sin_port); |
788 | } | 810 | } |
789 | if (0 == bport) | 811 | if (0 == bport) |
790 | return; /* IPv6-only */ | 812 | return; /* IPv6-only */ |
@@ -1008,6 +1030,66 @@ run_scan (void *cls) | |||
1008 | 1030 | ||
1009 | 1031 | ||
1010 | /** | 1032 | /** |
1033 | * Function called whenever our set of external addresses | ||
1034 | * as created by `upnpc` changes. | ||
1035 | * | ||
1036 | * @param cls closure with our `struct ClientHandle *` | ||
1037 | * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean | ||
1038 | * the previous (now invalid) one, #GNUNET_SYSERR indicates an error | ||
1039 | * @param addr either the previous or the new public IP address | ||
1040 | * @param addrlen actual length of the @a addr | ||
1041 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code | ||
1042 | */ | ||
1043 | static void | ||
1044 | upnp_addr_change_cb (void *cls, | ||
1045 | int add_remove, | ||
1046 | const struct sockaddr *addr, | ||
1047 | socklen_t addrlen, | ||
1048 | enum GNUNET_NAT_StatusCode result) | ||
1049 | { | ||
1050 | struct ClientHandle *ch = cls; | ||
1051 | enum GNUNET_NAT_AddressClass ac; | ||
1052 | |||
1053 | switch (result) | ||
1054 | { | ||
1055 | case GNUNET_NAT_ERROR_SUCCESS: | ||
1056 | GNUNET_assert (NULL != addr); | ||
1057 | break; | ||
1058 | case GNUNET_NAT_ERROR_UPNPC_FAILED: | ||
1059 | case GNUNET_NAT_ERROR_UPNPC_TIMEOUT: | ||
1060 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1061 | "Running upnpc failed: %d\n", | ||
1062 | result); | ||
1063 | return; | ||
1064 | default: | ||
1065 | GNUNET_break (0); /* should not be possible */ | ||
1066 | return; | ||
1067 | } | ||
1068 | switch (addr->sa_family) | ||
1069 | { | ||
1070 | case AF_INET: | ||
1071 | ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr) | ||
1072 | ? GNUNET_NAT_AC_LAN_PRIVATE | ||
1073 | : GNUNET_NAT_AC_GLOBAL_EXTERN; | ||
1074 | break; | ||
1075 | case AF_INET6: | ||
1076 | ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr) | ||
1077 | ? GNUNET_NAT_AC_LAN_PRIVATE | ||
1078 | : GNUNET_NAT_AC_GLOBAL_EXTERN; | ||
1079 | break; | ||
1080 | default: | ||
1081 | GNUNET_break (0); | ||
1082 | return; | ||
1083 | } | ||
1084 | notify_client (ac, | ||
1085 | ch, | ||
1086 | add_remove, | ||
1087 | addr, | ||
1088 | addrlen); | ||
1089 | } | ||
1090 | |||
1091 | |||
1092 | /** | ||
1011 | * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client. | 1093 | * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client. |
1012 | * We remember the client for updates upon future NAT events. | 1094 | * We remember the client for updates upon future NAT events. |
1013 | * | 1095 | * |
@@ -1023,7 +1105,7 @@ handle_register (void *cls, | |||
1023 | size_t left; | 1105 | size_t left; |
1024 | 1106 | ||
1025 | if ( (0 != ch->proto) || | 1107 | if ( (0 != ch->proto) || |
1026 | (NULL != ch->addrs) ) | 1108 | (NULL != ch->caddrs) ) |
1027 | { | 1109 | { |
1028 | /* double registration not allowed */ | 1110 | /* double registration not allowed */ |
1029 | GNUNET_break (0); | 1111 | GNUNET_break (0); |
@@ -1035,15 +1117,17 @@ handle_register (void *cls, | |||
1035 | ch->flags = message->flags; | 1117 | ch->flags = message->flags; |
1036 | ch->proto = message->proto; | 1118 | ch->proto = message->proto; |
1037 | ch->adv_port = ntohs (message->adv_port); | 1119 | ch->adv_port = ntohs (message->adv_port); |
1038 | ch->num_addrs = ntohs (message->num_addrs); | 1120 | ch->num_caddrs = ntohs (message->num_addrs); |
1039 | ch->addrs = GNUNET_new_array (ch->num_addrs, | 1121 | ch->caddrs = GNUNET_new_array (ch->num_caddrs, |
1040 | struct sockaddr *); | 1122 | struct ClientAddress); |
1041 | left = ntohs (message->header.size) - sizeof (*message); | 1123 | left = ntohs (message->header.size) - sizeof (*message); |
1042 | off = (const char *) &message[1]; | 1124 | off = (const char *) &message[1]; |
1043 | for (unsigned int i=0;i<ch->num_addrs;i++) | 1125 | for (unsigned int i=0;i<ch->num_caddrs;i++) |
1044 | { | 1126 | { |
1045 | size_t alen; | 1127 | size_t alen; |
1046 | const struct sockaddr *sa = (const struct sockaddr *) off; | 1128 | const struct sockaddr *sa = (const struct sockaddr *) off; |
1129 | uint16_t port; | ||
1130 | int is_nat; | ||
1047 | 1131 | ||
1048 | if (sizeof (sa_family_t) > left) | 1132 | if (sizeof (sa_family_t) > left) |
1049 | { | 1133 | { |
@@ -1051,6 +1135,7 @@ handle_register (void *cls, | |||
1051 | GNUNET_SERVICE_client_drop (ch->client); | 1135 | GNUNET_SERVICE_client_drop (ch->client); |
1052 | return; | 1136 | return; |
1053 | } | 1137 | } |
1138 | is_nat = GNUNET_NO; | ||
1054 | switch (sa->sa_family) | 1139 | switch (sa->sa_family) |
1055 | { | 1140 | { |
1056 | case AF_INET: | 1141 | case AF_INET: |
@@ -1059,7 +1144,8 @@ handle_register (void *cls, | |||
1059 | 1144 | ||
1060 | alen = sizeof (struct sockaddr_in); | 1145 | alen = sizeof (struct sockaddr_in); |
1061 | if (is_nat_v4 (&s4->sin_addr)) | 1146 | if (is_nat_v4 (&s4->sin_addr)) |
1062 | ch->natted_address = GNUNET_YES; | 1147 | is_nat = GNUNET_YES; |
1148 | port = ntohs (s4->sin_port); | ||
1063 | } | 1149 | } |
1064 | break; | 1150 | break; |
1065 | case AF_INET6: | 1151 | case AF_INET6: |
@@ -1068,12 +1154,14 @@ handle_register (void *cls, | |||
1068 | 1154 | ||
1069 | alen = sizeof (struct sockaddr_in6); | 1155 | alen = sizeof (struct sockaddr_in6); |
1070 | if (is_nat_v6 (&s6->sin6_addr)) | 1156 | if (is_nat_v6 (&s6->sin6_addr)) |
1071 | ch->natted_address = GNUNET_YES; | 1157 | is_nat = GNUNET_YES; |
1158 | port = ntohs (s6->sin6_port); | ||
1072 | } | 1159 | } |
1073 | break; | 1160 | break; |
1074 | #if AF_UNIX | 1161 | #if AF_UNIX |
1075 | case AF_UNIX: | 1162 | case AF_UNIX: |
1076 | alen = sizeof (struct sockaddr_un); | 1163 | alen = sizeof (struct sockaddr_un); |
1164 | port = 0; | ||
1077 | break; | 1165 | break; |
1078 | #endif | 1166 | #endif |
1079 | default: | 1167 | default: |
@@ -1081,11 +1169,27 @@ handle_register (void *cls, | |||
1081 | GNUNET_SERVICE_client_drop (ch->client); | 1169 | GNUNET_SERVICE_client_drop (ch->client); |
1082 | return; | 1170 | return; |
1083 | } | 1171 | } |
1172 | /* store address */ | ||
1084 | GNUNET_assert (alen <= left); | 1173 | GNUNET_assert (alen <= left); |
1085 | ch->addrs[i] = GNUNET_malloc (alen); | 1174 | GNUNET_assert (alen <= sizeof (struct sockaddr_storage)); |
1086 | GNUNET_memcpy (ch->addrs[i], | 1175 | GNUNET_memcpy (&ch->caddrs[i].ss, |
1087 | sa, | 1176 | sa, |
1088 | alen); | 1177 | alen); |
1178 | |||
1179 | /* If applicable, try UPNPC NAT punching */ | ||
1180 | if ( (is_nat) && | ||
1181 | (enable_upnp) && | ||
1182 | ( (IPPROTO_TCP == ch->proto) || | ||
1183 | (IPPROTO_UDP == ch->proto) ) ) | ||
1184 | { | ||
1185 | ch->natted_address = GNUNET_YES; | ||
1186 | ch->caddrs[i].mh | ||
1187 | = GNUNET_NAT_mini_map_start (port, | ||
1188 | IPPROTO_TCP == ch->proto, | ||
1189 | &upnp_addr_change_cb, | ||
1190 | ch); | ||
1191 | } | ||
1192 | |||
1089 | off += alen; | 1193 | off += alen; |
1090 | } | 1194 | } |
1091 | /* Actually send IP address list to client */ | 1195 | /* Actually send IP address list to client */ |
@@ -1822,9 +1926,15 @@ client_disconnect_cb (void *cls, | |||
1822 | GNUNET_CONTAINER_DLL_remove (ch_head, | 1926 | GNUNET_CONTAINER_DLL_remove (ch_head, |
1823 | ch_tail, | 1927 | ch_tail, |
1824 | ch); | 1928 | ch); |
1825 | for (unsigned int i=0;i<ch->num_addrs;i++) | 1929 | for (unsigned int i=0;i<ch->num_caddrs;i++) |
1826 | GNUNET_free_non_null (ch->addrs[i]); | 1930 | { |
1827 | GNUNET_free_non_null (ch->addrs); | 1931 | if (NULL != ch->caddrs[i].mh) |
1932 | { | ||
1933 | GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh); | ||
1934 | ch->caddrs[i].mh = NULL; | ||
1935 | } | ||
1936 | } | ||
1937 | GNUNET_free_non_null (ch->caddrs); | ||
1828 | GNUNET_free (ch); | 1938 | GNUNET_free (ch); |
1829 | } | 1939 | } |
1830 | 1940 | ||
diff --git a/src/nat/gnunet-service-nat_mini.c b/src/nat/gnunet-service-nat_mini.c index 658ec72b7..efdc0988b 100644 --- a/src/nat/gnunet-service-nat_mini.c +++ b/src/nat/gnunet-service-nat_mini.c | |||
@@ -431,7 +431,7 @@ process_refresh_output (void *cls, | |||
431 | } | 431 | } |
432 | return; | 432 | return; |
433 | } | 433 | } |
434 | if (!mini->did_map) | 434 | if (! mini->did_map) |
435 | return; /* never mapped, won't find our mapping anyway */ | 435 | return; /* never mapped, won't find our mapping anyway */ |
436 | 436 | ||
437 | /* we're looking for output of the form: | 437 | /* we're looking for output of the form: |
@@ -538,8 +538,8 @@ do_refresh (void *cls) | |||
538 | mini->refresh_cmd = NULL; | 538 | mini->refresh_cmd = NULL; |
539 | ac = GNUNET_YES; | 539 | ac = GNUNET_YES; |
540 | } | 540 | } |
541 | mini->refresh_cmd = | 541 | mini->refresh_cmd |
542 | GNUNET_OS_command_run (&process_refresh_output, | 542 | = GNUNET_OS_command_run (&process_refresh_output, |
543 | mini, | 543 | mini, |
544 | MAP_TIMEOUT, | 544 | MAP_TIMEOUT, |
545 | "upnpc", | 545 | "upnpc", |
@@ -581,10 +581,10 @@ process_map_output (void *cls, | |||
581 | NULL, 0, | 581 | NULL, 0, |
582 | GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED); | 582 | GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED); |
583 | if (NULL == mini->refresh_task) | 583 | if (NULL == mini->refresh_task) |
584 | mini->refresh_task = | 584 | mini->refresh_task |
585 | GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, | 585 | = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, |
586 | &do_refresh, | 586 | &do_refresh, |
587 | mini); | 587 | mini); |
588 | return; | 588 | return; |
589 | } | 589 | } |
590 | /* | 590 | /* |
@@ -600,7 +600,9 @@ process_map_output (void *cls, | |||
600 | } | 600 | } |
601 | ipa = GNUNET_strdup (ipaddr + 1); | 601 | ipa = GNUNET_strdup (ipaddr + 1); |
602 | strstr (ipa, ":")[0] = '\0'; | 602 | strstr (ipa, ":")[0] = '\0'; |
603 | if (1 != inet_pton (AF_INET, ipa, &mini->current_addr.sin_addr)) | 603 | if (1 != inet_pton (AF_INET, |
604 | ipa, | ||
605 | &mini->current_addr.sin_addr)) | ||
604 | { | 606 | { |
605 | GNUNET_free (ipa); | 607 | GNUNET_free (ipa); |
606 | return; /* skip line */ | 608 | return; /* skip line */ |
@@ -613,7 +615,8 @@ process_map_output (void *cls, | |||
613 | mini->current_addr.sin_len = sizeof (struct sockaddr_in); | 615 | mini->current_addr.sin_len = sizeof (struct sockaddr_in); |
614 | #endif | 616 | #endif |
615 | mini->did_map = GNUNET_YES; | 617 | mini->did_map = GNUNET_YES; |
616 | mini->ac (mini->ac_cls, GNUNET_YES, | 618 | mini->ac (mini->ac_cls, |
619 | GNUNET_YES, | ||
617 | (const struct sockaddr *) &mini->current_addr, | 620 | (const struct sockaddr *) &mini->current_addr, |
618 | sizeof (mini->current_addr), | 621 | sizeof (mini->current_addr), |
619 | GNUNET_NAT_ERROR_SUCCESS); | 622 | GNUNET_NAT_ERROR_SUCCESS); |