Fix: Cast closure to proper type
[oweals/gnunet.git] / src / nat / gnunet-service-nat_externalip.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2015, 2016, 2017 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      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 /**
19  * Code to figure out what our external IPv4 address(es) might
20  * be (external IPv4s are what is seen on the rest of the Internet).
21  *
22  * This can be implemented using different methods, and we allow
23  * the main service to be notified about changes to what we believe
24  * is our external IPv4 address.
25  *
26  * Note that this is explicitly only about NATed systems; if one
27  * of our network interfaces has a global IP address this does
28  * not count as "external".
29  *
30  * @file nat/gnunet-service-nat_externalip.c
31  * @brief Functions for monitoring external IPv4 addresses
32  * @author Christian Grothoff
33  */
34 #include "platform.h"
35 #include <math.h>
36 #include "gnunet_util_lib.h"
37 #include "gnunet_protocols.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_statistics_service.h"
40 #include "gnunet_resolver_service.h"
41 #include "gnunet_nat_service.h"
42 #include "gnunet-service-nat.h"
43 #include "gnunet-service-nat_externalip.h"
44 #include "gnunet-service-nat_stun.h"
45 #include "gnunet-service-nat_mini.h"
46 #include "gnunet-service-nat_helper.h"
47 #include "nat.h"
48 #include <gcrypt.h>
49
50
51 /**
52  * How long do we wait until we re-try running `external-ip` if the
53  * command failed to terminate nicely?
54  */
55 #define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
56
57 /**
58  * How long do we wait until we re-try running `external-ip` if the
59  * command failed (but terminated)?
60  */
61 #define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
62
63 /**
64  * How long do we wait until we re-try running `external-ip` if the
65  * command succeeded?
66  */
67 #define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
68
69
70 /**
71  * Handle to monitor for external IP changes.
72  */
73 struct GN_ExternalIPMonitor
74 {
75   /**
76    * Kept in DLL.
77    */
78   struct GN_ExternalIPMonitor *next;
79
80   /**
81    * Kept in DLL.
82    */
83   struct GN_ExternalIPMonitor *prev;
84
85   /**
86    * Function to call when we believe our external IPv4 address changed.
87    */
88   GN_NotifyExternalIPv4Change cb;
89
90   /**
91    * Closure for @e cb.
92    */
93   void *cb_cls;
94
95 };
96
97
98 /**
99  * List of monitors, kept in DLL.
100  */
101 static struct GN_ExternalIPMonitor *mon_head;
102
103 /**
104  * List of monitors, kept in DLL.
105  */
106 static struct GN_ExternalIPMonitor *mon_tail;
107
108 /**
109  * Task run to obtain our external IP (if #enable_upnp is set
110  * and if we find we have a NATed IP address).
111  */
112 static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
113
114 /**
115  * Handle to our operation to run `external-ip`.
116  */
117 static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op;
118
119 /**
120  * What is our external IP address as claimed by `external-ip`?
121  * 0 for unknown.
122  */
123 static struct in_addr mini_external_ipv4;
124
125
126 /**
127  * Tell relevant clients about a change in our external
128  * IPv4 address.
129  *
130  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
131  * @param v4 the external address that changed
132  */
133 static void
134 notify_monitors_external_ipv4_change (int add,
135                                       const struct in_addr *v4)
136 {
137   for (struct GN_ExternalIPMonitor *mon = mon_head;
138        NULL != mon;
139        mon = mon->next)
140     mon->cb (mon->cb_cls,
141              v4,
142              add);
143 }
144
145
146 /**
147  * Task used to run `external-ip` to get our external IPv4
148  * address and pass it to NATed clients if possible.
149  *
150  * @param cls NULL
151  */
152 static void
153 run_external_ip (void *cls);
154
155
156 /**
157  * We learn our current external IP address.  If it changed,
158  * notify all of our applicable clients. Also re-schedule
159  * #run_external_ip with an appropriate timeout.
160  *
161  * @param cls NULL
162  * @param addr the address, NULL on errors
163  * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
164  */
165 static void
166 handle_external_ip (void *cls,
167                     const struct in_addr *addr,
168                     enum GNUNET_NAT_StatusCode result)
169 {
170   char buf[INET_ADDRSTRLEN];
171
172   probe_external_ip_op = NULL;
173   GNUNET_SCHEDULER_cancel (probe_external_ip_task);
174   probe_external_ip_task
175     = GNUNET_SCHEDULER_add_delayed ((NULL == addr)
176                                     ? EXTERN_IP_RETRY_FAILURE
177                                     : EXTERN_IP_RETRY_SUCCESS,
178                                     &run_external_ip,
179                                     NULL);
180   switch (result)
181   {
182   case GNUNET_NAT_ERROR_SUCCESS:
183     GNUNET_assert (NULL != addr);
184     if (addr->s_addr == mini_external_ipv4.s_addr)
185       return; /* not change */
186     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
187                 "Our external IP is now %s\n",
188                 inet_ntop (AF_INET,
189                            addr,
190                            buf,
191                            sizeof (buf)));
192     if (0 != mini_external_ipv4.s_addr)
193       notify_monitors_external_ipv4_change (GNUNET_NO,
194                                             &mini_external_ipv4);
195     mini_external_ipv4 = *addr;
196     notify_monitors_external_ipv4_change (GNUNET_YES,
197                                           &mini_external_ipv4);
198     break;
199   default:
200     if (0 != mini_external_ipv4.s_addr)
201       notify_monitors_external_ipv4_change (GNUNET_NO,
202                                             &mini_external_ipv4);
203     mini_external_ipv4.s_addr = 0;
204     break;
205   }
206 }
207
208
209 /**
210  * Task used to run `external-ip` to get our external IPv4
211  * address and pass it to NATed clients if possible.
212  *
213  * @param cls NULL
214  */
215 static void
216 run_external_ip (void *cls)
217 {
218   probe_external_ip_task
219     = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT,
220                                     &run_external_ip,
221                                     NULL);
222   if (NULL != probe_external_ip_op)
223   {
224     GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
225     probe_external_ip_op = NULL;
226   }
227   probe_external_ip_op
228     = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip,
229                                           NULL);
230 }
231
232
233 /**
234  * We have changed our opinion about being NATed in the first
235  * place. Adapt our probing.
236  *
237  * @param have_nat #GNUNET_YES if we believe we are behind NAT
238  */
239 void
240 GN_nat_status_changed (int have_nat)
241 {
242   if (GNUNET_YES != enable_upnp)
243     return;
244   if ( (GNUNET_YES == have_nat) &&
245        (NULL == probe_external_ip_task) &&
246        (NULL == probe_external_ip_op) )
247   {
248     probe_external_ip_task
249       = GNUNET_SCHEDULER_add_now (&run_external_ip,
250                                   NULL);
251     return;
252   }
253   if (GNUNET_NO == have_nat)
254   {
255     if (NULL != probe_external_ip_task)
256     {
257       GNUNET_SCHEDULER_cancel (probe_external_ip_task);
258       probe_external_ip_task = NULL;
259     }
260     if (NULL != probe_external_ip_op)
261     {
262       GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
263       probe_external_ip_op = NULL;
264     }
265   }
266 }
267
268
269 /**
270  * Start monitoring external IPv4 addresses.
271  *
272  * @param cb function to call on changes
273  * @param cb_cls closure for @a cb
274  * @return handle to cancel
275  */
276 struct GN_ExternalIPMonitor *
277 GN_external_ipv4_monitor_start (GN_NotifyExternalIPv4Change cb,
278                                 void *cb_cls)
279 {
280   struct GN_ExternalIPMonitor *mon;
281
282   mon = GNUNET_new (struct GN_ExternalIPMonitor);
283   mon->cb = cb;
284   mon->cb_cls = cb_cls;
285   GNUNET_CONTAINER_DLL_insert (mon_head,
286                                mon_tail,
287                                mon);
288   if (0 != mini_external_ipv4.s_addr)
289     cb (cb_cls,
290         &mini_external_ipv4,
291         GNUNET_YES);
292   return mon;
293 }
294
295
296 /**
297  * Stop calling monitor.
298  *
299  * @param mon monitor to call
300  */
301 void
302 GN_external_ipv4_monitor_stop (struct GN_ExternalIPMonitor *mon)
303 {
304   GNUNET_CONTAINER_DLL_remove (mon_head,
305                                mon_tail,
306                                mon);
307   GNUNET_free (mon);
308 }
309
310 /* end of gnunet-service-nat_externalip.c */