diff options
author | Bruno Cabral <bcabral@uw.edu> | 2015-06-25 02:21:23 +0000 |
---|---|---|
committer | Bruno Cabral <bcabral@uw.edu> | 2015-06-25 02:21:23 +0000 |
commit | 26ad92551ed4afd96f3d7742179509b850a5cc7a (patch) | |
tree | ddcf6699873afc2431df036193b1e598c15e142c /src | |
parent | 20d8a41eaa19064d16e9a004dea2d9abcdbd9731 (diff) | |
download | gnunet-26ad92551ed4afd96f3d7742179509b850a5cc7a.tar.gz gnunet-26ad92551ed4afd96f3d7742179509b850a5cc7a.zip |
Polish and simplyfy STUN code, move STUN code to GNUNET_NAT_
Diffstat (limited to 'src')
-rw-r--r-- | src/include/gnunet_nat_lib.h | 35 | ||||
-rw-r--r-- | src/nat/nat_stun.c | 464 | ||||
-rw-r--r-- | src/nat/nat_stun.h (renamed from src/nat/test_stun.h) | 223 | ||||
-rw-r--r-- | src/nat/test_stun.c | 825 |
4 files changed, 817 insertions, 730 deletions
diff --git a/src/include/gnunet_nat_lib.h b/src/include/gnunet_nat_lib.h index 123d106e9..79031f9a9 100644 --- a/src/include/gnunet_nat_lib.h +++ b/src/include/gnunet_nat_lib.h | |||
@@ -455,6 +455,41 @@ GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
455 | void | 455 | void |
456 | GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah); | 456 | GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah); |
457 | 457 | ||
458 | |||
459 | struct GNUNET_NAT_StunRequestHandle; | ||
460 | |||
461 | /** | ||
462 | * Make Generic STUN request and | ||
463 | * Send a generic stun request to the server specified using the specified socket. | ||
464 | * possibly waiting for a reply and filling the 'reply' field with | ||
465 | * the externally visible address. | ||
466 | *c | ||
467 | * @param server, the address of the stun server | ||
468 | * @param port, port of the stun server | ||
469 | * @param sock the socket used to send the request | ||
470 | * @return GNUNET_NAT_StunRequestHandle on success, NULL on error. | ||
471 | */ | ||
472 | struct GNUNET_NAT_StunRequestHandle * | ||
473 | GNUNET_NAT_stun_make_request(char * server, int port, struct GNUNET_NETWORK_Handle * sock); | ||
474 | |||
475 | |||
476 | /** | ||
477 | * Handle an incoming STUN message, Do some basic sanity checks on packet size and content, | ||
478 | * try to extract a bit of information, and possibly reply. | ||
479 | * At the moment this only processes BIND requests, and returns | ||
480 | * the externally visible address of the request. | ||
481 | * If a callback is specified, invoke it with the attribute. | ||
482 | * | ||
483 | * @param data, pointer where we will set the type | ||
484 | * @param len, pointer where we will set the type | ||
485 | * @param st, pointer where we will set the type | ||
486 | * | ||
487 | * @return, 0 on IGNORE, -1 if the packet is invalid ( not a stun packet) | ||
488 | */ | ||
489 | int | ||
490 | GNUNET_NAT_stun_handle_packet(const uint8_t *data, size_t len,struct sockaddr_in *arg); | ||
491 | |||
492 | |||
458 | #endif | 493 | #endif |
459 | 494 | ||
460 | /* end of gnunet_nat_lib.h */ | 495 | /* end of gnunet_nat_lib.h */ |
diff --git a/src/nat/nat_stun.c b/src/nat/nat_stun.c index 06ed9261f..490a11257 100644 --- a/src/nat/nat_stun.c +++ b/src/nat/nat_stun.c | |||
@@ -34,6 +34,468 @@ | |||
34 | * | 34 | * |
35 | * | 35 | * |
36 | * @file nat/nat_stun.c | 36 | * @file nat/nat_stun.c |
37 | * @brief Testcase for STUN library | 37 | * @brief Functions for STUN functionality |
38 | * @author Bruno Souza Cabral | 38 | * @author Bruno Souza Cabral |
39 | */ | 39 | */ |
40 | |||
41 | #include "platform.h" | ||
42 | #include "gnunet_util_lib.h" | ||
43 | #include "gnunet_program_lib.h" | ||
44 | #include "gnunet_scheduler_lib.h" | ||
45 | #include "gnunet_nat_lib.h" | ||
46 | |||
47 | |||
48 | #include "nat_stun.h" | ||
49 | |||
50 | #define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__) | ||
51 | |||
52 | |||
53 | |||
54 | /** | ||
55 | * Handle to a request given to the resolver. Can be used to cancel | ||
56 | * the request prior to the timeout or successful execution. Also | ||
57 | * used to track our internal state for the request. | ||
58 | */ | ||
59 | struct GNUNET_NAT_StunRequestHandle { | ||
60 | |||
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 | |||
84 | |||
85 | |||
86 | /* here we store credentials extracted from a message */ | ||
87 | struct StunState { | ||
88 | uint16_t attr; | ||
89 | }; | ||
90 | |||
91 | |||
92 | /** | ||
93 | * Convert a message to a StunClass | ||
94 | * | ||
95 | * @param msg the received message | ||
96 | * @return the converted StunClass | ||
97 | */ | ||
98 | static int decode_class(int msg) | ||
99 | { | ||
100 | return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7); | ||
101 | } | ||
102 | |||
103 | /** | ||
104 | * Convert a message to a StunMethod | ||
105 | * | ||
106 | * @param msg the received message | ||
107 | * @return the converted StunMethod | ||
108 | */ | ||
109 | static int decode_method(int msg) | ||
110 | { | ||
111 | return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * Encode a class and method to a compatible STUN format | ||
116 | * | ||
117 | * @param msg_class class to be converted | ||
118 | * @param method method to be converted | ||
119 | * @return message in a STUN compatible format | ||
120 | */ | ||
121 | static int encode_message(StunClasses msg_class, StunMethods method) | ||
122 | { | ||
123 | return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) | | ||
124 | (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2); | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * Print a class and method from a STUN message | ||
129 | * | ||
130 | * @param msg | ||
131 | * @return string with the message class and method | ||
132 | */ | ||
133 | static const char *stun_msg2str(int msg) | ||
134 | { | ||
135 | |||
136 | const struct { enum StunClasses value; const char *name; } classes[] = { | ||
137 | { STUN_REQUEST, "Request" }, | ||
138 | { STUN_INDICATION, "Indication" }, | ||
139 | { STUN_RESPONSE, "Response" }, | ||
140 | { STUN_ERROR_RESPONSE, "Error Response" }, | ||
141 | { 0, NULL } | ||
142 | }; | ||
143 | |||
144 | const struct { enum StunMethods value; const char *name; } methods[] = { | ||
145 | { STUN_BINDING, "Binding" }, | ||
146 | { 0, NULL } | ||
147 | }; | ||
148 | |||
149 | static char result[32]; | ||
150 | const char *msg_class = NULL; | ||
151 | const char *method = NULL; | ||
152 | int i; | ||
153 | int value; | ||
154 | |||
155 | value = decode_class(msg); | ||
156 | for (i = 0; classes[i].name; i++) { | ||
157 | msg_class = classes[i].name; | ||
158 | if (classes[i].value == value) | ||
159 | break; | ||
160 | } | ||
161 | value = decode_method(msg); | ||
162 | for (i = 0; methods[i].name; i++) { | ||
163 | method = methods[i].name; | ||
164 | if (methods[i].value == value) | ||
165 | break; | ||
166 | } | ||
167 | snprintf(result, sizeof(result), "%s %s", | ||
168 | method ? : "Unknown Method", | ||
169 | msg_class ? : "Unknown Class Message"); | ||
170 | return result; | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * Print attribute name | ||
175 | * | ||
176 | * @param msg with a attribute type | ||
177 | * @return string with the attribute name | ||
178 | */ | ||
179 | static const char *stun_attr2str(int msg) | ||
180 | { | ||
181 | const struct { enum StunAttributes value; const char *name; } attrs[] = { | ||
182 | { STUN_MAPPED_ADDRESS, "Mapped Address" }, | ||
183 | { STUN_RESPONSE_ADDRESS, "Response Address" }, | ||
184 | { STUN_CHANGE_ADDRESS, "Change Address" }, | ||
185 | { STUN_SOURCE_ADDRESS, "Source Address" }, | ||
186 | { STUN_CHANGED_ADDRESS, "Changed Address" }, | ||
187 | { STUN_USERNAME, "Username" }, | ||
188 | { STUN_PASSWORD, "Password" }, | ||
189 | { STUN_MESSAGE_INTEGRITY, "Message Integrity" }, | ||
190 | { STUN_ERROR_CODE, "Error Code" }, | ||
191 | { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" }, | ||
192 | { STUN_REFLECTED_FROM, "Reflected From" }, | ||
193 | { STUN_REALM, "Realm" }, | ||
194 | { STUN_NONCE, "Nonce" }, | ||
195 | { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" }, | ||
196 | { STUN_MS_VERSION, "MS Version" }, | ||
197 | { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" }, | ||
198 | { STUN_SOFTWARE, "Software" }, | ||
199 | { STUN_ALTERNATE_SERVER, "Alternate Server" }, | ||
200 | { STUN_FINGERPRINT, "Fingerprint" }, | ||
201 | { 0, NULL } | ||
202 | }; | ||
203 | int i; | ||
204 | |||
205 | for (i = 0; attrs[i].name; i++) { | ||
206 | if (attrs[i].value == msg) | ||
207 | return attrs[i].name; | ||
208 | } | ||
209 | return "Unknown Attribute"; | ||
210 | } | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Fill the stun_header with a random request_id | ||
215 | * | ||
216 | * @param state, STUN attribute type | ||
217 | * @param attr , the actual attribute | ||
218 | * | ||
219 | * @param req, stun header to be filled | ||
220 | */ | ||
221 | static int stun_process_attr(struct StunState *state, struct stun_attr *attr) | ||
222 | { | ||
223 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
224 | "Found STUN Attribute %s (%04x), length %d\n", | ||
225 | stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); | ||
226 | |||
227 | switch (ntohs(attr->attr)) { | ||
228 | case STUN_MAPPED_ADDRESS: | ||
229 | case STUN_XOR_MAPPED_ADDRESS: | ||
230 | case STUN_MS_XOR_MAPPED_ADDRESS: | ||
231 | break; | ||
232 | default: | ||
233 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
234 | "Ignoring STUN Attribute %s (%04x), length %d\n", | ||
235 | stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); | ||
236 | |||
237 | } | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | |||
242 | |||
243 | /** | ||
244 | * Fill the stun_header with a random request_id | ||
245 | * | ||
246 | * @param req, stun header to be filled | ||
247 | */ | ||
248 | static void | ||
249 | generate_request_id(struct stun_header *req) | ||
250 | { | ||
251 | int x; | ||
252 | req->magic = htonl(STUN_MAGIC_COOKIE); | ||
253 | for (x = 0; x < 3; x++) | ||
254 | req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, | ||
255 | UINT32_MAX); | ||
256 | } | ||
257 | |||
258 | |||
259 | /** | ||
260 | * Extract the STUN_MAPPED_ADDRESS from the stun response. | ||
261 | * This is used as a callback for stun_handle_response | ||
262 | * when called from stun_request. | ||
263 | * | ||
264 | * @param st, pointer where we will set the type | ||
265 | * @param attr , received stun attribute | ||
266 | * @param arg , pointer to a sockaddr_in where we will set the reported IP and port | ||
267 | * @param magic , Magic cookie | ||
268 | * | ||
269 | * @return 0 on sucess, other value otherwise | ||
270 | */ | ||
271 | static int | ||
272 | stun_get_mapped(struct StunState *st, struct stun_attr *attr,struct sockaddr_in *arg, unsigned int magic) | ||
273 | { | ||
274 | struct stun_addr *returned_addr = (struct stun_addr *)(attr + 1); | ||
275 | struct sockaddr_in *sa = (struct sockaddr_in *)arg; | ||
276 | unsigned short type = ntohs(attr->attr); | ||
277 | |||
278 | switch (type) { | ||
279 | case STUN_MAPPED_ADDRESS: | ||
280 | if (st->attr == STUN_XOR_MAPPED_ADDRESS || | ||
281 | st->attr == STUN_MS_XOR_MAPPED_ADDRESS) | ||
282 | return 1; | ||
283 | magic = 0; | ||
284 | break; | ||
285 | case STUN_MS_XOR_MAPPED_ADDRESS: | ||
286 | if (st->attr == STUN_XOR_MAPPED_ADDRESS) | ||
287 | return 1; | ||
288 | break; | ||
289 | case STUN_XOR_MAPPED_ADDRESS: | ||
290 | break; | ||
291 | default: | ||
292 | return 1; | ||
293 | } | ||
294 | if (ntohs(attr->len) < 8 && returned_addr->family != 1) { | ||
295 | return 1; | ||
296 | } | ||
297 | |||
298 | st->attr = type; | ||
299 | sa->sin_port = returned_addr->port ^ htons(ntohl(magic) >> 16); | ||
300 | sa->sin_addr.s_addr = returned_addr->addr ^ magic; | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | |||
305 | /** | ||
306 | * Handle an incoming STUN message, Do some basic sanity checks on packet size and content, | ||
307 | * try to extract a bit of information, and possibly reply. | ||
308 | * At the moment this only processes BIND requests, and returns | ||
309 | * the externally visible address of the request. | ||
310 | * If a callback is specified, invoke it with the attribute. | ||
311 | * | ||
312 | * @param data, the packet | ||
313 | * @param len, the length of the packet | ||
314 | * @param arg, sockaddr_in where we will set our discovered packet | ||
315 | * | ||
316 | * @return, 0 on OK, -1 if the packet is invalid ( not a stun packet) | ||
317 | */ | ||
318 | int | ||
319 | GNUNET_NAT_stun_handle_packet(const uint8_t *data, size_t len,struct sockaddr_in *arg) | ||
320 | { | ||
321 | struct stun_header *hdr = (struct stun_header *)data; | ||
322 | struct stun_attr *attr; | ||
323 | struct StunState st; | ||
324 | int ret = STUN_IGNORE; | ||
325 | |||
326 | uint32_t advertised_message_size; | ||
327 | uint32_t message_magic_cookie; | ||
328 | |||
329 | |||
330 | /* On entry, 'len' is the length of the udp payload. After the | ||
331 | * initial checks it becomes the size of unprocessed options, | ||
332 | * while 'data' is advanced accordingly. | ||
333 | */ | ||
334 | if (len < sizeof(struct stun_header)) { | ||
335 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
336 | "STUN packet too short (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header)); | ||
337 | GNUNET_break_op (0); | ||
338 | return -1; | ||
339 | } | ||
340 | /* Skip header as it is already in hdr */ | ||
341 | len -= sizeof(struct stun_header); | ||
342 | data += sizeof(struct stun_header); | ||
343 | |||
344 | /* len as advertised in the message */ | ||
345 | advertised_message_size = ntohs(hdr->msglen); | ||
346 | |||
347 | message_magic_cookie = ntohl(hdr->magic); | ||
348 | /* Compare if the cookie match */ | ||
349 | if(STUN_MAGIC_COOKIE != message_magic_cookie){ | ||
350 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
351 | "Invalid magic cookie \n"); | ||
352 | GNUNET_break_op (0); | ||
353 | return -1; | ||
354 | } | ||
355 | |||
356 | |||
357 | LOG (GNUNET_ERROR_TYPE_INFO, "STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), advertised_message_size); | ||
358 | |||
359 | |||
360 | if (advertised_message_size > len) { | ||
361 | LOG (GNUNET_ERROR_TYPE_INFO, "Scrambled STUN packet length (got %d, expecting %d)\n", advertised_message_size, (int)len); | ||
362 | GNUNET_break_op (0); | ||
363 | return -1; | ||
364 | } else { | ||
365 | len = advertised_message_size; | ||
366 | } | ||
367 | /* Zero the struct */ | ||
368 | memset(&st,0, sizeof(st)); | ||
369 | |||
370 | while (len > 0) { | ||
371 | if (len < sizeof(struct stun_attr)) { | ||
372 | LOG (GNUNET_ERROR_TYPE_INFO, "Attribute too short (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr)); | ||
373 | GNUNET_break_op (0); | ||
374 | break; | ||
375 | } | ||
376 | attr = (struct stun_attr *)data; | ||
377 | |||
378 | /* compute total attribute length */ | ||
379 | advertised_message_size = ntohs(attr->len) + sizeof(struct stun_attr); | ||
380 | |||
381 | /* Check if we still have space in our buffer */ | ||
382 | if (advertised_message_size > len ) { | ||
383 | LOG (GNUNET_ERROR_TYPE_INFO, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", advertised_message_size, (int)len); | ||
384 | GNUNET_break_op (0); | ||
385 | break; | ||
386 | } | ||
387 | |||
388 | |||
389 | stun_get_mapped(&st, attr, arg, hdr->magic); | ||
390 | |||
391 | if (stun_process_attr(&st, attr)) { | ||
392 | LOG (GNUNET_ERROR_TYPE_INFO, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr)); | ||
393 | break; | ||
394 | } | ||
395 | /* Clear attribute id: in case previous entry was a string, | ||
396 | * this will act as the terminator for the string. | ||
397 | */ | ||
398 | attr->attr = 0; | ||
399 | data += advertised_message_size; | ||
400 | len -= advertised_message_size; | ||
401 | } | ||
402 | |||
403 | return ret; | ||
404 | } | ||
405 | |||
406 | |||
407 | |||
408 | /** | ||
409 | * Try to establish a connection given the specified address. | ||
410 | * | ||
411 | * @param cls our `struct GNUNET_NAT_StunRequestHandle *` | ||
412 | * @param addr address to try, NULL for "last call" | ||
413 | * @param addrlen length of @a addr | ||
414 | */ | ||
415 | static void | ||
416 | stun_dns_callback (void *cls, | ||
417 | const struct sockaddr *addr, | ||
418 | socklen_t addrlen) { | ||
419 | |||
420 | |||
421 | struct GNUNET_NAT_StunRequestHandle *request = cls; | ||
422 | |||
423 | struct stun_header *req; | ||
424 | uint8_t reqdata[1024]; | ||
425 | int reqlen; | ||
426 | struct sockaddr_in server; | ||
427 | |||
428 | if(NULL == request) { | ||
429 | LOG (GNUNET_ERROR_TYPE_INFO, "Empty request\n"); | ||
430 | return; | ||
431 | } | ||
432 | |||
433 | if (NULL == addr) { | ||
434 | request->dns_active = NULL; | ||
435 | LOG (GNUNET_ERROR_TYPE_INFO, "Error resolving host %s\n", request->stun_server); | ||
436 | return; | ||
437 | } | ||
438 | |||
439 | |||
440 | memset(&server,0, sizeof(server)); | ||
441 | server.sin_family = AF_INET; | ||
442 | server.sin_addr = ((struct sockaddr_in *)addr)->sin_addr; | ||
443 | server.sin_port = htons(request->stun_port); | ||
444 | |||
445 | |||
446 | /*Craft the simplest possible STUN packet. A request binding*/ | ||
447 | req = (struct stun_header *)reqdata; | ||
448 | generate_request_id(req); | ||
449 | reqlen = 0; | ||
450 | req->msgtype = 0; | ||
451 | req->msglen = 0; | ||
452 | req->msglen = htons(reqlen); | ||
453 | req->msgtype = htons(encode_message(STUN_REQUEST, STUN_BINDING)); | ||
454 | |||
455 | /* Send the packet */ | ||
456 | if (-1 == GNUNET_NETWORK_socket_sendto (request->sock, req, ntohs(req->msglen) + sizeof(*req), | ||
457 | (const struct sockaddr *) &server, sizeof (server))) | ||
458 | { | ||
459 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "Fail to sendto"); | ||
460 | } | ||
461 | |||
462 | } | ||
463 | |||
464 | |||
465 | /** | ||
466 | * Make Generic STUN request and | ||
467 | * Send a generic stun request to the server specified using the specified socket. | ||
468 | * possibly waiting for a reply and filling the 'reply' field with | ||
469 | * the externally visible address. | ||
470 | *c | ||
471 | * @param server, the address of the stun server | ||
472 | * @param port, port of the stun server | ||
473 | * @param sock the socket used to send the request | ||
474 | * @return GNUNET_NAT_StunRequestHandle on success, NULL on error. | ||
475 | */ | ||
476 | struct GNUNET_NAT_StunRequestHandle * | ||
477 | GNUNET_NAT_stun_make_request(char * server, int port, struct GNUNET_NETWORK_Handle * sock) | ||
478 | { | ||
479 | |||
480 | struct GNUNET_NAT_StunRequestHandle *rh; | ||
481 | |||
482 | rh = GNUNET_malloc (sizeof (struct GNUNET_NAT_StunRequestHandle)); | ||
483 | rh->sock = sock; | ||
484 | |||
485 | char * server_copy = GNUNET_malloc (1 + strlen (server)); | ||
486 | if (server_copy) { | ||
487 | strcpy (server_copy, server); | ||
488 | }else{ | ||
489 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "Failed to allocate string"); | ||
490 | return NULL; | ||
491 | } | ||
492 | |||
493 | rh->stun_server = server_copy; | ||
494 | rh->stun_port = port; | ||
495 | rh->dns_active = GNUNET_RESOLVER_ip_get (rh->stun_server, AF_INET, | ||
496 | GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, | ||
497 | &stun_dns_callback, rh); | ||
498 | |||
499 | |||
500 | return rh; | ||
501 | } \ No newline at end of file | ||
diff --git a/src/nat/test_stun.h b/src/nat/nat_stun.h index 170cda7fa..a3982bfc9 100644 --- a/src/nat/test_stun.h +++ b/src/nat/nat_stun.h | |||
@@ -1,112 +1,111 @@ | |||
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 STUN_SERVER "stun.ekiga.net" | 31 | |
32 | #define STUN_PORT 3478 | 32 | #define STUN_IGNORE (0) |
33 | #define STUN_IGNORE (0) | 33 | #define STUN_ACCEPT (1) |
34 | #define STUN_ACCEPT (1) | 34 | |
35 | 35 | #define STUN_MAGIC_COOKIE 0x2112A442 | |
36 | #define STUN_MAGIC_COOKIE 0x2112A442 | 36 | |
37 | 37 | typedef struct { uint32_t id[3]; } GNUNET_PACKED stun_trans_id; | |
38 | typedef struct { uint32_t id[3]; } GNUNET_PACKED stun_trans_id; | 38 | |
39 | 39 | struct stun_header { | |
40 | struct stun_header { | 40 | uint16_t msgtype; |
41 | uint16_t msgtype; | 41 | uint16_t msglen; |
42 | uint16_t msglen; | 42 | uint32_t magic; |
43 | uint32_t magic; | 43 | stun_trans_id id; |
44 | stun_trans_id id; | 44 | |
45 | 45 | } GNUNET_PACKED; | |
46 | } GNUNET_PACKED; | 46 | |
47 | 47 | struct stun_attr { | |
48 | struct stun_attr { | 48 | uint16_t attr; |
49 | uint16_t attr; | 49 | uint16_t len; |
50 | uint16_t len; | 50 | |
51 | 51 | } GNUNET_PACKED; | |
52 | } GNUNET_PACKED; | 52 | |
53 | 53 | /* | |
54 | /* | 54 | * The format normally used for addresses carried by STUN messages. |
55 | * The format normally used for addresses carried by STUN messages. | 55 | */ |
56 | */ | 56 | struct stun_addr { |
57 | struct stun_addr { | 57 | uint8_t unused; |
58 | uint8_t unused; | 58 | uint8_t family; |
59 | uint8_t family; | 59 | uint16_t port; |
60 | uint16_t port; | 60 | uint32_t addr; |
61 | uint32_t addr; | 61 | } GNUNET_PACKED; |
62 | } GNUNET_PACKED; | 62 | |
63 | 63 | ||
64 | 64 | ||
65 | 65 | /* STUN message classes */ | |
66 | /* STUN message classes */ | 66 | typedef enum StunClasses { |
67 | typedef enum 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 | } StunClasses; | 73 | |
74 | 74 | typedef enum StunMethods { | |
75 | typedef enum 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 | } StunMethods; | 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 | |
90 | 90 | typedef enum StunAttributes { | |
91 | typedef enum StunAttributes { | 91 | STUN_MAPPED_ADDRESS = 0x0001, |
92 | STUN_MAPPED_ADDRESS = 0x0001, | 92 | STUN_RESPONSE_ADDRESS = 0x0002, |
93 | STUN_RESPONSE_ADDRESS = 0x0002, | 93 | STUN_CHANGE_ADDRESS = 0x0003, |
94 | STUN_CHANGE_ADDRESS = 0x0003, | 94 | STUN_SOURCE_ADDRESS = 0x0004, |
95 | STUN_SOURCE_ADDRESS = 0x0004, | 95 | STUN_CHANGED_ADDRESS = 0x0005, |
96 | STUN_CHANGED_ADDRESS = 0x0005, | 96 | STUN_USERNAME = 0x0006, |
97 | STUN_USERNAME = 0x0006, | 97 | STUN_PASSWORD = 0x0007, |
98 | STUN_PASSWORD = 0x0007, | 98 | STUN_MESSAGE_INTEGRITY = 0x0008, |
99 | STUN_MESSAGE_INTEGRITY = 0x0008, | 99 | STUN_ERROR_CODE = 0x0009, |
100 | STUN_ERROR_CODE = 0x0009, | 100 | STUN_UNKNOWN_ATTRIBUTES = 0x000a, |
101 | STUN_UNKNOWN_ATTRIBUTES = 0x000a, | 101 | STUN_REFLECTED_FROM = 0x000b, |
102 | STUN_REFLECTED_FROM = 0x000b, | 102 | STUN_REALM = 0x0014, |
103 | STUN_REALM = 0x0014, | 103 | STUN_NONCE = 0x0015, |
104 | STUN_NONCE = 0x0015, | 104 | STUN_XOR_MAPPED_ADDRESS = 0x0020, |
105 | STUN_XOR_MAPPED_ADDRESS = 0x0020, | 105 | STUN_MS_VERSION = 0x8008, |
106 | STUN_MS_VERSION = 0x8008, | 106 | STUN_MS_XOR_MAPPED_ADDRESS = 0x8020, |
107 | STUN_MS_XOR_MAPPED_ADDRESS = 0x8020, | 107 | STUN_SOFTWARE = 0x8022, |
108 | STUN_SOFTWARE = 0x8022, | 108 | STUN_ALTERNATE_SERVER = 0x8023, |
109 | STUN_ALTERNATE_SERVER = 0x8023, | 109 | STUN_FINGERPRINT = 0x8028 |
110 | STUN_FINGERPRINT = 0x8028 | 110 | } StunAttributes; |
111 | } StunAttributes; | 111 | |
112 | |||
diff --git a/src/nat/test_stun.c b/src/nat/test_stun.c index 086789f27..c45714f4d 100644 --- a/src/nat/test_stun.c +++ b/src/nat/test_stun.c | |||
@@ -1,617 +1,208 @@ | |||
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 - Major rewrite. | 26 | * @author Bruno Souza Cabral - Major rewrite. |
27 | * @autor Mark Spencer (Original code - borrowed from Asterisk) | 27 | |
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 | |
40 | 40 | #define LOG(kind,...) GNUNET_log_from (kind, "test-stun", __VA_ARGS__) | |
41 | #define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__) | 41 | |
42 | 42 | /** | |
43 | /** | 43 | * The port the test service is running on (default 7895) |
44 | * The port the test service is running on (default 7895) | 44 | */ |
45 | */ | 45 | static unsigned long port = 7895; |
46 | static unsigned long port = 7895; | 46 | static int ret = 1; |
47 | static int ret = 1; | 47 | |
48 | 48 | static char *stun_server = "stun.ekiga.net"; | |
49 | static char *stun_server = STUN_SERVER; | 49 | static int stun_port = 3478; |
50 | static int stun_port = STUN_PORT; | 50 | |
51 | 51 | /** | |
52 | /** | 52 | * The listen socket of the service for IPv4 |
53 | * The listen socket of the service for IPv4 | 53 | */ |
54 | */ | 54 | static struct GNUNET_NETWORK_Handle *lsock4; |
55 | static struct GNUNET_NETWORK_Handle *lsock4; | 55 | |
56 | 56 | ||
57 | 57 | /** | |
58 | /** | 58 | * The listen task ID for IPv4 |
59 | * The listen task ID for IPv4 | 59 | */ |
60 | */ | 60 | static struct GNUNET_SCHEDULER_Task * ltask4; |
61 | static struct GNUNET_SCHEDULER_Task * ltask4; | 61 | |
62 | 62 | ||
63 | 63 | ||
64 | 64 | ||
65 | /** | 65 | static void |
66 | * Handle to a request given to the resolver. Can be used to cancel | 66 | print_answer(struct sockaddr_in* answer) |
67 | * the request prior to the timeout or successful execution. Also | 67 | { |
68 | * used to track our internal state for the request. | 68 | printf("External IP is: %s , with port %d\n", inet_ntoa(answer->sin_addr), ntohs(answer->sin_port)); |
69 | */ | 69 | } |
70 | struct GNUNET_NAT_StunRequestHandle { | 70 | |
71 | 71 | ||
72 | /** | 72 | /** |
73 | * Handle to a pending DNS lookup request. | 73 | * Activity on our incoming socket. Read data from the |
74 | */ | 74 | * incoming connection. |
75 | struct GNUNET_RESOLVER_RequestHandle *dns_active; | 75 | * |
76 | 76 | * @param cls | |
77 | 77 | * @param tc scheduler context | |
78 | /** | 78 | */ |
79 | * Handle to the listen socket | 79 | static void |
80 | */ | 80 | do_udp_read (void *cls, |
81 | struct GNUNET_NETWORK_Handle * sock; | 81 | const struct GNUNET_SCHEDULER_TaskContext *tc) |
82 | 82 | { | |
83 | }; | 83 | //struct GNUNET_NAT_Test *tst = cls; |
84 | 84 | unsigned char reply_buf[1024]; | |
85 | 85 | ssize_t rlen; | |
86 | 86 | struct sockaddr_in answer; | |
87 | 87 | ||
88 | /* here we store credentials extracted from a message */ | 88 | |
89 | struct StunState { | 89 | if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) && |
90 | uint16_t attr; | 90 | (GNUNET_NETWORK_fdset_isset (tc->read_ready, |
91 | }; | 91 | lsock4))) |
92 | 92 | { | |
93 | /* callback type to be invoked on stun responses. */ | 93 | rlen = GNUNET_NETWORK_socket_recv (lsock4, reply_buf, sizeof (reply_buf)); |
94 | typedef int (stun_cb_f)(struct StunState *st, struct stun_attr *attr, void *arg, unsigned int magic); | 94 | printf("Recivied something of size %d", rlen); |
95 | 95 | ||
96 | 96 | //Lets handle the packet | |
97 | 97 | memset(&answer, 0, sizeof(struct sockaddr_in)); | |
98 | /** | 98 | GNUNET_NAT_stun_handle_packet(reply_buf,rlen, &answer); |
99 | * Convert a message to a StunClass | 99 | |
100 | * | 100 | //Print the anser |
101 | * @param msg the received message | 101 | //TODO: Delete the object |
102 | * @return the converted StunClass | 102 | ret = 0; |
103 | */ | 103 | print_answer(&answer); |
104 | static int decode_class(int msg) | 104 | |
105 | { | 105 | |
106 | return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7); | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | /** | 109 | |
110 | * Convert a message to a StunMethod | 110 | /** |
111 | * | 111 | * Create an IPv4 listen socket bound to our port. |
112 | * @param msg the received message | 112 | * |
113 | * @return the converted StunMethod | 113 | * @return NULL on error |
114 | */ | 114 | */ |
115 | static int decode_method(int msg) | 115 | static struct GNUNET_NETWORK_Handle * |
116 | { | 116 | bind_v4 () |
117 | return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2); | 117 | { |
118 | } | 118 | struct GNUNET_NETWORK_Handle *ls; |
119 | 119 | struct sockaddr_in sa4; | |
120 | /** | 120 | int eno; |
121 | * Encode a class and method to a compatible STUN format | 121 | |
122 | * | 122 | memset (&sa4, 0, sizeof (sa4)); |
123 | * @param msg_class class to be converted | 123 | sa4.sin_family = AF_INET; |
124 | * @param method method to be converted | 124 | sa4.sin_port = htons (port); |
125 | * @return message in a STUN compatible format | 125 | #if HAVE_SOCKADDR_IN_SIN_LEN |
126 | */ | 126 | sa4.sin_len = sizeof (sa4); |
127 | static int encode_message(StunClasses msg_class, StunMethods method) | 127 | #endif |
128 | { | 128 | ls = GNUNET_NETWORK_socket_create (AF_INET, |
129 | return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) | | 129 | SOCK_DGRAM, |
130 | (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2); | 130 | 0); |
131 | } | 131 | if (NULL == ls) |
132 | 132 | return NULL; | |
133 | /* helper function to print message names */ | 133 | if (GNUNET_OK != |
134 | static const char *stun_msg2str(int msg) | 134 | GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa4, |
135 | { | 135 | sizeof (sa4))) |
136 | 136 | { | |
137 | const struct { enum StunClasses value; const char *name; } classes[] = { | 137 | eno = errno; |
138 | { STUN_REQUEST, "Request" }, | 138 | GNUNET_NETWORK_socket_close (ls); |
139 | { STUN_INDICATION, "Indication" }, | 139 | errno = eno; |
140 | { STUN_RESPONSE, "Response" }, | 140 | return NULL; |
141 | { STUN_ERROR_RESPONSE, "Error Response" }, | 141 | } |
142 | { 0, NULL } | 142 | return ls; |
143 | }; | 143 | } |
144 | 144 | ||
145 | const struct { enum StunMethods value; const char *name; } methods[] = { | 145 | |
146 | { STUN_BINDING, "Binding" }, | 146 | |
147 | { 0, NULL } | 147 | /** |
148 | }; | 148 | * Main function run with scheduler. |
149 | 149 | */ | |
150 | static char result[32]; | 150 | |
151 | const char *msg_class = NULL; | 151 | |
152 | const char *method = NULL; | 152 | static void |
153 | int i; | 153 | run (void *cls, char *const *args, const char *cfgfile, |
154 | int value; | 154 | const struct GNUNET_CONFIGURATION_Handle *cfg) |
155 | 155 | { | |
156 | value = decode_class(msg); | 156 | |
157 | for (i = 0; classes[i].name; i++) { | 157 | |
158 | msg_class = classes[i].name; | 158 | //Lets create the socket |
159 | if (classes[i].value == value) | 159 | lsock4 = bind_v4 (); |
160 | break; | 160 | if (NULL == lsock4) |
161 | } | 161 | { |
162 | value = decode_method(msg); | 162 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind"); |
163 | for (i = 0; methods[i].name; i++) { | 163 | } |
164 | method = methods[i].name; | 164 | else |
165 | if (methods[i].value == value) | 165 | { |
166 | break; | 166 | printf("Binded, now will call add_read\n"); |
167 | } | 167 | //Lets call our function now when it accepts |
168 | snprintf(result, sizeof(result), "%s %s", | 168 | ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, |
169 | method ? : "Unknown Method", | 169 | lsock4, &do_udp_read, NULL); |
170 | msg_class ? : "Unknown Class Message"); | 170 | |
171 | return result; | 171 | } |
172 | } | 172 | if(NULL == lsock4 ) |
173 | 173 | { | |
174 | /* helper function to print attribute names */ | 174 | GNUNET_SCHEDULER_shutdown (); |
175 | static const char *stun_attr2str(int msg) | 175 | return; |
176 | { | 176 | } |
177 | const struct { enum StunAttributes value; const char *name; } attrs[] = { | 177 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
178 | { STUN_MAPPED_ADDRESS, "Mapped Address" }, | 178 | "Service listens on port %u\n", |
179 | { STUN_RESPONSE_ADDRESS, "Response Address" }, | 179 | port); |
180 | { STUN_CHANGE_ADDRESS, "Change Address" }, | 180 | printf("Start main event\n"); |
181 | { STUN_SOURCE_ADDRESS, "Source Address" }, | 181 | GNUNET_NAT_stun_make_request(stun_server, stun_port, lsock4); |
182 | { STUN_CHANGED_ADDRESS, "Changed Address" }, | 182 | //Main event |
183 | { STUN_USERNAME, "Username" }, | 183 | //main_task = GNUNET_SCHEDULER_add_delayed (timeout, &do_timeout, nh); |
184 | { STUN_PASSWORD, "Password" }, | 184 | |
185 | { STUN_MESSAGE_INTEGRITY, "Message Integrity" }, | 185 | } |
186 | { STUN_ERROR_CODE, "Error Code" }, | 186 | |
187 | { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" }, | 187 | |
188 | { STUN_REFLECTED_FROM, "Reflected From" }, | 188 | int |
189 | { STUN_REALM, "Realm" }, | 189 | main (int argc, char *const argv[]) |
190 | { STUN_NONCE, "Nonce" }, | 190 | { |
191 | { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" }, | 191 | struct GNUNET_GETOPT_CommandLineOption options[] = { |
192 | { STUN_MS_VERSION, "MS Version" }, | 192 | GNUNET_GETOPT_OPTION_END |
193 | { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" }, | 193 | }; |
194 | { STUN_SOFTWARE, "Software" }, | 194 | |
195 | { STUN_ALTERNATE_SERVER, "Alternate Server" }, | 195 | char *const argv_prog[] = { |
196 | { STUN_FINGERPRINT, "Fingerprint" }, | 196 | "test-stun", |
197 | { 0, NULL } | 197 | NULL |
198 | }; | 198 | }; |
199 | int i; | 199 | GNUNET_log_setup ("test-stun", |
200 | 200 | "WARNING", | |
201 | for (i = 0; attrs[i].name; i++) { | 201 | NULL); |
202 | if (attrs[i].value == msg) | 202 | |
203 | return attrs[i].name; | 203 | GNUNET_PROGRAM_run (1, argv_prog, "test-stun", "nohelp", options, &run, NULL); |
204 | } | 204 | |
205 | return "Unknown Attribute"; | 205 | return ret; |
206 | } | 206 | } |
207 | 207 | ||
208 | 208 | /* end of test_nat.c */ | |
209 | |||
210 | static int stun_process_attr(struct StunState *state, struct stun_attr *attr) | ||
211 | { | ||
212 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
213 | "Found STUN Attribute %s (%04x), length %d\n", | ||
214 | stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); | ||
215 | |||
216 | switch (ntohs(attr->attr)) { | ||
217 | case STUN_MAPPED_ADDRESS: | ||
218 | case STUN_XOR_MAPPED_ADDRESS: | ||
219 | case STUN_MS_XOR_MAPPED_ADDRESS: | ||
220 | break; | ||
221 | default: | ||
222 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
223 | "Ignoring STUN Attribute %s (%04x), length %d\n", | ||
224 | stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len)); | ||
225 | |||
226 | } | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | |||
231 | /* helper function to generate a random request id */ | ||
232 | static void | ||
233 | generate_request_id(struct stun_header *req) | ||
234 | { | ||
235 | int x; | ||
236 | req->magic = htonl(STUN_MAGIC_COOKIE); | ||
237 | for (x = 0; x < 3; x++) | ||
238 | req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, | ||
239 | UINT32_MAX); | ||
240 | } | ||
241 | |||
242 | |||
243 | /* handle an incoming STUN message. | ||
244 | * | ||
245 | * Do some basic sanity checks on packet size and content, | ||
246 | * try to extract a bit of information, and possibly reply. | ||
247 | * At the moment this only processes BIND requests, and returns | ||
248 | * the externally visible address of the request. | ||
249 | * If a callback is specified, invoke it with the attribute. | ||
250 | */ | ||
251 | static int | ||
252 | stun_handle_packet(const uint8_t *data, size_t len, stun_cb_f *stun_cb, void *arg) | ||
253 | { | ||
254 | struct stun_header *hdr = (struct stun_header *)data; | ||
255 | struct stun_attr *attr; | ||
256 | struct StunState st; | ||
257 | int ret = STUN_IGNORE; | ||
258 | |||
259 | uint32_t advertised_message_size; | ||
260 | uint32_t message_magic_cookie; | ||
261 | |||
262 | |||
263 | /* On entry, 'len' is the length of the udp payload. After the | ||
264 | * initial checks it becomes the size of unprocessed options, | ||
265 | * while 'data' is advanced accordingly. | ||
266 | */ | ||
267 | if (len < sizeof(struct stun_header)) { | ||
268 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
269 | "STUN packet too short (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header)); | ||
270 | GNUNET_break_op (0); | ||
271 | return -1; | ||
272 | } | ||
273 | /* Skip header as it is already in hdr */ | ||
274 | len -= sizeof(struct stun_header); | ||
275 | data += sizeof(struct stun_header); | ||
276 | |||
277 | /* len as advertised in the message */ | ||
278 | advertised_message_size = ntohs(hdr->msglen); | ||
279 | |||
280 | message_magic_cookie = ntohl(hdr->magic); | ||
281 | /* Compare if the cookie match */ | ||
282 | if(STUN_MAGIC_COOKIE != message_magic_cookie){ | ||
283 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
284 | "Invalid magic cookie \n"); | ||
285 | GNUNET_break_op (0); | ||
286 | return -1; | ||
287 | } | ||
288 | |||
289 | |||
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 | |||
292 | |||
293 | if (advertised_message_size > len) { | ||
294 | LOG (GNUNET_ERROR_TYPE_INFO, "Scrambled STUN packet length (got %d, expecting %d)\n", advertised_message_size, (int)len); | ||
295 | GNUNET_break_op (0); | ||
296 | } else { | ||
297 | len = advertised_message_size; | ||
298 | } | ||
299 | /* Zero the struct */ | ||
300 | memset(&st,0, sizeof(st)); | ||
301 | |||
302 | while (len > 0) { | ||
303 | if (len < sizeof(struct stun_attr)) { | ||
304 | LOG (GNUNET_ERROR_TYPE_INFO, "Attribute too short (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr)); | ||
305 | GNUNET_break_op (0); | ||
306 | break; | ||
307 | } | ||
308 | attr = (struct stun_attr *)data; | ||
309 | |||
310 | /* compute total attribute length */ | ||
311 | advertised_message_size = ntohs(attr->len) + sizeof(struct stun_attr); | ||
312 | |||
313 | /* Check if we still have space in our buffer */ | ||
314 | if (advertised_message_size > len ) { | ||
315 | LOG (GNUNET_ERROR_TYPE_INFO, "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", advertised_message_size, (int)len); | ||
316 | GNUNET_break_op (0); | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | if (stun_cb){ | ||
321 | stun_cb(&st, attr, arg, hdr->magic); | ||
322 | } | ||
323 | |||
324 | if (stun_process_attr(&st, attr)) { | ||
325 | LOG (GNUNET_ERROR_TYPE_INFO, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr)); | ||
326 | break; | ||
327 | } | ||
328 | /* Clear attribute id: in case previous entry was a string, | ||
329 | * this will act as the terminator for the string. | ||
330 | */ | ||
331 | attr->attr = 0; | ||
332 | data += advertised_message_size; | ||
333 | len -= advertised_message_size; | ||
334 | } | ||
335 | |||
336 | return ret; | ||
337 | } | ||
338 | |||
339 | /* Extract the STUN_MAPPED_ADDRESS from the stun response. | ||
340 | * This is used as a callback for stun_handle_response | ||
341 | * when called from stun_request. | ||
342 | */ | ||
343 | static int | ||
344 | stun_get_mapped(struct StunState *st, struct stun_attr *attr, void *arg, unsigned int magic) | ||
345 | { | ||
346 | struct stun_addr *returned_addr = (struct stun_addr *)(attr + 1); | ||
347 | struct sockaddr_in *sa = (struct sockaddr_in *)arg; | ||
348 | unsigned short type = ntohs(attr->attr); | ||
349 | |||
350 | switch (type) { | ||
351 | case STUN_MAPPED_ADDRESS: | ||
352 | if (st->attr == STUN_XOR_MAPPED_ADDRESS || | ||
353 | st->attr == STUN_MS_XOR_MAPPED_ADDRESS) | ||
354 | return 1; | ||
355 | magic = 0; | ||
356 | break; | ||
357 | case STUN_MS_XOR_MAPPED_ADDRESS: | ||
358 | if (st->attr == STUN_XOR_MAPPED_ADDRESS) | ||
359 | return 1; | ||
360 | break; | ||
361 | case STUN_XOR_MAPPED_ADDRESS: | ||
362 | break; | ||
363 | default: | ||
364 | return 1; | ||
365 | } | ||
366 | if (ntohs(attr->len) < 8 && returned_addr->family != 1) { | ||
367 | return 1; | ||
368 | } | ||
369 | |||
370 | st->attr = type; | ||
371 | sa->sin_port = returned_addr->port ^ htons(ntohl(magic) >> 16); | ||
372 | sa->sin_addr.s_addr = returned_addr->addr ^ magic; | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | |||
377 | /** | ||
378 | * Try to establish a connection given the specified address. | ||
379 | * This function is called by the resolver once we have a DNS reply. | ||
380 | * | ||
381 | * @param cls our `struct GNUNET_CONNECTION_Handle *` | ||
382 | * @param addr address to try, NULL for "last call" | ||
383 | * @param addrlen length of @a addr | ||
384 | */ | ||
385 | static void | ||
386 | try_connect_using_address (void *cls, | ||
387 | const struct sockaddr *addr, | ||
388 | socklen_t addrlen) { | ||
389 | |||
390 | |||
391 | struct GNUNET_NAT_StunRequestHandle *request = cls; | ||
392 | |||
393 | struct stun_header *req; | ||
394 | uint8_t reqdata[1024]; | ||
395 | int reqlen; | ||
396 | |||
397 | if(NULL == request) { | ||
398 | LOG (GNUNET_ERROR_TYPE_INFO, "Empty request\n"); | ||
399 | return; | ||
400 | } | ||
401 | |||
402 | |||
403 | if (NULL == addr) { | ||
404 | request->dns_active = NULL; | ||
405 | LOG (GNUNET_ERROR_TYPE_INFO, "Error resolving host %s\n", stun_server); | ||
406 | //BREAk op | ||
407 | return; | ||
408 | } | ||
409 | |||
410 | |||
411 | |||
412 | struct sockaddr_in server; | ||
413 | |||
414 | |||
415 | memset(&server,0, sizeof(server)); | ||
416 | server.sin_family = AF_INET; | ||
417 | |||
418 | struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; | ||
419 | |||
420 | server.sin_addr = addr_in->sin_addr; | ||
421 | server.sin_port = htons(stun_port); | ||
422 | |||
423 | |||
424 | /*Craft the simplest possible STUN packet. A request binding*/ | ||
425 | req = (struct stun_header *)reqdata; | ||
426 | generate_request_id(req); | ||
427 | reqlen = 0; | ||
428 | req->msgtype = 0; | ||
429 | req->msglen = 0; | ||
430 | |||
431 | |||
432 | req->msglen = htons(reqlen); | ||
433 | req->msgtype = htons(encode_message(STUN_REQUEST, STUN_BINDING)); | ||
434 | |||
435 | |||
436 | if (-1 == GNUNET_NETWORK_socket_sendto (request->sock, req, ntohs(req->msglen) + sizeof(*req), | ||
437 | (const struct sockaddr *) &server, sizeof (server))) | ||
438 | { | ||
439 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "Failt to sendto"); | ||
440 | } | ||
441 | |||
442 | } | ||
443 | |||
444 | |||
445 | /* Generic STUN request | ||
446 | * Send a generic stun request to the server specified, | ||
447 | * possibly waiting for a reply and filling the 'reply' field with | ||
448 | * the externally visible address. | ||
449 | |||
450 | * \param s the socket used to send the request | ||
451 | * \return 0 on success, other values on error. | ||
452 | */ | ||
453 | struct GNUNET_NAT_StunRequestHandle * | ||
454 | stun_request(struct GNUNET_NETWORK_Handle * sock) | ||
455 | { | ||
456 | |||
457 | |||
458 | struct GNUNET_NAT_StunRequestHandle *rh; | ||
459 | |||
460 | |||
461 | rh = GNUNET_malloc (sizeof (struct GNUNET_NAT_StunRequestHandle)); | ||
462 | |||
463 | rh->sock = sock; | ||
464 | |||
465 | rh->dns_active = GNUNET_RESOLVER_ip_get (stun_server, AF_INET, | ||
466 | GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, | ||
467 | &try_connect_using_address, rh); | ||
468 | |||
469 | |||
470 | |||
471 | |||
472 | return rh; | ||
473 | } | ||
474 | |||
475 | static void | ||
476 | print_answer(struct sockaddr_in* answer) | ||
477 | { | ||
478 | printf("External IP is: %s , with port %d\n", inet_ntoa(answer->sin_addr), ntohs(answer->sin_port)); | ||
479 | } | ||
480 | |||
481 | |||
482 | /** | ||
483 | * Activity on our incoming socket. Read data from the | ||
484 | * incoming connection. | ||
485 | * | ||
486 | * @param cls | ||
487 | * @param tc scheduler context | ||
488 | */ | ||
489 | static void | ||
490 | do_udp_read (void *cls, | ||
491 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
492 | { | ||
493 | //struct GNUNET_NAT_Test *tst = cls; | ||
494 | unsigned char reply_buf[1024]; | ||
495 | ssize_t rlen; | ||
496 | struct sockaddr_in answer; | ||
497 | |||
498 | |||
499 | if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) && | ||
500 | (GNUNET_NETWORK_fdset_isset (tc->read_ready, | ||
501 | lsock4))) | ||
502 | { | ||
503 | rlen = GNUNET_NETWORK_socket_recv (lsock4, reply_buf, sizeof (reply_buf)); | ||
504 | printf("Recivied something of size %d", rlen); | ||
505 | |||
506 | //Lets handle the packet | ||
507 | memset(&answer, 0, sizeof(struct sockaddr_in)); | ||
508 | stun_handle_packet(reply_buf, rlen, stun_get_mapped, &answer); | ||
509 | //Print the anser | ||
510 | //TODO: Delete the object | ||
511 | ret = 0; | ||
512 | print_answer(&answer); | ||
513 | |||
514 | |||
515 | } | ||
516 | } | ||
517 | |||
518 | |||
519 | /** | ||
520 | * Create an IPv4 listen socket bound to our port. | ||
521 | * | ||
522 | * @return NULL on error | ||
523 | */ | ||
524 | static struct GNUNET_NETWORK_Handle * | ||
525 | bind_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 | |||
561 | static void | ||
562 | run (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 | |||
597 | int | ||
598 | main (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 */ | ||