aboutsummaryrefslogtreecommitdiff
path: root/src/nat
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-10-07 09:51:33 +0000
committerChristian Grothoff <christian@grothoff.org>2015-10-07 09:51:33 +0000
commit117a6b2f87eab48523f3ecd0d72d28ad9903c849 (patch)
treedc47d59f75047a2dfab458f116f4f80fa84ad57c /src/nat
parent886d8cda082a8005c1a73a6d6603b9791121a7ae (diff)
downloadgnunet-117a6b2f87eab48523f3ecd0d72d28ad9903c849.tar.gz
gnunet-117a6b2f87eab48523f3ecd0d72d28ad9903c849.zip
stylistic fixes
Diffstat (limited to 'src/nat')
-rw-r--r--src/nat/nat.c6
-rw-r--r--src/nat/nat_stun.c718
-rw-r--r--src/nat/nat_stun.h103
3 files changed, 398 insertions, 429 deletions
diff --git a/src/nat/nat.c b/src/nat/nat.c
index 709a13f03..3573ec497 100644
--- a/src/nat/nat.c
+++ b/src/nat/nat.c
@@ -1734,7 +1734,9 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
1734 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client"); 1734 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client");
1735 if ((GNUNET_YES == h->enable_nat_client) && 1735 if ((GNUNET_YES == h->enable_nat_client) &&
1736 (GNUNET_YES != 1736 (GNUNET_YES !=
1737 GNUNET_OS_check_helper_binary (binary, GNUNET_YES, "-d 127.0.0.1 127.0.0.2 42"))) // none of these parameters are actually used in privilege testing mode 1737 GNUNET_OS_check_helper_binary (binary,
1738 GNUNET_YES,
1739 "-d 127.0.0.1 127.0.0.2 42"))) /* none of these parameters are actually used in privilege testing mode */
1738 { 1740 {
1739 h->enable_nat_client = GNUNET_NO; 1741 h->enable_nat_client = GNUNET_NO;
1740 LOG (GNUNET_ERROR_TYPE_WARNING, 1742 LOG (GNUNET_ERROR_TYPE_WARNING,
@@ -1814,7 +1816,7 @@ GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h)
1814 GNUNET_SCHEDULER_cancel (h->dns_task); 1816 GNUNET_SCHEDULER_cancel (h->dns_task);
1815 h->dns_task = NULL; 1817 h->dns_task = NULL;
1816 } 1818 }
1817 if (NULL != h->stun_task) 1819 if (NULL != h->stun_task)
1818 { 1820 {
1819 GNUNET_SCHEDULER_cancel (h->stun_task); 1821 GNUNET_SCHEDULER_cancel (h->stun_task);
1820 h->stun_task = NULL; 1822 h->stun_task = NULL;
diff --git a/src/nat/nat_stun.c b/src/nat/nat_stun.c
index 5c819356c..66b4265a8 100644
--- a/src/nat/nat_stun.c
+++ b/src/nat/nat_stun.c
@@ -17,9 +17,7 @@
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 *
23 * This code provides some support for doing STUN transactions. 21 * This code provides some support for doing STUN transactions.
24 * We send simplest possible packet ia REQUEST with BIND to a STUN server. 22 * We send simplest possible packet ia REQUEST with BIND to a STUN server.
25 * 23 *
@@ -32,7 +30,6 @@
32 * 30 *
33 * This code was based on ministun.c. 31 * This code was based on ministun.c.
34 * 32 *
35 *
36 * @file nat/nat_stun.c 33 * @file nat/nat_stun.c
37 * @brief Functions for STUN functionality 34 * @brief Functions for STUN functionality
38 * @author Bruno Souza Cabral 35 * @author Bruno Souza Cabral
@@ -56,51 +53,52 @@
56 * the request prior to the timeout or successful execution. Also 53 * the request prior to the timeout or successful execution. Also
57 * used to track our internal state for the request. 54 * used to track our internal state for the request.
58 */ 55 */
59struct GNUNET_NAT_STUN_Handle { 56struct GNUNET_NAT_STUN_Handle
60 57{
61 /**
62 * Handle to a pending DNS lookup request.
63 */
64 struct GNUNET_RESOLVER_RequestHandle *dns_active;
65
66
67 /**
68 * Handle to the listen socket
69 */
70 struct GNUNET_NETWORK_Handle * sock;
71
72 /**
73 * Stun server address
74 */
75 char *stun_server ;
76
77 /**
78 * STUN port
79 */
80 int stun_port;
81
82 /**
83 * Function to call when a error occours
84 */
85 GNUNET_NAT_STUN_ErrorCallback cb;
86
87 /**
88 * Closure for @e cb.
89 */
90 void *cb_cls;
91
92 /**
93 * Do we got a DNS resolution successfully ?
94 */
95 int dns_success;
96 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;
97 93
98}; 94};
99 95
100 96
101 97/**
102/* here we store credentials extracted from a message */ 98 * here we store credentials extracted from a message
103struct StunState { 99*/
100struct StunState
101{
104 uint16_t attr; 102 uint16_t attr;
105}; 103};
106 104
@@ -114,8 +112,8 @@ struct StunState {
114static int 112static int
115decode_class(int msg) 113decode_class(int msg)
116{ 114{
117 /* Sorry for the magic, but this maps the class according to rfc5245 */ 115 /* Sorry for the magic, but this maps the class according to rfc5245 */
118 return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7); 116 return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7);
119} 117}
120 118
121/** 119/**
@@ -127,9 +125,10 @@ decode_class(int msg)
127static int 125static int
128decode_method(int msg) 126decode_method(int msg)
129{ 127{
130 return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2); 128 return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2);
131} 129}
132 130
131
133/** 132/**
134 * Encode a class and method to a compatible STUN format 133 * Encode a class and method to a compatible STUN format
135 * 134 *
@@ -138,12 +137,14 @@ decode_method(int msg)
138 * @return message in a STUN compatible format 137 * @return message in a STUN compatible format
139 */ 138 */
140static int 139static int
141encode_message(StunClasses msg_class, StunMethods method) 140encode_message (enum StunClasses msg_class,
141 enum StunMethods method)
142{ 142{
143 return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) | 143 return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) |
144 (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2); 144 (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2);
145} 145}
146 146
147
147/** 148/**
148 * Print a class and method from a STUN message 149 * Print a class and method from a STUN message
149 * 150 *
@@ -153,44 +154,46 @@ encode_message(StunClasses msg_class, StunMethods method)
153static const char * 154static const char *
154stun_msg2str(int msg) 155stun_msg2str(int msg)
155{ 156{
156 157 static const struct { enum StunClasses value; const char *name; } classes[] = {
157 const struct { enum StunClasses value; const char *name; } classes[] = { 158 { STUN_REQUEST, "Request" },
158 { STUN_REQUEST, "Request" }, 159 { STUN_INDICATION, "Indication" },
159 { STUN_INDICATION, "Indication" }, 160 { STUN_RESPONSE, "Response" },
160 { STUN_RESPONSE, "Response" }, 161 { STUN_ERROR_RESPONSE, "Error Response" },
161 { STUN_ERROR_RESPONSE, "Error Response" }, 162 { 0, NULL }
162 { 0, NULL } 163 };
163 }; 164 static const struct { enum StunMethods value; const char *name; } methods[] = {
164 165 { STUN_BINDING, "Binding" },
165 const struct { enum StunMethods value; const char *name; } methods[] = { 166 { 0, NULL }
166 { STUN_BINDING, "Binding" }, 167 };
167 { 0, NULL } 168 static char result[32];
168 }; 169 const char *msg_class = NULL;
169 170 const char *method = NULL;
170 static char result[32]; 171 int i;
171 const char *msg_class = NULL; 172 int value;
172 const char *method = NULL; 173
173 int i; 174 value = decode_class(msg);
174 int value; 175 for (i = 0; classes[i].name; i++)
175 176 {
176 value = decode_class(msg); 177 msg_class = classes[i].name;
177 for (i = 0; classes[i].name; i++) { 178 if (classes[i].value == value)
178 msg_class = classes[i].name; 179 break;
179 if (classes[i].value == value) 180 }
180 break; 181 value = decode_method(msg);
181 } 182 for (i = 0; methods[i].name; i++)
182 value = decode_method(msg); 183 {
183 for (i = 0; methods[i].name; i++) { 184 method = methods[i].name;
184 method = methods[i].name; 185 if (methods[i].value == value)
185 if (methods[i].value == value) 186 break;
186 break; 187 }
187 } 188 GNUNET_snprintf (result,
188 GNUNET_snprintf(result, sizeof(result), "%s %s", 189 sizeof(result),
189 method ? : "Unknown Method", 190 "%s %s",
190 msg_class ? : "Unknown Class Message"); 191 method ? : "Unknown Method",
191 return result; 192 msg_class ? : "Unknown Class Message");
193 return result;
192} 194}
193 195
196
194/** 197/**
195 * Print attribute name 198 * Print attribute name
196 * 199 *
@@ -200,69 +203,39 @@ stun_msg2str(int msg)
200static const char * 203static const char *
201stun_attr2str(int msg) 204stun_attr2str(int msg)
202{ 205{
203 const struct { enum StunAttributes value; const char *name; } attrs[] = { 206 const struct { enum StunAttributes value; const char *name; } attrs[] = {
204 { STUN_MAPPED_ADDRESS, "Mapped Address" }, 207 { STUN_MAPPED_ADDRESS, "Mapped Address" },
205 { STUN_RESPONSE_ADDRESS, "Response Address" }, 208 { STUN_RESPONSE_ADDRESS, "Response Address" },
206 { STUN_CHANGE_ADDRESS, "Change Address" }, 209 { STUN_CHANGE_ADDRESS, "Change Address" },
207 { STUN_SOURCE_ADDRESS, "Source Address" }, 210 { STUN_SOURCE_ADDRESS, "Source Address" },
208 { STUN_CHANGED_ADDRESS, "Changed Address" }, 211 { STUN_CHANGED_ADDRESS, "Changed Address" },
209 { STUN_USERNAME, "Username" }, 212 { STUN_USERNAME, "Username" },
210 { STUN_PASSWORD, "Password" }, 213 { STUN_PASSWORD, "Password" },
211 { STUN_MESSAGE_INTEGRITY, "Message Integrity" }, 214 { STUN_MESSAGE_INTEGRITY, "Message Integrity" },
212 { STUN_ERROR_CODE, "Error Code" }, 215 { STUN_ERROR_CODE, "Error Code" },
213 { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" }, 216 { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" },
214 { STUN_REFLECTED_FROM, "Reflected From" }, 217 { STUN_REFLECTED_FROM, "Reflected From" },
215 { STUN_REALM, "Realm" }, 218 { STUN_REALM, "Realm" },
216 { STUN_NONCE, "Nonce" }, 219 { STUN_NONCE, "Nonce" },
217 { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" }, 220 { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" },
218 { STUN_MS_VERSION, "MS Version" }, 221 { STUN_MS_VERSION, "MS Version" },
219 { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" }, 222 { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" },
220 { STUN_SOFTWARE, "Software" }, 223 { STUN_SOFTWARE, "Software" },
221 { STUN_ALTERNATE_SERVER, "Alternate Server" }, 224 { STUN_ALTERNATE_SERVER, "Alternate Server" },
222 { STUN_FINGERPRINT, "Fingerprint" }, 225 { STUN_FINGERPRINT, "Fingerprint" },
223 { 0, NULL } 226 { 0, NULL }
224 }; 227 };
225 int i; 228 unsigned int i;
226 229
227 for (i = 0; attrs[i].name; i++) { 230 for (i = 0; attrs[i].name; i++)
228 if (attrs[i].value == msg) 231 {
229 return attrs[i].name; 232 if (attrs[i].value == msg)
230 } 233 return attrs[i].name;
231 return "Unknown Attribute"; 234 }
232} 235 return "Unknown Attribute";
233
234
235/**
236 * Fill the stun_header with a random request_id
237 *
238 * @param state, STUN attribute type
239 * @param attr , the actual attribute
240 *
241 * @param req, stun header to be filled
242 */
243static int
244stun_process_attr(struct StunState *state, struct stun_attr *attr)
245{
246 LOG (GNUNET_ERROR_TYPE_INFO,
247 "Found STUN Attribute %s (%04x), length %d\n",
248 stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
249
250 switch (ntohs(attr->attr)) {
251 case STUN_MAPPED_ADDRESS:
252 case STUN_XOR_MAPPED_ADDRESS:
253 case STUN_MS_XOR_MAPPED_ADDRESS:
254 break;
255 default:
256 LOG (GNUNET_ERROR_TYPE_INFO,
257 "Ignoring STUN Attribute %s (%04x), length %d\n",
258 stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
259
260 }
261 return 0;
262} 236}
263 237
264 238
265
266/** 239/**
267 * Fill the stun_header with a random request_id 240 * Fill the stun_header with a random request_id
268 * 241 *
@@ -271,11 +244,12 @@ stun_process_attr(struct StunState *state, struct stun_attr *attr)
271static void 244static void
272generate_request_id(struct stun_header *req) 245generate_request_id(struct stun_header *req)
273{ 246{
274 unsigned int x; 247 unsigned int x;
275 req->magic = htonl(STUN_MAGIC_COOKIE); 248
276 for (x = 0; x < 3; x++) 249 req->magic = htonl(STUN_MAGIC_COOKIE);
277 req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 250 for (x = 0; x < 3; x++)
278 UINT32_MAX); 251 req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
252 UINT32_MAX);
279} 253}
280 254
281 255
@@ -292,38 +266,41 @@ generate_request_id(struct stun_header *req)
292 * @return 0 on success, other value otherwise 266 * @return 0 on success, other value otherwise
293 */ 267 */
294static int 268static int
295stun_get_mapped(struct StunState *st, struct stun_attr *attr,struct sockaddr_in *arg, unsigned int magic) 269stun_get_mapped (struct StunState *st,
270 struct stun_attr *attr,
271 struct sockaddr_in *arg,
272 unsigned int magic)
296{ 273{
297 struct stun_addr *returned_addr = (struct stun_addr *)(attr + 1); 274 struct stun_addr *returned_addr = (struct stun_addr *)(attr + 1);
298 struct sockaddr_in *sa = (struct sockaddr_in *)arg; 275 struct sockaddr_in *sa = (struct sockaddr_in *)arg;
299 unsigned short type = ntohs(attr->attr); 276 unsigned short type = ntohs(attr->attr);
300
301 switch (type) {
302 case STUN_MAPPED_ADDRESS:
303 if (st->attr == STUN_XOR_MAPPED_ADDRESS ||
304 st->attr == STUN_MS_XOR_MAPPED_ADDRESS)
305 return 1;
306 magic = 0;
307 break;
308 case STUN_MS_XOR_MAPPED_ADDRESS:
309 if (st->attr == STUN_XOR_MAPPED_ADDRESS)
310 return 1;
311 break;
312 case STUN_XOR_MAPPED_ADDRESS:
313 break;
314 default:
315 return 1;
316 }
317 if (ntohs(attr->len) < 8 && returned_addr->family != 1) {
318 return 1;
319 }
320 277
321 st->attr = type; 278 switch (type)
322 279 {
323 sa->sin_family = AF_INET; 280 case STUN_MAPPED_ADDRESS:
324 sa->sin_port = returned_addr->port ^ htons(ntohl(magic) >> 16); 281 if (st->attr == STUN_XOR_MAPPED_ADDRESS ||
325 sa->sin_addr.s_addr = returned_addr->addr ^ magic; 282 st->attr == STUN_MS_XOR_MAPPED_ADDRESS)
326 return 0; 283 return 1;
284 magic = 0;
285 break;
286 case STUN_MS_XOR_MAPPED_ADDRESS:
287 if (st->attr == STUN_XOR_MAPPED_ADDRESS)
288 return 1;
289 break;
290 case STUN_XOR_MAPPED_ADDRESS:
291 break;
292 default:
293 return 1;
294 }
295 if (ntohs(attr->len) < 8 && returned_addr->family != 1)
296 {
297 return 1;
298 }
299 st->attr = type;
300 sa->sin_family = AF_INET;
301 sa->sin_port = returned_addr->port ^ htons(ntohl(magic) >> 16);
302 sa->sin_addr.s_addr = returned_addr->addr ^ magic;
303 return 0;
327} 304}
328 305
329 306
@@ -334,123 +311,122 @@ stun_get_mapped(struct StunState *st, struct stun_attr *attr,struct sockaddr_in
334 * the externally visible address of the request. 311 * the externally visible address of the request.
335 * If a callback is specified, invoke it with the attribute. 312 * If a callback is specified, invoke it with the attribute.
336 * 313 *
337 * @param data, the packet 314 * @param data the packet
338 * @param len, the length of the packet 315 * @param len the length of the packet
339 * @param arg, sockaddr_in where we will set our discovered packet 316 * @param arg sockaddr_in where we will set our discovered packet
340 * 317 *
341 * @return, #GNUNET_OK on OK, #GNUNET_NO if the packet is invalid ( not a stun packet) 318 * @return, #GNUNET_OK on OK, #GNUNET_NO if the packet is invalid (not a stun packet)
342 */ 319 */
343int 320int
344GNUNET_NAT_stun_handle_packet(const void *data, size_t len, struct sockaddr_in *arg) 321GNUNET_NAT_stun_handle_packet (const void *data,
322 size_t len,
323 struct sockaddr_in *arg)
345{ 324{
346 const struct stun_header *hdr = (const struct stun_header *)data; 325 const struct stun_header *hdr = (const struct stun_header *)data;
347 struct stun_attr *attr; 326 struct stun_attr *attr;
348 struct StunState st; 327 struct StunState st;
349 int ret = GNUNET_OK; 328 int ret = GNUNET_OK;
350 329 uint32_t advertised_message_size;
351 uint32_t advertised_message_size; 330 uint32_t message_magic_cookie;
352 uint32_t message_magic_cookie; 331
353 332 /* On entry, 'len' is the length of the udp payload. After the
354 333 * initial checks it becomes the size of unprocessed options,
355 /* On entry, 'len' is the length of the udp payload. After the 334 * while 'data' is advanced accordingly.
356 * initial checks it becomes the size of unprocessed options, 335 */
357 * while 'data' is advanced accordingly. 336 if (len < sizeof(struct stun_header))
358 */ 337 {
359 if (len < sizeof(struct stun_header)) { 338 LOG (GNUNET_ERROR_TYPE_INFO,
360 LOG (GNUNET_ERROR_TYPE_INFO, 339 "STUN packet too short (only %d, wanting at least %d)\n",
361 "STUN packet too short (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header)); 340 (int) len,
362 GNUNET_break_op (0); 341 (int) sizeof(struct stun_header));
363 return GNUNET_NO; 342 GNUNET_break_op (0);
364 } 343 return GNUNET_NO;
365 /* Skip header as it is already in hdr */ 344 }
366 len -= sizeof(struct stun_header); 345 /* Skip header as it is already in hdr */
367 data += sizeof(struct stun_header); 346 len -= sizeof(struct stun_header);
368 347 data += sizeof(struct stun_header);
369 /* len as advertised in the message */
370 advertised_message_size = ntohs(hdr->msglen);
371
372 message_magic_cookie = ntohl(hdr->magic);
373 /* Compare if the cookie match */
374 if(STUN_MAGIC_COOKIE != message_magic_cookie){
375 LOG (GNUNET_ERROR_TYPE_INFO,
376 "Invalid magic cookie \n");
377 return GNUNET_NO;
378 }
379 348
349 /* len as advertised in the message */
350 advertised_message_size = ntohs(hdr->msglen);
380 351
381 LOG (GNUNET_ERROR_TYPE_INFO, "STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), 352 message_magic_cookie = ntohl(hdr->magic);
382 ntohs(hdr->msgtype), 353 /* Compare if the cookie match */
383 advertised_message_size); 354 if(STUN_MAGIC_COOKIE != message_magic_cookie)
355 {
356 LOG (GNUNET_ERROR_TYPE_INFO,
357 "Invalid magic cookie \n");
358 return GNUNET_NO;
359 }
384 360
361 LOG (GNUNET_ERROR_TYPE_INFO,
362 "STUN Packet, msg %s (%04x), length: %d\n",
363 stun_msg2str(ntohs(hdr->msgtype)),
364 ntohs(hdr->msgtype),
365 advertised_message_size);
366 if (advertised_message_size > len)
367 {
368 LOG (GNUNET_ERROR_TYPE_INFO,
369 "Scrambled STUN packet length (got %d, expecting %d)\n",
370 advertised_message_size,
371 (int)len);
372 return GNUNET_NO;
373 }
374 else
375 {
376 len = advertised_message_size;
377 }
378 memset (&st,0, sizeof(st));
385 379
386 if (advertised_message_size > len) { 380 while (len > 0)
387 LOG (GNUNET_ERROR_TYPE_INFO, "Scrambled STUN packet length (got %d, expecting %d)\n", advertised_message_size, 381 {
388 (int)len); 382 if (len < sizeof(struct stun_attr))
389 return GNUNET_NO; 383 {
390 } else { 384 LOG (GNUNET_ERROR_TYPE_INFO,
391 len = advertised_message_size; 385 "Attribute too short (got %d, expecting %d)\n",
386 (int)len,
387 (int) sizeof(struct stun_attr));
388 break;
392 } 389 }
390 attr = (struct stun_attr *)data;
393 391
394 memset(&st,0, sizeof(st)); 392 /* compute total attribute length */
395 393 advertised_message_size = ntohs(attr->len) + sizeof(struct stun_attr);
396 while (len > 0) {
397 if (len < sizeof(struct stun_attr)) {
398 LOG (GNUNET_ERROR_TYPE_INFO, "Attribute too short (got %d, expecting %d)\n", (int)len,
399 (int) sizeof(struct stun_attr));
400 break;
401 }
402 attr = (struct stun_attr *)data;
403
404 /* compute total attribute length */
405 advertised_message_size = ntohs(attr->len) + sizeof(struct stun_attr);
406
407 /* Check if we still have space in our buffer */
408 if (advertised_message_size > len ) {
409 LOG (GNUNET_ERROR_TYPE_INFO, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", advertised_message_size,
410 (int)len);
411 break;
412 }
413
414
415 stun_get_mapped(&st, attr, arg, hdr->magic);
416
417 if (stun_process_attr(&st, attr)) {
418 LOG (GNUNET_ERROR_TYPE_INFO, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)),
419 ntohs(attr->attr));
420 break;
421 }
422 /** Clear attribute id: in case previous entry was a string,
423 * this will act as the terminator for the string.
424 **/
425 attr->attr = 0;
426 data += advertised_message_size;
427 len -= advertised_message_size;
428 ret = GNUNET_OK;
429 }
430 394
431 return ret; 395 /* Check if we still have space in our buffer */
396 if (advertised_message_size > len )
397 {
398 LOG (GNUNET_ERROR_TYPE_INFO,
399 "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n",
400 advertised_message_size,
401 (int)len);
402 break;
403 }
404 stun_get_mapped (&st, attr, arg, hdr->magic);
405 /* Clear attribute id: in case previous entry was a string,
406 * this will act as the terminator for the string.
407 */
408 attr->attr = 0;
409 data += advertised_message_size;
410 len -= advertised_message_size;
411 ret = GNUNET_OK;
412 }
413 return ret;
432} 414}
433 415
434 416
435
436/** 417/**
437 * Clean-up used memory 418 * Clean-up used memory
438 * 419 *
439 * @param cls our `struct GNUNET_NAT_STUN_Handle *` 420 * @param handle handle to release memory for
440 */ 421 */
441static void 422static void
442clean(struct GNUNET_NAT_STUN_Handle * handle) 423clean (struct GNUNET_NAT_STUN_Handle *handle)
443{ 424{
444 if(handle->stun_server) 425 GNUNET_free (handle->stun_server);
445 { 426 GNUNET_free (handle);
446 GNUNET_free(handle->stun_server);
447 }
448 GNUNET_free(handle);
449
450} 427}
451 428
452 429
453
454/** 430/**
455 * Try to establish a connection given the specified address. 431 * Try to establish a connection given the specified address.
456 * 432 *
@@ -461,120 +437,112 @@ clean(struct GNUNET_NAT_STUN_Handle * handle)
461static void 437static void
462stun_dns_callback (void *cls, 438stun_dns_callback (void *cls,
463 const struct sockaddr *addr, 439 const struct sockaddr *addr,
464 socklen_t addrlen) { 440 socklen_t addrlen)
465 441{
466 442 struct GNUNET_NAT_STUN_Handle *request = cls;
467 struct GNUNET_NAT_STUN_Handle *request = cls; 443 struct stun_header *req;
468 444 uint8_t reqdata[1024];
469 struct stun_header *req; 445 int reqlen;
470 uint8_t reqdata[1024]; 446 struct sockaddr_in server;
471 int reqlen;
472 struct sockaddr_in server;
473
474
475 if(NULL == request) {
476
477 if( GNUNET_NO == request->dns_success){
478 LOG (GNUNET_ERROR_TYPE_INFO, "Empty request\n");
479 request->cb(request->cb_cls, GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR);
480 clean(request);
481
482 }
483 return;
484 }
485
486 if (NULL == addr) {
487 request->dns_active = NULL;
488
489 if( GNUNET_NO == request->dns_success){
490 LOG (GNUNET_ERROR_TYPE_INFO, "Error resolving host %s\n", request->stun_server);
491 request->cb(request->cb_cls, GNUNET_NAT_ERROR_NOT_ONLINE);
492 clean(request);
493
494 }
495 447
496 return; 448 if (NULL == request)
449 {
450 if (GNUNET_NO == request->dns_success)
451 {
452 LOG (GNUNET_ERROR_TYPE_INFO,
453 "Empty request\n");
454 request->cb (request->cb_cls,
455 GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR);
456 clean (request);
497 } 457 }
498 458 return;
499 459 }
500 request->dns_success= GNUNET_YES; 460 if (NULL == addr)
501 memset(&server,0, sizeof(server)); 461 {
502 server.sin_family = AF_INET; 462 request->dns_active = NULL;
503 server.sin_addr = ((struct sockaddr_in *)addr)->sin_addr; 463 if (GNUNET_NO == request->dns_success)
504 server.sin_port = htons(request->stun_port);
505
506
507 /*Craft the simplest possible STUN packet. A request binding*/
508 req = (struct stun_header *)reqdata;
509 generate_request_id(req);
510 reqlen = 0;
511 req->msgtype = 0;
512 req->msglen = 0;
513 req->msglen = htons(reqlen);
514 req->msgtype = htons(encode_message(STUN_REQUEST, STUN_BINDING));
515
516 /* Send the packet */
517 if (-1 == GNUNET_NETWORK_socket_sendto (request->sock, req, ntohs(req->msglen) + sizeof(*req),
518 (const struct sockaddr *) &server, sizeof (server)))
519 { 464 {
520 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "Fail to sendto"); 465 LOG (GNUNET_ERROR_TYPE_INFO,
521 request->cb(request->cb_cls, GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR); 466 "Error resolving host %s\n",
522 clean(request); 467 request->stun_server);
523 return; 468 request->cb (request->cb_cls,
469 GNUNET_NAT_ERROR_NOT_ONLINE);
470 clean (request);
524 } 471 }
472 return;
473 }
525 474
526 475 request->dns_success= GNUNET_YES;
476 memset(&server,0, sizeof(server));
477 server.sin_family = AF_INET;
478 server.sin_addr = ((struct sockaddr_in *)addr)->sin_addr;
479 server.sin_port = htons(request->stun_port);
480
481 /*Craft the simplest possible STUN packet. A request binding*/
482 req = (struct stun_header *)reqdata;
483 generate_request_id(req);
484 reqlen = 0;
485 req->msgtype = 0;
486 req->msglen = 0;
487 req->msglen = htons(reqlen);
488 req->msgtype = htons(encode_message(STUN_REQUEST, STUN_BINDING));
489
490 /* Send the packet */
491 if (-1 == GNUNET_NETWORK_socket_sendto (request->sock,
492 req,
493 ntohs(req->msglen) + sizeof(*req),
494 (const struct sockaddr *) &server,
495 sizeof (server)))
496 {
497 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
498 "Fail to sendto");
499 request->cb (request->cb_cls,
500 GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR);
501 clean (request);
502 return;
503 }
527} 504}
528 505
529 506
530
531
532
533/** 507/**
534 * Make Generic STUN request and 508 * Make Generic STUN request. Sends a generic stun request to the
535 * Send a generic stun request to the server specified using the specified socket. 509 * server specified using the specified socket, possibly waiting for
536 * possibly waiting for a reply and filling the 'reply' field with 510 * a reply and filling the 'reply' field with the externally visible
537 * the externally visible address. 511 * address.
538 * 512 *
539 * @param server, the address of the stun server 513 * @param server the address of the stun server
540 * @param port, port of the stun server 514 * @param port port of the stun server
541 * @param sock the socket used to send the request 515 * @param sock the socket used to send the request
542 * @param cb, callback in case of error 516 * @param cb callback in case of error
517 * @param cb_cls closure for @a cb
543 * @return #GNUNET_OK success, #GNUNET_NO on error. 518 * @return #GNUNET_OK success, #GNUNET_NO on error.
544 */ 519 */
545int 520int
546GNUNET_NAT_stun_make_request(char * server, 521GNUNET_NAT_stun_make_request (const char *server,
547 int port, 522 uint16_t port,
548 struct GNUNET_NETWORK_Handle * sock, 523 struct GNUNET_NETWORK_Handle *sock,
549 GNUNET_NAT_STUN_ErrorCallback cb, 524 GNUNET_NAT_STUN_ErrorCallback cb,
550 void *cb_cls) 525 void *cb_cls)
551{ 526{
552 527 struct GNUNET_NAT_STUN_Handle *rh;
553 struct GNUNET_NAT_STUN_Handle *rh; 528
554 529 rh = GNUNET_new (struct GNUNET_NAT_STUN_Handle);
555 rh = GNUNET_malloc (sizeof (struct GNUNET_NAT_STUN_Handle)); 530 rh->sock = sock;
556 rh->sock = sock; 531 rh->cb = cb;
557 532 rh->cb_cls = cb_cls;
558 char * server_copy = GNUNET_strdup (server); 533 rh->stun_server = GNUNET_strdup (server);
559 534 rh->stun_port = port;
560 rh->cb = cb; 535 rh->dns_success = GNUNET_NO;
561 rh->cb_cls = cb_cls; 536 rh->dns_active = GNUNET_RESOLVER_ip_get (rh->stun_server,
562 rh->stun_server = server_copy; 537 AF_INET,
563 rh->stun_port = port; 538 TIMEOUT,
564 rh->dns_success = GNUNET_NO; 539 &stun_dns_callback, rh);
565 540 if (NULL == rh->dns_active)
566 rh->dns_active = GNUNET_RESOLVER_ip_get (server_copy, AF_INET, 541 {
567 TIMEOUT, 542 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
568 &stun_dns_callback, rh); 543 "Failed DNS");
569 544 clean (rh);
570 if (rh->dns_active == NULL) 545 return GNUNET_NO;
571 { 546 }
572 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "Failed DNS"); 547 return GNUNET_OK;
573 GNUNET_free(rh);
574 GNUNET_free(server_copy);
575
576 return GNUNET_NO;
577 }
578
579 return GNUNET_OK;
580} 548}
diff --git a/src/nat/nat_stun.h b/src/nat/nat_stun.h
index 1dbb2a6ac..d79fd9ad2 100644
--- a/src/nat/nat_stun.h
+++ b/src/nat/nat_stun.h
@@ -36,76 +36,75 @@
36 36
37typedef struct { uint32_t id[3]; } GNUNET_PACKED stun_trans_id; 37typedef struct { uint32_t id[3]; } GNUNET_PACKED stun_trans_id;
38 38
39struct stun_header { 39struct stun_header
40 uint16_t msgtype; 40{
41 uint16_t msglen; 41 uint16_t msgtype;
42 uint32_t magic; 42 uint16_t msglen;
43 stun_trans_id id; 43 uint32_t magic;
44 44 stun_trans_id id;
45} GNUNET_PACKED; 45} GNUNET_PACKED;
46 46
47struct stun_attr { 47struct stun_attr
48 uint16_t attr; 48{
49 uint16_t len; 49 uint16_t attr;
50 50 uint16_t len;
51} GNUNET_PACKED; 51} GNUNET_PACKED;
52 52
53/* 53/*
54 * The format normally used for addresses carried by STUN messages. 54 * The format normally used for addresses carried by STUN messages.
55 */ 55 */
56struct stun_addr { 56struct stun_addr
57 uint8_t unused; 57{
58 uint8_t family; 58 uint8_t unused;
59 uint16_t port; 59 uint8_t family;
60 uint32_t addr; 60 uint16_t port;
61 uint32_t addr;
61} GNUNET_PACKED; 62} GNUNET_PACKED;
62 63
63 64
64 65
65/* STUN message classes */ 66/* STUN message classes */
66typedef enum StunClasses { 67enum StunClasses {
67 INVALID_CLASS = 0, 68 INVALID_CLASS = 0,
68 STUN_REQUEST = 0x0000, 69 STUN_REQUEST = 0x0000,
69 STUN_INDICATION = 0x0001, 70 STUN_INDICATION = 0x0001,
70 STUN_RESPONSE = 0x0002, 71 STUN_RESPONSE = 0x0002,
71 STUN_ERROR_RESPONSE = 0x0003 72 STUN_ERROR_RESPONSE = 0x0003
72} StunClasses; 73};
73 74
74typedef enum StunMethods { 75enum StunMethods {
75 INVALID_METHOD = 0, 76 INVALID_METHOD = 0,
76 STUN_BINDING = 0x0001, 77 STUN_BINDING = 0x0001,
77 STUN_SHARED_SECRET = 0x0002, 78 STUN_SHARED_SECRET = 0x0002,
78 STUN_ALLOCATE = 0x0003, 79 STUN_ALLOCATE = 0x0003,
79 STUN_REFRESH = 0x0004, 80 STUN_REFRESH = 0x0004,
80 STUN_SEND = 0x0006, 81 STUN_SEND = 0x0006,
81 STUN_DATA = 0x0007, 82 STUN_DATA = 0x0007,
82 STUN_CREATE_PERMISSION = 0x0008, 83 STUN_CREATE_PERMISSION = 0x0008,
83 STUN_CHANNEL_BIND = 0x0009 84 STUN_CHANNEL_BIND = 0x0009
84} StunMethods; 85};
85 86
86/* Basic attribute types in stun messages. 87/* Basic attribute types in stun messages.
87 * Messages can also contain custom attributes (codes above 0x7fff) 88 * Messages can also contain custom attributes (codes above 0x7fff)
88 */ 89 */
89 90enum StunAttributes {
90typedef enum StunAttributes { 91 STUN_MAPPED_ADDRESS = 0x0001,
91 STUN_MAPPED_ADDRESS = 0x0001, 92 STUN_RESPONSE_ADDRESS = 0x0002,
92 STUN_RESPONSE_ADDRESS = 0x0002, 93 STUN_CHANGE_ADDRESS = 0x0003,
93 STUN_CHANGE_ADDRESS = 0x0003, 94 STUN_SOURCE_ADDRESS = 0x0004,
94 STUN_SOURCE_ADDRESS = 0x0004, 95 STUN_CHANGED_ADDRESS = 0x0005,
95 STUN_CHANGED_ADDRESS = 0x0005, 96 STUN_USERNAME = 0x0006,
96 STUN_USERNAME = 0x0006, 97 STUN_PASSWORD = 0x0007,
97 STUN_PASSWORD = 0x0007, 98 STUN_MESSAGE_INTEGRITY = 0x0008,
98 STUN_MESSAGE_INTEGRITY = 0x0008, 99 STUN_ERROR_CODE = 0x0009,
99 STUN_ERROR_CODE = 0x0009, 100 STUN_UNKNOWN_ATTRIBUTES = 0x000a,
100 STUN_UNKNOWN_ATTRIBUTES = 0x000a, 101 STUN_REFLECTED_FROM = 0x000b,
101 STUN_REFLECTED_FROM = 0x000b, 102 STUN_REALM = 0x0014,
102 STUN_REALM = 0x0014, 103 STUN_NONCE = 0x0015,
103 STUN_NONCE = 0x0015, 104 STUN_XOR_MAPPED_ADDRESS = 0x0020,
104 STUN_XOR_MAPPED_ADDRESS = 0x0020, 105 STUN_MS_VERSION = 0x8008,
105 STUN_MS_VERSION = 0x8008, 106 STUN_MS_XOR_MAPPED_ADDRESS = 0x8020,
106 STUN_MS_XOR_MAPPED_ADDRESS = 0x8020, 107 STUN_SOFTWARE = 0x8022,
107 STUN_SOFTWARE = 0x8022, 108 STUN_ALTERNATE_SERVER = 0x8023,
108 STUN_ALTERNATE_SERVER = 0x8023, 109 STUN_FINGERPRINT = 0x8028
109 STUN_FINGERPRINT = 0x8028 110};
110} StunAttributes;
111