fix build issues
[oweals/gnunet.git] / src / nat-auto / gnunet-service-nat-auto.c
1 /*
2   This file is part of GNUnet.
3   Copyright (C) 2016, 2017 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 /**
22  * @file nat-auto/gnunet-service-nat-auto.c
23  * @brief NAT autoconfiguration service
24  * @author Christian Grothoff
25  *
26  * TODO:
27  * - merge client handle and autoconfig context
28  * - implement "more" autoconfig:
29  *   + re-work gnunet-nat-server & integrate!
30  *   + integrate "legacy" code
31  *   + test manually punched NAT (how?)
32  */
33 #include "platform.h"
34 #include <math.h>
35 #include "gnunet_util_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_signatures.h"
38 #include "gnunet_nat_service.h"
39 #include "gnunet_statistics_service.h"
40 #include "gnunet_resolver_service.h"
41 #include "nat-auto.h"
42 #include <gcrypt.h>
43
44
45 /**
46  * How long do we wait until we forcefully terminate autoconfiguration?
47  */
48 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
49
50
51 /**
52  * Internal data structure we track for each of our clients.
53  */
54 struct ClientHandle
55 {
56
57   /**
58    * Kept in a DLL.
59    */
60   struct ClientHandle *next;
61
62   /**
63    * Kept in a DLL.
64    */
65   struct ClientHandle *prev;
66
67   /**
68    * Underlying handle for this client with the service.
69    */
70   struct GNUNET_SERVICE_Client *client;
71
72   /**
73    * Message queue for communicating with the client.
74    */
75   struct GNUNET_MQ_Handle *mq;
76 };
77
78
79 /**
80  * Context for autoconfiguration operations.
81  */
82 struct AutoconfigContext
83 {
84   /**
85    * Kept in a DLL.
86    */
87   struct AutoconfigContext *prev;
88
89   /**
90    * Kept in a DLL.
91    */
92   struct AutoconfigContext *next;
93
94   /**
95    * Which client asked the question.
96    */
97   struct ClientHandle *ch;
98
99   /**
100    * Configuration we are creating.
101    */
102   struct GNUNET_CONFIGURATION_Handle *c;
103
104   /**
105    * Original configuration (for diffing).
106    */
107   struct GNUNET_CONFIGURATION_Handle *orig;
108
109   /**
110    * Timeout task to force termination.
111    */
112   struct GNUNET_SCHEDULER_Task *timeout_task;
113
114   /**
115    * #GNUNET_YES if upnpc should be used,
116    * #GNUNET_NO if upnpc should not be used,
117    * #GNUNET_SYSERR if we should simply not change the option.
118    */
119   int enable_upnpc;
120
121   /**
122    * Status code to return to the client.
123    */
124   enum GNUNET_NAT_StatusCode status_code;
125
126   /**
127    * NAT type to return to the client.
128    */
129   enum GNUNET_NAT_Type type;
130 };
131
132
133 /**
134  * Head of client DLL.
135  */
136 static struct ClientHandle *ch_head;
137
138 /**
139  * Tail of client DLL.
140  */
141 static struct ClientHandle *ch_tail;
142
143 /**
144  * DLL of our autoconfiguration operations.
145  */
146 static struct AutoconfigContext *ac_head;
147
148 /**
149  * DLL of our autoconfiguration operations.
150  */
151 static struct AutoconfigContext *ac_tail;
152
153 /**
154  * Handle to our current configuration.
155  */
156 static const struct GNUNET_CONFIGURATION_Handle *cfg;
157
158 /**
159  * Handle to the statistics service.
160  */
161 static struct GNUNET_STATISTICS_Handle *stats;
162
163
164 /**
165  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
166  * from client.
167  *
168  * @param cls client who sent the message
169  * @param message the message received
170  * @return #GNUNET_OK if message is well-formed
171  */
172 static int
173 check_autoconfig_request (void *cls,
174                           const struct GNUNET_NAT_AUTO_AutoconfigRequestMessage *message)
175 {
176   return GNUNET_OK;  /* checked later */
177 }
178
179
180 /**
181  * Stop all pending activities with respect to the @a ac
182  *
183  * @param ac autoconfiguration to terminate activities for
184  */
185 static void
186 terminate_ac_activities (struct AutoconfigContext *ac)
187 {
188   if (NULL != ac->timeout_task)
189   {
190     GNUNET_SCHEDULER_cancel (ac->timeout_task);
191     ac->timeout_task = NULL;
192   }
193 }
194
195
196 /**
197  * Finish handling the autoconfiguration request and send
198  * the response to the client.
199  *
200  * @param cls the `struct AutoconfigContext` to conclude
201  */
202 static void
203 conclude_autoconfig_request (void *cls)
204 {
205   struct AutoconfigContext *ac = cls;
206   struct ClientHandle *ch = ac->ch;
207   struct GNUNET_NAT_AUTO_AutoconfigResultMessage *arm;
208   struct GNUNET_MQ_Envelope *env;
209   size_t c_size;
210   char *buf;
211   struct GNUNET_CONFIGURATION_Handle *diff;
212
213   ac->timeout_task = NULL;
214   terminate_ac_activities (ac);
215
216   /* Send back response */
217   diff = GNUNET_CONFIGURATION_get_diff (ac->orig,
218                                         ac->c);
219   buf = GNUNET_CONFIGURATION_serialize (diff,
220                                         &c_size);
221   GNUNET_CONFIGURATION_destroy (diff);
222   env = GNUNET_MQ_msg_extra (arm,
223                              c_size,
224                              GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
225   arm->status_code = htonl ((uint32_t) ac->status_code);
226   arm->type = htonl ((uint32_t) ac->type);
227   GNUNET_memcpy (&arm[1],
228                  buf,
229                  c_size);
230   GNUNET_free (buf);
231   GNUNET_MQ_send (ch->mq,
232                   env);
233
234   /* clean up */
235   GNUNET_CONFIGURATION_destroy (ac->orig);
236   GNUNET_CONFIGURATION_destroy (ac->c);
237   GNUNET_CONTAINER_DLL_remove (ac_head,
238                                ac_tail,
239                                ac);
240   GNUNET_free (ac);
241   GNUNET_SERVICE_client_continue (ch->client);
242 }
243
244
245 /**
246  * Check if all autoconfiguration operations have concluded,
247  * and if they have, send the result back to the client.
248  *
249  * @param ac autoconfiguation context to check
250  */
251 static void
252 check_autoconfig_finished (struct AutoconfigContext *ac)
253 {
254   GNUNET_SCHEDULER_cancel (ac->timeout_task);
255   ac->timeout_task
256     = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
257                                 ac);
258 }
259
260
261 /**
262  * Update ENABLE_UPNPC configuration option.
263  *
264  * @param ac autoconfiguration to update
265  */
266 static void
267 update_enable_upnpc_option (struct AutoconfigContext *ac)
268 {
269   switch (ac->enable_upnpc)
270   {
271   case GNUNET_YES:
272     GNUNET_CONFIGURATION_set_value_string (ac->c,
273                                            "NAT",
274                                            "ENABLE_UPNP",
275                                            "YES");
276     break;
277   case GNUNET_NO:
278     GNUNET_CONFIGURATION_set_value_string (ac->c,
279                                            "NAT",
280                                            "ENABLE_UPNP",
281                                            "NO");
282     break;
283   case GNUNET_SYSERR:
284     /* We are unsure, do not change option */
285     break;
286   }
287 }
288
289
290 /**
291  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
292  * client.
293  *
294  * @param cls client who sent the message
295  * @param message the message received
296  */
297 static void
298 handle_autoconfig_request (void *cls,
299                            const struct GNUNET_NAT_AUTO_AutoconfigRequestMessage *message)
300 {
301   struct ClientHandle *ch = cls;
302   size_t left = ntohs (message->header.size) - sizeof (*message);
303   struct AutoconfigContext *ac;
304
305   ac = GNUNET_new (struct AutoconfigContext);
306   ac->status_code = GNUNET_NAT_ERROR_SUCCESS;
307   ac->ch = ch;
308   ac->c = GNUNET_CONFIGURATION_create ();
309   if (GNUNET_OK !=
310       GNUNET_CONFIGURATION_deserialize (ac->c,
311                                         (const char *) &message[1],
312                                         left,
313                                         GNUNET_NO))
314   {
315     GNUNET_break (0);
316     GNUNET_SERVICE_client_drop (ch->client);
317     GNUNET_CONFIGURATION_destroy (ac->c);
318     GNUNET_free (ac);
319     return;
320   }
321   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
322               "Received REQUEST_AUTO_CONFIG message from client\n");
323
324   GNUNET_CONTAINER_DLL_insert (ac_head,
325                                ac_tail,
326                                ac);
327   ac->orig
328     = GNUNET_CONFIGURATION_dup (ac->c);
329   ac->timeout_task
330     = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
331                                     &conclude_autoconfig_request,
332                                     ac);
333   ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
334
335   /* Probe for upnpc */
336   if (GNUNET_SYSERR ==
337       GNUNET_OS_check_helper_binary ("upnpc",
338                                      GNUNET_NO,
339                                      NULL))
340   {
341     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
342                 _("UPnP client `upnpc` command not found, disabling UPnP\n"));
343     ac->enable_upnpc = GNUNET_NO;
344   }
345   else
346   {
347     /* We might at some point be behind NAT, try upnpc */
348     ac->enable_upnpc = GNUNET_YES;
349   }
350   update_enable_upnpc_option (ac);
351
352   /* Finally, check if we are already done */
353   check_autoconfig_finished (ac);
354 }
355
356
357 /**
358  * Task run during shutdown.
359  *
360  * @param cls unused
361  */
362 static void
363 shutdown_task (void *cls)
364 {
365   struct AutoconfigContext *ac;
366
367   while (NULL != (ac = ac_head))
368   {
369     GNUNET_CONTAINER_DLL_remove (ac_head,
370                                  ac_tail,
371                                  ac);
372     terminate_ac_activities (ac);
373     GNUNET_free (ac);
374   }
375   if (NULL != stats)
376   {
377     GNUNET_STATISTICS_destroy (stats,
378                                GNUNET_NO);
379     stats = NULL;
380   }
381 }
382
383
384 /**
385  * Setup NAT service.
386  *
387  * @param cls closure
388  * @param c configuration to use
389  * @param service the initialized service
390  */
391 static void
392 run (void *cls,
393      const struct GNUNET_CONFIGURATION_Handle *c,
394      struct GNUNET_SERVICE_Handle *service)
395 {
396   cfg = c;
397   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
398                                  NULL);
399   stats = GNUNET_STATISTICS_create ("nat-auto",
400                                     cfg);
401 }
402
403
404 /**
405  * Callback called when a client connects to the service.
406  *
407  * @param cls closure for the service
408  * @param c the new client that connected to the service
409  * @param mq the message queue used to send messages to the client
410  * @return a `struct ClientHandle`
411  */
412 static void *
413 client_connect_cb (void *cls,
414                    struct GNUNET_SERVICE_Client *c,
415                    struct GNUNET_MQ_Handle *mq)
416 {
417   struct ClientHandle *ch;
418
419   ch = GNUNET_new (struct ClientHandle);
420   ch->mq = mq;
421   ch->client = c;
422   GNUNET_CONTAINER_DLL_insert (ch_head,
423                                ch_tail,
424                                ch);
425   return ch;
426 }
427
428
429 /**
430  * Callback called when a client disconnected from the service
431  *
432  * @param cls closure for the service
433  * @param c the client that disconnected
434  * @param internal_cls a `struct ClientHandle *`
435  */
436 static void
437 client_disconnect_cb (void *cls,
438                       struct GNUNET_SERVICE_Client *c,
439                       void *internal_cls)
440 {
441   struct ClientHandle *ch = internal_cls;
442
443   GNUNET_CONTAINER_DLL_remove (ch_head,
444                                ch_tail,
445                                ch);
446   GNUNET_free (ch);
447 }
448
449
450 /**
451  * Define "main" method using service macro.
452  */
453 GNUNET_SERVICE_MAIN
454 ("nat-auto",
455  GNUNET_SERVICE_OPTION_NONE,
456  &run,
457  &client_connect_cb,
458  &client_disconnect_cb,
459  NULL,
460  GNUNET_MQ_hd_var_size (autoconfig_request,
461                         GNUNET_MESSAGE_TYPE_NAT_AUTO_REQUEST_CFG,
462                         struct GNUNET_NAT_AUTO_AutoconfigRequestMessage,
463                         NULL),
464  GNUNET_MQ_handler_end ());
465
466
467 #if defined(LINUX) && defined(__GLIBC__)
468 #include <malloc.h>
469
470 /**
471  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
472  */
473 void __attribute__ ((constructor))
474 GNUNET_ARM_memory_init ()
475 {
476   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
477   mallopt (M_TOP_PAD, 1 * 1024);
478   malloc_trim (0);
479 }
480 #endif
481
482 /* end of gnunet-service-nat.c */