2 This file is part of GNUnet.
3 Copyright (C) 2009, 2015, 2016, 2017 GNUnet e.V.
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.
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.
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.
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).
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.
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".
33 * - implement NEW logic for external IP detection based on traceroute!
35 * @file nat/gnunet-service-nat_externalip.c
36 * @brief Functions for monitoring external IPv4 addresses
37 * @author Christian Grothoff
41 #include "gnunet_util_lib.h"
42 #include "gnunet_protocols.h"
43 #include "gnunet_signatures.h"
44 #include "gnunet_statistics_service.h"
45 #include "gnunet_resolver_service.h"
46 #include "gnunet_nat_service.h"
47 #include "gnunet-service-nat.h"
48 #include "gnunet-service-nat_externalip.h"
49 #include "gnunet-service-nat_stun.h"
50 #include "gnunet-service-nat_mini.h"
51 #include "gnunet-service-nat_helper.h"
57 * How long do we wait until we re-try running `external-ip` if the
58 * command failed to terminate nicely?
60 #define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
63 * How long do we wait until we re-try running `external-ip` if the
64 * command failed (but terminated)?
66 #define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
69 * How long do we wait until we re-try running `external-ip` if the
72 #define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
76 * Handle to monitor for external IP changes.
78 struct GN_ExternalIPMonitor
83 struct GN_ExternalIPMonitor *next;
88 struct GN_ExternalIPMonitor *prev;
91 * Function to call when we believe our external IPv4 address changed.
93 GN_NotifyExternalIPv4Change cb;
104 * List of monitors, kept in DLL.
106 static struct GN_ExternalIPMonitor *mon_head;
109 * List of monitors, kept in DLL.
111 static struct GN_ExternalIPMonitor *mon_tail;
114 * Task run to obtain our external IP (if #enable_upnp is set
115 * and if we find we have a NATed IP address).
117 static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
120 * Handle to our operation to run `external-ip`.
122 static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op;
125 * What is our external IP address as claimed by `external-ip`?
128 static struct in_addr mini_external_ipv4;
132 * Tell relevant clients about a change in our external
135 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
136 * @param v4 the external address that changed
139 notify_monitors_external_ipv4_change (int add,
140 const struct in_addr *v4)
142 for (struct GN_ExternalIPMonitor *mon = mon_head;
145 mon->cb (mon->cb_cls,
152 * Task used to run `external-ip` to get our external IPv4
153 * address and pass it to NATed clients if possible.
158 run_external_ip (void *cls);
162 * We learn our current external IP address. If it changed,
163 * notify all of our applicable clients. Also re-schedule
164 * #run_external_ip with an appropriate timeout.
167 * @param addr the address, NULL on errors
168 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
171 handle_external_ip (void *cls,
172 const struct in_addr *addr,
173 enum GNUNET_NAT_StatusCode result)
175 char buf[INET_ADDRSTRLEN];
177 probe_external_ip_op = NULL;
178 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
179 probe_external_ip_task
180 = GNUNET_SCHEDULER_add_delayed ((NULL == addr)
181 ? EXTERN_IP_RETRY_FAILURE
182 : EXTERN_IP_RETRY_SUCCESS,
187 case GNUNET_NAT_ERROR_SUCCESS:
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",
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);
204 if (0 != mini_external_ipv4.s_addr)
205 notify_monitors_external_ipv4_change (GNUNET_NO,
206 &mini_external_ipv4);
207 mini_external_ipv4.s_addr = 0;
214 * Task used to run `external-ip` to get our external IPv4
215 * address and pass it to NATed clients if possible.
220 run_external_ip (void *cls)
222 probe_external_ip_task
223 = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT,
226 if (NULL != probe_external_ip_op)
228 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
229 probe_external_ip_op = NULL;
232 = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip,
238 * We have changed our opinion about being NATed in the first
239 * place. Adapt our probing.
241 * @param have_nat #GNUNET_YES if we believe we are behind NAT
244 GN_nat_status_changed (int have_nat)
246 if (GNUNET_YES != enable_upnp)
248 if ( (GNUNET_YES == have_nat) &&
249 (NULL == probe_external_ip_task) &&
250 (NULL == probe_external_ip_op) )
252 probe_external_ip_task
253 = GNUNET_SCHEDULER_add_now (&run_external_ip,
257 if (GNUNET_NO == have_nat)
259 if (NULL != probe_external_ip_task)
261 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
262 probe_external_ip_task = NULL;
264 if (NULL != probe_external_ip_op)
266 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
267 probe_external_ip_op = NULL;
274 * Start monitoring external IPv4 addresses.
276 * @param cb function to call on changes
277 * @param cb_cls closure for @a cb
278 * @return handle to cancel
280 struct GN_ExternalIPMonitor *
281 GN_external_ipv4_monitor_start (GN_NotifyExternalIPv4Change cb,
284 struct GN_ExternalIPMonitor *mon;
286 mon = GNUNET_new (struct GN_ExternalIPMonitor);
288 mon->cb_cls = cb_cls;
289 GNUNET_CONTAINER_DLL_insert (mon_head,
292 if (0 != mini_external_ipv4.s_addr)
301 * Stop calling monitor.
303 * @param mon monitor to call
306 GN_external_ipv4_monitor_stop (struct GN_ExternalIPMonitor *mon)
308 GNUNET_CONTAINER_DLL_remove (mon_head,
314 /* end of gnunet-service-nat_externalip.c */