aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nat/nat_stun.c11
-rw-r--r--src/nat/test_stun.c1131
-rw-r--r--src/nat/test_stun.h220
3 files changed, 733 insertions, 629 deletions
diff --git a/src/nat/nat_stun.c b/src/nat/nat_stun.c
index 78b0a56fc..06ed9261f 100644
--- a/src/nat/nat_stun.c
+++ b/src/nat/nat_stun.c
@@ -19,14 +19,9 @@
19*/ 19*/
20 20
21/** 21/**
22 * This code is based on ministun.c, that is based on Asterisk old STUN code. 22 *
23 * This code provides some support for doing STUN transactions. 23 * This code provides some support for doing STUN transactions.
24 * The simplest request packet is just the header defined in 24 * We send simplest possible packet ia REQUEST with BIND to a STUN server.
25 * struct stun_header, and from the response we may just look at
26 * one attribute, STUN_MAPPED_ADDRESS, that we find in the response.
27 * By doing more transactions with different server addresses we
28 * may determine more about the behaviour of the NAT boxes, of
29 * course - the details are in the RFC.
30 * 25 *
31 * All STUN packets start with a simple header made of a type, 26 * All STUN packets start with a simple header made of a type,
32 * length (excluding the header) and a 16-byte random transaction id. 27 * length (excluding the header) and a 16-byte random transaction id.
@@ -34,6 +29,8 @@
34 * structured as a type, length and a value (whose format depends 29 * structured as a type, length and a value (whose format depends
35 * on the type, but often contains addresses). 30 * on the type, but often contains addresses).
36 * Of course all fields are in network format. 31 * Of course all fields are in network format.
32 *
33 * This code was based on ministun.c.
37 * 34 *
38 * 35 *
39 * @file nat/nat_stun.c 36 * @file nat/nat_stun.c
diff --git a/src/nat/test_stun.c b/src/nat/test_stun.c
index 8448f7f85..086789f27 100644
--- a/src/nat/test_stun.c
+++ b/src/nat/test_stun.c
@@ -1,514 +1,617 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2009, 2015 Christian Grothoff (and other contributing authors) 3 Copyright (C) 2009, 2015 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 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 7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version. 8 option) any later version.
9 9
10 GNUnet is distributed in the hope that it will be useful, but 10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details. 13 General Public License for more details.
14 14
15 You should have received a copy of the GNU General Public License 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 16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19*/ 19*/
20 20
21/** 21/**
22 * Testcase for STUN server resolution 22 * Testcase for STUN server resolution
23 * 23 *
24 * @file nat/test_stun.c 24 * @file nat/test_stun.c
25 * @brief Testcase for STUN library 25 * @brief Testcase for STUN library
26 * @author Bruno Souza Cabral 26 * @author Bruno Souza Cabral - Major rewrite.
27 * @autor Mark Spencer (Original code borrowed from Asterisk) 27 * @autor Mark Spencer (Original code - borrowed from Asterisk)
28 * 28 *
29 */ 29 */
30 30
31 31
32#include "platform.h" 32#include "platform.h"
33#include "gnunet_util_lib.h" 33#include "gnunet_util_lib.h"
34#include "gnunet_program_lib.h" 34#include "gnunet_program_lib.h"
35#include "gnunet_scheduler_lib.h" 35#include "gnunet_scheduler_lib.h"
36#include "gnunet_nat_lib.h" 36#include "gnunet_nat_lib.h"
37 37
38 38
39#include "test_stun.h" 39#include "test_stun.h"
40 40
41 41#define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
42/** 42
43 * The port the test service is running on (default 7895) 43/**
44 */ 44 * The port the test service is running on (default 7895)
45static unsigned long port = 7895; 45 */
46 46static unsigned long port = 7895;
47static int ret = 1; 47static int ret = 1;
48 48
49/** 49static char *stun_server = STUN_SERVER;
50 * The listen socket of the service for IPv4 50static int stun_port = STUN_PORT;
51 */ 51
52static struct GNUNET_NETWORK_Handle *lsock4; 52/**
53 53 * The listen socket of the service for IPv4
54 54 */
55/** 55static struct GNUNET_NETWORK_Handle *lsock4;
56 * The listen task ID for IPv4 56
57 */ 57
58static struct GNUNET_SCHEDULER_Task * ltask4; 58/**
59 59 * The listen task ID for IPv4
60 60 */
61static char *stun_server = STUN_SERVER; 61static struct GNUNET_SCHEDULER_Task * ltask4;
62static int stun_port = STUN_PORT; 62
63 63
64static int stun_debug = 1; 64
65 65/**
66 66 * Handle to a request given to the resolver. Can be used to cancel
67struct stun_strings { 67 * the request prior to the timeout or successful execution. Also
68 const int value; 68 * used to track our internal state for the request.
69 const char *name; 69 */
70}; 70struct GNUNET_NAT_StunRequestHandle {
71 71
72 72 /**
73static inline int stun_msg2class(int msg) 73 * Handle to a pending DNS lookup request.
74{ 74 */
75 return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7); 75 struct GNUNET_RESOLVER_RequestHandle *dns_active;
76} 76
77 77
78static inline int stun_msg2method(int msg) 78 /**
79{ 79 * Handle to the listen socket
80 return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2); 80 */
81} 81 struct GNUNET_NETWORK_Handle * sock;
82 82
83static inline int stun_msg2type(int class, int method) 83};
84{ 84
85 return ((class & 1) << 4) | ((class & 2) << 7) | 85
86 (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2); 86
87} 87
88 88/* here we store credentials extracted from a message */
89/* helper function to print message names */ 89struct StunState {
90static const char *stun_msg2str(int msg) 90 uint16_t attr;
91{ 91};
92 static const struct stun_strings classes[] = { 92
93 { STUN_REQUEST, "Request" }, 93/* callback type to be invoked on stun responses. */
94 { STUN_INDICATION, "Indication" }, 94typedef int (stun_cb_f)(struct StunState *st, struct stun_attr *attr, void *arg, unsigned int magic);
95 { STUN_RESPONSE, "Response" }, 95
96 { STUN_ERROR_RESPONSE, "Error Response" }, 96
97 { 0, NULL } 97
98}; 98/**
99 static const struct stun_strings methods[] = { 99 * Convert a message to a StunClass
100 { STUN_BINDING, "Binding" }, 100 *
101 { 0, NULL } 101 * @param msg the received message
102}; 102 * @return the converted StunClass
103 static char result[32]; 103 */
104 const char *class = NULL, *method = NULL; 104static int decode_class(int msg)
105 int i, value; 105{
106 106 return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7);
107 value = stun_msg2class(msg); 107}
108 for (i = 0; classes[i].name; i++) { 108
109 class = classes[i].name; 109/**
110 if (classes[i].value == value) 110 * Convert a message to a StunMethod
111 break; 111 *
112 } 112 * @param msg the received message
113 value = stun_msg2method(msg); 113 * @return the converted StunMethod
114 for (i = 0; methods[i].name; i++) { 114 */
115 method = methods[i].name; 115static int decode_method(int msg)
116 if (methods[i].value == value) 116{
117 break; 117 return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2);
118 } 118}
119 snprintf(result, sizeof(result), "%s %s", 119
120 method ? : "Unknown Method", 120/**
121 class ? : "Unknown Class Message"); 121 * Encode a class and method to a compatible STUN format
122 return result; 122 *
123} 123 * @param msg_class class to be converted
124 124 * @param method method to be converted
125/* helper function to print attribute names */ 125 * @return message in a STUN compatible format
126static const char *stun_attr2str(int msg) 126 */
127{ 127static int encode_message(StunClasses msg_class, StunMethods method)
128 static const struct stun_strings attrs[] = { 128{
129 { STUN_MAPPED_ADDRESS, "Mapped Address" }, 129 return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) |
130 { STUN_RESPONSE_ADDRESS, "Response Address" }, 130 (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2);
131 { STUN_CHANGE_ADDRESS, "Change Address" }, 131}
132 { STUN_SOURCE_ADDRESS, "Source Address" }, 132
133 { STUN_CHANGED_ADDRESS, "Changed Address" }, 133/* helper function to print message names */
134 { STUN_USERNAME, "Username" }, 134static const char *stun_msg2str(int msg)
135 { STUN_PASSWORD, "Password" }, 135{
136 { STUN_MESSAGE_INTEGRITY, "Message Integrity" }, 136
137 { STUN_ERROR_CODE, "Error Code" }, 137 const struct { enum StunClasses value; const char *name; } classes[] = {
138 { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" }, 138 { STUN_REQUEST, "Request" },
139 { STUN_REFLECTED_FROM, "Reflected From" }, 139 { STUN_INDICATION, "Indication" },
140 { STUN_REALM, "Realm" }, 140 { STUN_RESPONSE, "Response" },
141 { STUN_NONCE, "Nonce" }, 141 { STUN_ERROR_RESPONSE, "Error Response" },
142 { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" }, 142 { 0, NULL }
143 { STUN_MS_VERSION, "MS Version" }, 143 };
144 { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" }, 144
145 { STUN_SOFTWARE, "Software" }, 145 const struct { enum StunMethods value; const char *name; } methods[] = {
146 { STUN_ALTERNATE_SERVER, "Alternate Server" }, 146 { STUN_BINDING, "Binding" },
147 { STUN_FINGERPRINT, "Fingerprint" }, 147 { 0, NULL }
148 { 0, NULL } 148 };
149}; 149
150 int i; 150 static char result[32];
151 151 const char *msg_class = NULL;
152 for (i = 0; attrs[i].name; i++) { 152 const char *method = NULL;
153 if (attrs[i].value == msg) 153 int i;
154 return attrs[i].name; 154 int value;
155 } 155
156 return "Unknown Attribute"; 156 value = decode_class(msg);
157} 157 for (i = 0; classes[i].name; i++) {
158 158 msg_class = classes[i].name;
159/* here we store credentials extracted from a message */ 159 if (classes[i].value == value)
160struct stun_state { 160 break;
161 unsigned short attr; 161 }
162}; 162 value = decode_method(msg);
163 163 for (i = 0; methods[i].name; i++) {
164static int stun_process_attr(struct stun_state *state, struct stun_attr *attr) 164 method = methods[i].name;
165{ 165 if (methods[i].value == value)
166 if (stun_debug) 166 break;
167 fprintf(stderr, "Found STUN Attribute %s (%04x), length %d\n", 167 }
168 stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); 168 snprintf(result, sizeof(result), "%s %s",
169 switch (ntohs(attr->attr)) { 169 method ? : "Unknown Method",
170 case STUN_MAPPED_ADDRESS: 170 msg_class ? : "Unknown Class Message");
171 case STUN_XOR_MAPPED_ADDRESS: 171 return result;
172 case STUN_MS_XOR_MAPPED_ADDRESS: 172}
173 break; 173
174 default: 174/* helper function to print attribute names */
175 if (stun_debug) 175static const char *stun_attr2str(int msg)
176 fprintf(stderr, "Ignoring STUN Attribute %s (%04x), length %d\n", 176{
177 stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); 177 const struct { enum StunAttributes value; const char *name; } attrs[] = {
178 } 178 { STUN_MAPPED_ADDRESS, "Mapped Address" },
179 return 0; 179 { STUN_RESPONSE_ADDRESS, "Response Address" },
180} 180 { STUN_CHANGE_ADDRESS, "Change Address" },
181 181 { STUN_SOURCE_ADDRESS, "Source Address" },
182/* append a string to an STUN message */ 182 { STUN_CHANGED_ADDRESS, "Changed Address" },
183static void append_attr_string(struct stun_attr **attr, int attrval, const char *s, int *len, int *left) 183 { STUN_USERNAME, "Username" },
184{ 184 { STUN_PASSWORD, "Password" },
185 int str_length = strlen(s); 185 { STUN_MESSAGE_INTEGRITY, "Message Integrity" },
186 int attr_length = str_length + ((~(str_length - 1)) & 0x3); 186 { STUN_ERROR_CODE, "Error Code" },
187 int size = sizeof(**attr) + attr_length; 187 { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" },
188 if (*left > size) { 188 { STUN_REFLECTED_FROM, "Reflected From" },
189 (*attr)->attr = htons(attrval); 189 { STUN_REALM, "Realm" },
190 (*attr)->len = htons(attr_length); 190 { STUN_NONCE, "Nonce" },
191 memcpy((*attr)->value, s, str_length); 191 { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" },
192 memset((*attr)->value + str_length, 0, attr_length - str_length); 192 { STUN_MS_VERSION, "MS Version" },
193 (*attr) = (struct stun_attr *)((*attr)->value + attr_length); 193 { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" },
194 *len += size; 194 { STUN_SOFTWARE, "Software" },
195 *left -= size; 195 { STUN_ALTERNATE_SERVER, "Alternate Server" },
196 } 196 { STUN_FINGERPRINT, "Fingerprint" },
197} 197 { 0, NULL }
198 198 };
199 199 int i;
200/* helper function to generate a random request id */ 200
201static void stun_req_id(struct stun_header *req) 201 for (i = 0; attrs[i].name; i++) {
202{ 202 if (attrs[i].value == msg)
203 int x; 203 return attrs[i].name;
204 srand(time(0)); 204 }
205 req->magic = htonl(STUN_MAGIC_COOKIE); 205 return "Unknown Attribute";
206 for (x = 0; x < 3; x++) 206}
207 req->id.id[x] = rand(); 207
208} 208
209 209
210/* callback type to be invoked on stun responses. */ 210static int stun_process_attr(struct StunState *state, struct stun_attr *attr)
211typedef int (stun_cb_f)(struct stun_state *st, struct stun_attr *attr, void *arg, unsigned int magic); 211{
212 212 LOG (GNUNET_ERROR_TYPE_INFO,
213/* handle an incoming STUN message. 213 "Found STUN Attribute %s (%04x), length %d\n",
214 * 214 stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
215 * Do some basic sanity checks on packet size and content, 215
216 * try to extract a bit of information, and possibly reply. 216 switch (ntohs(attr->attr)) {
217 * At the moment this only processes BIND requests, and returns 217 case STUN_MAPPED_ADDRESS:
218 * the externally visible address of the request. 218 case STUN_XOR_MAPPED_ADDRESS:
219 * If a callback is specified, invoke it with the attribute. 219 case STUN_MS_XOR_MAPPED_ADDRESS:
220 */ 220 break;
221static int stun_handle_packet(unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg) 221 default:
222{ 222 LOG (GNUNET_ERROR_TYPE_INFO,
223 struct stun_header *hdr = (struct stun_header *)data; 223 "Ignoring STUN Attribute %s (%04x), length %d\n",
224 struct stun_attr *attr; 224 stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
225 struct stun_state st; 225
226 int ret = STUN_IGNORE; 226 }
227 int x; 227 return 0;
228 228}
229 /* On entry, 'len' is the length of the udp payload. After the 229
230 * initial checks it becomes the size of unprocessed options, 230
231 * while 'data' is advanced accordingly. 231/* helper function to generate a random request id */
232 */ 232static void
233 if (len < sizeof(struct stun_header)) { 233generate_request_id(struct stun_header *req)
234 fprintf(stderr, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header)); 234{
235 return -1; 235 int x;
236 } 236 req->magic = htonl(STUN_MAGIC_COOKIE);
237 len -= sizeof(struct stun_header); 237 for (x = 0; x < 3; x++)
238 data += sizeof(struct stun_header); 238 req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
239 x = ntohs(hdr->msglen); /* len as advertised in the message */ 239 UINT32_MAX);
240 if (stun_debug) 240}
241 fprintf(stderr, "STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x); 241
242 if (x > len) { 242
243 fprintf(stderr, "Scrambled STUN packet length (got %d, expecting %d)\n", x, (int)len); 243/* handle an incoming STUN message.
244 } else 244 *
245 len = x; 245 * Do some basic sanity checks on packet size and content,
246 memset(&st,0, sizeof(st)); 246 * try to extract a bit of information, and possibly reply.
247 247 * At the moment this only processes BIND requests, and returns
248 while (len) { 248 * the externally visible address of the request.
249 if (len < sizeof(struct stun_attr)) { 249 * If a callback is specified, invoke it with the attribute.
250 fprintf(stderr, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr)); 250 */
251 break; 251static int
252 } 252stun_handle_packet(const uint8_t *data, size_t len, stun_cb_f *stun_cb, void *arg)
253 attr = (struct stun_attr *)data; 253{
254 254 struct stun_header *hdr = (struct stun_header *)data;
255 /* compute total attribute length */ 255 struct stun_attr *attr;
256 x = ntohs(attr->len) + sizeof(struct stun_attr); 256 struct StunState st;
257 if (x > len) { 257 int ret = STUN_IGNORE;
258 fprintf(stderr, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", x, (int)len); 258
259 break; 259 uint32_t advertised_message_size;
260 } 260 uint32_t message_magic_cookie;
261 if (stun_cb) 261
262 stun_cb(&st, attr, arg, hdr->magic); 262
263 if (stun_process_attr(&st, attr)) { 263 /* On entry, 'len' is the length of the udp payload. After the
264 fprintf(stderr, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr)); 264 * initial checks it becomes the size of unprocessed options,
265 break; 265 * while 'data' is advanced accordingly.
266 } 266 */
267 /* Clear attribute id: in case previous entry was a string, 267 if (len < sizeof(struct stun_header)) {
268 * this will act as the terminator for the string. 268 LOG (GNUNET_ERROR_TYPE_INFO,
269 */ 269 "STUN packet too short (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
270 attr->attr = 0; 270 GNUNET_break_op (0);
271 data += x; 271 return -1;
272 len -= x; 272 }
273 } 273 /* Skip header as it is already in hdr */
274 /* Null terminate any string. 274 len -= sizeof(struct stun_header);
275 * XXX NOTE, we write past the size of the buffer passed by the 275 data += sizeof(struct stun_header);
276 * caller, so this is potentially dangerous. The only thing that 276
277 * saves us is that usually we read the incoming message in a 277 /* len as advertised in the message */
278 * much larger buffer 278 advertised_message_size = ntohs(hdr->msglen);
279 */ 279
280 *data = '\0'; 280 message_magic_cookie = ntohl(hdr->magic);
281 281 /* Compare if the cookie match */
282 return ret; 282 if(STUN_MAGIC_COOKIE != message_magic_cookie){
283} 283 LOG (GNUNET_ERROR_TYPE_INFO,
284 284 "Invalid magic cookie \n");
285/* Extract the STUN_MAPPED_ADDRESS from the stun response. 285 GNUNET_break_op (0);
286 * This is used as a callback for stun_handle_response 286 return -1;
287 * when called from stun_request. 287 }
288 */ 288
289static int stun_get_mapped(struct stun_state *st, struct stun_attr *attr, void *arg, unsigned int magic) 289
290{ 290 LOG (GNUNET_ERROR_TYPE_INFO, "STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), advertised_message_size);
291 struct stun_addr *returned_addr = (struct stun_addr *)(attr + 1); 291
292 struct sockaddr_in *sa = (struct sockaddr_in *)arg; 292
293 unsigned short type = ntohs(attr->attr); 293 if (advertised_message_size > len) {
294 294 LOG (GNUNET_ERROR_TYPE_INFO, "Scrambled STUN packet length (got %d, expecting %d)\n", advertised_message_size, (int)len);
295 switch (type) { 295 GNUNET_break_op (0);
296 case STUN_MAPPED_ADDRESS: 296 } else {
297 if (st->attr == STUN_XOR_MAPPED_ADDRESS || 297 len = advertised_message_size;
298 st->attr == STUN_MS_XOR_MAPPED_ADDRESS) 298 }
299 return 1; 299 /* Zero the struct */
300 magic = 0; 300 memset(&st,0, sizeof(st));
301 break; 301
302 case STUN_MS_XOR_MAPPED_ADDRESS: 302 while (len > 0) {
303 if (st->attr == STUN_XOR_MAPPED_ADDRESS) 303 if (len < sizeof(struct stun_attr)) {
304 return 1; 304 LOG (GNUNET_ERROR_TYPE_INFO, "Attribute too short (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
305 break; 305 GNUNET_break_op (0);
306 case STUN_XOR_MAPPED_ADDRESS: 306 break;
307 break; 307 }
308 default: 308 attr = (struct stun_attr *)data;
309 return 1; 309
310 } 310 /* compute total attribute length */
311 if (ntohs(attr->len) < 8 && returned_addr->family != 1) 311 advertised_message_size = ntohs(attr->len) + sizeof(struct stun_attr);
312 return 1; 312
313 313 /* Check if we still have space in our buffer */
314 st->attr = type; 314 if (advertised_message_size > len ) {
315 sa->sin_port = returned_addr->port ^ htons(ntohl(magic) >> 16); 315 LOG (GNUNET_ERROR_TYPE_INFO, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", advertised_message_size, (int)len);
316 sa->sin_addr.s_addr = returned_addr->addr ^ magic; 316 GNUNET_break_op (0);
317 return 0; 317 break;
318} 318 }
319 319
320/* Generic STUN request 320 if (stun_cb){
321 * Send a generic stun request to the server specified, 321 stun_cb(&st, attr, arg, hdr->magic);
322 * possibly waiting for a reply and filling the 'reply' field with 322 }
323 * the externally visible address. 323
324 324 if (stun_process_attr(&st, attr)) {
325 * \param s the socket used to send the request 325 LOG (GNUNET_ERROR_TYPE_INFO, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
326 * \return 0 on success, other values on error. 326 break;
327 */ 327 }
328int stun_request(struct GNUNET_NETWORK_Handle * sock) 328 /* Clear attribute id: in case previous entry was a string,
329{ 329 * this will act as the terminator for the string.
330 struct stun_header *req; 330 */
331 unsigned char reqdata[1024]; 331 attr->attr = 0;
332 int reqlen, reqleft; 332 data += advertised_message_size;
333 struct stun_attr *attr; 333 len -= advertised_message_size;
334 334 }
335 335
336 336 return ret;
337 337}
338 struct sockaddr_in server; 338
339 struct hostent *hostinfo = gethostbyname(stun_server); 339/* Extract the STUN_MAPPED_ADDRESS from the stun response.
340 if (!hostinfo) { 340 * This is used as a callback for stun_handle_response
341 fprintf(stderr, "Error resolving host %s\n", stun_server); 341 * when called from stun_request.
342 return -1; 342 */
343 } 343static int
344 memset(&server,0, sizeof(server)); 344stun_get_mapped(struct StunState *st, struct stun_attr *attr, void *arg, unsigned int magic)
345 server.sin_family = AF_INET; 345{
346 server.sin_addr = *(struct in_addr*) hostinfo->h_addr; 346 struct stun_addr *returned_addr = (struct stun_addr *)(attr + 1);
347 server.sin_port = htons(stun_port); 347 struct sockaddr_in *sa = (struct sockaddr_in *)arg;
348 348 unsigned short type = ntohs(attr->attr);
349 349
350 350 switch (type) {
351 req = (struct stun_header *)reqdata; 351 case STUN_MAPPED_ADDRESS:
352 stun_req_id(req); 352 if (st->attr == STUN_XOR_MAPPED_ADDRESS ||
353 reqlen = 0; 353 st->attr == STUN_MS_XOR_MAPPED_ADDRESS)
354 reqleft = sizeof(reqdata) - sizeof(struct stun_header); 354 return 1;
355 req->msgtype = 0; 355 magic = 0;
356 req->msglen = 0; 356 break;
357 attr = (struct stun_attr *)req->ies; 357 case STUN_MS_XOR_MAPPED_ADDRESS:
358 358 if (st->attr == STUN_XOR_MAPPED_ADDRESS)
359 append_attr_string(&attr, STUN_SOFTWARE, PACKAGE " v" VERSION_PACKAGE, &reqlen, &reqleft); 359 return 1;
360 req->msglen = htons(reqlen); 360 break;
361 req->msgtype = htons(stun_msg2type(STUN_REQUEST, STUN_BINDING)); 361 case STUN_XOR_MAPPED_ADDRESS:
362 362 break;
363 363 default:
364 if (-1 == GNUNET_NETWORK_socket_sendto (sock, req, ntohs(req->msglen) + sizeof(*req), 364 return 1;
365 (const struct sockaddr *) &server, sizeof (server))) 365 }
366 { 366 if (ntohs(attr->len) < 8 && returned_addr->family != 1) {
367 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto"); 367 return 1;
368 } 368 }
369 369
370 return -1; 370 st->attr = type;
371} 371 sa->sin_port = returned_addr->port ^ htons(ntohl(magic) >> 16);
372 372 sa->sin_addr.s_addr = returned_addr->addr ^ magic;
373static void print_answer(struct sockaddr_in* answer) 373 return 0;
374{ 374}
375 printf("External IP is: %s , with port %d\n", inet_ntoa(answer->sin_addr), ntohs(answer->sin_port)); 375
376} 376
377 377/**
378 378 * Try to establish a connection given the specified address.
379/** 379 * This function is called by the resolver once we have a DNS reply.
380 * Activity on our incoming socket. Read data from the 380 *
381 * incoming connection. 381 * @param cls our `struct GNUNET_CONNECTION_Handle *`
382 * 382 * @param addr address to try, NULL for "last call"
383 * @param cls 383 * @param addrlen length of @a addr
384 * @param tc scheduler context 384 */
385 */ 385static void
386static void 386try_connect_using_address (void *cls,
387do_udp_read (void *cls, 387 const struct sockaddr *addr,
388 const struct GNUNET_SCHEDULER_TaskContext *tc) 388 socklen_t addrlen) {
389{ 389
390 //struct GNUNET_NAT_Test *tst = cls; 390
391 unsigned char reply_buf[1024]; 391 struct GNUNET_NAT_StunRequestHandle *request = cls;
392 ssize_t rlen; 392
393 struct sockaddr_in answer; 393 struct stun_header *req;
394 394 uint8_t reqdata[1024];
395 395 int reqlen;
396 if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) && 396
397 (GNUNET_NETWORK_fdset_isset (tc->read_ready, 397 if(NULL == request) {
398 lsock4))) 398 LOG (GNUNET_ERROR_TYPE_INFO, "Empty request\n");
399 { 399 return;
400 rlen = GNUNET_NETWORK_socket_recv (lsock4, reply_buf, sizeof (reply_buf)); 400 }
401 printf("Recivied something of size %d", rlen); 401
402 402
403 //Lets handle the packet 403 if (NULL == addr) {
404 memset(&answer, 0, sizeof(struct sockaddr_in)); 404 request->dns_active = NULL;
405 stun_handle_packet(reply_buf, rlen, stun_get_mapped, &answer); 405 LOG (GNUNET_ERROR_TYPE_INFO, "Error resolving host %s\n", stun_server);
406 //Print the anser 406 //BREAk op
407 //TODO: Delete the object 407 return;
408 ret = 0; 408 }
409 print_answer(&answer); 409
410 410
411 411
412 } 412 struct sockaddr_in server;
413} 413
414 414
415 415 memset(&server,0, sizeof(server));
416/** 416 server.sin_family = AF_INET;
417 * Create an IPv4 listen socket bound to our port. 417
418 * 418 struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
419 * @return NULL on error 419
420 */ 420 server.sin_addr = addr_in->sin_addr;
421static struct GNUNET_NETWORK_Handle * 421 server.sin_port = htons(stun_port);
422 bind_v4 () 422
423{ 423
424 struct GNUNET_NETWORK_Handle *ls; 424 /*Craft the simplest possible STUN packet. A request binding*/
425 struct sockaddr_in sa4; 425 req = (struct stun_header *)reqdata;
426 int eno; 426 generate_request_id(req);
427 427 reqlen = 0;
428 memset (&sa4, 0, sizeof (sa4)); 428 req->msgtype = 0;
429 sa4.sin_family = AF_INET; 429 req->msglen = 0;
430 sa4.sin_port = htons (port); 430
431#if HAVE_SOCKADDR_IN_SIN_LEN 431
432 sa4.sin_len = sizeof (sa4); 432 req->msglen = htons(reqlen);
433#endif 433 req->msgtype = htons(encode_message(STUN_REQUEST, STUN_BINDING));
434 ls = GNUNET_NETWORK_socket_create (AF_INET, 434
435 SOCK_DGRAM, 435
436 0); 436 if (-1 == GNUNET_NETWORK_socket_sendto (request->sock, req, ntohs(req->msglen) + sizeof(*req),
437 if (NULL == ls) 437 (const struct sockaddr *) &server, sizeof (server)))
438 return NULL; 438 {
439 if (GNUNET_OK != 439 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "Failt to sendto");
440 GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa4, 440 }
441 sizeof (sa4))) 441
442 { 442}
443 eno = errno; 443
444 GNUNET_NETWORK_socket_close (ls); 444
445 errno = eno; 445/* Generic STUN request
446 return NULL; 446 * Send a generic stun request to the server specified,
447 } 447 * possibly waiting for a reply and filling the 'reply' field with
448 return ls; 448 * the externally visible address.
449} 449
450 450 * \param s the socket used to send the request
451 451 * \return 0 on success, other values on error.
452 452 */
453/** 453struct GNUNET_NAT_StunRequestHandle *
454 * Main function run with scheduler. 454stun_request(struct GNUNET_NETWORK_Handle * sock)
455 */ 455{
456 456
457 457
458static void 458 struct GNUNET_NAT_StunRequestHandle *rh;
459run (void *cls, char *const *args, const char *cfgfile, 459
460 const struct GNUNET_CONFIGURATION_Handle *cfg) 460
461{ 461 rh = GNUNET_malloc (sizeof (struct GNUNET_NAT_StunRequestHandle));
462 462
463 463 rh->sock = sock;
464 //Lets create the socket 464
465 lsock4 = bind_v4 (); 465 rh->dns_active = GNUNET_RESOLVER_ip_get (stun_server, AF_INET,
466 if (NULL == lsock4) 466 GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
467 { 467 &try_connect_using_address, rh);
468 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind"); 468
469 } 469
470 else 470
471 { 471
472 printf("Binded, now will call add_read\n"); 472 return rh;
473 //Lets call our function now when it accepts 473}
474 ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 474
475 lsock4, &do_udp_read, NULL); 475static void
476 476print_answer(struct sockaddr_in* answer)
477 } 477{
478 if(NULL == lsock4 ) 478 printf("External IP is: %s , with port %d\n", inet_ntoa(answer->sin_addr), ntohs(answer->sin_port));
479 { 479}
480 GNUNET_SCHEDULER_shutdown (); 480
481 return; 481
482 } 482/**
483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 483 * Activity on our incoming socket. Read data from the
484 "Service listens on port %u\n", 484 * incoming connection.
485 port); 485 *
486 printf("Start main event\n"); 486 * @param cls
487 stun_request(lsock4); 487 * @param tc scheduler context
488 //Main event 488 */
489 //main_task = GNUNET_SCHEDULER_add_delayed (timeout, &do_timeout, nh); 489static void
490 490do_udp_read (void *cls,
491} 491 const struct GNUNET_SCHEDULER_TaskContext *tc)
492 492{
493 493 //struct GNUNET_NAT_Test *tst = cls;
494int 494 unsigned char reply_buf[1024];
495main (int argc, char *const argv[]) 495 ssize_t rlen;
496{ 496 struct sockaddr_in answer;
497 struct GNUNET_GETOPT_CommandLineOption options[] = { 497
498 GNUNET_GETOPT_OPTION_END 498
499 }; 499 if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
500 500 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
501 char *const argv_prog[] = { 501 lsock4)))
502 "test-stun", 502 {
503 NULL 503 rlen = GNUNET_NETWORK_socket_recv (lsock4, reply_buf, sizeof (reply_buf));
504 }; 504 printf("Recivied something of size %d", rlen);
505 GNUNET_log_setup ("test-stun", 505
506 "WARNING", 506 //Lets handle the packet
507 NULL); 507 memset(&answer, 0, sizeof(struct sockaddr_in));
508 508 stun_handle_packet(reply_buf, rlen, stun_get_mapped, &answer);
509 GNUNET_PROGRAM_run (1, argv_prog, "test-stun", "nohelp", options, &run, NULL); 509 //Print the anser
510 510 //TODO: Delete the object
511 return ret; 511 ret = 0;
512} 512 print_answer(&answer);
513 513
514/* end of test_nat.c */ 514
515 }
516}
517
518
519/**
520 * Create an IPv4 listen socket bound to our port.
521 *
522 * @return NULL on error
523 */
524static struct GNUNET_NETWORK_Handle *
525bind_v4 ()
526{
527 struct GNUNET_NETWORK_Handle *ls;
528 struct sockaddr_in sa4;
529 int eno;
530
531 memset (&sa4, 0, sizeof (sa4));
532 sa4.sin_family = AF_INET;
533 sa4.sin_port = htons (port);
534#if HAVE_SOCKADDR_IN_SIN_LEN
535 sa4.sin_len = sizeof (sa4);
536#endif
537 ls = GNUNET_NETWORK_socket_create (AF_INET,
538 SOCK_DGRAM,
539 0);
540 if (NULL == ls)
541 return NULL;
542 if (GNUNET_OK !=
543 GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa4,
544 sizeof (sa4)))
545 {
546 eno = errno;
547 GNUNET_NETWORK_socket_close (ls);
548 errno = eno;
549 return NULL;
550 }
551 return ls;
552}
553
554
555
556/**
557 * Main function run with scheduler.
558 */
559
560
561static void
562run (void *cls, char *const *args, const char *cfgfile,
563 const struct GNUNET_CONFIGURATION_Handle *cfg)
564{
565
566
567 //Lets create the socket
568 lsock4 = bind_v4 ();
569 if (NULL == lsock4)
570 {
571 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
572 }
573 else
574 {
575 printf("Binded, now will call add_read\n");
576 //Lets call our function now when it accepts
577 ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
578 lsock4, &do_udp_read, NULL);
579
580 }
581 if(NULL == lsock4 )
582 {
583 GNUNET_SCHEDULER_shutdown ();
584 return;
585 }
586 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
587 "Service listens on port %u\n",
588 port);
589 printf("Start main event\n");
590 stun_request(lsock4);
591 //Main event
592 //main_task = GNUNET_SCHEDULER_add_delayed (timeout, &do_timeout, nh);
593
594}
595
596
597int
598main (int argc, char *const argv[])
599{
600 struct GNUNET_GETOPT_CommandLineOption options[] = {
601 GNUNET_GETOPT_OPTION_END
602 };
603
604 char *const argv_prog[] = {
605 "test-stun",
606 NULL
607 };
608 GNUNET_log_setup ("test-stun",
609 "WARNING",
610 NULL);
611
612 GNUNET_PROGRAM_run (1, argv_prog, "test-stun", "nohelp", options, &run, NULL);
613
614 return ret;
615}
616
617/* end of test_nat.c */
diff --git a/src/nat/test_stun.h b/src/nat/test_stun.h
index 9beae6f79..170cda7fa 100644
--- a/src/nat/test_stun.h
+++ b/src/nat/test_stun.h
@@ -1,108 +1,112 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2009, 2015 Christian Grothoff (and other contributing authors) 3 Copyright (C) 2009, 2015 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 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 7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version. 8 option) any later version.
9 9
10 GNUnet is distributed in the hope that it will be useful, but 10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of 11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details. 13 General Public License for more details.
14 14
15 You should have received a copy of the GNU General Public License 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 16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. 18 Boston, MA 02111-1307, USA.
19*/ 19*/
20 20
21/** 21/**
22 * Testcase for STUN server resolution 22 * Testcase for STUN server resolution
23 * 23 *
24 * @file nat/test_stun.h 24 * @file nat/test_stun.h
25 * @brief Testcase for STUN library 25 * @brief Testcase for STUN library
26 * @author Bruno Souza Cabral 26 * @author Bruno Souza Cabral
27 * @autor Mark Spencer (Original code borrowed from Asterisk) 27 * @autor Mark Spencer (Original code borrowed from Asterisk)
28 * 28 *
29 */ 29 */
30 30
31#define PACKAGE "gnunet" 31#define STUN_SERVER "stun.ekiga.net"
32#define VERSION_PACKAGE "0.4" 32#define STUN_PORT 3478
33 33#define STUN_IGNORE (0)
34#define STUN_SERVER "stun.services.mozilla.com" 34#define STUN_ACCEPT (1)
35#define STUN_PORT 3478 35
36#define STUN_COUNT 3 36#define STUN_MAGIC_COOKIE 0x2112A442
37#define STUN_RTO 500 /* ms */ 37
38#define STUN_MRC 3 38typedef struct { uint32_t id[3]; } GNUNET_PACKED stun_trans_id;
39 39
40typedef struct { unsigned int id[3]; } __attribute__((packed)) stun_trans_id; 40struct stun_header {
41 41 uint16_t msgtype;
42struct stun_header { 42 uint16_t msglen;
43 unsigned short msgtype; 43 uint32_t magic;
44 unsigned short msglen; 44 stun_trans_id id;
45 unsigned int magic; 45
46 stun_trans_id id; 46} GNUNET_PACKED;
47 unsigned char ies[0]; 47
48} __attribute__((packed)); 48struct stun_attr {
49 49 uint16_t attr;
50struct stun_attr { 50 uint16_t len;
51 unsigned short attr; 51
52 unsigned short len; 52} GNUNET_PACKED;
53 unsigned char value[0]; 53
54} __attribute__((packed)); 54/*
55 55 * The format normally used for addresses carried by STUN messages.
56/* 56 */
57 * The format normally used for addresses carried by STUN messages. 57struct stun_addr {
58 */ 58 uint8_t unused;
59struct stun_addr { 59 uint8_t family;
60 unsigned char unused; 60 uint16_t port;
61 unsigned char family; 61 uint32_t addr;
62 unsigned short port; 62} GNUNET_PACKED;
63 unsigned int addr; 63
64} __attribute__((packed)); 64
65 65
66#define STUN_IGNORE (0) 66/* STUN message classes */
67#define STUN_ACCEPT (1) 67typedef enum StunClasses {
68 68 INVALID_CLASS = 0,
69#define STUN_MAGIC_COOKIE 0x2112A442 69 STUN_REQUEST = 0x0000,
70 70 STUN_INDICATION = 0x0001,
71/* STUN message classes */ 71 STUN_RESPONSE = 0x0002,
72#define STUN_REQUEST 0x0000 72 STUN_ERROR_RESPONSE = 0x0003
73#define STUN_INDICATION 0x0001 73} StunClasses;
74#define STUN_RESPONSE 0x0002 74
75#define STUN_ERROR_RESPONSE 0x0003 75typedef enum StunMethods {
76 76 INVALID_METHOD = 0,
77/* STUN message methods */ 77 STUN_BINDING = 0x0001,
78#define STUN_BINDING 0x0001 78 STUN_SHARED_SECRET = 0x0002,
79#define STUN_SHARED_SECRET 0x0002 79 STUN_ALLOCATE = 0x0003,
80#define STUN_ALLOCATE 0x0003 80 STUN_REFRESH = 0x0004,
81#define STUN_REFRESH 0x0004 81 STUN_SEND = 0x0006,
82#define STUN_SEND 0x0006 82 STUN_DATA = 0x0007,
83#define STUN_DATA 0x0007 83 STUN_CREATE_PERMISSION = 0x0008,
84#define STUN_CREATE_PERMISSION 0x0008 84 STUN_CHANNEL_BIND = 0x0009
85#define STUN_CHANNEL_BIND 0x0009 85} StunMethods;
86 86
87/* Basic attribute types in stun messages. 87/* Basic attribute types in stun messages.
88 * Messages can also contain custom attributes (codes above 0x7fff) 88 * Messages can also contain custom attributes (codes above 0x7fff)
89 */ 89 */
90#define STUN_MAPPED_ADDRESS 0x0001 90
91#define STUN_RESPONSE_ADDRESS 0x0002 91typedef enum StunAttributes {
92#define STUN_CHANGE_ADDRESS 0x0003 92 STUN_MAPPED_ADDRESS = 0x0001,
93#define STUN_SOURCE_ADDRESS 0x0004 93 STUN_RESPONSE_ADDRESS = 0x0002,
94#define STUN_CHANGED_ADDRESS 0x0005 94 STUN_CHANGE_ADDRESS = 0x0003,
95#define STUN_USERNAME 0x0006 95 STUN_SOURCE_ADDRESS = 0x0004,
96#define STUN_PASSWORD 0x0007 96 STUN_CHANGED_ADDRESS = 0x0005,
97#define STUN_MESSAGE_INTEGRITY 0x0008 97 STUN_USERNAME = 0x0006,
98#define STUN_ERROR_CODE 0x0009 98 STUN_PASSWORD = 0x0007,
99#define STUN_UNKNOWN_ATTRIBUTES 0x000a 99 STUN_MESSAGE_INTEGRITY = 0x0008,
100#define STUN_REFLECTED_FROM 0x000b 100 STUN_ERROR_CODE = 0x0009,
101#define STUN_REALM 0x0014 101 STUN_UNKNOWN_ATTRIBUTES = 0x000a,
102#define STUN_NONCE 0x0015 102 STUN_REFLECTED_FROM = 0x000b,
103#define STUN_XOR_MAPPED_ADDRESS 0x0020 103 STUN_REALM = 0x0014,
104#define STUN_MS_VERSION 0x8008 104 STUN_NONCE = 0x0015,
105#define STUN_MS_XOR_MAPPED_ADDRESS 0x8020 105 STUN_XOR_MAPPED_ADDRESS = 0x0020,
106#define STUN_SOFTWARE 0x8022 106 STUN_MS_VERSION = 0x8008,
107#define STUN_ALTERNATE_SERVER 0x8023 107 STUN_MS_XOR_MAPPED_ADDRESS = 0x8020,
108#define STUN_FINGERPRINT 0x8028 108 STUN_SOFTWARE = 0x8022,
109 STUN_ALTERNATE_SERVER = 0x8023,
110 STUN_FINGERPRINT = 0x8028
111} StunAttributes;
112