aboutsummaryrefslogtreecommitdiff
path: root/src/nat/gnunet-service-nat_externalip.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-01-05 18:51:02 +0100
committerChristian Grothoff <christian@grothoff.org>2017-01-05 18:51:02 +0100
commit8c1ee5dd1319bcd9ddb6c55d2104c286b61b2e99 (patch)
tree704449a28ae0249ca3a3bd2789c2cbadb8171230 /src/nat/gnunet-service-nat_externalip.c
parent3c31d74877c1243b98e7b31a0d5acab91fc5795e (diff)
downloadgnunet-8c1ee5dd1319bcd9ddb6c55d2104c286b61b2e99.tar.gz
gnunet-8c1ee5dd1319bcd9ddb6c55d2104c286b61b2e99.zip
move external IP logic to separate file
Diffstat (limited to 'src/nat/gnunet-service-nat_externalip.c')
-rw-r--r--src/nat/gnunet-service-nat_externalip.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/src/nat/gnunet-service-nat_externalip.c b/src/nat/gnunet-service-nat_externalip.c
new file mode 100644
index 000000000..979d2f0f5
--- /dev/null
+++ b/src/nat/gnunet-service-nat_externalip.c
@@ -0,0 +1,314 @@
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
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 * 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 * TODO:
33 * - implement NEW logic for external IP detection based on traceroute!
34 *
35 * @file nat/gnunet-service-nat_externalip.c
36 * @brief Functions for monitoring external IPv4 addresses
37 * @author Christian Grothoff
38 */
39#include "platform.h"
40#include <math.h>
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"
52#include "nat.h"
53#include <gcrypt.h>
54
55
56/**
57 * How long do we wait until we re-try running `external-ip` if the
58 * command failed to terminate nicely?
59 */
60#define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
61
62/**
63 * How long do we wait until we re-try running `external-ip` if the
64 * command failed (but terminated)?
65 */
66#define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
67
68/**
69 * How long do we wait until we re-try running `external-ip` if the
70 * command succeeded?
71 */
72#define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
73
74
75/**
76 * Handle to monitor for external IP changes.
77 */
78struct 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/**
104 * List of monitors, kept in DLL.
105 */
106static struct GN_ExternalIPMonitor *mon_head;
107
108/**
109 * List of monitors, kept in DLL.
110 */
111static struct GN_ExternalIPMonitor *mon_tail;
112
113/**
114 * Task run to obtain our external IP (if #enable_upnp is set
115 * and if we find we have a NATed IP address).
116 */
117static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
118
119/**
120 * Handle to our operation to run `external-ip`.
121 */
122static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op;
123
124/**
125 * What is our external IP address as claimed by `external-ip`?
126 * 0 for unknown.
127 */
128static struct in_addr mini_external_ipv4;
129
130
131/**
132 * Tell relevant clients about a change in our external
133 * IPv4 address.
134 *
135 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
136 * @param v4 the external address that changed
137 */
138static void
139notify_monitors_external_ipv4_change (int add,
140 const struct in_addr *v4)
141{
142 for (struct GN_ExternalIPMonitor *mon = mon_head;
143 NULL != mon;
144 mon = mon->next)
145 mon->cb (mon->cb_cls,
146 v4,
147 add);
148}
149
150
151/**
152 * Task used to run `external-ip` to get our external IPv4
153 * address and pass it to NATed clients if possible.
154 *
155 * @param cls NULL
156 */
157static void
158run_external_ip (void *cls);
159
160
161/**
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.
165 *
166 * @param cls NULL
167 * @param addr the address, NULL on errors
168 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
169 */
170static void
171handle_external_ip (void *cls,
172 const struct in_addr *addr,
173 enum GNUNET_NAT_StatusCode result)
174{
175 char buf[INET_ADDRSTRLEN];
176
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,
183 &run_external_ip,
184 NULL);
185 switch (result)
186 {
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",
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 default:
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;
208 break;
209 }
210}
211
212
213/**
214 * Task used to run `external-ip` to get our external IPv4
215 * address and pass it to NATed clients if possible.
216 *
217 * @param cls NULL
218 */
219static void
220run_external_ip (void *cls)
221{
222 probe_external_ip_task
223 = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT,
224 &run_external_ip,
225 NULL);
226 if (NULL != probe_external_ip_op)
227 {
228 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
229 probe_external_ip_op = NULL;
230 }
231 probe_external_ip_op
232 = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip,
233 NULL);
234}
235
236
237/**
238 * We have changed our opinion about being NATed in the first
239 * place. Adapt our probing.
240 *
241 * @param have_nat #GNUNET_YES if we believe we are behind NAT
242 */
243void
244GN_nat_status_changed (int have_nat)
245{
246 if (GNUNET_YES != enable_upnp)
247 return;
248 if ( (GNUNET_YES == have_nat) &&
249 (NULL == probe_external_ip_task) &&
250 (NULL == probe_external_ip_op) )
251 {
252 probe_external_ip_task
253 = GNUNET_SCHEDULER_add_now (&run_external_ip,
254 NULL);
255 return;
256 }
257 if (GNUNET_NO == have_nat)
258 {
259 if (NULL != probe_external_ip_task)
260 {
261 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
262 probe_external_ip_task = NULL;
263 }
264 if (NULL != probe_external_ip_op)
265 {
266 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
267 probe_external_ip_op = NULL;
268 }
269 }
270}
271
272
273/**
274 * Start monitoring external IPv4 addresses.
275 *
276 * @param cb function to call on changes
277 * @param cb_cls closure for @a cb
278 * @return handle to cancel
279 */
280struct GN_ExternalIPMonitor *
281GN_external_ipv4_monitor_start (GN_NotifyExternalIPv4Change cb,
282 void *cb_cls)
283{
284 struct GN_ExternalIPMonitor *mon;
285
286 mon = GNUNET_new (struct GN_ExternalIPMonitor);
287 mon->cb = cb;
288 mon->cb_cls = cb_cls;
289 GNUNET_CONTAINER_DLL_insert (mon_head,
290 mon_tail,
291 mon);
292 if (0 != mini_external_ipv4.s_addr)
293 cb (cb_cls,
294 &mini_external_ipv4,
295 GNUNET_YES);
296 return mon;
297}
298
299
300/**
301 * Stop calling monitor.
302 *
303 * @param mon monitor to call
304 */
305void
306GN_external_ipv4_monitor_stop (struct GN_ExternalIPMonitor *mon)
307{
308 GNUNET_CONTAINER_DLL_remove (mon_head,
309 mon_tail,
310 mon);
311 GNUNET_free (mon);
312}
313
314/* end of gnunet-service-nat_externalip.c */