void *callback_cls);
-/**
- * Handle an incoming STUN message. This function is useful as
- * some GNUnet service may be listening on a UDP port and might
- * thus receive STUN messages while trying to receive other data.
- * In this case, this function can be used to act as a proper
- * STUN server (if desired).
- *
- * The function does some basic sanity checks on packet size and
- * content, try to extract a bit of information, and possibly replies
- * if this is an actual STUN message.
- *
- * At the moment this only processes BIND requests, and returns the
- * externally visible address of the request.
- *
- * @param nh handle to the NAT service
- * @param sender_addr address from which we got @a data
- * @param sender_addr_len number of bytes in @a sender_addr
- * @param data the packet
- * @param data_size number of bytes in @a data
- * @return #GNUNET_OK on success
- * #GNUNET_NO if the packet is not a STUN packet
- * #GNUNET_SYSERR on internal error handling the packet
- */
-int
-GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
- const struct sockaddr *sender_addr,
- size_t sender_addr_len,
- const void *data,
- size_t data_size);
-
-
/**
* Test if the given address is (currently) a plausible IP address for
* this peer. Mostly a convenience function so that clients do not
enum GNUNET_NAT_StatusCode result);
+/**
+ * Handle an incoming STUN message. This function is useful as
+ * some GNUnet service may be listening on a UDP port and might
+ * thus receive STUN messages while trying to receive other data.
+ * In this case, this function can be used to process replies
+ * to STUN requests.
+ *
+ * The function does some basic sanity checks on packet size and
+ * content, try to extract a bit of information.
+ *
+ * At the moment this only processes BIND requests, and returns the
+ * externally visible address of the request to the rest of the
+ * NAT logic.
+ *
+ * @param nh handle to the NAT service
+ * @param sender_addr address from which we got @a data
+ * @param sender_addr_len number of bytes in @a sender_addr
+ * @param data the packet
+ * @param data_size number of bytes in @a data
+ * @return #GNUNET_OK on success
+ * #GNUNET_NO if the packet is not a STUN packet
+ * #GNUNET_SYSERR on internal error handling the packet
+ */
+int
+GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
+ const struct sockaddr *sender_addr,
+ size_t sender_addr_len,
+ const void *data,
+ size_t data_size);
+
+
+/**
+ * Handle to a request given to the resolver. Can be used to cancel
+ * the request prior to the timeout or successful execution. Also
+ * used to track our internal state for the request.
+ */
+struct GNUNET_NAT_STUN_Handle;
+
+
+/**
+ * Make Generic STUN request. Sends a generic stun request to the
+ * server specified using the specified socket. If we do this,
+ * we need to watch for possible responses and call
+ * #GNUNET_NAT_stun_handle_packet() on incoming packets.
+ *
+ * @param server the address of the stun server
+ * @param port port of the stun server, in host byte order
+ * @param sock the socket used to send the request, must be a
+ * UDP socket
+ * @param cb callback in case of error
+ * @param cb_cls closure for @a cb
+ * @return NULL on error
+ */
+struct GNUNET_NAT_STUN_Handle *
+GNUNET_NAT_stun_make_request (const char *server,
+ uint16_t port,
+ struct GNUNET_NETWORK_Handle *sock,
+ GNUNET_NAT_TestCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel active STUN request. Frees associated resources
+ * and ensures that the callback is no longer invoked.
+ *
+ * @param rh request to cancel
+ */
+void
+GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh);
+
+
/**
* Start testing if NAT traversal works using the given configuration
* (IPv4-only). The transport adapters should be down while using
-version-info 1:1:1
libgnunetnatnew_la_SOURCES = \
- nat_api.c nat.h
+ nat_api.c \
+ nat_api_stun.c nat_stun.h \
+ nat.h
libgnunetnatnew_la_LIBADD = \
$(top_builddir)/src/util/libgnunetutil.la \
$(GN_LIBINTL) @EXT_LIBS@
-version-info 2:0:0
gnunet_service_nat_SOURCES = \
- gnunet-service-nat.c
+ gnunet-service-nat.c \
+ gnunet-service-nat_stun.c gnunet-service-nat_stun.h
gnunet_service_nat_LDADD = \
$(top_builddir)/src/util/libgnunetutil.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
#include "gnunet_signatures.h"
#include "gnunet_statistics_service.h"
#include "gnunet_nat_service.h"
+#include "gnunet-service-nat_stun.h"
#include "nat.h"
#include <gcrypt.h>
const void *payload;
size_t sa_len;
size_t payload_size;
+ struct sockaddr_in external_addr;
sa_len = ntohs (message->sender_addr_size);
payload_size = ntohs (message->payload_size);
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received HANDLE_STUN message from client\n");
- // FIXME: actually handle STUN request!
+ if (GNUNET_OK ==
+ GNUNET_NAT_stun_handle_packet_ (payload,
+ payload_size,
+ &external_addr))
+ {
+ /* FIXME: do something with "external_addr"! We
+ now know that a server at "sa" claims that
+ we are visible at IP "external_addr".
+
+ We should (for some fixed period of time) tell
+ all of our clients that listen to a NAT'ed address
+ that they might want to consider the given 'external_ip'
+ as their public IP address (this includes TCP and UDP
+ clients, even if only UDP sends STUN requests).
+
+ If we do not get a renewal, the "external_addr" should be
+ removed again. The timeout frequency should be configurable
+ (with a sane default), so that the UDP plugin can tell how
+ often to re-request STUN.
+ */
+
+ }
GNUNET_SERVICE_client_continue (ch->client);
}
* of addresses this peer has.
*
* @param delta the entry in the list that changed
+ * @param ch client to contact
* @param add #GNUNET_YES to add, #GNUNET_NO to remove
* @param addr the address that changed
* @param addr_len number of bytes in @a addr
*/
static void
notify_client (struct LocalAddressList *delta,
+ struct ClientHandle *ch,
int add,
const void *addr,
size_t addr_len)
struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
env = GNUNET_MQ_msg_extra (msg,
- alen,
+ addr_len,
GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
msg->add_remove = htonl (add);
msg->addr_class = htonl (delta->ac);
GNUNET_memcpy (&msg[1],
addr,
- alen);
+ addr_len);
GNUNET_MQ_send (ch->mq,
env);
}
c4 = (const struct sockaddr_in *) ch->addrs[i];
v4.sin_port = c4->sin_port;
notify_client (delta,
+ ch,
add,
&v4,
alen);
if (AF_INET6 != ch->addrs[i]->sa_family)
continue; /* IPv4 not relevant */
c6 = (const struct sockaddr_in6 *) ch->addrs[i];
- v6.sin_port = c6->sin_port;
+ v6.sin6_port = c6->sin6_port;
notify_client (delta,
+ ch,
add,
&v6,
alen);
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2009, 2015, 2016 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+/**
+ * This code provides some support for doing STUN transactions. We
+ * receive the simplest possible packet as the STUN server and try
+ * to respond properly.
+ *
+ * All STUN packets start with a simple header made of a type,
+ * length (excluding the header) and a 16-byte random transaction id.
+ * Following the header we may have zero or more attributes, each
+ * structured as a type, length and a value (whose format depends
+ * on the type, but often contains addresses).
+ * Of course all fields are in network format.
+ *
+ * This code was based on ministun.c.
+ *
+ * @file nat/gnunet-service-nat_stun.c
+ * @brief Functions for STUN functionality
+ * @author Bruno Souza Cabral
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "nat_stun.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
+
+
+/**
+ * Context for #stun_get_mapped().
+ * Used to store state across processing attributes.
+ */
+struct StunState
+{
+ uint16_t attr;
+};
+
+
+/**
+ * Extract the STUN_MAPPED_ADDRESS from the stun response.
+ * This is used as a callback for stun_handle_response
+ * when called from stun_request.
+ *
+ * @param[out] st pointer where we will set the type
+ * @param attr received stun attribute
+ * @param magic Magic cookie
+ * @param[out] arg pointer to a sockaddr_in where we will set the reported IP and port
+ * @return #GNUNET_OK if @a arg was initialized
+ */
+static int
+stun_get_mapped (struct StunState *st,
+ const struct stun_attr *attr,
+ uint32_t magic,
+ struct sockaddr_in *arg)
+{
+ const struct stun_addr *returned_addr;
+ struct sockaddr_in *sa = (struct sockaddr_in *) arg;
+ uint16_t type = ntohs (attr->attr);
+
+ switch (type)
+ {
+ case STUN_MAPPED_ADDRESS:
+ if ( (st->attr == STUN_XOR_MAPPED_ADDRESS) ||
+ (st->attr == STUN_MS_XOR_MAPPED_ADDRESS) )
+ return GNUNET_NO;
+ magic = 0;
+ break;
+ case STUN_MS_XOR_MAPPED_ADDRESS:
+ if (st->attr == STUN_XOR_MAPPED_ADDRESS)
+ return GNUNET_NO;
+ break;
+ case STUN_XOR_MAPPED_ADDRESS:
+ break;
+ default:
+ return GNUNET_NO;
+ }
+
+ if (ntohs (attr->len) < sizeof (struct stun_addr))
+ return GNUNET_NO;
+ returned_addr = (const struct stun_addr *)(attr + 1);
+ if (AF_INET != returned_addr->family)
+ return GNUNET_NO;
+ st->attr = type;
+ sa->sin_family = AF_INET;
+ sa->sin_port = returned_addr->port ^ htons (ntohl(magic) >> 16);
+ sa->sin_addr.s_addr = returned_addr->addr ^ magic;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handle an incoming STUN response. Do some basic sanity checks on
+ * packet size and content, try to extract information.
+ * At the moment this only processes BIND requests,
+ * and returns the externally visible address of the original
+ * request.
+ *
+ * @param data the packet
+ * @param len the length of the packet in @a data
+ * @param[out] arg sockaddr_in where we will set our discovered address
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if the packet is invalid (not a stun packet)
+ */
+int
+GNUNET_NAT_stun_handle_packet_ (const void *data,
+ size_t len,
+ struct sockaddr_in *arg)
+{
+ const struct stun_header *hdr;
+ const struct stun_attr *attr;
+ struct StunState st;
+ uint32_t advertised_message_size;
+ uint32_t message_magic_cookie;
+ int ret = GNUNET_SYSERR;
+
+ /* On entry, 'len' is the length of the UDP payload. After the
+ * initial checks it becomes the size of unprocessed options,
+ * while 'data' is advanced accordingly.
+ */
+ if (len < sizeof(struct stun_header))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Packet too short to be a STUN packet\n");
+ return GNUNET_NO;
+ }
+ hdr = data;
+ /* Skip header as it is already in hdr */
+ len -= sizeof(struct stun_header);
+ data += sizeof(struct stun_header);
+
+ /* len as advertised in the message */
+ advertised_message_size = ntohs (hdr->msglen);
+ message_magic_cookie = ntohl (hdr->magic);
+ /* Compare if the cookie match */
+ if (STUN_MAGIC_COOKIE != message_magic_cookie)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Invalid magic cookie for STUN packet\n");
+ return GNUNET_NO;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "STUN Packet, msg %s (%04x), length: %d\n",
+ stun_msg2str (ntohs (hdr->msgtype)),
+ ntohs (hdr->msgtype),
+ advertised_message_size);
+ if (advertised_message_size > len)
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Scrambled STUN packet length (got %d, expecting %d)\n",
+ advertised_message_size,
+ (int) len);
+ return GNUNET_NO;
+ }
+ len = advertised_message_size;
+ memset (&st, 0, sizeof(st));
+
+ while (len > 0)
+ {
+ if (len < sizeof (struct stun_attr))
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Attribute too short (got %d, expecting %d)\n",
+ (int) len,
+ (int) sizeof (struct stun_attr));
+ break;
+ }
+ attr = (const struct stun_attr *) data;
+
+ /* compute total attribute length */
+ advertised_message_size = ntohs (attr->len) + sizeof (struct stun_attr);
+
+ /* Check if we still have space in our buffer */
+ if (advertised_message_size > len)
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Inconsistent attribute (length %d exceeds remaining msg len %d)\n",
+ advertised_message_size,
+ (int) len);
+ break;
+ }
+ if (GNUNET_OK ==
+ stun_get_mapped (&st,
+ attr,
+ hdr->magic,
+ arg))
+ ret = GNUNET_OK;
+ data += advertised_message_size;
+ len -= advertised_message_size;
+ }
+ return ret;
+}
+
+/* end of gnunet-service-nat_stun.c */
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2009, 2015, 2016 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+/**
+ * This code provides some support for doing STUN transactions. We
+ * receive the simplest possible packet as the STUN server and try
+ * to respond properly.
+ *
+ * All STUN packets start with a simple header made of a type,
+ * length (excluding the header) and a 16-byte random transaction id.
+ * Following the header we may have zero or more attributes, each
+ * structured as a type, length and a value (whose format depends
+ * on the type, but often contains addresses).
+ * Of course all fields are in network format.
+ *
+ * This code was based on ministun.c.
+ *
+ * @file nat/gnunet-service-nat_stun.h
+ * @brief Functions for STUN functionality
+ * @author Bruno Souza Cabral
+ */
+#ifndef GNUNET_SERVICE_NAT_STUN_H
+#define GNUNET_SERVICE_NAT_STUN_H
+
+#include "platform.h"
+
+/**
+ * Handle an incoming STUN response. Do some basic sanity checks on
+ * packet size and content, try to extract information.
+ * At the moment this only processes BIND requests,
+ * and returns the externally visible address of the original
+ * request.
+ *
+ * @param data the packet
+ * @param len the length of the packet in @a data
+ * @param[out] arg sockaddr_in where we will set our discovered address
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if the packet is invalid (not a stun packet)
+ */
+int
+GNUNET_NAT_stun_handle_packet_ (const void *data,
+ size_t len,
+ struct sockaddr_in *arg);
+
+#endif
* Handle an incoming STUN message. This function is useful as
* some GNUnet service may be listening on a UDP port and might
* thus receive STUN messages while trying to receive other data.
- * In this case, this function can be used to act as a proper
- * STUN server (if desired).
+ * In this case, this function can be used to process replies
+ * to STUN requests.
*
* The function does some basic sanity checks on packet size and
- * content, try to extract a bit of information, and possibly replies
- * if this is an actual STUN message.
+ * content, try to extract a bit of information.
*
* At the moment this only processes BIND requests, and returns the
- * externally visible address of the request.
+ * externally visible address of the request to the rest of the
+ * NAT logic.
*
* @param nh handle to the NAT service
* @param sender_addr address from which we got @a data
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2009, 2015, 2016 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+/**
+ * This code provides some support for doing STUN transactions.
+ * We send simplest possible packet ia REQUEST with BIND to a STUN server.
+ *
+ * All STUN packets start with a simple header made of a type,
+ * length (excluding the header) and a 16-byte random transaction id.
+ * Following the header we may have zero or more attributes, each
+ * structured as a type, length and a value (whose format depends
+ * on the type, but often contains addresses).
+ * Of course all fields are in network format.
+ *
+ * This code was based on ministun.c.
+ *
+ * @file nat/nat_api_stun.c
+ * @brief Functions for STUN functionality
+ * @author Bruno Souza Cabral
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_nat_lib.h"
+
+
+#include "nat_stun.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
+
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+
+/**
+ * Handle to a request given to the resolver. Can be used to cancel
+ * the request prior to the timeout or successful execution. Also
+ * used to track our internal state for the request.
+ */
+struct GNUNET_NAT_STUN_Handle
+{
+
+ /**
+ * Handle to a pending DNS lookup request.
+ */
+ struct GNUNET_RESOLVER_RequestHandle *dns_active;
+
+ /**
+ * Handle to the listen socket
+ */
+ struct GNUNET_NETWORK_Handle *sock;
+
+ /**
+ * Stun server address
+ */
+ char *stun_server;
+
+ /**
+ * Function to call when a error occours
+ */
+ GNUNET_NAT_STUN_ErrorCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Do we got a DNS resolution successfully?
+ */
+ int dns_success;
+
+ /**
+ * STUN port
+ */
+ uint16_t stun_port;
+
+};
+
+
+/**
+ * Encode a class and method to a compatible STUN format
+ *
+ * @param msg_class class to be converted
+ * @param method method to be converted
+ * @return message in a STUN compatible format
+ */
+static int
+encode_message (enum StunClasses msg_class,
+ enum StunMethods method)
+{
+ return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) |
+ (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2);
+}
+
+
+/**
+ * Fill the stun_header with a random request_id
+ *
+ * @param req, stun header to be filled
+ */
+static void
+generate_request_id (struct stun_header *req)
+{
+ req->magic = htonl(STUN_MAGIC_COOKIE);
+ for (unsigned int x = 0; x < 3; x++)
+ req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+ UINT32_MAX);
+}
+
+
+/**
+ * Try to establish a connection given the specified address.
+ *
+ * @param cls our `struct GNUNET_NAT_STUN_Handle *`
+ * @param addr address to try, NULL for "last call"
+ * @param addrlen length of @a addr
+ */
+static void
+stun_dns_callback (void *cls,
+ const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ struct GNUNET_NAT_STUN_Handle *rh = cls;
+ struct stun_header req;
+ struct sockaddr_in server;
+
+ if (NULL == addr)
+ {
+ rh->dns_active = NULL;
+ if (GNUNET_NO == rh->dns_success)
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Error resolving host %s\n",
+ rh->stun_server);
+ rh->cb (rh->cb_cls,
+ GNUNET_NAT_ERROR_NOT_ONLINE);
+ }
+ else if (GNUNET_SYSERR == rh->dns_success)
+ {
+ rh->cb (rh->cb_cls,
+ GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR);
+ }
+ else
+ {
+ rh->cb (rh->cb_cls,
+ GNUNET_NAT_ERROR_SUCCESS);
+ }
+ GNUNET_NAT_stun_make_request_cancel (rh);
+ return;
+ }
+
+ rh->dns_success = GNUNET_YES;
+ memset (&server, 0, sizeof(server));
+ server.sin_family = AF_INET;
+ server.sin_addr = ((struct sockaddr_in *)addr)->sin_addr;
+ server.sin_port = htons (rh->stun_port);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ server.sin_len = (u_char) sizeof (struct sockaddr_in);
+#endif
+
+ /* Craft the simplest possible STUN packet. A request binding */
+ generate_request_id (&req);
+ req.msglen = htons (0);
+ req.msgtype = htons (encode_message (STUN_REQUEST,
+ STUN_BINDING));
+
+ /* Send the packet */
+ if (-1 ==
+ GNUNET_NETWORK_socket_sendto (rh->sock,
+ &req,
+ sizeof (req),
+ (const struct sockaddr *) &server,
+ sizeof (server)))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "sendto");
+ rh->dns_success = GNUNET_SYSERR;
+ return;
+ }
+}
+
+
+/**
+ * Make Generic STUN request. Sends a generic stun request to the
+ * server specified using the specified socket, possibly waiting for
+ * a reply and filling the 'reply' field with the externally visible
+ * address.
+ *
+ * @param server the address of the stun server
+ * @param port port of the stun server, in host byte order
+ * @param sock the socket used to send the request
+ * @param cb callback in case of error
+ * @param cb_cls closure for @a cb
+ * @return NULL on error
+ */
+struct GNUNET_NAT_STUN_Handle *
+GNUNET_NAT_stun_make_request (const char *server,
+ uint16_t port,
+ struct GNUNET_NETWORK_Handle *sock,
+ GNUNET_NAT_STUN_ErrorCallback cb,
+ void *cb_cls)
+{
+ struct GNUNET_NAT_STUN_Handle *rh;
+
+ rh = GNUNET_new (struct GNUNET_NAT_STUN_Handle);
+ rh->sock = sock;
+ rh->cb = cb;
+ rh->cb_cls = cb_cls;
+ rh->stun_server = GNUNET_strdup (server);
+ rh->stun_port = port;
+ rh->dns_success = GNUNET_NO;
+ rh->dns_active = GNUNET_RESOLVER_ip_get (rh->stun_server,
+ AF_INET,
+ TIMEOUT,
+ &stun_dns_callback, rh);
+ if (NULL == rh->dns_active)
+ {
+ GNUNET_NAT_stun_make_request_cancel (rh);
+ return NULL;
+ }
+ return rh;
+}
+
+
+/**
+ * Cancel active STUN request. Frees associated resources
+ * and ensures that the callback is no longer invoked.
+ *
+ * @param rh request to cancel
+ */
+void
+GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh)
+{
+ if (NULL != rh->dns_active)
+ {
+ GNUNET_RESOLVER_request_cancel (rh->dns_active);
+ rh->dns_active = NULL;
+ }
+ GNUNET_free (rh->stun_server);
+ GNUNET_free (rh);
+}
+
+
+/* end of nat_stun.c */
};
-/**
- * Convert a message to a StunClass
- *
- * @param msg the received message
- * @return the converted StunClass
- */
-static int
-decode_class(int msg)
-{
- /* Sorry for the magic, but this maps the class according to rfc5245 */
- return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7);
-}
-
-/**
- * Convert a message to a StunMethod
- *
- * @param msg the received message
- * @return the converted StunMethod
- */
-static int
-decode_method(int msg)
-{
- return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2);
-}
-
-
/**
* Encode a class and method to a compatible STUN format
*
}
-/**
- * Print a class and method from a STUN message
- *
- * @param msg
- * @return string with the message class and method
- */
-static const char *
-stun_msg2str(int msg)
-{
- static const struct {
- enum StunClasses value;
- const char *name;
- } classes[] = {
- { STUN_REQUEST, "Request" },
- { STUN_INDICATION, "Indication" },
- { STUN_RESPONSE, "Response" },
- { STUN_ERROR_RESPONSE, "Error Response" },
- { 0, NULL }
- };
- static const struct {
- enum StunMethods value;
- const char *name;
- } methods[] = {
- { STUN_BINDING, "Binding" },
- { 0, NULL }
- };
- static char result[32];
- const char *msg_class = NULL;
- const char *method = NULL;
- int i;
- int value;
-
- value = decode_class(msg);
- for (i = 0; classes[i].name; i++)
- {
- msg_class = classes[i].name;
- if (classes[i].value == value)
- break;
- }
- value = decode_method(msg);
- for (i = 0; methods[i].name; i++)
- {
- method = methods[i].name;
- if (methods[i].value == value)
- break;
- }
- GNUNET_snprintf (result,
- sizeof(result),
- "%s %s",
- method ? : "Unknown Method",
- msg_class ? : "Unknown Class Message");
- return result;
-}
-
-
-/**
- * Print attribute name
- *
- * @param msg with a attribute type
- * @return string with the attribute name
- */
-static const char *
-stun_attr2str (int msg)
-{
- static const struct {
- enum StunAttributes value;
- const char *name;
- } attrs[] = {
- { STUN_MAPPED_ADDRESS, "Mapped Address" },
- { STUN_RESPONSE_ADDRESS, "Response Address" },
- { STUN_CHANGE_ADDRESS, "Change Address" },
- { STUN_SOURCE_ADDRESS, "Source Address" },
- { STUN_CHANGED_ADDRESS, "Changed Address" },
- { STUN_USERNAME, "Username" },
- { STUN_PASSWORD, "Password" },
- { STUN_MESSAGE_INTEGRITY, "Message Integrity" },
- { STUN_ERROR_CODE, "Error Code" },
- { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" },
- { STUN_REFLECTED_FROM, "Reflected From" },
- { STUN_REALM, "Realm" },
- { STUN_NONCE, "Nonce" },
- { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" },
- { STUN_MS_VERSION, "MS Version" },
- { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" },
- { STUN_SOFTWARE, "Software" },
- { STUN_ALTERNATE_SERVER, "Alternate Server" },
- { STUN_FINGERPRINT, "Fingerprint" },
- { 0, NULL }
- };
- unsigned int i;
-
- for (i = 0; attrs[i].name; i++)
- {
- if (attrs[i].value == msg)
- return attrs[i].name;
- }
- return "Unknown Attribute";
-}
-
-
/**
* Fill the stun_header with a random request_id
*
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
-
/**
- * Testcase for STUN server resolution
+ * Message types for STUN server resolution
*
* @file nat/nat_stun.h
* @brief Testcase for STUN library
* @author Bruno Souza Cabral
* @autor Mark Spencer (Original code borrowed from Asterisk)
- *
+ * @author Christian Grothoff
*/
#define STUN_MAGIC_COOKIE 0x2112A442
-typedef struct { uint32_t id[3]; } GNUNET_PACKED stun_trans_id;
+typedef struct {
+ uint32_t id[3];
+} GNUNET_PACKED stun_trans_id;
+
struct stun_header
{
stun_trans_id id;
} GNUNET_PACKED;
+
struct stun_attr
{
uint16_t attr;
uint16_t len;
} GNUNET_PACKED;
-/*
+
+/**
* The format normally used for addresses carried by STUN messages.
*/
struct stun_addr
{
uint8_t unused;
+
+ /**
+ * Address family, we expect AF_INET.
+ */
uint8_t family;
+
+ /**
+ * Port number.
+ */
uint16_t port;
+
+ /**
+ * IPv4 address. Should this be "struct in_addr"?
+ */
uint32_t addr;
} GNUNET_PACKED;
-
-/* STUN message classes */
+/**
+ * STUN message classes
+ */
enum StunClasses {
- INVALID_CLASS = 0,
- STUN_REQUEST = 0x0000,
- STUN_INDICATION = 0x0001,
- STUN_RESPONSE = 0x0002,
- STUN_ERROR_RESPONSE = 0x0003
+ INVALID_CLASS = 0,
+ STUN_REQUEST = 0x0000,
+ STUN_INDICATION = 0x0001,
+ STUN_RESPONSE = 0x0002,
+ STUN_ERROR_RESPONSE = 0x0003
};
enum StunMethods {
STUN_CHANNEL_BIND = 0x0009
};
-/* Basic attribute types in stun messages.
+
+/**
+ * Basic attribute types in stun messages.
* Messages can also contain custom attributes (codes above 0x7fff)
*/
enum StunAttributes {
STUN_ALTERNATE_SERVER = 0x8023,
STUN_FINGERPRINT = 0x8028
};
+
+
+/**
+ * Convert a message to a StunClass
+ *
+ * @param msg the received message
+ * @return the converted StunClass
+ */
+static int
+decode_class(int msg)
+{
+ /* Sorry for the magic, but this maps the class according to rfc5245 */
+ return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7);
+}
+
+/**
+ * Convert a message to a StunMethod
+ *
+ * @param msg the received message
+ * @return the converted StunMethod
+ */
+static int
+decode_method(int msg)
+{
+ return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2);
+}
+
+
+/**
+ * Print a class and method from a STUN message
+ *
+ * @param msg
+ * @return string with the message class and method
+ */
+static const char *
+stun_msg2str (int msg)
+{
+ static const struct {
+ enum StunClasses value;
+ const char *name;
+ } classes[] = {
+ { STUN_REQUEST, "Request" },
+ { STUN_INDICATION, "Indication" },
+ { STUN_RESPONSE, "Response" },
+ { STUN_ERROR_RESPONSE, "Error Response" },
+ { 0, NULL }
+ };
+ static const struct {
+ enum StunMethods value;
+ const char *name;
+ } methods[] = {
+ { STUN_BINDING, "Binding" },
+ { 0, NULL }
+ };
+ static char result[64];
+ const char *msg_class = NULL;
+ const char *method = NULL;
+ int value;
+
+ value = decode_class (msg);
+ for (unsigned int i = 0; classes[i].name; i++)
+ if (classes[i].value == value)
+ {
+ msg_class = classes[i].name;
+ break;
+ }
+ value = decode_method (msg);
+ for (unsigned int i = 0; methods[i].name; i++)
+ if (methods[i].value == value)
+ {
+ method = methods[i].name;
+ break;
+ }
+ GNUNET_snprintf (result,
+ sizeof(result),
+ "%s %s",
+ method ? : "Unknown Method",
+ msg_class ? : "Unknown Class Message");
+ return result;
+}
+
+
+/**
+ * Print attribute name
+ *
+ * @param msg with a attribute type
+ * @return string with the attribute name
+ */
+static const char *
+stun_attr2str (enum StunAttributes msg)
+{
+ static const struct {
+ enum StunAttributes value;
+ const char *name;
+ } attrs[] = {
+ { STUN_MAPPED_ADDRESS, "Mapped Address" },
+ { STUN_RESPONSE_ADDRESS, "Response Address" },
+ { STUN_CHANGE_ADDRESS, "Change Address" },
+ { STUN_SOURCE_ADDRESS, "Source Address" },
+ { STUN_CHANGED_ADDRESS, "Changed Address" },
+ { STUN_USERNAME, "Username" },
+ { STUN_PASSWORD, "Password" },
+ { STUN_MESSAGE_INTEGRITY, "Message Integrity" },
+ { STUN_ERROR_CODE, "Error Code" },
+ { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" },
+ { STUN_REFLECTED_FROM, "Reflected From" },
+ { STUN_REALM, "Realm" },
+ { STUN_NONCE, "Nonce" },
+ { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" },
+ { STUN_MS_VERSION, "MS Version" },
+ { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" },
+ { STUN_SOFTWARE, "Software" },
+ { STUN_ALTERNATE_SERVER, "Alternate Server" },
+ { STUN_FINGERPRINT, "Fingerprint" },
+ { 0, NULL }
+ };
+
+ for (unsigned int i = 0; attrs[i].name; i++)
+ if (attrs[i].value == msg)
+ return attrs[i].name;
+ return "Unknown Attribute";
+}
+
+
+/* end of nat_stun.h */