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.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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.
43 struct AddrEntry *next;
48 struct AddrEntry *prev;
51 * Place where the application can store data (on add,
52 * and retrieve on remove).
57 * Address class of the address.
59 enum GNUNET_NAT_AddressClass ac;
62 * Number of bytes that follow.
69 * Handle for active NAT registrations.
71 struct GNUNET_NAT_Handle
74 * Configuration we use.
76 const struct GNUNET_CONFIGURATION_Handle *cfg;
79 * Message queue for communicating with the NAT service.
81 struct GNUNET_MQ_Handle *mq;
84 * Our registration message.
86 struct GNUNET_MessageHeader *reg;
89 * Head of address DLL.
91 struct AddrEntry *ae_head;
94 * Tail of address DLL.
96 struct AddrEntry *ae_tail;
99 * Function to call when our addresses change.
101 GNUNET_NAT_AddressCallback address_callback;
104 * Function to call when another peer requests connection reversal.
106 GNUNET_NAT_ReversalCallback reversal_callback;
109 * Closure for the various callbacks.
114 * Task scheduled to reconnect to the service.
116 struct GNUNET_SCHEDULER_Task *reconnect_task;
119 * How long to wait until we reconnect.
121 struct GNUNET_TIME_Relative reconnect_delay;
126 * Task to connect to the NAT service.
128 * @param cls our `struct GNUNET_NAT_Handle *`
131 do_connect (void *cls);
135 * Task to connect to the NAT service.
137 * @param nh handle to reconnect
140 reconnect (struct GNUNET_NAT_Handle *nh)
142 struct AddrEntry *ae;
146 GNUNET_MQ_destroy (nh->mq);
149 while (NULL != (ae = nh->ae_head))
151 GNUNET_CONTAINER_DLL_remove (nh->ae_head, nh->ae_tail, ae);
152 nh->address_callback (nh->callback_cls,
156 (const struct sockaddr *) &ae[1],
160 nh->reconnect_delay = GNUNET_TIME_STD_BACKOFF (nh->reconnect_delay);
162 GNUNET_SCHEDULER_add_delayed (nh->reconnect_delay, &do_connect, nh);
167 * Check connection reversal request.
169 * @param cls our `struct GNUNET_NAT_Handle`
170 * @param crm the message
171 * @return #GNUNET_OK if @a crm is well-formed
174 check_connection_reversal_request (
176 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
178 if (ntohs (crm->header.size) != sizeof(*crm) + sizeof(struct sockaddr_in))
181 return GNUNET_SYSERR;
188 * Handle connection reversal request.
190 * @param cls our `struct GNUNET_NAT_Handle`
191 * @param crm the message
194 handle_connection_reversal_request (
196 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
198 struct GNUNET_NAT_Handle *nh = cls;
200 nh->reversal_callback (nh->callback_cls,
201 (const struct sockaddr *) &crm[1],
202 sizeof(struct sockaddr_in));
207 * Check address change notification.
209 * @param cls our `struct GNUNET_NAT_Handle`
210 * @param acn the message
211 * @return #GNUNET_OK if @a crm is well-formed
214 check_address_change_notification (
216 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
218 size_t alen = ntohs (acn->header.size) - sizeof(*acn);
222 case sizeof(struct sockaddr_in): {
223 const struct sockaddr_in *s4 = (const struct sockaddr_in *) &acn[1];
224 if (AF_INET != s4->sin_family)
227 return GNUNET_SYSERR;
232 case sizeof(struct sockaddr_in6): {
233 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) &acn[1];
234 if (AF_INET6 != s6->sin6_family)
237 return GNUNET_SYSERR;
244 return GNUNET_SYSERR;
251 * Handle connection reversal request.
253 * @param cls our `struct GNUNET_NAT_Handle`
254 * @param acn the message
257 handle_address_change_notification (
259 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
261 struct GNUNET_NAT_Handle *nh = cls;
262 size_t alen = ntohs (acn->header.size) - sizeof(*acn);
263 const struct sockaddr *sa = (const struct sockaddr *) &acn[1];
264 enum GNUNET_NAT_AddressClass ac;
265 struct AddrEntry *ae;
267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
268 "Received address change notification\n");
269 ac = (enum GNUNET_NAT_AddressClass) ntohl (acn->addr_class);
270 if (GNUNET_YES == ntohl (acn->add_remove))
272 ae = GNUNET_malloc (sizeof(*ae) + alen);
275 GNUNET_memcpy (&ae[1], sa, alen);
276 GNUNET_CONTAINER_DLL_insert (nh->ae_head, nh->ae_tail, ae);
277 nh->address_callback (nh->callback_cls,
279 ntohl (acn->add_remove),
286 for (ae = nh->ae_head; NULL != ae; ae = ae->next)
287 if ((ae->addrlen == alen) && (0 == memcmp (&ae[1], sa, alen)))
295 GNUNET_CONTAINER_DLL_remove (nh->ae_head, nh->ae_tail, ae);
296 nh->address_callback (nh->callback_cls,
298 ntohl (acn->add_remove),
308 * Handle queue errors by reconnecting to NAT.
310 * @param cls the `struct GNUNET_NAT_Handle *`
311 * @param error details about the error
314 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
316 struct GNUNET_NAT_Handle *nh = cls;
323 * Task to connect to the NAT service.
325 * @param cls our `struct GNUNET_NAT_Handle *`
328 do_connect (void *cls)
330 struct GNUNET_NAT_Handle *nh = cls;
331 struct GNUNET_MQ_MessageHandler handlers[] =
332 { GNUNET_MQ_hd_var_size (connection_reversal_request,
333 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED,
335 GNUNET_NAT_ConnectionReversalRequestedMessage,
337 GNUNET_MQ_hd_var_size (address_change_notification,
338 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE,
339 struct GNUNET_NAT_AddressChangeNotificationMessage,
341 GNUNET_MQ_handler_end () };
342 struct GNUNET_MQ_Envelope *env;
344 nh->reconnect_task = NULL;
346 GNUNET_CLIENT_connect (nh->cfg, "nat", handlers, &mq_error_handler, nh);
352 env = GNUNET_MQ_msg_copy (nh->reg);
353 GNUNET_MQ_send (nh->mq, env);
358 * Attempt to enable port redirection and detect public IP address
359 * contacting UPnP or NAT-PMP routers on the local network. Use @a
360 * addr to specify to which of the local host's addresses should the
361 * external port be mapped. The port is taken from the corresponding
362 * sockaddr_in[6] field. The NAT module should call the given @a
363 * address_callback for any 'plausible' external address.
365 * @param cfg configuration to use
366 * @param config_section name of the configuration section for optionsx
367 * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP
368 * @param num_addrs number of addresses in @a addrs
369 * @param addrs list of local addresses packets should be redirected to
370 * @param addrlens actual lengths of the addresses in @a addrs
371 * @param address_callback function to call everytime the public IP address changes
372 * @param reversal_callback function to call if someone wants connection reversal from us,
373 * NULL if connection reversal is not supported
374 * @param callback_cls closure for callbacks
375 * @return NULL on error, otherwise handle that can be used to unregister
377 struct GNUNET_NAT_Handle *
378 GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
379 const char *config_section,
381 unsigned int num_addrs,
382 const struct sockaddr **addrs,
383 const socklen_t *addrlens,
384 GNUNET_NAT_AddressCallback address_callback,
385 GNUNET_NAT_ReversalCallback reversal_callback,
388 struct GNUNET_NAT_Handle *nh;
389 struct GNUNET_NAT_RegisterMessage *rm;
395 for (unsigned int i = 0; i < num_addrs; i++)
397 str_len = strlen (config_section) + 1;
399 if ((len > GNUNET_MAX_MESSAGE_SIZE - sizeof(*rm)) ||
400 (num_addrs > UINT16_MAX))
405 rm = GNUNET_malloc (sizeof(*rm) + len);
406 rm->header.size = htons (sizeof(*rm) + len);
407 rm->header.type = htons (GNUNET_MESSAGE_TYPE_NAT_REGISTER);
408 rm->flags = GNUNET_NAT_RF_NONE;
409 if (NULL != address_callback)
410 rm->flags |= GNUNET_NAT_RF_ADDRESSES;
411 if (NULL != reversal_callback)
412 rm->flags |= GNUNET_NAT_RF_REVERSAL;
414 rm->str_len = htons (str_len);
415 rm->num_addrs = htons ((uint16_t) num_addrs);
416 off = (char *) &rm[1];
417 for (unsigned int i = 0; i < num_addrs; i++)
419 switch (addrs[i]->sa_family)
422 if (sizeof(struct sockaddr_in) != addrlens[i])
431 if (sizeof(struct sockaddr_in6) != addrlens[i])
441 if (sizeof(struct sockaddr_un) != addrlens[i])
454 GNUNET_memcpy (off, addrs[i], addrlens[i]);
457 GNUNET_memcpy (off, config_section, str_len);
459 nh = GNUNET_new (struct GNUNET_NAT_Handle);
460 nh->reg = &rm->header;
462 nh->address_callback = address_callback;
463 nh->reversal_callback = reversal_callback;
464 nh->callback_cls = callback_cls;
471 * Check if an incoming message is a STUN message.
473 * @param data the packet
474 * @param len the length of the packet in @a data
475 * @return #GNUNET_YES if @a data is a STUN packet,
476 * #GNUNET_NO if the packet is invalid (not a stun packet)
479 test_stun_packet (const void *data, size_t len)
481 const struct stun_header *hdr;
482 const struct stun_attr *attr;
483 uint32_t advertised_message_size;
484 uint32_t message_magic_cookie;
486 /* On entry, 'len' is the length of the UDP payload. After the
487 * initial checks it becomes the size of unprocessed options,
488 * while 'data' is advanced accordingly.
490 if (len < sizeof(struct stun_header))
492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
493 "STUN packet too short (only %d, wanting at least %d)\n",
495 (int) sizeof(struct stun_header));
498 hdr = (const struct stun_header *) data;
499 /* Skip header as it is already in hdr */
500 len -= sizeof(struct stun_header);
501 data += sizeof(struct stun_header);
503 /* len as advertised in the message */
504 advertised_message_size = ntohs (hdr->msglen);
506 message_magic_cookie = ntohl (hdr->magic);
507 /* Compare if the cookie match */
508 if (STUN_MAGIC_COOKIE != message_magic_cookie)
510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Invalid magic cookie for STUN\n");
514 if (advertised_message_size > len)
516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
517 "Scrambled STUN packet length (got %d, expecting %d)\n",
518 advertised_message_size,
522 len = advertised_message_size;
525 if (len < sizeof(struct stun_attr))
527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
528 "Attribute too short in STUN packet (got %d, expecting %d)\n",
530 (int) sizeof(struct stun_attr));
533 attr = (const struct stun_attr *) data;
535 /* compute total attribute length */
536 advertised_message_size = ntohs (attr->len) + sizeof(struct stun_attr);
538 /* Check if we still have space in our buffer */
539 if (advertised_message_size > len)
542 GNUNET_ERROR_TYPE_DEBUG,
543 "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n",
544 advertised_message_size,
548 data += advertised_message_size;
549 len -= advertised_message_size;
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552 "STUN Packet, msg %04x, length: %d\n",
553 ntohs (hdr->msgtype),
554 advertised_message_size);
560 * Handle an incoming STUN message. This function is useful as
561 * some GNUnet service may be listening on a UDP port and might
562 * thus receive STUN messages while trying to receive other data.
563 * In this case, this function can be used to process replies
566 * The function does some basic sanity checks on packet size and
567 * content, try to extract a bit of information.
569 * At the moment this only processes BIND requests, and returns the
570 * externally visible address of the request to the rest of the
573 * @param nh handle to the NAT service
574 * @param sender_addr address from which we got @a data
575 * @param sender_addr_len number of bytes in @a sender_addr
576 * @param data the packet
577 * @param data_size number of bytes in @a data
578 * @return #GNUNET_OK on success
579 * #GNUNET_NO if the packet is not a STUN packet
580 * #GNUNET_SYSERR on internal error handling the packet
583 GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
584 const struct sockaddr *sender_addr,
585 size_t sender_addr_len,
589 struct GNUNET_MQ_Envelope *env;
590 struct GNUNET_NAT_HandleStunMessage *hsn;
593 if (GNUNET_YES != test_stun_packet (data, data_size))
596 return GNUNET_SYSERR;
597 env = GNUNET_MQ_msg_extra (hsn,
598 data_size + sender_addr_len,
599 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN);
600 hsn->sender_addr_size = htons ((uint16_t) sender_addr_len);
601 hsn->payload_size = htons ((uint16_t) data_size);
602 buf = (char *) &hsn[1];
603 GNUNET_memcpy (buf, sender_addr, sender_addr_len);
604 buf += sender_addr_len;
605 GNUNET_memcpy (buf, data, data_size);
606 GNUNET_MQ_send (nh->mq, env);
612 * Test if the given address is (currently) a plausible IP address for
613 * this peer. Mostly a convenience function so that clients do not
614 * have to explicitly track all IPs that the #GNUNET_NAT_AddressCallback
615 * has returned so far.
617 * @param nh the handle returned by register
618 * @param addr IP address to test (IPv4 or IPv6)
619 * @param addrlen number of bytes in @a addr
620 * @return #GNUNET_YES if the address is plausible,
621 * #GNUNET_NO if the address is not plausible,
622 * #GNUNET_SYSERR if the address is malformed
625 GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
629 struct AddrEntry *ae;
631 if ((addrlen != sizeof(struct sockaddr_in)) &&
632 (addrlen != sizeof(struct sockaddr_in6)))
635 return GNUNET_SYSERR;
637 for (ae = nh->ae_head; NULL != ae; ae = ae->next)
638 if ((addrlen == ae->addrlen) && (0 == memcmp (addr, &ae[1], addrlen)))
645 * We learned about a peer (possibly behind NAT) so run the
646 * gnunet-nat-client to send dummy ICMP responses to cause
647 * that peer to connect to us (connection reversal).
649 * @param nh handle (used for configuration)
650 * @param local_sa our local address of the peer (IPv4-only)
651 * @param remote_sa the remote address of the peer (IPv4-only)
652 * @return #GNUNET_SYSERR on error,
653 * #GNUNET_NO if connection reversal is unavailable,
654 * #GNUNET_OK otherwise (presumably in progress)
657 GNUNET_NAT_request_reversal (struct GNUNET_NAT_Handle *nh,
658 const struct sockaddr_in *local_sa,
659 const struct sockaddr_in *remote_sa)
661 struct GNUNET_MQ_Envelope *env;
662 struct GNUNET_NAT_RequestConnectionReversalMessage *req;
666 return GNUNET_SYSERR;
667 GNUNET_break (AF_INET == local_sa->sin_family);
668 GNUNET_break (AF_INET == remote_sa->sin_family);
670 GNUNET_MQ_msg_extra (req,
671 2 * sizeof(struct sockaddr_in),
672 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL);
673 req->local_addr_size = htons (sizeof(struct sockaddr_in));
674 req->remote_addr_size = htons (sizeof(struct sockaddr_in));
675 buf = (char *) &req[1];
676 GNUNET_memcpy (buf, local_sa, sizeof(struct sockaddr_in));
677 buf += sizeof(struct sockaddr_in);
678 GNUNET_memcpy (buf, remote_sa, sizeof(struct sockaddr_in));
679 GNUNET_MQ_send (nh->mq, env);
685 * Stop port redirection and public IP address detection for the given
686 * handle. This frees the handle, after having sent the needed
687 * commands to close open ports.
689 * @param nh the handle to stop
692 GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh)
696 GNUNET_MQ_destroy (nh->mq);
699 if (NULL != nh->reconnect_task)
701 GNUNET_SCHEDULER_cancel (nh->reconnect_task);
702 nh->reconnect_task = NULL;
704 GNUNET_free (nh->reg);
709 /* end of nat_api.c */