aboutsummaryrefslogtreecommitdiff
path: root/src/nat/upnp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nat/upnp.c')
-rw-r--r--src/nat/upnp.c422
1 files changed, 0 insertions, 422 deletions
diff --git a/src/nat/upnp.c b/src/nat/upnp.c
deleted file mode 100644
index 45c7df419..000000000
--- a/src/nat/upnp.c
+++ /dev/null
@@ -1,422 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/*
22 * This file has been adapted from the Transmission project:
23 * Originally licensed by the GPL version 2.
24 * Copyright (C) 2007-2009 Charles Kerr <charles@transmissionbt.com>
25 */
26
27/**
28 * @file nat/upnp.c
29 * @brief UPnP support for the NAT library
30 *
31 * @author Milan Bouchet-Valat
32 */
33#include "platform.h"
34#include "gnunet_common.h"
35
36#include <stdlib.h>
37#include <assert.h>
38#include <errno.h>
39#include <string.h>
40
41#include "gnunet_nat_lib.h"
42#include "nat.h"
43#include "upnp-discover.h"
44#include "upnp-commands.h"
45#include "upnp.h"
46
47/* Component name for logging */
48#define COMP_NAT_UPNP _("NAT (UPnP)")
49
50enum UPNP_State
51{
52 UPNP_IDLE,
53 UPNP_ERR,
54 UPNP_DISCOVER,
55 UPNP_MAP,
56 UPNP_UNMAP
57};
58
59struct GNUNET_NAT_UPNP_Handle
60{
61 int hasDiscovered;
62 char *control_url;
63 char *service_type;
64 int port;
65 const struct sockaddr *addr;
66 socklen_t addrlen;
67 unsigned int is_mapped;
68 enum UPNP_State state;
69 struct sockaddr *ext_addr;
70 char *iface;
71 int processing;
72 GNUNET_NAT_UPNP_pulse_cb pulse_cb;
73 void *pulse_cls;
74};
75
76static int
77process_if (void *cls,
78 const char *name,
79 int isDefault, const struct sockaddr *addr, socklen_t addrlen)
80{
81 struct GNUNET_NAT_UPNP_Handle *upnp = cls;
82 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "UPNP found if `%s'\n", name);
83 if (addr && GNUNET_NAT_cmp_addr (upnp->addr, addr) == 0)
84 {
85 upnp->iface = GNUNET_strdup(name); // BADNESS!
86 return GNUNET_SYSERR;
87 }
88
89 return GNUNET_OK;
90}
91
92
93struct GNUNET_NAT_UPNP_Handle *
94GNUNET_NAT_UPNP_init (const struct sockaddr *addr,
95 socklen_t addrlen,
96 u_short port,
97 GNUNET_NAT_UPNP_pulse_cb pulse_cb, void *pulse_cls)
98{
99 struct GNUNET_NAT_UPNP_Handle *handle;
100
101 handle = GNUNET_malloc (sizeof (struct GNUNET_NAT_UPNP_Handle));
102 handle->processing = GNUNET_NO;
103 handle->state = UPNP_DISCOVER;
104 handle->addr = addr;
105 handle->addrlen = addrlen;
106 handle->port = port;
107 handle->pulse_cb = pulse_cb;
108 handle->pulse_cls = pulse_cls;
109 handle->control_url = NULL;
110 handle->service_type = NULL;
111
112 /* Find the interface corresponding to the address,
113 * on which we should broadcast call for routers */
114 GNUNET_OS_network_interfaces_list (&process_if, handle);
115 if (!handle->iface)
116 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
117 COMP_NAT_UPNP,
118 "Could not find an interface matching the wanted address.\n");
119 return handle;
120}
121
122
123void
124GNUNET_NAT_UPNP_close (struct GNUNET_NAT_UPNP_Handle *handle)
125{
126 GNUNET_assert (!handle->is_mapped);
127 GNUNET_assert ((handle->state == UPNP_IDLE)
128 || (handle->state == UPNP_ERR)
129 || (handle->state == UPNP_DISCOVER));
130
131 GNUNET_free_non_null (handle->control_url);
132 GNUNET_free_non_null (handle->service_type);
133 GNUNET_free (handle);
134}
135
136static void
137pulse_finish (struct GNUNET_NAT_UPNP_Handle *handle)
138{
139 enum GNUNET_NAT_PortState status;
140 handle->processing = GNUNET_NO;
141
142 switch (handle->state)
143 {
144 case UPNP_DISCOVER:
145 status = GNUNET_NAT_PORT_UNMAPPED;
146 break;
147
148 case UPNP_MAP:
149 status = GNUNET_NAT_PORT_MAPPING;
150 break;
151
152 case UPNP_UNMAP:
153 status = GNUNET_NAT_PORT_UNMAPPING;
154 break;
155
156 case UPNP_IDLE:
157 status =
158 handle->is_mapped ? GNUNET_NAT_PORT_MAPPED : GNUNET_NAT_PORT_UNMAPPED;
159 break;
160
161 default:
162 status = GNUNET_NAT_PORT_ERROR;
163 break;
164 }
165
166 handle->pulse_cb (status, handle->ext_addr, handle->pulse_cls);
167}
168
169static void
170discover_cb (const char *control_url, const char *service_type, void *cls)
171{
172 struct GNUNET_NAT_UPNP_Handle *handle = cls;
173
174 if (control_url)
175 {
176 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
177 _("Found Internet Gateway Device \"%s\"\n"),
178 control_url);
179
180 GNUNET_free_non_null (handle->control_url);
181 GNUNET_free_non_null (handle->service_type);
182
183 handle->control_url = GNUNET_strdup (control_url);
184 handle->service_type = GNUNET_strdup (service_type);
185 handle->state = UPNP_IDLE;
186 handle->hasDiscovered = 1;
187 }
188 else
189 {
190 handle->control_url = NULL;
191 handle->service_type = NULL;
192 handle->state = UPNP_ERR;
193#ifdef DEBUG_UPNP
194 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_UPNP,
195 "UPNP device discovery failed\n");
196#endif
197 }
198
199 pulse_finish (handle);
200}
201
202static void
203check_port_mapping_cb (int error, const char *control_url,
204 const char *service_type, const char *extPort,
205 const char *inPort, const char *proto,
206 const char *remoteHost, void *cls)
207{
208 struct GNUNET_NAT_UPNP_Handle *handle = cls;
209
210 if (error)
211 {
212 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
213 _("Port %d isn't forwarded\n"), handle->port);
214 handle->is_mapped = GNUNET_NO;
215 }
216
217 pulse_finish (handle);
218}
219
220static void
221delete_port_mapping_cb (int error, const char *control_url,
222 const char *service_type, const char *extPort,
223 const char *inPort, const char *proto,
224 const char *remoteHost, void *cls)
225{
226 struct GNUNET_NAT_UPNP_Handle *handle = cls;
227
228 if (error)
229 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
230 _
231 ("Could not stop port forwarding through \"%s\", service \"%s\": error %d\n"),
232 handle->control_url, handle->service_type, error);
233 else
234 {
235 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
236 _
237 ("Stopped port forwarding through \"%s\", service \"%s\"\n"),
238 handle->control_url, handle->service_type);
239 handle->is_mapped = !error;
240 handle->state = UPNP_IDLE;
241 handle->port = -1;
242 }
243
244 pulse_finish (handle);
245}
246
247static void
248add_port_mapping_cb (int error, const char *control_url,
249 const char *service_type, const char *extPort,
250 const char *inPort, const char *proto,
251 const char *remoteHost, void *cls)
252{
253 struct GNUNET_NAT_UPNP_Handle *handle = cls;
254
255 if (error)
256 {
257 handle->is_mapped = GNUNET_NO;
258 handle->state = UPNP_ERR;
259 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
260 _
261 ("Port forwarding through \"%s\", service \"%s\" failed with error %d\n"),
262 handle->control_url, handle->service_type, error);
263 return;
264 }
265 else
266 {
267 handle->is_mapped = GNUNET_NO;
268 handle->state = UPNP_IDLE;
269 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_UPNP,
270 _("Port %d forwarded successfully\n"), handle->port);
271 }
272
273 pulse_finish (handle);
274}
275
276static void
277get_ip_address_cb (int error, char *ext_addr, void *cls)
278{
279 struct GNUNET_NAT_UPNP_Handle *handle = cls;
280
281 if (error)
282 {
283 if (handle->ext_addr)
284 {
285 GNUNET_free (handle->ext_addr);
286 handle->ext_addr = NULL;
287 }
288#ifdef DEBUG_UPNP
289 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_UPNP,
290 "UPNP_get_external_ip_address_ failed (error %d)\n",
291 error);
292#endif
293 }
294 else
295 {
296 struct in_addr addr;
297 struct in6_addr addr6;
298
299 if (handle->ext_addr)
300 {
301 GNUNET_free (handle->ext_addr);
302 handle->ext_addr = NULL;
303 }
304
305 /* Try IPv4 and IPv6 as we don't know what's the format */
306#ifndef MINGW
307 if (inet_aton (ext_addr, &addr) != 0)
308#else
309 addr.S_un.S_addr = inet_addr(ext_addr);
310 if (addr.S_un.S_addr == INADDR_NONE)
311#endif
312 {
313 handle->ext_addr = GNUNET_malloc (sizeof (struct sockaddr_in));
314 handle->ext_addr->sa_family = AF_INET;
315 ((struct sockaddr_in *) handle->ext_addr)->sin_addr = addr;
316 }
317 else if (inet_pton (AF_INET6, ext_addr, &addr6) != 1)
318 {
319 handle->ext_addr = GNUNET_malloc (sizeof (struct sockaddr_in6));
320 handle->ext_addr->sa_family = AF_INET6;
321 ((struct sockaddr_in6 *) handle->ext_addr)->sin6_addr = addr6;
322 }
323 else
324 GNUNET_assert (GNUNET_YES);
325
326#ifdef DEBUG_UPNP
327 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_UPNP,
328 _("Found public IP address %s\n"), ext_addr);
329#endif
330 }
331
332 pulse_finish (handle);
333}
334
335/**
336 * Check state of UPnP NAT: port redirection, external IP address.
337 *
338 *
339 * @param handle the handle for UPnP object
340 * @param is_enabled whether enable port redirection
341 * @param doPortCheck do port check
342 */
343void
344GNUNET_NAT_UPNP_pulse (struct GNUNET_NAT_UPNP_Handle *handle,
345 int is_enabled, int doPortCheck)
346{
347 /* Stop if we're already waiting for an action to complete */
348 if (handle->processing == GNUNET_YES)
349 return;
350
351 if (is_enabled && (handle->state == UPNP_DISCOVER))
352 {
353 handle->processing = GNUNET_YES;
354 UPNP_discover_ (handle->iface, handle->addr, discover_cb,
355 handle);
356 }
357
358 if (handle->state == UPNP_IDLE)
359 {
360 if (handle->is_mapped && !is_enabled)
361 handle->state = UPNP_UNMAP;
362 }
363
364 if (is_enabled && handle->is_mapped && doPortCheck)
365 {
366 char portStr[8];
367
368 GNUNET_snprintf (portStr, sizeof (portStr), "%d", handle->port);
369
370 handle->processing = GNUNET_YES;
371 UPNP_get_specific_port_mapping_entry_ (handle->control_url,
372 handle->service_type, portStr,
373 "TCP", check_port_mapping_cb,
374 handle);
375 }
376
377 if (handle->state == UPNP_UNMAP)
378 {
379 char portStr[16];
380 GNUNET_snprintf (portStr, sizeof (portStr), "%d", handle->port);
381
382 handle->processing = GNUNET_YES;
383 UPNP_delete_port_mapping_ (handle->control_url,
384 handle->service_type, portStr, "TCP", NULL,
385 delete_port_mapping_cb, handle);
386 }
387
388 if (handle->state == UPNP_IDLE)
389 {
390 if (is_enabled && !handle->is_mapped)
391 handle->state = UPNP_MAP;
392 }
393
394 if (handle->state == UPNP_MAP)
395 {
396 if (!handle->control_url)
397 handle->is_mapped = 0;
398 else
399 {
400 char portStr[16];
401 char desc[64];
402 GNUNET_snprintf (portStr, sizeof (portStr), "%d", handle->port);
403 GNUNET_snprintf (desc, sizeof (desc), "GNUnet at %d", handle->port);
404
405 handle->processing = GNUNET_YES;
406 UPNP_add_port_mapping_ (handle->control_url,
407 handle->service_type,
408 portStr, portStr, GNUNET_a2s (handle->addr,
409 handle->addrlen),
410 desc, "TCP", NULL, add_port_mapping_cb,
411 handle);
412 }
413 }
414
415 if (handle->state != UPNP_DISCOVER)
416 {
417 handle->processing = GNUNET_YES;
418 UPNP_get_external_ip_address_ (handle->control_url,
419 handle->service_type,
420 get_ip_address_cb, handle);
421 }
422}