aboutsummaryrefslogtreecommitdiff
path: root/src/nat/gnunet-service-nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nat/gnunet-service-nat.c')
-rw-r--r--src/nat/gnunet-service-nat.c1168
1 files changed, 480 insertions, 688 deletions
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c
index e29f37108..98d87262e 100644
--- a/src/nat/gnunet-service-nat.c
+++ b/src/nat/gnunet-service-nat.c
@@ -23,20 +23,16 @@
23 * @brief network address translation traversal service 23 * @brief network address translation traversal service
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 * 25 *
26 * The purpose of this service is to enable transports to 26 * The purpose of this service is to enable transports to
27 * traverse NAT routers, by providing traversal options and 27 * traverse NAT routers, by providing traversal options and
28 * knowledge about the local network topology. 28 * knowledge about the local network topology.
29 * 29 *
30 * TODO: 30 * TODO:
31 * - test and document (!) ICMP based NAT traversal 31 * - migrate test cases to new NAT service
32 * - implement manual hole punching support (incl. DNS 32 * - add new traceroute-based logic for external IP detection
33 * lookup for DynDNS setups!) 33 *
34 * - implement "more" autoconfig:
35 * re-work gnunet-nat-server & integrate!
36 * + test manually punched NAT (how?)
37 * - implement & test STUN processing to classify NAT; 34 * - implement & test STUN processing to classify NAT;
38 * basically, open port & try different methods. 35 * basically, open port & try different methods.
39 * - implement NEW logic for external IP detection
40 */ 36 */
41#include "platform.h" 37#include "platform.h"
42#include <math.h> 38#include <math.h>
@@ -44,7 +40,10 @@
44#include "gnunet_protocols.h" 40#include "gnunet_protocols.h"
45#include "gnunet_signatures.h" 41#include "gnunet_signatures.h"
46#include "gnunet_statistics_service.h" 42#include "gnunet_statistics_service.h"
43#include "gnunet_resolver_service.h"
47#include "gnunet_nat_service.h" 44#include "gnunet_nat_service.h"
45#include "gnunet-service-nat.h"
46#include "gnunet-service-nat_externalip.h"
48#include "gnunet-service-nat_stun.h" 47#include "gnunet-service-nat_stun.h"
49#include "gnunet-service-nat_mini.h" 48#include "gnunet-service-nat_mini.h"
50#include "gnunet-service-nat_helper.h" 49#include "gnunet-service-nat_helper.h"
@@ -64,26 +63,13 @@
64#define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) 63#define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
65 64
66/** 65/**
67 * How long do we wait until we re-try running `external-ip` if the 66 * How often do we scan for changes in how our external (dyndns) hostname resolves?
68 * command failed to terminate nicely?
69 */ 67 */
70#define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) 68#define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7)
71 69
72/**
73 * How long do we wait until we re-try running `external-ip` if the
74 * command failed (but terminated)?
75 */
76#define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
77 70
78/** 71/**
79 * How long do we wait until we re-try running `external-ip` if the 72 * Information we track per client address.
80 * command succeeded?
81 */
82#define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
83
84
85/**
86 * Information we track per client address.
87 */ 73 */
88struct ClientAddress 74struct ClientAddress
89{ 75{
@@ -98,7 +84,54 @@ struct ClientAddress
98 * pending. 84 * pending.
99 */ 85 */
100 struct GNUNET_NAT_MiniHandle *mh; 86 struct GNUNET_NAT_MiniHandle *mh;
101 87
88};
89
90
91/**
92 * List of local addresses this system has.
93 */
94struct LocalAddressList
95{
96 /**
97 * This is a linked list.
98 */
99 struct LocalAddressList *next;
100
101 /**
102 * Previous entry.
103 */
104 struct LocalAddressList *prev;
105
106 /**
107 * Context for a gnunet-helper-nat-server used to listen
108 * for ICMP messages to this client for connection reversal.
109 */
110 struct HelperContext *hc;
111
112 /**
113 * The address itself (i.e. `struct sockaddr_in` or `struct
114 * sockaddr_in6`, in the respective byte order).
115 */
116 struct sockaddr_storage addr;
117
118 /**
119 * Address family. (FIXME: redundant, addr.ss_family! Remove!?)
120 */
121 int af;
122
123 /**
124 * #GNUNET_YES if we saw this one in the previous iteration,
125 * but not in the current iteration and thus might need to
126 * remove it at the end.
127 */
128 int old;
129
130 /**
131 * What type of address is this?
132 */
133 enum GNUNET_NAT_AddressClass ac;
134
102}; 135};
103 136
104 137
@@ -112,7 +145,7 @@ struct ClientHandle
112 * Kept in a DLL. 145 * Kept in a DLL.
113 */ 146 */
114 struct ClientHandle *next; 147 struct ClientHandle *next;
115 148
116 /** 149 /**
117 * Kept in a DLL. 150 * Kept in a DLL.
118 */ 151 */
@@ -120,7 +153,7 @@ struct ClientHandle
120 153
121 /** 154 /**
122 * Underlying handle for this client with the service. 155 * Underlying handle for this client with the service.
123 */ 156 */
124 struct GNUNET_SERVICE_Client *client; 157 struct GNUNET_SERVICE_Client *client;
125 158
126 /** 159 /**
@@ -136,74 +169,70 @@ struct ClientHandle
136 /** 169 /**
137 * External DNS name and port given by user due to manual 170 * External DNS name and port given by user due to manual
138 * hole punching. Special DNS name 'AUTO' is used to indicate 171 * hole punching. Special DNS name 'AUTO' is used to indicate
139 * desire for automatic determination of the external IP 172 * desire for automatic determination of the external IP
140 * (instead of DNS or manual configuration, i.e. to be used 173 * (instead of DNS or manual configuration, i.e. to be used
141 * if the IP keeps changing and we have no DynDNS, but we do 174 * if the IP keeps changing and we have no DynDNS, but we do
142 * have a hole punched). 175 * have a hole punched).
143 */ 176 */
144 char *hole_external; 177 char *hole_external;
145 178
146 /** 179 /**
147 * What does this client care about? 180 * Name of the configuration section this client cares about.
148 */ 181 */
149 enum GNUNET_NAT_RegisterFlags flags; 182 char *section_name;
150 183
151 /** 184 /**
152 * Is any of the @e caddrs in a reserved subnet for NAT? 185 * Task for periodically re-running the @e ext_dns DNS lookup.
153 */ 186 */
154 int natted_address; 187 struct GNUNET_SCHEDULER_Task *ext_dns_task;
155 188
156 /** 189 /**
157 * Number of addresses that this service is bound to. 190 * Handle for (DYN)DNS lookup of our external IP as given in
158 * Length of the @e caddrs array. 191 * @e hole_external.
159 */ 192 */
160 uint16_t num_caddrs; 193 struct GNUNET_RESOLVER_RequestHandle *ext_dns;
161 194
162 /** 195 /**
163 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP. 196 * Handle for monitoring external IP changes.
164 */ 197 */
165 uint8_t proto; 198 struct GN_ExternalIPMonitor *external_monitor;
166
167};
168 199
200 /**
201 * DLL of external IP addresses as given in @e hole_external.
202 */
203 struct LocalAddressList *ext_addr_head;
169 204
170/**
171 * List of local addresses this system has.
172 */
173struct LocalAddressList
174{
175 /** 205 /**
176 * This is a linked list. 206 * DLL of external IP addresses as given in @e hole_external.
177 */ 207 */
178 struct LocalAddressList *next; 208 struct LocalAddressList *ext_addr_tail;
179 209
180 /** 210 /**
181 * Previous entry. 211 * Port number we found in @e hole_external.
182 */ 212 */
183 struct LocalAddressList *prev; 213 uint16_t ext_dns_port;
184 214
185 /** 215 /**
186 * Context for a gnunet-helper-nat-server used to listen 216 * What does this client care about?
187 * for ICMP messages to this client for connection reversal.
188 */ 217 */
189 struct HelperContext *hc; 218 enum GNUNET_NAT_RegisterFlags flags;
190 219
191 /** 220 /**
192 * The address itself (i.e. `struct sockaddr_in` or `struct 221 * Is any of the @e caddrs in a reserved subnet for NAT?
193 * sockaddr_in6`, in the respective byte order).
194 */ 222 */
195 struct sockaddr_storage addr; 223 int natted_address;
196 224
197 /** 225 /**
198 * Address family. 226 * Number of addresses that this service is bound to.
227 * Length of the @e caddrs array.
199 */ 228 */
200 int af; 229 uint16_t num_caddrs;
201 230
202 /** 231 /**
203 * What type of address is this? 232 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
204 */ 233 */
205 enum GNUNET_NAT_AddressClass ac; 234 uint8_t proto;
206 235
207}; 236};
208 237
209 238
@@ -214,12 +243,12 @@ struct StunExternalIP
214{ 243{
215 /** 244 /**
216 * Kept in a DLL. 245 * Kept in a DLL.
217 */ 246 */
218 struct StunExternalIP *next; 247 struct StunExternalIP *next;
219 248
220 /** 249 /**
221 * Kept in a DLL. 250 * Kept in a DLL.
222 */ 251 */
223 struct StunExternalIP *prev; 252 struct StunExternalIP *prev;
224 253
225 /** 254 /**
@@ -228,13 +257,13 @@ struct StunExternalIP
228 struct GNUNET_SCHEDULER_Task *timeout_task; 257 struct GNUNET_SCHEDULER_Task *timeout_task;
229 258
230 /** 259 /**
231 * Our external IP address as reported by the 260 * Our external IP address as reported by the
232 * STUN server. 261 * STUN server.
233 */ 262 */
234 struct sockaddr_in external_addr; 263 struct sockaddr_in external_addr;
235 264
236 /** 265 /**
237 * Address of the reporting STUN server. Used to 266 * Address of the reporting STUN server. Used to
238 * detect when a STUN server changes its opinion 267 * detect when a STUN server changes its opinion
239 * to more quickly remove stale results. 268 * to more quickly remove stale results.
240 */ 269 */
@@ -248,83 +277,14 @@ struct StunExternalIP
248 277
249 278
250/** 279/**
251 * Context for autoconfiguration operations. 280 * Timeout to use when STUN data is considered stale.
252 */
253struct AutoconfigContext
254{
255 /**
256 * Kept in a DLL.
257 */
258 struct AutoconfigContext *prev;
259
260 /**
261 * Kept in a DLL.
262 */
263 struct AutoconfigContext *next;
264
265 /**
266 * Which client asked the question.
267 */
268 struct ClientHandle *ch;
269
270 /**
271 * Configuration we are creating.
272 */
273 struct GNUNET_CONFIGURATION_Handle *c;
274
275 /**
276 * Original configuration (for diffing).
277 */
278 struct GNUNET_CONFIGURATION_Handle *orig;
279
280 /**
281 * Timeout task to force termination.
282 */
283 struct GNUNET_SCHEDULER_Task *timeout_task;
284
285 /**
286 * What type of system are we on?
287 */
288 char *system_type;
289
290 /**
291 * Handle to activity to probe for our external IP.
292 */
293 struct GNUNET_NAT_ExternalHandle *probe_external;
294
295 /**
296 * #GNUNET_YES if upnpc should be used,
297 * #GNUNET_NO if upnpc should not be used,
298 * #GNUNET_SYSERR if we should simply not change the option.
299 */
300 int enable_upnpc;
301
302 /**
303 * Status code to return to the client.
304 */
305 enum GNUNET_NAT_StatusCode status_code;
306
307 /**
308 * NAT type to return to the client.
309 */
310 enum GNUNET_NAT_Type type;
311};
312
313
314/**
315 * DLL of our autoconfiguration operations.
316 */
317static struct AutoconfigContext *ac_head;
318
319/**
320 * DLL of our autoconfiguration operations.
321 */ 281 */
322static struct AutoconfigContext *ac_tail; 282static struct GNUNET_TIME_Relative stun_stale_timeout;
323 283
324/** 284/**
325 * Timeout to use when STUN data is considered stale. 285 * How often do we scan for changes in how our external (dyndns) hostname resolves?
326 */ 286 */
327static struct GNUNET_TIME_Relative stun_stale_timeout; 287static struct GNUNET_TIME_Relative dyndns_frequency;
328 288
329/** 289/**
330 * Handle to our current configuration. 290 * Handle to our current configuration.
@@ -345,7 +305,7 @@ static struct GNUNET_SCHEDULER_Task *scan_task;
345 * Head of client DLL. 305 * Head of client DLL.
346 */ 306 */
347static struct ClientHandle *ch_head; 307static struct ClientHandle *ch_head;
348 308
349/** 309/**
350 * Tail of client DLL. 310 * Tail of client DLL.
351 */ 311 */
@@ -363,36 +323,19 @@ static struct LocalAddressList *lal_tail;
363 323
364/** 324/**
365 * Kept in a DLL. 325 * Kept in a DLL.
366 */ 326 */
367static struct StunExternalIP *se_head; 327static struct StunExternalIP *se_head;
368 328
369/** 329/**
370 * Kept in a DLL. 330 * Kept in a DLL.
371 */ 331 */
372static struct StunExternalIP *se_tail; 332static struct StunExternalIP *se_tail;
373 333
374/** 334/**
375 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled, 335 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
376 * #GNUNET_SYSERR if configuration enabled but binary is unavailable. 336 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
377 */ 337 */
378static int enable_upnp; 338int enable_upnp;
379
380/**
381 * Task run to obtain our external IP (if #enable_upnp is set
382 * and if we find we have a NATed IP address).
383 */
384static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
385
386/**
387 * Handle to our operation to run `external-ip`.
388 */
389static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op;
390
391/**
392 * What is our external IP address as claimed by `external-ip`?
393 * 0 for unknown.
394 */
395static struct in_addr mini_external_ipv4;
396 339
397 340
398/** 341/**
@@ -422,7 +365,7 @@ free_lal (struct LocalAddressList *lal)
422 365
423/** 366/**
424 * Free the DLL starting at #lal_head. 367 * Free the DLL starting at #lal_head.
425 */ 368 */
426static void 369static void
427destroy_lal () 370destroy_lal ()
428{ 371{
@@ -474,22 +417,22 @@ check_register (void *cls,
474#endif 417#endif
475 default: 418 default:
476 GNUNET_break (0); 419 GNUNET_break (0);
477 return GNUNET_SYSERR; 420 return GNUNET_SYSERR;
478 } 421 }
479 if (alen > left) 422 if (alen > left)
480 { 423 {
481 GNUNET_break (0); 424 GNUNET_break (0);
482 return GNUNET_SYSERR; 425 return GNUNET_SYSERR;
483 } 426 }
484 off += alen; 427 off += alen;
485 left -= alen; 428 left -= alen;
486 } 429 }
487 if (left != ntohs (message->hole_external_len)) 430 if (left != ntohs (message->str_len))
488 { 431 {
489 GNUNET_break (0); 432 GNUNET_break (0);
490 return GNUNET_SYSERR; 433 return GNUNET_SYSERR;
491 } 434 }
492 return GNUNET_OK; 435 return GNUNET_OK;
493} 436}
494 437
495 438
@@ -535,7 +478,7 @@ match_ipv6 (const char *network,
535 struct in6_addr net; 478 struct in6_addr net;
536 struct in6_addr mask; 479 struct in6_addr mask;
537 unsigned int off; 480 unsigned int off;
538 481
539 if (0 == bits) 482 if (0 == bits)
540 return GNUNET_YES; 483 return GNUNET_YES;
541 GNUNET_assert (1 == inet_pton (AF_INET6, 484 GNUNET_assert (1 == inet_pton (AF_INET6,
@@ -607,7 +550,7 @@ is_nat_v6 (const struct in6_addr *ip)
607struct IfcProcContext 550struct IfcProcContext
608{ 551{
609 552
610 /** 553 /**
611 * Head of DLL of local addresses. 554 * Head of DLL of local addresses.
612 */ 555 */
613 struct LocalAddressList *lal_head; 556 struct LocalAddressList *lal_head;
@@ -718,7 +661,7 @@ notify_client (enum GNUNET_NAT_AddressClass ac,
718{ 661{
719 struct GNUNET_MQ_Envelope *env; 662 struct GNUNET_MQ_Envelope *env;
720 struct GNUNET_NAT_AddressChangeNotificationMessage *msg; 663 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
721 664
722 env = GNUNET_MQ_msg_extra (msg, 665 env = GNUNET_MQ_msg_extra (msg,
723 addr_len, 666 addr_len,
724 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); 667 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
@@ -729,7 +672,7 @@ notify_client (enum GNUNET_NAT_AddressClass ac,
729 addr_len); 672 addr_len);
730 GNUNET_MQ_send (ch->mq, 673 GNUNET_MQ_send (ch->mq,
731 env); 674 env);
732} 675}
733 676
734 677
735/** 678/**
@@ -748,7 +691,7 @@ check_notify_client (struct LocalAddressList *delta,
748 size_t alen; 691 size_t alen;
749 struct sockaddr_in v4; 692 struct sockaddr_in v4;
750 struct sockaddr_in6 v6; 693 struct sockaddr_in6 v6;
751 694
752 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES)) 695 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
753 return; 696 return;
754 switch (delta->af) 697 switch (delta->af)
@@ -758,14 +701,14 @@ check_notify_client (struct LocalAddressList *delta,
758 GNUNET_memcpy (&v4, 701 GNUNET_memcpy (&v4,
759 &delta->addr, 702 &delta->addr,
760 alen); 703 alen);
761 704
762 /* Check for client notifications */ 705 /* Check for client notifications */
763 for (unsigned int i=0;i<ch->num_caddrs;i++) 706 for (unsigned int i=0;i<ch->num_caddrs;i++)
764 { 707 {
765 const struct sockaddr_in *c4; 708 const struct sockaddr_in *c4;
766 709
767 if (AF_INET != ch->caddrs[i].ss.ss_family) 710 if (AF_INET != ch->caddrs[i].ss.ss_family)
768 return; /* IPv4 not relevant */ 711 continue; /* IPv4 not relevant */
769 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss; 712 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
770 if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) && 713 if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
771 (0 != c4->sin_addr.s_addr) && 714 (0 != c4->sin_addr.s_addr) &&
@@ -806,9 +749,9 @@ check_notify_client (struct LocalAddressList *delta,
806 for (unsigned int i=0;i<ch->num_caddrs;i++) 749 for (unsigned int i=0;i<ch->num_caddrs;i++)
807 { 750 {
808 const struct sockaddr_in6 *c6; 751 const struct sockaddr_in6 *c6;
809 752
810 if (AF_INET6 != ch->caddrs[i].ss.ss_family) 753 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
811 return; /* IPv4 not relevant */ 754 continue; /* IPv4 not relevant */
812 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss; 755 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
813 if ( match_ipv6 ("::1", &c6->sin6_addr, 128) && 756 if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
814 (0 != memcmp (&c6->sin6_addr, 757 (0 != memcmp (&c6->sin6_addr,
@@ -888,19 +831,40 @@ notify_clients (struct LocalAddressList *delta,
888/** 831/**
889 * Tell relevant client about a change in our external 832 * Tell relevant client about a change in our external
890 * IPv4 address. 833 * IPv4 address.
891 * 834 *
835 * @param cls client to check if it cares and possibly notify
892 * @param v4 the external address that changed 836 * @param v4 the external address that changed
893 * @param ch client to check if it cares and possibly notify
894 * @param add #GNUNET_YES to add, #GNUNET_NO to remove 837 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
895 */ 838 */
896static void 839static void
897check_notify_client_external_ipv4_change (const struct in_addr *v4, 840notify_client_external_ipv4_change (void *cls,
898 struct ClientHandle *ch, 841 const struct in_addr *v4,
899 int add) 842 int add)
900{ 843{
844 struct ClientHandle *ch = cls;
901 struct sockaddr_in sa; 845 struct sockaddr_in sa;
902 int have_v4; 846 int have_v4;
903 847
848 /* (0) check if this impacts 'hole_external' */
849 if ( (NULL != ch->hole_external) &&
850 (0 == strcasecmp (ch->hole_external,
851 "AUTO")) )
852 {
853 struct LocalAddressList lal;
854 struct sockaddr_in *s4;
855
856 memset (&lal, 0, sizeof (lal));
857 s4 = (struct sockaddr_in *) &lal.addr;
858 s4->sin_family = AF_INET;
859 s4->sin_port = htons (ch->ext_dns_port);
860 s4->sin_addr = *v4;
861 lal.af = AF_INET;
862 lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
863 check_notify_client (&lal,
864 ch,
865 add);
866 }
867
904 /* (1) check if client cares. */ 868 /* (1) check if client cares. */
905 if (! ch->natted_address) 869 if (! ch->natted_address)
906 return; 870 return;
@@ -919,17 +883,17 @@ check_notify_client_external_ipv4_change (const struct in_addr *v4,
919 if (GNUNET_NO == have_v4) 883 if (GNUNET_NO == have_v4)
920 return; /* IPv6-only */ 884 return; /* IPv6-only */
921 885
922 /* build address info */ 886 /* (2) build address info */
923 memset (&sa, 887 memset (&sa,
924 0, 888 0,
925 sizeof (sa)); 889 sizeof (sa));
926 sa.sin_family = AF_INET; 890 sa.sin_family = AF_INET;
927 sa.sin_addr = *v4; 891 sa.sin_addr = *v4;
928 sa.sin_port = htons (0); 892 sa.sin_port = htons (0);
929 893
930 /* (3) notify client of change */ 894 /* (3) notify client of change */
931 notify_client (is_nat_v4 (v4) 895 notify_client (is_nat_v4 (v4)
932 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN 896 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
933 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL, 897 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
934 ch, 898 ch,
935 add, 899 add,
@@ -939,117 +903,11 @@ check_notify_client_external_ipv4_change (const struct in_addr *v4,
939 903
940 904
941/** 905/**
942 * Tell relevant clients about a change in our external
943 * IPv4 address.
944 *
945 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
946 * @param v4 the external address that changed
947 */
948static void
949notify_clients_external_ipv4_change (int add,
950 const struct in_addr *v4)
951{
952 for (struct ClientHandle *ch = ch_head;
953 NULL != ch;
954 ch = ch->next)
955 check_notify_client_external_ipv4_change (v4,
956 ch,
957 add);
958}
959
960
961/**
962 * Task used to run `external-ip` to get our external IPv4
963 * address and pass it to NATed clients if possible.
964 *
965 * @param cls NULL
966 */
967static void
968run_external_ip (void *cls);
969
970
971/**
972 * We learn our current external IP address. If it changed,
973 * notify all of our applicable clients. Also re-schedule
974 * #run_external_ip with an appropriate timeout.
975 *
976 * @param cls NULL
977 * @param addr the address, NULL on errors
978 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
979 */
980static void
981handle_external_ip (void *cls,
982 const struct in_addr *addr,
983 enum GNUNET_NAT_StatusCode result)
984{
985 char buf[INET_ADDRSTRLEN];
986
987 probe_external_ip_op = NULL;
988 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
989 probe_external_ip_task
990 = GNUNET_SCHEDULER_add_delayed ((NULL == addr)
991 ? EXTERN_IP_RETRY_FAILURE
992 : EXTERN_IP_RETRY_SUCCESS,
993 &run_external_ip,
994 NULL);
995 switch (result)
996 {
997 case GNUNET_NAT_ERROR_SUCCESS:
998 if (addr->s_addr == mini_external_ipv4.s_addr)
999 return; /* not change */
1000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1001 "Our external IP is now %s\n",
1002 inet_ntop (AF_INET,
1003 addr,
1004 buf,
1005 sizeof (buf)));
1006 if (0 != mini_external_ipv4.s_addr)
1007 notify_clients_external_ipv4_change (GNUNET_NO,
1008 &mini_external_ipv4);
1009 mini_external_ipv4 = *addr;
1010 notify_clients_external_ipv4_change (GNUNET_YES,
1011 &mini_external_ipv4);
1012 break;
1013 default:
1014 if (0 != mini_external_ipv4.s_addr)
1015 notify_clients_external_ipv4_change (GNUNET_NO,
1016 &mini_external_ipv4);
1017 mini_external_ipv4.s_addr = 0;
1018 break;
1019 }
1020}
1021
1022
1023/**
1024 * Task used to run `external-ip` to get our external IPv4
1025 * address and pass it to NATed clients if possible.
1026 *
1027 * @param cls NULL
1028 */
1029static void
1030run_external_ip (void *cls)
1031{
1032 probe_external_ip_task
1033 = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT,
1034 &run_external_ip,
1035 NULL);
1036 if (NULL != probe_external_ip_op)
1037 {
1038 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
1039 probe_external_ip_op = NULL;
1040 }
1041 probe_external_ip_op
1042 = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip,
1043 NULL);
1044}
1045
1046
1047/**
1048 * We got a connection reversal request from another peer. 906 * We got a connection reversal request from another peer.
1049 * Notify applicable clients. 907 * Notify applicable clients.
1050 * 908 *
1051 * @param cls closure with the `struct LocalAddressList` 909 * @param cls closure with the `struct LocalAddressList`
1052 * @param ra IP address of the peer who wants us to connect to it 910 * @param ra IP address of the peer who wants us to connect to it
1053 */ 911 */
1054static void 912static void
1055reversal_callback (void *cls, 913reversal_callback (void *cls,
@@ -1063,7 +921,7 @@ reversal_callback (void *cls,
1063 for (struct ClientHandle *ch = ch_head; 921 for (struct ClientHandle *ch = ch_head;
1064 NULL != ch; 922 NULL != ch;
1065 ch = ch->next) 923 ch = ch->next)
1066 { 924 {
1067 struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm; 925 struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
1068 struct GNUNET_MQ_Envelope *env; 926 struct GNUNET_MQ_Envelope *env;
1069 int match; 927 int match;
@@ -1077,7 +935,7 @@ reversal_callback (void *cls,
1077 { 935 {
1078 struct ClientAddress *ca = &ch->caddrs[i]; 936 struct ClientAddress *ca = &ch->caddrs[i];
1079 const struct sockaddr_in *c4; 937 const struct sockaddr_in *c4;
1080 938
1081 if (AF_INET != ca->ss.ss_family) 939 if (AF_INET != ca->ss.ss_family)
1082 continue; 940 continue;
1083 c4 = (const struct sockaddr_in *) &ca->ss; 941 c4 = (const struct sockaddr_in *) &ca->ss;
@@ -1107,7 +965,7 @@ reversal_callback (void *cls,
1107 * Task we run periodically to scan for network interfaces. 965 * Task we run periodically to scan for network interfaces.
1108 * 966 *
1109 * @param cls NULL 967 * @param cls NULL
1110 */ 968 */
1111static void 969static void
1112run_scan (void *cls) 970run_scan (void *cls)
1113{ 971{
@@ -1115,7 +973,7 @@ run_scan (void *cls)
1115 int found; 973 int found;
1116 int have_nat; 974 int have_nat;
1117 struct LocalAddressList *lnext; 975 struct LocalAddressList *lnext;
1118 976
1119 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ, 977 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
1120 &run_scan, 978 &run_scan,
1121 NULL); 979 NULL);
@@ -1194,8 +1052,8 @@ run_scan (void *cls)
1194 { 1052 {
1195 const struct sockaddr_in *s4 1053 const struct sockaddr_in *s4
1196 = (const struct sockaddr_in *) &pos->addr; 1054 = (const struct sockaddr_in *) &pos->addr;
1197 1055
1198 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, 1056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1199 "Found NATed local address %s, starting NAT server\n", 1057 "Found NATed local address %s, starting NAT server\n",
1200 GNUNET_a2s ((void *) &pos->addr, sizeof (*s4))); 1058 GNUNET_a2s ((void *) &pos->addr, sizeof (*s4)));
1201 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr, 1059 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
@@ -1204,29 +1062,7 @@ run_scan (void *cls)
1204 } 1062 }
1205 } 1063 }
1206 } 1064 }
1207 if ( (GNUNET_YES == have_nat) && 1065 GN_nat_status_changed (have_nat);
1208 (GNUNET_YES == enable_upnp) &&
1209 (NULL == probe_external_ip_task) &&
1210 (NULL == probe_external_ip_op) )
1211 {
1212 probe_external_ip_task
1213 = GNUNET_SCHEDULER_add_now (&run_external_ip,
1214 NULL);
1215 }
1216 if ( (GNUNET_NO == have_nat) &&
1217 (GNUNET_YES == enable_upnp) )
1218 {
1219 if (NULL != probe_external_ip_task)
1220 {
1221 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
1222 probe_external_ip_task = NULL;
1223 }
1224 if (NULL != probe_external_ip_op)
1225 {
1226 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
1227 probe_external_ip_op = NULL;
1228 }
1229 }
1230} 1066}
1231 1067
1232 1068
@@ -1267,6 +1103,10 @@ upnp_addr_change_cb (void *cls,
1267 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1103 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1268 "external-ip binary not found\n"); 1104 "external-ip binary not found\n");
1269 return; 1105 return;
1106 case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
1107 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1108 "upnpc binary not found\n");
1109 return;
1270 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED: 1110 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1271 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1111 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1272 "external-ip binary could not be run\n"); 1112 "external-ip binary could not be run\n");
@@ -1317,6 +1157,250 @@ upnp_addr_change_cb (void *cls,
1317 1157
1318 1158
1319/** 1159/**
1160 * Resolve the `hole_external` name to figure out our
1161 * external address from a manually punched hole. The
1162 * port number has already been parsed, this task is
1163 * responsible for periodically doing a DNS lookup.
1164 *
1165 * @param ch client handle to act upon
1166 */
1167static void
1168dyndns_lookup (void *cls);
1169
1170
1171/**
1172 * Our (external) hostname was resolved. Update lists of
1173 * current external IPs (note that DNS may return multiple
1174 * addresses!) and notify client accordingly.
1175 *
1176 * @param cls the `struct ClientHandle`
1177 * @param addr NULL on error, otherwise result of DNS lookup
1178 * @param addrlen number of bytes in @a addr
1179 */
1180static void
1181process_external_ip (void *cls,
1182 const struct sockaddr *addr,
1183 socklen_t addrlen)
1184{
1185 struct ClientHandle *ch = cls;
1186 struct LocalAddressList *lal;
1187 struct sockaddr_storage ss;
1188 struct sockaddr_in *v4;
1189 struct sockaddr_in6 *v6;
1190
1191 if (NULL == addr)
1192 {
1193 struct LocalAddressList *laln;
1194
1195 ch->ext_dns = NULL;
1196 ch->ext_dns_task
1197 = GNUNET_SCHEDULER_add_delayed (dyndns_frequency,
1198 &dyndns_lookup,
1199 ch);
1200 /* Current iteration is over, remove 'old' IPs now */
1201 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1202 {
1203 laln = lal->next;
1204 if (GNUNET_YES == lal->old)
1205 {
1206 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1207 ch->ext_addr_tail,
1208 lal);
1209 check_notify_client (lal,
1210 ch,
1211 GNUNET_NO);
1212 GNUNET_free (lal);
1213 }
1214 }
1215 return;
1216 }
1217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1218 "Got IP `%s' for external address `%s'\n",
1219 GNUNET_a2s (addr,
1220 addrlen),
1221 ch->hole_external);
1222
1223 /* build sockaddr storage with port number */
1224 memset (&ss, 0, sizeof (ss));
1225 memcpy (&ss, addr, addrlen);
1226 switch (addr->sa_family)
1227 {
1228 case AF_INET:
1229 v4 = (struct sockaddr_in *) &ss;
1230 v4->sin_port = htons (ch->ext_dns_port);
1231 break;
1232 case AF_INET6:
1233 v6 = (struct sockaddr_in6 *) &ss;
1234 v6->sin6_port = htons (ch->ext_dns_port);
1235 break;
1236 default:
1237 GNUNET_break (0);
1238 return;
1239 }
1240 /* See if 'ss' matches any of our known addresses */
1241 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1242 {
1243 if (GNUNET_NO == lal->old)
1244 continue; /* already processed, skip */
1245 if ( (addr->sa_family == lal->addr.ss_family) &&
1246 (0 == memcmp (&ss,
1247 &lal->addr,
1248 addrlen)) )
1249 {
1250 /* Address unchanged, remember so we do not remove */
1251 lal->old = GNUNET_NO;
1252 return; /* done here */
1253 }
1254 }
1255 /* notify client, and remember IP for later removal! */
1256 lal = GNUNET_new (struct LocalAddressList);
1257 lal->addr = ss;
1258 lal->af = ss.ss_family;
1259 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1260 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1261 ch->ext_addr_tail,
1262 lal);
1263 check_notify_client (lal,
1264 ch,
1265 GNUNET_YES);
1266}
1267
1268
1269/**
1270 * Resolve the `hole_external` name to figure out our
1271 * external address from a manually punched hole. The
1272 * port number has already been parsed, this task is
1273 * responsible for periodically doing a DNS lookup.
1274 *
1275 * @param ch client handle to act upon
1276 */
1277static void
1278dyndns_lookup (void *cls)
1279{
1280 struct ClientHandle *ch = cls;
1281 struct LocalAddressList *lal;
1282
1283 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1284 lal->old = GNUNET_YES;
1285 ch->ext_dns_task = NULL;
1286 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1287 AF_UNSPEC,
1288 GNUNET_TIME_UNIT_MINUTES,
1289 &process_external_ip,
1290 ch);
1291}
1292
1293
1294/**
1295 * Resolve the `hole_external` name to figure out our
1296 * external address from a manually punched hole. The
1297 * given name may be "AUTO" in which case we should use
1298 * the IP address(es) we have from upnpc or other methods.
1299 * The name can also be an IP address, in which case we
1300 * do not need to do DNS resolution. Finally, we also
1301 * need to parse the port number.
1302 *
1303 * @param ch client handle to act upon
1304 */
1305static void
1306lookup_hole_external (struct ClientHandle *ch)
1307{
1308 char *port;
1309 unsigned int pnum;
1310 struct sockaddr_in *s4;
1311 struct LocalAddressList *lal;
1312
1313 port = strrchr (ch->hole_external, ':');
1314 if (NULL == port)
1315 {
1316 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1317 _("Malformed punched hole specification `%s' (lacks port)\n"),
1318 ch->hole_external);
1319 return;
1320 }
1321 if ( (1 != sscanf (port + 1,
1322 "%u",
1323 &pnum)) ||
1324 (pnum > 65535) )
1325 {
1326 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1327 _("Invalid port number in punched hole specification `%s' (lacks port)\n"),
1328 port + 1);
1329 return;
1330 }
1331 ch->ext_dns_port = (uint16_t) pnum;
1332 *port = '\0';
1333
1334 lal = GNUNET_new (struct LocalAddressList);
1335 if ('[' == *ch->hole_external)
1336 {
1337 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1338
1339 s6->sin6_family = AF_INET6;
1340 if (']' != (ch->hole_external[strlen(ch->hole_external)-1]))
1341 {
1342 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1343 _("Malformed punched hole specification `%s' (lacks `]')\n"),
1344 ch->hole_external);
1345 GNUNET_free (lal);
1346 return;
1347 }
1348 ch->hole_external[strlen(ch->hole_external)-1] = '\0';
1349 if (1 != inet_pton (AF_INET6,
1350 ch->hole_external + 1,
1351 &s6->sin6_addr))
1352 {
1353 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1354 _("Malformed punched hole specification `%s' (IPv6 address invalid)"),
1355 ch->hole_external + 1);
1356 GNUNET_free (lal);
1357 return;
1358 }
1359 s6->sin6_port = htons (ch->ext_dns_port);
1360 lal->af = AF_INET6;
1361 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1362 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1363 ch->ext_addr_tail,
1364 lal);
1365 check_notify_client (lal,
1366 ch,
1367 GNUNET_YES);
1368 return;
1369 }
1370
1371 s4 = (struct sockaddr_in *) &lal->addr;
1372 s4->sin_family = AF_INET;
1373 if (1 == inet_pton (AF_INET,
1374 ch->hole_external,
1375 &s4->sin_addr))
1376 {
1377 s4->sin_port = htons (ch->ext_dns_port);
1378 lal->af = AF_INET;
1379 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1380 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1381 ch->ext_addr_tail,
1382 lal);
1383 check_notify_client (lal,
1384 ch,
1385 GNUNET_YES);
1386 return;
1387 }
1388 if (0 == strcasecmp (ch->hole_external,
1389 "AUTO"))
1390 {
1391 /* handled in #notify_client_external_ipv4_change() */
1392 GNUNET_free (lal);
1393 return;
1394 }
1395 /* got a DNS name, trigger lookup! */
1396 GNUNET_free (lal);
1397 ch->ext_dns_task
1398 = GNUNET_SCHEDULER_add_now (&dyndns_lookup,
1399 ch);
1400}
1401
1402
1403/**
1320 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client. 1404 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1321 * We remember the client for updates upon future NAT events. 1405 * We remember the client for updates upon future NAT events.
1322 * 1406 *
@@ -1367,7 +1451,7 @@ handle_register (void *cls,
1367 case AF_INET: 1451 case AF_INET:
1368 { 1452 {
1369 const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa; 1453 const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
1370 1454
1371 alen = sizeof (struct sockaddr_in); 1455 alen = sizeof (struct sockaddr_in);
1372 if (is_nat_v4 (&s4->sin_addr)) 1456 if (is_nat_v4 (&s4->sin_addr))
1373 is_nat = GNUNET_YES; 1457 is_nat = GNUNET_YES;
@@ -1377,7 +1461,7 @@ handle_register (void *cls,
1377 case AF_INET6: 1461 case AF_INET6:
1378 { 1462 {
1379 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa; 1463 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
1380 1464
1381 alen = sizeof (struct sockaddr_in6); 1465 alen = sizeof (struct sockaddr_in6);
1382 if (is_nat_v6 (&s6->sin6_addr)) 1466 if (is_nat_v6 (&s6->sin6_addr))
1383 is_nat = GNUNET_YES; 1467 is_nat = GNUNET_YES;
@@ -1393,14 +1477,14 @@ handle_register (void *cls,
1393 default: 1477 default:
1394 GNUNET_break (0); 1478 GNUNET_break (0);
1395 GNUNET_SERVICE_client_drop (ch->client); 1479 GNUNET_SERVICE_client_drop (ch->client);
1396 return; 1480 return;
1397 } 1481 }
1398 /* store address */ 1482 /* store address */
1399 GNUNET_assert (alen <= left); 1483 GNUNET_assert (alen <= left);
1400 GNUNET_assert (alen <= sizeof (struct sockaddr_storage)); 1484 GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
1401 GNUNET_memcpy (&ch->caddrs[i].ss, 1485 GNUNET_memcpy (&ch->caddrs[i].ss,
1402 sa, 1486 sa,
1403 alen); 1487 alen);
1404 1488
1405 /* If applicable, try UPNPC NAT punching */ 1489 /* If applicable, try UPNPC NAT punching */
1406 if ( (is_nat) && 1490 if ( (is_nat) &&
@@ -1419,10 +1503,16 @@ handle_register (void *cls,
1419 off += alen; 1503 off += alen;
1420 } 1504 }
1421 1505
1422 ch->hole_external 1506 ch->section_name
1423 = GNUNET_strndup (off, 1507 = GNUNET_strndup (off,
1424 ntohs (message->hole_external_len)); 1508 ntohs (message->str_len));
1425 1509 if (GNUNET_OK ==
1510 GNUNET_CONFIGURATION_get_value_string (cfg,
1511 ch->section_name,
1512 "HOLE_EXTERNAL",
1513 &ch->hole_external))
1514 lookup_hole_external (ch);
1515
1426 /* Actually send IP address list to client */ 1516 /* Actually send IP address list to client */
1427 for (struct LocalAddressList *lal = lal_head; 1517 for (struct LocalAddressList *lal = lal_head;
1428 NULL != lal; 1518 NULL != lal;
@@ -1433,12 +1523,9 @@ handle_register (void *cls,
1433 GNUNET_YES); 1523 GNUNET_YES);
1434 } 1524 }
1435 /* Also consider IPv4 determined by `external-ip` */ 1525 /* Also consider IPv4 determined by `external-ip` */
1436 if (0 != mini_external_ipv4.s_addr) 1526 ch->external_monitor
1437 { 1527 = GN_external_ipv4_monitor_start (&notify_client_external_ipv4_change,
1438 check_notify_client_external_ipv4_change (&mini_external_ipv4, 1528 ch);
1439 ch,
1440 GNUNET_YES);
1441 }
1442 GNUNET_SERVICE_client_continue (ch->client); 1529 GNUNET_SERVICE_client_continue (ch->client);
1443} 1530}
1444 1531
@@ -1457,7 +1544,7 @@ check_stun (void *cls,
1457{ 1544{
1458 size_t sa_len = ntohs (message->sender_addr_size); 1545 size_t sa_len = ntohs (message->sender_addr_size);
1459 size_t expect = sa_len + ntohs (message->payload_size); 1546 size_t expect = sa_len + ntohs (message->payload_size);
1460 1547
1461 if (ntohs (message->header.size) - sizeof (*message) != expect) 1548 if (ntohs (message->header.size) - sizeof (*message) != expect)
1462 { 1549 {
1463 GNUNET_break (0); 1550 GNUNET_break (0);
@@ -1490,7 +1577,7 @@ notify_clients_stun_change (const struct sockaddr_in *ip,
1490 struct sockaddr_in v4; 1577 struct sockaddr_in v4;
1491 struct GNUNET_NAT_AddressChangeNotificationMessage *msg; 1578 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1492 struct GNUNET_MQ_Envelope *env; 1579 struct GNUNET_MQ_Envelope *env;
1493 1580
1494 if (! ch->natted_address) 1581 if (! ch->natted_address)
1495 continue; 1582 continue;
1496 v4 = *ip; 1583 v4 = *ip;
@@ -1580,9 +1667,9 @@ handle_stun (void *cls,
1580 GNUNET_NAT_stun_handle_packet_ (payload, 1667 GNUNET_NAT_stun_handle_packet_ (payload,
1581 payload_size, 1668 payload_size,
1582 &external_addr)) 1669 &external_addr))
1583 { 1670 {
1584 /* We now know that a server at "sa" claims that 1671 /* We now know that a server at "sa" claims that
1585 we are visible at IP "external_addr". 1672 we are visible at IP "external_addr".
1586 1673
1587 We should (for some fixed period of time) tell 1674 We should (for some fixed period of time) tell
1588 all of our clients that listen to a NAT'ed address 1675 all of our clients that listen to a NAT'ed address
@@ -1685,347 +1772,44 @@ handle_request_connection_reversal (void *cls,
1685 const char *buf = (const char *) &message[1]; 1772 const char *buf = (const char *) &message[1];
1686 size_t local_sa_len = ntohs (message->local_addr_size); 1773 size_t local_sa_len = ntohs (message->local_addr_size);
1687 size_t remote_sa_len = ntohs (message->remote_addr_size); 1774 size_t remote_sa_len = ntohs (message->remote_addr_size);
1688 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0]; 1775 struct sockaddr_in l4;
1689 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len]; 1776 struct sockaddr_in r4;
1690 const struct sockaddr_in *l4 = NULL;
1691 const struct sockaddr_in *r4;
1692 int ret; 1777 int ret;
1693 1778
1694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1695 "Received REQUEST CONNECTION REVERSAL message from client\n"); 1780 "Received REQUEST CONNECTION REVERSAL message from client\n");
1696 switch (local_sa->sa_family) 1781 if (local_sa_len != sizeof (struct sockaddr_in))
1697 { 1782 {
1698 case AF_INET: 1783 GNUNET_break_op (0);
1699 if (local_sa_len != sizeof (struct sockaddr_in))
1700 {
1701 GNUNET_break (0);
1702 GNUNET_SERVICE_client_drop (ch->client);
1703 return;
1704 }
1705 l4 = (const struct sockaddr_in *) local_sa;
1706 break;
1707 case AF_INET6:
1708 if (local_sa_len != sizeof (struct sockaddr_in6))
1709 {
1710 GNUNET_break (0);
1711 GNUNET_SERVICE_client_drop (ch->client);
1712 return;
1713 }
1714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1715 _("Connection reversal for IPv6 not supported yet\n"));
1716 ret = GNUNET_SYSERR;
1717 break;
1718 default:
1719 GNUNET_break (0);
1720 GNUNET_SERVICE_client_drop (ch->client); 1784 GNUNET_SERVICE_client_drop (ch->client);
1721 return; 1785 return;
1722 } 1786 }
1723 switch (remote_sa->sa_family) 1787 if (remote_sa_len != sizeof (struct sockaddr_in))
1724 { 1788 {
1725 case AF_INET: 1789 GNUNET_break_op (0);
1726 if (remote_sa_len != sizeof (struct sockaddr_in))
1727 {
1728 GNUNET_break (0);
1729 GNUNET_SERVICE_client_drop (ch->client);
1730 return;
1731 }
1732 r4 = (const struct sockaddr_in *) remote_sa;
1733 ret = GN_request_connection_reversal (&l4->sin_addr,
1734 ntohs (l4->sin_port),
1735 &r4->sin_addr);
1736 break;
1737 case AF_INET6:
1738 if (remote_sa_len != sizeof (struct sockaddr_in6))
1739 {
1740 GNUNET_break (0);
1741 GNUNET_SERVICE_client_drop (ch->client);
1742 return;
1743 }
1744 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1745 _("Connection reversal for IPv6 not supported yet\n"));
1746 ret = GNUNET_SYSERR;
1747 break;
1748 default:
1749 GNUNET_break (0);
1750 GNUNET_SERVICE_client_drop (ch->client); 1790 GNUNET_SERVICE_client_drop (ch->client);
1751 return; 1791 return;
1752 } 1792 }
1793 GNUNET_memcpy (&l4,
1794 buf,
1795 sizeof (struct sockaddr_in));
1796 GNUNET_break_op (AF_INET == l4.sin_family);
1797 buf += sizeof (struct sockaddr_in);
1798 GNUNET_memcpy (&r4,
1799 buf,
1800 sizeof (struct sockaddr_in));
1801 GNUNET_break_op (AF_INET == r4.sin_family);
1802 ret = GN_request_connection_reversal (&l4.sin_addr,
1803 ntohs (l4.sin_port),
1804 &r4.sin_addr);
1753 if (GNUNET_OK != ret) 1805 if (GNUNET_OK != ret)
1754 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1806 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1755 _("Connection reversal request failed\n")); 1807 _("Connection reversal request failed\n"));
1756 GNUNET_SERVICE_client_continue (ch->client); 1808 GNUNET_SERVICE_client_continue (ch->client);
1757} 1809}
1758 1810
1759 1811
1760/** 1812/**
1761 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
1762 * from client.
1763 *
1764 * @param cls client who sent the message
1765 * @param message the message received
1766 * @return #GNUNET_OK if message is well-formed
1767 */
1768static int
1769check_autoconfig_request (void *cls,
1770 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1771{
1772 return GNUNET_OK; /* checked later */
1773}
1774
1775
1776/**
1777 * Stop all pending activities with respect to the @a ac
1778 *
1779 * @param ac autoconfiguration to terminate activities for
1780 */
1781static void
1782terminate_ac_activities (struct AutoconfigContext *ac)
1783{
1784 if (NULL != ac->probe_external)
1785 {
1786 GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external);
1787 ac->probe_external = NULL;
1788 }
1789 if (NULL != ac->timeout_task)
1790 {
1791 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1792 ac->timeout_task = NULL;
1793 }
1794}
1795
1796
1797/**
1798 * Finish handling the autoconfiguration request and send
1799 * the response to the client.
1800 *
1801 * @param cls the `struct AutoconfigContext` to conclude
1802 */
1803static void
1804conclude_autoconfig_request (void *cls)
1805{
1806 struct AutoconfigContext *ac = cls;
1807 struct ClientHandle *ch = ac->ch;
1808 struct GNUNET_NAT_AutoconfigResultMessage *arm;
1809 struct GNUNET_MQ_Envelope *env;
1810 size_t c_size;
1811 char *buf;
1812 struct GNUNET_CONFIGURATION_Handle *diff;
1813
1814 ac->timeout_task = NULL;
1815 terminate_ac_activities (ac);
1816
1817 /* Send back response */
1818 diff = GNUNET_CONFIGURATION_get_diff (ac->orig,
1819 ac->c);
1820 buf = GNUNET_CONFIGURATION_serialize (diff,
1821 &c_size);
1822 GNUNET_CONFIGURATION_destroy (diff);
1823 env = GNUNET_MQ_msg_extra (arm,
1824 c_size,
1825 GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
1826 arm->status_code = htonl ((uint32_t) ac->status_code);
1827 arm->type = htonl ((uint32_t) ac->type);
1828 GNUNET_memcpy (&arm[1],
1829 buf,
1830 c_size);
1831 GNUNET_free (buf);
1832 GNUNET_MQ_send (ch->mq,
1833 env);
1834
1835 /* clean up */
1836 GNUNET_free (ac->system_type);
1837 GNUNET_CONFIGURATION_destroy (ac->orig);
1838 GNUNET_CONFIGURATION_destroy (ac->c);
1839 GNUNET_CONTAINER_DLL_remove (ac_head,
1840 ac_tail,
1841 ac);
1842 GNUNET_free (ac);
1843 GNUNET_SERVICE_client_continue (ch->client);
1844}
1845
1846
1847/**
1848 * Check if all autoconfiguration operations have concluded,
1849 * and if they have, send the result back to the client.
1850 *
1851 * @param ac autoconfiguation context to check
1852 */
1853static void
1854check_autoconfig_finished (struct AutoconfigContext *ac)
1855{
1856 if (NULL != ac->probe_external)
1857 return;
1858 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1859 ac->timeout_task
1860 = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
1861 ac);
1862}
1863
1864
1865/**
1866 * Update ENABLE_UPNPC configuration option.
1867 *
1868 * @param ac autoconfiguration to update
1869 */
1870static void
1871update_enable_upnpc_option (struct AutoconfigContext *ac)
1872{
1873 switch (ac->enable_upnpc)
1874 {
1875 case GNUNET_YES:
1876 GNUNET_CONFIGURATION_set_value_string (ac->c,
1877 "NAT",
1878 "ENABLE_UPNP",
1879 "YES");
1880 break;
1881 case GNUNET_NO:
1882 GNUNET_CONFIGURATION_set_value_string (ac->c,
1883 "NAT",
1884 "ENABLE_UPNP",
1885 "NO");
1886 break;
1887 case GNUNET_SYSERR:
1888 /* We are unsure, do not change option */
1889 break;
1890 }
1891}
1892
1893
1894/**
1895 * Handle result from external IP address probe during
1896 * autoconfiguration.
1897 *
1898 * @param cls our `struct AutoconfigContext`
1899 * @param addr the address, NULL on errors
1900 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1901 */
1902static void
1903auto_external_result_cb (void *cls,
1904 const struct in_addr *addr,
1905 enum GNUNET_NAT_StatusCode result)
1906{
1907 struct AutoconfigContext *ac = cls;
1908
1909 ac->probe_external = NULL;
1910 switch (result)
1911 {
1912 case GNUNET_NAT_ERROR_SUCCESS:
1913 ac->enable_upnpc = GNUNET_YES;
1914 break;
1915 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1916 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1917 case GNUNET_NAT_ERROR_IPC_FAILURE:
1918 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1919 "Disabling UPNPC: %d\n",
1920 (int) result);
1921 ac->enable_upnpc = GNUNET_NO; /* did not work */
1922 break;
1923 default:
1924 GNUNET_break (0); /* unexpected */
1925 ac->enable_upnpc = GNUNET_SYSERR;
1926 break;
1927 }
1928 update_enable_upnpc_option (ac);
1929 check_autoconfig_finished (ac);
1930}
1931
1932
1933/**
1934 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
1935 * client.
1936 *
1937 * @param cls client who sent the message
1938 * @param message the message received
1939 */
1940static void
1941handle_autoconfig_request (void *cls,
1942 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1943{
1944 struct ClientHandle *ch = cls;
1945 size_t left = ntohs (message->header.size) - sizeof (*message);
1946 struct LocalAddressList *lal;
1947 struct AutoconfigContext *ac;
1948
1949 ac = GNUNET_new (struct AutoconfigContext);
1950 ac->status_code = GNUNET_NAT_ERROR_SUCCESS;
1951 ac->ch = ch;
1952 ac->c = GNUNET_CONFIGURATION_create ();
1953 if (GNUNET_OK !=
1954 GNUNET_CONFIGURATION_deserialize (ac->c,
1955 (const char *) &message[1],
1956 left,
1957 GNUNET_NO))
1958 {
1959 GNUNET_break (0);
1960 GNUNET_SERVICE_client_drop (ch->client);
1961 GNUNET_CONFIGURATION_destroy (ac->c);
1962 GNUNET_free (ac);
1963 return;
1964 }
1965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1966 "Received REQUEST_AUTO_CONFIG message from client\n");
1967
1968 if (GNUNET_OK !=
1969 GNUNET_CONFIGURATION_get_value_string (ac->c,
1970 "PEER",
1971 "SYSTEM_TYPE",
1972 &ac->system_type))
1973 ac->system_type = GNUNET_strdup ("UNKNOWN");
1974
1975 GNUNET_CONTAINER_DLL_insert (ac_head,
1976 ac_tail,
1977 ac);
1978 ac->orig
1979 = GNUNET_CONFIGURATION_dup (ac->c);
1980 ac->timeout_task
1981 = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
1982 &conclude_autoconfig_request,
1983 ac);
1984 ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
1985
1986 /* Probe for upnpc */
1987 if (GNUNET_SYSERR ==
1988 GNUNET_OS_check_helper_binary ("upnpc",
1989 GNUNET_NO,
1990 NULL))
1991 {
1992 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1993 _("UPnP client `upnpc` command not found, disabling UPnP\n"));
1994 ac->enable_upnpc = GNUNET_NO;
1995 }
1996 else
1997 {
1998 for (lal = lal_head; NULL != lal; lal = lal->next)
1999 if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN))
2000 /* we are behind NAT, useful to try upnpc */
2001 ac->enable_upnpc = GNUNET_YES;
2002 }
2003 if (GNUNET_YES == ac->enable_upnpc)
2004 {
2005 /* If we are a mobile device, always leave it on as the network
2006 may change to one that supports UPnP anytime. If we are
2007 stationary, check if our network actually supports UPnP, and if
2008 not, disable it. */
2009 if ( (0 == strcasecmp (ac->system_type,
2010 "INFRASTRUCTURE")) ||
2011 (0 == strcasecmp (ac->system_type,
2012 "DESKTOP")) )
2013 {
2014 /* Check if upnpc gives us an external IP */
2015 ac->probe_external
2016 = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb,
2017 ac);
2018 }
2019 }
2020 if (NULL == ac->probe_external)
2021 update_enable_upnpc_option (ac);
2022
2023 /* Finally, check if we are already done */
2024 check_autoconfig_finished (ac);
2025}
2026
2027
2028/**
2029 * Task run during shutdown. 1813 * Task run during shutdown.
2030 * 1814 *
2031 * @param cls unused 1815 * @param cls unused
@@ -2034,16 +1818,7 @@ static void
2034shutdown_task (void *cls) 1818shutdown_task (void *cls)
2035{ 1819{
2036 struct StunExternalIP *se; 1820 struct StunExternalIP *se;
2037 struct AutoconfigContext *ac;
2038 1821
2039 while (NULL != (ac = ac_head))
2040 {
2041 GNUNET_CONTAINER_DLL_remove (ac_head,
2042 ac_tail,
2043 ac);
2044 terminate_ac_activities (ac);
2045 GNUNET_free (ac);
2046 }
2047 while (NULL != (se = se_head)) 1822 while (NULL != (se = se_head))
2048 { 1823 {
2049 GNUNET_CONTAINER_DLL_remove (se_head, 1824 GNUNET_CONTAINER_DLL_remove (se_head,
@@ -2052,16 +1827,7 @@ shutdown_task (void *cls)
2052 GNUNET_SCHEDULER_cancel (se->timeout_task); 1827 GNUNET_SCHEDULER_cancel (se->timeout_task);
2053 GNUNET_free (se); 1828 GNUNET_free (se);
2054 } 1829 }
2055 if (NULL != probe_external_ip_task) 1830 GN_nat_status_changed (GNUNET_NO);
2056 {
2057 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
2058 probe_external_ip_task = NULL;
2059 }
2060 if (NULL != probe_external_ip_op)
2061 {
2062 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
2063 probe_external_ip_op = NULL;
2064 }
2065 if (NULL != scan_task) 1831 if (NULL != scan_task)
2066 { 1832 {
2067 GNUNET_SCHEDULER_cancel (scan_task); 1833 GNUNET_SCHEDULER_cancel (scan_task);
@@ -2098,7 +1864,7 @@ run (void *cls,
2098 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS; 1864 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
2099 1865
2100 /* Check for UPnP */ 1866 /* Check for UPnP */
2101 enable_upnp 1867 enable_upnp
2102 = GNUNET_CONFIGURATION_get_value_yesno (cfg, 1868 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
2103 "NAT", 1869 "NAT",
2104 "ENABLE_UPNP"); 1870 "ENABLE_UPNP");
@@ -2115,7 +1881,13 @@ run (void *cls,
2115 enable_upnp = GNUNET_SYSERR; 1881 enable_upnp = GNUNET_SYSERR;
2116 } 1882 }
2117 } 1883 }
2118 1884 if (GNUNET_OK !=
1885 GNUNET_CONFIGURATION_get_value_time (cfg,
1886 "nat",
1887 "DYNDNS_FREQUENCY",
1888 &dyndns_frequency))
1889 dyndns_frequency = DYNDNS_FREQUENCY;
1890
2119 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1891 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2120 NULL); 1892 NULL);
2121 stats = GNUNET_STATISTICS_create ("nat", 1893 stats = GNUNET_STATISTICS_create ("nat",
@@ -2163,6 +1935,7 @@ client_disconnect_cb (void *cls,
2163 void *internal_cls) 1935 void *internal_cls)
2164{ 1936{
2165 struct ClientHandle *ch = internal_cls; 1937 struct ClientHandle *ch = internal_cls;
1938 struct LocalAddressList *lal;
2166 1939
2167 GNUNET_CONTAINER_DLL_remove (ch_head, 1940 GNUNET_CONTAINER_DLL_remove (ch_head,
2168 ch_tail, 1941 ch_tail,
@@ -2176,7 +1949,30 @@ client_disconnect_cb (void *cls,
2176 } 1949 }
2177 } 1950 }
2178 GNUNET_free_non_null (ch->caddrs); 1951 GNUNET_free_non_null (ch->caddrs);
2179 GNUNET_free (ch->hole_external); 1952 while (NULL != (lal = ch->ext_addr_head))
1953 {
1954 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1955 ch->ext_addr_tail,
1956 lal);
1957 GNUNET_free (lal);
1958 }
1959 if (NULL != ch->ext_dns_task)
1960 {
1961 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
1962 ch->ext_dns_task = NULL;
1963 }
1964 if (NULL != ch->external_monitor)
1965 {
1966 GN_external_ipv4_monitor_stop (ch->external_monitor);
1967 ch->external_monitor = NULL;
1968 }
1969 if (NULL != ch->ext_dns)
1970 {
1971 GNUNET_RESOLVER_request_cancel (ch->ext_dns);
1972 ch->ext_dns = NULL;
1973 }
1974 GNUNET_free_non_null (ch->hole_external);
1975 GNUNET_free_non_null (ch->section_name);
2180 GNUNET_free (ch); 1976 GNUNET_free (ch);
2181} 1977}
2182 1978
@@ -2203,10 +1999,6 @@ GNUNET_SERVICE_MAIN
2203 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL, 1999 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2204 struct GNUNET_NAT_RequestConnectionReversalMessage, 2000 struct GNUNET_NAT_RequestConnectionReversalMessage,
2205 NULL), 2001 NULL),
2206 GNUNET_MQ_hd_var_size (autoconfig_request,
2207 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
2208 struct GNUNET_NAT_AutoconfigRequestMessage,
2209 NULL),
2210 GNUNET_MQ_handler_end ()); 2002 GNUNET_MQ_handler_end ());
2211 2003
2212 2004