aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-11-30 07:31:09 +0100
committerChristian Grothoff <christian@grothoff.org>2016-11-30 07:31:09 +0100
commit1b4333f3a6a4f76aa76fc3abc21e8476ea0a92e3 (patch)
tree86bbecfcd30d250ab5a123c793595f8ff6ff33b1 /src
parent27068700bceca89cd940816a7b5cd03933d3cc0b (diff)
downloadgnunet-1b4333f3a6a4f76aa76fc3abc21e8476ea0a92e3.tar.gz
gnunet-1b4333f3a6a4f76aa76fc3abc21e8476ea0a92e3.zip
towards moving STUN logic into new NAT service
Diffstat (limited to 'src')
-rw-r--r--src/include/gnunet_nat_service.h102
-rw-r--r--src/nat/Makefile.am7
-rw-r--r--src/nat/gnunet-service-nat.c35
-rw-r--r--src/nat/gnunet-service-nat_stun.c211
-rw-r--r--src/nat/gnunet-service-nat_stun.h61
-rw-r--r--src/nat/nat_api.c10
-rw-r--r--src/nat/nat_api_stun.c261
-rw-r--r--src/nat/nat_stun.c126
-rw-r--r--src/nat/nat_stun.h170
9 files changed, 802 insertions, 181 deletions
diff --git a/src/include/gnunet_nat_service.h b/src/include/gnunet_nat_service.h
index a59069545..378f5a8cb 100644
--- a/src/include/gnunet_nat_service.h
+++ b/src/include/gnunet_nat_service.h
@@ -198,37 +198,6 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
198 198
199 199
200/** 200/**
201 * Handle an incoming STUN message. This function is useful as
202 * some GNUnet service may be listening on a UDP port and might
203 * thus receive STUN messages while trying to receive other data.
204 * In this case, this function can be used to act as a proper
205 * STUN server (if desired).
206 *
207 * The function does some basic sanity checks on packet size and
208 * content, try to extract a bit of information, and possibly replies
209 * if this is an actual STUN message.
210 *
211 * At the moment this only processes BIND requests, and returns the
212 * externally visible address of the request.
213 *
214 * @param nh handle to the NAT service
215 * @param sender_addr address from which we got @a data
216 * @param sender_addr_len number of bytes in @a sender_addr
217 * @param data the packet
218 * @param data_size number of bytes in @a data
219 * @return #GNUNET_OK on success
220 * #GNUNET_NO if the packet is not a STUN packet
221 * #GNUNET_SYSERR on internal error handling the packet
222 */
223int
224GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
225 const struct sockaddr *sender_addr,
226 size_t sender_addr_len,
227 const void *data,
228 size_t data_size);
229
230
231/**
232 * Test if the given address is (currently) a plausible IP address for 201 * Test if the given address is (currently) a plausible IP address for
233 * this peer. Mostly a convenience function so that clients do not 202 * this peer. Mostly a convenience function so that clients do not
234 * have to explicitly track all IPs that the #GNUNET_NAT_AddressCallback 203 * have to explicitly track all IPs that the #GNUNET_NAT_AddressCallback
@@ -398,6 +367,77 @@ typedef void
398 367
399 368
400/** 369/**
370 * Handle an incoming STUN message. This function is useful as
371 * some GNUnet service may be listening on a UDP port and might
372 * thus receive STUN messages while trying to receive other data.
373 * In this case, this function can be used to process replies
374 * to STUN requests.
375 *
376 * The function does some basic sanity checks on packet size and
377 * content, try to extract a bit of information.
378 *
379 * At the moment this only processes BIND requests, and returns the
380 * externally visible address of the request to the rest of the
381 * NAT logic.
382 *
383 * @param nh handle to the NAT service
384 * @param sender_addr address from which we got @a data
385 * @param sender_addr_len number of bytes in @a sender_addr
386 * @param data the packet
387 * @param data_size number of bytes in @a data
388 * @return #GNUNET_OK on success
389 * #GNUNET_NO if the packet is not a STUN packet
390 * #GNUNET_SYSERR on internal error handling the packet
391 */
392int
393GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
394 const struct sockaddr *sender_addr,
395 size_t sender_addr_len,
396 const void *data,
397 size_t data_size);
398
399
400/**
401 * Handle to a request given to the resolver. Can be used to cancel
402 * the request prior to the timeout or successful execution. Also
403 * used to track our internal state for the request.
404 */
405struct GNUNET_NAT_STUN_Handle;
406
407
408/**
409 * Make Generic STUN request. Sends a generic stun request to the
410 * server specified using the specified socket. If we do this,
411 * we need to watch for possible responses and call
412 * #GNUNET_NAT_stun_handle_packet() on incoming packets.
413 *
414 * @param server the address of the stun server
415 * @param port port of the stun server, in host byte order
416 * @param sock the socket used to send the request, must be a
417 * UDP socket
418 * @param cb callback in case of error
419 * @param cb_cls closure for @a cb
420 * @return NULL on error
421 */
422struct GNUNET_NAT_STUN_Handle *
423GNUNET_NAT_stun_make_request (const char *server,
424 uint16_t port,
425 struct GNUNET_NETWORK_Handle *sock,
426 GNUNET_NAT_TestCallback cb,
427 void *cb_cls);
428
429
430/**
431 * Cancel active STUN request. Frees associated resources
432 * and ensures that the callback is no longer invoked.
433 *
434 * @param rh request to cancel
435 */
436void
437GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh);
438
439
440/**
401 * Start testing if NAT traversal works using the given configuration 441 * Start testing if NAT traversal works using the given configuration
402 * (IPv4-only). The transport adapters should be down while using 442 * (IPv4-only). The transport adapters should be down while using
403 * this function. 443 * this function.
diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am
index c3477930d..6e96c41ff 100644
--- a/src/nat/Makefile.am
+++ b/src/nat/Makefile.am
@@ -84,7 +84,9 @@ libgnunetnat_la_LDFLAGS = \
84 -version-info 1:1:1 84 -version-info 1:1:1
85 85
86libgnunetnatnew_la_SOURCES = \ 86libgnunetnatnew_la_SOURCES = \
87 nat_api.c nat.h 87 nat_api.c \
88 nat_api_stun.c nat_stun.h \
89 nat.h
88libgnunetnatnew_la_LIBADD = \ 90libgnunetnatnew_la_LIBADD = \
89 $(top_builddir)/src/util/libgnunetutil.la \ 91 $(top_builddir)/src/util/libgnunetutil.la \
90 $(GN_LIBINTL) @EXT_LIBS@ 92 $(GN_LIBINTL) @EXT_LIBS@
@@ -93,7 +95,8 @@ libgnunetnatnew_la_LDFLAGS = \
93 -version-info 2:0:0 95 -version-info 2:0:0
94 96
95gnunet_service_nat_SOURCES = \ 97gnunet_service_nat_SOURCES = \
96 gnunet-service-nat.c 98 gnunet-service-nat.c \
99 gnunet-service-nat_stun.c gnunet-service-nat_stun.h
97gnunet_service_nat_LDADD = \ 100gnunet_service_nat_LDADD = \
98 $(top_builddir)/src/util/libgnunetutil.la \ 101 $(top_builddir)/src/util/libgnunetutil.la \
99 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 102 $(top_builddir)/src/statistics/libgnunetstatistics.la \
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c
index f7dbbce3a..8499a9724 100644
--- a/src/nat/gnunet-service-nat.c
+++ b/src/nat/gnunet-service-nat.c
@@ -34,6 +34,7 @@
34#include "gnunet_signatures.h" 34#include "gnunet_signatures.h"
35#include "gnunet_statistics_service.h" 35#include "gnunet_statistics_service.h"
36#include "gnunet_nat_service.h" 36#include "gnunet_nat_service.h"
37#include "gnunet-service-nat_stun.h"
37#include "nat.h" 38#include "nat.h"
38#include <gcrypt.h> 39#include <gcrypt.h>
39 40
@@ -360,6 +361,7 @@ handle_stun (void *cls,
360 const void *payload; 361 const void *payload;
361 size_t sa_len; 362 size_t sa_len;
362 size_t payload_size; 363 size_t payload_size;
364 struct sockaddr_in external_addr;
363 365
364 sa_len = ntohs (message->sender_addr_size); 366 sa_len = ntohs (message->sender_addr_size);
365 payload_size = ntohs (message->payload_size); 367 payload_size = ntohs (message->payload_size);
@@ -386,7 +388,28 @@ handle_stun (void *cls,
386 } 388 }
387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
388 "Received HANDLE_STUN message from client\n"); 390 "Received HANDLE_STUN message from client\n");
389 // FIXME: actually handle STUN request! 391 if (GNUNET_OK ==
392 GNUNET_NAT_stun_handle_packet_ (payload,
393 payload_size,
394 &external_addr))
395 {
396 /* FIXME: do something with "external_addr"! We
397 now know that a server at "sa" claims that
398 we are visible at IP "external_addr".
399
400 We should (for some fixed period of time) tell
401 all of our clients that listen to a NAT'ed address
402 that they might want to consider the given 'external_ip'
403 as their public IP address (this includes TCP and UDP
404 clients, even if only UDP sends STUN requests).
405
406 If we do not get a renewal, the "external_addr" should be
407 removed again. The timeout frequency should be configurable
408 (with a sane default), so that the UDP plugin can tell how
409 often to re-request STUN.
410 */
411
412 }
390 GNUNET_SERVICE_client_continue (ch->client); 413 GNUNET_SERVICE_client_continue (ch->client);
391} 414}
392 415
@@ -786,12 +809,14 @@ ifc_proc (void *cls,
786 * of addresses this peer has. 809 * of addresses this peer has.
787 * 810 *
788 * @param delta the entry in the list that changed 811 * @param delta the entry in the list that changed
812 * @param ch client to contact
789 * @param add #GNUNET_YES to add, #GNUNET_NO to remove 813 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
790 * @param addr the address that changed 814 * @param addr the address that changed
791 * @param addr_len number of bytes in @a addr 815 * @param addr_len number of bytes in @a addr
792 */ 816 */
793static void 817static void
794notify_client (struct LocalAddressList *delta, 818notify_client (struct LocalAddressList *delta,
819 struct ClientHandle *ch,
795 int add, 820 int add,
796 const void *addr, 821 const void *addr,
797 size_t addr_len) 822 size_t addr_len)
@@ -800,13 +825,13 @@ notify_client (struct LocalAddressList *delta,
800 struct GNUNET_NAT_AddressChangeNotificationMessage *msg; 825 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
801 826
802 env = GNUNET_MQ_msg_extra (msg, 827 env = GNUNET_MQ_msg_extra (msg,
803 alen, 828 addr_len,
804 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); 829 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
805 msg->add_remove = htonl (add); 830 msg->add_remove = htonl (add);
806 msg->addr_class = htonl (delta->ac); 831 msg->addr_class = htonl (delta->ac);
807 GNUNET_memcpy (&msg[1], 832 GNUNET_memcpy (&msg[1],
808 addr, 833 addr,
809 alen); 834 addr_len);
810 GNUNET_MQ_send (ch->mq, 835 GNUNET_MQ_send (ch->mq,
811 env); 836 env);
812} 837}
@@ -849,6 +874,7 @@ notify_clients (struct LocalAddressList *delta,
849 c4 = (const struct sockaddr_in *) ch->addrs[i]; 874 c4 = (const struct sockaddr_in *) ch->addrs[i];
850 v4.sin_port = c4->sin_port; 875 v4.sin_port = c4->sin_port;
851 notify_client (delta, 876 notify_client (delta,
877 ch,
852 add, 878 add,
853 &v4, 879 &v4,
854 alen); 880 alen);
@@ -866,8 +892,9 @@ notify_clients (struct LocalAddressList *delta,
866 if (AF_INET6 != ch->addrs[i]->sa_family) 892 if (AF_INET6 != ch->addrs[i]->sa_family)
867 continue; /* IPv4 not relevant */ 893 continue; /* IPv4 not relevant */
868 c6 = (const struct sockaddr_in6 *) ch->addrs[i]; 894 c6 = (const struct sockaddr_in6 *) ch->addrs[i];
869 v6.sin_port = c6->sin_port; 895 v6.sin6_port = c6->sin6_port;
870 notify_client (delta, 896 notify_client (delta,
897 ch,
871 add, 898 add,
872 &v6, 899 &v6,
873 alen); 900 alen);
diff --git a/src/nat/gnunet-service-nat_stun.c b/src/nat/gnunet-service-nat_stun.c
new file mode 100644
index 000000000..6f3ea10eb
--- /dev/null
+++ b/src/nat/gnunet-service-nat_stun.c
@@ -0,0 +1,211 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2015, 2016 GNUnet e.V.
4
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.
9
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.
14
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.
19*/
20/**
21 * This code provides some support for doing STUN transactions. We
22 * receive the simplest possible packet as the STUN server and try
23 * to respond properly.
24 *
25 * All STUN packets start with a simple header made of a type,
26 * length (excluding the header) and a 16-byte random transaction id.
27 * Following the header we may have zero or more attributes, each
28 * structured as a type, length and a value (whose format depends
29 * on the type, but often contains addresses).
30 * Of course all fields are in network format.
31 *
32 * This code was based on ministun.c.
33 *
34 * @file nat/gnunet-service-nat_stun.c
35 * @brief Functions for STUN functionality
36 * @author Bruno Souza Cabral
37 */
38
39#include "platform.h"
40#include "gnunet_util_lib.h"
41#include "nat_stun.h"
42
43#define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
44
45
46/**
47 * Context for #stun_get_mapped().
48 * Used to store state across processing attributes.
49 */
50struct StunState
51{
52 uint16_t attr;
53};
54
55
56/**
57 * Extract the STUN_MAPPED_ADDRESS from the stun response.
58 * This is used as a callback for stun_handle_response
59 * when called from stun_request.
60 *
61 * @param[out] st pointer where we will set the type
62 * @param attr received stun attribute
63 * @param magic Magic cookie
64 * @param[out] arg pointer to a sockaddr_in where we will set the reported IP and port
65 * @return #GNUNET_OK if @a arg was initialized
66 */
67static int
68stun_get_mapped (struct StunState *st,
69 const struct stun_attr *attr,
70 uint32_t magic,
71 struct sockaddr_in *arg)
72{
73 const struct stun_addr *returned_addr;
74 struct sockaddr_in *sa = (struct sockaddr_in *) arg;
75 uint16_t type = ntohs (attr->attr);
76
77 switch (type)
78 {
79 case STUN_MAPPED_ADDRESS:
80 if ( (st->attr == STUN_XOR_MAPPED_ADDRESS) ||
81 (st->attr == STUN_MS_XOR_MAPPED_ADDRESS) )
82 return GNUNET_NO;
83 magic = 0;
84 break;
85 case STUN_MS_XOR_MAPPED_ADDRESS:
86 if (st->attr == STUN_XOR_MAPPED_ADDRESS)
87 return GNUNET_NO;
88 break;
89 case STUN_XOR_MAPPED_ADDRESS:
90 break;
91 default:
92 return GNUNET_NO;
93 }
94
95 if (ntohs (attr->len) < sizeof (struct stun_addr))
96 return GNUNET_NO;
97 returned_addr = (const struct stun_addr *)(attr + 1);
98 if (AF_INET != returned_addr->family)
99 return GNUNET_NO;
100 st->attr = type;
101 sa->sin_family = AF_INET;
102 sa->sin_port = returned_addr->port ^ htons (ntohl(magic) >> 16);
103 sa->sin_addr.s_addr = returned_addr->addr ^ magic;
104 return GNUNET_OK;
105}
106
107
108/**
109 * Handle an incoming STUN response. Do some basic sanity checks on
110 * packet size and content, try to extract information.
111 * At the moment this only processes BIND requests,
112 * and returns the externally visible address of the original
113 * request.
114 *
115 * @param data the packet
116 * @param len the length of the packet in @a data
117 * @param[out] arg sockaddr_in where we will set our discovered address
118 * @return #GNUNET_OK on success,
119 * #GNUNET_NO if the packet is invalid (not a stun packet)
120 */
121int
122GNUNET_NAT_stun_handle_packet_ (const void *data,
123 size_t len,
124 struct sockaddr_in *arg)
125{
126 const struct stun_header *hdr;
127 const struct stun_attr *attr;
128 struct StunState st;
129 uint32_t advertised_message_size;
130 uint32_t message_magic_cookie;
131 int ret = GNUNET_SYSERR;
132
133 /* On entry, 'len' is the length of the UDP payload. After the
134 * initial checks it becomes the size of unprocessed options,
135 * while 'data' is advanced accordingly.
136 */
137 if (len < sizeof(struct stun_header))
138 {
139 LOG (GNUNET_ERROR_TYPE_DEBUG,
140 "Packet too short to be a STUN packet\n");
141 return GNUNET_NO;
142 }
143 hdr = data;
144 /* Skip header as it is already in hdr */
145 len -= sizeof(struct stun_header);
146 data += sizeof(struct stun_header);
147
148 /* len as advertised in the message */
149 advertised_message_size = ntohs (hdr->msglen);
150 message_magic_cookie = ntohl (hdr->magic);
151 /* Compare if the cookie match */
152 if (STUN_MAGIC_COOKIE != message_magic_cookie)
153 {
154 LOG (GNUNET_ERROR_TYPE_DEBUG,
155 "Invalid magic cookie for STUN packet\n");
156 return GNUNET_NO;
157 }
158
159 LOG (GNUNET_ERROR_TYPE_INFO,
160 "STUN Packet, msg %s (%04x), length: %d\n",
161 stun_msg2str (ntohs (hdr->msgtype)),
162 ntohs (hdr->msgtype),
163 advertised_message_size);
164 if (advertised_message_size > len)
165 {
166 LOG (GNUNET_ERROR_TYPE_INFO,
167 "Scrambled STUN packet length (got %d, expecting %d)\n",
168 advertised_message_size,
169 (int) len);
170 return GNUNET_NO;
171 }
172 len = advertised_message_size;
173 memset (&st, 0, sizeof(st));
174
175 while (len > 0)
176 {
177 if (len < sizeof (struct stun_attr))
178 {
179 LOG (GNUNET_ERROR_TYPE_INFO,
180 "Attribute too short (got %d, expecting %d)\n",
181 (int) len,
182 (int) sizeof (struct stun_attr));
183 break;
184 }
185 attr = (const struct stun_attr *) data;
186
187 /* compute total attribute length */
188 advertised_message_size = ntohs (attr->len) + sizeof (struct stun_attr);
189
190 /* Check if we still have space in our buffer */
191 if (advertised_message_size > len)
192 {
193 LOG (GNUNET_ERROR_TYPE_INFO,
194 "Inconsistent attribute (length %d exceeds remaining msg len %d)\n",
195 advertised_message_size,
196 (int) len);
197 break;
198 }
199 if (GNUNET_OK ==
200 stun_get_mapped (&st,
201 attr,
202 hdr->magic,
203 arg))
204 ret = GNUNET_OK;
205 data += advertised_message_size;
206 len -= advertised_message_size;
207 }
208 return ret;
209}
210
211/* end of gnunet-service-nat_stun.c */
diff --git a/src/nat/gnunet-service-nat_stun.h b/src/nat/gnunet-service-nat_stun.h
new file mode 100644
index 000000000..3d7e18f53
--- /dev/null
+++ b/src/nat/gnunet-service-nat_stun.h
@@ -0,0 +1,61 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2015, 2016 GNUnet e.V.
4
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.
9
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.
14
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.
19*/
20/**
21 * This code provides some support for doing STUN transactions. We
22 * receive the simplest possible packet as the STUN server and try
23 * to respond properly.
24 *
25 * All STUN packets start with a simple header made of a type,
26 * length (excluding the header) and a 16-byte random transaction id.
27 * Following the header we may have zero or more attributes, each
28 * structured as a type, length and a value (whose format depends
29 * on the type, but often contains addresses).
30 * Of course all fields are in network format.
31 *
32 * This code was based on ministun.c.
33 *
34 * @file nat/gnunet-service-nat_stun.h
35 * @brief Functions for STUN functionality
36 * @author Bruno Souza Cabral
37 */
38#ifndef GNUNET_SERVICE_NAT_STUN_H
39#define GNUNET_SERVICE_NAT_STUN_H
40
41#include "platform.h"
42
43/**
44 * Handle an incoming STUN response. Do some basic sanity checks on
45 * packet size and content, try to extract information.
46 * At the moment this only processes BIND requests,
47 * and returns the externally visible address of the original
48 * request.
49 *
50 * @param data the packet
51 * @param len the length of the packet in @a data
52 * @param[out] arg sockaddr_in where we will set our discovered address
53 * @return #GNUNET_OK on success,
54 * #GNUNET_NO if the packet is invalid (not a stun packet)
55 */
56int
57GNUNET_NAT_stun_handle_packet_ (const void *data,
58 size_t len,
59 struct sockaddr_in *arg);
60
61#endif
diff --git a/src/nat/nat_api.c b/src/nat/nat_api.c
index 421befab3..4c324376b 100644
--- a/src/nat/nat_api.c
+++ b/src/nat/nat_api.c
@@ -544,15 +544,15 @@ test_stun_packet (const void *data,
544 * Handle an incoming STUN message. This function is useful as 544 * Handle an incoming STUN message. This function is useful as
545 * some GNUnet service may be listening on a UDP port and might 545 * some GNUnet service may be listening on a UDP port and might
546 * thus receive STUN messages while trying to receive other data. 546 * thus receive STUN messages while trying to receive other data.
547 * In this case, this function can be used to act as a proper 547 * In this case, this function can be used to process replies
548 * STUN server (if desired). 548 * to STUN requests.
549 * 549 *
550 * The function does some basic sanity checks on packet size and 550 * The function does some basic sanity checks on packet size and
551 * content, try to extract a bit of information, and possibly replies 551 * content, try to extract a bit of information.
552 * if this is an actual STUN message.
553 * 552 *
554 * At the moment this only processes BIND requests, and returns the 553 * At the moment this only processes BIND requests, and returns the
555 * externally visible address of the request. 554 * externally visible address of the request to the rest of the
555 * NAT logic.
556 * 556 *
557 * @param nh handle to the NAT service 557 * @param nh handle to the NAT service
558 * @param sender_addr address from which we got @a data 558 * @param sender_addr address from which we got @a data
diff --git a/src/nat/nat_api_stun.c b/src/nat/nat_api_stun.c
new file mode 100644
index 000000000..0d4ba86d1
--- /dev/null
+++ b/src/nat/nat_api_stun.c
@@ -0,0 +1,261 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2015, 2016 GNUnet e.V.
4
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.
9
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.
14
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.
19*/
20/**
21 * This code provides some support for doing STUN transactions.
22 * We send simplest possible packet ia REQUEST with BIND to a STUN server.
23 *
24 * All STUN packets start with a simple header made of a type,
25 * length (excluding the header) and a 16-byte random transaction id.
26 * Following the header we may have zero or more attributes, each
27 * structured as a type, length and a value (whose format depends
28 * on the type, but often contains addresses).
29 * Of course all fields are in network format.
30 *
31 * This code was based on ministun.c.
32 *
33 * @file nat/nat_api_stun.c
34 * @brief Functions for STUN functionality
35 * @author Bruno Souza Cabral
36 */
37
38#include "platform.h"
39#include "gnunet_util_lib.h"
40#include "gnunet_resolver_service.h"
41#include "gnunet_nat_lib.h"
42
43
44#include "nat_stun.h"
45
46#define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
47
48#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
49
50
51/**
52 * Handle to a request given to the resolver. Can be used to cancel
53 * the request prior to the timeout or successful execution. Also
54 * used to track our internal state for the request.
55 */
56struct GNUNET_NAT_STUN_Handle
57{
58
59 /**
60 * Handle to a pending DNS lookup request.
61 */
62 struct GNUNET_RESOLVER_RequestHandle *dns_active;
63
64 /**
65 * Handle to the listen socket
66 */
67 struct GNUNET_NETWORK_Handle *sock;
68
69 /**
70 * Stun server address
71 */
72 char *stun_server;
73
74 /**
75 * Function to call when a error occours
76 */
77 GNUNET_NAT_STUN_ErrorCallback cb;
78
79 /**
80 * Closure for @e cb.
81 */
82 void *cb_cls;
83
84 /**
85 * Do we got a DNS resolution successfully?
86 */
87 int dns_success;
88
89 /**
90 * STUN port
91 */
92 uint16_t stun_port;
93
94};
95
96
97/**
98 * Encode a class and method to a compatible STUN format
99 *
100 * @param msg_class class to be converted
101 * @param method method to be converted
102 * @return message in a STUN compatible format
103 */
104static int
105encode_message (enum StunClasses msg_class,
106 enum StunMethods method)
107{
108 return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) |
109 (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2);
110}
111
112
113/**
114 * Fill the stun_header with a random request_id
115 *
116 * @param req, stun header to be filled
117 */
118static void
119generate_request_id (struct stun_header *req)
120{
121 req->magic = htonl(STUN_MAGIC_COOKIE);
122 for (unsigned int x = 0; x < 3; x++)
123 req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
124 UINT32_MAX);
125}
126
127
128/**
129 * Try to establish a connection given the specified address.
130 *
131 * @param cls our `struct GNUNET_NAT_STUN_Handle *`
132 * @param addr address to try, NULL for "last call"
133 * @param addrlen length of @a addr
134 */
135static void
136stun_dns_callback (void *cls,
137 const struct sockaddr *addr,
138 socklen_t addrlen)
139{
140 struct GNUNET_NAT_STUN_Handle *rh = cls;
141 struct stun_header req;
142 struct sockaddr_in server;
143
144 if (NULL == addr)
145 {
146 rh->dns_active = NULL;
147 if (GNUNET_NO == rh->dns_success)
148 {
149 LOG (GNUNET_ERROR_TYPE_INFO,
150 "Error resolving host %s\n",
151 rh->stun_server);
152 rh->cb (rh->cb_cls,
153 GNUNET_NAT_ERROR_NOT_ONLINE);
154 }
155 else if (GNUNET_SYSERR == rh->dns_success)
156 {
157 rh->cb (rh->cb_cls,
158 GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR);
159 }
160 else
161 {
162 rh->cb (rh->cb_cls,
163 GNUNET_NAT_ERROR_SUCCESS);
164 }
165 GNUNET_NAT_stun_make_request_cancel (rh);
166 return;
167 }
168
169 rh->dns_success = GNUNET_YES;
170 memset (&server, 0, sizeof(server));
171 server.sin_family = AF_INET;
172 server.sin_addr = ((struct sockaddr_in *)addr)->sin_addr;
173 server.sin_port = htons (rh->stun_port);
174#if HAVE_SOCKADDR_IN_SIN_LEN
175 server.sin_len = (u_char) sizeof (struct sockaddr_in);
176#endif
177
178 /* Craft the simplest possible STUN packet. A request binding */
179 generate_request_id (&req);
180 req.msglen = htons (0);
181 req.msgtype = htons (encode_message (STUN_REQUEST,
182 STUN_BINDING));
183
184 /* Send the packet */
185 if (-1 ==
186 GNUNET_NETWORK_socket_sendto (rh->sock,
187 &req,
188 sizeof (req),
189 (const struct sockaddr *) &server,
190 sizeof (server)))
191 {
192 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
193 "sendto");
194 rh->dns_success = GNUNET_SYSERR;
195 return;
196 }
197}
198
199
200/**
201 * Make Generic STUN request. Sends a generic stun request to the
202 * server specified using the specified socket, possibly waiting for
203 * a reply and filling the 'reply' field with the externally visible
204 * address.
205 *
206 * @param server the address of the stun server
207 * @param port port of the stun server, in host byte order
208 * @param sock the socket used to send the request
209 * @param cb callback in case of error
210 * @param cb_cls closure for @a cb
211 * @return NULL on error
212 */
213struct GNUNET_NAT_STUN_Handle *
214GNUNET_NAT_stun_make_request (const char *server,
215 uint16_t port,
216 struct GNUNET_NETWORK_Handle *sock,
217 GNUNET_NAT_STUN_ErrorCallback cb,
218 void *cb_cls)
219{
220 struct GNUNET_NAT_STUN_Handle *rh;
221
222 rh = GNUNET_new (struct GNUNET_NAT_STUN_Handle);
223 rh->sock = sock;
224 rh->cb = cb;
225 rh->cb_cls = cb_cls;
226 rh->stun_server = GNUNET_strdup (server);
227 rh->stun_port = port;
228 rh->dns_success = GNUNET_NO;
229 rh->dns_active = GNUNET_RESOLVER_ip_get (rh->stun_server,
230 AF_INET,
231 TIMEOUT,
232 &stun_dns_callback, rh);
233 if (NULL == rh->dns_active)
234 {
235 GNUNET_NAT_stun_make_request_cancel (rh);
236 return NULL;
237 }
238 return rh;
239}
240
241
242/**
243 * Cancel active STUN request. Frees associated resources
244 * and ensures that the callback is no longer invoked.
245 *
246 * @param rh request to cancel
247 */
248void
249GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh)
250{
251 if (NULL != rh->dns_active)
252 {
253 GNUNET_RESOLVER_request_cancel (rh->dns_active);
254 rh->dns_active = NULL;
255 }
256 GNUNET_free (rh->stun_server);
257 GNUNET_free (rh);
258}
259
260
261/* end of nat_stun.c */
diff --git a/src/nat/nat_stun.c b/src/nat/nat_stun.c
index b914abb2e..62916ab84 100644
--- a/src/nat/nat_stun.c
+++ b/src/nat/nat_stun.c
@@ -104,32 +104,6 @@ struct StunState
104 104
105 105
106/** 106/**
107 * Convert a message to a StunClass
108 *
109 * @param msg the received message
110 * @return the converted StunClass
111 */
112static int
113decode_class(int msg)
114{
115 /* Sorry for the magic, but this maps the class according to rfc5245 */
116 return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7);
117}
118
119/**
120 * Convert a message to a StunMethod
121 *
122 * @param msg the received message
123 * @return the converted StunMethod
124 */
125static int
126decode_method(int msg)
127{
128 return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2);
129}
130
131
132/**
133 * Encode a class and method to a compatible STUN format 107 * Encode a class and method to a compatible STUN format
134 * 108 *
135 * @param msg_class class to be converted 109 * @param msg_class class to be converted
@@ -146,106 +120,6 @@ encode_message (enum StunClasses msg_class,
146 120
147 121
148/** 122/**
149 * Print a class and method from a STUN message
150 *
151 * @param msg
152 * @return string with the message class and method
153 */
154static const char *
155stun_msg2str(int msg)
156{
157 static const struct {
158 enum StunClasses value;
159 const char *name;
160 } classes[] = {
161 { STUN_REQUEST, "Request" },
162 { STUN_INDICATION, "Indication" },
163 { STUN_RESPONSE, "Response" },
164 { STUN_ERROR_RESPONSE, "Error Response" },
165 { 0, NULL }
166 };
167 static const struct {
168 enum StunMethods value;
169 const char *name;
170 } methods[] = {
171 { STUN_BINDING, "Binding" },
172 { 0, NULL }
173 };
174 static char result[32];
175 const char *msg_class = NULL;
176 const char *method = NULL;
177 int i;
178 int value;
179
180 value = decode_class(msg);
181 for (i = 0; classes[i].name; i++)
182 {
183 msg_class = classes[i].name;
184 if (classes[i].value == value)
185 break;
186 }
187 value = decode_method(msg);
188 for (i = 0; methods[i].name; i++)
189 {
190 method = methods[i].name;
191 if (methods[i].value == value)
192 break;
193 }
194 GNUNET_snprintf (result,
195 sizeof(result),
196 "%s %s",
197 method ? : "Unknown Method",
198 msg_class ? : "Unknown Class Message");
199 return result;
200}
201
202
203/**
204 * Print attribute name
205 *
206 * @param msg with a attribute type
207 * @return string with the attribute name
208 */
209static const char *
210stun_attr2str (int msg)
211{
212 static const struct {
213 enum StunAttributes value;
214 const char *name;
215 } attrs[] = {
216 { STUN_MAPPED_ADDRESS, "Mapped Address" },
217 { STUN_RESPONSE_ADDRESS, "Response Address" },
218 { STUN_CHANGE_ADDRESS, "Change Address" },
219 { STUN_SOURCE_ADDRESS, "Source Address" },
220 { STUN_CHANGED_ADDRESS, "Changed Address" },
221 { STUN_USERNAME, "Username" },
222 { STUN_PASSWORD, "Password" },
223 { STUN_MESSAGE_INTEGRITY, "Message Integrity" },
224 { STUN_ERROR_CODE, "Error Code" },
225 { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" },
226 { STUN_REFLECTED_FROM, "Reflected From" },
227 { STUN_REALM, "Realm" },
228 { STUN_NONCE, "Nonce" },
229 { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" },
230 { STUN_MS_VERSION, "MS Version" },
231 { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" },
232 { STUN_SOFTWARE, "Software" },
233 { STUN_ALTERNATE_SERVER, "Alternate Server" },
234 { STUN_FINGERPRINT, "Fingerprint" },
235 { 0, NULL }
236 };
237 unsigned int i;
238
239 for (i = 0; attrs[i].name; i++)
240 {
241 if (attrs[i].value == msg)
242 return attrs[i].name;
243 }
244 return "Unknown Attribute";
245}
246
247
248/**
249 * Fill the stun_header with a random request_id 123 * Fill the stun_header with a random request_id
250 * 124 *
251 * @param req, stun header to be filled 125 * @param req, stun header to be filled
diff --git a/src/nat/nat_stun.h b/src/nat/nat_stun.h
index f8d99b164..4c6c178fb 100644
--- a/src/nat/nat_stun.h
+++ b/src/nat/nat_stun.h
@@ -17,15 +17,14 @@
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA. 18 Boston, MA 02110-1301, USA.
19*/ 19*/
20
21/** 20/**
22 * Testcase for STUN server resolution 21 * Message types for STUN server resolution
23 * 22 *
24 * @file nat/nat_stun.h 23 * @file nat/nat_stun.h
25 * @brief Testcase for STUN library 24 * @brief Testcase for STUN library
26 * @author Bruno Souza Cabral 25 * @author Bruno Souza Cabral
27 * @autor Mark Spencer (Original code borrowed from Asterisk) 26 * @autor Mark Spencer (Original code borrowed from Asterisk)
28 * 27 * @author Christian Grothoff
29 */ 28 */
30 29
31 30
@@ -34,7 +33,10 @@
34 33
35#define STUN_MAGIC_COOKIE 0x2112A442 34#define STUN_MAGIC_COOKIE 0x2112A442
36 35
37typedef struct { uint32_t id[3]; } GNUNET_PACKED stun_trans_id; 36typedef struct {
37 uint32_t id[3];
38} GNUNET_PACKED stun_trans_id;
39
38 40
39struct stun_header 41struct stun_header
40{ 42{
@@ -44,32 +46,47 @@ struct stun_header
44 stun_trans_id id; 46 stun_trans_id id;
45} GNUNET_PACKED; 47} GNUNET_PACKED;
46 48
49
47struct stun_attr 50struct stun_attr
48{ 51{
49 uint16_t attr; 52 uint16_t attr;
50 uint16_t len; 53 uint16_t len;
51} GNUNET_PACKED; 54} GNUNET_PACKED;
52 55
53/* 56
57/**
54 * The format normally used for addresses carried by STUN messages. 58 * The format normally used for addresses carried by STUN messages.
55 */ 59 */
56struct stun_addr 60struct stun_addr
57{ 61{
58 uint8_t unused; 62 uint8_t unused;
63
64 /**
65 * Address family, we expect AF_INET.
66 */
59 uint8_t family; 67 uint8_t family;
68
69 /**
70 * Port number.
71 */
60 uint16_t port; 72 uint16_t port;
73
74 /**
75 * IPv4 address. Should this be "struct in_addr"?
76 */
61 uint32_t addr; 77 uint32_t addr;
62} GNUNET_PACKED; 78} GNUNET_PACKED;
63 79
64 80
65 81/**
66/* STUN message classes */ 82 * STUN message classes
83 */
67enum StunClasses { 84enum StunClasses {
68 INVALID_CLASS = 0, 85 INVALID_CLASS = 0,
69 STUN_REQUEST = 0x0000, 86 STUN_REQUEST = 0x0000,
70 STUN_INDICATION = 0x0001, 87 STUN_INDICATION = 0x0001,
71 STUN_RESPONSE = 0x0002, 88 STUN_RESPONSE = 0x0002,
72 STUN_ERROR_RESPONSE = 0x0003 89 STUN_ERROR_RESPONSE = 0x0003
73}; 90};
74 91
75enum StunMethods { 92enum StunMethods {
@@ -84,7 +101,9 @@ enum StunMethods {
84 STUN_CHANNEL_BIND = 0x0009 101 STUN_CHANNEL_BIND = 0x0009
85}; 102};
86 103
87/* Basic attribute types in stun messages. 104
105/**
106 * Basic attribute types in stun messages.
88 * Messages can also contain custom attributes (codes above 0x7fff) 107 * Messages can also contain custom attributes (codes above 0x7fff)
89 */ 108 */
90enum StunAttributes { 109enum StunAttributes {
@@ -108,3 +127,128 @@ enum StunAttributes {
108 STUN_ALTERNATE_SERVER = 0x8023, 127 STUN_ALTERNATE_SERVER = 0x8023,
109 STUN_FINGERPRINT = 0x8028 128 STUN_FINGERPRINT = 0x8028
110}; 129};
130
131
132/**
133 * Convert a message to a StunClass
134 *
135 * @param msg the received message
136 * @return the converted StunClass
137 */
138static int
139decode_class(int msg)
140{
141 /* Sorry for the magic, but this maps the class according to rfc5245 */
142 return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7);
143}
144
145/**
146 * Convert a message to a StunMethod
147 *
148 * @param msg the received message
149 * @return the converted StunMethod
150 */
151static int
152decode_method(int msg)
153{
154 return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2);
155}
156
157
158/**
159 * Print a class and method from a STUN message
160 *
161 * @param msg
162 * @return string with the message class and method
163 */
164static const char *
165stun_msg2str (int msg)
166{
167 static const struct {
168 enum StunClasses value;
169 const char *name;
170 } classes[] = {
171 { STUN_REQUEST, "Request" },
172 { STUN_INDICATION, "Indication" },
173 { STUN_RESPONSE, "Response" },
174 { STUN_ERROR_RESPONSE, "Error Response" },
175 { 0, NULL }
176 };
177 static const struct {
178 enum StunMethods value;
179 const char *name;
180 } methods[] = {
181 { STUN_BINDING, "Binding" },
182 { 0, NULL }
183 };
184 static char result[64];
185 const char *msg_class = NULL;
186 const char *method = NULL;
187 int value;
188
189 value = decode_class (msg);
190 for (unsigned int i = 0; classes[i].name; i++)
191 if (classes[i].value == value)
192 {
193 msg_class = classes[i].name;
194 break;
195 }
196 value = decode_method (msg);
197 for (unsigned int i = 0; methods[i].name; i++)
198 if (methods[i].value == value)
199 {
200 method = methods[i].name;
201 break;
202 }
203 GNUNET_snprintf (result,
204 sizeof(result),
205 "%s %s",
206 method ? : "Unknown Method",
207 msg_class ? : "Unknown Class Message");
208 return result;
209}
210
211
212/**
213 * Print attribute name
214 *
215 * @param msg with a attribute type
216 * @return string with the attribute name
217 */
218static const char *
219stun_attr2str (enum StunAttributes msg)
220{
221 static const struct {
222 enum StunAttributes value;
223 const char *name;
224 } attrs[] = {
225 { STUN_MAPPED_ADDRESS, "Mapped Address" },
226 { STUN_RESPONSE_ADDRESS, "Response Address" },
227 { STUN_CHANGE_ADDRESS, "Change Address" },
228 { STUN_SOURCE_ADDRESS, "Source Address" },
229 { STUN_CHANGED_ADDRESS, "Changed Address" },
230 { STUN_USERNAME, "Username" },
231 { STUN_PASSWORD, "Password" },
232 { STUN_MESSAGE_INTEGRITY, "Message Integrity" },
233 { STUN_ERROR_CODE, "Error Code" },
234 { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" },
235 { STUN_REFLECTED_FROM, "Reflected From" },
236 { STUN_REALM, "Realm" },
237 { STUN_NONCE, "Nonce" },
238 { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" },
239 { STUN_MS_VERSION, "MS Version" },
240 { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" },
241 { STUN_SOFTWARE, "Software" },
242 { STUN_ALTERNATE_SERVER, "Alternate Server" },
243 { STUN_FINGERPRINT, "Fingerprint" },
244 { 0, NULL }
245 };
246
247 for (unsigned int i = 0; attrs[i].name; i++)
248 if (attrs[i].value == msg)
249 return attrs[i].name;
250 return "Unknown Attribute";
251}
252
253
254/* end of nat_stun.h */