fix #4546
[oweals/gnunet.git] / src / nat / nat_stun.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2015 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * This code provides some support for doing STUN transactions.
22  * We send simplest possible packet ia REQUEST with BIND to a STUN server.
23  *
24  * All STUN packets start with a simple header made of a type,
25  * length (excluding the header) and a 16-byte random transaction id.
26  * Following the header we may have zero or more attributes, each
27  * structured as a type, length and a value (whose format depends
28  * on the type, but often contains addresses).
29  * Of course all fields are in network format.
30  *
31  * This code was based on ministun.c.
32  *
33  * @file nat/nat_stun.c
34  * @brief Functions for STUN functionality
35  * @author Bruno Souza Cabral
36  */
37
38 #include "platform.h"
39 #include "gnunet_util_lib.h"
40 #include "gnunet_resolver_service.h"
41 #include "gnunet_nat_lib.h"
42
43
44 #include "nat_stun.h"
45
46 #define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
47
48 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
49
50
51 /**
52  * Handle to a request given to the resolver.  Can be used to cancel
53  * the request prior to the timeout or successful execution.  Also
54  * used to track our internal state for the request.
55  */
56 struct GNUNET_NAT_STUN_Handle
57 {
58
59   /**
60    * Handle to a pending DNS lookup request.
61    */
62   struct GNUNET_RESOLVER_RequestHandle *dns_active;
63
64   /**
65    * Handle to the listen socket
66    */
67   struct GNUNET_NETWORK_Handle *sock;
68
69   /**
70    * Stun server address
71    */
72   char *stun_server;
73
74   /**
75    * Function to call when a error occours
76    */
77   GNUNET_NAT_STUN_ErrorCallback cb;
78
79   /**
80    * Closure for @e cb.
81    */
82   void *cb_cls;
83
84   /**
85    * Do we got a DNS resolution successfully?
86    */
87   int dns_success;
88
89   /**
90    * STUN port
91    */
92   uint16_t stun_port;
93
94 };
95
96
97 /**
98  * here we store credentials extracted from a message
99 */
100 struct StunState
101 {
102     uint16_t attr;
103 };
104
105
106 /**
107  * Convert a message to a StunClass
108  *
109  * @param msg the received message
110  * @return the converted StunClass
111  */
112 static int
113 decode_class(int msg)
114 {
115   /* Sorry for the magic, but this maps the class according to rfc5245 */
116   return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7);
117 }
118
119 /**
120  * Convert a message to a StunMethod
121  *
122  * @param msg the received message
123  * @return the converted StunMethod
124  */
125 static int
126 decode_method(int msg)
127 {
128   return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2);
129 }
130
131
132 /**
133  * Encode a class and method to a compatible STUN format
134  *
135  * @param msg_class class to be converted
136  * @param method method to be converted
137  * @return message in a STUN compatible format
138  */
139 static int
140 encode_message (enum StunClasses msg_class,
141                 enum StunMethods method)
142 {
143   return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) |
144     (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2);
145 }
146
147
148 /**
149  * Print a class and method from a STUN message
150  *
151  * @param msg
152  * @return string with the message class and method
153  */
154 static const char *
155 stun_msg2str(int msg)
156 {
157   static const struct {
158     enum StunClasses value;
159     const char *name;
160   } classes[] = {
161     { STUN_REQUEST, "Request" },
162     { STUN_INDICATION, "Indication" },
163     { STUN_RESPONSE, "Response" },
164     { STUN_ERROR_RESPONSE, "Error Response" },
165     { 0, NULL }
166   };
167   static const struct {
168     enum StunMethods value;
169     const char *name;
170   } methods[] = {
171     { STUN_BINDING, "Binding" },
172     { 0, NULL }
173   };
174   static char result[32];
175   const char *msg_class = NULL;
176   const char *method = NULL;
177   int i;
178   int value;
179
180   value = decode_class(msg);
181   for (i = 0; classes[i].name; i++)
182   {
183     msg_class = classes[i].name;
184     if (classes[i].value == value)
185       break;
186   }
187   value = decode_method(msg);
188   for (i = 0; methods[i].name; i++)
189   {
190     method = methods[i].name;
191     if (methods[i].value == value)
192       break;
193   }
194   GNUNET_snprintf (result,
195                    sizeof(result),
196                    "%s %s",
197                    method ? : "Unknown Method",
198                    msg_class ? : "Unknown Class Message");
199   return result;
200 }
201
202
203 /**
204  * Print attribute name
205  *
206  * @param msg with a attribute type
207  * @return string with the attribute name
208  */
209 static const char *
210 stun_attr2str (int msg)
211 {
212   static const struct {
213     enum StunAttributes value;
214     const char *name;
215   } attrs[] = {
216     { STUN_MAPPED_ADDRESS, "Mapped Address" },
217     { STUN_RESPONSE_ADDRESS, "Response Address" },
218     { STUN_CHANGE_ADDRESS, "Change Address" },
219     { STUN_SOURCE_ADDRESS, "Source Address" },
220     { STUN_CHANGED_ADDRESS, "Changed Address" },
221     { STUN_USERNAME, "Username" },
222     { STUN_PASSWORD, "Password" },
223     { STUN_MESSAGE_INTEGRITY, "Message Integrity" },
224     { STUN_ERROR_CODE, "Error Code" },
225     { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" },
226     { STUN_REFLECTED_FROM, "Reflected From" },
227     { STUN_REALM, "Realm" },
228     { STUN_NONCE, "Nonce" },
229     { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" },
230     { STUN_MS_VERSION, "MS Version" },
231     { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" },
232     { STUN_SOFTWARE, "Software" },
233     { STUN_ALTERNATE_SERVER, "Alternate Server" },
234     { STUN_FINGERPRINT, "Fingerprint" },
235     { 0, NULL }
236   };
237   unsigned int i;
238
239   for (i = 0; attrs[i].name; i++)
240   {
241     if (attrs[i].value == msg)
242       return attrs[i].name;
243   }
244   return "Unknown Attribute";
245 }
246
247
248 /**
249  * Fill the stun_header with a random request_id
250  *
251  * @param req, stun header to be filled
252  */
253 static void
254 generate_request_id (struct stun_header *req)
255 {
256   unsigned int x;
257
258   req->magic = htonl(STUN_MAGIC_COOKIE);
259   for (x = 0; x < 3; x++)
260     req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
261                                               UINT32_MAX);
262 }
263
264
265 /**
266  * Extract the STUN_MAPPED_ADDRESS from the stun response.
267  * This is used as a callback for stun_handle_response
268  * when called from stun_request.
269  *
270  * @param st, pointer where we will set the type
271  * @param attr , received stun attribute
272  * @param arg , pointer to a sockaddr_in where we will set the reported IP and port
273  * @param magic , Magic cookie
274  *
275  * @return 0 on success, other value otherwise
276  */
277 static int
278 stun_get_mapped (struct StunState *st,
279                  struct stun_attr *attr,
280                  struct sockaddr_in *arg,
281                  unsigned int magic)
282 {
283   struct stun_addr *returned_addr = (struct stun_addr *)(attr + 1);
284   struct sockaddr_in *sa = (struct sockaddr_in *)arg;
285   unsigned short type = ntohs(attr->attr);
286
287   switch (type)
288   {
289   case STUN_MAPPED_ADDRESS:
290     if (st->attr == STUN_XOR_MAPPED_ADDRESS ||
291         st->attr == STUN_MS_XOR_MAPPED_ADDRESS)
292       return 1;
293     magic = 0;
294     break;
295   case STUN_MS_XOR_MAPPED_ADDRESS:
296     if (st->attr == STUN_XOR_MAPPED_ADDRESS)
297       return 1;
298     break;
299   case STUN_XOR_MAPPED_ADDRESS:
300     break;
301   default:
302     return 1;
303   }
304   if ( (ntohs(attr->len) < 8) &&
305        (returned_addr->family != 1) )
306   {
307     return 1;
308   }
309   st->attr = type;
310   sa->sin_family = AF_INET;
311   sa->sin_port = returned_addr->port ^ htons(ntohl(magic) >> 16);
312   sa->sin_addr.s_addr = returned_addr->addr ^ magic;
313   return 0;
314 }
315
316
317 /**
318  * Handle an incoming STUN message, Do some basic sanity checks on packet size and content,
319  * try to extract a bit of information, and possibly reply.
320  * At the moment this only processes BIND requests, and returns
321  * the externally visible address of the request.
322  * If a callback is specified, invoke it with the attribute.
323  *
324  * @param data the packet
325  * @param len the length of the packet in @a data
326  * @param[out] arg sockaddr_in where we will set our discovered address
327  *
328  * @return, #GNUNET_OK on OK, #GNUNET_NO if the packet is invalid (not a stun packet)
329  */
330 int
331 GNUNET_NAT_stun_handle_packet (const void *data,
332                                size_t len,
333                                struct sockaddr_in *arg)
334 {
335   const struct stun_header *hdr = (const struct stun_header *)data;
336   struct stun_attr *attr;
337   struct StunState st;
338   int ret = GNUNET_OK;
339   uint32_t advertised_message_size;
340   uint32_t message_magic_cookie;
341
342   /* On entry, 'len' is the length of the udp payload. After the
343    * initial checks it becomes the size of unprocessed options,
344    * while 'data' is advanced accordingly.
345    */
346   if (len < sizeof(struct stun_header))
347   {
348     LOG (GNUNET_ERROR_TYPE_INFO,
349          "STUN packet too short (only %d, wanting at least %d)\n",
350          (int) len,
351          (int) sizeof(struct stun_header));
352     GNUNET_break_op (0);
353     return GNUNET_NO;
354   }
355   /* Skip header as it is already in hdr */
356   len -= sizeof(struct stun_header);
357   data += sizeof(struct stun_header);
358
359   /* len as advertised in the message */
360   advertised_message_size = ntohs(hdr->msglen);
361
362   message_magic_cookie = ntohl(hdr->magic);
363   /* Compare if the cookie match */
364   if (STUN_MAGIC_COOKIE != message_magic_cookie)
365   {
366     LOG (GNUNET_ERROR_TYPE_INFO,
367          "Invalid magic cookie \n");
368     return GNUNET_NO;
369   }
370
371   LOG (GNUNET_ERROR_TYPE_INFO,
372        "STUN Packet, msg %s (%04x), length: %d\n",
373        stun_msg2str(ntohs(hdr->msgtype)),
374        ntohs(hdr->msgtype),
375        advertised_message_size);
376   if (advertised_message_size > len)
377   {
378     LOG (GNUNET_ERROR_TYPE_INFO,
379          "Scrambled STUN packet length (got %d, expecting %d)\n",
380          advertised_message_size,
381          (int)len);
382     return GNUNET_NO;
383   }
384   len = advertised_message_size;
385   memset (&st, 0, sizeof(st));
386
387   while (len > 0)
388   {
389     if (len < sizeof(struct stun_attr))
390     {
391       LOG (GNUNET_ERROR_TYPE_INFO,
392            "Attribute too short (got %d, expecting %d)\n",
393            (int)len,
394            (int) sizeof(struct stun_attr));
395       break;
396     }
397     attr = (struct stun_attr *)data;
398
399     /* compute total attribute length */
400     advertised_message_size = ntohs(attr->len) + sizeof(struct stun_attr);
401
402     /* Check if we still have space in our buffer */
403     if (advertised_message_size > len )
404     {
405       LOG (GNUNET_ERROR_TYPE_INFO,
406            "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n",
407            advertised_message_size,
408            (int)len);
409       break;
410     }
411     stun_get_mapped (&st,
412                      attr,
413                      arg,
414                      hdr->magic);
415     /* Clear attribute id: in case previous entry was a string,
416      * this will act as the terminator for the string.
417      */
418     attr->attr = 0;
419     data += advertised_message_size;
420     len -= advertised_message_size;
421     ret = GNUNET_OK;
422   }
423   return ret;
424 }
425
426
427 /**
428  * Cancel active STUN request. Frees associated resources
429  * and ensures that the callback is no longer invoked.
430  *
431  * @param rh request to cancel
432  */
433 void
434 GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh)
435 {
436   if (NULL != rh->dns_active)
437   {
438     GNUNET_RESOLVER_request_cancel (rh->dns_active);
439     rh->dns_active = NULL;
440   }
441   GNUNET_free (rh->stun_server);
442   GNUNET_free (rh);
443 }
444
445
446 /**
447  * Try to establish a connection given the specified address.
448  *
449  * @param cls our `struct GNUNET_NAT_STUN_Handle *`
450  * @param addr address to try, NULL for "last call"
451  * @param addrlen length of @a addr
452  */
453 static void
454 stun_dns_callback (void *cls,
455                    const struct sockaddr *addr,
456                    socklen_t addrlen)
457 {
458   struct GNUNET_NAT_STUN_Handle *rh = cls;
459   struct stun_header *req;
460   uint8_t reqdata[1024];
461   int reqlen;
462   struct sockaddr_in server;
463
464   rh->dns_active = NULL;
465   if (NULL == addr)
466   {
467     if (GNUNET_NO == rh->dns_success)
468     {
469       LOG (GNUNET_ERROR_TYPE_INFO,
470            "Error resolving host %s\n",
471            rh->stun_server);
472       rh->cb (rh->cb_cls,
473               GNUNET_NAT_ERROR_NOT_ONLINE);
474       GNUNET_NAT_stun_make_request_cancel (rh);
475     }
476     return;
477   }
478
479   rh->dns_success = GNUNET_YES;
480   memset (&server,0, sizeof(server));
481   server.sin_family = AF_INET;
482   server.sin_addr = ((struct sockaddr_in *)addr)->sin_addr;
483   server.sin_port = htons(rh->stun_port);
484 #if HAVE_SOCKADDR_IN_SIN_LEN
485   server.sin_len = (u_char) sizeof (struct sockaddr_in);
486 #endif
487
488   /*Craft the simplest possible STUN packet. A request binding*/
489   req = (struct stun_header *)reqdata;
490   generate_request_id(req);
491   reqlen = 0;
492   req->msgtype = 0;
493   req->msglen = 0;
494   req->msglen = htons(reqlen);
495   req->msgtype = htons(encode_message(STUN_REQUEST, STUN_BINDING));
496
497   /* Send the packet */
498   if (-1 == GNUNET_NETWORK_socket_sendto (rh->sock,
499                                           req,
500                                           ntohs(req->msglen) + sizeof(*req),
501                                           (const struct sockaddr *) &server,
502                                           sizeof (server)))
503   {
504     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
505                          "Fail to sendto");
506     rh->cb (rh->cb_cls,
507             GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR);
508     GNUNET_NAT_stun_make_request_cancel (rh);
509     return;
510   }
511   /* sending STUN request done, let's wait for replies... */
512   rh->cb (rh->cb_cls,
513           GNUNET_NAT_ERROR_SUCCESS);
514   GNUNET_NAT_stun_make_request_cancel (rh);
515 }
516
517
518 /**
519  * Make Generic STUN request. Sends a generic stun request to the
520  * server specified using the specified socket, possibly waiting for
521  * a reply and filling the 'reply' field with the externally visible
522  * address.
523  *
524  * @param server the address of the stun server
525  * @param port port of the stun server
526  * @param sock the socket used to send the request
527  * @param cb callback in case of error
528  * @param cb_cls closure for @a cb
529  * @return NULL on error
530  */
531 struct GNUNET_NAT_STUN_Handle *
532 GNUNET_NAT_stun_make_request (const char *server,
533                               uint16_t port,
534                               struct GNUNET_NETWORK_Handle *sock,
535                               GNUNET_NAT_STUN_ErrorCallback cb,
536                               void *cb_cls)
537 {
538   struct GNUNET_NAT_STUN_Handle *rh;
539
540   rh = GNUNET_new (struct GNUNET_NAT_STUN_Handle);
541   rh->sock = sock;
542   rh->cb = cb;
543   rh->cb_cls = cb_cls;
544   rh->stun_server = GNUNET_strdup (server);
545   rh->stun_port = port;
546   rh->dns_success = GNUNET_NO;
547   rh->dns_active = GNUNET_RESOLVER_ip_get (rh->stun_server,
548                                            AF_INET,
549                                            TIMEOUT,
550                                            &stun_dns_callback, rh);
551   if (NULL == rh->dns_active)
552   {
553     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
554                          "Failed DNS");
555     GNUNET_NAT_stun_make_request_cancel (rh);
556     return NULL;
557   }
558   return rh;
559 }
560
561 /* end of nat_stun.c */