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