aboutsummaryrefslogtreecommitdiff
path: root/src/nat/nat_api.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-10-24 20:16:19 +0000
committerChristian Grothoff <christian@grothoff.org>2016-10-24 20:16:19 +0000
commit0cda05a0cbbe53f97f74062cbd3fedca7d602925 (patch)
treeb66ce9f5138e9189eb5ff3d7abb0a402c087f84a /src/nat/nat_api.c
parentb81008870d47cfb342bc2a689718fd03eee10cd4 (diff)
downloadgnunet-0cda05a0cbbe53f97f74062cbd3fedca7d602925.tar.gz
gnunet-0cda05a0cbbe53f97f74062cbd3fedca7d602925.zip
working towards new NAT client library implementation
Diffstat (limited to 'src/nat/nat_api.c')
-rw-r--r--src/nat/nat_api.c457
1 files changed, 447 insertions, 10 deletions
diff --git a/src/nat/nat_api.c b/src/nat/nat_api.c
index 6488fdf88..e7320eb50 100644
--- a/src/nat/nat_api.c
+++ b/src/nat/nat_api.c
@@ -28,6 +28,31 @@
28 */ 28 */
29#include "platform.h" 29#include "platform.h"
30#include "gnunet_nat_service.h" 30#include "gnunet_nat_service.h"
31#include "nat.h"
32#include "nat_stun.h"
33
34
35/**
36 * Entry in DLL of addresses of this peer.
37 */
38struct AddrEntry
39{
40
41 /**
42 * DLL.
43 */
44 struct AddrEntry *next;
45
46 /**
47 * DLL.
48 */
49 struct AddrEntry *prev;
50
51 /**
52 * Number of bytes that follow.
53 */
54 socklen_t addrlen;
55};
31 56
32 57
33/** 58/**
@@ -52,6 +77,16 @@ struct GNUNET_NAT_Handle
52 struct GNUNET_MessageHeader *reg; 77 struct GNUNET_MessageHeader *reg;
53 78
54 /** 79 /**
80 * Head of address DLL.
81 */
82 struct AddrEntry *ae_head;
83
84 /**
85 * Tail of address DLL.
86 */
87 struct AddrEntry *ae_tail;
88
89 /**
55 * Function to call when our addresses change. 90 * Function to call when our addresses change.
56 */ 91 */
57 GNUNET_NAT_AddressCallback address_callback; 92 GNUNET_NAT_AddressCallback address_callback;
@@ -66,10 +101,163 @@ struct GNUNET_NAT_Handle
66 */ 101 */
67 void *callback_cls; 102 void *callback_cls;
68 103
104 /**
105 * Task scheduled to reconnect to the service.
106 */
107 struct GNUNET_SCHEDULER_Task *reconnect_task;
108
109 /**
110 * How long to wait until we reconnect.
111 */
112 struct GNUNET_TIME_Relative reconnect_delay;
69}; 113};
70 114
71 115
72/** 116/**
117 * Task to connect to the NAT service.
118 *
119 * @param cls our `struct GNUNET_NAT_Handle *`
120 */
121static void
122do_connect (void *cls);
123
124
125/**
126 * Task to connect to the NAT service.
127 *
128 * @param nh handle to reconnect
129 */
130static void
131reconnect (struct GNUNET_NAT_Handle *nh)
132{
133 if (NULL != nh->mq)
134 {
135 GNUNET_MQ_destroy (nh->mq);
136 nh->mq = NULL;
137 }
138 nh->reconnect_delay
139 = GNUNET_TIME_STD_BACKOFF (nh->reconnect_delay);
140 nh->reconnect_task
141 = GNUNET_SCHEDULER_add_delayed (nh->reconnect_delay,
142 &do_connect,
143 nh);
144}
145
146
147/**
148 * Check connection reversal request.
149 *
150 * @param cls our `struct GNUNET_NAT_Handle`
151 * @param crm the message
152 * @return #GNUNET_OK if @a crm is well-formed
153 */
154static int
155check_connection_reversal_request (void *cls,
156 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
157{
158 GNUNET_break (0);
159 return GNUNET_SYSERR;
160}
161
162
163/**
164 * Handle connection reversal request.
165 *
166 * @param cls our `struct GNUNET_NAT_Handle`
167 * @param crm the message
168 */
169static void
170handle_connection_reversal_request (void *cls,
171 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
172{
173 // FIXME: parse
174 // FIXME: call callback!
175 GNUNET_break (0);
176}
177
178
179/**
180 * Check address change notification.
181 *
182 * @param cls our `struct GNUNET_NAT_Handle`
183 * @param acn the message
184 * @return #GNUNET_OK if @a crm is well-formed
185 */
186static int
187check_address_change_notification (void *cls,
188 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
189{
190 GNUNET_break (0);
191 return GNUNET_SYSERR;
192}
193
194
195/**
196 * Handle connection reversal request.
197 *
198 * @param cls our `struct GNUNET_NAT_Handle`
199 * @param acn the message
200 */
201static void
202handle_address_change_notification (void *cls,
203 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
204{
205 // FIXME: parse
206 // FIXME: update ae-DLL
207 // FIXME: call callback!
208 GNUNET_break (0);
209}
210
211
212/**
213 * Handle queue errors by reconnecting to NAT.
214 *
215 * @param cls the `struct GNUNET_NAT_Handle *`
216 * @param error details about the error
217 */
218static void
219mq_error_handler (void *cls,
220 enum GNUNET_MQ_Error error)
221{
222 struct GNUNET_NAT_Handle *nh = cls;
223
224 reconnect (nh);
225}
226
227
228/**
229 * Task to connect to the NAT service.
230 *
231 * @param cls our `struct GNUNET_NAT_Handle *`
232 */
233static void
234do_connect (void *cls)
235{
236 struct GNUNET_NAT_Handle *nh = cls;
237 struct GNUNET_MQ_MessageHandler handlers[] = {
238 GNUNET_MQ_hd_var_size (connection_reversal_request,
239 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED,
240 struct GNUNET_NAT_ConnectionReversalRequestedMessage,
241 nh),
242 GNUNET_MQ_hd_var_size (address_change_notification,
243 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE,
244 struct GNUNET_NAT_AddressChangeNotificationMessage,
245 nh),
246 GNUNET_MQ_handler_end ()
247 };
248
249 nh->reconnect_task = NULL;
250 nh->mq = GNUNET_CLIENT_connecT (nh->cfg,
251 "nat",
252 handlers,
253 &mq_error_handler,
254 nh);
255 if (NULL == nh->mq)
256 reconnect (nh);
257}
258
259
260/**
73 * Attempt to enable port redirection and detect public IP address 261 * Attempt to enable port redirection and detect public IP address
74 * contacting UPnP or NAT-PMP routers on the local network. Use @a 262 * contacting UPnP or NAT-PMP routers on the local network. Use @a
75 * addr to specify to which of the local host's addresses should the 263 * addr to specify to which of the local host's addresses should the
@@ -101,18 +289,143 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
101 GNUNET_NAT_ReversalCallback reversal_callback, 289 GNUNET_NAT_ReversalCallback reversal_callback,
102 void *callback_cls) 290 void *callback_cls)
103{ 291{
104 struct GNUNET_NAT_Handle *nh = GNUNET_new (struct GNUNET_NAT_Handle); 292 struct GNUNET_NAT_Handle *nh;
105 293 struct GNUNET_NAT_RegisterMessage *rm;
294 size_t len;
295 char *off;
296
297 len = 0;
298 for (unsigned int i=0;i<num_addrs;i++)
299 len += addrlens[i];
300 if ( (len > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*rm)) ||
301 (num_addrs > UINT16_MAX) )
302 {
303 GNUNET_break (0);
304 return NULL;
305 }
306 rm = GNUNET_malloc (sizeof (*rm) + len);
307 rm->header.size = htons (sizeof (*rm) + len);
308 rm->header.type = htons (GNUNET_MESSAGE_TYPE_NAT_REGISTER);
309 rm->flags = GNUNET_NAT_RF_NONE;
310 if (NULL != address_callback)
311 rm->flags |= GNUNET_NAT_RF_ADDRESSES;
312 if (NULL != reversal_callback)
313 rm->flags |= GNUNET_NAT_RF_REVERSAL;
314 rm->proto = proto;
315 rm->adv_port = htons (adv_port);
316 rm->num_addrs = htons ((uint16_t) num_addrs);
317 off = (char *) &rm[1];
318 for (unsigned int i=0;i<num_addrs;i++)
319 {
320 GNUNET_memcpy (off,
321 addrs[i],
322 addrlens[i]);
323 off += addrlens[i];
324 }
325
326 nh = GNUNET_new (struct GNUNET_NAT_Handle);
327 nh->reg = &rm->header;
106 nh->cfg = cfg; 328 nh->cfg = cfg;
107 nh->address_callback = address_callback; 329 nh->address_callback = address_callback;
108 nh->reversal_callback = reversal_callback; 330 nh->reversal_callback = reversal_callback;
109 nh->callback_cls = callback_cls; 331 nh->callback_cls = callback_cls;
332 do_connect (nh);
110 GNUNET_break (0); 333 GNUNET_break (0);
111 return nh; 334 return nh;
112} 335}
113 336
114 337
115/** 338/**
339 * Check if an incoming message is a STUN message.
340 *
341 * @param data the packet
342 * @param len the length of the packet in @a data
343 * @return #GNUNET_YES if @a data is a STUN packet,
344 * #GNUNET_NO if the packet is invalid (not a stun packet)
345 */
346static int
347test_stun_packet (const void *data,
348 size_t len)
349{
350 const struct stun_header *hdr;
351 const struct stun_attr *attr;
352 uint32_t advertised_message_size;
353 uint32_t message_magic_cookie;
354
355 /* On entry, 'len' is the length of the UDP payload. After the
356 * initial checks it becomes the size of unprocessed options,
357 * while 'data' is advanced accordingly.
358 */
359 if (len < sizeof(struct stun_header))
360 {
361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
362 "STUN packet too short (only %d, wanting at least %d)\n",
363 (int) len,
364 (int) sizeof (struct stun_header));
365 return GNUNET_NO;
366 }
367 hdr = (const struct stun_header *) data;
368 /* Skip header as it is already in hdr */
369 len -= sizeof (struct stun_header);
370 data += sizeof (struct stun_header);
371
372 /* len as advertised in the message */
373 advertised_message_size = ntohs (hdr->msglen);
374
375 message_magic_cookie = ntohl (hdr->magic);
376 /* Compare if the cookie match */
377 if (STUN_MAGIC_COOKIE != message_magic_cookie)
378 {
379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
380 "Invalid magic cookie for STUN\n");
381 return GNUNET_NO;
382 }
383
384 if (advertised_message_size > len)
385 {
386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
387 "Scrambled STUN packet length (got %d, expecting %d)\n",
388 advertised_message_size,
389 (int)len);
390 return GNUNET_NO;
391 }
392 len = advertised_message_size;
393 while (len > 0)
394 {
395 if (len < sizeof (struct stun_attr))
396 {
397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398 "Attribute too short in STUN packet (got %d, expecting %d)\n",
399 (int) len,
400 (int) sizeof(struct stun_attr));
401 return GNUNET_NO;
402 }
403 attr = (const struct stun_attr *) data;
404
405 /* compute total attribute length */
406 advertised_message_size = ntohs (attr->len) + sizeof(struct stun_attr);
407
408 /* Check if we still have space in our buffer */
409 if (advertised_message_size > len)
410 {
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n",
413 advertised_message_size,
414 (int) len);
415 return GNUNET_NO;
416 }
417 data += advertised_message_size;
418 len -= advertised_message_size;
419 }
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421 "STUN Packet, msg %04x, length: %d\n",
422 ntohs (hdr->msgtype),
423 advertised_message_size);
424 return GNUNET_OK;
425}
426
427
428/**
116 * Handle an incoming STUN message. This function is useful as 429 * Handle an incoming STUN message. This function is useful as
117 * some GNUnet service may be listening on a UDP port and might 430 * some GNUnet service may be listening on a UDP port and might
118 * thus receive STUN messages while trying to receive other data. 431 * thus receive STUN messages while trying to receive other data.
@@ -128,6 +441,7 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
128 * 441 *
129 * @param nh handle to the NAT service 442 * @param nh handle to the NAT service
130 * @param sender_addr address from which we got @a data 443 * @param sender_addr address from which we got @a data
444 * @param sender_addr_len number of bytes in @a sender_addr
131 * @param data the packet 445 * @param data the packet
132 * @param data_size number of bytes in @a data 446 * @param data_size number of bytes in @a data
133 * @return #GNUNET_OK on success 447 * @return #GNUNET_OK on success
@@ -137,11 +451,36 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
137int 451int
138GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh, 452GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
139 const struct sockaddr *sender_addr, 453 const struct sockaddr *sender_addr,
454 size_t sender_addr_len,
140 const void *data, 455 const void *data,
141 size_t data_size) 456 size_t data_size)
142{ 457{
143 GNUNET_break (0); 458 struct GNUNET_MQ_Envelope *env;
144 return GNUNET_SYSERR; 459 struct GNUNET_NAT_HandleStunMessage *hsn;
460 char *buf;
461
462 if (GNUNET_YES !=
463 test_stun_packet (data,
464 data_size))
465 return GNUNET_NO;
466 if (NULL == nh->mq)
467 return GNUNET_SYSERR;
468 env = GNUNET_MQ_msg_extra (hsn,
469 data_size + sender_addr_len,
470 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN);
471 hsn->sender_addr_size = htons ((uint16_t) sender_addr_len);
472 hsn->payload_size = htons ((uint16_t) data_size);
473 buf = (char *) &hsn[1];
474 GNUNET_memcpy (buf,
475 sender_addr,
476 sender_addr_len);
477 buf += sender_addr_len;
478 GNUNET_memcpy (buf,
479 data,
480 data_size);
481 GNUNET_MQ_send (nh->mq,
482 env);
483 return GNUNET_OK;
145} 484}
146 485
147 486
@@ -163,8 +502,21 @@ GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
163 const void *addr, 502 const void *addr,
164 socklen_t addrlen) 503 socklen_t addrlen)
165{ 504{
166 GNUNET_break (0); 505 struct AddrEntry *ae;
167 return GNUNET_SYSERR; 506
507 if ( (addrlen != sizeof (struct sockaddr_in)) &&
508 (addrlen != sizeof (struct sockaddr_in6)) )
509 {
510 GNUNET_break (0);
511 return GNUNET_SYSERR;
512 }
513 for (ae = nh->ae_head; NULL != ae; ae = ae->next)
514 if ( (addrlen == ae->addrlen) &&
515 (0 == memcmp (addr,
516 &ae[1],
517 addrlen)) )
518 return GNUNET_YES;
519 return GNUNET_NO;
168} 520}
169 521
170 522
@@ -185,8 +537,28 @@ GNUNET_NAT_request_reversal (struct GNUNET_NAT_Handle *nh,
185 const struct sockaddr_in *local_sa, 537 const struct sockaddr_in *local_sa,
186 const struct sockaddr_in *remote_sa) 538 const struct sockaddr_in *remote_sa)
187{ 539{
188 GNUNET_break (0); 540 struct GNUNET_MQ_Envelope *env;
189 return GNUNET_SYSERR; 541 struct GNUNET_NAT_RequestConnectionReversalMessage *req;
542 char *buf;
543
544 if (NULL == nh->mq)
545 return GNUNET_SYSERR;
546 env = GNUNET_MQ_msg_extra (req,
547 2 * sizeof (struct sockaddr_in),
548 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL);
549 req->local_addr_size = htons (sizeof (struct sockaddr_in));
550 req->remote_addr_size = htons (sizeof (struct sockaddr_in));
551 buf = (char *) &req[1];
552 GNUNET_memcpy (buf,
553 local_sa,
554 sizeof (struct sockaddr_in));
555 buf += sizeof (struct sockaddr_in);
556 GNUNET_memcpy (buf,
557 remote_sa,
558 sizeof (struct sockaddr_in));
559 GNUNET_MQ_send (nh->mq,
560 env);
561 return GNUNET_OK;
190} 562}
191 563
192 564
@@ -237,6 +609,44 @@ struct GNUNET_NAT_Test
237 609
238 610
239/** 611/**
612 * Handle result for a NAT test from the service.
613 *
614 * @param cls our `struct GNUNET_NAT_Test *`
615 * @param rm message with the result of the test
616 */
617static void
618handle_test_result (void *cls,
619 const struct GNUNET_NAT_TestResultMessage *rm)
620{
621 struct GNUNET_NAT_Test *tst = cls;
622 enum GNUNET_NAT_StatusCode sc;
623
624 sc = (enum GNUNET_NAT_StatusCode) ntohl (rm->status_code);
625 tst->cb (tst->cb_cls,
626 sc);
627 GNUNET_NAT_test_stop (tst);
628}
629
630
631/**
632 * Handle queue errors by reconnecting to NAT.
633 *
634 * @param cls the `struct GNUNET_NAT_Test *`
635 * @param error details about the error
636 */
637static void
638tst_error_handler (void *cls,
639 enum GNUNET_MQ_Error error)
640{
641 struct GNUNET_NAT_Test *tst = cls;
642
643 tst->cb (tst->cb_cls,
644 GNUNET_NAT_ERROR_IPC_FAILURE);
645 GNUNET_NAT_test_stop (tst);
646}
647
648
649/**
240 * Start testing if NAT traversal works using the given configuration 650 * Start testing if NAT traversal works using the given configuration
241 * (IPv4-only). The transport adapters should be down while using 651 * (IPv4-only). The transport adapters should be down while using
242 * this function. 652 * this function.
@@ -262,10 +672,38 @@ GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
262 void *report_cls) 672 void *report_cls)
263{ 673{
264 struct GNUNET_NAT_Test *tst = GNUNET_new (struct GNUNET_NAT_Test); 674 struct GNUNET_NAT_Test *tst = GNUNET_new (struct GNUNET_NAT_Test);
675 struct GNUNET_MQ_MessageHandler handlers[] = {
676 GNUNET_MQ_hd_fixed_size (test_result,
677 GNUNET_MESSAGE_TYPE_NAT_TEST_RESULT,
678 struct GNUNET_NAT_TestResultMessage,
679 tst),
680 GNUNET_MQ_handler_end ()
681 };
682 struct GNUNET_MQ_Envelope *env;
683 struct GNUNET_NAT_RequestTestMessage *req;
265 684
266 tst->cb = report; 685 tst->cb = report;
267 tst->cb_cls = report_cls; 686 tst->cb_cls = report_cls;
268 GNUNET_break (0); 687 tst->mq = GNUNET_CLIENT_connecT (cfg,
688 "nat",
689 handlers,
690 &tst_error_handler,
691 tst);
692 if (NULL == tst->mq)
693 {
694 GNUNET_break (0);
695 GNUNET_free (tst);
696 return NULL;
697 }
698 env = GNUNET_MQ_msg (req,
699 GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST);
700 req->bind_port = htons (bnd_port);
701 req->extern_port = htons (extern_port);
702 req->bind_ip = bind_ip;
703 req->extern_ip = extern_ip;
704 req->proto = proto;
705 GNUNET_MQ_send (tst->mq,
706 env);
269 return tst; 707 return tst;
270} 708}
271 709
@@ -278,7 +716,6 @@ GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
278void 716void
279GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst) 717GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst)
280{ 718{
281 GNUNET_break (0);
282 GNUNET_MQ_destroy (tst->mq); 719 GNUNET_MQ_destroy (tst->mq);
283 GNUNET_free (tst); 720 GNUNET_free (tst);
284} 721}