2 This file is part of GNUnet.
3 Copyright (C) 2007-2017 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
17 * @author Christian Grothoff
18 * @author Milan Bouchet-Valat
21 * Service for handling UPnP and NAT-PMP port forwarding
22 * and external IP address retrieval
25 #include "gnunet_nat_service.h"
31 * Entry in DLL of addresses of this peer.
39 struct AddrEntry *next;
44 struct AddrEntry *prev;
47 * Address class of the address.
49 enum GNUNET_NAT_AddressClass ac;
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)
133 struct AddrEntry *ae;
137 GNUNET_MQ_destroy (nh->mq);
140 while (NULL != (ae = nh->ae_head))
142 GNUNET_CONTAINER_DLL_remove (nh->ae_head,
145 nh->address_callback (nh->callback_cls,
148 (const struct sockaddr *) &ae[1],
153 = GNUNET_TIME_STD_BACKOFF (nh->reconnect_delay);
155 = GNUNET_SCHEDULER_add_delayed (nh->reconnect_delay,
162 * Check connection reversal request.
164 * @param cls our `struct GNUNET_NAT_Handle`
165 * @param crm the message
166 * @return #GNUNET_OK if @a crm is well-formed
169 check_connection_reversal_request (void *cls,
170 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
172 if (ntohs (crm->header.size) !=
174 sizeof (struct sockaddr_in) )
177 return GNUNET_SYSERR;
184 * Handle connection reversal request.
186 * @param cls our `struct GNUNET_NAT_Handle`
187 * @param crm the message
190 handle_connection_reversal_request (void *cls,
191 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
193 struct GNUNET_NAT_Handle *nh = cls;
195 nh->reversal_callback (nh->callback_cls,
196 (const struct sockaddr *) &crm[1],
197 sizeof (struct sockaddr_in));
202 * Check address change notification.
204 * @param cls our `struct GNUNET_NAT_Handle`
205 * @param acn the message
206 * @return #GNUNET_OK if @a crm is well-formed
209 check_address_change_notification (void *cls,
210 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
212 size_t alen = ntohs (acn->header.size) - sizeof (*acn);
216 case sizeof (struct sockaddr_in):
218 const struct sockaddr_in *s4
219 = (const struct sockaddr_in *) &acn[1];
220 if (AF_INET != s4->sin_family)
223 return GNUNET_SYSERR;
227 case sizeof (struct sockaddr_in6):
229 const struct sockaddr_in6 *s6
230 = (const struct sockaddr_in6 *) &acn[1];
231 if (AF_INET6 != s6->sin6_family)
234 return GNUNET_SYSERR;
240 return GNUNET_SYSERR;
247 * Handle connection reversal request.
249 * @param cls our `struct GNUNET_NAT_Handle`
250 * @param acn the message
253 handle_address_change_notification (void *cls,
254 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
256 struct GNUNET_NAT_Handle *nh = cls;
257 size_t alen = ntohs (acn->header.size) - sizeof (*acn);
258 const struct sockaddr *sa = (const struct sockaddr *) &acn[1];
259 enum GNUNET_NAT_AddressClass ac;
260 struct AddrEntry *ae;
262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
263 "Received address change notification\n");
264 ac = (enum GNUNET_NAT_AddressClass) ntohl (acn->addr_class);
265 if (GNUNET_YES == ntohl (acn->add_remove))
267 ae = GNUNET_malloc (sizeof (*ae) + alen);
270 GNUNET_memcpy (&ae[1],
273 GNUNET_CONTAINER_DLL_insert (nh->ae_head,
279 for (ae = nh->ae_head; NULL != ae; ae = ae->next)
280 if ( (ae->addrlen == alen) &&
281 (0 == memcmp (&ae[1],
291 GNUNET_CONTAINER_DLL_remove (nh->ae_head,
296 nh->address_callback (nh->callback_cls,
297 ntohl (acn->add_remove),
305 * Handle queue errors by reconnecting to NAT.
307 * @param cls the `struct GNUNET_NAT_Handle *`
308 * @param error details about the error
311 mq_error_handler (void *cls,
312 enum GNUNET_MQ_Error error)
314 struct GNUNET_NAT_Handle *nh = cls;
321 * Task to connect to the NAT service.
323 * @param cls our `struct GNUNET_NAT_Handle *`
326 do_connect (void *cls)
328 struct GNUNET_NAT_Handle *nh = cls;
329 struct GNUNET_MQ_MessageHandler handlers[] = {
330 GNUNET_MQ_hd_var_size (connection_reversal_request,
331 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED,
332 struct GNUNET_NAT_ConnectionReversalRequestedMessage,
334 GNUNET_MQ_hd_var_size (address_change_notification,
335 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE,
336 struct GNUNET_NAT_AddressChangeNotificationMessage,
338 GNUNET_MQ_handler_end ()
340 struct GNUNET_MQ_Envelope *env;
342 nh->reconnect_task = NULL;
343 nh->mq = GNUNET_CLIENT_connect (nh->cfg,
353 env = GNUNET_MQ_msg_copy (nh->reg);
354 GNUNET_MQ_send (nh->mq,
360 * Attempt to enable port redirection and detect public IP address
361 * contacting UPnP or NAT-PMP routers on the local network. Use @a
362 * addr to specify to which of the local host's addresses should the
363 * external port be mapped. The port is taken from the corresponding
364 * sockaddr_in[6] field. The NAT module should call the given @a
365 * address_callback for any 'plausible' external address.
367 * @param cfg configuration to use
368 * @param config_section name of the configuration section for optionsx
369 * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP
370 * @param num_addrs number of addresses in @a addrs
371 * @param addrs list of local addresses packets should be redirected to
372 * @param addrlens actual lengths of the addresses in @a addrs
373 * @param address_callback function to call everytime the public IP address changes
374 * @param reversal_callback function to call if someone wants connection reversal from us,
375 * NULL if connection reversal is not supported
376 * @param callback_cls closure for callbacks
377 * @return NULL on error, otherwise handle that can be used to unregister
379 struct GNUNET_NAT_Handle *
380 GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
381 const char *config_section,
383 unsigned int num_addrs,
384 const struct sockaddr **addrs,
385 const socklen_t *addrlens,
386 GNUNET_NAT_AddressCallback address_callback,
387 GNUNET_NAT_ReversalCallback reversal_callback,
390 struct GNUNET_NAT_Handle *nh;
391 struct GNUNET_NAT_RegisterMessage *rm;
397 for (unsigned int i=0;i<num_addrs;i++)
399 str_len = strlen (config_section) + 1;
401 if ( (len > GNUNET_MAX_MESSAGE_SIZE - sizeof (*rm)) ||
402 (num_addrs > UINT16_MAX) )
407 rm = GNUNET_malloc (sizeof (*rm) + len);
408 rm->header.size = htons (sizeof (*rm) + len);
409 rm->header.type = htons (GNUNET_MESSAGE_TYPE_NAT_REGISTER);
410 rm->flags = GNUNET_NAT_RF_NONE;
411 if (NULL != address_callback)
412 rm->flags |= GNUNET_NAT_RF_ADDRESSES;
413 if (NULL != reversal_callback)
414 rm->flags |= GNUNET_NAT_RF_REVERSAL;
416 rm->str_len = htons (str_len);
417 rm->num_addrs = htons ((uint16_t) num_addrs);
418 off = (char *) &rm[1];
419 for (unsigned int i=0;i<num_addrs;i++)
421 switch (addrs[i]->sa_family)
424 if (sizeof (struct sockaddr_in) != addrlens[i])
432 if (sizeof (struct sockaddr_in6) != addrlens[i])
441 if (sizeof (struct sockaddr_un) != addrlens[i])
463 nh = GNUNET_new (struct GNUNET_NAT_Handle);
464 nh->reg = &rm->header;
466 nh->address_callback = address_callback;
467 nh->reversal_callback = reversal_callback;
468 nh->callback_cls = callback_cls;
475 * Check if an incoming message is a STUN message.
477 * @param data the packet
478 * @param len the length of the packet in @a data
479 * @return #GNUNET_YES if @a data is a STUN packet,
480 * #GNUNET_NO if the packet is invalid (not a stun packet)
483 test_stun_packet (const void *data,
486 const struct stun_header *hdr;
487 const struct stun_attr *attr;
488 uint32_t advertised_message_size;
489 uint32_t message_magic_cookie;
491 /* On entry, 'len' is the length of the UDP payload. After the
492 * initial checks it becomes the size of unprocessed options,
493 * while 'data' is advanced accordingly.
495 if (len < sizeof(struct stun_header))
497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498 "STUN packet too short (only %d, wanting at least %d)\n",
500 (int) sizeof (struct stun_header));
503 hdr = (const struct stun_header *) data;
504 /* Skip header as it is already in hdr */
505 len -= sizeof (struct stun_header);
506 data += sizeof (struct stun_header);
508 /* len as advertised in the message */
509 advertised_message_size = ntohs (hdr->msglen);
511 message_magic_cookie = ntohl (hdr->magic);
512 /* Compare if the cookie match */
513 if (STUN_MAGIC_COOKIE != message_magic_cookie)
515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
516 "Invalid magic cookie for STUN\n");
520 if (advertised_message_size > len)
522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
523 "Scrambled STUN packet length (got %d, expecting %d)\n",
524 advertised_message_size,
528 len = advertised_message_size;
531 if (len < sizeof (struct stun_attr))
533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
534 "Attribute too short in STUN packet (got %d, expecting %d)\n",
536 (int) sizeof(struct stun_attr));
539 attr = (const struct stun_attr *) data;
541 /* compute total attribute length */
542 advertised_message_size = ntohs (attr->len) + sizeof(struct stun_attr);
544 /* Check if we still have space in our buffer */
545 if (advertised_message_size > len)
547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
548 "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n",
549 advertised_message_size,
553 data += advertised_message_size;
554 len -= advertised_message_size;
556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
557 "STUN Packet, msg %04x, length: %d\n",
558 ntohs (hdr->msgtype),
559 advertised_message_size);
565 * Handle an incoming STUN message. This function is useful as
566 * some GNUnet service may be listening on a UDP port and might
567 * thus receive STUN messages while trying to receive other data.
568 * In this case, this function can be used to process replies
571 * The function does some basic sanity checks on packet size and
572 * content, try to extract a bit of information.
574 * At the moment this only processes BIND requests, and returns the
575 * externally visible address of the request to the rest of the
578 * @param nh handle to the NAT service
579 * @param sender_addr address from which we got @a data
580 * @param sender_addr_len number of bytes in @a sender_addr
581 * @param data the packet
582 * @param data_size number of bytes in @a data
583 * @return #GNUNET_OK on success
584 * #GNUNET_NO if the packet is not a STUN packet
585 * #GNUNET_SYSERR on internal error handling the packet
588 GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
589 const struct sockaddr *sender_addr,
590 size_t sender_addr_len,
594 struct GNUNET_MQ_Envelope *env;
595 struct GNUNET_NAT_HandleStunMessage *hsn;
599 test_stun_packet (data,
603 return GNUNET_SYSERR;
604 env = GNUNET_MQ_msg_extra (hsn,
605 data_size + sender_addr_len,
606 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN);
607 hsn->sender_addr_size = htons ((uint16_t) sender_addr_len);
608 hsn->payload_size = htons ((uint16_t) data_size);
609 buf = (char *) &hsn[1];
613 buf += sender_addr_len;
617 GNUNET_MQ_send (nh->mq,
624 * Test if the given address is (currently) a plausible IP address for
625 * this peer. Mostly a convenience function so that clients do not
626 * have to explicitly track all IPs that the #GNUNET_NAT_AddressCallback
627 * has returned so far.
629 * @param nh the handle returned by register
630 * @param addr IP address to test (IPv4 or IPv6)
631 * @param addrlen number of bytes in @a addr
632 * @return #GNUNET_YES if the address is plausible,
633 * #GNUNET_NO if the address is not plausible,
634 * #GNUNET_SYSERR if the address is malformed
637 GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
641 struct AddrEntry *ae;
643 if ( (addrlen != sizeof (struct sockaddr_in)) &&
644 (addrlen != sizeof (struct sockaddr_in6)) )
647 return GNUNET_SYSERR;
649 for (ae = nh->ae_head; NULL != ae; ae = ae->next)
650 if ( (addrlen == ae->addrlen) &&
660 * We learned about a peer (possibly behind NAT) so run the
661 * gnunet-nat-client to send dummy ICMP responses to cause
662 * that peer to connect to us (connection reversal).
664 * @param nh handle (used for configuration)
665 * @param local_sa our local address of the peer (IPv4-only)
666 * @param remote_sa the remote address of the peer (IPv4-only)
667 * @return #GNUNET_SYSERR on error,
668 * #GNUNET_NO if connection reversal is unavailable,
669 * #GNUNET_OK otherwise (presumably in progress)
672 GNUNET_NAT_request_reversal (struct GNUNET_NAT_Handle *nh,
673 const struct sockaddr_in *local_sa,
674 const struct sockaddr_in *remote_sa)
676 struct GNUNET_MQ_Envelope *env;
677 struct GNUNET_NAT_RequestConnectionReversalMessage *req;
681 return GNUNET_SYSERR;
682 GNUNET_break (AF_INET == local_sa->sin_family);
683 GNUNET_break (AF_INET == remote_sa->sin_family);
684 env = GNUNET_MQ_msg_extra (req,
685 2 * sizeof (struct sockaddr_in),
686 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL);
687 req->local_addr_size = htons (sizeof (struct sockaddr_in));
688 req->remote_addr_size = htons (sizeof (struct sockaddr_in));
689 buf = (char *) &req[1];
692 sizeof (struct sockaddr_in));
693 buf += sizeof (struct sockaddr_in);
696 sizeof (struct sockaddr_in));
697 GNUNET_MQ_send (nh->mq,
704 * Stop port redirection and public IP address detection for the given
705 * handle. This frees the handle, after having sent the needed
706 * commands to close open ports.
708 * @param nh the handle to stop
711 GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh)
715 GNUNET_MQ_destroy (nh->mq);
718 if (NULL != nh->reconnect_task)
720 GNUNET_SCHEDULER_cancel (nh->reconnect_task);
721 nh->reconnect_task = NULL;
723 GNUNET_free (nh->reg);
728 /* end of nat_api.c */