aboutsummaryrefslogtreecommitdiff
path: root/src/nat
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-12-18 07:35:34 +0100
committerChristian Grothoff <christian@grothoff.org>2016-12-18 07:35:34 +0100
commit605227ee99846471196e222c6c25cafbe0a64232 (patch)
treec8e018743aeca724111fac8ca5c544984ce303eb /src/nat
parentbc4a5aeac8a6f1a1d25b118a26233d4fe7d23741 (diff)
downloadgnunet-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.c160
-rw-r--r--src/nat/gnunet-service-nat_mini.c21
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 */
82struct 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 */
82struct ClientHandle 102struct 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 */
358static struct in_addr mini_external_ipv4; 379static 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 */
1043static void
1044upnp_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);