aboutsummaryrefslogtreecommitdiff
path: root/src/service/nat/gnunet-service-nat_externalip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/nat/gnunet-service-nat_externalip.c')
-rw-r--r--src/service/nat/gnunet-service-nat_externalip.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/src/service/nat/gnunet-service-nat_externalip.c b/src/service/nat/gnunet-service-nat_externalip.c
new file mode 100644
index 000000000..c2625be2d
--- /dev/null
+++ b/src/service/nat/gnunet-service-nat_externalip.c
@@ -0,0 +1,316 @@
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 */
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 * List of monitors, kept in DLL.
104 */
105static struct GN_ExternalIPMonitor *mon_head;
106
107/**
108 * List of monitors, kept in DLL.
109 */
110static 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 */
116static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
117
118/**
119 * Handle to our operation to run `external-ip`.
120 */
121static 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 */
127static 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 */
137static void
138notify_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 */
156static void
157run_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 */
169static void
170handle_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 */
220static void
221run_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 */
244void
245GN_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 */
281struct GN_ExternalIPMonitor *
282GN_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 */
306void
307GN_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 */