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.
44 struct AddrEntry *next;
49 struct AddrEntry *prev;
52 * Place where the application can store data (on add,
53 * and retrieve on remove).
58 * Address class of the address.
60 enum GNUNET_NAT_AddressClass ac;
63 * Number of bytes that follow.
70 * Handle for active NAT registrations.
72 struct GNUNET_NAT_Handle
76 * Configuration we use.
78 const struct GNUNET_CONFIGURATION_Handle *cfg;
81 * Message queue for communicating with the NAT service.
83 struct GNUNET_MQ_Handle *mq;
86 * Our registration message.
88 struct GNUNET_MessageHeader *reg;
91 * Head of address DLL.
93 struct AddrEntry *ae_head;
96 * Tail of address DLL.
98 struct AddrEntry *ae_tail;
101 * Function to call when our addresses change.
103 GNUNET_NAT_AddressCallback address_callback;
106 * Function to call when another peer requests connection reversal.
108 GNUNET_NAT_ReversalCallback reversal_callback;
111 * Closure for the various callbacks.
116 * Task scheduled to reconnect to the service.
118 struct GNUNET_SCHEDULER_Task *reconnect_task;
121 * How long to wait until we reconnect.
123 struct GNUNET_TIME_Relative reconnect_delay;
128 * Task to connect to the NAT service.
130 * @param cls our `struct GNUNET_NAT_Handle *`
133 do_connect (void *cls);
137 * Task to connect to the NAT service.
139 * @param nh handle to reconnect
142 reconnect (struct GNUNET_NAT_Handle *nh)
144 struct AddrEntry *ae;
148 GNUNET_MQ_destroy (nh->mq);
151 while (NULL != (ae = nh->ae_head))
153 GNUNET_CONTAINER_DLL_remove (nh->ae_head,
156 nh->address_callback (nh->callback_cls,
160 (const struct sockaddr *) &ae[1],
165 = GNUNET_TIME_STD_BACKOFF (nh->reconnect_delay);
167 = GNUNET_SCHEDULER_add_delayed (nh->reconnect_delay,
174 * Check connection reversal request.
176 * @param cls our `struct GNUNET_NAT_Handle`
177 * @param crm the message
178 * @return #GNUNET_OK if @a crm is well-formed
181 check_connection_reversal_request (void *cls,
182 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
184 if (ntohs (crm->header.size) !=
186 sizeof (struct sockaddr_in) )
189 return GNUNET_SYSERR;
196 * Handle connection reversal request.
198 * @param cls our `struct GNUNET_NAT_Handle`
199 * @param crm the message
202 handle_connection_reversal_request (void *cls,
203 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
205 struct GNUNET_NAT_Handle *nh = cls;
207 nh->reversal_callback (nh->callback_cls,
208 (const struct sockaddr *) &crm[1],
209 sizeof (struct sockaddr_in));
214 * Check address change notification.
216 * @param cls our `struct GNUNET_NAT_Handle`
217 * @param acn the message
218 * @return #GNUNET_OK if @a crm is well-formed
221 check_address_change_notification (void *cls,
222 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
224 size_t alen = ntohs (acn->header.size) - sizeof (*acn);
228 case sizeof (struct sockaddr_in):
230 const struct sockaddr_in *s4
231 = (const struct sockaddr_in *) &acn[1];
232 if (AF_INET != s4->sin_family)
235 return GNUNET_SYSERR;
239 case sizeof (struct sockaddr_in6):
241 const struct sockaddr_in6 *s6
242 = (const struct sockaddr_in6 *) &acn[1];
243 if (AF_INET6 != s6->sin6_family)
246 return GNUNET_SYSERR;
252 return GNUNET_SYSERR;
259 * Handle connection reversal request.
261 * @param cls our `struct GNUNET_NAT_Handle`
262 * @param acn the message
265 handle_address_change_notification (void *cls,
266 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
268 struct GNUNET_NAT_Handle *nh = cls;
269 size_t alen = ntohs (acn->header.size) - sizeof (*acn);
270 const struct sockaddr *sa = (const struct sockaddr *) &acn[1];
271 enum GNUNET_NAT_AddressClass ac;
272 struct AddrEntry *ae;
274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
275 "Received address change notification\n");
276 ac = (enum GNUNET_NAT_AddressClass) ntohl (acn->addr_class);
277 if (GNUNET_YES == ntohl (acn->add_remove))
279 ae = GNUNET_malloc (sizeof (*ae) + alen);
282 GNUNET_memcpy (&ae[1],
285 GNUNET_CONTAINER_DLL_insert (nh->ae_head,
291 for (ae = nh->ae_head; NULL != ae; ae = ae->next)
292 if ( (ae->addrlen == alen) &&
293 (0 == memcmp (&ae[1],
303 GNUNET_CONTAINER_DLL_remove (nh->ae_head,
308 nh->address_callback (nh->callback_cls,
310 ntohl (acn->add_remove),
318 * Handle queue errors by reconnecting to NAT.
320 * @param cls the `struct GNUNET_NAT_Handle *`
321 * @param error details about the error
324 mq_error_handler (void *cls,
325 enum GNUNET_MQ_Error error)
327 struct GNUNET_NAT_Handle *nh = cls;
334 * Task to connect to the NAT service.
336 * @param cls our `struct GNUNET_NAT_Handle *`
339 do_connect (void *cls)
341 struct GNUNET_NAT_Handle *nh = cls;
342 struct GNUNET_MQ_MessageHandler handlers[] = {
343 GNUNET_MQ_hd_var_size (connection_reversal_request,
344 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED,
345 struct GNUNET_NAT_ConnectionReversalRequestedMessage,
347 GNUNET_MQ_hd_var_size (address_change_notification,
348 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE,
349 struct GNUNET_NAT_AddressChangeNotificationMessage,
351 GNUNET_MQ_handler_end ()
353 struct GNUNET_MQ_Envelope *env;
355 nh->reconnect_task = NULL;
356 nh->mq = GNUNET_CLIENT_connect (nh->cfg,
366 env = GNUNET_MQ_msg_copy (nh->reg);
367 GNUNET_MQ_send (nh->mq,
373 * Attempt to enable port redirection and detect public IP address
374 * contacting UPnP or NAT-PMP routers on the local network. Use @a
375 * addr to specify to which of the local host's addresses should the
376 * external port be mapped. The port is taken from the corresponding
377 * sockaddr_in[6] field. The NAT module should call the given @a
378 * address_callback for any 'plausible' external address.
380 * @param cfg configuration to use
381 * @param config_section name of the configuration section for optionsx
382 * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP
383 * @param num_addrs number of addresses in @a addrs
384 * @param addrs list of local addresses packets should be redirected to
385 * @param addrlens actual lengths of the addresses in @a addrs
386 * @param address_callback function to call everytime the public IP address changes
387 * @param reversal_callback function to call if someone wants connection reversal from us,
388 * NULL if connection reversal is not supported
389 * @param callback_cls closure for callbacks
390 * @return NULL on error, otherwise handle that can be used to unregister
392 struct GNUNET_NAT_Handle *
393 GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
394 const char *config_section,
396 unsigned int num_addrs,
397 const struct sockaddr **addrs,
398 const socklen_t *addrlens,
399 GNUNET_NAT_AddressCallback address_callback,
400 GNUNET_NAT_ReversalCallback reversal_callback,
403 struct GNUNET_NAT_Handle *nh;
404 struct GNUNET_NAT_RegisterMessage *rm;
410 for (unsigned int i=0;i<num_addrs;i++)
412 str_len = strlen (config_section) + 1;
414 if ( (len > GNUNET_MAX_MESSAGE_SIZE - sizeof (*rm)) ||
415 (num_addrs > UINT16_MAX) )
420 rm = GNUNET_malloc (sizeof (*rm) + len);
421 rm->header.size = htons (sizeof (*rm) + len);
422 rm->header.type = htons (GNUNET_MESSAGE_TYPE_NAT_REGISTER);
423 rm->flags = GNUNET_NAT_RF_NONE;
424 if (NULL != address_callback)
425 rm->flags |= GNUNET_NAT_RF_ADDRESSES;
426 if (NULL != reversal_callback)
427 rm->flags |= GNUNET_NAT_RF_REVERSAL;
429 rm->str_len = htons (str_len);
430 rm->num_addrs = htons ((uint16_t) num_addrs);
431 off = (char *) &rm[1];
432 for (unsigned int i=0;i<num_addrs;i++)
434 switch (addrs[i]->sa_family)
437 if (sizeof (struct sockaddr_in) != addrlens[i])
445 if (sizeof (struct sockaddr_in6) != addrlens[i])
454 if (sizeof (struct sockaddr_un) != addrlens[i])
476 nh = GNUNET_new (struct GNUNET_NAT_Handle);
477 nh->reg = &rm->header;
479 nh->address_callback = address_callback;
480 nh->reversal_callback = reversal_callback;
481 nh->callback_cls = callback_cls;
488 * Check if an incoming message is a STUN message.
490 * @param data the packet
491 * @param len the length of the packet in @a data
492 * @return #GNUNET_YES if @a data is a STUN packet,
493 * #GNUNET_NO if the packet is invalid (not a stun packet)
496 test_stun_packet (const void *data,
499 const struct stun_header *hdr;
500 const struct stun_attr *attr;
501 uint32_t advertised_message_size;
502 uint32_t message_magic_cookie;
504 /* On entry, 'len' is the length of the UDP payload. After the
505 * initial checks it becomes the size of unprocessed options,
506 * while 'data' is advanced accordingly.
508 if (len < sizeof(struct stun_header))
510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511 "STUN packet too short (only %d, wanting at least %d)\n",
513 (int) sizeof (struct stun_header));
516 hdr = (const struct stun_header *) data;
517 /* Skip header as it is already in hdr */
518 len -= sizeof (struct stun_header);
519 data += sizeof (struct stun_header);
521 /* len as advertised in the message */
522 advertised_message_size = ntohs (hdr->msglen);
524 message_magic_cookie = ntohl (hdr->magic);
525 /* Compare if the cookie match */
526 if (STUN_MAGIC_COOKIE != message_magic_cookie)
528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529 "Invalid magic cookie for STUN\n");
533 if (advertised_message_size > len)
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536 "Scrambled STUN packet length (got %d, expecting %d)\n",
537 advertised_message_size,
541 len = advertised_message_size;
544 if (len < sizeof (struct stun_attr))
546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
547 "Attribute too short in STUN packet (got %d, expecting %d)\n",
549 (int) sizeof(struct stun_attr));
552 attr = (const struct stun_attr *) data;
554 /* compute total attribute length */
555 advertised_message_size = ntohs (attr->len) + sizeof(struct stun_attr);
557 /* Check if we still have space in our buffer */
558 if (advertised_message_size > len)
560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
561 "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n",
562 advertised_message_size,
566 data += advertised_message_size;
567 len -= advertised_message_size;
569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
570 "STUN Packet, msg %04x, length: %d\n",
571 ntohs (hdr->msgtype),
572 advertised_message_size);
578 * Handle an incoming STUN message. This function is useful as
579 * some GNUnet service may be listening on a UDP port and might
580 * thus receive STUN messages while trying to receive other data.
581 * In this case, this function can be used to process replies
584 * The function does some basic sanity checks on packet size and
585 * content, try to extract a bit of information.
587 * At the moment this only processes BIND requests, and returns the
588 * externally visible address of the request to the rest of the
591 * @param nh handle to the NAT service
592 * @param sender_addr address from which we got @a data
593 * @param sender_addr_len number of bytes in @a sender_addr
594 * @param data the packet
595 * @param data_size number of bytes in @a data
596 * @return #GNUNET_OK on success
597 * #GNUNET_NO if the packet is not a STUN packet
598 * #GNUNET_SYSERR on internal error handling the packet
601 GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
602 const struct sockaddr *sender_addr,
603 size_t sender_addr_len,
607 struct GNUNET_MQ_Envelope *env;
608 struct GNUNET_NAT_HandleStunMessage *hsn;
612 test_stun_packet (data,
616 return GNUNET_SYSERR;
617 env = GNUNET_MQ_msg_extra (hsn,
618 data_size + sender_addr_len,
619 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN);
620 hsn->sender_addr_size = htons ((uint16_t) sender_addr_len);
621 hsn->payload_size = htons ((uint16_t) data_size);
622 buf = (char *) &hsn[1];
626 buf += sender_addr_len;
630 GNUNET_MQ_send (nh->mq,
637 * Test if the given address is (currently) a plausible IP address for
638 * this peer. Mostly a convenience function so that clients do not
639 * have to explicitly track all IPs that the #GNUNET_NAT_AddressCallback
640 * has returned so far.
642 * @param nh the handle returned by register
643 * @param addr IP address to test (IPv4 or IPv6)
644 * @param addrlen number of bytes in @a addr
645 * @return #GNUNET_YES if the address is plausible,
646 * #GNUNET_NO if the address is not plausible,
647 * #GNUNET_SYSERR if the address is malformed
650 GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
654 struct AddrEntry *ae;
656 if ( (addrlen != sizeof (struct sockaddr_in)) &&
657 (addrlen != sizeof (struct sockaddr_in6)) )
660 return GNUNET_SYSERR;
662 for (ae = nh->ae_head; NULL != ae; ae = ae->next)
663 if ( (addrlen == ae->addrlen) &&
673 * We learned about a peer (possibly behind NAT) so run the
674 * gnunet-nat-client to send dummy ICMP responses to cause
675 * that peer to connect to us (connection reversal).
677 * @param nh handle (used for configuration)
678 * @param local_sa our local address of the peer (IPv4-only)
679 * @param remote_sa the remote address of the peer (IPv4-only)
680 * @return #GNUNET_SYSERR on error,
681 * #GNUNET_NO if connection reversal is unavailable,
682 * #GNUNET_OK otherwise (presumably in progress)
685 GNUNET_NAT_request_reversal (struct GNUNET_NAT_Handle *nh,
686 const struct sockaddr_in *local_sa,
687 const struct sockaddr_in *remote_sa)
689 struct GNUNET_MQ_Envelope *env;
690 struct GNUNET_NAT_RequestConnectionReversalMessage *req;
694 return GNUNET_SYSERR;
695 GNUNET_break (AF_INET == local_sa->sin_family);
696 GNUNET_break (AF_INET == remote_sa->sin_family);
697 env = GNUNET_MQ_msg_extra (req,
698 2 * sizeof (struct sockaddr_in),
699 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL);
700 req->local_addr_size = htons (sizeof (struct sockaddr_in));
701 req->remote_addr_size = htons (sizeof (struct sockaddr_in));
702 buf = (char *) &req[1];
705 sizeof (struct sockaddr_in));
706 buf += sizeof (struct sockaddr_in);
709 sizeof (struct sockaddr_in));
710 GNUNET_MQ_send (nh->mq,
717 * Stop port redirection and public IP address detection for the given
718 * handle. This frees the handle, after having sent the needed
719 * commands to close open ports.
721 * @param nh the handle to stop
724 GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh)
728 GNUNET_MQ_destroy (nh->mq);
731 if (NULL != nh->reconnect_task)
733 GNUNET_SCHEDULER_cancel (nh->reconnect_task);
734 nh->reconnect_task = NULL;
736 GNUNET_free (nh->reg);
741 /* end of nat_api.c */