diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-11-30 07:31:09 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-11-30 07:31:09 +0100 |
commit | 1b4333f3a6a4f76aa76fc3abc21e8476ea0a92e3 (patch) | |
tree | 86bbecfcd30d250ab5a123c793595f8ff6ff33b1 /src | |
parent | 27068700bceca89cd940816a7b5cd03933d3cc0b (diff) | |
download | gnunet-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.h | 102 | ||||
-rw-r--r-- | src/nat/Makefile.am | 7 | ||||
-rw-r--r-- | src/nat/gnunet-service-nat.c | 35 | ||||
-rw-r--r-- | src/nat/gnunet-service-nat_stun.c | 211 | ||||
-rw-r--r-- | src/nat/gnunet-service-nat_stun.h | 61 | ||||
-rw-r--r-- | src/nat/nat_api.c | 10 | ||||
-rw-r--r-- | src/nat/nat_api_stun.c | 261 | ||||
-rw-r--r-- | src/nat/nat_stun.c | 126 | ||||
-rw-r--r-- | src/nat/nat_stun.h | 170 |
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 | */ | ||
223 | int | ||
224 | GNUNET_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 | */ | ||
392 | int | ||
393 | GNUNET_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 | */ | ||
405 | struct 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 | */ | ||
422 | struct GNUNET_NAT_STUN_Handle * | ||
423 | GNUNET_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 | */ | ||
436 | void | ||
437 | GNUNET_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 | ||
86 | libgnunetnatnew_la_SOURCES = \ | 86 | libgnunetnatnew_la_SOURCES = \ |
87 | nat_api.c nat.h | 87 | nat_api.c \ |
88 | nat_api_stun.c nat_stun.h \ | ||
89 | nat.h | ||
88 | libgnunetnatnew_la_LIBADD = \ | 90 | libgnunetnatnew_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 | ||
95 | gnunet_service_nat_SOURCES = \ | 97 | gnunet_service_nat_SOURCES = \ |
96 | gnunet-service-nat.c | 98 | gnunet-service-nat.c \ |
99 | gnunet-service-nat_stun.c gnunet-service-nat_stun.h | ||
97 | gnunet_service_nat_LDADD = \ | 100 | gnunet_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 | */ |
793 | static void | 817 | static void |
794 | notify_client (struct LocalAddressList *delta, | 818 | notify_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 | */ | ||
50 | struct 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 | */ | ||
67 | static int | ||
68 | stun_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 | */ | ||
121 | int | ||
122 | GNUNET_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 | */ | ||
56 | int | ||
57 | GNUNET_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 | */ | ||
56 | struct 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 | */ | ||
104 | static int | ||
105 | encode_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 | */ | ||
118 | static void | ||
119 | generate_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 | */ | ||
135 | static void | ||
136 | stun_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 | */ | ||
213 | struct GNUNET_NAT_STUN_Handle * | ||
214 | GNUNET_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 | */ | ||
248 | void | ||
249 | GNUNET_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 | */ | ||
112 | static int | ||
113 | decode_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 | */ | ||
125 | static int | ||
126 | decode_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 | */ | ||
154 | static const char * | ||
155 | stun_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 | */ | ||
209 | static const char * | ||
210 | stun_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 | ||
37 | typedef struct { uint32_t id[3]; } GNUNET_PACKED stun_trans_id; | 36 | typedef struct { |
37 | uint32_t id[3]; | ||
38 | } GNUNET_PACKED stun_trans_id; | ||
39 | |||
38 | 40 | ||
39 | struct stun_header | 41 | struct 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 | |||
47 | struct stun_attr | 50 | struct 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 | */ |
56 | struct stun_addr | 60 | struct 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 | */ | ||
67 | enum StunClasses { | 84 | enum 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 | ||
75 | enum StunMethods { | 92 | enum 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 | */ |
90 | enum StunAttributes { | 109 | enum 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 | */ | ||
138 | static int | ||
139 | decode_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 | */ | ||
151 | static int | ||
152 | decode_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 | */ | ||
164 | static const char * | ||
165 | stun_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 | */ | ||
218 | static const char * | ||
219 | stun_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 */ | ||