glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / nat / nat_api_stun.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2015, 2016 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14 */
15 /**
16  * This code provides some support for doing STUN transactions.
17  * We send simplest possible packet ia REQUEST with BIND to a STUN server.
18  *
19  * All STUN packets start with a simple header made of a type,
20  * length (excluding the header) and a 16-byte random transaction id.
21  * Following the header we may have zero or more attributes, each
22  * structured as a type, length and a value (whose format depends
23  * on the type, but often contains addresses).
24  * Of course all fields are in network format.
25  *
26  * This code was based on ministun.c.
27  *
28  * @file nat/nat_api_stun.c
29  * @brief Functions for STUN functionality
30  * @author Bruno Souza Cabral
31  */
32
33 #include "platform.h"
34 #include "gnunet_util_lib.h"
35 #include "gnunet_resolver_service.h"
36 #include "gnunet_nat_service.h"
37
38
39 #include "nat_stun.h"
40
41 #define LOG(kind,...) GNUNET_log_from (kind, "stun", __VA_ARGS__)
42
43 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
44
45
46 /**
47  * Handle to a request given to the resolver.  Can be used to cancel
48  * the request prior to the timeout or successful execution.  Also
49  * used to track our internal state for the request.
50  */
51 struct GNUNET_NAT_STUN_Handle
52 {
53
54   /**
55    * Handle to a pending DNS lookup request.
56    */
57   struct GNUNET_RESOLVER_RequestHandle *dns_active;
58
59   /**
60    * Handle to the listen socket
61    */
62   struct GNUNET_NETWORK_Handle *sock;
63
64   /**
65    * Stun server address
66    */
67   char *stun_server;
68
69   /**
70    * Function to call when a error occours
71    */
72   GNUNET_NAT_TestCallback cb;
73
74   /**
75    * Closure for @e cb.
76    */
77   void *cb_cls;
78
79   /**
80    * Do we got a DNS resolution successfully?
81    */
82   int dns_success;
83
84   /**
85    * STUN port
86    */
87   uint16_t stun_port;
88
89 };
90
91
92 /**
93  * Encode a class and method to a compatible STUN format
94  *
95  * @param msg_class class to be converted
96  * @param method method to be converted
97  * @return message in a STUN compatible format
98  */
99 static int
100 encode_message (enum StunClasses msg_class,
101                 enum StunMethods method)
102 {
103   return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) |
104     (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) << 2);
105 }
106
107
108 /**
109  * Fill the stun_header with a random request_id
110  *
111  * @param req, stun header to be filled
112  */
113 static void
114 generate_request_id (struct stun_header *req)
115 {
116   req->magic = htonl(STUN_MAGIC_COOKIE);
117   for (unsigned int x = 0; x < 3; x++)
118     req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
119                                               UINT32_MAX);
120 }
121
122
123 /**
124  * Try to establish a connection given the specified address.
125  *
126  * @param cls our `struct GNUNET_NAT_STUN_Handle *`
127  * @param addr address to try, NULL for "last call"
128  * @param addrlen length of @a addr
129  */
130 static void
131 stun_dns_callback (void *cls,
132                    const struct sockaddr *addr,
133                    socklen_t addrlen)
134 {
135   struct GNUNET_NAT_STUN_Handle *rh = cls;
136   struct stun_header req;
137   struct sockaddr_in server;
138
139   if (NULL == addr)
140   {
141     rh->dns_active = NULL;
142     if (GNUNET_NO == rh->dns_success)
143     {
144       LOG (GNUNET_ERROR_TYPE_INFO,
145            "Error resolving host %s\n",
146            rh->stun_server);
147       rh->cb (rh->cb_cls,
148               GNUNET_NAT_ERROR_NOT_ONLINE);
149     }
150     else if (GNUNET_SYSERR == rh->dns_success)
151     {
152       rh->cb (rh->cb_cls,
153               GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR);
154     }
155     else
156     {
157       rh->cb (rh->cb_cls,
158               GNUNET_NAT_ERROR_SUCCESS);
159     }
160     GNUNET_NAT_stun_make_request_cancel (rh);
161     return;
162   }
163
164   rh->dns_success = GNUNET_YES;
165   memset (&server, 0, sizeof(server));
166   server.sin_family = AF_INET;
167   server.sin_addr = ((struct sockaddr_in *)addr)->sin_addr;
168   server.sin_port = htons (rh->stun_port);
169 #if HAVE_SOCKADDR_IN_SIN_LEN
170   server.sin_len = (u_char) sizeof (struct sockaddr_in);
171 #endif
172
173   /* Craft the simplest possible STUN packet. A request binding */
174   generate_request_id (&req);
175   req.msglen = htons (0);
176   req.msgtype = htons (encode_message (STUN_REQUEST,
177                                        STUN_BINDING));
178
179   /* Send the packet */
180   if (-1 ==
181       GNUNET_NETWORK_socket_sendto (rh->sock,
182                                     &req,
183                                     sizeof (req),
184                                     (const struct sockaddr *) &server,
185                                     sizeof (server)))
186   {
187     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
188                          "sendto");
189     rh->dns_success = GNUNET_SYSERR;
190     return;
191   }
192 }
193
194
195 /**
196  * Make Generic STUN request. Sends a generic stun request to the
197  * server specified using the specified socket.
198  *
199  * @param server the address of the stun server
200  * @param port port of the stun server, in host byte order
201  * @param sock the socket used to send the request
202  * @param cb callback in case of error
203  * @param cb_cls closure for @a cb
204  * @return NULL on error
205  */
206 struct GNUNET_NAT_STUN_Handle *
207 GNUNET_NAT_stun_make_request (const char *server,
208                               uint16_t port,
209                               struct GNUNET_NETWORK_Handle *sock,
210                               GNUNET_NAT_TestCallback cb,
211                               void *cb_cls)
212 {
213   struct GNUNET_NAT_STUN_Handle *rh;
214
215   rh = GNUNET_new (struct GNUNET_NAT_STUN_Handle);
216   rh->sock = sock;
217   rh->cb = cb;
218   rh->cb_cls = cb_cls;
219   rh->stun_server = GNUNET_strdup (server);
220   rh->stun_port = port;
221   rh->dns_success = GNUNET_NO;
222   rh->dns_active = GNUNET_RESOLVER_ip_get (rh->stun_server,
223                                            AF_INET,
224                                            TIMEOUT,
225                                            &stun_dns_callback,
226                                            rh);
227   if (NULL == rh->dns_active)
228   {
229     GNUNET_NAT_stun_make_request_cancel (rh);
230     return NULL;
231   }
232   return rh;
233 }
234
235
236 /**
237  * Cancel active STUN request. Frees associated resources
238  * and ensures that the callback is no longer invoked.
239  *
240  * @param rh request to cancel
241  */
242 void
243 GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh)
244 {
245   if (NULL != rh->dns_active)
246   {
247     GNUNET_RESOLVER_request_cancel (rh->dns_active);
248     rh->dns_active = NULL;
249   }
250   GNUNET_free (rh->stun_server);
251   GNUNET_free (rh);
252 }
253
254
255 /* end of nat_stun.c */