2 This file is part of GNUnet.
3 Copyright (C) 2007-2016 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @author Christian Grothoff
23 * @author Milan Bouchet-Valat
26 * Service for handling UPnP and NAT-PMP port forwarding
27 * and external IP address retrieval
30 #include "gnunet_nat_service.h"
36 * Entry in DLL of addresses of this peer.
44 struct AddrEntry *next;
49 struct AddrEntry *prev;
52 * Number of bytes that follow.
59 * Handle for active NAT registrations.
61 struct GNUNET_NAT_Handle
65 * Configuration we use.
67 const struct GNUNET_CONFIGURATION_Handle *cfg;
70 * Message queue for communicating with the NAT service.
72 struct GNUNET_MQ_Handle *mq;
75 * Our registration message.
77 struct GNUNET_MessageHeader *reg;
80 * Head of address DLL.
82 struct AddrEntry *ae_head;
85 * Tail of address DLL.
87 struct AddrEntry *ae_tail;
90 * Function to call when our addresses change.
92 GNUNET_NAT_AddressCallback address_callback;
95 * Function to call when another peer requests connection reversal.
97 GNUNET_NAT_ReversalCallback reversal_callback;
100 * Closure for the various callbacks.
105 * Task scheduled to reconnect to the service.
107 struct GNUNET_SCHEDULER_Task *reconnect_task;
110 * How long to wait until we reconnect.
112 struct GNUNET_TIME_Relative reconnect_delay;
117 * Task to connect to the NAT service.
119 * @param cls our `struct GNUNET_NAT_Handle *`
122 do_connect (void *cls);
126 * Task to connect to the NAT service.
128 * @param nh handle to reconnect
131 reconnect (struct GNUNET_NAT_Handle *nh)
135 GNUNET_MQ_destroy (nh->mq);
139 = GNUNET_TIME_STD_BACKOFF (nh->reconnect_delay);
141 = GNUNET_SCHEDULER_add_delayed (nh->reconnect_delay,
148 * Check connection reversal request.
150 * @param cls our `struct GNUNET_NAT_Handle`
151 * @param crm the message
152 * @return #GNUNET_OK if @a crm is well-formed
155 check_connection_reversal_request (void *cls,
156 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
159 return GNUNET_SYSERR;
164 * Handle connection reversal request.
166 * @param cls our `struct GNUNET_NAT_Handle`
167 * @param crm the message
170 handle_connection_reversal_request (void *cls,
171 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
174 // FIXME: call callback!
180 * Check address change notification.
182 * @param cls our `struct GNUNET_NAT_Handle`
183 * @param acn the message
184 * @return #GNUNET_OK if @a crm is well-formed
187 check_address_change_notification (void *cls,
188 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
191 return GNUNET_SYSERR;
196 * Handle connection reversal request.
198 * @param cls our `struct GNUNET_NAT_Handle`
199 * @param acn the message
202 handle_address_change_notification (void *cls,
203 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
206 // FIXME: update ae-DLL
207 // FIXME: call callback!
213 * Handle queue errors by reconnecting to NAT.
215 * @param cls the `struct GNUNET_NAT_Handle *`
216 * @param error details about the error
219 mq_error_handler (void *cls,
220 enum GNUNET_MQ_Error error)
222 struct GNUNET_NAT_Handle *nh = cls;
229 * Task to connect to the NAT service.
231 * @param cls our `struct GNUNET_NAT_Handle *`
234 do_connect (void *cls)
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,
242 GNUNET_MQ_hd_var_size (address_change_notification,
243 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE,
244 struct GNUNET_NAT_AddressChangeNotificationMessage,
246 GNUNET_MQ_handler_end ()
249 nh->reconnect_task = NULL;
250 nh->mq = GNUNET_CLIENT_connecT (nh->cfg,
261 * Attempt to enable port redirection and detect public IP address
262 * contacting UPnP or NAT-PMP routers on the local network. Use @a
263 * addr to specify to which of the local host's addresses should the
264 * external port be mapped. The port is taken from the corresponding
265 * sockaddr_in[6] field. The NAT module should call the given @a
266 * address_callback for any 'plausible' external address.
268 * @param cfg configuration to use
269 * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP
270 * @param adv_port advertised port (port we are either bound to or that our OS
271 * locally performs redirection from to our bound port).
272 * @param num_addrs number of addresses in @a addrs
273 * @param addrs list of local addresses packets should be redirected to
274 * @param addrlens actual lengths of the addresses in @a addrs
275 * @param address_callback function to call everytime the public IP address changes
276 * @param reversal_callback function to call if someone wants connection reversal from us,
277 * NULL if connection reversal is not supported
278 * @param callback_cls closure for callbacks
279 * @return NULL on error, otherwise handle that can be used to unregister
281 struct GNUNET_NAT_Handle *
282 GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
285 unsigned int num_addrs,
286 const struct sockaddr **addrs,
287 const socklen_t *addrlens,
288 GNUNET_NAT_AddressCallback address_callback,
289 GNUNET_NAT_ReversalCallback reversal_callback,
292 struct GNUNET_NAT_Handle *nh;
293 struct GNUNET_NAT_RegisterMessage *rm;
298 for (unsigned int i=0;i<num_addrs;i++)
300 if ( (len > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*rm)) ||
301 (num_addrs > UINT16_MAX) )
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;
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++)
326 nh = GNUNET_new (struct GNUNET_NAT_Handle);
327 nh->reg = &rm->header;
329 nh->address_callback = address_callback;
330 nh->reversal_callback = reversal_callback;
331 nh->callback_cls = callback_cls;
339 * Check if an incoming message is a STUN message.
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)
347 test_stun_packet (const void *data,
350 const struct stun_header *hdr;
351 const struct stun_attr *attr;
352 uint32_t advertised_message_size;
353 uint32_t message_magic_cookie;
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.
359 if (len < sizeof(struct stun_header))
361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
362 "STUN packet too short (only %d, wanting at least %d)\n",
364 (int) sizeof (struct stun_header));
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);
372 /* len as advertised in the message */
373 advertised_message_size = ntohs (hdr->msglen);
375 message_magic_cookie = ntohl (hdr->magic);
376 /* Compare if the cookie match */
377 if (STUN_MAGIC_COOKIE != message_magic_cookie)
379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
380 "Invalid magic cookie for STUN\n");
384 if (advertised_message_size > len)
386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
387 "Scrambled STUN packet length (got %d, expecting %d)\n",
388 advertised_message_size,
392 len = advertised_message_size;
395 if (len < sizeof (struct stun_attr))
397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398 "Attribute too short in STUN packet (got %d, expecting %d)\n",
400 (int) sizeof(struct stun_attr));
403 attr = (const struct stun_attr *) data;
405 /* compute total attribute length */
406 advertised_message_size = ntohs (attr->len) + sizeof(struct stun_attr);
408 /* Check if we still have space in our buffer */
409 if (advertised_message_size > len)
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n",
413 advertised_message_size,
417 data += advertised_message_size;
418 len -= advertised_message_size;
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421 "STUN Packet, msg %04x, length: %d\n",
422 ntohs (hdr->msgtype),
423 advertised_message_size);
429 * Handle an incoming STUN message. This function is useful as
430 * some GNUnet service may be listening on a UDP port and might
431 * thus receive STUN messages while trying to receive other data.
432 * In this case, this function can be used to act as a proper
433 * STUN server (if desired).
435 * The function does some basic sanity checks on packet size and
436 * content, try to extract a bit of information, and possibly replies
437 * if this is an actual STUN message.
439 * At the moment this only processes BIND requests, and returns the
440 * externally visible address of the request.
442 * @param nh handle to the NAT service
443 * @param sender_addr address from which we got @a data
444 * @param sender_addr_len number of bytes in @a sender_addr
445 * @param data the packet
446 * @param data_size number of bytes in @a data
447 * @return #GNUNET_OK on success
448 * #GNUNET_NO if the packet is not a STUN packet
449 * #GNUNET_SYSERR on internal error handling the packet
452 GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
453 const struct sockaddr *sender_addr,
454 size_t sender_addr_len,
458 struct GNUNET_MQ_Envelope *env;
459 struct GNUNET_NAT_HandleStunMessage *hsn;
463 test_stun_packet (data,
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];
477 buf += sender_addr_len;
481 GNUNET_MQ_send (nh->mq,
488 * Test if the given address is (currently) a plausible IP address for
489 * this peer. Mostly a convenience function so that clients do not
490 * have to explicitly track all IPs that the #GNUNET_NAT_AddressCallback
491 * has returned so far.
493 * @param nh the handle returned by register
494 * @param addr IP address to test (IPv4 or IPv6)
495 * @param addrlen number of bytes in @a addr
496 * @return #GNUNET_YES if the address is plausible,
497 * #GNUNET_NO if the address is not plausible,
498 * #GNUNET_SYSERR if the address is malformed
501 GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
505 struct AddrEntry *ae;
507 if ( (addrlen != sizeof (struct sockaddr_in)) &&
508 (addrlen != sizeof (struct sockaddr_in6)) )
511 return GNUNET_SYSERR;
513 for (ae = nh->ae_head; NULL != ae; ae = ae->next)
514 if ( (addrlen == ae->addrlen) &&
524 * We learned about a peer (possibly behind NAT) so run the
525 * gnunet-nat-client to send dummy ICMP responses to cause
526 * that peer to connect to us (connection reversal).
528 * @param nh handle (used for configuration)
529 * @param local_sa our local address of the peer (IPv4-only)
530 * @param remote_sa the remote address of the peer (IPv4-only)
531 * @return #GNUNET_SYSERR on error,
532 * #GNUNET_NO if connection reversal is unavailable,
533 * #GNUNET_OK otherwise (presumably in progress)
536 GNUNET_NAT_request_reversal (struct GNUNET_NAT_Handle *nh,
537 const struct sockaddr_in *local_sa,
538 const struct sockaddr_in *remote_sa)
540 struct GNUNET_MQ_Envelope *env;
541 struct GNUNET_NAT_RequestConnectionReversalMessage *req;
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];
554 sizeof (struct sockaddr_in));
555 buf += sizeof (struct sockaddr_in);
558 sizeof (struct sockaddr_in));
559 GNUNET_MQ_send (nh->mq,
566 * Stop port redirection and public IP address detection for the given
567 * handle. This frees the handle, after having sent the needed
568 * commands to close open ports.
570 * @param nh the handle to stop
573 GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh)
575 GNUNET_MQ_destroy (nh->mq);
576 GNUNET_free (nh->reg);
582 * Handle to a NAT test.
584 struct GNUNET_NAT_Test
588 * Configuration we use.
590 const struct GNUNET_CONFIGURATION_Handle *cfg;
593 * Message queue for communicating with the NAT service.
595 struct GNUNET_MQ_Handle *mq;
598 * Function called to report success or failure for
599 * NAT configuration test.
601 GNUNET_NAT_TestCallback cb;
612 * Handle result for a NAT test from the service.
614 * @param cls our `struct GNUNET_NAT_Test *`
615 * @param rm message with the result of the test
618 handle_test_result (void *cls,
619 const struct GNUNET_NAT_TestResultMessage *rm)
621 struct GNUNET_NAT_Test *tst = cls;
622 enum GNUNET_NAT_StatusCode sc;
624 sc = (enum GNUNET_NAT_StatusCode) ntohl (rm->status_code);
625 tst->cb (tst->cb_cls,
627 GNUNET_NAT_test_stop (tst);
632 * Handle queue errors by reconnecting to NAT.
634 * @param cls the `struct GNUNET_NAT_Test *`
635 * @param error details about the error
638 tst_error_handler (void *cls,
639 enum GNUNET_MQ_Error error)
641 struct GNUNET_NAT_Test *tst = cls;
643 tst->cb (tst->cb_cls,
644 GNUNET_NAT_ERROR_IPC_FAILURE);
645 GNUNET_NAT_test_stop (tst);
650 * Start testing if NAT traversal works using the given configuration
651 * (IPv4-only). The transport adapters should be down while using
654 * @param cfg configuration for the NAT traversal
655 * @param proto protocol to test, i.e. IPPROTO_TCP or IPPROTO_UDP
656 * @param bind_ip IPv4 address to bind to
657 * @param bnd_port port to bind to, 0 to test connection reversal
658 * @param extern_ip IPv4 address to externally advertise
659 * @param extern_port externally advertised port to use
660 * @param report function to call with the result of the test
661 * @param report_cls closure for @a report
662 * @return handle to cancel NAT test
664 struct GNUNET_NAT_Test *
665 GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
667 struct in_addr bind_ip,
669 struct in_addr extern_ip,
670 uint16_t extern_port,
671 GNUNET_NAT_TestCallback report,
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,
680 GNUNET_MQ_handler_end ()
682 struct GNUNET_MQ_Envelope *env;
683 struct GNUNET_NAT_RequestTestMessage *req;
686 tst->cb_cls = report_cls;
687 tst->mq = GNUNET_CLIENT_connecT (cfg,
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;
705 GNUNET_MQ_send (tst->mq,
712 * Stop an active NAT test.
714 * @param tst test to stop.
717 GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst)
719 GNUNET_MQ_destroy (tst->mq);
725 * Handle to auto-configuration in progress.
727 struct GNUNET_NAT_AutoHandle
731 * Configuration we use.
733 const struct GNUNET_CONFIGURATION_Handle *cfg;
736 * Message queue for communicating with the NAT service.
738 struct GNUNET_MQ_Handle *mq;
741 * Function called with the result from the autoconfiguration.
743 GNUNET_NAT_AutoResultCallback arc;
746 * Closure for @e arc.
754 * Converts `enum GNUNET_NAT_StatusCode` to string
756 * @param err error code to resolve to a string
757 * @return point to a static string containing the error code
760 GNUNET_NAT_status2string (enum GNUNET_NAT_StatusCode err)
768 * Start auto-configuration routine. The transport adapters should
769 * be stopped while this function is called.
771 * @param cfg initial configuration
772 * @param cb function to call with autoconfiguration result
773 * @param cb_cls closure for @a cb
774 * @return handle to cancel operation
776 struct GNUNET_NAT_AutoHandle *
777 GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
778 GNUNET_NAT_AutoResultCallback cb,
781 struct GNUNET_NAT_AutoHandle *ah = GNUNET_new (struct GNUNET_NAT_AutoHandle);
785 ah->arc_cls = cb_cls;
792 * Abort autoconfiguration.
794 * @param ah handle for operation to abort
797 GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah)
800 GNUNET_MQ_destroy (ah->mq);
804 /* end of nat_api.c */