2 This file is part of GNUnet.
3 Copyright (C) 2009, 2015 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
23 * This code provides some support for doing STUN transactions.
24 * We send simplest possible packet ia REQUEST with BIND to a STUN server.
26 * All STUN packets start with a simple header made of a type,
27 * length (excluding the header) and a 16-byte random transaction id.
28 * Following the header we may have zero or more attributes, each
29 * structured as a type, length and a value (whose format depends
30 * on the type, but often contains addresses).
31 * Of course all fields are in network format.
33 * This code was based on ministun.c.
36 * @file nat/nat_stun.c
37 * @brief Functions for STUN functionality
38 * @author Bruno Souza Cabral
42 #include "gnunet_util_lib.h"
43 #include "gnunet_resolver_service.h"
44 #include "gnunet_nat_lib.h"
49 #define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
51 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
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.
59 struct GNUNET_NAT_STUN_Handle {
62 * Handle to a pending DNS lookup request.
64 struct GNUNET_RESOLVER_RequestHandle *dns_active;
68 * Handle to the listen socket
70 struct GNUNET_NETWORK_Handle * sock;
83 * Function to call when a error occours
85 GNUNET_NAT_STUN_ErrorCallback cb;
93 * Do we got a DNS resolution successfully ?
102 /* here we store credentials extracted from a message */
109 * Convert a message to a StunClass
111 * @param msg the received message
112 * @return the converted StunClass
115 decode_class(int msg)
117 /* Sorry for the magic, but this maps the class according to rfc5245 */
118 return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7);
122 * Convert a message to a StunMethod
124 * @param msg the received message
125 * @return the converted StunMethod
128 decode_method(int msg)
130 return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2);
134 * Encode a class and method to a compatible STUN format
136 * @param msg_class class to be converted
137 * @param method method to be converted
138 * @return message in a STUN compatible format
141 encode_message(StunClasses msg_class, StunMethods method)
143 return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) |
144 (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2);
148 * Print a class and method from a STUN message
151 * @return string with the message class and method
154 stun_msg2str(int msg)
157 const struct { enum StunClasses value; const char *name; } classes[] = {
158 { STUN_REQUEST, "Request" },
159 { STUN_INDICATION, "Indication" },
160 { STUN_RESPONSE, "Response" },
161 { STUN_ERROR_RESPONSE, "Error Response" },
165 const struct { enum StunMethods value; const char *name; } methods[] = {
166 { STUN_BINDING, "Binding" },
170 static char result[32];
171 const char *msg_class = NULL;
172 const char *method = NULL;
176 value = decode_class(msg);
177 for (i = 0; classes[i].name; i++) {
178 msg_class = classes[i].name;
179 if (classes[i].value == value)
182 value = decode_method(msg);
183 for (i = 0; methods[i].name; i++) {
184 method = methods[i].name;
185 if (methods[i].value == value)
188 GNUNET_snprintf(result, sizeof(result), "%s %s",
189 method ? : "Unknown Method",
190 msg_class ? : "Unknown Class Message");
195 * Print attribute name
197 * @param msg with a attribute type
198 * @return string with the attribute name
201 stun_attr2str(int msg)
203 const struct { enum StunAttributes value; const char *name; } attrs[] = {
204 { STUN_MAPPED_ADDRESS, "Mapped Address" },
205 { STUN_RESPONSE_ADDRESS, "Response Address" },
206 { STUN_CHANGE_ADDRESS, "Change Address" },
207 { STUN_SOURCE_ADDRESS, "Source Address" },
208 { STUN_CHANGED_ADDRESS, "Changed Address" },
209 { STUN_USERNAME, "Username" },
210 { STUN_PASSWORD, "Password" },
211 { STUN_MESSAGE_INTEGRITY, "Message Integrity" },
212 { STUN_ERROR_CODE, "Error Code" },
213 { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" },
214 { STUN_REFLECTED_FROM, "Reflected From" },
215 { STUN_REALM, "Realm" },
216 { STUN_NONCE, "Nonce" },
217 { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" },
218 { STUN_MS_VERSION, "MS Version" },
219 { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" },
220 { STUN_SOFTWARE, "Software" },
221 { STUN_ALTERNATE_SERVER, "Alternate Server" },
222 { STUN_FINGERPRINT, "Fingerprint" },
227 for (i = 0; attrs[i].name; i++) {
228 if (attrs[i].value == msg)
229 return attrs[i].name;
231 return "Unknown Attribute";
236 * Fill the stun_header with a random request_id
238 * @param state, STUN attribute type
239 * @param attr , the actual attribute
241 * @param req, stun header to be filled
244 stun_process_attr(struct StunState *state, struct stun_attr *attr)
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));
250 switch (ntohs(attr->attr)) {
251 case STUN_MAPPED_ADDRESS:
252 case STUN_XOR_MAPPED_ADDRESS:
253 case STUN_MS_XOR_MAPPED_ADDRESS:
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));
267 * Fill the stun_header with a random request_id
269 * @param req, stun header to be filled
272 generate_request_id(struct stun_header *req)
275 req->magic = htonl(STUN_MAGIC_COOKIE);
276 for (x = 0; x < 3; x++)
277 req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
283 * Extract the STUN_MAPPED_ADDRESS from the stun response.
284 * This is used as a callback for stun_handle_response
285 * when called from stun_request.
287 * @param st, pointer where we will set the type
288 * @param attr , received stun attribute
289 * @param arg , pointer to a sockaddr_in where we will set the reported IP and port
290 * @param magic , Magic cookie
292 * @return 0 on success, other value otherwise
295 stun_get_mapped(struct StunState *st, struct stun_attr *attr,struct sockaddr_in *arg, unsigned int magic)
297 struct stun_addr *returned_addr = (struct stun_addr *)(attr + 1);
298 struct sockaddr_in *sa = (struct sockaddr_in *)arg;
299 unsigned short type = ntohs(attr->attr);
302 case STUN_MAPPED_ADDRESS:
303 if (st->attr == STUN_XOR_MAPPED_ADDRESS ||
304 st->attr == STUN_MS_XOR_MAPPED_ADDRESS)
308 case STUN_MS_XOR_MAPPED_ADDRESS:
309 if (st->attr == STUN_XOR_MAPPED_ADDRESS)
312 case STUN_XOR_MAPPED_ADDRESS:
317 if (ntohs(attr->len) < 8 && returned_addr->family != 1) {
323 sa->sin_family = AF_INET;
324 sa->sin_port = returned_addr->port ^ htons(ntohl(magic) >> 16);
325 sa->sin_addr.s_addr = returned_addr->addr ^ magic;
331 * Handle an incoming STUN message, Do some basic sanity checks on packet size and content,
332 * try to extract a bit of information, and possibly reply.
333 * At the moment this only processes BIND requests, and returns
334 * the externally visible address of the request.
335 * If a callback is specified, invoke it with the attribute.
337 * @param data, the packet
338 * @param len, the length of the packet
339 * @param arg, sockaddr_in where we will set our discovered packet
341 * @return, #GNUNET_OK on OK, #GNUNET_NO if the packet is invalid ( not a stun packet)
344 GNUNET_NAT_stun_handle_packet(const void *data, size_t len, struct sockaddr_in *arg)
346 const struct stun_header *hdr = (const struct stun_header *)data;
347 struct stun_attr *attr;
351 uint32_t advertised_message_size;
352 uint32_t message_magic_cookie;
355 /* On entry, 'len' is the length of the udp payload. After the
356 * initial checks it becomes the size of unprocessed options,
357 * while 'data' is advanced accordingly.
359 if (len < sizeof(struct stun_header)) {
360 LOG (GNUNET_ERROR_TYPE_INFO,
361 "STUN packet too short (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
365 /* Skip header as it is already in hdr */
366 len -= sizeof(struct stun_header);
367 data += sizeof(struct stun_header);
369 /* len as advertised in the message */
370 advertised_message_size = ntohs(hdr->msglen);
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");
381 LOG (GNUNET_ERROR_TYPE_INFO, "STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)),
383 advertised_message_size);
386 if (advertised_message_size > len) {
387 LOG (GNUNET_ERROR_TYPE_INFO, "Scrambled STUN packet length (got %d, expecting %d)\n", advertised_message_size,
391 len = advertised_message_size;
394 memset(&st,0, sizeof(st));
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));
402 attr = (struct stun_attr *)data;
404 /* compute total attribute length */
405 advertised_message_size = ntohs(attr->len) + sizeof(struct stun_attr);
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,
415 stun_get_mapped(&st, attr, arg, hdr->magic);
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)),
422 /** Clear attribute id: in case previous entry was a string,
423 * this will act as the terminator for the string.
426 data += advertised_message_size;
427 len -= advertised_message_size;
437 * Clean-up used memory
439 * @param cls our `struct GNUNET_NAT_STUN_Handle *`
442 clean(struct GNUNET_NAT_STUN_Handle * handle)
444 if(handle->stun_server)
446 GNUNET_free(handle->stun_server);
455 * Try to establish a connection given the specified address.
457 * @param cls our `struct GNUNET_NAT_STUN_Handle *`
458 * @param addr address to try, NULL for "last call"
459 * @param addrlen length of @a addr
462 stun_dns_callback (void *cls,
463 const struct sockaddr *addr,
467 struct GNUNET_NAT_STUN_Handle *request = cls;
469 struct stun_header *req;
470 uint8_t reqdata[1024];
472 struct sockaddr_in server;
475 if(NULL == request) {
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);
487 request->dns_active = NULL;
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);
500 request->dns_success= GNUNET_YES;
501 memset(&server,0, sizeof(server));
502 server.sin_family = AF_INET;
503 server.sin_addr = ((struct sockaddr_in *)addr)->sin_addr;
504 server.sin_port = htons(request->stun_port);
507 /*Craft the simplest possible STUN packet. A request binding*/
508 req = (struct stun_header *)reqdata;
509 generate_request_id(req);
513 req->msglen = htons(reqlen);
514 req->msgtype = htons(encode_message(STUN_REQUEST, STUN_BINDING));
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)))
520 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "Fail to sendto");
521 request->cb(request->cb_cls, GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR);
534 * Make Generic STUN request and
535 * Send a generic stun request to the server specified using the specified socket.
536 * possibly waiting for a reply and filling the 'reply' field with
537 * the externally visible address.
539 * @param server, the address of the stun server
540 * @param port, port of the stun server
541 * @param sock the socket used to send the request
542 * @param cb, callback in case of error
543 * @return #GNUNET_OK success, #GNUNET_NO on error.
546 GNUNET_NAT_stun_make_request(char * server,
548 struct GNUNET_NETWORK_Handle * sock,
549 GNUNET_NAT_STUN_ErrorCallback cb,
553 struct GNUNET_NAT_STUN_Handle *rh;
555 rh = GNUNET_malloc (sizeof (struct GNUNET_NAT_STUN_Handle));
558 char * server_copy = GNUNET_strdup (server);
562 rh->stun_server = server_copy;
563 rh->stun_port = port;
564 rh->dns_success = GNUNET_NO;
566 rh->dns_active = GNUNET_RESOLVER_ip_get (server_copy, AF_INET,
568 &stun_dns_callback, rh);
570 if (rh->dns_active == NULL)
572 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "Failed DNS");
574 GNUNET_free(server_copy);