diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-06-25 06:24:01 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-06-25 06:24:01 +0000 |
commit | 8a3016481ba6aeb36de3950a56e641dda53ca544 (patch) | |
tree | 0c5468ec6e5d2165ad5931940e0b8439d09398de | |
parent | b6d4eeb39fd0cd41df164bd0959f58b08aa45e83 (diff) | |
download | gnunet-8a3016481ba6aeb36de3950a56e641dda53ca544.tar.gz gnunet-8a3016481ba6aeb36de3950a56e641dda53ca544.zip |
the big NAT change
37 files changed, 1793 insertions, 7641 deletions
diff --git a/contrib/defaults.conf b/contrib/defaults.conf index 2c2cd7a77..4c21158c8 100644 --- a/contrib/defaults.conf +++ b/contrib/defaults.conf | |||
@@ -31,6 +31,9 @@ PUNCHED_NAT = NO | |||
31 | # Disable UPNP by default until it gets cleaner! | 31 | # Disable UPNP by default until it gets cleaner! |
32 | ENABLE_UPNP = NO | 32 | ENABLE_UPNP = NO |
33 | 33 | ||
34 | # Use addresses from the local network interfaces (inluding loopback, but also others) | ||
35 | USE_LOCALADDR = YES | ||
36 | |||
34 | # External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) | 37 | # External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) |
35 | # normal interface IP address for non-NATed peers; | 38 | # normal interface IP address for non-NATed peers; |
36 | # possibly auto-detected (using UPnP) if possible if not specified | 39 | # possibly auto-detected (using UPnP) if possible if not specified |
@@ -58,12 +61,8 @@ ADVERTISED_PORT = 2086 | |||
58 | # Maximum number of open TCP connections allowed | 61 | # Maximum number of open TCP connections allowed |
59 | MAX_CONNECTIONS = 128 | 62 | MAX_CONNECTIONS = 128 |
60 | 63 | ||
61 | # After how long do we drop inactive connections? | ||
62 | TIMEOUT = 5000 | 64 | TIMEOUT = 5000 |
63 | 65 | ||
64 | # Allow use of loopback address | ||
65 | USE_LOCALADDR = NO | ||
66 | |||
67 | # ACCEPT_FROM = | 66 | # ACCEPT_FROM = |
68 | # ACCEPT_FROM6 = | 67 | # ACCEPT_FROM6 = |
69 | # REJECT_FROM = | 68 | # REJECT_FROM = |
@@ -74,20 +73,13 @@ USE_LOCALADDR = NO | |||
74 | [transport-udp] | 73 | [transport-udp] |
75 | PORT = 2086 | 74 | PORT = 2086 |
76 | 75 | ||
77 | # Allow use of loopback address | ||
78 | USE_LOCALADDR = NO | ||
79 | |||
80 | 76 | ||
81 | [transport-http] | 77 | [transport-http] |
82 | PORT = 1080 | 78 | PORT = 1080 |
83 | # Allow use of loopback address | ||
84 | USE_LOCALADDR = NO | ||
85 | 79 | ||
86 | 80 | ||
87 | [transport-https] | 81 | [transport-https] |
88 | PORT = 4433 | 82 | PORT = 4433 |
89 | # Allow use of loopback address | ||
90 | USE_LOCALADDR = NO | ||
91 | 83 | ||
92 | 84 | ||
93 | [transport-wlan] | 85 | [transport-wlan] |
diff --git a/src/include/gnunet_nat_lib.h b/src/include/gnunet_nat_lib.h index 14da4e684..9550bb1e3 100644 --- a/src/include/gnunet_nat_lib.h +++ b/src/include/gnunet_nat_lib.h | |||
@@ -32,7 +32,8 @@ | |||
32 | #include "gnunet_util_lib.h" | 32 | #include "gnunet_util_lib.h" |
33 | 33 | ||
34 | /** | 34 | /** |
35 | * Signature of the callback passed to GNUNET_NAT_register. | 35 | * Signature of the callback passed to GNUNET_NAT_register for |
36 | * a function to call whenever our set of 'valid' addresses changes. | ||
36 | * | 37 | * |
37 | * @param cls closure | 38 | * @param cls closure |
38 | * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean | 39 | * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean |
@@ -47,38 +48,95 @@ typedef void (*GNUNET_NAT_AddressCallback) (void *cls, | |||
47 | 48 | ||
48 | 49 | ||
49 | /** | 50 | /** |
51 | * Signature of the callback passed to GNUNET_NAT_register | ||
52 | * for a function to call whenever someone asks us to do connection | ||
53 | * reversal. | ||
54 | * | ||
55 | * @param cls closure | ||
56 | * @param addr public IP address of the other peer | ||
57 | * @param addrlen actual lenght of the address | ||
58 | */ | ||
59 | typedef void (*GNUNET_NAT_ReversalCallback) (void *cls, | ||
60 | const struct sockaddr *addr, | ||
61 | socklen_t addrlen); | ||
62 | |||
63 | |||
64 | /** | ||
50 | * Handle for active NAT registrations. | 65 | * Handle for active NAT registrations. |
51 | */ | 66 | */ |
52 | struct GNUNET_NAT_Handle; | 67 | struct GNUNET_NAT_Handle; |
53 | 68 | ||
69 | |||
54 | /** | 70 | /** |
55 | * Attempt to enable port redirection and detect public IP address contacting | 71 | * Attempt to enable port redirection and detect public IP address contacting |
56 | * UPnP or NAT-PMP routers on the local network. Use addr to specify to which | 72 | * UPnP or NAT-PMP routers on the local network. Use addr to specify to which |
57 | * of the local host's addresses should the external port be mapped. The port | 73 | * of the local host's addresses should the external port be mapped. The port |
58 | * is taken from the corresponding sockaddr_in[6] field. | 74 | * is taken from the corresponding sockaddr_in[6] field. The NAT module |
75 | * should call the given callback for any 'plausible' external address. | ||
59 | * | 76 | * |
60 | * @param cfg configuration to use | 77 | * @param cfg configuration to use |
61 | * @param addr the local address packets should be redirected to | 78 | * @param is_tcp GNUNET_YES for TCP, GNUNET_NO for UDP |
62 | * @param addrlen actual lenght of the address | 79 | * @param adv_port advertised port (port we are either bound to or that our OS |
63 | * @param callback function to call everytime the public IP address changes | 80 | * locally performs redirection from to our bound port). |
81 | * @param num_addrs number of addresses in 'addrs' | ||
82 | * @param addrs list of local addresses packets should be redirected to | ||
83 | * @param addrlens actual lengths of the addresses | ||
84 | * @param address_callback function to call everytime the public IP address changes | ||
85 | * @param reversal_callback function to call if someone wants connection reversal from us, | ||
86 | * NULL if connection reversal is not supported | ||
64 | * @param callback_cls closure for callback | 87 | * @param callback_cls closure for callback |
65 | * @return NULL on error, otherwise handle that can be used to unregister | 88 | * @return NULL on error, otherwise handle that can be used to unregister |
66 | */ | 89 | */ |
67 | struct GNUNET_NAT_Handle * | 90 | struct GNUNET_NAT_Handle * |
68 | GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, | 91 | GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, |
69 | const struct sockaddr *addr, | 92 | int is_tcp, |
70 | socklen_t addrlen, | 93 | uint16_t adv_port, |
71 | GNUNET_NAT_AddressCallback callback, | 94 | unsigned int num_addrs, |
95 | const struct sockaddr **addrs, | ||
96 | const socklen_t *addrlens, | ||
97 | GNUNET_NAT_AddressCallback address_callback, | ||
98 | GNUNET_NAT_ReversalCallback reversal_callback, | ||
72 | void *callback_cls); | 99 | void *callback_cls); |
73 | 100 | ||
74 | 101 | ||
75 | /** | 102 | /** |
103 | * Test if the given address is (currently) a plausible IP address for this peer. | ||
104 | * | ||
105 | * @param h the handle returned by register | ||
106 | * @param addr IP address to test (IPv4 or IPv6) | ||
107 | * @param addrlen number of bytes in addr | ||
108 | * @return GNUNET_YES if the address is plausible, | ||
109 | * GNUNET_NO if the address is not plausible, | ||
110 | * GNUNET_SYSERR if the address is malformed | ||
111 | */ | ||
112 | int | ||
113 | GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *h, | ||
114 | const void *addr, | ||
115 | socklen_t addrlen); | ||
116 | |||
117 | |||
118 | /** | ||
119 | * We learned about a peer (possibly behind NAT) so run the | ||
120 | * gnunet-nat-client to send dummy ICMP responses to cause | ||
121 | * that peer to connect to us (connection reversal). | ||
122 | * | ||
123 | * @param h handle (used for configuration) | ||
124 | * @param sa the address of the peer (IPv4-only) | ||
125 | */ | ||
126 | void | ||
127 | GNUNET_NAT_run_client (struct GNUNET_NAT_Handle *h, | ||
128 | const struct sockaddr_in *sa); | ||
129 | |||
130 | |||
131 | |||
132 | /** | ||
76 | * Stop port redirection and public IP address detection for the given handle. | 133 | * Stop port redirection and public IP address detection for the given handle. |
77 | * This frees the handle, after having sent the needed commands to close open ports. | 134 | * This frees the handle, after having sent the needed commands to close open ports. |
78 | * | 135 | * |
79 | * @param h the handle to stop | 136 | * @param h the handle to stop |
80 | */ | 137 | */ |
81 | void GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h); | 138 | void |
139 | GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h); | ||
82 | 140 | ||
83 | #endif | 141 | #endif |
84 | 142 | ||
diff --git a/src/include/gnunet_transport_plugin.h b/src/include/gnunet_transport_plugin.h index 507d95abe..40f134db0 100644 --- a/src/include/gnunet_transport_plugin.h +++ b/src/include/gnunet_transport_plugin.h | |||
@@ -123,19 +123,17 @@ typedef struct GNUNET_TIME_Relative (*GNUNET_TRANSPORT_PluginReceiveCallback) (v | |||
123 | * is aware that it might be reachable under. | 123 | * is aware that it might be reachable under. |
124 | * | 124 | * |
125 | * @param cls closure | 125 | * @param cls closure |
126 | * @param name name of the transport that generated the address | 126 | * @param add_remove should the address added (YES) or removed (NO) from the |
127 | * @param addr one of the addresses of the host, NULL for the last address | 127 | * set of valid addresses? |
128 | * @param addr one of the addresses of the host | ||
128 | * the specific address format depends on the transport | 129 | * the specific address format depends on the transport |
129 | * @param addrlen length of the address | 130 | * @param addrlen length of the address |
130 | * @param expires when should this address automatically expire? | ||
131 | */ | 131 | */ |
132 | typedef void (*GNUNET_TRANSPORT_AddressNotification) (void *cls, | 132 | typedef void (*GNUNET_TRANSPORT_AddressNotification) (void *cls, |
133 | const char *name, | 133 | int add_remove, |
134 | const void *addr, | 134 | const void *addr, |
135 | uint16_t addrlen, | 135 | size_t addrlen); |
136 | struct | 136 | |
137 | GNUNET_TIME_Relative | ||
138 | expires); | ||
139 | 137 | ||
140 | /** | 138 | /** |
141 | * Function that will be called whenever the plugin receives data over | 139 | * Function that will be called whenever the plugin receives data over |
diff --git a/src/include/gnunet_transport_service.h b/src/include/gnunet_transport_service.h index 98ef8c229..9a7093a10 100644 --- a/src/include/gnunet_transport_service.h +++ b/src/include/gnunet_transport_service.h | |||
@@ -558,12 +558,12 @@ struct GNUNET_TRANSPORT_TransmitHandle | |||
558 | /** | 558 | /** |
559 | * Cancel the specified transmission-ready notification. | 559 | * Cancel the specified transmission-ready notification. |
560 | * | 560 | * |
561 | * @param h handle of the transmission notification request to cancel | 561 | * @param th handle of the transmission notification request to cancel |
562 | */ | 562 | */ |
563 | void | 563 | void |
564 | GNUNET_TRANSPORT_notify_transmit_ready_cancel (struct | 564 | GNUNET_TRANSPORT_notify_transmit_ready_cancel (struct |
565 | GNUNET_TRANSPORT_TransmitHandle | 565 | GNUNET_TRANSPORT_TransmitHandle |
566 | *h); | 566 | *th); |
567 | 567 | ||
568 | 568 | ||
569 | 569 | ||
diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am index 8542af8fa..2f30d3185 100644 --- a/src/nat/Makefile.am +++ b/src/nat/Makefile.am | |||
@@ -11,26 +11,12 @@ endif | |||
11 | lib_LTLIBRARIES = libgnunetnat.la | 11 | lib_LTLIBRARIES = libgnunetnat.la |
12 | 12 | ||
13 | libgnunetnat_la_SOURCES = \ | 13 | libgnunetnat_la_SOURCES = \ |
14 | upnp.c upnp.h \ | 14 | nat.c |
15 | upnp-commands.c upnp-commands.h \ | ||
16 | upnp-discover.c upnp-discover.h \ | ||
17 | upnp-igd-parse.c upnp-igd-parse.h \ | ||
18 | upnp-minixml.c upnp-minixml.h \ | ||
19 | upnp-reply-parse.c upnp-reply-parse.h bsdqueue.h \ | ||
20 | nat.c nat.h \ | ||
21 | natpmp.h | ||
22 | |||
23 | libgnunetnat_la_CFLAGS = \ | ||
24 | -DDEBUG_UPNP -g -O0 | ||
25 | 15 | ||
26 | libgnunetnat_la_LIBADD = \ | 16 | libgnunetnat_la_LIBADD = \ |
27 | $(top_builddir)/src/util/libgnunetutil.la \ | 17 | $(top_builddir)/src/util/libgnunetutil.la \ |
28 | @LIBCURL@ \ | ||
29 | $(GN_LIBINTL) @EXT_LIBS@ | 18 | $(GN_LIBINTL) @EXT_LIBS@ |
30 | 19 | ||
31 | libgnunetnat_la_CPPFLAGS = \ | ||
32 | @LIBCURL_CPPFLAGS@ | ||
33 | |||
34 | libgnunetnat_la_LDFLAGS = \ | 20 | libgnunetnat_la_LDFLAGS = \ |
35 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | 21 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ |
36 | -version-info 0:0:0 | 22 | -version-info 0:0:0 |
@@ -39,7 +25,7 @@ check_PROGRAMS = \ | |||
39 | test-nat | 25 | test-nat |
40 | 26 | ||
41 | if ENABLE_TEST_RUN | 27 | if ENABLE_TEST_RUN |
42 | TESTS = $(check_PROGRAMS) | 28 | TESTS = $(check_PROGRAMS) |
43 | endif | 29 | endif |
44 | 30 | ||
45 | test_nat_SOURCES = \ | 31 | test_nat_SOURCES = \ |
@@ -51,4 +37,4 @@ test_nat_LDADD = \ | |||
51 | @LIBCURL@ | 37 | @LIBCURL@ |
52 | 38 | ||
53 | EXTRA_DIST = \ | 39 | EXTRA_DIST = \ |
54 | test-nat.conf | 40 | test_nat_data.conf |
diff --git a/src/nat/bsdqueue.h b/src/nat/bsdqueue.h deleted file mode 100644 index 7b6cb60b3..000000000 --- a/src/nat/bsdqueue.h +++ /dev/null | |||
@@ -1,157 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * @file nat/bsdqueue.h | ||
23 | * @brief BSD implementation of simple lists | ||
24 | * | ||
25 | * @author Milan Bouchet-Valat | ||
26 | */ | ||
27 | |||
28 | /* | ||
29 | * Copyright (c) 1991, 1993 | ||
30 | * The Regents of the University of California. All rights reserved. | ||
31 | * | ||
32 | * Redistribution and use in source and binary forms, with or without | ||
33 | * modification, are permitted provided that the following conditions | ||
34 | * are met: | ||
35 | * 1. Redistributions of source code must retain the above copyright | ||
36 | * notice, this list of conditions and the following disclaimer. | ||
37 | * 2. Redistributions in binary form must reproduce the above copyright | ||
38 | * notice, this list of conditions and the following disclaimer in the | ||
39 | * documentation and/or other materials provided with the distribution. | ||
40 | * 3. Neither the name of the University nor the names of its contributors | ||
41 | * may be used to endorse or promote products derived from this software | ||
42 | * without specific prior written permission. | ||
43 | * | ||
44 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
45 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
46 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
47 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
48 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
49 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
50 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
51 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
52 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
53 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
54 | * SUCH DAMAGE. | ||
55 | * | ||
56 | * @(#)queue.h 8.5 (Berkeley) 8/20/94 | ||
57 | */ | ||
58 | |||
59 | #ifndef BSD_QUEUE_H | ||
60 | #define BSD_QUEUE_H | ||
61 | |||
62 | /* | ||
63 | * A list is headed by a single forward pointer (or an array of forward | ||
64 | * pointers for a hash table header). The elements are doubly linked | ||
65 | * so that an arbitrary element can be removed without a need to | ||
66 | * traverse the list. New elements can be added to the list before | ||
67 | * or after an existing element or at the head of the list. A list | ||
68 | * may only be traversed in the forward direction. | ||
69 | */ | ||
70 | |||
71 | #ifdef QUEUE_MACRO_DEBUG | ||
72 | #define _Q_INVALIDATE(a) (a) = ((void *)-1) | ||
73 | #else | ||
74 | #define _Q_INVALIDATE(a) | ||
75 | #endif | ||
76 | |||
77 | /* | ||
78 | * List definitions. | ||
79 | */ | ||
80 | #define LIST_HEAD(name, type) \ | ||
81 | struct name { \ | ||
82 | struct type *lh_first; /* first element */ \ | ||
83 | } | ||
84 | |||
85 | #define LIST_HEAD_INITIALIZER(head) \ | ||
86 | { NULL } | ||
87 | |||
88 | #define LIST_ENTRY(type) \ | ||
89 | struct { \ | ||
90 | struct type *le_next; /* next element */ \ | ||
91 | struct type **le_prev; /* address of previous next element */ \ | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * List access methods | ||
96 | */ | ||
97 | #define LIST_FIRST(head) ((head)->lh_first) | ||
98 | #define LIST_END(head) NULL | ||
99 | #define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) | ||
100 | #define LIST_NEXT(elm, field) ((elm)->field.le_next) | ||
101 | |||
102 | #define LIST_FOREACH(var, head, field) \ | ||
103 | for((var) = LIST_FIRST(head); \ | ||
104 | (var)!= LIST_END(head); \ | ||
105 | (var) = LIST_NEXT(var, field)) | ||
106 | |||
107 | /* | ||
108 | * List functions. | ||
109 | */ | ||
110 | #define LIST_INIT(head) do { \ | ||
111 | LIST_FIRST(head) = LIST_END(head); \ | ||
112 | } while (0) | ||
113 | |||
114 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \ | ||
115 | if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ | ||
116 | (listelm)->field.le_next->field.le_prev = \ | ||
117 | &(elm)->field.le_next; \ | ||
118 | (listelm)->field.le_next = (elm); \ | ||
119 | (elm)->field.le_prev = &(listelm)->field.le_next; \ | ||
120 | } while (0) | ||
121 | |||
122 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ | ||
123 | (elm)->field.le_prev = (listelm)->field.le_prev; \ | ||
124 | (elm)->field.le_next = (listelm); \ | ||
125 | *(listelm)->field.le_prev = (elm); \ | ||
126 | (listelm)->field.le_prev = &(elm)->field.le_next; \ | ||
127 | } while (0) | ||
128 | |||
129 | #define LIST_INSERT_HEAD(head, elm, field) do { \ | ||
130 | if (((elm)->field.le_next = (head)->lh_first) != NULL) \ | ||
131 | (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ | ||
132 | (head)->lh_first = (elm); \ | ||
133 | (elm)->field.le_prev = &(head)->lh_first; \ | ||
134 | } while (0) | ||
135 | |||
136 | #define LIST_REMOVE(elm, field) do { \ | ||
137 | if ((elm)->field.le_next != NULL) \ | ||
138 | (elm)->field.le_next->field.le_prev = \ | ||
139 | (elm)->field.le_prev; \ | ||
140 | *(elm)->field.le_prev = (elm)->field.le_next; \ | ||
141 | _Q_INVALIDATE((elm)->field.le_prev); \ | ||
142 | _Q_INVALIDATE((elm)->field.le_next); \ | ||
143 | } while (0) | ||
144 | |||
145 | #define LIST_REPLACE(elm, elm2, field) do { \ | ||
146 | if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ | ||
147 | (elm2)->field.le_next->field.le_prev = \ | ||
148 | &(elm2)->field.le_next; \ | ||
149 | (elm2)->field.le_prev = (elm)->field.le_prev; \ | ||
150 | *(elm2)->field.le_prev = (elm2); \ | ||
151 | _Q_INVALIDATE((elm)->field.le_prev); \ | ||
152 | _Q_INVALIDATE((elm)->field.le_next); \ | ||
153 | } while (0) | ||
154 | |||
155 | #endif | ||
156 | |||
157 | /* end of bsd-queue.h */ | ||
diff --git a/src/nat/nat.c b/src/nat/nat.c index 7e83134bd..e92f57259 100644 --- a/src/nat/nat.c +++ b/src/nat/nat.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | (C) 2009, 2010 Christian Grothoff (and other contributing authors) | 3 | (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -18,345 +18,841 @@ | |||
18 | Boston, MA 02111-1307, USA. | 18 | Boston, MA 02111-1307, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | /* | ||
22 | * Parts of this file have 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 | /** | 21 | /** |
28 | * @file nat/nat.c | 22 | * @file nat/nat.c |
29 | * @brief Library handling UPnP and NAT-PMP port forwarding and | 23 | * @brief Library handling UPnP and NAT-PMP port forwarding and |
30 | * external IP address retrieval | 24 | * external IP address retrieval |
31 | * | ||
32 | * @author Milan Bouchet-Valat | 25 | * @author Milan Bouchet-Valat |
26 | * @author Christian Grothoff | ||
27 | * | ||
28 | * TODO: | ||
29 | * - implement UPnP/PMP support | ||
30 | * - repeatedly perform certain checks again to notice changes | ||
33 | */ | 31 | */ |
34 | #include "platform.h" | 32 | #include "platform.h" |
35 | #include "gnunet_util_lib.h" | 33 | #include "gnunet_util_lib.h" |
34 | #include "gnunet_resolver_service.h" | ||
36 | #include "gnunet_nat_lib.h" | 35 | #include "gnunet_nat_lib.h" |
37 | #include "nat.h" | 36 | |
38 | #include "natpmp.h" | 37 | |
39 | #include "upnp.h" | 38 | /** |
39 | * How long until we give up on transmitting the welcome message? | ||
40 | */ | ||
41 | #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
42 | |||
43 | |||
44 | /** | ||
45 | * Where did the given local address originate from? | ||
46 | * To be used for debugging as well as in the future | ||
47 | * to remove all addresses from a certain source when | ||
48 | * we reevaluate the source. | ||
49 | */ | ||
50 | enum LocalAddressSource | ||
51 | { | ||
52 | /** | ||
53 | * Address was obtained by DNS resolution of the external hostname | ||
54 | * given in the configuration (i.e. hole-punched DynDNS setup). | ||
55 | * FIXME: repeatedly do the lookup to notice changes! | ||
56 | */ | ||
57 | LAL_EXTERNAL_IP, | ||
58 | |||
59 | /** | ||
60 | * Address was obtained by looking up our own hostname in DNS. | ||
61 | * FIXME: repeatedly do the lookup to notice changes! | ||
62 | */ | ||
63 | LAL_HOSTNAME_DNS, | ||
64 | |||
65 | /** | ||
66 | * Address was obtained by scanning our hosts's network interfaces | ||
67 | * and taking their address (no DNS involved). | ||
68 | * FIXME: repeatedly do the lookup to notice changes! | ||
69 | */ | ||
70 | LAL_INTERFACE_ADDRESS, | ||
71 | |||
72 | /* TODO: add UPnP, etc. */ | ||
73 | |||
74 | /** | ||
75 | * End of the list. | ||
76 | */ | ||
77 | LAL_END | ||
78 | |||
79 | }; | ||
80 | |||
81 | |||
82 | /** | ||
83 | * List of local addresses that we currently deem valid. Actual | ||
84 | * struct is followed by the 'struct sockaddr'. Note that the code | ||
85 | * intentionally makes no attempt to ensure that a particular address | ||
86 | * is only listed once (especially since it may come from different | ||
87 | * sources, and the source is an "internal" construct). | ||
88 | */ | ||
89 | struct LocalAddressList | ||
90 | { | ||
91 | /** | ||
92 | * This is a linked list. | ||
93 | */ | ||
94 | struct LocalAddressList *next; | ||
95 | |||
96 | /** | ||
97 | * Previous entry. | ||
98 | */ | ||
99 | struct LocalAddressList *prev; | ||
100 | |||
101 | /** | ||
102 | * Number of bytes of address that follow. | ||
103 | */ | ||
104 | socklen_t addrlen; | ||
105 | |||
106 | /** | ||
107 | * Origin of the local address. | ||
108 | */ | ||
109 | enum LocalAddressSource source; | ||
110 | }; | ||
111 | |||
40 | 112 | ||
41 | /** | 113 | /** |
42 | * Handle for active NAT registrations. | 114 | * Handle for active NAT registrations. |
43 | */ | 115 | */ |
44 | struct GNUNET_NAT_Handle | 116 | struct GNUNET_NAT_Handle |
45 | { | 117 | { |
118 | |||
119 | /** | ||
120 | * Configuration to use. | ||
121 | */ | ||
122 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
123 | |||
124 | /** | ||
125 | * Function to call when we learn about a new address. | ||
126 | */ | ||
127 | GNUNET_NAT_AddressCallback address_callback; | ||
128 | |||
46 | /** | 129 | /** |
47 | * Handle for UPnP operations. | 130 | * Function to call when we notice another peer asking for |
131 | * connection reversal. | ||
48 | */ | 132 | */ |
49 | struct GNUNET_NAT_UPNP_Handle *upnp; | 133 | GNUNET_NAT_ReversalCallback reversal_callback; |
50 | 134 | ||
51 | /** | 135 | /** |
52 | * Handle for NAT PMP operations. | 136 | * Closure for 'callback'. |
53 | */ | 137 | */ |
54 | struct GNUNET_NAT_NATPMP_Handle *natpmp; | 138 | void *callback_cls; |
55 | 139 | ||
56 | /** | 140 | /** |
57 | * LAN address as passed by the caller | 141 | * Handle for (DYN)DNS lookup of our external IP. |
58 | */ | 142 | */ |
59 | struct sockaddr *local_addr; | 143 | struct GNUNET_RESOLVER_RequestHandle *ext_dns; |
60 | 144 | ||
61 | /** | 145 | /** |
62 | * External address as reported by found NAT box | 146 | * Handle for request of hostname resolution, non-NULL if pending. |
63 | */ | 147 | */ |
64 | struct sockaddr *ext_addr; | 148 | struct GNUNET_RESOLVER_RequestHandle *hostname_dns; |
65 | 149 | ||
66 | /** | 150 | /** |
67 | * External address as reported by each type of NAT box | 151 | * stdout pipe handle for the gnunet-nat-server process |
68 | */ | 152 | */ |
69 | struct sockaddr *ext_addr_upnp; | 153 | struct GNUNET_DISK_PipeHandle *server_stdout; |
70 | struct sockaddr *ext_addr_natpmp; | ||
71 | 154 | ||
72 | /** | 155 | /** |
73 | * External address and port where packets are redirected | 156 | * stdout file handle (for reading) for the gnunet-nat-server process |
74 | */ | 157 | */ |
75 | struct sockaddr *contact_addr; | 158 | const struct GNUNET_DISK_FileHandle *server_stdout_handle; |
76 | 159 | ||
77 | GNUNET_NAT_AddressCallback callback; | 160 | /** |
161 | * Linked list of currently valid addresses (head). | ||
162 | */ | ||
163 | struct LocalAddressList *lal_head; | ||
78 | 164 | ||
79 | /** | 165 | /** |
80 | * Closure for 'callback'. | 166 | * Linked list of currently valid addresses (tail). |
81 | */ | 167 | */ |
82 | void *callback_cls; | 168 | struct LocalAddressList *lal_tail; |
83 | 169 | ||
84 | GNUNET_SCHEDULER_TaskIdentifier pulse_timer; | 170 | /** |
171 | * How long do we wait for restarting a crashed gnunet-nat-server? | ||
172 | */ | ||
173 | struct GNUNET_TIME_Relative server_retry_delay; | ||
85 | 174 | ||
86 | enum GNUNET_NAT_PortState natpmp_status; | 175 | /** |
176 | * ID of select gnunet-nat-server stdout read task | ||
177 | */ | ||
178 | GNUNET_SCHEDULER_TaskIdentifier server_read_task; | ||
87 | 179 | ||
88 | enum GNUNET_NAT_PortState upnp_status; | 180 | /** |
181 | * The process id of the server process (if behind NAT) | ||
182 | */ | ||
183 | struct GNUNET_OS_Process *server_proc; | ||
89 | 184 | ||
90 | int is_enabled; | 185 | /** |
186 | * LAN address as passed by the caller (array). | ||
187 | */ | ||
188 | struct sockaddr **local_addrs; | ||
91 | 189 | ||
92 | int should_change; | 190 | /** |
191 | * Length of the 'local_addrs'. | ||
192 | */ | ||
193 | socklen_t *local_addrlens; | ||
194 | |||
195 | /** | ||
196 | * Number of entries in 'local_addrs' array. | ||
197 | */ | ||
198 | unsigned int num_local_addrs; | ||
199 | |||
200 | /** | ||
201 | * The our external address (according to config, UPnP may disagree...) | ||
202 | */ | ||
203 | char *external_address; | ||
204 | |||
205 | /** | ||
206 | * Presumably our internal address (according to config) | ||
207 | */ | ||
208 | char *internal_address; | ||
209 | |||
210 | /** | ||
211 | * Is this transport configured to be behind a NAT? | ||
212 | */ | ||
213 | int behind_nat; | ||
214 | |||
215 | /** | ||
216 | * Has the NAT been punched? (according to config) | ||
217 | */ | ||
218 | int nat_punched; | ||
219 | |||
220 | /** | ||
221 | * Is this transport configured to allow connections to NAT'd peers? | ||
222 | */ | ||
223 | int enable_nat_client; | ||
93 | 224 | ||
94 | int port_mapped; | 225 | /** |
226 | * Should we run the gnunet-nat-server? | ||
227 | */ | ||
228 | int enable_nat_server; | ||
95 | 229 | ||
96 | int old_status; | 230 | /** |
231 | * Are we allowed to try UPnP/PMP for NAT traversal? | ||
232 | */ | ||
233 | int enable_upnp; | ||
97 | 234 | ||
98 | int new_status; | 235 | /** |
236 | * Should we use local addresses (loopback)? (according to config) | ||
237 | */ | ||
238 | int use_localaddresses; | ||
99 | 239 | ||
100 | int did_warn; | 240 | /** |
241 | * Is using IPv6 disabled? | ||
242 | */ | ||
243 | int disable_ipv6; | ||
101 | 244 | ||
102 | int processing; | 245 | /** |
246 | * Is this TCP or UDP? | ||
247 | */ | ||
248 | int is_tcp; | ||
103 | 249 | ||
104 | uint16_t public_port; | 250 | /** |
251 | * Port we advertise to the outside. | ||
252 | */ | ||
253 | uint16_t adv_port; | ||
105 | 254 | ||
106 | }; | 255 | }; |
107 | 256 | ||
108 | #ifdef DEBUG | ||
109 | static const char * | ||
110 | get_nat_state_str (enum GNUNET_NAT_PortState state) | ||
111 | { | ||
112 | switch (state) | ||
113 | { | ||
114 | case GNUNET_NAT_PORT_MAPPING: | ||
115 | return "Starting"; | ||
116 | case GNUNET_NAT_PORT_MAPPED: | ||
117 | return "Forwarded"; | ||
118 | case GNUNET_NAT_PORT_UNMAPPING: | ||
119 | return "Stopping"; | ||
120 | case GNUNET_NAT_PORT_UNMAPPED: | ||
121 | return "Not forwarded"; | ||
122 | case GNUNET_NAT_PORT_ERROR: | ||
123 | return "Redirection failed"; | ||
124 | default: | ||
125 | return "not found"; | ||
126 | } | ||
127 | } | ||
128 | #endif | ||
129 | 257 | ||
258 | /** | ||
259 | * Try to start the gnunet-nat-server (if it is not | ||
260 | * already running). | ||
261 | * | ||
262 | * @param h handle to NAT | ||
263 | */ | ||
264 | static void | ||
265 | start_gnunet_nat_server (struct GNUNET_NAT_Handle *h); | ||
130 | 266 | ||
131 | static int | 267 | |
132 | get_traversal_status (const struct GNUNET_NAT_Handle *h) | 268 | /** |
269 | * Add the given address to the list of 'local' addresses, thereby | ||
270 | * making it a 'legal' address for this peer to have. | ||
271 | * | ||
272 | * @param plugin the plugin | ||
273 | * @param src where did the local address originate from? | ||
274 | * @param arg the address, some 'struct sockaddr' | ||
275 | * @param arg_size number of bytes in arg | ||
276 | */ | ||
277 | static void | ||
278 | add_to_address_list_as_is (struct GNUNET_NAT_Handle *h, | ||
279 | enum LocalAddressSource src, | ||
280 | const struct sockaddr *arg, | ||
281 | socklen_t arg_size) | ||
133 | { | 282 | { |
134 | return GNUNET_MAX (h->natpmp_status, h->upnp_status); | 283 | struct LocalAddressList *lal; |
284 | |||
285 | lal = GNUNET_malloc (sizeof (struct LocalAddressList) + arg_size); | ||
286 | memcpy (&lal[1], arg, arg_size); | ||
287 | lal->addrlen = arg_size; | ||
288 | lal->source = src; | ||
289 | GNUNET_CONTAINER_DLL_insert (h->lal_head, | ||
290 | h->lal_tail, | ||
291 | lal); | ||
292 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
293 | "nat", | ||
294 | "Adding address `%s' from source %d\n", | ||
295 | GNUNET_a2s (arg, arg_size), | ||
296 | src); | ||
297 | h->address_callback (h->callback_cls, | ||
298 | GNUNET_YES, | ||
299 | arg, | ||
300 | arg_size); | ||
135 | } | 301 | } |
136 | 302 | ||
137 | 303 | ||
138 | /** | 304 | /** |
139 | * Compare the sin(6)_addr fields of AF_INET or AF_INET(6) sockaddr. | 305 | * Add the given address to the list of 'local' addresses, thereby |
140 | * @param a first sockaddr | 306 | * making it a 'legal' address for this peer to have. Set the |
141 | * @param b second sockaddr | 307 | * port number in the process to the advertised port and possibly |
142 | * @return 0 if addresses are equal, non-null value otherwise */ | 308 | * also to zero (if we have the gnunet-nat-server). |
143 | int | 309 | * |
144 | GNUNET_NAT_cmp_addr (const struct sockaddr *a, const struct sockaddr *b) | 310 | * @param plugin the plugin |
311 | * @param src where did the local address originate from? | ||
312 | * @param arg the address, some 'struct sockaddr' | ||
313 | * @param arg_size number of bytes in arg | ||
314 | */ | ||
315 | static void | ||
316 | add_to_address_list (struct GNUNET_NAT_Handle *h, | ||
317 | enum LocalAddressSource src, | ||
318 | const struct sockaddr *arg, | ||
319 | socklen_t arg_size) | ||
145 | { | 320 | { |
146 | if (!(a && b)) | 321 | struct sockaddr_in s4; |
147 | return -1; | 322 | const struct sockaddr_in *in4; |
148 | if ((a->sa_family == AF_INET) && (b->sa_family == AF_INET)) | 323 | struct sockaddr_in6 s6; |
149 | return memcmp (&(((struct sockaddr_in *) a)->sin_addr), | 324 | const struct sockaddr_in6 *in6; |
150 | &(((struct sockaddr_in *) b)->sin_addr), | 325 | |
151 | sizeof (struct in_addr)); | 326 | if (arg_size == sizeof (struct sockaddr_in)) |
152 | if ((a->sa_family == AF_INET6) && (b->sa_family == AF_INET6)) | 327 | { |
153 | return memcmp (&(((struct sockaddr_in6 *) a)->sin6_addr), | 328 | in4 = (const struct sockaddr_in *) arg; |
154 | &(((struct sockaddr_in6 *) b)->sin6_addr), | 329 | s4 = *in4; |
155 | sizeof (struct in6_addr)); | 330 | s4.sin_port = htons (h->adv_port); |
156 | return -1; | 331 | add_to_address_list_as_is (h, |
332 | src, | ||
333 | (const struct sockaddr*) &s4, | ||
334 | sizeof (struct sockaddr_in)); | ||
335 | if (GNUNET_YES == h->enable_nat_server) | ||
336 | { | ||
337 | /* also add with PORT = 0 to indicate NAT server is enabled */ | ||
338 | s4.sin_port = htons(0); | ||
339 | add_to_address_list_as_is (h, | ||
340 | src, | ||
341 | (const struct sockaddr*) &s4, | ||
342 | sizeof (struct sockaddr_in)); | ||
343 | } | ||
344 | } | ||
345 | else if (arg_size == sizeof (struct sockaddr_in6)) | ||
346 | { | ||
347 | if (GNUNET_YES != h->disable_ipv6) | ||
348 | { | ||
349 | in6 = (const struct sockaddr_in6 *) arg; | ||
350 | s6 = *in6; | ||
351 | s6.sin6_port = htons(h->adv_port); | ||
352 | add_to_address_list_as_is (h, | ||
353 | src, | ||
354 | (const struct sockaddr*) &s6, | ||
355 | sizeof (struct sockaddr_in6)); | ||
356 | } | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | GNUNET_assert (0); | ||
361 | } | ||
157 | } | 362 | } |
158 | 363 | ||
159 | 364 | ||
160 | /** | 365 | /** |
161 | * Deal with a new IP address or port redirection: | 366 | * Add the given IP address to the list of 'local' addresses, thereby |
162 | * Send signals with the appropriate sockaddr (IP and port), free and changes | 367 | * making it a 'legal' address for this peer to have. |
163 | * or nullify the previous sockaddr. Change the port if needed. | 368 | * |
369 | * @param plugin the plugin | ||
370 | * @param src where did the local address originate from? | ||
371 | * @param arg the address, some 'struct in_addr' or 'struct in6_addr' | ||
372 | * @param arg_size number of bytes in arg | ||
164 | */ | 373 | */ |
165 | static void | 374 | static void |
166 | notify_change (struct GNUNET_NAT_Handle *h, | 375 | add_ip_to_address_list (struct GNUNET_NAT_Handle *h, |
167 | struct sockaddr *addr, size_t addrlen, int new_port_mapped) | 376 | enum LocalAddressSource src, |
377 | const void *addr, | ||
378 | socklen_t addrlen) | ||
168 | { | 379 | { |
169 | if (new_port_mapped == h->port_mapped) | 380 | struct sockaddr_in s4; |
170 | return; | 381 | const struct in_addr *in4; |
171 | h->port_mapped = new_port_mapped; | 382 | struct sockaddr_in6 s6; |
172 | 383 | const struct in6_addr *in6; | |
173 | if ((NULL != h->contact_addr) && (NULL != h->callback)) | ||
174 | h->callback (h->callback_cls, | ||
175 | GNUNET_NO, h->contact_addr, sizeof (h->contact_addr)); | ||
176 | GNUNET_free_non_null (h->contact_addr); | ||
177 | h->contact_addr = NULL; | ||
178 | GNUNET_free_non_null (h->ext_addr); | ||
179 | h->ext_addr = NULL; | ||
180 | if (NULL == addr) | ||
181 | return; | ||
182 | h->ext_addr = GNUNET_malloc (addrlen); | ||
183 | memcpy (h->ext_addr, addr, addrlen); | ||
184 | 384 | ||
185 | /* Recreate the ext_addr:public_port bogus address to pass to the callback */ | 385 | if (addrlen == sizeof (struct in_addr)) |
186 | if (h->ext_addr->sa_family == AF_INET) | ||
187 | { | 386 | { |
188 | struct sockaddr_in *tmp_addr; | 387 | in4 = (const struct in_addr *) addr; |
189 | 388 | memset (&s4, 0, sizeof (s4)); | |
190 | tmp_addr = GNUNET_malloc (sizeof (struct sockaddr_in)); | 389 | s4.sin_family = AF_INET; |
191 | tmp_addr->sin_family = AF_INET; | 390 | s4.sin_port = 0; |
192 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | 391 | #if HAVE_SOCKADDR_IN_SIN_LEN |
193 | tmp_addr->sin_len = sizeof (struct sockaddr_in); | 392 | s4.sin_len = (u_char) sizeof (struct sockaddr_in); |
194 | #endif | 393 | #endif |
195 | tmp_addr->sin_port = h->port_mapped ? htons (h->public_port) : 0; | 394 | s4.sin_addr = *in4; |
196 | tmp_addr->sin_addr = ((struct sockaddr_in *) h->ext_addr)->sin_addr; | 395 | add_to_address_list (h, |
197 | h->contact_addr = (struct sockaddr *) tmp_addr; | 396 | src, |
198 | 397 | (const struct sockaddr*) &s4, | |
199 | if (NULL != h->callback) | 398 | sizeof (struct sockaddr_in)); |
200 | h->callback (h->callback_cls, | 399 | if (GNUNET_YES == h->enable_nat_server) |
201 | GNUNET_YES, | 400 | { |
202 | h->contact_addr, sizeof (struct sockaddr_in)); | 401 | /* also add with PORT = 0 to indicate NAT server is enabled */ |
402 | s4.sin_port = htons(0); | ||
403 | add_to_address_list (h, | ||
404 | src, | ||
405 | (const struct sockaddr*) &s4, | ||
406 | sizeof (struct sockaddr_in)); | ||
407 | |||
408 | } | ||
203 | } | 409 | } |
204 | else if (h->ext_addr->sa_family == AF_INET6) | 410 | else if (addrlen == sizeof (struct in6_addr)) |
205 | { | 411 | { |
206 | struct sockaddr_in6 *tmp_addr; | 412 | if (GNUNET_YES != h->disable_ipv6) |
207 | 413 | { | |
208 | tmp_addr = GNUNET_malloc (sizeof (struct sockaddr_in6)); | 414 | in6 = (const struct in6_addr *) addr; |
209 | tmp_addr->sin6_family = AF_INET6; | 415 | memset (&s6, 0, sizeof (s6)); |
210 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | 416 | s6.sin6_family = AF_INET6; |
211 | tmp_addr->sin6_len = sizeof (struct sockaddr_in6); | 417 | s6.sin6_port = htons(h->adv_port); |
418 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
419 | s6.sin6_len = (u_char) sizeof (struct sockaddr_in6); | ||
212 | #endif | 420 | #endif |
213 | tmp_addr->sin6_port = h->port_mapped ? htons (h->public_port) : 0; | 421 | s6.sin6_addr = *in6; |
214 | tmp_addr->sin6_addr = ((struct sockaddr_in6 *) h->ext_addr)->sin6_addr; | 422 | add_to_address_list (h, |
215 | h->contact_addr = (struct sockaddr *) tmp_addr; | 423 | src, |
216 | 424 | (const struct sockaddr*) &s6, | |
217 | if (NULL != h->callback) | 425 | sizeof (struct sockaddr_in6)); |
218 | h->callback (h->callback_cls, | 426 | } |
219 | GNUNET_YES, | ||
220 | h->contact_addr, sizeof (struct sockaddr_in6)); | ||
221 | } | 427 | } |
222 | else | 428 | else |
223 | { | 429 | { |
224 | GNUNET_break (0); | 430 | GNUNET_assert (0); |
225 | } | 431 | } |
226 | } | 432 | } |
227 | 433 | ||
228 | static void nat_pulse (void *cls, | ||
229 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
230 | 434 | ||
435 | /** | ||
436 | * Our (external) hostname was resolved and the configuration says that | ||
437 | * the NAT was hole-punched. | ||
438 | * | ||
439 | * @param cls the 'struct Plugin' | ||
440 | * @param addr NULL on error, otherwise result of DNS lookup | ||
441 | * @param addrlen number of bytes in addr | ||
442 | */ | ||
231 | static void | 443 | static void |
232 | pulse_cb (struct GNUNET_NAT_Handle *h) | 444 | process_external_ip (void *cls, |
445 | const struct sockaddr *addr, | ||
446 | socklen_t addrlen) | ||
233 | { | 447 | { |
234 | socklen_t addrlen; | 448 | struct GNUNET_NAT_Handle *h = cls; |
235 | int port_mapped; | ||
236 | 449 | ||
237 | /* One of the protocols is still working, wait for it to complete */ | 450 | if (addr == NULL) |
238 | if (h->processing) | 451 | { |
239 | return; | 452 | h->ext_dns = NULL; |
453 | /* FIXME: schedule task to resolve IP again in the | ||
454 | future, and if the result changes, update the | ||
455 | local address list accordingly */ | ||
456 | return; | ||
457 | } | ||
458 | add_to_address_list (h, LAL_EXTERNAL_IP, addr, addrlen); | ||
459 | } | ||
240 | 460 | ||
241 | h->new_status = get_traversal_status (h); | ||
242 | if ((h->old_status != h->new_status) && | ||
243 | ((h->new_status == GNUNET_NAT_PORT_UNMAPPED) || | ||
244 | (h->new_status == GNUNET_NAT_PORT_ERROR))) | ||
245 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | ||
246 | "NAT", | ||
247 | _ | ||
248 | ("Port redirection failed: no UPnP or NAT-PMP routers supporting this feature found\n")); | ||
249 | #ifdef DEBUG | ||
250 | if (h->new_status != h->old_status) | ||
251 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "NAT", | ||
252 | _("State changed from `%s' to `%s'\n"), | ||
253 | get_nat_state_str (h->old_status), | ||
254 | get_nat_state_str (h->new_status)); | ||
255 | #endif | ||
256 | 461 | ||
257 | port_mapped = (h->new_status == GNUNET_NAT_PORT_MAPPED); | 462 | /** |
258 | if (!(h->ext_addr_upnp || h->ext_addr_natpmp)) | 463 | * Function called by the resolver for each address obtained from DNS |
464 | * for our own hostname. Add the addresses to the list of our IP | ||
465 | * addresses. | ||
466 | * | ||
467 | * @param cls closure | ||
468 | * @param addr one of the addresses of the host, NULL for the last address | ||
469 | * @param addrlen length of the address | ||
470 | */ | ||
471 | static void | ||
472 | process_hostname_ip (void *cls, | ||
473 | const struct sockaddr *addr, socklen_t addrlen) | ||
474 | { | ||
475 | struct GNUNET_NAT_Handle *h = cls; | ||
476 | |||
477 | if (addr == NULL) | ||
259 | { | 478 | { |
260 | /* Address has just changed and we could not get it, or it's the first try, | 479 | h->hostname_dns = NULL; |
261 | * and we're not waiting for a reply from UPnP or NAT-PMP */ | 480 | /* FIXME: schedule task to resolve IP again in the |
262 | if (((NULL != h->ext_addr) || | 481 | future, and if the result changes, update the |
263 | (GNUNET_NO == h->did_warn)) && h->processing != 0) | 482 | address list accordingly */ |
264 | { | 483 | return; |
265 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | ||
266 | "NAT", | ||
267 | _("Could not determine external IP address\n")); | ||
268 | h->did_warn = GNUNET_YES; | ||
269 | } | ||
270 | notify_change (h, NULL, 0, port_mapped); | ||
271 | } | 484 | } |
272 | else if (h->ext_addr_upnp | 485 | add_to_address_list (h, LAL_HOSTNAME_DNS, addr, addrlen); |
273 | && GNUNET_NAT_cmp_addr (h->ext_addr, h->ext_addr_upnp) != 0) | 486 | } |
487 | |||
488 | |||
489 | /** | ||
490 | * Add the IP of our network interface to the list of | ||
491 | * our IP addresses. | ||
492 | * | ||
493 | * @param cls the 'struct GNUNET_NAT_Handle' | ||
494 | * @param name name of the interface | ||
495 | * @param isDefault do we think this may be our default interface | ||
496 | * @param addr address of the interface | ||
497 | * @param addrlen number of bytes in addr | ||
498 | * @return GNUNET_OK to continue iterating | ||
499 | */ | ||
500 | static int | ||
501 | process_interfaces (void *cls, | ||
502 | const char *name, | ||
503 | int isDefault, | ||
504 | const struct sockaddr *addr, socklen_t addrlen) | ||
505 | { | ||
506 | struct GNUNET_NAT_Handle *h = cls; | ||
507 | const struct sockaddr_in *s4; | ||
508 | const struct sockaddr_in6 *s6; | ||
509 | const void *ip; | ||
510 | char buf[INET6_ADDRSTRLEN]; | ||
511 | |||
512 | switch (addr->sa_family) | ||
274 | { | 513 | { |
275 | addrlen = h->ext_addr_upnp->sa_family == AF_INET ? | 514 | case AF_INET: |
276 | sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6); | 515 | s4 = (struct sockaddr_in *) addr; |
277 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | 516 | ip = &s4->sin_addr; |
278 | "NAT", | 517 | if (GNUNET_YES == h->use_localaddresses) |
279 | _("External IP address changed to %s\n"), | 518 | add_ip_to_address_list (h, |
280 | GNUNET_a2s (h->ext_addr_upnp, addrlen)); | 519 | LAL_INTERFACE_ADDRESS, |
281 | notify_change (h, h->ext_addr_upnp, addrlen, port_mapped); | 520 | &s4->sin_addr, |
521 | sizeof (struct in_addr)); | ||
522 | break; | ||
523 | case AF_INET6: | ||
524 | s6 = (struct sockaddr_in6 *) addr; | ||
525 | if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) | ||
526 | { | ||
527 | /* skip link local addresses */ | ||
528 | return GNUNET_OK; | ||
529 | } | ||
530 | ip = &s6->sin6_addr; | ||
531 | if (GNUNET_YES == h->use_localaddresses) | ||
532 | add_ip_to_address_list (h, | ||
533 | LAL_INTERFACE_ADDRESS, | ||
534 | &s6->sin6_addr, | ||
535 | sizeof (struct in6_addr)); | ||
536 | break; | ||
537 | default: | ||
538 | GNUNET_break (0); | ||
539 | break; | ||
282 | } | 540 | } |
283 | else if (h->ext_addr_natpmp | 541 | if ( (h->internal_address == NULL) && |
284 | && GNUNET_NAT_cmp_addr (h->ext_addr, h->ext_addr_natpmp) != 0) | 542 | (h->server_proc == NULL) && |
543 | (h->server_read_task == GNUNET_SCHEDULER_NO_TASK) && | ||
544 | (GNUNET_YES == isDefault) && | ||
545 | ( (addr->sa_family == AF_INET) || (addr->sa_family == AF_INET6) ) ) | ||
285 | { | 546 | { |
286 | addrlen = h->ext_addr_natpmp->sa_family == AF_INET ? | 547 | /* no internal address configured, but we found a "default" |
287 | sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6); | 548 | interface, try using that as our 'internal' address */ |
288 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "NAT", | 549 | h->internal_address = GNUNET_strdup (inet_ntop (addr->sa_family, |
289 | _("External IP address changed to `%s'\n"), | 550 | ip, |
290 | GNUNET_a2s (h->ext_addr_natpmp, addrlen)); | 551 | buf, |
291 | notify_change (h, h->ext_addr_natpmp, addrlen, port_mapped); | 552 | sizeof (buf))); |
553 | start_gnunet_nat_server (h); | ||
292 | } | 554 | } |
293 | 555 | return GNUNET_OK; | |
294 | h->pulse_timer = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
295 | &nat_pulse, h); | ||
296 | } | 556 | } |
297 | 557 | ||
298 | static void | 558 | |
299 | upnp_pulse_cb (int status, struct sockaddr *ext_addr, void *cls) | 559 | /** |
560 | * Return the actual path to a file found in the current | ||
561 | * PATH environment variable. | ||
562 | * | ||
563 | * @param binary the name of the file to find | ||
564 | * @return path to binary, NULL if not found | ||
565 | */ | ||
566 | static char * | ||
567 | get_path_from_PATH (const char *binary) | ||
300 | { | 568 | { |
301 | struct GNUNET_NAT_Handle *h = cls; | 569 | char *path; |
570 | char *pos; | ||
571 | char *end; | ||
572 | char *buf; | ||
573 | const char *p; | ||
574 | |||
575 | p = getenv ("PATH"); | ||
576 | if (p == NULL) | ||
577 | { | ||
578 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
579 | "tcp", | ||
580 | _("PATH environment variable is unset.\n")); | ||
581 | return NULL; | ||
582 | } | ||
583 | path = GNUNET_strdup (p); /* because we write on it */ | ||
584 | buf = GNUNET_malloc (strlen (path) + 20); | ||
585 | pos = path; | ||
586 | |||
587 | while (NULL != (end = strchr (pos, PATH_SEPARATOR))) | ||
588 | { | ||
589 | *end = '\0'; | ||
590 | sprintf (buf, "%s/%s", pos, binary); | ||
591 | if (GNUNET_DISK_file_test (buf) == GNUNET_YES) | ||
592 | { | ||
593 | GNUNET_free (path); | ||
594 | return buf; | ||
595 | } | ||
596 | pos = end + 1; | ||
597 | } | ||
598 | sprintf (buf, "%s/%s", pos, binary); | ||
599 | if (GNUNET_DISK_file_test (buf) == GNUNET_YES) | ||
600 | { | ||
601 | GNUNET_free (path); | ||
602 | return buf; | ||
603 | } | ||
604 | GNUNET_free (buf); | ||
605 | GNUNET_free (path); | ||
606 | return NULL; | ||
607 | } | ||
302 | 608 | ||
303 | h->upnp_status = status; | ||
304 | h->ext_addr_upnp = ext_addr; | ||
305 | 609 | ||
306 | h->processing--; | 610 | /** |
307 | pulse_cb (h); | 611 | * Check whether the suid bit is set on a file. |
612 | * Attempts to find the file using the current | ||
613 | * PATH environment variable as a search path. | ||
614 | * | ||
615 | * @param binary the name of the file to check | ||
616 | * @return GNUNET_YES if the file is SUID, | ||
617 | * GNUNET_NO if not, | ||
618 | * GNUNET_SYSERR on error | ||
619 | */ | ||
620 | static int | ||
621 | check_gnunet_nat_binary (const char *binary) | ||
622 | { | ||
623 | struct stat statbuf; | ||
624 | char *p; | ||
625 | #ifdef MINGW | ||
626 | SOCKET rawsock; | ||
627 | char *binaryexe; | ||
628 | |||
629 | GNUNET_asprintf (&binaryexe, "%s.exe", binary); | ||
630 | p = get_path_from_PATH (binaryexe); | ||
631 | free (binaryexe); | ||
632 | #else | ||
633 | p = get_path_from_PATH (binary); | ||
634 | #endif | ||
635 | if (p == NULL) | ||
636 | { | ||
637 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
638 | "tcp", | ||
639 | _("Could not find binary `%s' in PATH!\n"), | ||
640 | binary); | ||
641 | return GNUNET_NO; | ||
642 | } | ||
643 | if (0 != STAT (p, &statbuf)) | ||
644 | { | ||
645 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
646 | _("stat (%s) failed: %s\n"), | ||
647 | p, | ||
648 | STRERROR (errno)); | ||
649 | GNUNET_free (p); | ||
650 | return GNUNET_SYSERR; | ||
651 | } | ||
652 | GNUNET_free (p); | ||
653 | #ifndef MINGW | ||
654 | if ( (0 != (statbuf.st_mode & S_ISUID)) && | ||
655 | (statbuf.st_uid == 0) ) | ||
656 | return GNUNET_YES; | ||
657 | return GNUNET_NO; | ||
658 | #else | ||
659 | rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); | ||
660 | if (INVALID_SOCKET == rawsock) | ||
661 | { | ||
662 | DWORD err = GetLastError (); | ||
663 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | ||
664 | "tcp", | ||
665 | "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) failed! GLE = %d\n", err); | ||
666 | return GNUNET_NO; /* not running as administrator */ | ||
667 | } | ||
668 | closesocket (rawsock); | ||
669 | return GNUNET_YES; | ||
670 | #endif | ||
308 | } | 671 | } |
309 | 672 | ||
310 | #if 0 | 673 | |
674 | /** | ||
675 | * Task that restarts the gnunet-nat-server process after a crash | ||
676 | * after a certain delay. | ||
677 | * | ||
678 | * @param cls the 'struct GNUNET_NAT_Handle' | ||
679 | * @param tc scheduler context | ||
680 | */ | ||
311 | static void | 681 | static void |
312 | natpmp_pulse_cb (int status, struct sockaddr *ext_addr, void *cls) | 682 | restart_nat_server (void *cls, |
683 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
313 | { | 684 | { |
314 | struct GNUNET_NAT_Handle *h = cls; | 685 | struct GNUNET_NAT_Handle *h = cls; |
315 | 686 | ||
316 | h->natpmp_status = status; | 687 | h->server_read_task = GNUNET_SCHEDULER_NO_TASK; |
317 | h->ext_addr_natpmp = ext_addr; | 688 | if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) |
318 | 689 | return; | |
319 | h->processing--; | 690 | start_gnunet_nat_server (h); |
320 | pulse_cb (h); | ||
321 | } | 691 | } |
322 | #endif | ||
323 | 692 | ||
693 | |||
694 | /** | ||
695 | * We have been notified that gnunet-nat-server has written something to stdout. | ||
696 | * Handle the output, then reschedule this function to be called again once | ||
697 | * more is available. | ||
698 | * | ||
699 | * @param cls the NAT handle | ||
700 | * @param tc the scheduling context | ||
701 | */ | ||
324 | static void | 702 | static void |
325 | nat_pulse (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 703 | nat_server_read (void *cls, |
704 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
326 | { | 705 | { |
327 | struct GNUNET_NAT_Handle *h = cls; | 706 | struct GNUNET_NAT_Handle *h = cls; |
328 | 707 | char mybuf[40]; | |
329 | /* Stop if we're already waiting for an action to complete */ | 708 | ssize_t bytes; |
330 | h->pulse_timer = GNUNET_SCHEDULER_NO_TASK; | 709 | size_t i; |
331 | if (h->processing) | 710 | int port; |
711 | const char *port_start; | ||
712 | struct sockaddr_in sin_addr; | ||
713 | |||
714 | h->server_read_task = GNUNET_SCHEDULER_NO_TASK; | ||
715 | if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
332 | return; | 716 | return; |
333 | h->old_status = get_traversal_status (h); | 717 | memset (mybuf, 0, sizeof(mybuf)); |
334 | 718 | bytes = GNUNET_DISK_file_read(h->server_stdout_handle, | |
335 | /* Only update the protocol that has been successful until now */ | 719 | mybuf, |
336 | if (h->upnp_status >= GNUNET_NAT_PORT_UNMAPPED) | 720 | sizeof(mybuf)); |
721 | if (bytes < 1) | ||
337 | { | 722 | { |
338 | h->processing = 1; | 723 | #if DEBUG_TCP_NAT |
339 | GNUNET_NAT_UPNP_pulse (h->upnp, h->is_enabled, GNUNET_YES); | 724 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, |
340 | 725 | "nat", | |
341 | /* Wait for the callback to call pulse_cb() to handle changes */ | 726 | "Finished reading from server stdout with code: %d\n", |
727 | bytes); | ||
728 | #endif | ||
729 | if (0 != GNUNET_OS_process_kill (h->server_proc, SIGTERM)) | ||
730 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
731 | GNUNET_OS_process_wait (h->server_proc); | ||
732 | GNUNET_OS_process_close (h->server_proc); | ||
733 | h->server_proc = NULL; | ||
734 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
735 | h->server_stdout = NULL; | ||
736 | h->server_stdout_handle = NULL; | ||
737 | /* now try to restart it */ | ||
738 | h->server_retry_delay = GNUNET_TIME_relative_multiply (h->server_retry_delay, 2); | ||
739 | h->server_retry_delay = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_HOURS, | ||
740 | h->server_retry_delay); | ||
741 | h->server_read_task = GNUNET_SCHEDULER_add_delayed (h->server_retry_delay, | ||
742 | &restart_nat_server, | ||
743 | h); | ||
342 | return; | 744 | return; |
343 | } | 745 | } |
344 | else if (h->natpmp_status >= GNUNET_NAT_PORT_UNMAPPED) | 746 | |
747 | port_start = NULL; | ||
748 | for (i = 0; i < sizeof(mybuf); i++) | ||
345 | { | 749 | { |
346 | h->processing = 1; | 750 | if (mybuf[i] == '\n') |
347 | #if 0 | 751 | { |
348 | GNUNET_NAT_NATPMP_pulse (h->natpmp, h->is_enabled); | 752 | mybuf[i] = '\0'; |
349 | #endif | 753 | break; |
754 | } | ||
755 | if ( (mybuf[i] == ':') && (i + 1 < sizeof(mybuf)) ) | ||
756 | { | ||
757 | mybuf[i] = '\0'; | ||
758 | port_start = &mybuf[i + 1]; | ||
759 | } | ||
350 | } | 760 | } |
351 | else /* try both */ | ||
352 | { | ||
353 | h->processing = 2; | ||
354 | 761 | ||
355 | GNUNET_NAT_UPNP_pulse (h->upnp, h->is_enabled, GNUNET_YES); | 762 | /* construct socket address of sender */ |
356 | #if 0 | 763 | memset (&sin_addr, 0, sizeof (sin_addr)); |
357 | GNUNET_NAT_NATPMP_pulse (h->natpmp, h->is_enabled, &natpmp_pulse_cb, h); | 764 | sin_addr.sin_family = AF_INET; |
765 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
766 | sin_addr.sin_len = sizeof (sin_addr); | ||
358 | #endif | 767 | #endif |
768 | if ( (NULL == port_start) || | ||
769 | (1 != sscanf (port_start, "%d", &port)) || | ||
770 | (-1 == inet_pton(AF_INET, mybuf, &sin_addr.sin_addr)) ) | ||
771 | { | ||
772 | /* should we restart gnunet-nat-server? */ | ||
773 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | ||
774 | "nat", | ||
775 | _("gnunet-nat-server generated malformed address `%s'\n"), | ||
776 | mybuf); | ||
777 | h->server_read_task | ||
778 | = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
779 | h->server_stdout_handle, | ||
780 | &nat_server_read, | ||
781 | h); | ||
782 | return; | ||
359 | } | 783 | } |
784 | sin_addr.sin_port = htons((uint16_t) port); | ||
785 | #if DEBUG_NAT | ||
786 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
787 | "nat", | ||
788 | "gnunet-nat-server read: %s:%d\n", | ||
789 | mybuf, port); | ||
790 | #endif | ||
791 | h->reversal_callback (h->callback_cls, | ||
792 | (const struct sockaddr*) &sin_addr, | ||
793 | sizeof (sin_addr)); | ||
794 | h->server_read_task = | ||
795 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
796 | h->server_stdout_handle, | ||
797 | &nat_server_read, | ||
798 | h); | ||
799 | } | ||
800 | |||
801 | |||
802 | /** | ||
803 | * Try to start the gnunet-nat-server (if it is not | ||
804 | * already running). | ||
805 | * | ||
806 | * @param h handle to NAT | ||
807 | */ | ||
808 | static void | ||
809 | start_gnunet_nat_server (struct GNUNET_NAT_Handle *h) | ||
810 | { | ||
811 | if ( (h->behind_nat == GNUNET_YES) && | ||
812 | (h->enable_nat_server == GNUNET_YES) && | ||
813 | (h->internal_address != NULL) && | ||
814 | (NULL != (h->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, | ||
815 | GNUNET_NO, | ||
816 | GNUNET_YES))) ) | ||
817 | { | ||
818 | #if DEBUG_NAT | ||
819 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
820 | "nat" | ||
821 | "Starting %s at `%s'\n", | ||
822 | "gnunet-nat-server", | ||
823 | h->internal_address); | ||
824 | #endif | ||
825 | /* Start the server process */ | ||
826 | h->server_proc = GNUNET_OS_start_process (NULL, | ||
827 | h->server_stdout, | ||
828 | "gnunet-nat-server", | ||
829 | "gnunet-nat-server", | ||
830 | h->internal_address, | ||
831 | NULL); | ||
832 | if (h->server_proc == NULL) | ||
833 | { | ||
834 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | ||
835 | "nat", | ||
836 | _("Failed to start %s\n"), | ||
837 | "gnunet-nat-server"); | ||
838 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
839 | h->server_stdout = NULL; | ||
840 | } | ||
841 | else | ||
842 | { | ||
843 | /* Close the write end of the read pipe */ | ||
844 | GNUNET_DISK_pipe_close_end(h->server_stdout, | ||
845 | GNUNET_DISK_PIPE_END_WRITE); | ||
846 | h->server_stdout_handle | ||
847 | = GNUNET_DISK_pipe_handle (h->server_stdout, | ||
848 | GNUNET_DISK_PIPE_END_READ); | ||
849 | h->server_read_task | ||
850 | = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
851 | h->server_stdout_handle, | ||
852 | &nat_server_read, | ||
853 | h); | ||
854 | } | ||
855 | } | ||
360 | } | 856 | } |
361 | 857 | ||
362 | 858 | ||
@@ -367,55 +863,165 @@ nat_pulse (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
367 | * is taken from the corresponding sockaddr_in[6] field. | 863 | * is taken from the corresponding sockaddr_in[6] field. |
368 | * | 864 | * |
369 | * @param cfg configuration to use | 865 | * @param cfg configuration to use |
866 | * @param is_tcp GNUNET_YES for TCP, GNUNET_NO for UDP | ||
867 | * @param adv_port advertised port (port we are either bound to or that our OS | ||
868 | * locally performs redirection from to our bound port). | ||
869 | * @param num_addrs number of addresses in 'addrs' | ||
370 | * @param addr the local address packets should be redirected to | 870 | * @param addr the local address packets should be redirected to |
371 | * @param addrlen actual lenght of the address | 871 | * @param addrlen actual lenght of the address |
372 | * @param callback function to call everytime the public IP address changes | 872 | * @param address_callback function to call everytime the public IP address changes |
373 | * @param callback_cls closure for callback | 873 | * @param reversal_callback function to call if someone wants connection reversal from us |
874 | * @param callback_cls closure for callbacks | ||
374 | * @return NULL on error, otherwise handle that can be used to unregister | 875 | * @return NULL on error, otherwise handle that can be used to unregister |
375 | */ | 876 | */ |
376 | struct GNUNET_NAT_Handle * | 877 | struct GNUNET_NAT_Handle * |
377 | GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, | 878 | GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, |
378 | const struct sockaddr *addr, | 879 | int is_tcp, |
379 | socklen_t addrlen, | 880 | uint16_t adv_port, |
380 | GNUNET_NAT_AddressCallback callback, void *callback_cls) | 881 | unsigned int num_addrs, |
882 | const struct sockaddr **addrs, | ||
883 | const socklen_t *addrlens, | ||
884 | GNUNET_NAT_AddressCallback address_callback, | ||
885 | GNUNET_NAT_ReversalCallback reversal_callback, | ||
886 | void *callback_cls) | ||
381 | { | 887 | { |
382 | struct GNUNET_NAT_Handle *h; | 888 | struct GNUNET_NAT_Handle *h; |
889 | struct in_addr in_addr; | ||
890 | unsigned int i; | ||
383 | 891 | ||
384 | h = GNUNET_malloc (sizeof (struct GNUNET_NAT_Handle)); | 892 | h = GNUNET_malloc (sizeof (struct GNUNET_NAT_Handle)); |
893 | h->server_retry_delay = GNUNET_TIME_UNIT_SECONDS; | ||
894 | h->cfg = cfg; | ||
895 | h->is_tcp = is_tcp; | ||
896 | h->address_callback = address_callback; | ||
897 | h->reversal_callback = reversal_callback; | ||
898 | h->callback_cls = callback_cls; | ||
899 | h->num_local_addrs = num_addrs; | ||
900 | h->adv_port = adv_port; | ||
901 | if (num_addrs != 0) | ||
902 | { | ||
903 | h->local_addrs = GNUNET_malloc (num_addrs * sizeof (struct sockaddr*)); | ||
904 | h->local_addrlens = GNUNET_malloc (num_addrs * sizeof (socklen_t)); | ||
905 | for (i=0;i<num_addrs;i++) | ||
906 | { | ||
907 | h->local_addrlens[i] = addrlens[i]; | ||
908 | h->local_addrs[i] = GNUNET_malloc (addrlens[i]); | ||
909 | memcpy (h->local_addrs[i], addrs[i], addrlens[i]); | ||
910 | } | ||
911 | } | ||
385 | 912 | ||
386 | if (addr) | 913 | if (GNUNET_OK == |
914 | GNUNET_CONFIGURATION_have_value (cfg, | ||
915 | "nat", | ||
916 | "INTERNAL_ADDRESS")) | ||
387 | { | 917 | { |
388 | GNUNET_assert ((addr->sa_family == AF_INET) || | 918 | (void) GNUNET_CONFIGURATION_get_value_string (cfg, |
389 | (addr->sa_family == AF_INET6)); | 919 | "nat", |
390 | h->local_addr = GNUNET_malloc (addrlen); | 920 | "INTERNAL_ADDRESS", |
391 | memcpy (h->local_addr, addr, addrlen); | 921 | &h->internal_address); |
392 | if (addr->sa_family == AF_INET) | 922 | } |
393 | { | 923 | if ( (h->internal_address != NULL) && |
394 | h->public_port = ntohs (((struct sockaddr_in *) addr)->sin_port); | 924 | (inet_pton(AF_INET, h->internal_address, &in_addr) != 1) ) |
395 | ((struct sockaddr_in *) h->local_addr)->sin_port = 0; | 925 | { |
396 | } | 926 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, |
397 | else if (addr->sa_family == AF_INET6) | 927 | "nat", |
398 | { | 928 | _("Malformed %s `%s' given in configuration!\n"), |
399 | h->public_port = ntohs (((struct sockaddr_in6 *) addr)->sin6_port); | 929 | "INTERNAL_ADDRESS", |
400 | ((struct sockaddr_in6 *) h->local_addr)->sin6_port = 0; | 930 | h->internal_address); |
401 | } | 931 | GNUNET_free (h->internal_address); |
932 | h->internal_address = NULL; | ||
933 | } | ||
934 | |||
935 | if (GNUNET_OK == | ||
936 | GNUNET_CONFIGURATION_have_value (cfg, | ||
937 | "nat", | ||
938 | "EXTERNAL_ADDRESS")) | ||
939 | { | ||
940 | (void) GNUNET_CONFIGURATION_get_value_string (cfg, | ||
941 | "nat", | ||
942 | "EXTERNAL_ADDRESS", | ||
943 | &h->external_address); | ||
944 | } | ||
945 | if ( (h->external_address != NULL) && | ||
946 | (inet_pton(AF_INET, h->external_address, &in_addr) != 1) ) | ||
947 | { | ||
948 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | ||
949 | "nat", | ||
950 | _("Malformed %s `%s' given in configuration!\n"), | ||
951 | "EXTERNAL_ADDRESS", | ||
952 | h->external_address); | ||
953 | GNUNET_free (h->external_address); | ||
954 | h->external_address = NULL; | ||
955 | } | ||
956 | h->behind_nat = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
957 | "nat", | ||
958 | "BEHIND_NAT"); | ||
959 | h->nat_punched = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
960 | "nat", | ||
961 | "NAT_PUNCHED"); | ||
962 | h->enable_nat_client = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
963 | "nat", | ||
964 | "ENABLE_NAT_CLIENT"); | ||
965 | h->enable_nat_server = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
966 | "nat", | ||
967 | "ENABLE_NAT_SERVER"); | ||
968 | h->enable_upnp = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
969 | "nat", | ||
970 | "ENABLE_UPNP"); | ||
971 | h->use_localaddresses = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
972 | "nat", | ||
973 | "USE_LOCALADDR"); | ||
974 | h->disable_ipv6 = GNUNET_CONFIGURATION_get_value_yesno(cfg, | ||
975 | "nat", | ||
976 | "DISABLEV6"); | ||
977 | if (NULL == reversal_callback) | ||
978 | h->enable_nat_server = GNUNET_NO; | ||
979 | |||
980 | /* Check if NAT was hole-punched */ | ||
981 | if ( (NULL != h->address_callback) && | ||
982 | (h->external_address != NULL) && | ||
983 | (h->nat_punched == GNUNET_YES) ) | ||
984 | { | ||
985 | h->ext_dns = GNUNET_RESOLVER_ip_get (h->external_address, | ||
986 | AF_INET, | ||
987 | GNUNET_TIME_UNIT_MINUTES, | ||
988 | &process_external_ip, | ||
989 | h); | ||
990 | h->enable_nat_server = GNUNET_NO; | ||
991 | h->enable_upnp = GNUNET_NO; | ||
992 | } | ||
993 | |||
994 | /* Test for SUID binaries */ | ||
995 | if ( (h->behind_nat == GNUNET_YES) && | ||
996 | (GNUNET_YES == h->enable_nat_server) && | ||
997 | (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-server")) ) | ||
998 | { | ||
999 | h->enable_nat_server = GNUNET_NO; | ||
1000 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1001 | _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), | ||
1002 | "gnunet-nat-server"); | ||
1003 | } | ||
1004 | if ( (GNUNET_YES == h->enable_nat_client) && | ||
1005 | (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-client")) ) | ||
1006 | { | ||
1007 | h->enable_nat_client = GNUNET_NO; | ||
1008 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1009 | _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), | ||
1010 | "gnunet-nat-client"); | ||
1011 | } | ||
1012 | |||
1013 | start_gnunet_nat_server (h); | ||
1014 | |||
1015 | /* FIXME: add support for UPnP, etc */ | ||
1016 | |||
1017 | if (NULL != h->address_callback) | ||
1018 | { | ||
1019 | GNUNET_OS_network_interfaces_list (&process_interfaces, h); | ||
1020 | h->hostname_dns = GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, | ||
1021 | HOSTNAME_RESOLVE_TIMEOUT, | ||
1022 | &process_hostname_ip, | ||
1023 | h); | ||
402 | } | 1024 | } |
403 | h->should_change = GNUNET_YES; | ||
404 | h->is_enabled = GNUNET_YES; | ||
405 | h->upnp_status = GNUNET_NAT_PORT_UNMAPPED; | ||
406 | h->natpmp_status = GNUNET_NAT_PORT_UNMAPPED; | ||
407 | h->callback = callback; | ||
408 | h->callback_cls = callback_cls; | ||
409 | h->upnp = | ||
410 | GNUNET_NAT_UPNP_init (h->local_addr, addrlen, h->public_port, | ||
411 | &upnp_pulse_cb, h); | ||
412 | #if 0 | ||
413 | h->natpmp = | ||
414 | GNUNET_NAT_NATPMP_init (h->local_addr, addrlen, h->public_port, | ||
415 | &natpmp_pulse_cb, h); | ||
416 | #endif | ||
417 | h->pulse_timer = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
418 | &nat_pulse, h); | ||
419 | return h; | 1025 | return h; |
420 | } | 1026 | } |
421 | 1027 | ||
@@ -429,22 +1035,175 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
429 | void | 1035 | void |
430 | GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h) | 1036 | GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h) |
431 | { | 1037 | { |
432 | GNUNET_NAT_UPNP_pulse (h->upnp, GNUNET_NO, GNUNET_NO); | 1038 | unsigned int i; |
433 | GNUNET_NAT_UPNP_close (h->upnp); | 1039 | struct LocalAddressList *lal; |
434 | 1040 | ||
435 | #if 0 | 1041 | if (h->ext_dns != NULL) |
436 | GNUNET_NAT_NATPMP_pulse (h->natpmp, GNUNET_NO); | 1042 | { |
437 | GNUNET_NAT_NATPMP_close (h->natpmp); | 1043 | GNUNET_RESOLVER_request_cancel (h->ext_dns); |
1044 | h->ext_dns = NULL; | ||
1045 | } | ||
1046 | if (NULL != h->hostname_dns) | ||
1047 | { | ||
1048 | GNUNET_RESOLVER_request_cancel (h->hostname_dns); | ||
1049 | h->hostname_dns = NULL; | ||
1050 | } | ||
1051 | if (GNUNET_SCHEDULER_NO_TASK != h->server_read_task) | ||
1052 | { | ||
1053 | GNUNET_SCHEDULER_cancel (h->server_read_task); | ||
1054 | h->server_read_task = GNUNET_SCHEDULER_NO_TASK; | ||
1055 | } | ||
1056 | if (NULL != h->server_proc) | ||
1057 | { | ||
1058 | if (0 != GNUNET_OS_process_kill (h->server_proc, SIGTERM)) | ||
1059 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
1060 | GNUNET_OS_process_wait (h->server_proc); | ||
1061 | GNUNET_OS_process_close (h->server_proc); | ||
1062 | h->server_proc = NULL; | ||
1063 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
1064 | h->server_stdout = NULL; | ||
1065 | h->server_stdout_handle = NULL; | ||
1066 | } | ||
1067 | if (NULL != h->server_stdout) | ||
1068 | { | ||
1069 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
1070 | h->server_stdout = NULL; | ||
1071 | h->server_stdout_handle = NULL; | ||
1072 | } | ||
1073 | while (NULL != (lal = h->lal_head)) | ||
1074 | { | ||
1075 | GNUNET_CONTAINER_DLL_remove (h->lal_head, | ||
1076 | h->lal_tail, | ||
1077 | lal); | ||
1078 | h->address_callback (h->callback_cls, | ||
1079 | GNUNET_NO, | ||
1080 | (const struct sockaddr*) &lal[1], | ||
1081 | lal->addrlen); | ||
1082 | GNUNET_free (lal); | ||
1083 | } | ||
1084 | for (i=0;i<h->num_local_addrs;i++) | ||
1085 | GNUNET_free (h->local_addrs[i]); | ||
1086 | GNUNET_free_non_null (h->local_addrs); | ||
1087 | GNUNET_free_non_null (h->local_addrlens); | ||
1088 | GNUNET_free_non_null (h->external_address); | ||
1089 | GNUNET_free_non_null (h->internal_address); | ||
1090 | GNUNET_free (h); | ||
1091 | } | ||
1092 | |||
1093 | |||
1094 | /** | ||
1095 | * We learned about a peer (possibly behind NAT) so run the | ||
1096 | * gnunet-nat-client to send dummy ICMP responses to cause | ||
1097 | * that peer to connect to us (connection reversal). | ||
1098 | * | ||
1099 | * @param h NAT handle for us (largely used for configuration) | ||
1100 | * @param sa the address of the peer (IPv4-only) | ||
1101 | */ | ||
1102 | void | ||
1103 | GNUNET_NAT_run_client (struct GNUNET_NAT_Handle *h, | ||
1104 | const struct sockaddr_in *sa) | ||
1105 | { | ||
1106 | char inet4[INET_ADDRSTRLEN]; | ||
1107 | char port_as_string[6]; | ||
1108 | struct GNUNET_OS_Process *proc; | ||
1109 | |||
1110 | if (GNUNET_YES != h->enable_nat_client) | ||
1111 | return; /* not permitted / possible */ | ||
1112 | |||
1113 | if (h->internal_address == NULL) | ||
1114 | { | ||
1115 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | ||
1116 | "nat", | ||
1117 | _("Internal IP address not known, cannot use ICMP NAT traversal method\n")); | ||
1118 | return; | ||
1119 | } | ||
1120 | GNUNET_assert (sa->sin_family == AF_INET); | ||
1121 | if (NULL == inet_ntop (AF_INET, | ||
1122 | &sa->sin_addr, | ||
1123 | inet4, INET_ADDRSTRLEN)) | ||
1124 | { | ||
1125 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); | ||
1126 | return; | ||
1127 | } | ||
1128 | GNUNET_snprintf(port_as_string, | ||
1129 | sizeof (port_as_string), | ||
1130 | "%d", | ||
1131 | h->adv_port); | ||
1132 | #if DEBUG_TCP_NAT | ||
1133 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
1134 | "nat", | ||
1135 | _("Running gnunet-nat-client %s %s %u\n"), | ||
1136 | h->internal_address, | ||
1137 | inet4, | ||
1138 | (unsigned int) h->adv_port); | ||
438 | #endif | 1139 | #endif |
1140 | proc = GNUNET_OS_start_process (NULL, | ||
1141 | NULL, | ||
1142 | "gnunet-nat-client", | ||
1143 | "gnunet-nat-client", | ||
1144 | h->internal_address, | ||
1145 | inet4, | ||
1146 | port_as_string, | ||
1147 | NULL); | ||
1148 | if (NULL == proc) | ||
1149 | return; | ||
1150 | /* we know that the gnunet-nat-client will terminate virtually | ||
1151 | instantly */ | ||
1152 | GNUNET_OS_process_wait (proc); | ||
1153 | GNUNET_OS_process_close (proc); | ||
1154 | } | ||
439 | 1155 | ||
440 | if (GNUNET_SCHEDULER_NO_TASK != h->pulse_timer) | ||
441 | GNUNET_SCHEDULER_cancel (h->pulse_timer); | ||
442 | 1156 | ||
443 | GNUNET_free_non_null (h->local_addr); | 1157 | /** |
444 | GNUNET_free_non_null (h->ext_addr); | 1158 | * Test if the given address is (currently) a plausible IP address for this peer. |
445 | GNUNET_free_non_null (h->ext_addr_upnp); | 1159 | * |
446 | GNUNET_free_non_null (h->ext_addr_natpmp); | 1160 | * @param h the handle returned by register |
447 | GNUNET_free (h); | 1161 | * @param addr IP address to test (IPv4 or IPv6) |
1162 | * @param addrlen number of bytes in addr | ||
1163 | * @return GNUNET_YES if the address is plausible, | ||
1164 | * GNUNET_NO if the address is not plausible, | ||
1165 | * GNUNET_SYSERR if the address is malformed | ||
1166 | */ | ||
1167 | int | ||
1168 | GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *h, | ||
1169 | const void *addr, | ||
1170 | socklen_t addrlen) | ||
1171 | { | ||
1172 | struct LocalAddressList *pos; | ||
1173 | const struct sockaddr_in *in4; | ||
1174 | const struct sockaddr_in6 *in6; | ||
1175 | |||
1176 | if ( (addrlen != sizeof (struct in_addr)) && | ||
1177 | (addrlen != sizeof (struct in6_addr)) ) | ||
1178 | { | ||
1179 | GNUNET_break (0); | ||
1180 | return GNUNET_SYSERR; | ||
1181 | } | ||
1182 | pos = h->lal_head; | ||
1183 | while (NULL != pos) | ||
1184 | { | ||
1185 | if (pos->addrlen == sizeof (struct sockaddr_in)) | ||
1186 | { | ||
1187 | in4 = (struct sockaddr_in* ) &pos[1]; | ||
1188 | if ( (addrlen == sizeof (struct in_addr)) && | ||
1189 | (0 == memcmp (&in4->sin_addr, addr, sizeof (struct in_addr))) ) | ||
1190 | return GNUNET_YES; | ||
1191 | } | ||
1192 | else if (pos->addrlen == sizeof (struct sockaddr_in6)) | ||
1193 | { | ||
1194 | in6 = (struct sockaddr_in6* ) &pos[1]; | ||
1195 | if ( (addrlen == sizeof (struct in6_addr)) && | ||
1196 | (0 == memcmp (&in6->sin6_addr, addr, sizeof (struct in6_addr))) ) | ||
1197 | return GNUNET_YES; | ||
1198 | } | ||
1199 | else | ||
1200 | { | ||
1201 | GNUNET_assert (0); | ||
1202 | } | ||
1203 | pos = pos->next; | ||
1204 | } | ||
1205 | return GNUNET_YES; | ||
448 | } | 1206 | } |
449 | 1207 | ||
1208 | |||
450 | /* end of nat.c */ | 1209 | /* end of nat.c */ |
diff --git a/src/nat/nat.h b/src/nat/nat.h deleted file mode 100644 index 3a0f21e7b..000000000 --- a/src/nat/nat.h +++ /dev/null | |||
@@ -1,72 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2007, 2008, 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 | * @file nat/nat.h | ||
23 | * @brief Library handling UPnP and NAT-PMP port forwarding and | ||
24 | * external IP address retrieval | ||
25 | * @author Milan Bouchet-Valat | ||
26 | */ | ||
27 | |||
28 | #ifndef NAT_H | ||
29 | #define NAT_H | ||
30 | |||
31 | #define DEBUG GNUNET_YES | ||
32 | |||
33 | /** | ||
34 | * Used to communicate with the UPnP and NAT-PMP plugins | ||
35 | */ | ||
36 | enum GNUNET_NAT_PortState | ||
37 | { | ||
38 | GNUNET_NAT_PORT_ERROR, | ||
39 | |||
40 | /** | ||
41 | * the port isn't forwarded | ||
42 | */ | ||
43 | GNUNET_NAT_PORT_UNMAPPED, | ||
44 | |||
45 | /** | ||
46 | * we're cancelling the port forwarding | ||
47 | */ | ||
48 | GNUNET_NAT_PORT_UNMAPPING, | ||
49 | |||
50 | /** | ||
51 | * we're in the process of trying to set up port forwarding | ||
52 | */ | ||
53 | GNUNET_NAT_PORT_MAPPING, | ||
54 | |||
55 | /** | ||
56 | * we've successfully forwarded the port | ||
57 | */ | ||
58 | GNUNET_NAT_PORT_MAPPED | ||
59 | }; | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Compare the sin(6)_addr fields of AF_INET or AF_INET(6) sockaddr. | ||
64 | * | ||
65 | * @param a first sockaddr | ||
66 | * @param b second sockaddr | ||
67 | * @return 0 if addresses are equal, non-null value otherwise | ||
68 | */ | ||
69 | int GNUNET_NAT_cmp_addr (const struct sockaddr *a, const struct sockaddr *b); | ||
70 | |||
71 | |||
72 | #endif | ||
diff --git a/src/nat/natpmp.c b/src/nat/natpmp.c deleted file mode 100644 index c6a5604d8..000000000 --- a/src/nat/natpmp.c +++ /dev/null | |||
@@ -1,325 +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/natpmp.c | ||
29 | * @brief NAT-PMP support for the NAT library | ||
30 | * | ||
31 | * @author Milan Bouchet-Valat | ||
32 | */ | ||
33 | #include <assert.h> | ||
34 | #include <errno.h> | ||
35 | #include <time.h> | ||
36 | #include <inttypes.h> | ||
37 | |||
38 | #define ENABLE_STRNATPMPERR | ||
39 | #include <libnatpmp/natpmp.h> | ||
40 | |||
41 | #include "platform.h" | ||
42 | #include "gnunet_common.h" | ||
43 | #include "gnunet_nat_lib.h" | ||
44 | #include "nat.h" | ||
45 | #include "natpmp.h" | ||
46 | |||
47 | #define LIFETIME_SECS 3600 | ||
48 | #define COMMAND_WAIT_SECS 8 | ||
49 | /* Component name for logging */ | ||
50 | #define COMP_NAT_NATPMP _("NAT (NAT-PMP))") | ||
51 | |||
52 | enum NATPMP_state | ||
53 | { | ||
54 | NATPMP_IDLE, | ||
55 | NATPMP_ERR, | ||
56 | NATPMP_DISCOVER, | ||
57 | NATPMP_RECV_PUB, | ||
58 | NATPMP_SEND_MAP, | ||
59 | NATPMP_RECV_MAP, | ||
60 | NATPMP_SEND_UNMAP, | ||
61 | NATPMP_RECV_UNMAP | ||
62 | } | ||
63 | ; | ||
64 | |||
65 | struct GNUNET_NAT_NATPMP_Handle | ||
66 | { | ||
67 | const struct sockaddr *addr; | ||
68 | socklen_t addrlen; | ||
69 | struct sockaddr *ext_addr; | ||
70 | int is_mapped; | ||
71 | int has_discovered; | ||
72 | int port; | ||
73 | time_t renew_time; | ||
74 | time_t command_time; | ||
75 | enum NATPMP_state state; | ||
76 | struct natpmp_t natpmp; | ||
77 | }; | ||
78 | |||
79 | |||
80 | static void | ||
81 | log_val (const char *func, int ret) | ||
82 | { | ||
83 | #ifdef DEBUG | ||
84 | if (ret == NATPMP_TRYAGAIN) | ||
85 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
86 | COMP_NAT_NATPMP, _("%s retry (%d)\n"), func, ret); | ||
87 | if (ret >= 0) | ||
88 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | ||
89 | COMP_NAT_NATPMP, _("%s succeeded (%d)\n"), func, ret); | ||
90 | else | ||
91 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
92 | COMP_NAT_NATPMP, | ||
93 | "%s failed. natpmp returned %d (%s); errno is %d (%s)\n", | ||
94 | func, ret, strnatpmperr (ret), errno, strerror (errno)); | ||
95 | #endif | ||
96 | } | ||
97 | |||
98 | struct GNUNET_NAT_NATPMP_Handle * | ||
99 | GNUNET_NAT_NATPMP_init (const struct sockaddr *addr, socklen_t addrlen, | ||
100 | u_short port) | ||
101 | { | ||
102 | struct GNUNET_NAT_NATPMP_Handle *nat; | ||
103 | |||
104 | nat = GNUNET_malloc (sizeof (struct GNUNET_NAT_NATPMP_Handle)); | ||
105 | nat->state = NATPMP_DISCOVER; | ||
106 | nat->port = port; | ||
107 | nat->addr = addr; | ||
108 | nat->addrlen = addrlen; | ||
109 | return nat; | ||
110 | } | ||
111 | |||
112 | void | ||
113 | GNUNET_NAT_NATPMP_close (struct GNUNET_NAT_NATPMP_Handle *nat) | ||
114 | { | ||
115 | if (nat) | ||
116 | { | ||
117 | closenatpmp (&nat->natpmp); | ||
118 | GNUNET_free (nat); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | static int | ||
123 | can_send_command (const struct GNUNET_NAT_NATPMP_Handle *nat) | ||
124 | { | ||
125 | return time (NULL) >= nat->command_time; | ||
126 | } | ||
127 | |||
128 | static void | ||
129 | set_command_time (struct GNUNET_NAT_NATPMP_Handle *nat) | ||
130 | { | ||
131 | nat->command_time = time (NULL) + COMMAND_WAIT_SECS; | ||
132 | } | ||
133 | |||
134 | int | ||
135 | GNUNET_NAT_NATPMP_pulse (struct GNUNET_NAT_NATPMP_Handle *nat, int is_enabled, | ||
136 | struct sockaddr **ext_addr) | ||
137 | { | ||
138 | #if DEBUG | ||
139 | char buf[INET6_ADDRSTRLEN]; | ||
140 | #endif | ||
141 | struct sockaddr_in *v4; | ||
142 | struct sockaddr_in6 *v6; | ||
143 | int ret; | ||
144 | |||
145 | /* Keep to NULL if address could not be found */ | ||
146 | *ext_addr = NULL; | ||
147 | |||
148 | if (is_enabled && (nat->state == NATPMP_DISCOVER)) | ||
149 | { | ||
150 | int val = initnatpmp (&nat->natpmp); | ||
151 | log_val ("initnatpmp", val); | ||
152 | val = sendpublicaddressrequest (&nat->natpmp); | ||
153 | log_val ("sendpublicaddressrequest", val); | ||
154 | nat->state = val < 0 ? NATPMP_ERR : NATPMP_RECV_PUB; | ||
155 | nat->has_discovered = 1; | ||
156 | set_command_time (nat); | ||
157 | } | ||
158 | |||
159 | if ((nat->state == NATPMP_RECV_PUB) && can_send_command (nat)) | ||
160 | { | ||
161 | struct natpmpresp_t response; | ||
162 | const int val = readnatpmpresponseorretry (&nat->natpmp, | ||
163 | &response); | ||
164 | log_val ("readnatpmpresponseorretry", val); | ||
165 | if (val >= 0) | ||
166 | { | ||
167 | if (NULL != nat->ext_addr) | ||
168 | { | ||
169 | GNUNET_free (nat->ext_addr); | ||
170 | nat->ext_addr = NULL; | ||
171 | } | ||
172 | |||
173 | if (response.pnu.publicaddress.family == AF_INET) | ||
174 | { | ||
175 | v4 = GNUNET_malloc (sizeof (struct sockaddr_in)); | ||
176 | nat->ext_addr = (struct sockaddr *) v4; | ||
177 | v4->sin_family = AF_INET; | ||
178 | v4->sin_port = response.pnu.newportmapping.mappedpublicport; | ||
179 | memcpy (&v4->sin_addr, &response.pnu.publicaddress.addr, | ||
180 | sizeof (struct in_addr)); | ||
181 | #ifdef DEBUG | ||
182 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_NATPMP, | ||
183 | _("Found public IP address %s\n"), | ||
184 | inet_ntop (AF_INET, | ||
185 | &response.pnu.publicaddress.addr, | ||
186 | buf, sizeof (buf))); | ||
187 | #endif | ||
188 | } | ||
189 | else | ||
190 | { | ||
191 | v6 = GNUNET_malloc (sizeof (struct sockaddr_in6)); | ||
192 | nat->ext_addr = (struct sockaddr *) v6; | ||
193 | v6->sin6_family = AF_INET6; | ||
194 | v6->sin6_port = response.pnu.newportmapping.mappedpublicport; | ||
195 | memcpy (&v6->sin6_addr, | ||
196 | &response.pnu.publicaddress.addr6, | ||
197 | (sizeof (struct in6_addr))); | ||
198 | #ifdef DEBUG | ||
199 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, COMP_NAT_NATPMP, | ||
200 | _("Found public IP address %s\n"), | ||
201 | inet_ntop (AF_INET6, | ||
202 | &response.pnu.publicaddress.addr6, | ||
203 | buf, sizeof (buf))); | ||
204 | #endif | ||
205 | } | ||
206 | *ext_addr = nat->ext_addr; | ||
207 | nat->state = NATPMP_IDLE; | ||
208 | } | ||
209 | else if (val != NATPMP_TRYAGAIN) | ||
210 | { | ||
211 | nat->state = NATPMP_ERR; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | if ((nat->state == NATPMP_IDLE) || (nat->state == NATPMP_ERR)) | ||
216 | { | ||
217 | if (nat->is_mapped && !is_enabled) | ||
218 | nat->state = NATPMP_SEND_UNMAP; | ||
219 | } | ||
220 | |||
221 | if ((nat->state == NATPMP_SEND_UNMAP) && can_send_command (nat)) | ||
222 | { | ||
223 | const int val = | ||
224 | sendnewportmappingrequest (&nat->natpmp, NATPMP_PROTOCOL_TCP, | ||
225 | nat->port, nat->port, | ||
226 | 0); | ||
227 | log_val ("sendnewportmappingrequest", val); | ||
228 | nat->state = val < 0 ? NATPMP_ERR : NATPMP_RECV_UNMAP; | ||
229 | set_command_time (nat); | ||
230 | } | ||
231 | |||
232 | if (nat->state == NATPMP_RECV_UNMAP) | ||
233 | { | ||
234 | struct natpmpresp_t resp; | ||
235 | const int val = readnatpmpresponseorretry (&nat->natpmp, &resp); | ||
236 | log_val ("readnatpmpresponseorretry", val); | ||
237 | if (val >= 0) | ||
238 | { | ||
239 | const int p = resp.pnu.newportmapping.privateport; | ||
240 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_NATPMP, | ||
241 | _("No longer forwarding port %d\n"), p); | ||
242 | if (nat->port == p) | ||
243 | { | ||
244 | nat->port = -1; | ||
245 | nat->state = NATPMP_IDLE; | ||
246 | nat->is_mapped = 0; | ||
247 | } | ||
248 | } | ||
249 | else if (val != NATPMP_TRYAGAIN) | ||
250 | { | ||
251 | nat->state = NATPMP_ERR; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | if (nat->state == NATPMP_IDLE) | ||
256 | { | ||
257 | if (is_enabled && !nat->is_mapped && nat->has_discovered) | ||
258 | nat->state = NATPMP_SEND_MAP; | ||
259 | |||
260 | else if (nat->is_mapped && time (NULL) >= nat->renew_time) | ||
261 | nat->state = NATPMP_SEND_MAP; | ||
262 | } | ||
263 | |||
264 | if ((nat->state == NATPMP_SEND_MAP) && can_send_command (nat)) | ||
265 | { | ||
266 | const int val = | ||
267 | sendnewportmappingrequest (&nat->natpmp, NATPMP_PROTOCOL_TCP, | ||
268 | nat->port, | ||
269 | nat->port, | ||
270 | LIFETIME_SECS); | ||
271 | log_val ("sendnewportmappingrequest", val); | ||
272 | nat->state = val < 0 ? NATPMP_ERR : NATPMP_RECV_MAP; | ||
273 | set_command_time (nat); | ||
274 | } | ||
275 | |||
276 | if (nat->state == NATPMP_RECV_MAP) | ||
277 | { | ||
278 | struct natpmpresp_t resp; | ||
279 | const int val = readnatpmpresponseorretry (&nat->natpmp, &resp); | ||
280 | log_val ("readnatpmpresponseorretry", val); | ||
281 | if (val >= 0) | ||
282 | { | ||
283 | nat->state = NATPMP_IDLE; | ||
284 | nat->is_mapped = 1; | ||
285 | nat->renew_time = time (NULL) + LIFETIME_SECS; | ||
286 | nat->port = resp.pnu.newportmapping.privateport; | ||
287 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, COMP_NAT_NATPMP, | ||
288 | _("Port %d forwarded successfully\n"), nat->port); | ||
289 | } | ||
290 | else if (val != NATPMP_TRYAGAIN) | ||
291 | { | ||
292 | nat->state = NATPMP_ERR; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | switch (nat->state) | ||
297 | { | ||
298 | case NATPMP_IDLE: | ||
299 | ret = | ||
300 | nat->is_mapped ? GNUNET_NAT_PORT_MAPPED : GNUNET_NAT_PORT_UNMAPPED; | ||
301 | break; | ||
302 | |||
303 | case NATPMP_DISCOVER: | ||
304 | ret = GNUNET_NAT_PORT_UNMAPPED; | ||
305 | break; | ||
306 | |||
307 | case NATPMP_RECV_PUB: | ||
308 | case NATPMP_SEND_MAP: | ||
309 | case NATPMP_RECV_MAP: | ||
310 | ret = GNUNET_NAT_PORT_MAPPING; | ||
311 | break; | ||
312 | |||
313 | case NATPMP_SEND_UNMAP: | ||
314 | case NATPMP_RECV_UNMAP: | ||
315 | ret = GNUNET_NAT_PORT_UNMAPPING; | ||
316 | break; | ||
317 | |||
318 | default: | ||
319 | ret = GNUNET_NAT_PORT_ERROR; | ||
320 | break; | ||
321 | } | ||
322 | return ret; | ||
323 | } | ||
324 | |||
325 | /* end of natpmp.c */ | ||
diff --git a/src/nat/natpmp.h b/src/nat/natpmp.h deleted file mode 100644 index 56d5f0034..000000000 --- a/src/nat/natpmp.h +++ /dev/null | |||
@@ -1,46 +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 | * @file nat/natpmp.h | ||
23 | * @brief NAT-PMP support for the NAT library | ||
24 | * | ||
25 | * @author Milan Bouchet-Valat | ||
26 | */ | ||
27 | |||
28 | #ifndef NATPMP_H | ||
29 | #define NATPMP_H 1 | ||
30 | |||
31 | #include "platform.h" | ||
32 | |||
33 | struct GNUNET_NAT_NATPMP_Handle; | ||
34 | |||
35 | struct GNUNET_NAT_NATPMP_Handle *GNUNET_NAT_NATPMP_init (const struct sockaddr | ||
36 | *addr, | ||
37 | socklen_t addrlen, | ||
38 | unsigned short port); | ||
39 | |||
40 | void GNUNET_NAT_NATPMP_close (struct GNUNET_NAT_NATPMP_Handle *nat); | ||
41 | |||
42 | int GNUNET_NAT_NATPMP_pulse (struct GNUNET_NAT_NATPMP_Handle *nat, | ||
43 | int is_enabled, struct sockaddr **ext_addr); | ||
44 | |||
45 | #endif | ||
46 | /* NATPMP_H */ | ||
diff --git a/src/nat/test-nat.conf b/src/nat/test-nat.conf deleted file mode 100644 index 311eb3c15..000000000 --- a/src/nat/test-nat.conf +++ /dev/null | |||
@@ -1,355 +0,0 @@ | |||
1 | [PATHS] | ||
2 | SERVICEHOME = /tmp/nat-test | ||
3 | # SERVICEHOME = /var/lib/gnunet/ | ||
4 | # DEFAULTCONFIG = /etc/gnunet.conf | ||
5 | # If 'DEFAULTCONFIG' is not defined, the current | ||
6 | # configuration file is assumed to be the default, | ||
7 | # which is what we want by default... | ||
8 | |||
9 | [gnunetd] | ||
10 | HOSTKEY = $SERVICEHOME/.hostkey | ||
11 | |||
12 | [TESTING] | ||
13 | WEAKRANDOM = NO | ||
14 | |||
15 | [client] | ||
16 | HOME = $SERVICEHOME | ||
17 | |||
18 | [transport-tcp] | ||
19 | # Use 0 to ONLY advertise as a peer behind NAT (no port binding) | ||
20 | PORT = 2086 | ||
21 | ADVERTISED_PORT = 2086 | ||
22 | |||
23 | # Are we behind NAT? | ||
24 | BEHIND_NAT = YES | ||
25 | |||
26 | # Is the NAT hole-punched? | ||
27 | PUNCHED_NAT = NO | ||
28 | |||
29 | # Disable UPNP by default until it gets cleaner! | ||
30 | ENABLE_UPNP = NO | ||
31 | |||
32 | # External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) | ||
33 | # normal interface IP address for non-NATed peers; | ||
34 | # possibly auto-detected (using UPnP) if possible if not specified | ||
35 | # EXTERNAL_ADDRESS = | ||
36 | |||
37 | # Should we use ICMP-based NAT traversal to try connect to NATed peers | ||
38 | # or, if we are behind NAT, to allow connections to us? | ||
39 | ENABLE_ICMP_CLIENT = YES | ||
40 | ENABLE_ICMP_SERVER = YES | ||
41 | |||
42 | # IP address of the interface connected to the NAT box; IPv4 dotted-decimal ONLY; | ||
43 | # normal interface IP address for non-NATed peers; | ||
44 | # likely auto-detected (via interface list) if not specified (!) | ||
45 | # INTERNAL_ADDRESS = | ||
46 | |||
47 | # Only bind to a specific IP address; if both are given, this should be idential to INTERNAL_ADDRESS | ||
48 | # (but use different: this one restricts our bind!) | ||
49 | # BINDTO = | ||
50 | |||
51 | TIMEOUT = 300000 | ||
52 | |||
53 | # Disable IPv6 support | ||
54 | # DISABLEV6 = | ||
55 | # ACCEPT_FROM = | ||
56 | # ACCEPT_FROM6 = | ||
57 | # REJECT_FROM = | ||
58 | # REJECT_FROM6 = | ||
59 | |||
60 | [transport-udp] | ||
61 | PORT = 2086 | ||
62 | # BEHIND_NAT = | ||
63 | # BINDTO = | ||
64 | # ALLOW_NAT = | ||
65 | # ONLY_NAT_ADDRESSES = | ||
66 | # INTERNAL_ADDRESS = | ||
67 | # EXTERNAL_ADDRESS = | ||
68 | |||
69 | [transport-http] | ||
70 | PORT = 1080 | ||
71 | |||
72 | [transport-https] | ||
73 | PORT = 4433 | ||
74 | |||
75 | [arm] | ||
76 | PORT = 2087 | ||
77 | HOSTNAME = localhost | ||
78 | HOME = $SERVICEHOME | ||
79 | CONFIG = $DEFAULTCONFIG | ||
80 | BINARY = gnunet-service-arm | ||
81 | ACCEPT_FROM = 127.0.0.1; | ||
82 | ACCEPT_FROM6 = ::1; | ||
83 | DEFAULTSERVICES = topology hostlist | ||
84 | UNIXPATH = /tmp/gnunet-service-arm.sock | ||
85 | UNIX_MATCH_UID = YES | ||
86 | UNIX_MATCH_GID = YES | ||
87 | # GLOBAL_POSTFIX = -l $SERVICEHOME/{}-logs | ||
88 | # GLOBAL_PREFIX = | ||
89 | # USERNAME = | ||
90 | # MAXBUF = | ||
91 | # TIMEOUT = | ||
92 | # DISABLEV6 = | ||
93 | # BINDTO = | ||
94 | # REJECT_FROM = | ||
95 | # REJECT_FROM6 = | ||
96 | # PREFIX = | ||
97 | |||
98 | [statistics] | ||
99 | AUTOSTART = YES | ||
100 | PORT = 2088 | ||
101 | HOSTNAME = localhost | ||
102 | HOME = $SERVICEHOME | ||
103 | CONFIG = $DEFAULTCONFIG | ||
104 | BINARY = gnunet-service-statistics | ||
105 | ACCEPT_FROM = 127.0.0.1; | ||
106 | ACCEPT_FROM6 = ::1; | ||
107 | UNIXPATH = /tmp/gnunet-service-statistics.sock | ||
108 | UNIX_MATCH_UID = NO | ||
109 | UNIX_MATCH_GID = YES | ||
110 | # DISABLE_SOCKET_FORWARDING = NO | ||
111 | # USERNAME = | ||
112 | # MAXBUF = | ||
113 | # TIMEOUT = | ||
114 | # DISABLEV6 = | ||
115 | # BINDTO = | ||
116 | # REJECT_FROM = | ||
117 | # REJECT_FROM6 = | ||
118 | # PREFIX = | ||
119 | |||
120 | [resolver] | ||
121 | AUTOSTART = YES | ||
122 | PORT = 2089 | ||
123 | HOSTNAME = localhost | ||
124 | HOME = $SERVICEHOME | ||
125 | CONFIG = $DEFAULTCONFIG | ||
126 | BINARY = gnunet-service-resolver | ||
127 | ACCEPT_FROM = 127.0.0.1; | ||
128 | ACCEPT_FROM6 = ::1; | ||
129 | UNIXPATH = /tmp/gnunet-service-resolver.sock | ||
130 | UNIX_MATCH_UID = NO | ||
131 | UNIX_MATCH_GID = NO | ||
132 | # DISABLE_SOCKET_FORWARDING = NO | ||
133 | # USERNAME = | ||
134 | # MAXBUF = | ||
135 | # TIMEOUT = | ||
136 | # DISABLEV6 = | ||
137 | # BINDTO = | ||
138 | # REJECT_FROM = | ||
139 | # REJECT_FROM6 = | ||
140 | # PREFIX = | ||
141 | |||
142 | [peerinfo] | ||
143 | AUTOSTART = YES | ||
144 | PORT = 2090 | ||
145 | HOSTNAME = localhost | ||
146 | HOME = $SERVICEHOME | ||
147 | CONFIG = $DEFAULTCONFIG | ||
148 | BINARY = gnunet-service-peerinfo | ||
149 | ACCEPT_FROM = 127.0.0.1; | ||
150 | ACCEPT_FROM6 = ::1; | ||
151 | UNIXPATH = /tmp/gnunet-service-peerinfo.sock | ||
152 | UNIX_MATCH_UID = NO | ||
153 | UNIX_MATCH_GID = YES | ||
154 | # DISABLE_SOCKET_FORWARDING = NO | ||
155 | # USERNAME = | ||
156 | # MAXBUF = | ||
157 | # TIMEOUT = | ||
158 | # DISABLEV6 = | ||
159 | # BINDTO = | ||
160 | # REJECT_FROM = | ||
161 | # REJECT_FROM6 = | ||
162 | # PREFIX = | ||
163 | HOSTS = $SERVICEHOME/data/hosts/ | ||
164 | |||
165 | |||
166 | [transport] | ||
167 | AUTOSTART = YES | ||
168 | PORT = 2091 | ||
169 | HOSTNAME = localhost | ||
170 | HOME = $SERVICEHOME | ||
171 | CONFIG = $DEFAULTCONFIG | ||
172 | BINARY = gnunet-service-transport | ||
173 | NEIGHBOUR_LIMIT = 50 | ||
174 | ACCEPT_FROM = 127.0.0.1; | ||
175 | ACCEPT_FROM6 = ::1; | ||
176 | PLUGINS = tcp | ||
177 | UNIXPATH = /tmp/gnunet-service-transport.sock | ||
178 | BLACKLIST_FILE = $SERVICEHOME/blacklist | ||
179 | UNIX_MATCH_UID = YES | ||
180 | UNIX_MATCH_GID = YES | ||
181 | # DISABLE_SOCKET_FORWARDING = NO | ||
182 | # USERNAME = | ||
183 | # MAXBUF = | ||
184 | # TIMEOUT = | ||
185 | # DISABLEV6 = | ||
186 | # BINDTO = | ||
187 | # REJECT_FROM = | ||
188 | # REJECT_FROM6 = | ||
189 | # PREFIX = | ||
190 | |||
191 | [core] | ||
192 | AUTOSTART = YES | ||
193 | PORT = 2092 | ||
194 | HOSTNAME = localhost | ||
195 | HOME = $SERVICEHOME | ||
196 | CONFIG = $DEFAULTCONFIG | ||
197 | BINARY = gnunet-service-core | ||
198 | ACCEPT_FROM = 127.0.0.1; | ||
199 | ACCEPT_FROM6 = ::1; | ||
200 | # quotas are in bytes per second now! | ||
201 | TOTAL_QUOTA_IN = 65536 | ||
202 | TOTAL_QUOTA_OUT = 65536 | ||
203 | UNIXPATH = /tmp/gnunet-service-core.sock | ||
204 | UNIX_MATCH_UID = YES | ||
205 | UNIX_MATCH_GID = YES | ||
206 | # DISABLE_SOCKET_FORWARDING = NO | ||
207 | # DEBUG = YES | ||
208 | # USERNAME = | ||
209 | # MAXBUF = | ||
210 | # TIMEOUT = | ||
211 | # DISABLEV6 = | ||
212 | # BINDTO = | ||
213 | # REJECT_FROM = | ||
214 | # REJECT_FROM6 = | ||
215 | # PREFIX = | ||
216 | |||
217 | |||
218 | [topology] | ||
219 | MINIMUM-FRIENDS = 0 | ||
220 | FRIENDS-ONLY = NO | ||
221 | AUTOCONNECT = YES | ||
222 | TARGET-CONNECTION-COUNT = 16 | ||
223 | FRIENDS = $SERVICEHOME/friends | ||
224 | CONFIG = $DEFAULTCONFIG | ||
225 | BINARY = gnunet-daemon-topology | ||
226 | |||
227 | [hostlist] | ||
228 | # port for hostlist http server | ||
229 | HTTPPORT = 8080 | ||
230 | HOME = $SERVICEHOME | ||
231 | HOSTLISTFILE = $SERVICEHOME/hostlist/learned.data | ||
232 | CONFIG = $DEFAULTCONFIG | ||
233 | BINARY = gnunet-daemon-hostlist | ||
234 | # consider having "-e" as default as well once implemented | ||
235 | OPTIONS = -b | ||
236 | SERVERS = http://v9.gnunet.org:58080/ | ||
237 | # proxy for downloading hostlists | ||
238 | HTTP-PROXY = | ||
239 | |||
240 | |||
241 | [datastore] | ||
242 | AUTOSTART = YES | ||
243 | UNIXPATH = /tmp/gnunet-service-datastore.sock | ||
244 | UNIX_MATCH_UID = YES | ||
245 | UNIX_MATCH_GID = YES | ||
246 | PORT = 2093 | ||
247 | HOSTNAME = localhost | ||
248 | HOME = $SERVICEHOME | ||
249 | CONFIG = $DEFAULTCONFIG | ||
250 | BINARY = gnunet-service-datastore | ||
251 | ACCEPT_FROM = 127.0.0.1; | ||
252 | ACCEPT_FROM6 = ::1; | ||
253 | QUOTA = 100000000 | ||
254 | BLOOMFILTER = $SERVICEHOME/fs/bloomfilter | ||
255 | DATABASE = sqlite | ||
256 | # DISABLE_SOCKET_FORWARDING = NO | ||
257 | |||
258 | [datastore-sqlite] | ||
259 | FILENAME = $SERVICEHOME/datastore/sqlite.db | ||
260 | |||
261 | [datastore-postgres] | ||
262 | CONFIG = connect_timeout=10; dbname=gnunet | ||
263 | |||
264 | [datastore-mysql] | ||
265 | DATABASE = gnunet | ||
266 | CONFIG = ~/.my.cnf | ||
267 | # USER = gnunet | ||
268 | # PASSWORD = | ||
269 | # HOST = localhost | ||
270 | # PORT = 3306 | ||
271 | |||
272 | [datacache-mysql] | ||
273 | DATABASE = gnunetcheck | ||
274 | CONFIG = ~/.my.cnf | ||
275 | # USER = gnunet | ||
276 | # PASSWORD = | ||
277 | # HOST = localhost | ||
278 | # PORT = 3306 | ||
279 | |||
280 | |||
281 | [fs] | ||
282 | AUTOSTART = YES | ||
283 | INDEXDB = $SERVICEHOME/idxinfo.lst | ||
284 | TRUST = $SERVICEHOME/data/credit/ | ||
285 | IDENTITY_DIR = $SERVICEHOME/identities/ | ||
286 | STATE_DIR = $SERVICEHOME/persistence/ | ||
287 | UPDATE_DIR = $SERVICEHOME/updates/ | ||
288 | PORT = 2094 | ||
289 | HOSTNAME = localhost | ||
290 | HOME = $SERVICEHOME | ||
291 | CONFIG = $DEFAULTCONFIG | ||
292 | BINARY = gnunet-service-fs | ||
293 | ACCEPT_FROM = 127.0.0.1; | ||
294 | ACCEPT_FROM6 = ::1; | ||
295 | |||
296 | CONTENT_CACHING = YES | ||
297 | CONTENT_PUSHING = YES | ||
298 | |||
299 | UNIXPATH = /tmp/gnunet-service-fs.sock | ||
300 | UNIX_MATCH_UID = NO | ||
301 | UNIX_MATCH_GID = YES | ||
302 | # DISABLE_SOCKET_FORWARDING = NO | ||
303 | # DEBUG = YES | ||
304 | MAX_PENDING_REQUESTS = 65536 | ||
305 | # Maximum frequency we're allowed to poll the datastore | ||
306 | # for content for migration (can be used to reduce | ||
307 | # GNUnet's disk-IO rate) | ||
308 | MIN_MIGRATION_DELAY = 1000 | ||
309 | EXPECTED_NEIGHBOUR_COUNT = 128 | ||
310 | |||
311 | [dht] | ||
312 | AUTOSTART = YES | ||
313 | PORT = 2095 | ||
314 | HOSTNAME = localhost | ||
315 | HOME = $SERVICEHOME | ||
316 | CONFIG = $DEFAULTCONFIG | ||
317 | BINARY = gnunet-service-dht | ||
318 | ACCEPT_FROM = 127.0.0.1; | ||
319 | ACCEPT_FROM6 = ::1; | ||
320 | BUCKET_SIZE = 4 | ||
321 | UNIXPATH = /tmp/gnunet-service-dht.sock | ||
322 | UNIX_MATCH_UID = YES | ||
323 | UNIX_MATCH_GID = YES | ||
324 | # DISABLE_SOCKET_FORWARDING = NO | ||
325 | # DEBUG = YES | ||
326 | # USERNAME = | ||
327 | # MAXBUF = | ||
328 | # TIMEOUT = | ||
329 | # DISABLEV6 = | ||
330 | # BINDTO = | ||
331 | # REJECT_FROM = | ||
332 | # REJECT_FROM6 = | ||
333 | # PREFIX = | ||
334 | # DO_FIND_PEER = | ||
335 | # STRICT_KADEMLIA = | ||
336 | # USE_MAX_HOPS = | ||
337 | # MAX_HOPS = | ||
338 | # REPUBLISH = YES | ||
339 | # REPLICATION_FREQUENCY = 60 | ||
340 | # STOP_ON_CLOSEST = | ||
341 | # STOP_FOUND = | ||
342 | # CONVERGE_MODIFIER = | ||
343 | |||
344 | |||
345 | [dhtcache] | ||
346 | DATABASE = sqlite | ||
347 | QUOTA = 1024000 | ||
348 | |||
349 | [block] | ||
350 | PLUGINS = fs dht test | ||
351 | |||
352 | [dns] | ||
353 | AUTOSTART = NO | ||
354 | |||
355 | |||
diff --git a/src/nat/test_nat.c b/src/nat/test_nat.c index d1268c93a..72cff0915 100644 --- a/src/nat/test_nat.c +++ b/src/nat/test_nat.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | (C) 2009 Christian Grothoff (and other contributing authors) | 3 | (C) 2009, 2011 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -19,20 +19,20 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file nat/test_nat.c | ||
23 | * @brief Testcase for NAT library | ||
24 | * @author Milan Bouchet-Valat | ||
25 | */ | ||
26 | |||
27 | /** | ||
28 | * Testcase for port redirection and public IP address retrieval. | 22 | * Testcase for port redirection and public IP address retrieval. |
29 | * This test never fails, because there need to be a NAT box set up for that. | 23 | * This test never fails, because there need to be a NAT box set up for that. |
30 | * So we only get IP address and open the 2086 port using any UPnP and NAT-PMP | 24 | * So we only get IP address and open the 2086 port using any NAT traversal |
31 | * routers found, wait for 30s, close ports and return. | 25 | * method available, wait for 30s, close ports and return. |
32 | * Have a look at the logs and use NMAP to check that it works with your box. | 26 | * Have a look at the logs and use NMAP to check that it works with your box. |
27 | * | ||
28 | * @file nat/test_nat.c | ||
29 | * @brief Testcase for NAT library | ||
30 | * @author Milan Bouchet-Valat | ||
31 | * @author Christian Grothoff | ||
32 | * | ||
33 | * TODO: actually use ARM to start resolver service to make DNS work! | ||
33 | */ | 34 | */ |
34 | 35 | ||
35 | |||
36 | #include "platform.h" | 36 | #include "platform.h" |
37 | #include "gnunet_common.h" | 37 | #include "gnunet_common.h" |
38 | #include "gnunet_util_lib.h" | 38 | #include "gnunet_util_lib.h" |
@@ -40,35 +40,62 @@ | |||
40 | #include "gnunet_scheduler_lib.h" | 40 | #include "gnunet_scheduler_lib.h" |
41 | #include "gnunet_nat_lib.h" | 41 | #include "gnunet_nat_lib.h" |
42 | 42 | ||
43 | |||
44 | #define VERBOSE GNUNET_YES | ||
45 | |||
46 | |||
43 | /* Time to wait before stopping NAT, in seconds */ | 47 | /* Time to wait before stopping NAT, in seconds */ |
44 | #define TIMEOUT 60 | 48 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) |
45 | 49 | ||
46 | struct addr_cls | ||
47 | { | ||
48 | struct sockaddr *addr; | ||
49 | socklen_t addrlen; | ||
50 | }; | ||
51 | 50 | ||
51 | /** | ||
52 | * Function called on each address that the NAT service | ||
53 | * believes to be valid for the transport. | ||
54 | */ | ||
52 | static void | 55 | static void |
53 | addr_callback (void *cls, int add_remove, | 56 | addr_callback (void *cls, int add_remove, |
54 | const struct sockaddr *addr, socklen_t addrlen) | 57 | const struct sockaddr *addr, socklen_t addrlen) |
55 | { | 58 | { |
56 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "External address changed: %s %s\n", | 59 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
60 | "Address changed: %s `%s' (%u bytes)\n", | ||
57 | add_remove == GNUNET_YES ? "added" : "removed", | 61 | add_remove == GNUNET_YES ? "added" : "removed", |
58 | GNUNET_a2s (addr, addrlen)); | 62 | GNUNET_a2s (addr, addrlen), |
63 | (unsigned int) addrlen); | ||
59 | } | 64 | } |
60 | 65 | ||
66 | |||
67 | /** | ||
68 | * Function that terminates the test. | ||
69 | */ | ||
61 | static void | 70 | static void |
62 | stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 71 | stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
63 | { | 72 | { |
64 | struct GNUNET_NAT_Handle *nat = cls; | 73 | struct GNUNET_NAT_Handle *nat = cls; |
65 | 74 | ||
66 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping NAT and quitting...\n"); | 75 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
76 | "Stopping NAT and quitting...\n"); | ||
67 | GNUNET_NAT_unregister (nat); | 77 | GNUNET_NAT_unregister (nat); |
68 | } | 78 | } |
69 | 79 | ||
70 | /* Return the address of the default interface, | 80 | |
71 | * or any interface with a valid address if the default is not valid */ | 81 | struct addr_cls |
82 | { | ||
83 | struct sockaddr *addr; | ||
84 | socklen_t addrlen; | ||
85 | }; | ||
86 | |||
87 | |||
88 | /** | ||
89 | * Return the address of the default interface, | ||
90 | * or any interface with a valid address if the default is not valid | ||
91 | * | ||
92 | * @param cls the 'struct addr_cls' | ||
93 | * @param name name of the interface | ||
94 | * @param isDefault do we think this may be our default interface | ||
95 | * @param addr address of the interface | ||
96 | * @param addrlen number of bytes in addr | ||
97 | * @return GNUNET_OK to continue iterating | ||
98 | */ | ||
72 | static int | 99 | static int |
73 | process_if (void *cls, | 100 | process_if (void *cls, |
74 | const char *name, | 101 | const char *name, |
@@ -76,18 +103,21 @@ process_if (void *cls, | |||
76 | { | 103 | { |
77 | struct addr_cls *data = cls; | 104 | struct addr_cls *data = cls; |
78 | 105 | ||
79 | if (addr && addrlen > 0) | 106 | if (addr == NULL) |
80 | { | 107 | return GNUNET_OK; |
81 | if (data->addr) | 108 | GNUNET_free_non_null (data->addr); |
82 | GNUNET_free (data->addr); | 109 | data->addr = GNUNET_malloc (addrlen); |
83 | data->addr = memcpy (GNUNET_malloc (addrlen), addr, addrlen); | 110 | memcpy (data->addr, addr, addrlen); |
84 | data->addrlen = addrlen; | 111 | data->addrlen = addrlen; |
85 | if (isDefault) | 112 | if (isDefault) |
86 | return GNUNET_SYSERR; | 113 | return GNUNET_SYSERR; |
87 | } | ||
88 | return GNUNET_OK; | 114 | return GNUNET_OK; |
89 | } | 115 | } |
90 | 116 | ||
117 | |||
118 | /** | ||
119 | * Main function run with scheduler. | ||
120 | */ | ||
91 | static void | 121 | static void |
92 | run (void *cls, | 122 | run (void *cls, |
93 | char *const *args, | 123 | char *const *args, |
@@ -98,19 +128,15 @@ run (void *cls, | |||
98 | struct sockaddr *addr; | 128 | struct sockaddr *addr; |
99 | 129 | ||
100 | GNUNET_log_setup ("test-nat", "DEBUG", NULL); | 130 | GNUNET_log_setup ("test-nat", "DEBUG", NULL); |
101 | |||
102 | data.addr = NULL; | 131 | data.addr = NULL; |
103 | GNUNET_OS_network_interfaces_list (process_if, &data); | 132 | GNUNET_OS_network_interfaces_list (process_if, &data); |
104 | if (!data.addr) | 133 | if (NULL == data.addr) |
105 | { | 134 | { |
106 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 135 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
107 | "Could not find a valid interface address!\n"); | 136 | "Could not find a valid interface address!\n"); |
108 | exit (GNUNET_SYSERR); | 137 | exit (GNUNET_SYSERR); |
109 | } | 138 | } |
110 | 139 | addr = data.addr; | |
111 | addr = GNUNET_malloc (data.addrlen); | ||
112 | memcpy (addr, data.addr, data.addrlen); | ||
113 | |||
114 | GNUNET_assert (addr->sa_family == AF_INET || addr->sa_family == AF_INET6); | 140 | GNUNET_assert (addr->sa_family == AF_INET || addr->sa_family == AF_INET6); |
115 | if (addr->sa_family == AF_INET) | 141 | if (addr->sa_family == AF_INET) |
116 | ((struct sockaddr_in *) addr)->sin_port = htons (2086); | 142 | ((struct sockaddr_in *) addr)->sin_port = htons (2086); |
@@ -121,14 +147,18 @@ run (void *cls, | |||
121 | "Requesting NAT redirection from address %s...\n", | 147 | "Requesting NAT redirection from address %s...\n", |
122 | GNUNET_a2s (addr, data.addrlen)); | 148 | GNUNET_a2s (addr, data.addrlen)); |
123 | 149 | ||
124 | nat = GNUNET_NAT_register (cfg, addr, data.addrlen, addr_callback, NULL); | 150 | nat = GNUNET_NAT_register (cfg, |
151 | GNUNET_YES /* tcp */, | ||
152 | 2086, | ||
153 | 1, | ||
154 | (const struct sockaddr**) &addr, | ||
155 | &data.addrlen, | ||
156 | &addr_callback, NULL, NULL); | ||
125 | GNUNET_free (addr); | 157 | GNUNET_free (addr); |
126 | 158 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, &stop, nat); | |
127 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
128 | (GNUNET_TIME_UNIT_SECONDS, TIMEOUT), stop, | ||
129 | nat); | ||
130 | } | 159 | } |
131 | 160 | ||
161 | |||
132 | int | 162 | int |
133 | main (int argc, char *const argv[]) | 163 | main (int argc, char *const argv[]) |
134 | { | 164 | { |
@@ -139,7 +169,7 @@ main (int argc, char *const argv[]) | |||
139 | char *const argv_prog[] = { | 169 | char *const argv_prog[] = { |
140 | "test-nat", | 170 | "test-nat", |
141 | "-c", | 171 | "-c", |
142 | "test-nat.conf", | 172 | "test_nat_data.conf", |
143 | "-L", | 173 | "-L", |
144 | #if VERBOSE | 174 | #if VERBOSE |
145 | "DEBUG", | 175 | "DEBUG", |
diff --git a/src/nat/test_nat_data.conf b/src/nat/test_nat_data.conf new file mode 100644 index 000000000..c312c69fb --- /dev/null +++ b/src/nat/test_nat_data.conf | |||
@@ -0,0 +1,136 @@ | |||
1 | [PATHS] | ||
2 | SERVICEHOME = /tmp/nat-test | ||
3 | # SERVICEHOME = /var/lib/gnunet/ | ||
4 | # DEFAULTCONFIG = /etc/gnunet.conf | ||
5 | # If 'DEFAULTCONFIG' is not defined, the current | ||
6 | # configuration file is assumed to be the default, | ||
7 | # which is what we want by default... | ||
8 | |||
9 | [gnunetd] | ||
10 | HOSTKEY = $SERVICEHOME/.hostkey | ||
11 | |||
12 | [TESTING] | ||
13 | WEAKRANDOM = NO | ||
14 | |||
15 | [client] | ||
16 | HOME = $SERVICEHOME | ||
17 | |||
18 | |||
19 | [nat] | ||
20 | # Are we behind NAT? | ||
21 | BEHIND_NAT = YES | ||
22 | |||
23 | # Is the NAT hole-punched? | ||
24 | PUNCHED_NAT = NO | ||
25 | |||
26 | # Disable UPNP by default until it gets cleaner! | ||
27 | ENABLE_UPNP = YES | ||
28 | |||
29 | # Use addresses from the local network interfaces (inluding loopback, but also others) | ||
30 | USE_LOCALADDR = YES | ||
31 | |||
32 | # External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) | ||
33 | # normal interface IP address for non-NATed peers; | ||
34 | # possibly auto-detected (using UPnP) if possible if not specified | ||
35 | # EXTERNAL_ADDRESS = | ||
36 | |||
37 | # Should we use ICMP-based NAT traversal to try connect to NATed peers | ||
38 | # or, if we are behind NAT, to allow connections to us? | ||
39 | ENABLE_ICMP_CLIENT = YES | ||
40 | ENABLE_ICMP_SERVER = YES | ||
41 | |||
42 | # IP address of the interface connected to the NAT box; IPv4 dotted-decimal ONLY; | ||
43 | # normal interface IP address for non-NATed peers; | ||
44 | # likely auto-detected (via interface list) if not specified (!) | ||
45 | # INTERNAL_ADDRESS = | ||
46 | |||
47 | # Disable IPv6 support | ||
48 | DISABLEV6 = NO | ||
49 | |||
50 | [arm] | ||
51 | PORT = 2087 | ||
52 | HOSTNAME = localhost | ||
53 | HOME = $SERVICEHOME | ||
54 | CONFIG = $DEFAULTCONFIG | ||
55 | BINARY = gnunet-service-arm | ||
56 | ACCEPT_FROM = 127.0.0.1; | ||
57 | ACCEPT_FROM6 = ::1; | ||
58 | DEFAULTSERVICES = topology hostlist | ||
59 | UNIXPATH = /tmp/gnunet-service-arm.sock | ||
60 | UNIX_MATCH_UID = YES | ||
61 | UNIX_MATCH_GID = YES | ||
62 | # GLOBAL_POSTFIX = -l $SERVICEHOME/{}-logs | ||
63 | # GLOBAL_PREFIX = | ||
64 | # USERNAME = | ||
65 | # MAXBUF = | ||
66 | # TIMEOUT = | ||
67 | # DISABLEV6 = | ||
68 | # BINDTO = | ||
69 | # REJECT_FROM = | ||
70 | # REJECT_FROM6 = | ||
71 | # PREFIX = | ||
72 | |||
73 | [statistics] | ||
74 | AUTOSTART = YES | ||
75 | PORT = 2088 | ||
76 | HOSTNAME = localhost | ||
77 | HOME = $SERVICEHOME | ||
78 | CONFIG = $DEFAULTCONFIG | ||
79 | BINARY = gnunet-service-statistics | ||
80 | ACCEPT_FROM = 127.0.0.1; | ||
81 | ACCEPT_FROM6 = ::1; | ||
82 | UNIXPATH = /tmp/gnunet-service-statistics.sock | ||
83 | UNIX_MATCH_UID = NO | ||
84 | UNIX_MATCH_GID = YES | ||
85 | # DISABLE_SOCKET_FORWARDING = NO | ||
86 | # USERNAME = | ||
87 | # MAXBUF = | ||
88 | # TIMEOUT = | ||
89 | # DISABLEV6 = | ||
90 | # BINDTO = | ||
91 | # REJECT_FROM = | ||
92 | # REJECT_FROM6 = | ||
93 | # PREFIX = | ||
94 | |||
95 | [resolver] | ||
96 | AUTOSTART = YES | ||
97 | PORT = 2089 | ||
98 | HOSTNAME = localhost | ||
99 | HOME = $SERVICEHOME | ||
100 | CONFIG = $DEFAULTCONFIG | ||
101 | BINARY = gnunet-service-resolver | ||
102 | ACCEPT_FROM = 127.0.0.1; | ||
103 | ACCEPT_FROM6 = ::1; | ||
104 | UNIXPATH = /tmp/gnunet-service-resolver.sock | ||
105 | UNIX_MATCH_UID = NO | ||
106 | UNIX_MATCH_GID = NO | ||
107 | # DISABLE_SOCKET_FORWARDING = NO | ||
108 | # USERNAME = | ||
109 | # MAXBUF = | ||
110 | # TIMEOUT = | ||
111 | # DISABLEV6 = | ||
112 | # BINDTO = | ||
113 | # REJECT_FROM = | ||
114 | # REJECT_FROM6 = | ||
115 | # PREFIX = | ||
116 | |||
117 | [peerinfo] | ||
118 | AUTOSTART = NO | ||
119 | |||
120 | [transport] | ||
121 | AUTOSTART = NO | ||
122 | |||
123 | [core] | ||
124 | AUTOSTART = NO | ||
125 | |||
126 | [datastore] | ||
127 | AUTOSTART = NO | ||
128 | |||
129 | [fs] | ||
130 | AUTOSTART = NO | ||
131 | |||
132 | [dht] | ||
133 | AUTOSTART = NO | ||
134 | |||
135 | [mesh] | ||
136 | AUTOSTART = NO | ||
diff --git a/src/nat/upnp-commands.c b/src/nat/upnp-commands.c deleted file mode 100644 index 2a88f90f4..000000000 --- a/src/nat/upnp-commands.c +++ /dev/null | |||
@@ -1,877 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * Code in this file is originally based on the miniupnp library. | ||
23 | * Copyright (c) 2005-2009, Thomas BERNARD. All rights reserved. | ||
24 | * | ||
25 | * Original licence: | ||
26 | * | ||
27 | * Redistribution and use in source and binary forms, with or without | ||
28 | * modification, are permitted provided that the following conditions are met: | ||
29 | * | ||
30 | * * Redistributions of source code must retain the above copyright notice, | ||
31 | * this list of conditions and the following disclaimer. | ||
32 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
33 | * this list of conditions and the following disclaimer in the documentation | ||
34 | * and/or other materials provided with the distribution. | ||
35 | * * The name of the author may not be used to endorse or promote products | ||
36 | * derived from this software without specific prior written permission. | ||
37 | * | ||
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
39 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
41 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
42 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
43 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
44 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
45 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
46 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
47 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
48 | * POSSIBILITY OF SUCH DAMAGE. | ||
49 | */ | ||
50 | |||
51 | /** | ||
52 | * @file nat/upnp-commands.c | ||
53 | * @brief Implementation of a basic set of UPnP commands | ||
54 | * | ||
55 | * @author Milan Bouchet-Valat | ||
56 | */ | ||
57 | |||
58 | #include "platform.h" | ||
59 | #include "gnunet_util_lib.h" | ||
60 | |||
61 | #include <stdlib.h> | ||
62 | #include <stdio.h> | ||
63 | #include <string.h> | ||
64 | |||
65 | #include "upnp-reply-parse.h" | ||
66 | #include "upnp-igd-parse.h" | ||
67 | #include "upnp-discover.h" | ||
68 | #include "upnp-commands.h" | ||
69 | |||
70 | #define SOAP_PREFIX "s" | ||
71 | #define SERVICE_PREFIX "u" | ||
72 | #define SERVICE_PREFIX2 'u' | ||
73 | #define MAX_HOSTNAME_LEN 64 | ||
74 | |||
75 | #define PRINT_UPNP_ERROR(a, b) GNUNET_log_from(GNUNET_ERROR_TYPE_WARNING, "UPnP", _("%s failed at %s:%d: %s\n"), a, __FILE__, __LINE__, b); | ||
76 | |||
77 | |||
78 | /** | ||
79 | * Private closure used by UPNP_command() and its callbacks. | ||
80 | */ | ||
81 | struct UPNP_command_cls | ||
82 | { | ||
83 | /** | ||
84 | * Connection handle used for sending and receiving. | ||
85 | */ | ||
86 | struct GNUNET_CONNECTION_Handle *s; | ||
87 | |||
88 | /** | ||
89 | * Transmission handle used for sending command. | ||
90 | */ | ||
91 | struct GNUNET_CONNECTION_TransmitHandle *th; | ||
92 | |||
93 | /** | ||
94 | * HTML content to send to run command. | ||
95 | */ | ||
96 | char *content; | ||
97 | |||
98 | /** | ||
99 | * Buffer where to copy received data to pass to caller. | ||
100 | */ | ||
101 | char *buffer; | ||
102 | |||
103 | /** | ||
104 | * Size of buffer. | ||
105 | */ | ||
106 | size_t buf_size; | ||
107 | |||
108 | /** | ||
109 | * User callback to trigger when done. | ||
110 | */ | ||
111 | UPNP_command_cb_ caller_cb; | ||
112 | |||
113 | /** | ||
114 | * User closure to pass to caller_cb. | ||
115 | */ | ||
116 | void *caller_cls; | ||
117 | }; | ||
118 | |||
119 | /** | ||
120 | * Get the length of content included in an HTML line. | ||
121 | * | ||
122 | * @param p line to parse | ||
123 | * @param n size of p | ||
124 | * @return the length of the content | ||
125 | */ | ||
126 | static ssize_t | ||
127 | get_content_len_from_line (const char *p, int n) | ||
128 | { | ||
129 | static const char cont_len_str[] = "content-length"; | ||
130 | const char *p2 = cont_len_str; | ||
131 | int a = 0; | ||
132 | |||
133 | while (*p2) | ||
134 | { | ||
135 | if (n == 0) | ||
136 | return -1; | ||
137 | |||
138 | if (*p2 != *p && *p2 != (*p + 32)) | ||
139 | return -1; | ||
140 | |||
141 | p++; | ||
142 | p2++; | ||
143 | n--; | ||
144 | } | ||
145 | |||
146 | if (n == 0) | ||
147 | return -1; | ||
148 | |||
149 | if (*p != ':') | ||
150 | return -1; | ||
151 | |||
152 | p++; | ||
153 | n--; | ||
154 | |||
155 | while (*p == ' ') | ||
156 | { | ||
157 | if (n == 0) | ||
158 | return -1; | ||
159 | |||
160 | p++; | ||
161 | n--; | ||
162 | } | ||
163 | |||
164 | while (*p >= '0' && *p <= '9') | ||
165 | { | ||
166 | if (n == 0) | ||
167 | return -1; | ||
168 | |||
169 | a = (a * 10) + (*p - '0'); | ||
170 | p++; | ||
171 | n--; | ||
172 | } | ||
173 | |||
174 | return a; | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * Get the respective lengths of content and header from an HTML reply. | ||
179 | * | ||
180 | * @param p HTML to parse | ||
181 | * @param n size of p | ||
182 | * @param content_len pointer to store content length to | ||
183 | * @param header_len pointer to store header length to | ||
184 | */ | ||
185 | static void | ||
186 | get_content_and_header_len (const char *p, int n, | ||
187 | int *content_len, int *header_len) | ||
188 | { | ||
189 | const char *line; | ||
190 | int line_len; | ||
191 | int r; | ||
192 | |||
193 | line = p; | ||
194 | |||
195 | while (line < p + n) | ||
196 | { | ||
197 | line_len = 0; | ||
198 | |||
199 | while (line[line_len] != '\r' && line[line_len] != '\r') | ||
200 | { | ||
201 | if (line + line_len >= p + n) | ||
202 | return; | ||
203 | |||
204 | line_len++; | ||
205 | } | ||
206 | |||
207 | r = get_content_len_from_line (line, line_len); | ||
208 | |||
209 | if (r > 0) | ||
210 | *content_len = r; | ||
211 | |||
212 | line = line + line_len + 2; | ||
213 | |||
214 | if (line[0] == '\r' && line[1] == '\n') | ||
215 | { | ||
216 | *header_len = (line - p) + 2; | ||
217 | return; | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * Receive reply of the device to our UPnP command. | ||
224 | * | ||
225 | * @param data closure from UPNP_command() | ||
226 | * @param buf struct UPNP_command_cls *cls | ||
227 | * @param available number of bytes in buf | ||
228 | * @param addr address of the sender | ||
229 | * @param addrlen size of addr | ||
230 | * @param errCode value of errno | ||
231 | */ | ||
232 | static void | ||
233 | UPNP_command_receiver (void *data, | ||
234 | const void *buf, | ||
235 | size_t available, | ||
236 | const struct sockaddr *addr, | ||
237 | socklen_t addrlen, int errCode) | ||
238 | { | ||
239 | struct UPNP_command_cls *cls = data; | ||
240 | int content_len; | ||
241 | int header_len; | ||
242 | |||
243 | if (available > 0) | ||
244 | { | ||
245 | content_len = -1; | ||
246 | header_len = -1; | ||
247 | get_content_and_header_len (buf, available, &content_len, &header_len); | ||
248 | |||
249 | strncpy (cls->buffer, (char *) buf, cls->buf_size - 2); | ||
250 | cls->buffer[cls->buf_size - 2] = '\0'; | ||
251 | } | ||
252 | else | ||
253 | { | ||
254 | cls->buffer[0] = '\0'; | ||
255 | } | ||
256 | |||
257 | GNUNET_CONNECTION_destroy (cls->s, GNUNET_NO); | ||
258 | |||
259 | cls->caller_cb (cls->buffer, cls->buf_size, cls->caller_cls); | ||
260 | |||
261 | GNUNET_free (cls->content); | ||
262 | GNUNET_free (cls); | ||
263 | } | ||
264 | |||
265 | /** | ||
266 | * Send UPnP command to device. | ||
267 | */ | ||
268 | static size_t | ||
269 | UPNP_command_transmit (void *data, size_t size, void *buf) | ||
270 | { | ||
271 | struct UPNP_command_cls *cls = data; | ||
272 | int n; | ||
273 | char *content = cls->content; | ||
274 | |||
275 | n = strlen (content); | ||
276 | memcpy (buf, content, size); | ||
277 | |||
278 | GNUNET_CONNECTION_receive (cls->s, cls->buf_size, GNUNET_TIME_UNIT_MINUTES, | ||
279 | UPNP_command_receiver, cls); | ||
280 | |||
281 | return n; | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * Parse a HTTP URL string to extract hostname, port and path it points to. | ||
286 | * | ||
287 | * @param url source string corresponding to URL | ||
288 | * @param hostname pointer where to store hostname (size of MAX_HOSTNAME_LEN+1) | ||
289 | * @param port pointer where to store port | ||
290 | * @param path pointer where to store path | ||
291 | * | ||
292 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
293 | */ | ||
294 | int | ||
295 | parse_url (const char *url, char *hostname, unsigned short *port, char **path) | ||
296 | { | ||
297 | char *p1, *p2, *p3; | ||
298 | |||
299 | if (!url) | ||
300 | return GNUNET_SYSERR; | ||
301 | |||
302 | p1 = strstr (url, "://"); | ||
303 | |||
304 | if (!p1) | ||
305 | return GNUNET_SYSERR; | ||
306 | |||
307 | p1 += 3; | ||
308 | |||
309 | if ((url[0] != 'h') || (url[1] != 't') | ||
310 | || (url[2] != 't') || (url[3] != 'p')) | ||
311 | return GNUNET_SYSERR; | ||
312 | |||
313 | p2 = strchr (p1, ':'); | ||
314 | p3 = strchr (p1, '/'); | ||
315 | |||
316 | if (!p3) | ||
317 | return GNUNET_SYSERR; | ||
318 | |||
319 | memset (hostname, 0, MAX_HOSTNAME_LEN + 1); | ||
320 | |||
321 | if (!p2 || (p2 > p3)) | ||
322 | { | ||
323 | strncpy (hostname, p1, GNUNET_MIN (MAX_HOSTNAME_LEN, (int) (p3 - p1))); | ||
324 | *port = 80; | ||
325 | } | ||
326 | else | ||
327 | { | ||
328 | strncpy (hostname, p1, GNUNET_MIN (MAX_HOSTNAME_LEN, (int) (p2 - p1))); | ||
329 | *port = 0; | ||
330 | p2++; | ||
331 | |||
332 | while ((*p2 >= '0') && (*p2 <= '9')) | ||
333 | { | ||
334 | *port *= 10; | ||
335 | *port += (unsigned short) (*p2 - '0'); | ||
336 | p2++; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | *path = p3; | ||
341 | return GNUNET_OK; | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * Send UPnP command to the device identified by url and service. | ||
346 | * | ||
347 | * @param url control URL of the device | ||
348 | * @param service type of the service corresponding to the command | ||
349 | * @param action action to send | ||
350 | * @param args arguments for action | ||
351 | * @param buffer buffer | ||
352 | * @param buf_size buffer size | ||
353 | * @param caller_cb user callback to trigger when done | ||
354 | * @param caller_cls closure to pass to caller_cb | ||
355 | */ | ||
356 | void | ||
357 | UPNP_command_ (const char *url, const char *service, | ||
358 | const char *action, struct UPNP_Arg_ *args, | ||
359 | char *buffer, size_t buf_size, | ||
360 | UPNP_command_cb_ caller_cb, void *caller_cls) | ||
361 | { | ||
362 | struct GNUNET_CONNECTION_Handle *s; | ||
363 | struct UPNP_command_cls *cls; | ||
364 | struct sockaddr_in dest; | ||
365 | struct sockaddr_in6 dest6; | ||
366 | char hostname[MAX_HOSTNAME_LEN + 1]; | ||
367 | unsigned short port = 0; | ||
368 | char *path; | ||
369 | char soap_act[128]; | ||
370 | char soap_body[2048]; | ||
371 | int body_size; | ||
372 | char *content_buf; | ||
373 | int headers_size; | ||
374 | char port_str[8]; | ||
375 | |||
376 | snprintf (soap_act, sizeof (soap_act), "%s#%s", service, action); | ||
377 | |||
378 | if (args == NULL) | ||
379 | { | ||
380 | snprintf (soap_body, sizeof (soap_body), | ||
381 | "<?xml version=\"1.0\"?>\r\n" | ||
382 | "<" SOAP_PREFIX ":Envelope " | ||
383 | "xmlns:" SOAP_PREFIX | ||
384 | "=\"http://schemas.xmlsoap.org/soap/envelope/\" " | ||
385 | SOAP_PREFIX | ||
386 | ":encodingStyle=\"http://schema GNUNET_free (content_buf);s.xmlsoap.org/soap/encoding/\">" | ||
387 | "<" SOAP_PREFIX ":Body>" "<" SERVICE_PREFIX | ||
388 | ":%s xmlns:" SERVICE_PREFIX "=\"%s\">" "</" | ||
389 | SERVICE_PREFIX ":%s>" "</" SOAP_PREFIX | ||
390 | ":Body></" SOAP_PREFIX ":Envelope>" "\r\n", | ||
391 | action, service, action); | ||
392 | } | ||
393 | else | ||
394 | { | ||
395 | char *p; | ||
396 | const char *pe, *pv; | ||
397 | int soap_body_len; | ||
398 | |||
399 | soap_body_len = snprintf (soap_body, sizeof (soap_body), | ||
400 | "<?xml version=\"1.0\"?>\r\n" | ||
401 | "<" SOAP_PREFIX ":Envelope " | ||
402 | "xmlns:" SOAP_PREFIX | ||
403 | "=\"http://schemas.xmlsoap.org/soap/envelope/\" " | ||
404 | SOAP_PREFIX | ||
405 | ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" | ||
406 | "<" SOAP_PREFIX ":Body>" "<" SERVICE_PREFIX | ||
407 | ":%s xmlns:" SERVICE_PREFIX "=\"%s\">", | ||
408 | action, service); | ||
409 | |||
410 | p = soap_body + soap_body_len; | ||
411 | |||
412 | while (args->elt) | ||
413 | { | ||
414 | /* check that we are never overflowing the string... */ | ||
415 | if (soap_body + sizeof (soap_body) <= p + 100) | ||
416 | { | ||
417 | GNUNET_assert (GNUNET_NO); | ||
418 | caller_cb (buffer, 0, caller_cls); | ||
419 | return; | ||
420 | } | ||
421 | *(p++) = '<'; | ||
422 | pe = args->elt; | ||
423 | while (*pe) | ||
424 | *(p++) = *(pe++); | ||
425 | *(p++) = '>'; | ||
426 | if ((pv = args->val)) | ||
427 | { | ||
428 | while (*pv) | ||
429 | *(p++) = *(pv++); | ||
430 | } | ||
431 | *(p++) = '<'; | ||
432 | *(p++) = '/'; | ||
433 | pe = args->elt; | ||
434 | while (*pe) | ||
435 | *(p++) = *(pe++); | ||
436 | *(p++) = '>'; | ||
437 | args++; | ||
438 | } | ||
439 | *(p++) = '<'; | ||
440 | *(p++) = '/'; | ||
441 | *(p++) = SERVICE_PREFIX2; | ||
442 | *(p++) = ':'; | ||
443 | pe = action; | ||
444 | |||
445 | while (*pe) | ||
446 | *(p++) = *(pe++); | ||
447 | |||
448 | strncpy (p, "></" SOAP_PREFIX ":Body></" SOAP_PREFIX ":Envelope>\r\n", | ||
449 | soap_body + sizeof (soap_body) - p); | ||
450 | } | ||
451 | |||
452 | if (GNUNET_OK != parse_url (url, hostname, &port, &path)) | ||
453 | { | ||
454 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "UPnP", | ||
455 | "Invalid URL passed to UPNP_command(): %s\n", url); | ||
456 | caller_cb (buffer, 0, caller_cls); | ||
457 | return; | ||
458 | } | ||
459 | |||
460 | |||
461 | /* Test IPv4 address, else use IPv6 */ | ||
462 | memset (&dest, 0, sizeof (dest)); | ||
463 | memset (&dest6, 0, sizeof (dest6)); | ||
464 | |||
465 | if (inet_pton (AF_INET, hostname, &dest.sin_addr) == 1) | ||
466 | { | ||
467 | dest.sin_family = AF_INET; | ||
468 | dest.sin_port = htons (port); | ||
469 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
470 | dest.sin_len = sizeof (dest); | ||
471 | #endif | ||
472 | |||
473 | s = GNUNET_CONNECTION_create_from_sockaddr (PF_INET, | ||
474 | (struct sockaddr *) &dest, | ||
475 | sizeof (dest)); | ||
476 | } | ||
477 | else if (inet_pton (AF_INET6, hostname, &dest6.sin6_addr) == 1) | ||
478 | { | ||
479 | dest6.sin6_family = AF_INET6; | ||
480 | dest6.sin6_port = htons (port); | ||
481 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
482 | dest6.sin6_len = sizeof (dest6); | ||
483 | #endif | ||
484 | |||
485 | s = GNUNET_CONNECTION_create_from_sockaddr (PF_INET6, | ||
486 | (struct sockaddr *) &dest6, | ||
487 | sizeof (dest6)); | ||
488 | } | ||
489 | else | ||
490 | { | ||
491 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, _("%s failed at %s:%d\n"), | ||
492 | "UPnP", "inet_pton", __FILE__, __LINE__); | ||
493 | |||
494 | caller_cb (buffer, 0, caller_cls); | ||
495 | return; | ||
496 | } | ||
497 | |||
498 | body_size = (int) strlen (soap_body); | ||
499 | content_buf = GNUNET_malloc (512 + body_size); | ||
500 | |||
501 | /* We are not using keep-alive HTTP connections. | ||
502 | * HTTP/1.1 needs the header Connection: close to do that. | ||
503 | * This is the default with HTTP/1.0 */ | ||
504 | /* Connection: Close is normally there only in HTTP/1.1 but who knows */ | ||
505 | port_str[0] = '\0'; | ||
506 | |||
507 | if (port != 80) | ||
508 | snprintf (port_str, sizeof (port_str), ":%hu", port); | ||
509 | |||
510 | headers_size = snprintf (content_buf, 512, "POST %s HTTP/1.1\r\n" "Host: %s%s\r\n" "User-Agent: GNU, UPnP/1.0, GNUnet/" PACKAGE_VERSION "\r\n" "Content-Length: %d\r\n" "Content-Type: text/xml\r\n" "SOAPAction: \"%s\"\r\n" "Connection: Close\r\n" "Cache-Control: no-cache\r\n" /* ??? */ | ||
511 | "Pragma: no-cache\r\n" | ||
512 | "\r\n", path, hostname, port_str, body_size, | ||
513 | soap_act); | ||
514 | memcpy (content_buf + headers_size, soap_body, body_size); | ||
515 | |||
516 | #ifdef DEBUG_UPNP | ||
517 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
518 | "Sending command '%s' to '%s' (service '%s')\n", | ||
519 | action, url, service); | ||
520 | #endif | ||
521 | |||
522 | cls = GNUNET_malloc (sizeof (struct UPNP_command_cls)); | ||
523 | cls->s = s; | ||
524 | cls->content = content_buf; | ||
525 | cls->buffer = buffer; | ||
526 | cls->buf_size = buf_size; | ||
527 | cls->caller_cb = caller_cb; | ||
528 | cls->caller_cls = caller_cls; | ||
529 | |||
530 | cls->th = | ||
531 | GNUNET_CONNECTION_notify_transmit_ready (s, body_size + headers_size, | ||
532 | GNUNET_TIME_relative_multiply | ||
533 | (GNUNET_TIME_UNIT_SECONDS, 15), | ||
534 | &UPNP_command_transmit, cls); | ||
535 | |||
536 | |||
537 | if (cls->th == NULL) | ||
538 | { | ||
539 | #ifdef DEBUG_UPNP | ||
540 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "UPnP", | ||
541 | "Error sending SOAP request at %s:%d\n", __FILE__, | ||
542 | __LINE__); | ||
543 | #endif | ||
544 | |||
545 | caller_cb (buffer, 0, caller_cls); | ||
546 | |||
547 | GNUNET_free (content_buf); | ||
548 | GNUNET_free (cls); | ||
549 | GNUNET_CONNECTION_destroy (s, GNUNET_NO); | ||
550 | return; | ||
551 | } | ||
552 | } | ||
553 | |||
554 | struct get_external_ip_address_cls | ||
555 | { | ||
556 | UPNP_get_external_ip_address_cb_ caller_cb; | ||
557 | void *caller_cls; | ||
558 | }; | ||
559 | |||
560 | static void | ||
561 | get_external_ip_address_receiver (char *response, size_t received, void *data) | ||
562 | { | ||
563 | struct get_external_ip_address_cls *cls = data; | ||
564 | struct UPNP_REPLY_NameValueList_ pdata; | ||
565 | char extIpAdd[128]; | ||
566 | char *p; | ||
567 | int ret = UPNP_COMMAND_UNKNOWN_ERROR; | ||
568 | |||
569 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Response: %s", response); | ||
570 | |||
571 | UPNP_REPLY_parse_ (response, received, &pdata); | ||
572 | p = UPNP_REPLY_get_value_ (&pdata, "NewExternalIPAddress"); | ||
573 | if (p) | ||
574 | { | ||
575 | strncpy (extIpAdd, p, 128); | ||
576 | extIpAdd[127] = '\0'; | ||
577 | ret = UPNP_COMMAND_SUCCESS; | ||
578 | } | ||
579 | else | ||
580 | extIpAdd[0] = '\0'; | ||
581 | |||
582 | p = UPNP_REPLY_get_value_ (&pdata, "errorCode"); | ||
583 | if (p) | ||
584 | { | ||
585 | ret = UPNP_COMMAND_UNKNOWN_ERROR; | ||
586 | sscanf (p, "%d", &ret); | ||
587 | } | ||
588 | cls->caller_cb (ret, extIpAdd, cls->caller_cls); | ||
589 | |||
590 | UPNP_REPLY_free_ (&pdata); | ||
591 | GNUNET_free (response); | ||
592 | GNUNET_free (cls); | ||
593 | } | ||
594 | |||
595 | /* UPNP_get_external_ip_address_() call the corresponding UPNP method. | ||
596 | * | ||
597 | * Return values : | ||
598 | * 0 : SUCCESS | ||
599 | * NON ZERO : ERROR Either an UPnP error code or an unknown error. | ||
600 | * | ||
601 | * 402 Invalid Args - See UPnP Device Architecture section on Control. | ||
602 | * 501 Action Failed - See UPnP Device Architecture section on Control. | ||
603 | */ | ||
604 | void | ||
605 | UPNP_get_external_ip_address_ (const char *control_url, | ||
606 | const char *service_type, | ||
607 | UPNP_get_external_ip_address_cb_ caller_cb, | ||
608 | void *caller_cls) | ||
609 | { | ||
610 | struct get_external_ip_address_cls *cls; | ||
611 | char *buffer; | ||
612 | |||
613 | if (!control_url || !service_type) | ||
614 | caller_cb (UPNP_COMMAND_INVALID_ARGS, NULL, caller_cls); | ||
615 | |||
616 | cls = GNUNET_malloc (sizeof (struct get_external_ip_address_cls)); | ||
617 | cls->caller_cb = caller_cb; | ||
618 | cls->caller_cls = caller_cls; | ||
619 | |||
620 | buffer = GNUNET_malloc (UPNP_COMMAND_BUFSIZE); | ||
621 | |||
622 | UPNP_command_ (control_url, service_type, "GetExternalIPAddress", | ||
623 | NULL, buffer, UPNP_COMMAND_BUFSIZE, | ||
624 | (UPNP_command_cb_) get_external_ip_address_receiver, cls); | ||
625 | } | ||
626 | |||
627 | struct PortMapping_cls | ||
628 | { | ||
629 | const char *control_url; | ||
630 | const char *service_type; | ||
631 | const char *ext_port; | ||
632 | const char *in_port; | ||
633 | const char *proto; | ||
634 | const char *remoteHost; | ||
635 | UPNP_port_mapping_cb_ caller_cb; | ||
636 | void *caller_cls; | ||
637 | }; | ||
638 | |||
639 | static void | ||
640 | add_delete_port_mapping_receiver (char *response, size_t received, void *data) | ||
641 | { | ||
642 | struct PortMapping_cls *cls = data; | ||
643 | struct UPNP_REPLY_NameValueList_ pdata; | ||
644 | const char *resVal; | ||
645 | int ret; | ||
646 | |||
647 | UPNP_REPLY_parse_ (response, received, &pdata); | ||
648 | resVal = UPNP_REPLY_get_value_ (&pdata, "errorCode"); | ||
649 | if (resVal) | ||
650 | { | ||
651 | ret = UPNP_COMMAND_UNKNOWN_ERROR; | ||
652 | sscanf (resVal, "%d", &ret); | ||
653 | } | ||
654 | else | ||
655 | { | ||
656 | ret = UPNP_COMMAND_SUCCESS; | ||
657 | } | ||
658 | |||
659 | cls->caller_cb (ret, cls->control_url, cls->service_type, | ||
660 | cls->ext_port, cls->in_port, cls->proto, | ||
661 | cls->remoteHost, cls->caller_cls); | ||
662 | |||
663 | UPNP_REPLY_free_ (&pdata); | ||
664 | GNUNET_free (response); | ||
665 | GNUNET_free (cls); | ||
666 | } | ||
667 | |||
668 | void | ||
669 | UPNP_add_port_mapping_ (const char *control_url, const char *service_type, | ||
670 | const char *ext_port, | ||
671 | const char *in_port, | ||
672 | const char *inClient, | ||
673 | const char *desc, | ||
674 | const char *proto, const char *remoteHost, | ||
675 | UPNP_port_mapping_cb_ caller_cb, void *caller_cls) | ||
676 | { | ||
677 | struct UPNP_Arg_ args[9]; | ||
678 | struct PortMapping_cls *cls; | ||
679 | char *buffer; | ||
680 | |||
681 | if (!in_port || !inClient || !proto || !ext_port) | ||
682 | { | ||
683 | caller_cb (UPNP_COMMAND_INVALID_ARGS, control_url, service_type, | ||
684 | ext_port, in_port, proto, remoteHost, caller_cls); | ||
685 | return; | ||
686 | } | ||
687 | |||
688 | args[0].elt = "NewRemoteHost"; | ||
689 | args[0].val = remoteHost; | ||
690 | args[1].elt = "NewExternalPort"; | ||
691 | args[1].val = ext_port; | ||
692 | args[2].elt = "NewProtocol"; | ||
693 | args[2].val = proto; | ||
694 | args[3].elt = "NewInternalPort"; | ||
695 | args[3].val = in_port; | ||
696 | args[4].elt = "NewInternalClient"; | ||
697 | args[4].val = inClient; | ||
698 | args[5].elt = "NewEnabled"; | ||
699 | args[5].val = "1"; | ||
700 | args[6].elt = "NewPortMappingDescription"; | ||
701 | args[6].val = desc ? desc : "GNUnet"; | ||
702 | args[7].elt = "NewLeaseDuration"; | ||
703 | args[7].val = "0"; | ||
704 | args[8].elt = NULL; | ||
705 | args[8].val = NULL; | ||
706 | |||
707 | cls = GNUNET_malloc (sizeof (struct PortMapping_cls)); | ||
708 | cls->control_url = control_url; | ||
709 | cls->service_type = service_type; | ||
710 | cls->ext_port = ext_port;; | ||
711 | cls->in_port = in_port; | ||
712 | cls->proto = proto; | ||
713 | cls->remoteHost = remoteHost; | ||
714 | cls->caller_cb = caller_cb; | ||
715 | cls->caller_cls = caller_cls; | ||
716 | |||
717 | buffer = GNUNET_malloc (UPNP_COMMAND_BUFSIZE); | ||
718 | |||
719 | UPNP_command_ (control_url, service_type, "AddPortMapping", | ||
720 | args, buffer, UPNP_COMMAND_BUFSIZE, | ||
721 | add_delete_port_mapping_receiver, cls); | ||
722 | } | ||
723 | |||
724 | void | ||
725 | UPNP_delete_port_mapping_ (const char *control_url, const char *service_type, | ||
726 | const char *ext_port, const char *proto, | ||
727 | const char *remoteHost, | ||
728 | UPNP_port_mapping_cb_ caller_cb, void *caller_cls) | ||
729 | { | ||
730 | struct UPNP_Arg_ args[4]; | ||
731 | struct PortMapping_cls *cls; | ||
732 | char *buffer; | ||
733 | |||
734 | if (!ext_port || !proto) | ||
735 | { | ||
736 | caller_cb (UPNP_COMMAND_INVALID_ARGS, control_url, service_type, | ||
737 | ext_port, NULL, proto, remoteHost, caller_cls); | ||
738 | return; | ||
739 | } | ||
740 | |||
741 | args[0].elt = "NewRemoteHost"; | ||
742 | args[0].val = remoteHost; | ||
743 | args[1].elt = "NewExternalPort"; | ||
744 | args[1].val = ext_port; | ||
745 | args[2].elt = "NewProtocol"; | ||
746 | args[2].val = proto; | ||
747 | args[3].elt = NULL; | ||
748 | args[3].val = NULL; | ||
749 | |||
750 | cls = GNUNET_malloc (sizeof (struct PortMapping_cls)); | ||
751 | cls->control_url = control_url; | ||
752 | cls->service_type = service_type; | ||
753 | cls->ext_port = ext_port; | ||
754 | cls->in_port = "0"; | ||
755 | cls->proto = proto; | ||
756 | cls->remoteHost = remoteHost; | ||
757 | cls->caller_cb = caller_cb; | ||
758 | cls->caller_cls = caller_cls; | ||
759 | |||
760 | buffer = GNUNET_malloc (UPNP_COMMAND_BUFSIZE); | ||
761 | |||
762 | UPNP_command_ (control_url, service_type, | ||
763 | "DeletePortMapping", | ||
764 | args, buffer, UPNP_COMMAND_BUFSIZE, | ||
765 | add_delete_port_mapping_receiver, cls); | ||
766 | } | ||
767 | |||
768 | |||
769 | struct get_specific_port_mapping_entry_cls | ||
770 | { | ||
771 | const char *control_url; | ||
772 | const char *service_type; | ||
773 | const char *ext_port; | ||
774 | const char *proto; | ||
775 | UPNP_port_mapping_cb_ caller_cb; | ||
776 | void *caller_cls; | ||
777 | }; | ||
778 | |||
779 | static void | ||
780 | get_specific_port_mapping_entry_receiver (char *response, size_t received, | ||
781 | void *data) | ||
782 | { | ||
783 | struct PortMapping_cls *cls = data; | ||
784 | struct UPNP_REPLY_NameValueList_ pdata; | ||
785 | char *p; | ||
786 | char in_port[128]; | ||
787 | char in_client[128]; | ||
788 | int ret; | ||
789 | |||
790 | UPNP_REPLY_parse_ (response, received, &pdata); | ||
791 | |||
792 | p = UPNP_REPLY_get_value_ (&pdata, "NewInternalClient"); | ||
793 | if (p) | ||
794 | { | ||
795 | strncpy (in_client, p, 128); | ||
796 | in_client[127] = '\0'; | ||
797 | } | ||
798 | else | ||
799 | in_client[0] = '\0'; | ||
800 | |||
801 | p = UPNP_REPLY_get_value_ (&pdata, "NewInternalPort"); | ||
802 | if (p) | ||
803 | { | ||
804 | strncpy (in_port, p, 6); | ||
805 | in_port[5] = '\0'; | ||
806 | } | ||
807 | else | ||
808 | in_port[0] = '\0'; | ||
809 | |||
810 | p = UPNP_REPLY_get_value_ (&pdata, "errorCode"); | ||
811 | if (p) | ||
812 | { | ||
813 | if (p) | ||
814 | { | ||
815 | ret = UPNP_COMMAND_UNKNOWN_ERROR; | ||
816 | sscanf (p, "%d", &ret); | ||
817 | } | ||
818 | #if DEBUG_UPNP | ||
819 | PRINT_UPNP_ERROR ("GetSpecificPortMappingEntry", p); | ||
820 | #endif | ||
821 | } | ||
822 | |||
823 | cls->caller_cb (ret, cls->control_url, cls->service_type, | ||
824 | cls->ext_port, cls->proto, in_port, in_client, | ||
825 | cls->caller_cls); | ||
826 | |||
827 | UPNP_REPLY_free_ (&pdata); | ||
828 | GNUNET_free (response); | ||
829 | GNUNET_free (cls); | ||
830 | } | ||
831 | |||
832 | /* UPNP_get_specific_port_mapping_entry _ retrieves an existing port mapping | ||
833 | * the result is returned in the in_client and in_port strings | ||
834 | * please provide 128 and 6 bytes of data */ | ||
835 | void | ||
836 | UPNP_get_specific_port_mapping_entry_ (const char *control_url, | ||
837 | const char *service_type, | ||
838 | const char *ext_port, | ||
839 | const char *proto, | ||
840 | UPNP_get_specific_port_mapping_entry_cb_ | ||
841 | caller_cb, void *caller_cls) | ||
842 | { | ||
843 | struct UPNP_Arg_ args[4]; | ||
844 | struct get_specific_port_mapping_entry_cls *cls; | ||
845 | char *buffer; | ||
846 | |||
847 | if (!ext_port || !proto) | ||
848 | { | ||
849 | caller_cb (UPNP_COMMAND_INVALID_ARGS, control_url, service_type, | ||
850 | ext_port, proto, NULL, NULL, caller_cls); | ||
851 | return; | ||
852 | } | ||
853 | |||
854 | args[0].elt = "NewRemoteHost"; | ||
855 | args[0].val = NULL; | ||
856 | args[1].elt = "NewExternalPort"; | ||
857 | args[1].val = ext_port; | ||
858 | args[2].elt = "NewProtocol"; | ||
859 | args[2].val = proto; | ||
860 | args[3].elt = NULL; | ||
861 | args[3].val = NULL; | ||
862 | |||
863 | cls = GNUNET_malloc (sizeof (struct PortMapping_cls)); | ||
864 | cls->control_url = control_url; | ||
865 | cls->service_type = service_type; | ||
866 | cls->ext_port = ext_port; | ||
867 | cls->proto = proto; | ||
868 | cls->caller_cb = caller_cb; | ||
869 | cls->caller_cls = caller_cls; | ||
870 | |||
871 | buffer = GNUNET_malloc (UPNP_COMMAND_BUFSIZE); | ||
872 | |||
873 | UPNP_command_ (control_url, service_type, | ||
874 | "GetSpecificPortMappingEntry", | ||
875 | args, buffer, UPNP_COMMAND_BUFSIZE, | ||
876 | get_specific_port_mapping_entry_receiver, cls); | ||
877 | } | ||
diff --git a/src/nat/upnp-commands.h b/src/nat/upnp-commands.h deleted file mode 100644 index ea7b48162..000000000 --- a/src/nat/upnp-commands.h +++ /dev/null | |||
@@ -1,271 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * Code in this file is originally based on the miniupnp library. | ||
23 | * Copyright (c) 2005-2009, Thomas BERNARD. All rights reserved. | ||
24 | * | ||
25 | * Original licence: | ||
26 | * | ||
27 | * Redistribution and use in source and binary forms, with or without | ||
28 | * modification, are permitted provided that the following conditions are met: | ||
29 | * | ||
30 | * * Redistributions of source code must retain the above copyright notice, | ||
31 | * this list of conditions and the following disclaimer. | ||
32 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
33 | * this list of conditions and the following disclaimer in the documentation | ||
34 | * and/or other materials provided with the distribution. | ||
35 | * * The name of the author may not be used to endorse or promote products | ||
36 | * derived from this software without specific prior written permission. | ||
37 | * | ||
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
39 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
41 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
42 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
43 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
44 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
45 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
46 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
47 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
48 | * POSSIBILITY OF SUCH DAMAGE. | ||
49 | */ | ||
50 | |||
51 | /** | ||
52 | * @file nat/upnp-commands.h | ||
53 | * @brief Commands to control UPnP IGD devices | ||
54 | * | ||
55 | * @author Milan Bouchet-Valat | ||
56 | */ | ||
57 | #ifndef UPNP_COMMANDS_H | ||
58 | #define UPNP_COMMANDS_H | ||
59 | |||
60 | #include "platform.h" | ||
61 | #include "gnunet_scheduler_lib.h" | ||
62 | |||
63 | /** | ||
64 | * Generic UPnP error codes. | ||
65 | */ | ||
66 | #define UPNP_COMMAND_SUCCESS (0) | ||
67 | #define UPNP_COMMAND_UNKNOWN_ERROR (-1) | ||
68 | #define UPNP_COMMAND_INVALID_ARGS (-2) | ||
69 | |||
70 | /** | ||
71 | * Size of the buffer used to store anwsers to UPnP commands. | ||
72 | */ | ||
73 | #define UPNP_COMMAND_BUFSIZE 4096 | ||
74 | |||
75 | /** | ||
76 | * Name-value pair containing an argumeny to a UPnP command. | ||
77 | */ | ||
78 | struct UPNP_Arg_ | ||
79 | { | ||
80 | const char *elt; | ||
81 | const char *val; | ||
82 | }; | ||
83 | |||
84 | /** | ||
85 | * Callback for UPNP_command_(). | ||
86 | * | ||
87 | * @param response the buffer passed to UPNP_command_(), filled with | ||
88 | * NULL-terminated content (if any) | ||
89 | * @param received length of the content received and stored in response | ||
90 | * @param cls closure passed to UPNP_command_() | ||
91 | */ | ||
92 | typedef void (*UPNP_command_cb_) (char *response, size_t received, void *cls); | ||
93 | |||
94 | /** | ||
95 | * Send UPnP command to the device identified by url and service. | ||
96 | * | ||
97 | * @param url control URL of the device | ||
98 | * @param service type of the service corresponding to the command | ||
99 | * @param action action to send | ||
100 | * @param args arguments for action | ||
101 | * @param buffer buffer | ||
102 | * @param buf_size buffer size | ||
103 | * @param caller_cb user callback to trigger when done | ||
104 | * @param caller_cls closure to pass to caller_cb | ||
105 | */ | ||
106 | void UPNP_command_ (const char *url, const char *service, | ||
107 | const char *action, struct UPNP_Arg_ *args, | ||
108 | char *buffer, size_t buf_size, | ||
109 | UPNP_command_cb_ caller_cb, void *caller_cls); | ||
110 | |||
111 | /** | ||
112 | * Callback to UPNP_get_external_ip_address_(). | ||
113 | * | ||
114 | * Possible UPnP Errors : | ||
115 | * 402 Invalid Args - See UPnP Device Architecture section on Control. | ||
116 | * 501 Action Failed - See UPnP Device Architecture section on Control. | ||
117 | * | ||
118 | * @param error GNUNET_OK on success, another value on error (see above) | ||
119 | * @param ext_ip_addr the external IP address reported by the device (IPv4 or v6) | ||
120 | * @param cls the closure passed to UPNP_get_external_ip_address_() | ||
121 | */ | ||
122 | typedef void (*UPNP_get_external_ip_address_cb_) (int error, | ||
123 | char *ext_ip_addr, | ||
124 | void *cls); | ||
125 | |||
126 | /** | ||
127 | * Get the IP address associated with the WAN connection of the device. | ||
128 | * See UPNP_get_external_ip_address_cb_. | ||
129 | * | ||
130 | * @param control_url the control URL corresponding to service_type on the device | ||
131 | * @param service_type service type to call the command on | ||
132 | * @param caller_cb function to call when done | ||
133 | * @param caller_cls closure passed to caller_cb | ||
134 | */ | ||
135 | void | ||
136 | UPNP_get_external_ip_address_ (const char *control_url, | ||
137 | const char *service_type, | ||
138 | UPNP_get_external_ip_address_cb_ caller_cb, | ||
139 | void *caller_cls); | ||
140 | |||
141 | /** | ||
142 | * Callback to UPNP_add_port_mapping_() and UPNP_delete_port_mapping_(). | ||
143 | * | ||
144 | * Possible UPnP Errors with UPNP_add_port_mapping_(): | ||
145 | * 402 Invalid Args - See UPnP Device Architecture section on Control. | ||
146 | * 501 Action Failed - See UPnP Device Architecture section on Control. | ||
147 | * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be | ||
148 | * wild-carded | ||
149 | * 716 WildCardNotPermittedInext_port - The external port cannot be wild-carded | ||
150 | * 718 ConflictInMappingEntry - The port mapping entry specified conflicts | ||
151 | * with a mapping assigned previously to another client | ||
152 | * 724 SamePortValuesRequired - Internal and External port values | ||
153 | * must be the same | ||
154 | * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports | ||
155 | * permanent lease times on port mappings | ||
156 | * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard | ||
157 | * and cannot be a specific IP address or DNS name | ||
158 | * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and | ||
159 | * cannot be a specific port value | ||
160 | * | ||
161 | * Possible UPnP Errors with UPNP_delete_port_mapping_(): | ||
162 | * 402 Invalid Args - See UPnP Device Architecture section on Control. | ||
163 | * 714 NoSuchEntryInArray - The specified value does not exist in the array | ||
164 | * | ||
165 | * @param error GNUNET_OK on success, another value on error (see above) | ||
166 | * @param control_url the control URL the command was called on | ||
167 | * @param service_type service the command was called on | ||
168 | * @param ext_port external port | ||
169 | * @param inPort port on the gateway on the LAN side which was requested | ||
170 | * @param proto protocol for which port mapping was requested | ||
171 | * @param remote_host remote host for which port mapping was requested | ||
172 | * @param cls the closure passed to the command function | ||
173 | */ | ||
174 | typedef void (*UPNP_port_mapping_cb_) (int error, | ||
175 | const char *control_url, | ||
176 | const char *service_type, | ||
177 | const char *ext_port, | ||
178 | const char *inPort, const char *proto, | ||
179 | const char *remote_host, void *cls); | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Request opening a port on the IGD device. | ||
184 | * (remote_host is usually NULL because IGDs don't support it.) | ||
185 | * | ||
186 | * @param control_url the control URL corresponding to service_type on the device | ||
187 | * @param service_type service type to call the command on | ||
188 | * @param ext_port port that should be opened on the WAN side | ||
189 | * @param in_port port on the gateway on the LAN side which should map ext_port | ||
190 | * @param in_client address in the LAN to which packets should be redirected | ||
191 | * @param desc description | ||
192 | * @param proto protocol for which to request port mapping | ||
193 | * @param remote_host remote host for which to request port mapping | ||
194 | * @param caller_cb function to call when done | ||
195 | * @param caller_cls closure passed to caller_cb | ||
196 | */ | ||
197 | void | ||
198 | UPNP_add_port_mapping_ (const char *control_url, const char *service_type, | ||
199 | const char *ext_port, | ||
200 | const char *in_port, | ||
201 | const char *in_client, | ||
202 | const char *desc, | ||
203 | const char *proto, const char *remote_host, | ||
204 | UPNP_port_mapping_cb_ caller_cb, void *caller_cls); | ||
205 | |||
206 | /** | ||
207 | * Request closing a a port on the IGD device that was previously opened | ||
208 | * using UPNP_add_port_mapping_(). Use the same argument values that were | ||
209 | * used when opening the port. | ||
210 | * (remote_host is usually NULL because IGDs don't support it.) | ||
211 | * | ||
212 | * @param control_url the control URL the command was called on | ||
213 | * @param service_type service the command was called on | ||
214 | * @param ext_port external port | ||
215 | * @param proto protocol for which port mapping was requested | ||
216 | * @param remote_host remote host for which port mapping was requested | ||
217 | * @param caller_cb function to call when done | ||
218 | * @param caller_cls closure passed to caller_cb | ||
219 | */ | ||
220 | void | ||
221 | UPNP_delete_port_mapping_ (const char *control_url, const char *service_type, | ||
222 | const char *ext_port, const char *proto, | ||
223 | const char *remote_host, | ||
224 | UPNP_port_mapping_cb_ caller_cb, void *caller_cls); | ||
225 | |||
226 | |||
227 | /** | ||
228 | * Callback to UPNP_get_specific_port_mapping_entry _(). | ||
229 | * | ||
230 | * @param error GNUNET_OK if port is currently mapped, another value on error | ||
231 | * @param control_url the control URL the command was called on | ||
232 | * @param service_type service the command was called on | ||
233 | * @param ext_port external port | ||
234 | * @param proto protocol for which port mapping was requested | ||
235 | * @param in_port port on the gateway on the LAN side which was requested | ||
236 | * @param in_client address in the LAN which was requested | ||
237 | * @param cls the closure passed to the command function | ||
238 | */ | ||
239 | typedef void (*UPNP_get_specific_port_mapping_entry_cb_) (int error, | ||
240 | const char | ||
241 | *control_url, | ||
242 | const char | ||
243 | *service_type, | ||
244 | const char | ||
245 | *ext_port, | ||
246 | const char *proto, | ||
247 | const char *in_port, | ||
248 | const char | ||
249 | *in_client, | ||
250 | void *cls); | ||
251 | |||
252 | /** | ||
253 | * Check that a port mapping set up with UPNP_add_port_mapping_() | ||
254 | * is alive. | ||
255 | * | ||
256 | * @param control_url the control URL the command was called on | ||
257 | * @param service_type service the command was called on | ||
258 | * @param ext_port external port | ||
259 | * @param proto protocol for which port mapping was requested | ||
260 | * @param caller_cb function to call when done | ||
261 | * @param caller_cls closure passed to caller_cb | ||
262 | */ | ||
263 | void | ||
264 | UPNP_get_specific_port_mapping_entry_ (const char *control_url, | ||
265 | const char *service_type, | ||
266 | const char *ext_port, | ||
267 | const char *proto, | ||
268 | UPNP_get_specific_port_mapping_entry_cb_ | ||
269 | caller_cb, void *caller_cls); | ||
270 | |||
271 | #endif | ||
diff --git a/src/nat/upnp-discover.c b/src/nat/upnp-discover.c deleted file mode 100644 index 2e609d790..000000000 --- a/src/nat/upnp-discover.c +++ /dev/null | |||
@@ -1,1270 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * Code in this file is originally based on the miniupnp library. | ||
23 | * Copyright (c) 2005-2009, Thomas BERNARD. All rights reserved. | ||
24 | * | ||
25 | * Original license: | ||
26 | * | ||
27 | * Redistribution and use in source and binary forms, with or without | ||
28 | * modification, are permitted provided that the following conditions are met: | ||
29 | * | ||
30 | * * Redistributions of source code must retain the above copyright notice, | ||
31 | * this list of conditions and the following disclaimer. | ||
32 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
33 | * this list of conditions and the following disclaimer in the documentation | ||
34 | * and/or other materials provided with the distribution. | ||
35 | * * The name of the author may not be used to endorse or promote products | ||
36 | * derived from this software without specific prior written permission. | ||
37 | * | ||
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
39 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
41 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
42 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
43 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
44 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
45 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
46 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
47 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
48 | * POSSIBILITY OF SUCH DAMAGE. | ||
49 | */ | ||
50 | |||
51 | /** | ||
52 | * @file nat/upnp-discover.c | ||
53 | * @brief Look for UPnP IGD devices | ||
54 | * | ||
55 | * @author Milan Bouchet-Valat | ||
56 | */ | ||
57 | #include <stdio.h> | ||
58 | #include <stdlib.h> | ||
59 | #include <string.h> | ||
60 | #include <curl/curl.h> | ||
61 | |||
62 | #include "platform.h" | ||
63 | #include "gnunet_util_lib.h" | ||
64 | #include "upnp-discover.h" | ||
65 | #include "upnp-reply-parse.h" | ||
66 | #include "upnp-igd-parse.h" | ||
67 | #include "upnp-minixml.h" | ||
68 | |||
69 | #define DISCOVER_BUFSIZE 512 | ||
70 | #define DESCRIPTION_BUFSIZE 2048 | ||
71 | #define CURL_EASY_SETOPT(c, a, b) do { ret = curl_easy_setopt(c, a, b); if (ret != CURLE_OK) GNUNET_log(GNUNET_ERROR_TYPE_WARNING, _("%s failed at %s:%d: `%s'\n"), "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror(ret)); } while (0) | ||
72 | #define PRINT_SOCKET_ERROR(a) GNUNET_log_from(GNUNET_ERROR_TYPE_WARNING, "UPnP", _("%s failed at %s:%d: '%s'\n"), a, __FILE__, __LINE__, strerror (errno)); | ||
73 | #define PRINT_SOCKET_ERROR_STR(a, b) GNUNET_log_from(GNUNET_ERROR_TYPE_WARNING, "UPnP", _("%s failed at %s:%d: '%s' on `%s'\n"), a, __FILE__, __LINE__, strerror (errno), b); | ||
74 | |||
75 | /** | ||
76 | * Callback function called when download is finished. | ||
77 | * | ||
78 | * @param data the contents of the downloaded file, or NULL | ||
79 | * @param cls closure passed via download_device_description() | ||
80 | */ | ||
81 | typedef void (*download_cb) (char *data, void *cls); | ||
82 | |||
83 | /** | ||
84 | * Private closure used by download_device_description() and it's callbacks. | ||
85 | */ | ||
86 | struct download_cls | ||
87 | { | ||
88 | /** | ||
89 | * curl_easy handle. | ||
90 | */ | ||
91 | CURL *curl; | ||
92 | |||
93 | /** | ||
94 | * curl_multi handle. | ||
95 | */ | ||
96 | CURLM *multi; | ||
97 | |||
98 | /** | ||
99 | * URL of the file to download. | ||
100 | */ | ||
101 | char *url; | ||
102 | |||
103 | /** | ||
104 | * Time corresponding to timeout wanted by the caller. | ||
105 | */ | ||
106 | struct GNUNET_TIME_Absolute end_time; | ||
107 | |||
108 | /** | ||
109 | * Buffer to store downloaded content. | ||
110 | */ | ||
111 | char download_buffer[DESCRIPTION_BUFSIZE]; | ||
112 | |||
113 | /** | ||
114 | * Size of the already downloaded content. | ||
115 | */ | ||
116 | size_t download_pos; | ||
117 | |||
118 | /** | ||
119 | * User callback to trigger when done. | ||
120 | */ | ||
121 | download_cb caller_cb; | ||
122 | |||
123 | /** | ||
124 | * User closure to pass to caller_cb. | ||
125 | */ | ||
126 | void *caller_cls; | ||
127 | }; | ||
128 | |||
129 | /** | ||
130 | * Clean up the state of CURL multi handle and that of | ||
131 | * the only easy handle it uses. | ||
132 | */ | ||
133 | static void | ||
134 | download_clean_up (struct download_cls *cls) | ||
135 | { | ||
136 | CURLMcode mret; | ||
137 | |||
138 | mret = curl_multi_cleanup (cls->multi); | ||
139 | if (mret != CURLM_OK) | ||
140 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "UPnP", | ||
141 | _("%s failed at %s:%d: `%s'\n"), | ||
142 | "curl_multi_cleanup", __FILE__, __LINE__, | ||
143 | curl_multi_strerror (mret)); | ||
144 | |||
145 | curl_easy_cleanup (cls->curl); | ||
146 | GNUNET_free (cls); | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * Process downloaded bits by calling callback on each HELLO. | ||
151 | * | ||
152 | * @param ptr buffer with downloaded data | ||
153 | * @param size size of a record | ||
154 | * @param nmemb number of records downloaded | ||
155 | * @param ctx closure | ||
156 | * @return number of bytes that were processed (always size*nmemb) | ||
157 | */ | ||
158 | static size_t | ||
159 | callback_download (void *ptr, size_t size, size_t nmemb, void *ctx) | ||
160 | { | ||
161 | struct download_cls *cls = ctx; | ||
162 | const char *cbuf = ptr; | ||
163 | size_t total; | ||
164 | size_t cpy; | ||
165 | |||
166 | total = size * nmemb; | ||
167 | if (total == 0) | ||
168 | return total; /* ok, no data */ | ||
169 | |||
170 | cpy = GNUNET_MIN (total, DESCRIPTION_BUFSIZE - cls->download_pos - 1); | ||
171 | memcpy (&cls->download_buffer[cls->download_pos], cbuf, cpy); | ||
172 | cbuf += cpy; | ||
173 | cls->download_pos += cpy; | ||
174 | |||
175 | #if DEBUG_UPNP | ||
176 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
177 | "Downloaded %d records of size %d, download position: %d\n", | ||
178 | size, nmemb, cls->download_pos); | ||
179 | #endif | ||
180 | |||
181 | return total; | ||
182 | } | ||
183 | |||
184 | static void | ||
185 | task_download (void *cls, | ||
186 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
187 | |||
188 | /** | ||
189 | * Ask CURL for the select set and then schedule the | ||
190 | * receiving task with the scheduler. | ||
191 | */ | ||
192 | static void | ||
193 | download_prepare (struct download_cls *cls) | ||
194 | { | ||
195 | CURLMcode mret; | ||
196 | fd_set rs; | ||
197 | fd_set ws; | ||
198 | fd_set es; | ||
199 | int max; | ||
200 | struct GNUNET_NETWORK_FDSet *grs; | ||
201 | struct GNUNET_NETWORK_FDSet *gws; | ||
202 | long timeout; | ||
203 | struct GNUNET_TIME_Relative rtime; | ||
204 | |||
205 | max = -1; | ||
206 | FD_ZERO (&rs); | ||
207 | FD_ZERO (&ws); | ||
208 | FD_ZERO (&es); | ||
209 | mret = curl_multi_fdset (cls->multi, &rs, &ws, &es, &max); | ||
210 | if (mret != CURLM_OK) | ||
211 | { | ||
212 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "UPnP", | ||
213 | _("%s failed at %s:%d: `%s'\n"), | ||
214 | "curl_multi_fdset", __FILE__, __LINE__, | ||
215 | curl_multi_strerror (mret)); | ||
216 | download_clean_up (cls); | ||
217 | cls->caller_cb (NULL, cls->caller_cls); | ||
218 | return; | ||
219 | } | ||
220 | mret = curl_multi_timeout (cls->multi, &timeout); | ||
221 | if (mret != CURLM_OK) | ||
222 | { | ||
223 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "UPnP", | ||
224 | _("%s failed at %s:%d: `%s'\n"), | ||
225 | "curl_multi_timeout", __FILE__, __LINE__, | ||
226 | curl_multi_strerror (mret)); | ||
227 | download_clean_up (cls); | ||
228 | cls->caller_cb (NULL, cls->caller_cls); | ||
229 | return; | ||
230 | } | ||
231 | rtime = | ||
232 | GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining | ||
233 | (cls->end_time), | ||
234 | GNUNET_TIME_relative_multiply | ||
235 | (GNUNET_TIME_UNIT_MILLISECONDS, timeout)); | ||
236 | grs = GNUNET_NETWORK_fdset_create (); | ||
237 | gws = GNUNET_NETWORK_fdset_create (); | ||
238 | GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); | ||
239 | GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); | ||
240 | |||
241 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
242 | GNUNET_SCHEDULER_NO_TASK, | ||
243 | rtime, | ||
244 | grs, | ||
245 | gws, | ||
246 | & task_download, cls); | ||
247 | GNUNET_NETWORK_fdset_destroy (gws); | ||
248 | GNUNET_NETWORK_fdset_destroy (grs); | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * Task that is run when we are ready to receive more data from the device. | ||
253 | * | ||
254 | * @param cls closure | ||
255 | * @param tc task context | ||
256 | */ | ||
257 | static void | ||
258 | task_download (void *cls, | ||
259 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
260 | { | ||
261 | struct download_cls *dc = cls; | ||
262 | int running; | ||
263 | struct CURLMsg *msg; | ||
264 | CURLMcode mret; | ||
265 | |||
266 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
267 | { | ||
268 | #if DEBUG_UPNP | ||
269 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
270 | "Shutdown requested while trying to download device description from `%s'\n", | ||
271 | dc->url); | ||
272 | #endif | ||
273 | dc->caller_cb (NULL, dc->caller_cls); | ||
274 | download_clean_up (dc); | ||
275 | return; | ||
276 | } | ||
277 | if (GNUNET_TIME_absolute_get_remaining (dc->end_time).rel_value == 0) | ||
278 | { | ||
279 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "UPnP", | ||
280 | _ | ||
281 | ("Timeout trying to download UPnP device description from '%s'\n"), | ||
282 | dc->url); | ||
283 | dc->caller_cb (NULL, dc->caller_cls); | ||
284 | download_clean_up (dc); | ||
285 | return; | ||
286 | } | ||
287 | |||
288 | do | ||
289 | { | ||
290 | running = 0; | ||
291 | mret = curl_multi_perform (dc->multi, &running); | ||
292 | |||
293 | if (running == 0) | ||
294 | { | ||
295 | do | ||
296 | { | ||
297 | msg = curl_multi_info_read (dc->multi, &running); | ||
298 | GNUNET_break (msg != NULL); | ||
299 | if (msg == NULL) | ||
300 | break; | ||
301 | |||
302 | if ((msg->data.result != CURLE_OK) && | ||
303 | (msg->data.result != CURLE_GOT_NOTHING)) | ||
304 | { | ||
305 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
306 | _("%s failed for `%s' at %s:%d: `%s'\n"), | ||
307 | "curl_multi_perform", | ||
308 | dc->url, | ||
309 | __FILE__, | ||
310 | __LINE__, | ||
311 | curl_easy_strerror (msg->data.result)); | ||
312 | dc->caller_cb (NULL, dc->caller_cls); | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
317 | _ | ||
318 | ("Download of device description `%s' completed.\n"), | ||
319 | dc->url); | ||
320 | dc->caller_cb (GNUNET_strdup (dc->download_buffer), | ||
321 | dc->caller_cls); | ||
322 | } | ||
323 | |||
324 | download_clean_up (dc); | ||
325 | return; | ||
326 | } | ||
327 | while ((running > 0)); | ||
328 | } | ||
329 | } | ||
330 | while (mret == CURLM_CALL_MULTI_PERFORM); | ||
331 | |||
332 | if (mret != CURLM_OK) | ||
333 | { | ||
334 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "UPnP", | ||
335 | _("%s failed at %s:%d: `%s'\n"), | ||
336 | "curl_multi_perform", __FILE__, __LINE__, | ||
337 | curl_multi_strerror (mret)); | ||
338 | download_clean_up (dc); | ||
339 | dc->caller_cb (NULL, dc->caller_cls); | ||
340 | } | ||
341 | |||
342 | download_prepare (dc); | ||
343 | } | ||
344 | |||
345 | |||
346 | /** | ||
347 | * Download description from devices. | ||
348 | * | ||
349 | * @param url URL of the file to download | ||
350 | * @param caller_cb user function to call when done | ||
351 | * @param caller_cls closure to pass to caller_cb | ||
352 | */ | ||
353 | void | ||
354 | download_device_description (char *url, download_cb caller_cb, | ||
355 | void *caller_cls) | ||
356 | { | ||
357 | CURL *curl; | ||
358 | CURLM *multi; | ||
359 | CURLcode ret; | ||
360 | CURLMcode mret; | ||
361 | struct download_cls *cls; | ||
362 | |||
363 | cls = GNUNET_malloc (sizeof (struct download_cls)); | ||
364 | |||
365 | curl = curl_easy_init (); | ||
366 | if (curl == NULL) | ||
367 | goto error; | ||
368 | |||
369 | CURL_EASY_SETOPT (curl, CURLOPT_WRITEFUNCTION, &callback_download); | ||
370 | if (ret != CURLE_OK) | ||
371 | goto error; | ||
372 | |||
373 | CURL_EASY_SETOPT (curl, CURLOPT_WRITEDATA, cls); | ||
374 | if (ret != CURLE_OK) | ||
375 | goto error; | ||
376 | |||
377 | CURL_EASY_SETOPT (curl, CURLOPT_FOLLOWLOCATION, 1); | ||
378 | CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 4); | ||
379 | /* no need to abort if the above failed */ | ||
380 | CURL_EASY_SETOPT (curl, CURLOPT_URL, url); | ||
381 | if (ret != CURLE_OK) | ||
382 | goto error; | ||
383 | |||
384 | CURL_EASY_SETOPT (curl, CURLOPT_FAILONERROR, 1); | ||
385 | CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, DESCRIPTION_BUFSIZE); | ||
386 | CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet"); | ||
387 | CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 60L); | ||
388 | CURL_EASY_SETOPT (curl, CURLOPT_TIMEOUT, 60L); | ||
389 | |||
390 | multi = curl_multi_init (); | ||
391 | if (multi == NULL) | ||
392 | { | ||
393 | GNUNET_break (0); | ||
394 | /* clean_up (); */ | ||
395 | return; | ||
396 | } | ||
397 | mret = curl_multi_add_handle (multi, curl); | ||
398 | if (mret != CURLM_OK) | ||
399 | { | ||
400 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "UPnP", | ||
401 | _("%s failed at %s:%d: `%s'\n"), | ||
402 | "curl_multi_add_handle", __FILE__, __LINE__, | ||
403 | curl_multi_strerror (mret)); | ||
404 | mret = curl_multi_cleanup (multi); | ||
405 | if (mret != CURLM_OK) | ||
406 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "UPnP", | ||
407 | _("%s failed at %s:%d: `%s'\n"), | ||
408 | "curl_multi_cleanup", __FILE__, __LINE__, | ||
409 | curl_multi_strerror (mret)); | ||
410 | goto error; | ||
411 | return; | ||
412 | } | ||
413 | |||
414 | #if DEBUG_UPNP | ||
415 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
416 | "Preparing to download device description from '%s'\n", | ||
417 | url); | ||
418 | #endif | ||
419 | |||
420 | cls->curl = curl; | ||
421 | cls->multi = multi; | ||
422 | cls->url = url; | ||
423 | cls->end_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES); | ||
424 | memset (cls->download_buffer, 0, DESCRIPTION_BUFSIZE); | ||
425 | cls->download_pos = 0; | ||
426 | cls->caller_cb = caller_cb; | ||
427 | cls->caller_cls = caller_cls; | ||
428 | download_prepare (cls); | ||
429 | return; | ||
430 | |||
431 | |||
432 | error: | ||
433 | GNUNET_break (0); | ||
434 | GNUNET_free (cls); | ||
435 | curl_easy_cleanup (curl); | ||
436 | caller_cb (NULL, caller_cls); | ||
437 | } | ||
438 | |||
439 | /** | ||
440 | * Parse SSDP packet received in reply to a M-SEARCH message. | ||
441 | * | ||
442 | * @param reply contents of the packet | ||
443 | * @param size length of reply | ||
444 | * @param location address of a pointer that will be set to the start | ||
445 | * of the "location" field | ||
446 | * @param location_size pointer where to store the length of the "location" field | ||
447 | * @param st pointer address of a pointer that will be set to the start | ||
448 | * of the "st" (search target) field | ||
449 | * @param st_size pointer where to store the length of the "st" field | ||
450 | * The strings are NOT null terminated */ | ||
451 | static void | ||
452 | parse_msearch_reply (const char *reply, int size, | ||
453 | const char **location, int *location_size, | ||
454 | const char **st, int *st_size) | ||
455 | { | ||
456 | int a, b, i; | ||
457 | |||
458 | i = 0; | ||
459 | b = 0; | ||
460 | /* Start of the line */ | ||
461 | a = i; | ||
462 | |||
463 | while (i < size) | ||
464 | { | ||
465 | switch (reply[i]) | ||
466 | { | ||
467 | case ':': | ||
468 | if (b == 0) | ||
469 | /* End of the "header" */ | ||
470 | b = i; | ||
471 | break; | ||
472 | case '\x0a': | ||
473 | case '\x0d': | ||
474 | if (b != 0) | ||
475 | { | ||
476 | do | ||
477 | { | ||
478 | b++; | ||
479 | } | ||
480 | while (reply[b] == ' '); | ||
481 | |||
482 | if (0 == strncasecmp (reply + a, "location", 8)) | ||
483 | { | ||
484 | *location = reply + b; | ||
485 | *location_size = i - b; | ||
486 | } | ||
487 | else if (0 == strncasecmp (reply + a, "st", 2)) | ||
488 | { | ||
489 | *st = reply + b; | ||
490 | *st_size = i - b; | ||
491 | } | ||
492 | |||
493 | b = 0; | ||
494 | } | ||
495 | |||
496 | a = i + 1; | ||
497 | break; | ||
498 | default: | ||
499 | break; | ||
500 | } | ||
501 | |||
502 | i++; | ||
503 | } | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * Standard port for UPnP discovery (SSDP protocol). | ||
508 | */ | ||
509 | #define PORT 1900 | ||
510 | |||
511 | /** | ||
512 | * Convert a constant integer into a string. | ||
513 | */ | ||
514 | #define XSTR(s) STR(s) | ||
515 | #define STR(s) #s | ||
516 | |||
517 | /** | ||
518 | * Standard IPv4 multicast adress for UPnP discovery (SSDP protocol). | ||
519 | */ | ||
520 | #define UPNP_MCAST_ADDR "239.255.255.250" | ||
521 | |||
522 | /** | ||
523 | * Standard IPv6 multicast adress for UPnP discovery (SSDP protocol). | ||
524 | */ | ||
525 | #define UPNP_MCAST_ADDR6 "FF02:0:0:0:0:0:0:F" | ||
526 | |||
527 | /** | ||
528 | * Size of the buffer needed to store SSDP requests we send. | ||
529 | */ | ||
530 | #define UPNP_DISCOVER_BUFSIZE 1536 | ||
531 | |||
532 | /** | ||
533 | * Description of a UPnP device containing everything | ||
534 | * we may need to control it. | ||
535 | * | ||
536 | * Meant to be member of a chained list. | ||
537 | */ | ||
538 | struct UPNP_Dev_ | ||
539 | { | ||
540 | /** | ||
541 | * Next device in the list, if any. | ||
542 | */ | ||
543 | struct UPNP_Dev_ *pNext; | ||
544 | |||
545 | /** | ||
546 | * Path to the file describing the device. | ||
547 | */ | ||
548 | char *desc_url; | ||
549 | |||
550 | /** | ||
551 | * UPnP search target. | ||
552 | */ | ||
553 | char *st; | ||
554 | |||
555 | /** | ||
556 | * Service type associated with the control_url for the device. | ||
557 | */ | ||
558 | char *service_type; | ||
559 | |||
560 | /** | ||
561 | * URL to send commands to. | ||
562 | */ | ||
563 | char *control_url; | ||
564 | |||
565 | /** | ||
566 | * Whether the device is currently connected to the WAN. | ||
567 | */ | ||
568 | int is_connected; | ||
569 | |||
570 | /** | ||
571 | * IGD Data associated with the device. | ||
572 | */ | ||
573 | struct UPNP_IGD_Data_ *data; | ||
574 | }; | ||
575 | |||
576 | /** | ||
577 | * Private closure used by UPNP_discover() and its callbacks. | ||
578 | */ | ||
579 | struct UPNP_discover_cls | ||
580 | { | ||
581 | /** | ||
582 | * Remote address used for multicast emission and reception. | ||
583 | */ | ||
584 | struct sockaddr *multicast_addr; | ||
585 | |||
586 | /** | ||
587 | * Network handle used to send and receive discovery messages. | ||
588 | */ | ||
589 | struct GNUNET_NETWORK_Handle *sudp; | ||
590 | |||
591 | /** | ||
592 | * fdset used with sudp. | ||
593 | */ | ||
594 | struct GNUNET_NETWORK_FDSet *fdset; | ||
595 | |||
596 | /** | ||
597 | * Connection handle used to download device description. | ||
598 | */ | ||
599 | struct GNUNET_CONNECTION_Handle *s; | ||
600 | |||
601 | /** | ||
602 | * Transmission handle used with s. | ||
603 | */ | ||
604 | struct GNUNET_CONNECTION_TransmitHandle *th; | ||
605 | |||
606 | /** | ||
607 | * Index of the UPnP device type we're currently sending discovery messages to. | ||
608 | */ | ||
609 | int type_index; | ||
610 | |||
611 | /** | ||
612 | * List of discovered devices. | ||
613 | */ | ||
614 | struct UPNP_Dev_ *dev_list; | ||
615 | |||
616 | /** | ||
617 | * Device we're currently fetching description from. | ||
618 | */ | ||
619 | struct UPNP_Dev_ *current_dev; | ||
620 | |||
621 | /** | ||
622 | * User callback to trigger when done. | ||
623 | */ | ||
624 | UPNP_discover_cb_ caller_cb; | ||
625 | |||
626 | /** | ||
627 | * Closure passed to caller_cb. | ||
628 | */ | ||
629 | void *caller_cls; | ||
630 | }; | ||
631 | |||
632 | /** | ||
633 | * Check that raw_url is absolute, and if not, use ref_url to resolve it: | ||
634 | * if is_desc_file is GNUNET_YES, the path to the parent of the file is used; | ||
635 | * if it is GNUNET_NO, ref_url will be considered as the base URL for raw URL. | ||
636 | * | ||
637 | * @param ref_url base URL for the device | ||
638 | * @param is_desc_file whether ref_url is a path to the description file | ||
639 | * @param raw_url a possibly relative URL | ||
640 | * @returns a new string with an absolute URL | ||
641 | */ | ||
642 | static char * | ||
643 | get_absolute_url (const char *ref_url, int is_desc_file, const char *raw_url) | ||
644 | { | ||
645 | char *final_url; | ||
646 | |||
647 | if ((raw_url[0] == 'h') | ||
648 | && (raw_url[1] == 't') | ||
649 | && (raw_url[2] == 't') | ||
650 | && (raw_url[3] == 'p') | ||
651 | && (raw_url[4] == ':') && (raw_url[5] == '/') && (raw_url[6] == '/')) | ||
652 | { | ||
653 | final_url = GNUNET_strdup (raw_url); | ||
654 | } | ||
655 | else | ||
656 | { | ||
657 | int n = strlen (raw_url); | ||
658 | int l = strlen (ref_url); | ||
659 | int cpy_len = l; | ||
660 | char *slash; | ||
661 | |||
662 | /* If base URL is a path to the description file, go one level higher */ | ||
663 | if (is_desc_file == GNUNET_YES) | ||
664 | { | ||
665 | slash = strrchr (ref_url, '/'); | ||
666 | cpy_len = slash - ref_url; | ||
667 | } | ||
668 | |||
669 | final_url = GNUNET_malloc (l + n + 1); | ||
670 | |||
671 | /* Add trailing slash to base URL if needed */ | ||
672 | if (raw_url[0] != '/' && ref_url[cpy_len] != '\0') | ||
673 | final_url[cpy_len++] = '/'; | ||
674 | |||
675 | strncpy (final_url, ref_url, cpy_len); | ||
676 | strcpy (final_url + cpy_len, raw_url); | ||
677 | final_url[cpy_len + n] = '\0'; | ||
678 | } | ||
679 | |||
680 | return final_url; | ||
681 | } | ||
682 | |||
683 | |||
684 | /** | ||
685 | * Construct control URL and service type for device from its description URL | ||
686 | * and UPNP_IGD_Data_ information. This involves resolving relative paths | ||
687 | * and choosing between Common Interface Config and interface-specific | ||
688 | * paths. | ||
689 | * | ||
690 | * @param desc_url URL to the description file of the device | ||
691 | * @param data IGD information obtained from the description file | ||
692 | * @param control_url place to store a URL to control the IGD device (will be | ||
693 | * the empty string in case of failure) | ||
694 | * @param service_type place to store the service type corresponding to control_url | ||
695 | * (will be the empty string in case of failure) | ||
696 | */ | ||
697 | static void | ||
698 | format_control_urls (const char *desc_url, struct UPNP_IGD_Data_ *data, char **control_url, char **service_type) | ||
699 | { | ||
700 | const char *ref_url; | ||
701 | int is_desc_file; | ||
702 | |||
703 | if (data->base_url[0] != '\0') | ||
704 | { | ||
705 | ref_url = data->base_url; | ||
706 | is_desc_file = GNUNET_NO; | ||
707 | } | ||
708 | else | ||
709 | { | ||
710 | ref_url = desc_url; | ||
711 | is_desc_file = GNUNET_YES; | ||
712 | } | ||
713 | |||
714 | if (data->control_url[0] != '\0') | ||
715 | { | ||
716 | *control_url = get_absolute_url (ref_url, is_desc_file, data->control_url); | ||
717 | *service_type = GNUNET_strdup (data->service_type); | ||
718 | } | ||
719 | else if (data->control_url_CIF[0] != '\0') | ||
720 | { | ||
721 | *control_url = get_absolute_url (ref_url, is_desc_file, data->control_url_CIF); | ||
722 | *service_type = GNUNET_strdup (data->service_type_CIF); | ||
723 | } | ||
724 | else | ||
725 | { | ||
726 | /* If no suitable URL-service type pair was found, set both to empty | ||
727 | * to avoid pretending things will work */ | ||
728 | *control_url = GNUNET_strdup (""); | ||
729 | *service_type = GNUNET_strdup (""); | ||
730 | } | ||
731 | } | ||
732 | |||
733 | static void get_valid_igd (struct UPNP_discover_cls *cls); | ||
734 | |||
735 | /** | ||
736 | * Called when "GetStatusInfo" command finishes. Check whether IGD device reports | ||
737 | * to be currently connected or not. | ||
738 | * | ||
739 | * @param response content of the UPnP message answered by the device | ||
740 | * @param received number of received bytes stored in response | ||
741 | * @param data closure from UPNP_discover() | ||
742 | */ | ||
743 | static void | ||
744 | get_valid_igd_connected_cb (char *response, size_t received, void *data) | ||
745 | { | ||
746 | struct UPNP_discover_cls *cls = data; | ||
747 | struct UPNP_REPLY_NameValueList_ pdata; | ||
748 | char *status; | ||
749 | char *error; | ||
750 | |||
751 | UPNP_REPLY_parse_ (response, received, &pdata); | ||
752 | |||
753 | status = UPNP_REPLY_get_value_ (&pdata, "NewConnectionStatus"); | ||
754 | error = UPNP_REPLY_get_value_ (&pdata, "errorCode"); | ||
755 | |||
756 | if (status) | ||
757 | cls->current_dev->is_connected = (strcmp ("Connected", status) == 0); | ||
758 | else | ||
759 | cls->current_dev->is_connected = GNUNET_NO; | ||
760 | |||
761 | if (error) | ||
762 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "UPnP", | ||
763 | _("Could not get UPnP device status: error %s\n"), | ||
764 | error); | ||
765 | |||
766 | GNUNET_free (response); | ||
767 | UPNP_REPLY_free_ (&pdata); | ||
768 | |||
769 | /* Go on to next device, or finish discovery process */ | ||
770 | cls->current_dev = cls->current_dev->pNext; | ||
771 | get_valid_igd (cls); | ||
772 | } | ||
773 | |||
774 | /** | ||
775 | * Receive contents of the downloaded UPnP IGD description file, | ||
776 | * and fill UPNP_Dev_ and UPNP_IGD_Data_ structs with this data. | ||
777 | * Then, schedule UPnP command to check whether device is connected. | ||
778 | * | ||
779 | * @param desc UPnP IGD description (in XML) | ||
780 | * @param data closure from UPNP_discover() | ||
781 | */ | ||
782 | static void | ||
783 | get_valid_igd_receive (char *desc, void *data) | ||
784 | { | ||
785 | struct UPNP_discover_cls *cls = data; | ||
786 | struct UPNP_IGD_Data_ *igd_data; | ||
787 | char *buffer; | ||
788 | |||
789 | if (!desc || strlen (desc) == 0) | ||
790 | { | ||
791 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "UPnP", | ||
792 | "Error getting IGD XML description at %s:%d\n", | ||
793 | __FILE__, __LINE__); | ||
794 | |||
795 | /* Skip device */ | ||
796 | cls->current_dev->data = NULL; | ||
797 | cls->current_dev->is_connected = GNUNET_NO; | ||
798 | get_valid_igd (cls); | ||
799 | } | ||
800 | |||
801 | igd_data = GNUNET_malloc (sizeof (struct UPNP_IGD_Data_)); | ||
802 | memset (igd_data, 0, sizeof (struct UPNP_IGD_Data_)); | ||
803 | UPNP_IGD_parse_desc_ (desc, strlen (desc), igd_data); | ||
804 | |||
805 | format_control_urls (cls->current_dev->desc_url, igd_data, | ||
806 | &cls->current_dev->control_url, | ||
807 | &cls->current_dev->service_type); | ||
808 | |||
809 | cls->current_dev->data = igd_data; | ||
810 | |||
811 | /* Check whether device is connected */ | ||
812 | buffer = GNUNET_malloc (UPNP_COMMAND_BUFSIZE); | ||
813 | UPNP_command_ (cls->current_dev->control_url, | ||
814 | cls->current_dev->data->service_type, | ||
815 | "GetStatusInfo", NULL, buffer, UPNP_COMMAND_BUFSIZE, | ||
816 | get_valid_igd_connected_cb, cls); | ||
817 | |||
818 | GNUNET_free (desc); | ||
819 | } | ||
820 | |||
821 | /** | ||
822 | * Free a chained list of UPnP devices. | ||
823 | */ | ||
824 | static void | ||
825 | free_dev_list (struct UPNP_Dev_ *devlist) | ||
826 | { | ||
827 | struct UPNP_Dev_ *next; | ||
828 | |||
829 | while (devlist) | ||
830 | { | ||
831 | next = devlist->pNext; | ||
832 | GNUNET_free (devlist->control_url); | ||
833 | GNUNET_free (devlist->service_type); | ||
834 | GNUNET_free (devlist->desc_url); | ||
835 | GNUNET_free (devlist->data); | ||
836 | GNUNET_free (devlist->st); | ||
837 | GNUNET_free (devlist); | ||
838 | devlist = next; | ||
839 | } | ||
840 | } | ||
841 | |||
842 | /** | ||
843 | * Walk over the list of found devices looking for a connected IGD, | ||
844 | * if present, or at least a disconnected one. | ||
845 | */ | ||
846 | static void | ||
847 | get_valid_igd (struct UPNP_discover_cls *cls) | ||
848 | { | ||
849 | struct UPNP_Dev_ *dev; | ||
850 | int step; | ||
851 | |||
852 | /* No device was discovered */ | ||
853 | if (!cls->dev_list) | ||
854 | { | ||
855 | cls->caller_cb (NULL, NULL, cls->caller_cls); | ||
856 | |||
857 | GNUNET_free (cls); | ||
858 | return; | ||
859 | } | ||
860 | /* We already walked over all devices, see what we got, | ||
861 | * and return the device with the best state we have. */ | ||
862 | else if (cls->current_dev == NULL) | ||
863 | { | ||
864 | for (step = 1; step <= 3; step++) | ||
865 | { | ||
866 | for (dev = cls->dev_list; dev; dev = dev->pNext) | ||
867 | { | ||
868 | #if DEBUG_UPNP | ||
869 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
870 | "Found device: control_url: %s, service_type: %s\n", | ||
871 | dev->control_url, dev->service_type); | ||
872 | #endif | ||
873 | /* Accept connected IGDs on step 1, non-connected IGDs | ||
874 | * on step 2, and other device types on step 3. */ | ||
875 | if ((step == 1 && dev->is_connected) | ||
876 | || (step < 3 && 0 != strcmp (dev->service_type, | ||
877 | "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"))) | ||
878 | continue; | ||
879 | |||
880 | cls->caller_cb (dev->control_url, | ||
881 | dev->service_type, cls->caller_cls); | ||
882 | |||
883 | free_dev_list (cls->dev_list); | ||
884 | GNUNET_free (cls); | ||
885 | return; | ||
886 | } | ||
887 | } | ||
888 | |||
889 | /* We cannot reach this... */ | ||
890 | GNUNET_assert (GNUNET_NO); | ||
891 | } | ||
892 | |||
893 | /* There are still devices to ask, go on */ | ||
894 | download_device_description (cls->current_dev->desc_url, | ||
895 | get_valid_igd_receive, cls); | ||
896 | } | ||
897 | |||
898 | static const char *const discover_type_list[] = { | ||
899 | "urn:schemas-upnp-org:device:InternetGatewayDevice:1", | ||
900 | "urn:schemas-upnp-org:service:WANIPConnection:1", | ||
901 | "urn:schemas-upnp-org:service:WANPPPConnection:1", | ||
902 | NULL | ||
903 | }; | ||
904 | |||
905 | static void | ||
906 | discover_send (void *data, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
907 | |||
908 | /** | ||
909 | * Handle response from device. Stop when all device types have been tried, | ||
910 | * and get their descriptions. | ||
911 | * | ||
912 | * @param data closure from UPNP_discover() | ||
913 | * @param tc task context | ||
914 | */ | ||
915 | static void | ||
916 | discover_recv (void *data, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
917 | { | ||
918 | struct UPNP_discover_cls *cls = data; | ||
919 | GNUNET_SCHEDULER_TaskIdentifier task_w; | ||
920 | struct UPNP_Dev_ *tmp; | ||
921 | socklen_t addrlen; | ||
922 | ssize_t received; | ||
923 | char buf[DISCOVER_BUFSIZE]; | ||
924 | const char *desc_url = NULL; | ||
925 | int urlsize = 0; | ||
926 | const char *st = NULL; | ||
927 | int stsize = 0; | ||
928 | |||
929 | /* Free fdset that was used for this sned/receive operation */ | ||
930 | GNUNET_NETWORK_fdset_destroy (cls->fdset); | ||
931 | |||
932 | if (cls->multicast_addr->sa_family == AF_INET) | ||
933 | addrlen = sizeof (struct sockaddr_in); | ||
934 | else | ||
935 | addrlen = sizeof (struct sockaddr_in6); | ||
936 | |||
937 | errno = 0; | ||
938 | received = | ||
939 | GNUNET_NETWORK_socket_recvfrom (cls->sudp, &buf, DISCOVER_BUFSIZE - 1, | ||
940 | (struct sockaddr *) cls->multicast_addr, | ||
941 | &addrlen); | ||
942 | if (received == GNUNET_SYSERR) | ||
943 | { | ||
944 | if (errno != EAGAIN) | ||
945 | PRINT_SOCKET_ERROR ("GNUNET_NETWORK_socket_recvfrom"); | ||
946 | } | ||
947 | #if DEBUG_UPNP | ||
948 | else | ||
949 | { | ||
950 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
951 | "Received %d bytes from %s\n", received, | ||
952 | GNUNET_a2s (cls->multicast_addr, addrlen)); | ||
953 | } | ||
954 | #endif | ||
955 | |||
956 | parse_msearch_reply (buf, received, &desc_url, &urlsize, &st, &stsize); | ||
957 | |||
958 | if (st && desc_url) | ||
959 | { | ||
960 | tmp = (struct UPNP_Dev_ *) GNUNET_malloc (sizeof (struct UPNP_Dev_)); | ||
961 | tmp->pNext = cls->dev_list; | ||
962 | |||
963 | tmp->desc_url = GNUNET_malloc (urlsize + 1); | ||
964 | strncpy (tmp->desc_url, desc_url, urlsize); | ||
965 | tmp->desc_url[urlsize] = '\0'; | ||
966 | |||
967 | tmp->st = GNUNET_malloc (stsize + 1); | ||
968 | strncpy (tmp->st, st, stsize); | ||
969 | tmp->st[stsize] = '\0'; | ||
970 | cls->dev_list = tmp; | ||
971 | #if DEBUG_UPNP | ||
972 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
973 | "Found device %s when looking for type %s\n", | ||
974 | tmp->desc_url, tmp->st); | ||
975 | #endif | ||
976 | } | ||
977 | |||
978 | /* Continue discovery until all types of devices have been tried */ | ||
979 | if (discover_type_list[cls->type_index]) | ||
980 | { | ||
981 | /* Send queries for each device type and wait for a possible reply. | ||
982 | * receiver callback takes care of trying another device type, | ||
983 | * and eventually calls the caller's callback. */ | ||
984 | cls->fdset = GNUNET_NETWORK_fdset_create (); | ||
985 | GNUNET_NETWORK_fdset_zero (cls->fdset); | ||
986 | GNUNET_NETWORK_fdset_set (cls->fdset, cls->sudp); | ||
987 | |||
988 | task_w = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
989 | GNUNET_SCHEDULER_NO_TASK, | ||
990 | GNUNET_TIME_relative_multiply | ||
991 | (GNUNET_TIME_UNIT_SECONDS, 15), | ||
992 | NULL, cls->fdset, &discover_send, | ||
993 | cls); | ||
994 | |||
995 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
996 | task_w, | ||
997 | GNUNET_TIME_relative_multiply | ||
998 | (GNUNET_TIME_UNIT_SECONDS, 5), cls->fdset, | ||
999 | NULL, &discover_recv, cls); | ||
1000 | } | ||
1001 | else | ||
1002 | { | ||
1003 | GNUNET_NETWORK_socket_close (cls->sudp); | ||
1004 | GNUNET_free (cls->multicast_addr); | ||
1005 | cls->current_dev = cls->dev_list; | ||
1006 | get_valid_igd (cls); | ||
1007 | } | ||
1008 | } | ||
1009 | |||
1010 | /** | ||
1011 | * Send the SSDP M-SEARCH packet. | ||
1012 | * | ||
1013 | * @param data closure from UPNP_discover() | ||
1014 | * @param tc task context | ||
1015 | */ | ||
1016 | static void | ||
1017 | discover_send (void *data, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1018 | { | ||
1019 | struct UPNP_discover_cls *cls = data; | ||
1020 | socklen_t addrlen; | ||
1021 | ssize_t n, sent; | ||
1022 | char buf[DISCOVER_BUFSIZE]; | ||
1023 | static const char msearch_msg[] = | ||
1024 | "M-SEARCH * HTTP/1.1\r\n" | ||
1025 | "HOST: " UPNP_MCAST_ADDR ":" XSTR (PORT) "\r\n" | ||
1026 | "ST: %s\r\n" "MAN: \"ssdp:discover\"\r\n" "MX: 3\r\n" "\r\n"; | ||
1027 | |||
1028 | if (cls->multicast_addr->sa_family == AF_INET) | ||
1029 | addrlen = sizeof (struct sockaddr_in); | ||
1030 | else | ||
1031 | addrlen = sizeof (struct sockaddr_in6); | ||
1032 | |||
1033 | n = | ||
1034 | snprintf (buf, DISCOVER_BUFSIZE, msearch_msg, | ||
1035 | discover_type_list[cls->type_index++]); | ||
1036 | |||
1037 | errno = 0; | ||
1038 | sent = GNUNET_NETWORK_socket_sendto (cls->sudp, buf, n, | ||
1039 | (struct sockaddr *) | ||
1040 | cls->multicast_addr, addrlen); | ||
1041 | if (sent == GNUNET_SYSERR) | ||
1042 | { | ||
1043 | PRINT_SOCKET_ERROR ("GNUNET_NETWORK_socket_sendto"); | ||
1044 | } | ||
1045 | else if (sent < n) | ||
1046 | { | ||
1047 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
1048 | "Could only send %d bytes to %s, needed %d bytes\n", | ||
1049 | sent, GNUNET_a2s (cls->multicast_addr, addrlen), n); | ||
1050 | } | ||
1051 | #if DEBUG_UPNP | ||
1052 | else | ||
1053 | { | ||
1054 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
1055 | "Sent %d bytes to %s\n", sent, | ||
1056 | GNUNET_a2s (cls->multicast_addr, addrlen)); | ||
1057 | } | ||
1058 | #endif | ||
1059 | } | ||
1060 | |||
1061 | /** | ||
1062 | * Search for UPnP Internet Gateway Devices (IGD) on a given network interface. | ||
1063 | * If several devices are found, a device that is connected to the WAN | ||
1064 | * is returned first (if any). | ||
1065 | * | ||
1066 | * @param multicastif network interface to send discovery messages, or NULL | ||
1067 | * @param addr address used to send messages on multicastif, or NULL | ||
1068 | * @param caller_cb user function to call when done | ||
1069 | * @param caller_cls closure to pass to caller_cb | ||
1070 | */ | ||
1071 | void | ||
1072 | UPNP_discover_ (const char *multicastif, | ||
1073 | const struct sockaddr *addr, | ||
1074 | UPNP_discover_cb_ caller_cb, void *caller_cls) | ||
1075 | { | ||
1076 | int opt = 1; | ||
1077 | int domain = PF_INET; | ||
1078 | int if_index; | ||
1079 | struct in6_addr any_addr = IN6ADDR_ANY_INIT; | ||
1080 | struct sockaddr_in sockudp_r, sockudp_w; | ||
1081 | struct sockaddr_in6 sockudp6_r, sockudp6_w; | ||
1082 | GNUNET_SCHEDULER_TaskIdentifier task_w; | ||
1083 | struct GNUNET_NETWORK_Handle *sudp; | ||
1084 | struct UPNP_discover_cls *cls; | ||
1085 | |||
1086 | |||
1087 | if (addr && addr->sa_family == AF_INET) | ||
1088 | { | ||
1089 | domain = PF_INET; | ||
1090 | } | ||
1091 | else if (addr && addr->sa_family == AF_INET6) | ||
1092 | { | ||
1093 | domain = PF_INET6; | ||
1094 | } | ||
1095 | else if (addr) | ||
1096 | { | ||
1097 | GNUNET_break (0); | ||
1098 | caller_cb (NULL, NULL, caller_cls); | ||
1099 | return; | ||
1100 | } | ||
1101 | |||
1102 | errno = 0; | ||
1103 | sudp = GNUNET_NETWORK_socket_create (domain, SOCK_DGRAM, 0); | ||
1104 | |||
1105 | if (sudp == NULL) | ||
1106 | { | ||
1107 | PRINT_SOCKET_ERROR ("GNUNET_NETWORK_socket_create"); | ||
1108 | caller_cb (NULL, NULL, caller_cls); | ||
1109 | return; | ||
1110 | } | ||
1111 | |||
1112 | |||
1113 | cls = GNUNET_malloc (sizeof (struct UPNP_discover_cls)); | ||
1114 | cls->sudp = sudp; | ||
1115 | cls->type_index = 0; | ||
1116 | cls->dev_list = NULL; | ||
1117 | cls->current_dev = NULL; | ||
1118 | cls->caller_cb = caller_cb; | ||
1119 | cls->caller_cls = caller_cls; | ||
1120 | |||
1121 | |||
1122 | if (domain == PF_INET) | ||
1123 | { | ||
1124 | /* receive */ | ||
1125 | memset (&sockudp_r, 0, sizeof (struct sockaddr_in)); | ||
1126 | sockudp_r.sin_family = AF_INET; | ||
1127 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
1128 | sockudp_r.sin_len = sizeof (struct sockaddr_in); | ||
1129 | #endif | ||
1130 | sockudp_r.sin_port = 0; | ||
1131 | sockudp_r.sin_addr.s_addr = INADDR_ANY; | ||
1132 | |||
1133 | /* send */ | ||
1134 | memset (&sockudp_w, 0, sizeof (struct sockaddr_in)); | ||
1135 | sockudp_w.sin_family = AF_INET; | ||
1136 | sockudp_w.sin_port = htons (PORT); | ||
1137 | sockudp_w.sin_addr.s_addr = inet_addr (UPNP_MCAST_ADDR); | ||
1138 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
1139 | sockudp_w.sin_len = sizeof (struct sockaddr_in); | ||
1140 | #endif | ||
1141 | |||
1142 | cls->multicast_addr = GNUNET_malloc (sizeof (struct sockaddr_in)); | ||
1143 | memcpy (cls->multicast_addr, &sockudp_w, sizeof (struct sockaddr_in)); | ||
1144 | } | ||
1145 | else | ||
1146 | { | ||
1147 | /* receive */ | ||
1148 | memcpy (&sockudp6_r, addr, sizeof (struct sockaddr_in6)); | ||
1149 | sockudp6_r.sin6_port = 0; | ||
1150 | sockudp6_r.sin6_addr = any_addr; | ||
1151 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
1152 | sockudp6_r.sin6_len = sizeof (struct sockaddr_in6); | ||
1153 | #endif | ||
1154 | |||
1155 | /* send */ | ||
1156 | memset (&sockudp6_w, 0, sizeof (struct sockaddr_in6)); | ||
1157 | sockudp6_w.sin6_family = AF_INET6; | ||
1158 | sockudp6_w.sin6_port = htons (PORT); | ||
1159 | if (inet_pton (AF_INET6, UPNP_MCAST_ADDR6, &sockudp6_w.sin6_addr) != 1) | ||
1160 | { | ||
1161 | PRINT_SOCKET_ERROR ("inet_pton"); | ||
1162 | caller_cb (NULL, NULL, caller_cls); | ||
1163 | return; | ||
1164 | } | ||
1165 | #ifdef HAVE_SOCKADDR_IN_SIN_LEN | ||
1166 | sockudp6_w.sin6_len = sizeof (struct sockaddr_in6); | ||
1167 | #endif | ||
1168 | |||
1169 | cls->multicast_addr = GNUNET_malloc (sizeof (struct sockaddr_in6)); | ||
1170 | memcpy (cls->multicast_addr, &sockudp6_w, sizeof (struct sockaddr_in6)); | ||
1171 | } | ||
1172 | |||
1173 | if (GNUNET_NETWORK_socket_setsockopt | ||
1174 | (sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) == GNUNET_SYSERR) | ||
1175 | { | ||
1176 | PRINT_SOCKET_ERROR ("GNUNET_NETWORK_socket_setsockopt"); | ||
1177 | GNUNET_NETWORK_socket_close (sudp); | ||
1178 | caller_cb (NULL, NULL, caller_cls); | ||
1179 | return; | ||
1180 | } | ||
1181 | |||
1182 | if (addr) | ||
1183 | { | ||
1184 | if (domain == PF_INET) | ||
1185 | { | ||
1186 | sockudp_r.sin_addr.s_addr = | ||
1187 | ((struct sockaddr_in *) addr)->sin_addr.s_addr; | ||
1188 | if (GNUNET_NETWORK_socket_setsockopt | ||
1189 | (sudp, IPPROTO_IP, IP_MULTICAST_IF, | ||
1190 | (const char *) &sockudp_r.sin_addr, | ||
1191 | sizeof (struct in_addr)) == GNUNET_SYSERR) | ||
1192 | { | ||
1193 | PRINT_SOCKET_ERROR ("GNUNET_NETWORK_socket_setsockopt"); | ||
1194 | } | ||
1195 | } | ||
1196 | else | ||
1197 | { | ||
1198 | if (multicastif) | ||
1199 | { | ||
1200 | #ifndef MINGW | ||
1201 | if_index = if_nametoindex (multicastif); | ||
1202 | #else | ||
1203 | // FIXME | ||
1204 | if_index = 0; | ||
1205 | #endif | ||
1206 | if (!if_index) | ||
1207 | PRINT_SOCKET_ERROR_STR ("if_nametoindex", multicastif); | ||
1208 | |||
1209 | if (GNUNET_NETWORK_socket_setsockopt | ||
1210 | (sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_index, | ||
1211 | sizeof (if_index)) == GNUNET_SYSERR) | ||
1212 | { | ||
1213 | PRINT_SOCKET_ERROR ("GNUNET_NETWORK_socket_setsockopt"); | ||
1214 | } | ||
1215 | } | ||
1216 | |||
1217 | memcpy (&sockudp6_r.sin6_addr, | ||
1218 | &((struct sockaddr_in6 *) addr)->sin6_addr, | ||
1219 | sizeof (sockudp6_r.sin6_addr)); | ||
1220 | } | ||
1221 | } | ||
1222 | |||
1223 | if (domain == PF_INET) | ||
1224 | { | ||
1225 | /* Bind to receive response before sending packet */ | ||
1226 | if (GNUNET_NETWORK_socket_bind | ||
1227 | (sudp, (struct sockaddr *) &sockudp_r, | ||
1228 | sizeof (struct sockaddr_in)) != GNUNET_OK) | ||
1229 | { | ||
1230 | PRINT_SOCKET_ERROR ("GNUNET_NETWORK_socket_bind"); | ||
1231 | GNUNET_NETWORK_socket_close (sudp); | ||
1232 | GNUNET_free (cls->multicast_addr); | ||
1233 | caller_cb (NULL, NULL, caller_cls); | ||
1234 | return; | ||
1235 | } | ||
1236 | } | ||
1237 | else | ||
1238 | { | ||
1239 | /* Bind to receive response before sending packet */ | ||
1240 | if (GNUNET_NETWORK_socket_bind | ||
1241 | (sudp, (struct sockaddr *) &sockudp6_r, | ||
1242 | sizeof (struct sockaddr_in6)) != GNUNET_OK) | ||
1243 | { | ||
1244 | PRINT_SOCKET_ERROR ("GNUNET_NETWORK_socket_bind"); | ||
1245 | GNUNET_free (cls->multicast_addr); | ||
1246 | GNUNET_NETWORK_socket_close (sudp); | ||
1247 | caller_cb (NULL, NULL, caller_cls); | ||
1248 | return; | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | /* Send queries for each device type and wait for a possible reply. | ||
1253 | * receiver callback takes care of trying another device type, | ||
1254 | * and eventually calls the caller's callback. */ | ||
1255 | cls->fdset = GNUNET_NETWORK_fdset_create (); | ||
1256 | GNUNET_NETWORK_fdset_zero (cls->fdset); | ||
1257 | GNUNET_NETWORK_fdset_set (cls->fdset, sudp); | ||
1258 | |||
1259 | task_w = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1260 | GNUNET_SCHEDULER_NO_TASK, | ||
1261 | GNUNET_TIME_relative_multiply | ||
1262 | (GNUNET_TIME_UNIT_SECONDS, 15), NULL, | ||
1263 | cls->fdset, &discover_send, cls); | ||
1264 | |||
1265 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1266 | task_w, | ||
1267 | GNUNET_TIME_relative_multiply | ||
1268 | (GNUNET_TIME_UNIT_SECONDS, 15), cls->fdset, | ||
1269 | NULL, &discover_recv, cls); | ||
1270 | } | ||
diff --git a/src/nat/upnp-discover.h b/src/nat/upnp-discover.h deleted file mode 100644 index 39b704bcf..000000000 --- a/src/nat/upnp-discover.h +++ /dev/null | |||
@@ -1,82 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * Code in this file is originally based on the miniupnp library. | ||
23 | * Copyright (c) 2005-2009, Thomas BERNARD. All rights reserved. | ||
24 | * | ||
25 | * Original licence: | ||
26 | * | ||
27 | * Redistribution and use in source and binary forms, with or without | ||
28 | * modification, are permitted provided that the following conditions are met: | ||
29 | * | ||
30 | * * Redistributions of source code must retain the above copyright notice, | ||
31 | * this list of conditions and the following disclaimer. | ||
32 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
33 | * this list of conditions and the following disclaimer in the documentation | ||
34 | * and/or other materials provided with the distribution. | ||
35 | * * The name of the author may not be used to endorse or promote products | ||
36 | * derived from this software without specific prior written permission. | ||
37 | * | ||
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
39 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
41 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
42 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
43 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
44 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
45 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
46 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
47 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
48 | * POSSIBILITY OF SUCH DAMAGE. | ||
49 | */ | ||
50 | |||
51 | /** | ||
52 | * @file nat/upnp-discover.h | ||
53 | * @brief Look for UPnP IGD devices | ||
54 | * | ||
55 | * @author Milan Bouchet-Valat | ||
56 | */ | ||
57 | #ifndef UPNPC_H | ||
58 | #define UPNPC_H | ||
59 | |||
60 | #include "platform.h" | ||
61 | #include "gnunet_common.h" | ||
62 | #include "gnunet_util_lib.h" | ||
63 | #include "upnp-commands.h" | ||
64 | |||
65 | typedef void (*UPNP_discover_cb_) (const char *control_urls, | ||
66 | const char *service_type, void *cls); | ||
67 | |||
68 | /** | ||
69 | * Search for UPnP Internet Gateway Devices (IGD) on a given network interface. | ||
70 | * If several devices are found, a device that is connected to the WAN | ||
71 | * is returned first (if any). | ||
72 | * | ||
73 | * @param multicastif network interface to send discovery messages, or NULL | ||
74 | * @param addr address used to send messages on multicastif, or NULL | ||
75 | * @param caller_cb user function to call when done | ||
76 | * @param caller_cls closure to pass to caller_cb | ||
77 | */ | ||
78 | void UPNP_discover_ (const char *multicastif, | ||
79 | const struct sockaddr *addr, | ||
80 | UPNP_discover_cb_ caller_cb, void *caller_cls); | ||
81 | |||
82 | #endif | ||
diff --git a/src/nat/upnp-igd-parse.c b/src/nat/upnp-igd-parse.c deleted file mode 100644 index 0812065ed..000000000 --- a/src/nat/upnp-igd-parse.c +++ /dev/null | |||
@@ -1,207 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * Code in this file is originally based on the miniupnp library. | ||
23 | * Copyright (c) 2005-2008, Thomas BERNARD. All rights reserved. | ||
24 | * | ||
25 | * Original licence: | ||
26 | * | ||
27 | * Redistribution and use in source and binary forms, with or without | ||
28 | * modification, are permitted provided that the following conditions are met: | ||
29 | * | ||
30 | * * Redistributions of source code must retain the above copyright notice, | ||
31 | * this list of conditions and the following disclaimer. | ||
32 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
33 | * this list of conditions and the following disclaimer in the documentation | ||
34 | * and/or other materials provided with the distribution. | ||
35 | * * The name of the author may not be used to endorse or promote products | ||
36 | * derived from this software without specific prior written permission. | ||
37 | * | ||
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
39 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
41 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
42 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
43 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
44 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
45 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
46 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
47 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
48 | * POSSIBILITY OF SUCH DAMAGE. | ||
49 | */ | ||
50 | |||
51 | /** | ||
52 | * @file nat/upnp-igd-parse.h | ||
53 | * @brief Parser for XML descriptions of UPnP Internet Gateway Devices | ||
54 | * | ||
55 | * @author Milan Bouchet-Valat | ||
56 | */ | ||
57 | #include <stdio.h> | ||
58 | #include <string.h> | ||
59 | |||
60 | #include "platform.h" | ||
61 | #include "gnunet_util_lib.h" | ||
62 | #include "upnp-minixml.h" | ||
63 | #include "upnp-igd-parse.h" | ||
64 | |||
65 | /** | ||
66 | * Start element handler: update nesting level counter | ||
67 | * and copy element name. | ||
68 | */ | ||
69 | static void | ||
70 | start_elt (void *d, const char *name, int l) | ||
71 | { | ||
72 | struct UPNP_IGD_Data_ *datas = (struct UPNP_IGD_Data_ *) d; | ||
73 | |||
74 | memcpy (datas->cur_elt_name, name, l); | ||
75 | datas->cur_elt_name[l] = '\0'; | ||
76 | datas->level++; | ||
77 | if ((l == 7) && !memcmp (name, "service", l)) | ||
78 | { | ||
79 | datas->control_url_tmp[0] = '\0'; | ||
80 | datas->event_sub_url_tmp[0] = '\0'; | ||
81 | datas->scpd_url_tmp[0] = '\0'; | ||
82 | datas->service_type_tmp[0] = '\0'; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * End element handler: update nesting level counter | ||
88 | * and update parser state if service element is parsed. | ||
89 | */ | ||
90 | static void | ||
91 | end_elt (void *d, const char *name, int l) | ||
92 | { | ||
93 | struct UPNP_IGD_Data_ *datas = (struct UPNP_IGD_Data_ *) d; | ||
94 | |||
95 | datas->level--; | ||
96 | |||
97 | if ((l == 7) && !memcmp (name, "service", l)) | ||
98 | { | ||
99 | if (0 == strcmp (datas->service_type_tmp, | ||
100 | "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) | ||
101 | { | ||
102 | memcpy (datas->control_url_CIF, datas->control_url_tmp, | ||
103 | MINIUPNPC_URL_MAXSIZE); | ||
104 | memcpy (datas->event_sub_url_CIF, datas->event_sub_url_tmp, | ||
105 | MINIUPNPC_URL_MAXSIZE); | ||
106 | memcpy (datas->scpd_url_CIF, datas->scpd_url_tmp, | ||
107 | MINIUPNPC_URL_MAXSIZE); | ||
108 | memcpy (datas->service_type_CIF, datas->service_type_tmp, | ||
109 | MINIUPNPC_URL_MAXSIZE); | ||
110 | } | ||
111 | else if (0 == strcmp (datas->service_type_tmp, | ||
112 | "urn:schemas-upnp-org:service:WANIPConnection:1") | ||
113 | || 0 == strcmp (datas->service_type_tmp, | ||
114 | "urn:schemas-upnp-org:service:WANPPPConnection:1")) | ||
115 | { | ||
116 | memcpy (datas->control_url, datas->control_url_tmp, | ||
117 | MINIUPNPC_URL_MAXSIZE); | ||
118 | memcpy (datas->event_sub_url, datas->event_sub_url_tmp, | ||
119 | MINIUPNPC_URL_MAXSIZE); | ||
120 | memcpy (datas->scpd_url, datas->scpd_url_tmp, | ||
121 | MINIUPNPC_URL_MAXSIZE); | ||
122 | memcpy (datas->service_type, datas->service_type_tmp, | ||
123 | MINIUPNPC_URL_MAXSIZE); | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * Data handler: copy data depending on the current | ||
130 | * element name and state. | ||
131 | */ | ||
132 | static void | ||
133 | IGDdata (void *d, const char *data, int l) | ||
134 | { | ||
135 | struct UPNP_IGD_Data_ *datas = (struct UPNP_IGD_Data_ *) d; | ||
136 | char *dstmember = NULL; | ||
137 | |||
138 | if (!strcmp (datas->cur_elt_name, "URLBase")) | ||
139 | dstmember = datas->base_url; | ||
140 | else if (!strcmp (datas->cur_elt_name, "serviceType")) | ||
141 | dstmember = datas->service_type_tmp; | ||
142 | else if (!strcmp (datas->cur_elt_name, "controlURL")) | ||
143 | dstmember = datas->control_url_tmp; | ||
144 | else if (!strcmp (datas->cur_elt_name, "eventSubURL")) | ||
145 | dstmember = datas->event_sub_url_tmp; | ||
146 | else if (!strcmp (datas->cur_elt_name, "SCPDURL")) | ||
147 | dstmember = datas->scpd_url_tmp; | ||
148 | |||
149 | /* Copy current element name into destination member */ | ||
150 | if (dstmember) | ||
151 | { | ||
152 | if (l >= MINIUPNPC_URL_MAXSIZE) | ||
153 | l = MINIUPNPC_URL_MAXSIZE - 1; | ||
154 | |||
155 | memcpy (dstmember, data, l); | ||
156 | dstmember[l] = '\0'; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | #ifdef DEBUG_UPNP | ||
161 | static void | ||
162 | print_IGD (struct UPNP_IGD_Data_ *d) | ||
163 | { | ||
164 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
165 | "base_url = %s\n", d->base_url); | ||
166 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
167 | "WAN Device (Common interface config) :\n" | ||
168 | " sevice_type = %s\n" | ||
169 | " control_url = %s\n" | ||
170 | " event_sub_url = %s\n" | ||
171 | " scpd_url = %s\n", | ||
172 | d->service_type_CIF, | ||
173 | d->control_url_CIF, d->event_sub_url_CIF, d->scpd_url_CIF); | ||
174 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
175 | "WAN Connection Device (IP or PPP Connection):\n" | ||
176 | " service_type = %s\n" | ||
177 | " control_url = %s\n" | ||
178 | " event_sub_url = %s\n" | ||
179 | " scpd_url = %s\n", | ||
180 | d->service_type, | ||
181 | d->control_url, d->event_sub_url, d->scpd_url); | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | /** | ||
186 | * Parse XML description of an IGD device into a UPNP_IGD_Data_ struct. | ||
187 | */ | ||
188 | void | ||
189 | UPNP_IGD_parse_desc_ (const char *buffer, int buf_size, | ||
190 | struct UPNP_IGD_Data_ *data) | ||
191 | { | ||
192 | struct UPNP_xml_parser_ parser; | ||
193 | |||
194 | parser.xml_start = buffer; | ||
195 | parser.xml_size = buf_size; | ||
196 | parser.cls = data; | ||
197 | parser.start_elt_func = start_elt; | ||
198 | parser.end_elt_func = end_elt; | ||
199 | parser.data_func = IGDdata; | ||
200 | parser.att_func = 0; | ||
201 | |||
202 | UPNP_parse_xml_ (&parser); | ||
203 | |||
204 | #ifdef DEBUG_UPNP | ||
205 | print_IGD (data); | ||
206 | #endif | ||
207 | } | ||
diff --git a/src/nat/upnp-igd-parse.h b/src/nat/upnp-igd-parse.h deleted file mode 100644 index 8e0b8510c..000000000 --- a/src/nat/upnp-igd-parse.h +++ /dev/null | |||
@@ -1,99 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * Code in this file is originally based on the miniupnp library. | ||
23 | * Copyright (c) 2005-2008, Thomas BERNARD. All rights reserved. | ||
24 | * | ||
25 | * Original licence: | ||
26 | * | ||
27 | * Redistribution and use in source and binary forms, with or without | ||
28 | * modification, are permitted provided that the following conditions are met: | ||
29 | * | ||
30 | * * Redistributions of source code must retain the above copyright notice, | ||
31 | * this list of conditions and the following disclaimer. | ||
32 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
33 | * this list of conditions and the following disclaimer in the documentation | ||
34 | * and/or other materials provided with the distribution. | ||
35 | * * The name of the author may not be used to endorse or promote products | ||
36 | * derived from this software without specific prior written permission. | ||
37 | * | ||
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
39 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
41 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
42 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
43 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
44 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
45 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
46 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
47 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
48 | * POSSIBILITY OF SUCH DAMAGE. | ||
49 | */ | ||
50 | |||
51 | /** | ||
52 | * @file nat/upnp-igd-parse.h | ||
53 | * @brief Parser for XML descriptions of UPnP Internet Gateway Devices | ||
54 | * | ||
55 | * @author Milan Bouchet-Valat | ||
56 | */ | ||
57 | #ifndef UPNP_IGD_PARSE_H | ||
58 | #define UPNP_IGD_PARSE_H | ||
59 | |||
60 | #define MINIUPNPC_URL_MAXSIZE (128) | ||
61 | |||
62 | /** | ||
63 | * Structure to store the result of the parsing of UPnP | ||
64 | * descriptions of Internet Gateway Devices. | ||
65 | */ | ||
66 | struct UPNP_IGD_Data_ | ||
67 | { | ||
68 | char cur_elt_name[MINIUPNPC_URL_MAXSIZE]; | ||
69 | char base_url[MINIUPNPC_URL_MAXSIZE]; | ||
70 | int level; | ||
71 | |||
72 | /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ | ||
73 | char control_url_CIF[MINIUPNPC_URL_MAXSIZE]; | ||
74 | char event_sub_url_CIF[MINIUPNPC_URL_MAXSIZE]; | ||
75 | char scpd_url_CIF[MINIUPNPC_URL_MAXSIZE]; | ||
76 | char service_type_CIF[MINIUPNPC_URL_MAXSIZE]; | ||
77 | |||
78 | /* "urn:schemas-upnp-org:service:WANIPConnection:1" | ||
79 | * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ | ||
80 | char control_url[MINIUPNPC_URL_MAXSIZE]; | ||
81 | char event_sub_url[MINIUPNPC_URL_MAXSIZE]; | ||
82 | char scpd_url[MINIUPNPC_URL_MAXSIZE]; | ||
83 | char service_type[MINIUPNPC_URL_MAXSIZE]; | ||
84 | |||
85 | /* Used temporarily by the parser */ | ||
86 | char control_url_tmp[MINIUPNPC_URL_MAXSIZE]; | ||
87 | char event_sub_url_tmp[MINIUPNPC_URL_MAXSIZE]; | ||
88 | char scpd_url_tmp[MINIUPNPC_URL_MAXSIZE]; | ||
89 | char service_type_tmp[MINIUPNPC_URL_MAXSIZE]; | ||
90 | }; | ||
91 | |||
92 | /** | ||
93 | * Parse UPnP IGD XML description to a UPNP_IGD_Data_ structure. | ||
94 | */ | ||
95 | void | ||
96 | UPNP_IGD_parse_desc_ (const char *buffer, int buf_size, | ||
97 | struct UPNP_IGD_Data_ *data); | ||
98 | |||
99 | #endif | ||
diff --git a/src/nat/upnp-minixml.c b/src/nat/upnp-minixml.c deleted file mode 100644 index cd2d48739..000000000 --- a/src/nat/upnp-minixml.c +++ /dev/null | |||
@@ -1,239 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * Code in this file is originally based on the miniupnp library. | ||
23 | * Copyright (c) 2005-2009, Thomas BERNARD. All rights reserved. | ||
24 | * | ||
25 | * Original licence: | ||
26 | * | ||
27 | * Redistribution and use in source and binary forms, with or without | ||
28 | * modification, are permitted provided that the following conditions are met: | ||
29 | * | ||
30 | * * Redistributions of source code must retain the above copyright notice, | ||
31 | * this list of conditions and the following disclaimer. | ||
32 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
33 | * this list of conditions and the following disclaimer in the documentation | ||
34 | * and/or other materials provided with the distribution. | ||
35 | * * The name of the author may not be used to endorse or promote products | ||
36 | * derived from this software without specific prior written permission. | ||
37 | * | ||
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
39 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
41 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
42 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
43 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
44 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
45 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
46 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
47 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
48 | * POSSIBILITY OF SUCH DAMAGE. | ||
49 | */ | ||
50 | |||
51 | /** | ||
52 | * @file nat/upnp-minixml.c | ||
53 | * @brief Simple XML parser used by UPnP | ||
54 | * | ||
55 | * @author Milan Bouchet-Valat | ||
56 | */ | ||
57 | |||
58 | #include "platform.h" | ||
59 | #include "gnunet_util_lib.h" | ||
60 | #include "upnp-minixml.h" | ||
61 | |||
62 | /** | ||
63 | * Used to parse the argument list. | ||
64 | * | ||
65 | * @returns GNUNET_OK on success, or GNUNET_SYSERR if the end | ||
66 | * of the xmlbuffer is reached | ||
67 | */ | ||
68 | static int | ||
69 | parse_att (struct UPNP_xml_parser_ *p) | ||
70 | { | ||
71 | const char *att_name; | ||
72 | int att_name_len; | ||
73 | const char *att_value; | ||
74 | int att_value_len; | ||
75 | while (p->xml < p->xml_end) | ||
76 | { | ||
77 | if (*p->xml == '/' || *p->xml == '>') | ||
78 | return GNUNET_OK; | ||
79 | if (!IS_WHITE_SPACE (*p->xml)) | ||
80 | { | ||
81 | char sep; | ||
82 | att_name = p->xml; | ||
83 | att_name_len = 0; | ||
84 | while (*p->xml != '=' && !IS_WHITE_SPACE (*p->xml)) | ||
85 | { | ||
86 | att_name_len++; | ||
87 | p->xml++; | ||
88 | if (p->xml >= p->xml_end) | ||
89 | return GNUNET_SYSERR; | ||
90 | } | ||
91 | while (*(p->xml++) != '=') | ||
92 | { | ||
93 | if (p->xml >= p->xml_end) | ||
94 | return GNUNET_SYSERR; | ||
95 | } | ||
96 | while (IS_WHITE_SPACE (*p->xml)) | ||
97 | { | ||
98 | p->xml++; | ||
99 | if (p->xml >= p->xml_end) | ||
100 | return GNUNET_SYSERR; | ||
101 | } | ||
102 | sep = *p->xml; | ||
103 | if (sep == '\'' || sep == '\"') | ||
104 | { | ||
105 | p->xml++; | ||
106 | if (p->xml >= p->xml_end) | ||
107 | return GNUNET_SYSERR; | ||
108 | att_value = p->xml; | ||
109 | att_value_len = 0; | ||
110 | while (*p->xml != sep) | ||
111 | { | ||
112 | att_value_len++; | ||
113 | p->xml++; | ||
114 | if (p->xml >= p->xml_end) | ||
115 | return GNUNET_SYSERR; | ||
116 | } | ||
117 | } | ||
118 | else | ||
119 | { | ||
120 | att_value = p->xml; | ||
121 | att_value_len = 0; | ||
122 | while (!IS_WHITE_SPACE (*p->xml) | ||
123 | && *p->xml != '>' && *p->xml != '/') | ||
124 | { | ||
125 | att_value_len++; | ||
126 | p->xml++; | ||
127 | if (p->xml >= p->xml_end) | ||
128 | return GNUNET_SYSERR; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | if (p->att_func) | ||
133 | p->att_func (p->cls, att_name, att_name_len, att_value, | ||
134 | att_value_len); | ||
135 | } | ||
136 | p->xml++; | ||
137 | } | ||
138 | return GNUNET_SYSERR; | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * Parse the xml stream and call the callback | ||
143 | * functions when needed... | ||
144 | */ | ||
145 | void | ||
146 | parse_elt (struct UPNP_xml_parser_ *p) | ||
147 | { | ||
148 | int i; | ||
149 | const char *element_name; | ||
150 | while (p->xml < (p->xml_end - 1)) | ||
151 | { | ||
152 | /* Element name */ | ||
153 | if ((p->xml)[0] == '<' && (p->xml)[1] != '?') | ||
154 | { | ||
155 | i = 0; | ||
156 | element_name = ++p->xml; | ||
157 | while (!IS_WHITE_SPACE (*p->xml) | ||
158 | && (*p->xml != '>') && (*p->xml != '/')) | ||
159 | { | ||
160 | i++; | ||
161 | p->xml++; | ||
162 | if (p->xml >= p->xml_end) | ||
163 | return; | ||
164 | /* to ignore namespace : */ | ||
165 | if (*p->xml == ':') | ||
166 | { | ||
167 | i = 0; | ||
168 | element_name = ++p->xml; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | /* Start of element */ | ||
173 | if (i > 0) | ||
174 | { | ||
175 | if (p->start_elt_func) | ||
176 | p->start_elt_func (p->cls, element_name, i); | ||
177 | if (parse_att (p) != GNUNET_OK) | ||
178 | return; | ||
179 | if (*p->xml != '/') | ||
180 | { | ||
181 | const char *data; | ||
182 | i = 0; | ||
183 | data = ++p->xml; | ||
184 | if (p->xml >= p->xml_end) | ||
185 | return; | ||
186 | while (IS_WHITE_SPACE (*p->xml)) | ||
187 | { | ||
188 | p->xml++; | ||
189 | if (p->xml >= p->xml_end) | ||
190 | return; | ||
191 | } | ||
192 | while (*p->xml != '<') | ||
193 | { | ||
194 | i++; | ||
195 | p->xml++; | ||
196 | if (p->xml >= p->xml_end) | ||
197 | return; | ||
198 | } | ||
199 | if (i > 0 && p->data_func) | ||
200 | p->data_func (p->cls, data, i); | ||
201 | } | ||
202 | } | ||
203 | /* End of element */ | ||
204 | else if (*p->xml == '/') | ||
205 | { | ||
206 | i = 0; | ||
207 | element_name = ++p->xml; | ||
208 | if (p->xml >= p->xml_end) | ||
209 | return; | ||
210 | while ((*p->xml != '>')) | ||
211 | { | ||
212 | i++; | ||
213 | p->xml++; | ||
214 | if (p->xml >= p->xml_end) | ||
215 | return; | ||
216 | } | ||
217 | if (p->end_elt_func) | ||
218 | p->end_elt_func (p->cls, element_name, i); | ||
219 | p->xml++; | ||
220 | } | ||
221 | } | ||
222 | else | ||
223 | { | ||
224 | p->xml++; | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * Parse XML content according to the values stored in the parser struct. | ||
231 | * The parser must be initialized before calling this function | ||
232 | */ | ||
233 | void | ||
234 | UPNP_parse_xml_ (struct UPNP_xml_parser_ *parser) | ||
235 | { | ||
236 | parser->xml = parser->xml_start; | ||
237 | parser->xml_end = parser->xml_start + parser->xml_size; | ||
238 | parse_elt (parser); | ||
239 | } | ||
diff --git a/src/nat/upnp-minixml.h b/src/nat/upnp-minixml.h deleted file mode 100644 index 07cf70939..000000000 --- a/src/nat/upnp-minixml.h +++ /dev/null | |||
@@ -1,131 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * Code in this file is originally based on the miniupnp library. | ||
23 | * Copyright (c) 2005-2008, Thomas BERNARD. All rights reserved. | ||
24 | * | ||
25 | * Original licence: | ||
26 | * | ||
27 | * Redistribution and use in source and binary forms, with or without | ||
28 | * modification, are permitted provided that the following conditions are met: | ||
29 | * | ||
30 | * * Redistributions of source code must retain the above copyright notice, | ||
31 | * this list of conditions and the following disclaimer. | ||
32 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
33 | * this list of conditions and the following disclaimer in the documentation | ||
34 | * and/or other materials provided with the distribution. | ||
35 | * * The name of the author may not be used to endorse or promote products | ||
36 | * derived from this software without specific prior written permission. | ||
37 | * | ||
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
39 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
41 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
42 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
43 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
44 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
45 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
46 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
47 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
48 | * POSSIBILITY OF SUCH DAMAGE. | ||
49 | */ | ||
50 | |||
51 | /** | ||
52 | * @file nat/upnp-minixml.h | ||
53 | * @brief Simple XML parser used by UPnP | ||
54 | * | ||
55 | * @author Milan Bouchet-Valat | ||
56 | */ | ||
57 | |||
58 | #ifndef MINIXML_H | ||
59 | #define MINIXML_H | ||
60 | |||
61 | #define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) | ||
62 | |||
63 | /** | ||
64 | * Structure describing the contents and methods that should be | ||
65 | * used when running parse_xml(); | ||
66 | * | ||
67 | * If a callback function pointer is set to NULL, the function | ||
68 | * is not called */ | ||
69 | struct UPNP_xml_parser_ | ||
70 | { | ||
71 | /** | ||
72 | * Pointer to the XML data to parse | ||
73 | */ | ||
74 | const char *xml_start; | ||
75 | |||
76 | /** | ||
77 | * Pointer to the last character to parse (optional) | ||
78 | */ | ||
79 | const char *xml_end; | ||
80 | |||
81 | /** | ||
82 | * Size of the data stored at xml_start | ||
83 | */ | ||
84 | int xml_size; | ||
85 | |||
86 | /** | ||
87 | * Pointer to current character (private) | ||
88 | */ | ||
89 | const char *xml; | ||
90 | |||
91 | /** | ||
92 | * Closure for user-provided callback functions | ||
93 | */ | ||
94 | void *cls; | ||
95 | |||
96 | /** | ||
97 | * User function called when reaching the start of an XML element. | ||
98 | */ | ||
99 | void (*start_elt_func) (void *cls, const char *elt, int elt_len); | ||
100 | |||
101 | /** | ||
102 | * User function called when reaching the end of an XML element. | ||
103 | */ | ||
104 | void (*end_elt_func) (void *cls, const char *elt, int elt_len); | ||
105 | |||
106 | /** | ||
107 | * User function called when an XML element data is found. | ||
108 | */ | ||
109 | void (*data_func) (void *cls, const char *data, int data_len); | ||
110 | |||
111 | /** | ||
112 | * User function called for every XML element attribute. | ||
113 | */ | ||
114 | void (*att_func) (void *cls, const char *att_name, int att_name_len, | ||
115 | const char *att_value, int att_value_len); | ||
116 | }; | ||
117 | |||
118 | /** | ||
119 | * Parse data provided to the xml_parser structure, using | ||
120 | * user-provided functions. | ||
121 | * | ||
122 | * The xmlparser structure must be initialized before the call; | ||
123 | * the following structure members have to be set: | ||
124 | * xml_start, xml_size, cls, *func. | ||
125 | * The xml member is for internal usage, xml_end is computed | ||
126 | * automatically. | ||
127 | * | ||
128 | * @param parser the structure used for parsing */ | ||
129 | void UPNP_parse_xml_ (struct UPNP_xml_parser_ *parser); | ||
130 | |||
131 | #endif | ||
diff --git a/src/nat/upnp-reply-parse.c b/src/nat/upnp-reply-parse.c deleted file mode 100644 index 398cde834..000000000 --- a/src/nat/upnp-reply-parse.c +++ /dev/null | |||
@@ -1,166 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * Code in this file is originally inspired by the miniupnp library. | ||
23 | * Copyright (c) 2006, Thomas BERNARD. All rights reserved. | ||
24 | * | ||
25 | * Original licence: | ||
26 | * | ||
27 | * Redistribution and use in source and binary forms, with or without | ||
28 | * modification, are permitted provided that the following conditions are met: | ||
29 | * | ||
30 | * * Redistributions of source code must retain the above copyright notice, | ||
31 | * this list of conditions and the following disclaimer. | ||
32 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
33 | * this list of conditions and the following disclaimer in the documentation | ||
34 | * and/or other materials provided with the distribution. | ||
35 | * * The name of the author may not be used to endorse or promote products | ||
36 | * derived from this software without specific prior written permission. | ||
37 | * | ||
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
39 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
41 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
42 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
43 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
44 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
45 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
46 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
47 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
48 | * POSSIBILITY OF SUCH DAMAGE. | ||
49 | */ | ||
50 | |||
51 | /** | ||
52 | * @file nat/upnp-reply-parse.c | ||
53 | * @brief Parser for XML replies to UPnP commands | ||
54 | * | ||
55 | * @author Milan Bouchet-Valat | ||
56 | */ | ||
57 | |||
58 | #include <stdlib.h> | ||
59 | #include <string.h> | ||
60 | #include <stdio.h> | ||
61 | |||
62 | #include "platform.h" | ||
63 | #include "gnunet_util_lib.h" | ||
64 | #include "upnp-minixml.h" | ||
65 | #include "upnp-reply-parse.h" | ||
66 | |||
67 | static void | ||
68 | start_elt (void *d, const char *name, int l) | ||
69 | { | ||
70 | struct UPNP_REPLY_NameValueList_ *data = | ||
71 | (struct UPNP_REPLY_NameValueList_ *) d; | ||
72 | |||
73 | if (l > 63) | ||
74 | l = 63; | ||
75 | |||
76 | memcpy (data->curelt, name, l); | ||
77 | data->curelt[l] = '\0'; | ||
78 | } | ||
79 | |||
80 | static void | ||
81 | get_data (void *d, const char *datas, int l) | ||
82 | { | ||
83 | struct UPNP_REPLY_NameValueList_ *data = | ||
84 | (struct UPNP_REPLY_NameValueList_ *) d; | ||
85 | struct UPNP_REPLY_NameValue_ *nv; | ||
86 | |||
87 | nv = malloc (sizeof (struct UPNP_REPLY_NameValue_)); | ||
88 | |||
89 | if (l > 63) | ||
90 | l = 63; | ||
91 | |||
92 | strncpy (nv->name, data->curelt, 64); | ||
93 | nv->name[63] = '\0'; | ||
94 | memcpy (nv->value, datas, l); | ||
95 | nv->value[l] = '\0'; | ||
96 | |||
97 | LIST_INSERT_HEAD (&(data->head), nv, entries); | ||
98 | } | ||
99 | |||
100 | void | ||
101 | UPNP_REPLY_parse_ (const char *buffer, int buf_size, | ||
102 | struct UPNP_REPLY_NameValueList_ *data) | ||
103 | { | ||
104 | struct UPNP_xml_parser_ parser; | ||
105 | |||
106 | LIST_INIT (&(data->head)); | ||
107 | |||
108 | /* Init xml_parser object */ | ||
109 | parser.xml_start = buffer; | ||
110 | parser.xml_size = buf_size; | ||
111 | parser.cls = data; | ||
112 | parser.start_elt_func = start_elt; | ||
113 | parser.end_elt_func = 0; | ||
114 | parser.data_func = get_data; | ||
115 | parser.att_func = 0; | ||
116 | |||
117 | UPNP_parse_xml_ (&parser); | ||
118 | } | ||
119 | |||
120 | void | ||
121 | UPNP_REPLY_free_ (struct UPNP_REPLY_NameValueList_ *pdata) | ||
122 | { | ||
123 | struct UPNP_REPLY_NameValue_ *nv; | ||
124 | |||
125 | while ((nv = pdata->head.lh_first) != NULL) | ||
126 | { | ||
127 | LIST_REMOVE (nv, entries); | ||
128 | GNUNET_free (nv); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | char * | ||
133 | UPNP_REPLY_get_value_ (struct UPNP_REPLY_NameValueList_ *pdata, | ||
134 | const char *Name) | ||
135 | { | ||
136 | struct UPNP_REPLY_NameValue_ *nv; | ||
137 | char *p = NULL; | ||
138 | |||
139 | for (nv = pdata->head.lh_first; | ||
140 | (nv != NULL) && (p == NULL); nv = nv->entries.le_next) | ||
141 | { | ||
142 | if (strcmp (nv->name, Name) == 0) | ||
143 | p = nv->value; | ||
144 | } | ||
145 | |||
146 | return p; | ||
147 | } | ||
148 | |||
149 | #if DEBUG_UPNP | ||
150 | void | ||
151 | UPNP_REPLY_print_ (char *buffer, int buf_size) | ||
152 | { | ||
153 | struct UPNP_REPLY_NameValueList_ pdata; | ||
154 | struct UPNP_REPLY_NameValue_ *nv; | ||
155 | |||
156 | UPNP_REPLY_parse_ (buffer, buf_size, &pdata); | ||
157 | |||
158 | for (nv = pdata.head.lh_first; nv != NULL; nv = nv->entries.le_next) | ||
159 | { | ||
160 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "UPnP", | ||
161 | "%s = %s", nv->name, nv->value); | ||
162 | } | ||
163 | |||
164 | UPNP_REPLY_free_ (&pdata); | ||
165 | } | ||
166 | #endif | ||
diff --git a/src/nat/upnp-reply-parse.h b/src/nat/upnp-reply-parse.h deleted file mode 100644 index e5bedbd8f..000000000 --- a/src/nat/upnp-reply-parse.h +++ /dev/null | |||
@@ -1,107 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * Code in this file is originally inspired by the miniupnp library. | ||
23 | * Copyright (c) 2005-2009, Thomas BERNARD. All rights reserved. | ||
24 | * | ||
25 | * Original licence: | ||
26 | * | ||
27 | * Redistribution and use in source and binary forms, with or without | ||
28 | * modification, are permitted provided that the following conditions are met: | ||
29 | * | ||
30 | * * Redistributions of source code must retain the above copyright notice, | ||
31 | * this list of conditions and the following disclaimer. | ||
32 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
33 | * this list of conditions and the following disclaimer in the documentation | ||
34 | * and/or other materials provided with the distribution. | ||
35 | * * The name of the author may not be used to endorse or promote products | ||
36 | * derived from this software without specific prior written permission. | ||
37 | * | ||
38 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
39 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
41 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
42 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
43 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
44 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
45 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
46 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
47 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
48 | * POSSIBILITY OF SUCH DAMAGE. | ||
49 | */ | ||
50 | |||
51 | /** | ||
52 | * @file nat/upnp-reply-parse.h | ||
53 | * @brief Parser for XML replies to UPnP commands | ||
54 | * | ||
55 | * @author Milan Bouchet-Valat | ||
56 | */ | ||
57 | |||
58 | #ifndef UPNP_PARSE_REPLY_H | ||
59 | #define UPNP_PARSE_REPLY_H | ||
60 | |||
61 | #include "bsdqueue.h" | ||
62 | |||
63 | /** | ||
64 | * Name-value pair used by UPNP_REPLY_NameValueList. | ||
65 | */ | ||
66 | struct UPNP_REPLY_NameValue_ | ||
67 | { | ||
68 | LIST_ENTRY (UPNP_REPLY_NameValue_) entries; | ||
69 | char name[64]; | ||
70 | char value[64]; | ||
71 | }; | ||
72 | |||
73 | /** | ||
74 | * Name-value list to store data parsed from a UPnP reply. | ||
75 | */ | ||
76 | struct UPNP_REPLY_NameValueList_ | ||
77 | { | ||
78 | LIST_HEAD (listhead, UPNP_REPLY_NameValue_) head; | ||
79 | char curelt[64]; | ||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * Parse UPnP XML reply to a name-value list. | ||
84 | */ | ||
85 | void | ||
86 | UPNP_REPLY_parse_ (const char *buffer, int buf_size, | ||
87 | struct UPNP_REPLY_NameValueList_ *data); | ||
88 | |||
89 | /** | ||
90 | * Free name-value list obtained using UPNP_REPLY_parse(). | ||
91 | */ | ||
92 | void UPNP_REPLY_free_ (struct UPNP_REPLY_NameValueList_ *pdata); | ||
93 | |||
94 | /** | ||
95 | * Get value corresponding to name from a name-value list. | ||
96 | */ | ||
97 | char *UPNP_REPLY_get_value_ (struct UPNP_REPLY_NameValueList_ *pdata, | ||
98 | const char *name); | ||
99 | |||
100 | #if DEBUG_UPNP | ||
101 | /** | ||
102 | * Parse a UPnP XMl reply and print the result as names-value pairs. | ||
103 | */ | ||
104 | void UPNP_REPLY_print_ (char *buffer, int buf_size); | ||
105 | #endif | ||
106 | |||
107 | #endif | ||
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 | |||
50 | enum UPNP_State | ||
51 | { | ||
52 | UPNP_IDLE, | ||
53 | UPNP_ERR, | ||
54 | UPNP_DISCOVER, | ||
55 | UPNP_MAP, | ||
56 | UPNP_UNMAP | ||
57 | }; | ||
58 | |||
59 | struct 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 | |||
76 | static int | ||
77 | process_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 | |||
93 | struct GNUNET_NAT_UPNP_Handle * | ||
94 | GNUNET_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 | |||
123 | void | ||
124 | GNUNET_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 | |||
136 | static void | ||
137 | pulse_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 | |||
169 | static void | ||
170 | discover_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 | |||
202 | static void | ||
203 | check_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 | |||
220 | static void | ||
221 | delete_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 | |||
247 | static void | ||
248 | add_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 | |||
276 | static void | ||
277 | get_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 | */ | ||
343 | void | ||
344 | GNUNET_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 | } | ||
diff --git a/src/nat/upnp.h b/src/nat/upnp.h deleted file mode 100644 index dc6ba0d45..000000000 --- a/src/nat/upnp.h +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009, 2010 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 | * @file nat/upnp.h | ||
23 | * @brief UPnP support for the NAT library | ||
24 | * | ||
25 | * @author Milan Bouchet-Valat | ||
26 | */ | ||
27 | |||
28 | #ifndef UPNP_H | ||
29 | #define UPNP_H 1 | ||
30 | |||
31 | #include "platform.h" | ||
32 | |||
33 | struct GNUNET_NAT_UPNP_Handle; | ||
34 | |||
35 | typedef void (*GNUNET_NAT_UPNP_pulse_cb) (int status, | ||
36 | struct sockaddr * ext_addr, | ||
37 | void *cls); | ||
38 | |||
39 | struct GNUNET_NAT_UPNP_Handle *GNUNET_NAT_UPNP_init (const struct sockaddr | ||
40 | *addr, socklen_t addrlen, | ||
41 | unsigned short port, | ||
42 | GNUNET_NAT_UPNP_pulse_cb | ||
43 | pulse_cb, | ||
44 | void *pulse_cls); | ||
45 | |||
46 | void GNUNET_NAT_UPNP_close (struct GNUNET_NAT_UPNP_Handle *h); | ||
47 | |||
48 | void GNUNET_NAT_UPNP_pulse (struct GNUNET_NAT_UPNP_Handle *h, | ||
49 | int is_enabled, int do_port_check); | ||
50 | |||
51 | #endif | ||
52 | /* UPNP_H */ | ||
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 5919bf2ac..e8ed46aad 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am | |||
@@ -13,6 +13,7 @@ else | |||
13 | endif | 13 | endif |
14 | 14 | ||
15 | if HAVE_MHD | 15 | if HAVE_MHD |
16 | if HAVE_EXPERIMENTAL | ||
16 | GN_LIBMHD = -lmicrohttpd | 17 | GN_LIBMHD = -lmicrohttpd |
17 | HTTP_PLUGIN_LA = libgnunet_plugin_transport_http.la | 18 | HTTP_PLUGIN_LA = libgnunet_plugin_transport_http.la |
18 | HTTP_PLUGIN_TEST = test_plugin_transport_http | 19 | HTTP_PLUGIN_TEST = test_plugin_transport_http |
@@ -27,6 +28,7 @@ if HAVE_MHD | |||
27 | HTTPS_QUOTA_TEST = test_quota_compliance_https \ | 28 | HTTPS_QUOTA_TEST = test_quota_compliance_https \ |
28 | test_quota_compliance_https_asymmetric_recv_constant | 29 | test_quota_compliance_https_asymmetric_recv_constant |
29 | endif | 30 | endif |
31 | endif | ||
30 | 32 | ||
31 | if USE_COVERAGE | 33 | if USE_COVERAGE |
32 | AM_CFLAGS = --coverage -O0 | 34 | AM_CFLAGS = --coverage -O0 |
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index 0032b20c7..2010c8d51 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c | |||
@@ -44,9 +44,9 @@ | |||
44 | 44 | ||
45 | #define DEBUG_BLACKLIST GNUNET_NO | 45 | #define DEBUG_BLACKLIST GNUNET_NO |
46 | 46 | ||
47 | #define DEBUG_PING_PONG GNUNET_NO | 47 | #define DEBUG_PING_PONG GNUNET_YES |
48 | 48 | ||
49 | #define DEBUG_TRANSPORT_HELLO GNUNET_NO | 49 | #define DEBUG_TRANSPORT_HELLO GNUNET_YES |
50 | 50 | ||
51 | #define DEBUG_ATS GNUNET_NO | 51 | #define DEBUG_ATS GNUNET_NO |
52 | 52 | ||
@@ -277,12 +277,6 @@ struct OwnAddressList | |||
277 | struct OwnAddressList *next; | 277 | struct OwnAddressList *next; |
278 | 278 | ||
279 | /** | 279 | /** |
280 | * How long until we actually auto-expire this address (unless it is | ||
281 | * re-confirmed by the transport)? | ||
282 | */ | ||
283 | struct GNUNET_TIME_Absolute expires; | ||
284 | |||
285 | /** | ||
286 | * How long until the current signature expires? (ZERO if the | 280 | * How long until the current signature expires? (ZERO if the |
287 | * signature was never created). | 281 | * signature was never created). |
288 | */ | 282 | */ |
@@ -2331,100 +2325,6 @@ refresh_hello () | |||
2331 | 2325 | ||
2332 | 2326 | ||
2333 | /** | 2327 | /** |
2334 | * Task used to clean up expired addresses for a plugin. | ||
2335 | * | ||
2336 | * @param cls closure | ||
2337 | * @param tc context | ||
2338 | */ | ||
2339 | static void | ||
2340 | expire_address_task (void *cls, | ||
2341 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
2342 | |||
2343 | |||
2344 | /** | ||
2345 | * Update the list of addresses for this plugin, | ||
2346 | * expiring those that are past their expiration date. | ||
2347 | * | ||
2348 | * @param plugin addresses of which plugin should be recomputed? | ||
2349 | * @param fresh set to GNUNET_YES if a new address was added | ||
2350 | * and we need to regenerate the HELLO even if nobody | ||
2351 | * expired | ||
2352 | */ | ||
2353 | static void | ||
2354 | update_addresses (struct TransportPlugin *plugin, | ||
2355 | int fresh) | ||
2356 | { | ||
2357 | static struct GNUNET_TIME_Absolute last_update; | ||
2358 | struct GNUNET_TIME_Relative min_remaining; | ||
2359 | struct GNUNET_TIME_Relative remaining; | ||
2360 | struct GNUNET_TIME_Absolute now; | ||
2361 | struct OwnAddressList *pos; | ||
2362 | struct OwnAddressList *prev; | ||
2363 | struct OwnAddressList *next; | ||
2364 | int expired; | ||
2365 | |||
2366 | if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK) | ||
2367 | GNUNET_SCHEDULER_cancel (plugin->address_update_task); | ||
2368 | plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK; | ||
2369 | now = GNUNET_TIME_absolute_get (); | ||
2370 | min_remaining = GNUNET_TIME_UNIT_FOREVER_REL; | ||
2371 | expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4)); | ||
2372 | prev = NULL; | ||
2373 | pos = plugin->addresses; | ||
2374 | while (pos != NULL) | ||
2375 | { | ||
2376 | next = pos->next; | ||
2377 | if (pos->expires.abs_value < now.abs_value) | ||
2378 | { | ||
2379 | expired = GNUNET_YES; | ||
2380 | if (prev == NULL) | ||
2381 | plugin->addresses = pos->next; | ||
2382 | else | ||
2383 | prev->next = pos->next; | ||
2384 | GNUNET_free (pos); | ||
2385 | } | ||
2386 | else | ||
2387 | { | ||
2388 | remaining = GNUNET_TIME_absolute_get_remaining (pos->expires); | ||
2389 | if (remaining.rel_value < min_remaining.rel_value) | ||
2390 | min_remaining = remaining; | ||
2391 | prev = pos; | ||
2392 | } | ||
2393 | pos = next; | ||
2394 | } | ||
2395 | |||
2396 | if (expired || fresh) | ||
2397 | { | ||
2398 | last_update = now; | ||
2399 | refresh_hello (); | ||
2400 | } | ||
2401 | min_remaining = GNUNET_TIME_relative_min (min_remaining, | ||
2402 | GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION, | ||
2403 | 2)); | ||
2404 | plugin->address_update_task | ||
2405 | = GNUNET_SCHEDULER_add_delayed (min_remaining, | ||
2406 | &expire_address_task, plugin); | ||
2407 | } | ||
2408 | |||
2409 | |||
2410 | /** | ||
2411 | * Task used to clean up expired addresses for a plugin. | ||
2412 | * | ||
2413 | * @param cls closure | ||
2414 | * @param tc context | ||
2415 | */ | ||
2416 | static void | ||
2417 | expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
2418 | { | ||
2419 | struct TransportPlugin *plugin = cls; | ||
2420 | |||
2421 | plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK; | ||
2422 | if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
2423 | update_addresses (plugin, GNUNET_NO); | ||
2424 | } | ||
2425 | |||
2426 | |||
2427 | /** | ||
2428 | * Iterator over hash map entries that NULLs the session of validation | 2328 | * Iterator over hash map entries that NULLs the session of validation |
2429 | * entries that match the given session. | 2329 | * entries that match the given session. |
2430 | * | 2330 | * |
@@ -2508,7 +2408,7 @@ try_fast_reconnect (struct TransportPlugin *p, | |||
2508 | gettext_noop ("# disconnects due to try_fast_reconnect"), | 2408 | gettext_noop ("# disconnects due to try_fast_reconnect"), |
2509 | 1, | 2409 | 1, |
2510 | GNUNET_NO); | 2410 | GNUNET_NO); |
2511 | #if DISCONNECT | 2411 | #if DISCONNECT || 1 |
2512 | disconnect_neighbour (nl, GNUNET_YES); | 2412 | disconnect_neighbour (nl, GNUNET_YES); |
2513 | #endif | 2413 | #endif |
2514 | } | 2414 | } |
@@ -2609,8 +2509,8 @@ plugin_env_session_end (void *cls, | |||
2609 | gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"), | 2509 | gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"), |
2610 | 1, | 2510 | 1, |
2611 | GNUNET_NO); | 2511 | GNUNET_NO); |
2612 | if (GNUNET_YES == pos->connected) | 2512 | if (GNUNET_YES == pos->connected) |
2613 | try_fast_reconnect (p, nl); | 2513 | try_fast_reconnect (p, nl); |
2614 | } | 2514 | } |
2615 | else | 2515 | else |
2616 | { | 2516 | { |
@@ -2696,45 +2596,51 @@ plugin_env_session_end (void *cls, | |||
2696 | * provided by the plugin can be reached. | 2596 | * provided by the plugin can be reached. |
2697 | * | 2597 | * |
2698 | * @param cls closure | 2598 | * @param cls closure |
2699 | * @param name name of the transport that generated the address | 2599 | * @param add_remove YES to add, NO to remove the address |
2700 | * @param addr one of the addresses of the host, NULL for the last address | 2600 | * @param addr one of the addresses of the host, NULL for the last address |
2701 | * the specific address format depends on the transport | 2601 | * the specific address format depends on the transport |
2702 | * @param addrlen length of the address | 2602 | * @param addrlen length of the address |
2703 | * @param expires when should this address automatically expire? | ||
2704 | */ | 2603 | */ |
2705 | static void | 2604 | static void |
2706 | plugin_env_notify_address (void *cls, | 2605 | plugin_env_notify_address (void *cls, |
2707 | const char *name, | 2606 | int add_remove, |
2708 | const void *addr, | 2607 | const void *addr, |
2709 | uint16_t addrlen, | 2608 | size_t addrlen) |
2710 | struct GNUNET_TIME_Relative expires) | ||
2711 | { | 2609 | { |
2712 | struct TransportPlugin *p = cls; | 2610 | struct TransportPlugin *p = cls; |
2713 | struct OwnAddressList *al; | 2611 | struct OwnAddressList *al; |
2714 | struct GNUNET_TIME_Absolute abex; | 2612 | struct OwnAddressList *prev; |
2715 | 2613 | ||
2716 | GNUNET_assert (addr != NULL); | 2614 | GNUNET_assert (addr != NULL); |
2717 | abex = GNUNET_TIME_relative_to_absolute (expires); | 2615 | if (GNUNET_NO == add_remove) |
2718 | GNUNET_assert (p == find_transport (name)); | ||
2719 | al = p->addresses; | ||
2720 | while (al != NULL) | ||
2721 | { | 2616 | { |
2722 | if ( (addrlen == al->addrlen) && | 2617 | prev = NULL; |
2723 | (0 == memcmp (addr, &al[1], addrlen)) ) | 2618 | al = p->addresses; |
2724 | { | 2619 | while (al != NULL) |
2725 | al->expires = abex; | 2620 | { |
2726 | update_addresses (p, GNUNET_NO); | 2621 | if ( (addrlen == al->addrlen) && |
2727 | return; | 2622 | (0 == memcmp (addr, &al[1], addrlen)) ) |
2728 | } | 2623 | { |
2729 | al = al->next; | 2624 | if (prev == NULL) |
2625 | p->addresses = al->next; | ||
2626 | else | ||
2627 | prev->next = al->next; | ||
2628 | GNUNET_free (al); | ||
2629 | refresh_hello (); | ||
2630 | return; | ||
2631 | } | ||
2632 | prev = al; | ||
2633 | al = al->next; | ||
2634 | } | ||
2635 | GNUNET_break (0); | ||
2636 | return; | ||
2730 | } | 2637 | } |
2731 | al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen); | 2638 | al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen); |
2732 | al->next = p->addresses; | 2639 | al->next = p->addresses; |
2733 | p->addresses = al; | 2640 | p->addresses = al; |
2734 | al->expires = abex; | ||
2735 | al->addrlen = addrlen; | 2641 | al->addrlen = addrlen; |
2736 | memcpy (&al[1], addr, addrlen); | 2642 | memcpy (&al[1], addr, addrlen); |
2737 | update_addresses (p, GNUNET_YES); | 2643 | refresh_hello (); |
2738 | } | 2644 | } |
2739 | 2645 | ||
2740 | 2646 | ||
@@ -4365,7 +4271,6 @@ check_pending_validation (void *cls, | |||
4365 | if (GNUNET_NO == n->received_pong) | 4271 | if (GNUNET_NO == n->received_pong) |
4366 | { | 4272 | { |
4367 | n->received_pong = GNUNET_YES; | 4273 | n->received_pong = GNUNET_YES; |
4368 | |||
4369 | notify_clients_connect (&target, n->latency, n->distance); | 4274 | notify_clients_connect (&target, n->latency, n->distance); |
4370 | if (NULL != (prem = n->pre_connect_message_buffer)) | 4275 | if (NULL != (prem = n->pre_connect_message_buffer)) |
4371 | { | 4276 | { |
@@ -4508,6 +4413,8 @@ transmit_hello_and_ping (void *cls, | |||
4508 | abort_validation (NULL, NULL, va); | 4413 | abort_validation (NULL, NULL, va); |
4509 | return; | 4414 | return; |
4510 | } | 4415 | } |
4416 | if (NULL == our_hello) | ||
4417 | refresh_hello (); | ||
4511 | hello_size = GNUNET_HELLO_size(our_hello); | 4418 | hello_size = GNUNET_HELLO_size(our_hello); |
4512 | slen = strlen(va->transport_name) + 1; | 4419 | slen = strlen(va->transport_name) + 1; |
4513 | tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen; | 4420 | tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen; |
@@ -5004,8 +4911,11 @@ disconnect_neighbour (struct NeighbourList *n, int check) | |||
5004 | { | 4911 | { |
5005 | #if DEBUG_TRANSPORT | 4912 | #if DEBUG_TRANSPORT |
5006 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 4913 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
5007 | "NOT Disconnecting from `%4s', still have live addresses!\n", | 4914 | "NOT Disconnecting from `%4s', still have live address `%s'!\n", |
5008 | GNUNET_i2s (&n->id)); | 4915 | GNUNET_i2s (&n->id), |
4916 | a2s (peer_addresses->ready_list->plugin->short_name, | ||
4917 | peer_addresses->addr, | ||
4918 | peer_addresses->addrlen)); | ||
5009 | #endif | 4919 | #endif |
5010 | return; /* still connected */ | 4920 | return; /* still connected */ |
5011 | } | 4921 | } |
@@ -5289,8 +5199,7 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message, | |||
5289 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 5199 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
5290 | "Creating PONG signature to indicate ownership.\n"); | 5200 | "Creating PONG signature to indicate ownership.\n"); |
5291 | #endif | 5201 | #endif |
5292 | oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires, | 5202 | oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME); |
5293 | GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME)); | ||
5294 | pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires); | 5203 | pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires); |
5295 | GNUNET_assert (GNUNET_OK == | 5204 | GNUNET_assert (GNUNET_OK == |
5296 | GNUNET_CRYPTO_rsa_sign (my_private_key, | 5205 | GNUNET_CRYPTO_rsa_sign (my_private_key, |
diff --git a/src/transport/plugin_transport_http.c b/src/transport/plugin_transport_http.c index ba58f9ea7..09b3b219f 100644 --- a/src/transport/plugin_transport_http.c +++ b/src/transport/plugin_transport_http.c | |||
@@ -821,19 +821,19 @@ process_interfaces (void *cls, | |||
821 | t4->ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; | 821 | t4->ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; |
822 | t4->u_port = htons (plugin->port_inbound); | 822 | t4->u_port = htons (plugin->port_inbound); |
823 | if (plugin->bind4_address != NULL) { | 823 | if (plugin->bind4_address != NULL) { |
824 | if (0 == memcmp(&plugin->bind4_address->sin_addr, &bnd_cmp, sizeof (struct in_addr))) | 824 | if (0 == memcmp(&plugin->bind4_address->sin_addr, &bnd_cmp, sizeof (struct in_addr))) |
825 | { | 825 | { |
826 | GNUNET_CONTAINER_DLL_insert(plugin->ipv4_addr_head, | 826 | GNUNET_CONTAINER_DLL_insert(plugin->ipv4_addr_head, |
827 | plugin->ipv4_addr_tail,t4); | 827 | plugin->ipv4_addr_tail,t4); |
828 | plugin->env->notify_address(plugin->env->cls, | 828 | plugin->env->notify_address(plugin->env->cls, |
829 | PROTOCOL_PREFIX, | 829 | PROTOCOL_PREFIX, |
830 | t4, sizeof (struct IPv4HttpAddress), | 830 | t4, sizeof (struct IPv4HttpAddress), |
831 | GNUNET_TIME_UNIT_FOREVER_REL); | 831 | GNUNET_TIME_UNIT_FOREVER_REL); |
832 | return GNUNET_OK; | 832 | return GNUNET_OK; |
833 | } | ||
834 | GNUNET_free (t4); | ||
835 | return GNUNET_OK; | ||
836 | } | 833 | } |
834 | GNUNET_free (t4); | ||
835 | return GNUNET_OK; | ||
836 | } | ||
837 | else | 837 | else |
838 | { | 838 | { |
839 | GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, | 839 | GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, |
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index 491c536ca..a8eee970c 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c | |||
@@ -38,15 +38,10 @@ | |||
38 | #include "gnunet_transport_plugin.h" | 38 | #include "gnunet_transport_plugin.h" |
39 | #include "transport.h" | 39 | #include "transport.h" |
40 | 40 | ||
41 | #define DEBUG_TCP GNUNET_NO | 41 | #define DEBUG_TCP GNUNET_YES |
42 | 42 | ||
43 | #define DEBUG_TCP_NAT GNUNET_YES | 43 | #define DEBUG_TCP_NAT GNUNET_YES |
44 | 44 | ||
45 | /** | ||
46 | * How long until we give up on transmitting the welcome message? | ||
47 | */ | ||
48 | #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
49 | |||
50 | 45 | ||
51 | /** | 46 | /** |
52 | * Initial handshake message for a session. | 47 | * Initial handshake message for a session. |
@@ -136,7 +131,7 @@ struct IPv4TcpAddress | |||
136 | /** | 131 | /** |
137 | * Port number, in network byte order. | 132 | * Port number, in network byte order. |
138 | */ | 133 | */ |
139 | uint16_t t_port GNUNET_PACKED; | 134 | uint16_t t4_port GNUNET_PACKED; |
140 | 135 | ||
141 | }; | 136 | }; |
142 | 137 | ||
@@ -166,52 +161,6 @@ struct Plugin; | |||
166 | 161 | ||
167 | 162 | ||
168 | /** | 163 | /** |
169 | * Local network addresses (actual IP address follows this struct). | ||
170 | * PORT is NOT included! | ||
171 | */ | ||
172 | struct LocalAddrList | ||
173 | { | ||
174 | |||
175 | /** | ||
176 | * This is a doubly linked list. | ||
177 | */ | ||
178 | struct LocalAddrList *next; | ||
179 | |||
180 | /** | ||
181 | * This is a doubly linked list. | ||
182 | */ | ||
183 | struct LocalAddrList *prev; | ||
184 | |||
185 | /** | ||
186 | * Link to plugin. | ||
187 | */ | ||
188 | struct Plugin *plugin; | ||
189 | |||
190 | /** | ||
191 | * Handle to NAT holes we've tried to punch for this address. | ||
192 | */ | ||
193 | struct GNUNET_NAT_Handle *nat; | ||
194 | |||
195 | /** | ||
196 | * Pointer to a 'struct IPv4/V6TcpAddress' describing our external IP and port | ||
197 | * as obtained from the NAT by automatic port mapping. | ||
198 | */ | ||
199 | void *external_nat_address; | ||
200 | |||
201 | /** | ||
202 | * Number of bytes in 'external_nat_address' | ||
203 | */ | ||
204 | size_t ena_size; | ||
205 | |||
206 | /** | ||
207 | * Number of bytes of the address that follow | ||
208 | */ | ||
209 | size_t size; | ||
210 | |||
211 | }; | ||
212 | |||
213 | |||
214 | /** | ||
215 | * Information kept for each message that is yet to | 164 | * Information kept for each message that is yet to |
216 | * be transmitted. | 165 | * be transmitted. |
217 | */ | 166 | */ |
@@ -365,24 +314,9 @@ struct Plugin | |||
365 | struct GNUNET_CONNECTION_Handle *lsock; | 314 | struct GNUNET_CONNECTION_Handle *lsock; |
366 | 315 | ||
367 | /** | 316 | /** |
368 | * stdout pipe handle for the gnunet-nat-server process | 317 | * Our handle to the NAT module. |
369 | */ | ||
370 | struct GNUNET_DISK_PipeHandle *server_stdout; | ||
371 | |||
372 | /** | ||
373 | * stdout file handle (for reading) for the gnunet-nat-server process | ||
374 | */ | 318 | */ |
375 | const struct GNUNET_DISK_FileHandle *server_stdout_handle; | 319 | struct GNUNET_NAT_Handle *nat; |
376 | |||
377 | /** | ||
378 | * ID of select gnunet-nat-server stdout read task | ||
379 | */ | ||
380 | GNUNET_SCHEDULER_TaskIdentifier server_read_task; | ||
381 | |||
382 | /** | ||
383 | * The process id of the server process (if behind NAT) | ||
384 | */ | ||
385 | struct GNUNET_OS_Process *server_proc; | ||
386 | 320 | ||
387 | /** | 321 | /** |
388 | * List of open TCP sessions. | 322 | * List of open TCP sessions. |
@@ -406,48 +340,10 @@ struct Plugin | |||
406 | struct GNUNET_SERVER_MessageHandler *handlers; | 340 | struct GNUNET_SERVER_MessageHandler *handlers; |
407 | 341 | ||
408 | /** | 342 | /** |
409 | * Handle for request of hostname resolution, non-NULL if pending. | ||
410 | */ | ||
411 | struct GNUNET_RESOLVER_RequestHandle *hostname_dns; | ||
412 | |||
413 | /** | ||
414 | * Map of peers we have tried to contact behind a NAT | 343 | * Map of peers we have tried to contact behind a NAT |
415 | */ | 344 | */ |
416 | struct GNUNET_CONTAINER_MultiHashMap *nat_wait_conns; | 345 | struct GNUNET_CONTAINER_MultiHashMap *nat_wait_conns; |
417 | 346 | ||
418 | /** | ||
419 | * The external address given to us by the user. Used for HELLOs | ||
420 | * and address validation. | ||
421 | */ | ||
422 | char *external_address; | ||
423 | |||
424 | /** | ||
425 | * The internal address given to us by the user (or discovered). | ||
426 | * Used for NAT traversal (ICMP method), but not as a 'validateable' | ||
427 | * address in HELLOs. | ||
428 | */ | ||
429 | char *internal_address; | ||
430 | |||
431 | /** | ||
432 | * Address given for us to bind to (ONLY). | ||
433 | */ | ||
434 | char *bind_address; | ||
435 | |||
436 | /** | ||
437 | * use local addresses? | ||
438 | */ | ||
439 | int use_localaddresses; | ||
440 | |||
441 | /** | ||
442 | * List of our IP addresses. | ||
443 | */ | ||
444 | struct LocalAddrList *lal_head; | ||
445 | |||
446 | /** | ||
447 | * Tail of our IP address list. | ||
448 | */ | ||
449 | struct LocalAddrList *lal_tail; | ||
450 | |||
451 | /** | 347 | /** |
452 | * List of active TCP probes. | 348 | * List of active TCP probes. |
453 | */ | 349 | */ |
@@ -484,31 +380,6 @@ struct Plugin | |||
484 | */ | 380 | */ |
485 | uint16_t adv_port; | 381 | uint16_t adv_port; |
486 | 382 | ||
487 | /** | ||
488 | * Is this transport configured to be behind a NAT? | ||
489 | */ | ||
490 | int behind_nat; | ||
491 | |||
492 | /** | ||
493 | * Has the NAT been punched? | ||
494 | */ | ||
495 | int nat_punched; | ||
496 | |||
497 | /** | ||
498 | * Is this transport configured to allow connections to NAT'd peers? | ||
499 | */ | ||
500 | int enable_nat_client; | ||
501 | |||
502 | /** | ||
503 | * Should we run the gnunet-nat-server? | ||
504 | */ | ||
505 | int enable_nat_server; | ||
506 | |||
507 | /** | ||
508 | * Are we allowed to try UPnP/PMP for NAT traversal? | ||
509 | */ | ||
510 | int enable_upnp; | ||
511 | |||
512 | }; | 383 | }; |
513 | 384 | ||
514 | 385 | ||
@@ -549,30 +420,34 @@ plugin_tcp_access_check (void *cls, | |||
549 | * @param addrlen actual lenght of the address | 420 | * @param addrlen actual lenght of the address |
550 | */ | 421 | */ |
551 | static void | 422 | static void |
552 | nat_port_map_callback (void *cls, | 423 | tcp_nat_port_map_callback (void *cls, |
553 | int add_remove, | 424 | int add_remove, |
554 | const struct sockaddr *addr, | 425 | const struct sockaddr *addr, |
555 | socklen_t addrlen) | 426 | socklen_t addrlen) |
556 | { | 427 | { |
557 | struct LocalAddrList *lal = cls; | 428 | struct Plugin *plugin = cls; |
558 | struct Plugin *plugin = lal->plugin; | ||
559 | int af; | ||
560 | struct IPv4TcpAddress t4; | 429 | struct IPv4TcpAddress t4; |
561 | struct IPv6TcpAddress t6; | 430 | struct IPv6TcpAddress t6; |
562 | void *arg; | 431 | void *arg; |
563 | uint16_t args; | 432 | size_t args; |
564 | 433 | ||
434 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
435 | "tcp", | ||
436 | "NPMC called with %d for address `%s'\n", | ||
437 | add_remove, | ||
438 | GNUNET_a2s (addr, addrlen)); | ||
565 | /* convert 'addr' to our internal format */ | 439 | /* convert 'addr' to our internal format */ |
566 | af = addr->sa_family; | 440 | switch (addr->sa_family) |
567 | switch (af) | ||
568 | { | 441 | { |
569 | case AF_INET: | 442 | case AF_INET: |
443 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); | ||
570 | t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; | 444 | t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; |
571 | t4.t_port = ((struct sockaddr_in *) addr)->sin_port; | 445 | t4.t4_port = ((struct sockaddr_in *) addr)->sin_port; |
572 | arg = &t4; | 446 | arg = &t4; |
573 | args = sizeof (t4); | 447 | args = sizeof (t4); |
574 | break; | 448 | break; |
575 | case AF_INET6: | 449 | case AF_INET6: |
450 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); | ||
576 | memcpy (&t6.ipv6_addr, | 451 | memcpy (&t6.ipv6_addr, |
577 | &((struct sockaddr_in6 *) addr)->sin6_addr, | 452 | &((struct sockaddr_in6 *) addr)->sin6_addr, |
578 | sizeof (struct in6_addr)); | 453 | sizeof (struct in6_addr)); |
@@ -583,154 +458,11 @@ nat_port_map_callback (void *cls, | |||
583 | default: | 458 | default: |
584 | GNUNET_break (0); | 459 | GNUNET_break (0); |
585 | return; | 460 | return; |
586 | } | ||
587 | |||
588 | /* modify our published address list */ | ||
589 | if (GNUNET_YES == add_remove) | ||
590 | { | ||
591 | plugin->env->notify_address (plugin->env->cls, | ||
592 | "tcp", | ||
593 | arg, args, GNUNET_TIME_UNIT_FOREVER_REL); | ||
594 | GNUNET_free_non_null (lal->external_nat_address); | ||
595 | lal->external_nat_address = GNUNET_memdup (arg, args); | ||
596 | lal->ena_size = args; | ||
597 | } | ||
598 | else | ||
599 | { | ||
600 | plugin->env->notify_address (plugin->env->cls, | ||
601 | "tcp", | ||
602 | arg, args, GNUNET_TIME_UNIT_ZERO); | ||
603 | GNUNET_free_non_null (lal->external_nat_address); | ||
604 | lal->ena_size = 0; | ||
605 | } | ||
606 | } | ||
607 | |||
608 | |||
609 | /** | ||
610 | * Add the given address to the list of 'local' addresses, thereby | ||
611 | * making it a 'legal' address for this peer to have. | ||
612 | * | ||
613 | * @param plugin the plugin | ||
614 | * @param arg the address, either an IPv4 or an IPv6 IP address | ||
615 | * @param arg_size number of bytes in arg | ||
616 | */ | ||
617 | static void | ||
618 | add_to_address_list (struct Plugin *plugin, | ||
619 | const void *arg, | ||
620 | size_t arg_size) | ||
621 | { | ||
622 | struct LocalAddrList *lal; | ||
623 | struct sockaddr_in v4; | ||
624 | struct sockaddr_in6 v6; | ||
625 | const struct sockaddr *sa; | ||
626 | socklen_t salen; | ||
627 | |||
628 | lal = plugin->lal_head; | ||
629 | while (NULL != lal) | ||
630 | { | ||
631 | if ( (lal->size == arg_size) && | ||
632 | (0 == memcmp (&lal[1], arg, arg_size)) ) | ||
633 | return; | ||
634 | lal = lal->next; | ||
635 | } | ||
636 | lal = GNUNET_malloc (sizeof (struct LocalAddrList) + arg_size); | ||
637 | lal->plugin = plugin; | ||
638 | lal->size = arg_size; | ||
639 | memcpy (&lal[1], arg, arg_size); | ||
640 | GNUNET_CONTAINER_DLL_insert (plugin->lal_head, | ||
641 | plugin->lal_tail, | ||
642 | lal); | ||
643 | if (plugin->open_port == 0) | ||
644 | return; /* we're not listening at all... */ | ||
645 | if (arg_size == sizeof (struct in_addr)) | ||
646 | { | ||
647 | memset (&v4, 0, sizeof (v4)); | ||
648 | v4.sin_family = AF_INET; | ||
649 | v4.sin_port = htons (plugin->open_port); | ||
650 | memcpy (&v4.sin_addr, arg, arg_size); | ||
651 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
652 | v4.sin_len = sizeof (struct sockaddr_in); | ||
653 | #endif | ||
654 | sa = (const struct sockaddr*) &v4; | ||
655 | salen = sizeof (v4); | ||
656 | } | ||
657 | else if (arg_size == sizeof (struct in6_addr)) | ||
658 | { | ||
659 | memset (&v6, 0, sizeof (v6)); | ||
660 | v6.sin6_family = AF_INET6; | ||
661 | v6.sin6_port = htons (plugin->open_port); | ||
662 | memcpy (&v6.sin6_addr, arg, arg_size); | ||
663 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
664 | v6.sin6_len = sizeof (struct sockaddr_in6); | ||
665 | #endif | ||
666 | sa = (const struct sockaddr*) &v6; | ||
667 | salen = sizeof (v6); | ||
668 | } | ||
669 | else | ||
670 | { | ||
671 | GNUNET_break (0); | ||
672 | return; | ||
673 | } | 461 | } |
674 | if ( (plugin->behind_nat == GNUNET_YES) && | 462 | /* modify our published address list */ |
675 | (plugin->enable_upnp == GNUNET_YES) ) | 463 | plugin->env->notify_address (plugin->env->cls, |
676 | lal->nat = GNUNET_NAT_register (plugin->env->cfg, | 464 | add_remove, |
677 | sa, salen, | 465 | arg, args); |
678 | &nat_port_map_callback, | ||
679 | lal); | ||
680 | } | ||
681 | |||
682 | |||
683 | /** | ||
684 | * Check if the given address is in the list of 'local' addresses. | ||
685 | * | ||
686 | * @param plugin the plugin | ||
687 | * @param arg the address, either an IPv4 or an IPv6 IP address | ||
688 | * @param arg_size number of bytes in arg | ||
689 | * @return GNUNET_OK if this is one of our IPs, GNUNET_SYSERR if not | ||
690 | */ | ||
691 | static int | ||
692 | check_local_addr (struct Plugin *plugin, | ||
693 | const void *arg, | ||
694 | size_t arg_size) | ||
695 | { | ||
696 | struct LocalAddrList *lal; | ||
697 | |||
698 | lal = plugin->lal_head; | ||
699 | while (NULL != lal) | ||
700 | { | ||
701 | if ( (lal->size == arg_size) && | ||
702 | (0 == memcmp (&lal[1], arg, arg_size)) ) | ||
703 | return GNUNET_OK; | ||
704 | lal = lal->next; | ||
705 | } | ||
706 | return GNUNET_SYSERR; | ||
707 | } | ||
708 | |||
709 | |||
710 | /** | ||
711 | * Check if the given address is in the list of 'mapped' addresses. | ||
712 | * | ||
713 | * @param plugin the plugin | ||
714 | * @param arg the address, either a 'struct IPv4TcpAddress' or a 'struct IPv6TcpAddress' | ||
715 | * @param arg_size number of bytes in arg | ||
716 | * @return GNUNET_OK if this is one of our IPs, GNUNET_SYSERR if not | ||
717 | */ | ||
718 | static int | ||
719 | check_mapped_addr (struct Plugin *plugin, | ||
720 | const void *arg, | ||
721 | size_t arg_size) | ||
722 | { | ||
723 | struct LocalAddrList *lal; | ||
724 | |||
725 | lal = plugin->lal_head; | ||
726 | while (NULL != lal) | ||
727 | { | ||
728 | if ( (lal->ena_size == arg_size) && | ||
729 | (0 == memcmp (lal->external_nat_address, arg, arg_size)) ) | ||
730 | return GNUNET_OK; | ||
731 | lal = lal->next; | ||
732 | } | ||
733 | return GNUNET_SYSERR; | ||
734 | } | 466 | } |
735 | 467 | ||
736 | 468 | ||
@@ -772,7 +504,7 @@ tcp_address_to_string (void *cls, | |||
772 | { | 504 | { |
773 | t4 = addr; | 505 | t4 = addr; |
774 | af = AF_INET; | 506 | af = AF_INET; |
775 | port = ntohs (t4->t_port); | 507 | port = ntohs (t4->t4_port); |
776 | memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); | 508 | memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); |
777 | sb = &a4; | 509 | sb = &a4; |
778 | } | 510 | } |
@@ -1186,64 +918,6 @@ select_better_session (struct Session *s1, | |||
1186 | } | 918 | } |
1187 | 919 | ||
1188 | 920 | ||
1189 | /** | ||
1190 | * We learned about a peer (possibly behind NAT) so run the | ||
1191 | * gnunet-nat-client to send dummy ICMP responses. | ||
1192 | * | ||
1193 | * @param plugin the plugin for this transport | ||
1194 | * @param sa the address of the peer (IPv4-only) | ||
1195 | */ | ||
1196 | static void | ||
1197 | run_gnunet_nat_client (struct Plugin *plugin, | ||
1198 | const struct sockaddr_in *sa) | ||
1199 | { | ||
1200 | char inet4[INET_ADDRSTRLEN]; | ||
1201 | char port_as_string[6]; | ||
1202 | struct GNUNET_OS_Process *proc; | ||
1203 | |||
1204 | if (plugin->internal_address == NULL) | ||
1205 | { | ||
1206 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | ||
1207 | "tcp", | ||
1208 | _("Internal IP address not known, cannot use ICMP NAT traversal method\n")); | ||
1209 | return; | ||
1210 | } | ||
1211 | GNUNET_assert (sa->sin_family == AF_INET); | ||
1212 | if (NULL == inet_ntop (AF_INET, | ||
1213 | &sa->sin_addr, | ||
1214 | inet4, INET_ADDRSTRLEN)) | ||
1215 | { | ||
1216 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); | ||
1217 | return; | ||
1218 | } | ||
1219 | GNUNET_snprintf(port_as_string, | ||
1220 | sizeof (port_as_string), | ||
1221 | "%d", | ||
1222 | plugin->adv_port); | ||
1223 | #if DEBUG_TCP_NAT | ||
1224 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
1225 | "tcp", | ||
1226 | _("Running gnunet-nat-client %s %s %u\n"), | ||
1227 | plugin->internal_address, | ||
1228 | inet4, | ||
1229 | (unsigned int) plugin->adv_port); | ||
1230 | #endif | ||
1231 | proc = GNUNET_OS_start_process (NULL, | ||
1232 | NULL, | ||
1233 | "gnunet-nat-client", | ||
1234 | "gnunet-nat-client", | ||
1235 | plugin->internal_address, | ||
1236 | inet4, | ||
1237 | port_as_string, | ||
1238 | NULL); | ||
1239 | if (NULL == proc) | ||
1240 | return; | ||
1241 | /* we know that the gnunet-nat-client will terminate virtually | ||
1242 | instantly */ | ||
1243 | GNUNET_OS_process_wait (proc); | ||
1244 | GNUNET_OS_process_close (proc); | ||
1245 | } | ||
1246 | |||
1247 | 921 | ||
1248 | /** | 922 | /** |
1249 | * Function that can be used by the transport service to transmit | 923 | * Function that can be used by the transport service to transmit |
@@ -1400,8 +1074,8 @@ tcp_plugin_send (void *cls, | |||
1400 | a4.sin_len = sizeof (a4); | 1074 | a4.sin_len = sizeof (a4); |
1401 | #endif | 1075 | #endif |
1402 | a4.sin_family = AF_INET; | 1076 | a4.sin_family = AF_INET; |
1403 | a4.sin_port = t4->t_port; | 1077 | a4.sin_port = t4->t4_port; |
1404 | if (t4->t_port == 0) | 1078 | if (t4->t4_port == 0) |
1405 | is_natd = GNUNET_YES; | 1079 | is_natd = GNUNET_YES; |
1406 | a4.sin_addr.s_addr = t4->ipv4_addr; | 1080 | a4.sin_addr.s_addr = t4->ipv4_addr; |
1407 | sb = &a4; | 1081 | sb = &a4; |
@@ -1422,8 +1096,8 @@ tcp_plugin_send (void *cls, | |||
1422 | if (0 == plugin->max_connections) | 1096 | if (0 == plugin->max_connections) |
1423 | return -1; /* saturated */ | 1097 | return -1; /* saturated */ |
1424 | 1098 | ||
1425 | if ( (plugin->enable_nat_client == GNUNET_YES) && | 1099 | if ( (is_natd == GNUNET_YES) && |
1426 | (is_natd == GNUNET_YES) && | 1100 | (NULL != plugin->nat) && |
1427 | (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, | 1101 | (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, |
1428 | &target->hashPubKey)) ) | 1102 | &target->hashPubKey)) ) |
1429 | { | 1103 | { |
@@ -1466,11 +1140,10 @@ tcp_plugin_send (void *cls, | |||
1466 | GNUNET_i2s (target), | 1140 | GNUNET_i2s (target), |
1467 | GNUNET_a2s (sb, sbs)); | 1141 | GNUNET_a2s (sb, sbs)); |
1468 | #endif | 1142 | #endif |
1469 | run_gnunet_nat_client (plugin, &a4); | 1143 | GNUNET_NAT_run_client (plugin->nat, &a4); |
1470 | return 0; | 1144 | return 0; |
1471 | } | 1145 | } |
1472 | if ( (plugin->enable_nat_client == GNUNET_YES) && | 1146 | if ( (is_natd == GNUNET_YES) && |
1473 | (is_natd == GNUNET_YES) && | ||
1474 | (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, | 1147 | (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, |
1475 | &target->hashPubKey)) ) | 1148 | &target->hashPubKey)) ) |
1476 | { | 1149 | { |
@@ -1697,9 +1370,9 @@ tcp_plugin_address_pretty_printer (void *cls, | |||
1697 | t4 = addr; | 1370 | t4 = addr; |
1698 | memset (&a4, 0, sizeof (a4)); | 1371 | memset (&a4, 0, sizeof (a4)); |
1699 | a4.sin_family = AF_INET; | 1372 | a4.sin_family = AF_INET; |
1700 | a4.sin_port = t4->t_port; | 1373 | a4.sin_port = t4->t4_port; |
1701 | a4.sin_addr.s_addr = t4->ipv4_addr; | 1374 | a4.sin_addr.s_addr = t4->ipv4_addr; |
1702 | port = ntohs (t4->t_port); | 1375 | port = ntohs (t4->t4_port); |
1703 | sb = &a4; | 1376 | sb = &a4; |
1704 | sbs = sizeof (a4); | 1377 | sbs = sizeof (a4); |
1705 | } | 1378 | } |
@@ -1773,14 +1446,12 @@ tcp_plugin_check_address (void *cls, | |||
1773 | if (addrlen == sizeof (struct IPv4TcpAddress)) | 1446 | if (addrlen == sizeof (struct IPv4TcpAddress)) |
1774 | { | 1447 | { |
1775 | v4 = (struct IPv4TcpAddress *) addr; | 1448 | v4 = (struct IPv4TcpAddress *) addr; |
1776 | if (GNUNET_OK == | ||
1777 | check_mapped_addr (plugin, v4, sizeof (struct IPv4TcpAddress))) | ||
1778 | return GNUNET_OK; | ||
1779 | if (GNUNET_OK != | 1449 | if (GNUNET_OK != |
1780 | check_port (plugin, ntohs (v4->t_port))) | 1450 | check_port (plugin, ntohs (v4->t4_port))) |
1781 | return GNUNET_SYSERR; | 1451 | return GNUNET_SYSERR; |
1782 | if (GNUNET_OK != | 1452 | if (GNUNET_OK != |
1783 | check_local_addr (plugin, &v4->ipv4_addr, sizeof (struct in_addr))) | 1453 | GNUNET_NAT_test_address (plugin->nat, |
1454 | &v4->ipv4_addr, sizeof (struct in_addr))) | ||
1784 | return GNUNET_SYSERR; | 1455 | return GNUNET_SYSERR; |
1785 | } | 1456 | } |
1786 | else | 1457 | else |
@@ -1791,14 +1462,12 @@ tcp_plugin_check_address (void *cls, | |||
1791 | GNUNET_break_op (0); | 1462 | GNUNET_break_op (0); |
1792 | return GNUNET_SYSERR; | 1463 | return GNUNET_SYSERR; |
1793 | } | 1464 | } |
1794 | if (GNUNET_OK == | ||
1795 | check_mapped_addr (plugin, v6, sizeof (struct IPv6TcpAddress))) | ||
1796 | return GNUNET_OK; | ||
1797 | if (GNUNET_OK != | 1465 | if (GNUNET_OK != |
1798 | check_port (plugin, ntohs (v6->t6_port))) | 1466 | check_port (plugin, ntohs (v6->t6_port))) |
1799 | return GNUNET_SYSERR; | 1467 | return GNUNET_SYSERR; |
1800 | if (GNUNET_OK != | 1468 | if (GNUNET_OK != |
1801 | check_local_addr (plugin, &v6->ipv6_addr, sizeof (struct in6_addr))) | 1469 | GNUNET_NAT_test_address (plugin->nat, |
1470 | &v6->ipv6_addr, sizeof (struct in6_addr))) | ||
1802 | return GNUNET_SYSERR; | 1471 | return GNUNET_SYSERR; |
1803 | } | 1472 | } |
1804 | return GNUNET_OK; | 1473 | return GNUNET_OK; |
@@ -1903,7 +1572,7 @@ handle_tcp_nat_probe (void *cls, | |||
1903 | case AF_INET: | 1572 | case AF_INET: |
1904 | s4 = vaddr; | 1573 | s4 = vaddr; |
1905 | t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); | 1574 | t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); |
1906 | t4->t_port = s4->sin_port; | 1575 | t4->t4_port = s4->sin_port; |
1907 | t4->ipv4_addr = s4->sin_addr.s_addr; | 1576 | t4->ipv4_addr = s4->sin_addr.s_addr; |
1908 | session->connect_addr = t4; | 1577 | session->connect_addr = t4; |
1909 | session->connect_alen = sizeof (struct IPv4TcpAddress); | 1578 | session->connect_alen = sizeof (struct IPv4TcpAddress); |
@@ -2016,7 +1685,7 @@ handle_tcp_welcome (void *cls, | |||
2016 | { | 1685 | { |
2017 | s4 = vaddr; | 1686 | s4 = vaddr; |
2018 | t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); | 1687 | t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); |
2019 | t4->t_port = s4->sin_port; | 1688 | t4->t4_port = s4->sin_port; |
2020 | t4->ipv4_addr = s4->sin_addr.s_addr; | 1689 | t4->ipv4_addr = s4->sin_addr.s_addr; |
2021 | session->connect_addr = t4; | 1690 | session->connect_addr = t4; |
2022 | session->connect_alen = sizeof (struct IPv4TcpAddress); | 1691 | session->connect_alen = sizeof (struct IPv4TcpAddress); |
@@ -2215,228 +1884,6 @@ disconnect_notify (void *cls, | |||
2215 | } | 1884 | } |
2216 | 1885 | ||
2217 | 1886 | ||
2218 | static int check_localaddress (const struct sockaddr *addr, socklen_t addrlen) | ||
2219 | { | ||
2220 | uint32_t res = 0; | ||
2221 | int local = GNUNET_NO; | ||
2222 | int af = addr->sa_family; | ||
2223 | switch (af) | ||
2224 | { | ||
2225 | case AF_INET: | ||
2226 | { | ||
2227 | uint32_t netmask = 0x7F000000; | ||
2228 | uint32_t address = ntohl (((struct sockaddr_in *) addr)->sin_addr.s_addr); | ||
2229 | res = (address >> 24) ^ (netmask >> 24); | ||
2230 | if (res != 0) | ||
2231 | local = GNUNET_NO; | ||
2232 | else | ||
2233 | local = GNUNET_YES; | ||
2234 | #if DEBUG_TCP | ||
2235 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2236 | "Checking IPv4 address `%s': %s\n", GNUNET_a2s (addr, addrlen), (local==GNUNET_YES) ? "local" : "global"); | ||
2237 | #endif | ||
2238 | break; | ||
2239 | } | ||
2240 | case AF_INET6: | ||
2241 | { | ||
2242 | if (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr) || | ||
2243 | IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) | ||
2244 | local = GNUNET_YES; | ||
2245 | else | ||
2246 | local = GNUNET_NO; | ||
2247 | #if DEBUG_TCP | ||
2248 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2249 | "Checking IPv6 address `%s' : %s\n", GNUNET_a2s (addr, addrlen), (local==GNUNET_YES) ? "local" : "global"); | ||
2250 | #endif | ||
2251 | break; | ||
2252 | } | ||
2253 | } | ||
2254 | return local; | ||
2255 | } | ||
2256 | |||
2257 | /** | ||
2258 | * Add the IP of our network interface to the list of | ||
2259 | * our internal IP addresses. | ||
2260 | * | ||
2261 | * @param cls the 'struct Plugin*' | ||
2262 | * @param name name of the interface | ||
2263 | * @param isDefault do we think this may be our default interface | ||
2264 | * @param addr address of the interface | ||
2265 | * @param addrlen number of bytes in addr | ||
2266 | * @return GNUNET_OK to continue iterating | ||
2267 | */ | ||
2268 | static int | ||
2269 | process_interfaces (void *cls, | ||
2270 | const char *name, | ||
2271 | int isDefault, | ||
2272 | const struct sockaddr *addr, socklen_t addrlen) | ||
2273 | { | ||
2274 | struct Plugin *plugin = cls; | ||
2275 | int af; | ||
2276 | struct IPv4TcpAddress t4; | ||
2277 | struct IPv6TcpAddress t6; | ||
2278 | struct IPv4TcpAddress t4_nat; | ||
2279 | struct IPv6TcpAddress t6_nat; | ||
2280 | void *arg; | ||
2281 | uint16_t args; | ||
2282 | void *arg_nat; | ||
2283 | char buf[INET6_ADDRSTRLEN]; | ||
2284 | |||
2285 | af = addr->sa_family; | ||
2286 | arg_nat = NULL; | ||
2287 | |||
2288 | if (plugin->use_localaddresses == GNUNET_NO) | ||
2289 | { | ||
2290 | if (GNUNET_YES == check_localaddress (addr, addrlen)) | ||
2291 | { | ||
2292 | #if DEBUG_TCP | ||
2293 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
2294 | "tcp", | ||
2295 | "Not notifying transport of address `%s' (local address)\n", | ||
2296 | GNUNET_a2s (addr, addrlen)); | ||
2297 | #endif | ||
2298 | return GNUNET_OK; | ||
2299 | } | ||
2300 | } | ||
2301 | |||
2302 | switch (af) | ||
2303 | { | ||
2304 | case AF_INET: | ||
2305 | t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; | ||
2306 | GNUNET_assert (NULL != inet_ntop(AF_INET, | ||
2307 | &t4.ipv4_addr, | ||
2308 | buf, | ||
2309 | sizeof (buf))); | ||
2310 | if ( (plugin->bind_address != NULL) && | ||
2311 | (0 != strcmp(buf, plugin->bind_address)) ) | ||
2312 | { | ||
2313 | #if DEBUG_TCP | ||
2314 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
2315 | "tcp", | ||
2316 | "Not notifying transport of address `%s' (does not match bind address)\n", | ||
2317 | GNUNET_a2s (addr, addrlen)); | ||
2318 | #endif | ||
2319 | return GNUNET_OK; | ||
2320 | } | ||
2321 | if ( (plugin->internal_address == NULL) && | ||
2322 | (isDefault) ) | ||
2323 | plugin->internal_address = GNUNET_strdup (buf); | ||
2324 | add_to_address_list (plugin, &t4.ipv4_addr, sizeof (struct in_addr)); | ||
2325 | if (plugin->behind_nat == GNUNET_YES) | ||
2326 | { | ||
2327 | /* Also advertise as NAT (with port 0) */ | ||
2328 | t4_nat.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; | ||
2329 | t4_nat.t_port = htons(0); | ||
2330 | arg_nat = &t4_nat; | ||
2331 | } | ||
2332 | t4.t_port = htons (plugin->adv_port); | ||
2333 | arg = &t4; | ||
2334 | args = sizeof (t4); | ||
2335 | break; | ||
2336 | case AF_INET6: | ||
2337 | if ( (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) || | ||
2338 | (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(plugin->env->cfg, | ||
2339 | "nat", | ||
2340 | "DISABLEV6")) ) | ||
2341 | { | ||
2342 | /* skip link local addresses */ | ||
2343 | return GNUNET_OK; | ||
2344 | } | ||
2345 | memcpy (&t6.ipv6_addr, | ||
2346 | &((struct sockaddr_in6 *) addr)->sin6_addr, | ||
2347 | sizeof (struct in6_addr)); | ||
2348 | |||
2349 | /* check bind address */ | ||
2350 | GNUNET_assert (NULL != inet_ntop(AF_INET6, | ||
2351 | &t6.ipv6_addr, | ||
2352 | buf, | ||
2353 | sizeof (buf))); | ||
2354 | |||
2355 | if ( (plugin->bind_address != NULL) && | ||
2356 | (0 != strcmp(buf, plugin->bind_address)) ) | ||
2357 | { | ||
2358 | #if DEBUG_TCP | ||
2359 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
2360 | "tcp", | ||
2361 | "Not notifying transport of address `%s' (does not match bind address)\n", | ||
2362 | GNUNET_a2s (addr, addrlen)); | ||
2363 | #endif | ||
2364 | return GNUNET_OK; | ||
2365 | } | ||
2366 | |||
2367 | add_to_address_list (plugin, | ||
2368 | &t6.ipv6_addr, | ||
2369 | sizeof (struct in6_addr)); | ||
2370 | if (plugin->behind_nat == GNUNET_YES) | ||
2371 | { | ||
2372 | /* Also advertise as NAT (with port 0) */ | ||
2373 | memcpy (&t6_nat.ipv6_addr, | ||
2374 | &((struct sockaddr_in6 *) addr)->sin6_addr, | ||
2375 | sizeof (struct in6_addr)); | ||
2376 | t6_nat.t6_port = htons(0); | ||
2377 | arg_nat = &t6; | ||
2378 | } | ||
2379 | t6.t6_port = htons (plugin->adv_port); | ||
2380 | arg = &t6; | ||
2381 | args = sizeof (t6); | ||
2382 | break; | ||
2383 | default: | ||
2384 | GNUNET_break (0); | ||
2385 | return GNUNET_OK; | ||
2386 | } | ||
2387 | if (plugin->adv_port != 0) | ||
2388 | { | ||
2389 | #if DEBUG_TCP | ||
2390 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
2391 | "tcp", | ||
2392 | "Found address `%s' (%s) len %d\n", | ||
2393 | GNUNET_a2s (addr, addrlen), name, args); | ||
2394 | #endif | ||
2395 | plugin->env->notify_address (plugin->env->cls, | ||
2396 | "tcp", | ||
2397 | arg, args, GNUNET_TIME_UNIT_FOREVER_REL); | ||
2398 | } | ||
2399 | |||
2400 | if (arg_nat != NULL) | ||
2401 | { | ||
2402 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
2403 | "tcp", | ||
2404 | _("Found address `%s' (%s) len %d\n"), | ||
2405 | GNUNET_a2s (addr, addrlen), name, args); | ||
2406 | plugin->env->notify_address (plugin->env->cls, | ||
2407 | "tcp", | ||
2408 | arg_nat, args, GNUNET_TIME_UNIT_FOREVER_REL); | ||
2409 | } | ||
2410 | |||
2411 | return GNUNET_OK; | ||
2412 | } | ||
2413 | |||
2414 | |||
2415 | /** | ||
2416 | * Function called by the resolver for each address obtained from DNS | ||
2417 | * for our own hostname. Add the addresses to the list of our | ||
2418 | * external IP addresses. | ||
2419 | * | ||
2420 | * @param cls closure | ||
2421 | * @param addr one of the addresses of the host, NULL for the last address | ||
2422 | * @param addrlen length of the address | ||
2423 | */ | ||
2424 | static void | ||
2425 | process_hostname_ips (void *cls, | ||
2426 | const struct sockaddr *addr, socklen_t addrlen) | ||
2427 | { | ||
2428 | struct Plugin *plugin = cls; | ||
2429 | |||
2430 | if (addr == NULL) | ||
2431 | { | ||
2432 | plugin->hostname_dns = NULL; | ||
2433 | return; | ||
2434 | } | ||
2435 | /* FIXME: Can we figure out our external address here so it doesn't need to be user specified? */ | ||
2436 | process_interfaces (plugin, "<hostname>", GNUNET_YES, addr, addrlen); | ||
2437 | } | ||
2438 | |||
2439 | |||
2440 | /** | 1887 | /** |
2441 | * We can now send a probe message, copy into buffer to really send. | 1888 | * We can now send a probe message, copy into buffer to really send. |
2442 | * | 1889 | * |
@@ -2475,112 +1922,36 @@ notify_send_probe (void *cls, | |||
2475 | 1922 | ||
2476 | 1923 | ||
2477 | /** | 1924 | /** |
2478 | * We have been notified that gnunet-nat-server has written something to stdout. | 1925 | * Function called by the NAT subsystem suggesting another peer wants |
2479 | * Handle the output, then reschedule this function to be called again once | 1926 | * to connect to us via connection reversal. Try to connect back to the |
2480 | * more is available. | 1927 | * given IP. |
2481 | * | 1928 | * |
2482 | * @param cls the plugin handle | 1929 | * @param cls closure |
2483 | * @param tc the scheduling context | 1930 | * @param addr address to try |
1931 | * @param addrlen number of bytes in addr | ||
2484 | */ | 1932 | */ |
2485 | static void | 1933 | static void |
2486 | tcp_plugin_server_read (void *cls, | 1934 | try_connection_reversal (void *cls, |
2487 | const struct GNUNET_SCHEDULER_TaskContext *tc) | 1935 | const struct sockaddr *addr, |
1936 | socklen_t addrlen) | ||
2488 | { | 1937 | { |
2489 | struct Plugin *plugin = cls; | 1938 | struct Plugin *plugin = cls; |
2490 | char mybuf[40]; | ||
2491 | ssize_t bytes; | ||
2492 | size_t i; | ||
2493 | int port; | ||
2494 | const char *port_start; | ||
2495 | struct sockaddr_in sin_addr; | ||
2496 | struct TCPProbeContext *tcp_probe_ctx; | ||
2497 | struct GNUNET_CONNECTION_Handle *sock; | 1939 | struct GNUNET_CONNECTION_Handle *sock; |
2498 | 1940 | struct TCPProbeContext *tcp_probe_ctx; | |
2499 | if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
2500 | return; | ||
2501 | memset (mybuf, 0, sizeof(mybuf)); | ||
2502 | bytes = GNUNET_DISK_file_read(plugin->server_stdout_handle, | ||
2503 | mybuf, | ||
2504 | sizeof(mybuf)); | ||
2505 | if (bytes < 1) | ||
2506 | { | ||
2507 | #if DEBUG_TCP_NAT | ||
2508 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
2509 | "tcp", | ||
2510 | "Finished reading from server stdout with code: %d\n", | ||
2511 | bytes); | ||
2512 | #endif | ||
2513 | /* FIXME: consider process_wait here? */ | ||
2514 | return; | ||
2515 | } | ||
2516 | |||
2517 | port_start = NULL; | ||
2518 | for (i = 0; i < sizeof(mybuf); i++) | ||
2519 | { | ||
2520 | if (mybuf[i] == '\n') | ||
2521 | { | ||
2522 | mybuf[i] = '\0'; | ||
2523 | break; | ||
2524 | } | ||
2525 | if ( (mybuf[i] == ':') && (i + 1 < sizeof(mybuf)) ) | ||
2526 | { | ||
2527 | mybuf[i] = '\0'; | ||
2528 | port_start = &mybuf[i + 1]; | ||
2529 | } | ||
2530 | } | ||
2531 | |||
2532 | /* construct socket address of sender */ | ||
2533 | memset (&sin_addr, 0, sizeof (sin_addr)); | ||
2534 | sin_addr.sin_family = AF_INET; | ||
2535 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
2536 | sin_addr.sin_len = sizeof (sin_addr); | ||
2537 | #endif | ||
2538 | if ( (NULL == port_start) || | ||
2539 | (1 != sscanf (port_start, "%d", &port)) || | ||
2540 | (-1 == inet_pton(AF_INET, mybuf, &sin_addr.sin_addr)) ) | ||
2541 | { | ||
2542 | /* should we restart gnunet-nat-server? */ | ||
2543 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | ||
2544 | "tcp", | ||
2545 | _("gnunet-nat-server generated malformed address `%s'\n"), | ||
2546 | mybuf); | ||
2547 | plugin->server_read_task | ||
2548 | = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2549 | plugin->server_stdout_handle, | ||
2550 | &tcp_plugin_server_read, | ||
2551 | plugin); | ||
2552 | return; | ||
2553 | } | ||
2554 | sin_addr.sin_port = htons((uint16_t) port); | ||
2555 | #if DEBUG_TCP_NAT | ||
2556 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
2557 | "tcp", | ||
2558 | "gnunet-nat-server read: %s:%d\n", | ||
2559 | mybuf, port); | ||
2560 | #endif | ||
2561 | 1941 | ||
2562 | /** | 1942 | /** |
2563 | * We have received an ICMP response, ostensibly from a peer | 1943 | * We have received an ICMP response, ostensibly from a peer |
2564 | * that wants to connect to us! Send a message to establish a connection. | 1944 | * that wants to connect to us! Send a message to establish a connection. |
2565 | */ | 1945 | */ |
2566 | sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, | 1946 | sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, |
2567 | (const struct sockaddr *)&sin_addr, | 1947 | addr, |
2568 | sizeof (sin_addr)); | 1948 | addrlen); |
2569 | if (sock == NULL) | 1949 | if (sock == NULL) |
2570 | { | 1950 | { |
2571 | /* failed for some odd reason (out of sockets?); ignore attempt */ | 1951 | /* failed for some odd reason (out of sockets?); ignore attempt */ |
2572 | plugin->server_read_task = | ||
2573 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2574 | plugin->server_stdout_handle, | ||
2575 | &tcp_plugin_server_read, | ||
2576 | plugin); | ||
2577 | return; | 1952 | return; |
2578 | } | 1953 | } |
2579 | 1954 | ||
2580 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
2581 | "Sending TCP probe message to `%s:%u'!\n", | ||
2582 | mybuf, | ||
2583 | (unsigned int) port); | ||
2584 | /* FIXME: do we need to track these probe context objects so that | 1955 | /* FIXME: do we need to track these probe context objects so that |
2585 | we can clean them up on plugin unload? */ | 1956 | we can clean them up on plugin unload? */ |
2586 | tcp_probe_ctx | 1957 | tcp_probe_ctx |
@@ -2603,251 +1974,6 @@ tcp_plugin_server_read (void *cls, | |||
2603 | GNUNET_TIME_UNIT_FOREVER_REL, | 1974 | GNUNET_TIME_UNIT_FOREVER_REL, |
2604 | ¬ify_send_probe, tcp_probe_ctx); | 1975 | ¬ify_send_probe, tcp_probe_ctx); |
2605 | 1976 | ||
2606 | plugin->server_read_task = | ||
2607 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2608 | plugin->server_stdout_handle, | ||
2609 | &tcp_plugin_server_read, | ||
2610 | plugin); | ||
2611 | } | ||
2612 | |||
2613 | |||
2614 | /** | ||
2615 | * Start the gnunet-nat-server process for users behind NAT. | ||
2616 | * | ||
2617 | * @param plugin the transport plugin | ||
2618 | * @return GNUNET_YES if process was started, GNUNET_SYSERR on error | ||
2619 | */ | ||
2620 | static int | ||
2621 | tcp_transport_start_nat_server (struct Plugin *plugin) | ||
2622 | { | ||
2623 | if (plugin->internal_address == NULL) | ||
2624 | return GNUNET_SYSERR; | ||
2625 | plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, | ||
2626 | GNUNET_NO, | ||
2627 | GNUNET_YES); | ||
2628 | if (plugin->server_stdout == NULL) | ||
2629 | return GNUNET_SYSERR; | ||
2630 | #if DEBUG_TCP_NAT | ||
2631 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
2632 | "tcp" | ||
2633 | "Starting %s %s\n", "gnunet-nat-server", plugin->internal_address); | ||
2634 | #endif | ||
2635 | /* Start the server process */ | ||
2636 | plugin->server_proc = GNUNET_OS_start_process (NULL, | ||
2637 | plugin->server_stdout, | ||
2638 | "gnunet-nat-server", | ||
2639 | "gnunet-nat-server", | ||
2640 | plugin->internal_address, | ||
2641 | NULL); | ||
2642 | if (plugin->server_proc == NULL) | ||
2643 | { | ||
2644 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | ||
2645 | "tcp", | ||
2646 | _("Failed to start %s\n"), | ||
2647 | "gnunet-nat-server"); | ||
2648 | GNUNET_DISK_pipe_close (plugin->server_stdout); | ||
2649 | plugin->server_stdout = NULL; | ||
2650 | return GNUNET_SYSERR; | ||
2651 | } | ||
2652 | /* Close the write end of the read pipe */ | ||
2653 | GNUNET_DISK_pipe_close_end(plugin->server_stdout, | ||
2654 | GNUNET_DISK_PIPE_END_WRITE); | ||
2655 | plugin->server_stdout_handle | ||
2656 | = GNUNET_DISK_pipe_handle (plugin->server_stdout, | ||
2657 | GNUNET_DISK_PIPE_END_READ); | ||
2658 | plugin->server_read_task | ||
2659 | = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2660 | plugin->server_stdout_handle, | ||
2661 | &tcp_plugin_server_read, | ||
2662 | plugin); | ||
2663 | return GNUNET_YES; | ||
2664 | } | ||
2665 | |||
2666 | |||
2667 | /** | ||
2668 | * Return the actual path to a file found in the current | ||
2669 | * PATH environment variable. | ||
2670 | * | ||
2671 | * @param binary the name of the file to find | ||
2672 | * @return path to binary, NULL if not found | ||
2673 | */ | ||
2674 | static char * | ||
2675 | get_path_from_PATH (const char *binary) | ||
2676 | { | ||
2677 | char *path; | ||
2678 | char *pos; | ||
2679 | char *end; | ||
2680 | char *buf; | ||
2681 | const char *p; | ||
2682 | |||
2683 | p = getenv ("PATH"); | ||
2684 | if (p == NULL) | ||
2685 | { | ||
2686 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
2687 | "tcp", | ||
2688 | _("PATH environment variable is unset.\n")); | ||
2689 | return NULL; | ||
2690 | } | ||
2691 | path = GNUNET_strdup (p); /* because we write on it */ | ||
2692 | buf = GNUNET_malloc (strlen (path) + 20); | ||
2693 | pos = path; | ||
2694 | |||
2695 | while (NULL != (end = strchr (pos, PATH_SEPARATOR))) | ||
2696 | { | ||
2697 | *end = '\0'; | ||
2698 | sprintf (buf, "%s/%s", pos, binary); | ||
2699 | if (GNUNET_DISK_file_test (buf) == GNUNET_YES) | ||
2700 | { | ||
2701 | GNUNET_free (path); | ||
2702 | return buf; | ||
2703 | } | ||
2704 | pos = end + 1; | ||
2705 | } | ||
2706 | sprintf (buf, "%s/%s", pos, binary); | ||
2707 | if (GNUNET_DISK_file_test (buf) == GNUNET_YES) | ||
2708 | { | ||
2709 | GNUNET_free (path); | ||
2710 | return buf; | ||
2711 | } | ||
2712 | GNUNET_free (buf); | ||
2713 | GNUNET_free (path); | ||
2714 | return NULL; | ||
2715 | } | ||
2716 | |||
2717 | |||
2718 | /** | ||
2719 | * Check whether the suid bit is set on a file. | ||
2720 | * Attempts to find the file using the current | ||
2721 | * PATH environment variable as a search path. | ||
2722 | * | ||
2723 | * @param binary the name of the file to check | ||
2724 | * @return GNUNET_YES if the file is SUID, | ||
2725 | * GNUNET_NO if not, | ||
2726 | * GNUNET_SYSERR on error | ||
2727 | */ | ||
2728 | static int | ||
2729 | check_gnunet_nat_binary (const char *binary) | ||
2730 | { | ||
2731 | struct stat statbuf; | ||
2732 | char *p; | ||
2733 | #ifdef MINGW | ||
2734 | SOCKET rawsock; | ||
2735 | char *binaryexe; | ||
2736 | |||
2737 | GNUNET_asprintf (&binaryexe, "%s.exe", binary); | ||
2738 | p = get_path_from_PATH (binaryexe); | ||
2739 | free (binaryexe); | ||
2740 | #else | ||
2741 | p = get_path_from_PATH (binary); | ||
2742 | #endif | ||
2743 | if (p == NULL) | ||
2744 | { | ||
2745 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
2746 | "tcp", | ||
2747 | _("Could not find binary `%s' in PATH!\n"), | ||
2748 | binary); | ||
2749 | return GNUNET_NO; | ||
2750 | } | ||
2751 | if (0 != STAT (p, &statbuf)) | ||
2752 | { | ||
2753 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2754 | _("stat (%s) failed: %s\n"), | ||
2755 | p, | ||
2756 | STRERROR (errno)); | ||
2757 | GNUNET_free (p); | ||
2758 | return GNUNET_SYSERR; | ||
2759 | } | ||
2760 | GNUNET_free (p); | ||
2761 | #ifndef MINGW | ||
2762 | if ( (0 != (statbuf.st_mode & S_ISUID)) && | ||
2763 | (statbuf.st_uid == 0) ) | ||
2764 | return GNUNET_YES; | ||
2765 | return GNUNET_NO; | ||
2766 | #else | ||
2767 | rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); | ||
2768 | if (INVALID_SOCKET == rawsock) | ||
2769 | { | ||
2770 | DWORD err = GetLastError (); | ||
2771 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | ||
2772 | "tcp", | ||
2773 | "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) failed! GLE = %d\n", err); | ||
2774 | return GNUNET_NO; /* not running as administrator */ | ||
2775 | } | ||
2776 | closesocket (rawsock); | ||
2777 | return GNUNET_YES; | ||
2778 | #endif | ||
2779 | } | ||
2780 | |||
2781 | |||
2782 | /** | ||
2783 | * Our (external) hostname was resolved. | ||
2784 | * | ||
2785 | * @param cls the 'struct Plugin' | ||
2786 | * @param addr NULL on error, otherwise result of DNS lookup | ||
2787 | * @param addrlen number of bytes in addr | ||
2788 | */ | ||
2789 | static void | ||
2790 | process_external_ip (void *cls, | ||
2791 | const struct sockaddr *addr, | ||
2792 | socklen_t addrlen) | ||
2793 | { | ||
2794 | struct Plugin *plugin = cls; | ||
2795 | const struct sockaddr_in *s; | ||
2796 | struct IPv4TcpAddress t4; | ||
2797 | char buf[INET_ADDRSTRLEN]; | ||
2798 | |||
2799 | plugin->ext_dns = NULL; | ||
2800 | if (addr == NULL) | ||
2801 | return; | ||
2802 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); | ||
2803 | s = (const struct sockaddr_in *) addr; | ||
2804 | t4.ipv4_addr = s->sin_addr.s_addr; | ||
2805 | if ( (plugin->behind_nat == GNUNET_YES) && | ||
2806 | (plugin->enable_nat_server == GNUNET_YES) ) | ||
2807 | { | ||
2808 | t4.t_port = htons(0); | ||
2809 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
2810 | "tcp", | ||
2811 | "Notifying transport of address %s:%d\n", | ||
2812 | plugin->external_address, | ||
2813 | 0); | ||
2814 | } | ||
2815 | else | ||
2816 | { | ||
2817 | t4.t_port = htons(plugin->adv_port); | ||
2818 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
2819 | "tcp", | ||
2820 | "Notifying transport of address %s:%d\n", | ||
2821 | plugin->external_address, | ||
2822 | (int) plugin->adv_port); | ||
2823 | } | ||
2824 | |||
2825 | if ((plugin->bind_address != NULL) && (plugin->behind_nat == GNUNET_NO)) | ||
2826 | { | ||
2827 | GNUNET_assert (NULL != inet_ntop(AF_INET, | ||
2828 | &t4.ipv4_addr, | ||
2829 | buf, | ||
2830 | sizeof (buf))); | ||
2831 | if (0 != strcmp (plugin->bind_address, buf)) | ||
2832 | { | ||
2833 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
2834 | "tcp", | ||
2835 | "NAT is not enabled and specific bind address `%s' differs from external address `%s'! Not notifying about external address `%s'\n", | ||
2836 | plugin->bind_address, | ||
2837 | plugin->external_address, | ||
2838 | plugin->external_address); | ||
2839 | return; | ||
2840 | } | ||
2841 | } | ||
2842 | |||
2843 | add_to_address_list (plugin, | ||
2844 | &t4.ipv4_addr, | ||
2845 | sizeof (struct in_addr)); | ||
2846 | |||
2847 | plugin->env->notify_address (plugin->env->cls, | ||
2848 | "tcp", | ||
2849 | &t4, sizeof(t4), | ||
2850 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
2851 | } | 1977 | } |
2852 | 1978 | ||
2853 | 1979 | ||
@@ -2875,146 +2001,16 @@ libgnunet_plugin_transport_tcp_init (void *cls) | |||
2875 | unsigned long long bport; | 2001 | unsigned long long bport; |
2876 | unsigned long long max_connections; | 2002 | unsigned long long max_connections; |
2877 | unsigned int i; | 2003 | unsigned int i; |
2878 | int behind_nat; | ||
2879 | int nat_punched; | ||
2880 | int enable_nat_client; | ||
2881 | int enable_nat_server; | ||
2882 | int enable_upnp; | ||
2883 | int use_localaddresses; | ||
2884 | char *internal_address; | ||
2885 | char *external_address; | ||
2886 | char *bind_address; | ||
2887 | struct sockaddr_in in_addr; | ||
2888 | struct GNUNET_TIME_Relative idle_timeout; | 2004 | struct GNUNET_TIME_Relative idle_timeout; |
2005 | int ret; | ||
2006 | struct sockaddr **addrs; | ||
2007 | socklen_t *addrlens; | ||
2889 | 2008 | ||
2890 | behind_nat = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2891 | "nat", | ||
2892 | "BEHIND_NAT"); | ||
2893 | nat_punched = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2894 | "nat", | ||
2895 | "NAT_PUNCHED"); | ||
2896 | enable_nat_client = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2897 | "nat", | ||
2898 | "ENABLE_NAT_CLIENT"); | ||
2899 | enable_nat_server = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2900 | "nat", | ||
2901 | "ENABLE_NAT_SERVER"); | ||
2902 | enable_upnp = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2903 | "nat", | ||
2904 | "ENABLE_UPNP"); | ||
2905 | |||
2906 | if ( (GNUNET_YES == enable_nat_server) && | ||
2907 | (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-server")) ) | ||
2908 | { | ||
2909 | enable_nat_server = GNUNET_NO; | ||
2910 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2911 | _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), | ||
2912 | "gnunet-nat-server"); | ||
2913 | } | ||
2914 | |||
2915 | if ( (GNUNET_YES == enable_nat_client) && | ||
2916 | (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-client")) ) | ||
2917 | { | ||
2918 | enable_nat_client = GNUNET_NO; | ||
2919 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2920 | _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), | ||
2921 | "gnunet-nat-client"); | ||
2922 | } | ||
2923 | |||
2924 | external_address = NULL; | ||
2925 | if (GNUNET_OK == | ||
2926 | GNUNET_CONFIGURATION_have_value (env->cfg, | ||
2927 | "nat", | ||
2928 | "EXTERNAL_ADDRESS")) | ||
2929 | { | ||
2930 | (void) GNUNET_CONFIGURATION_get_value_string (env->cfg, | ||
2931 | "nat", | ||
2932 | "EXTERNAL_ADDRESS", | ||
2933 | &external_address); | ||
2934 | } | ||
2935 | |||
2936 | if ( (external_address != NULL) && | ||
2937 | (inet_pton(AF_INET, external_address, &in_addr.sin_addr) != 1) ) | ||
2938 | { | ||
2939 | |||
2940 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | ||
2941 | "tcp", | ||
2942 | _("Malformed %s `%s' given in configuration!\n"), | ||
2943 | "EXTERNAL_ADDRESS", | ||
2944 | external_address); | ||
2945 | return NULL; | ||
2946 | } | ||
2947 | if ( (external_address == NULL) && | ||
2948 | (nat_punched == GNUNET_YES) ) | ||
2949 | { | ||
2950 | nat_punched = GNUNET_NO; | ||
2951 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2952 | _("Configuration says NAT was punched, but `%s' is not given. Option ignored.\n"), | ||
2953 | "EXTERNAL_ADDRESS"); | ||
2954 | } | ||
2955 | |||
2956 | if (GNUNET_YES == nat_punched) | ||
2957 | { | ||
2958 | enable_nat_server = GNUNET_NO; | ||
2959 | enable_upnp = GNUNET_NO; | ||
2960 | } | ||
2961 | |||
2962 | bind_address = NULL; | ||
2963 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (env->cfg, | ||
2964 | "nat", | ||
2965 | "BINDTO", | ||
2966 | &bind_address)) | ||
2967 | { | ||
2968 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | ||
2969 | "tcp", | ||
2970 | _("Binding TCP plugin to specific address: `%s'\n"), | ||
2971 | bind_address); | ||
2972 | } | ||
2973 | |||
2974 | internal_address = NULL; | ||
2975 | if (GNUNET_OK == | ||
2976 | GNUNET_CONFIGURATION_have_value (env->cfg, | ||
2977 | "nat", | ||
2978 | "INTERNAL_ADDRESS")) | ||
2979 | { | ||
2980 | (void) GNUNET_CONFIGURATION_get_value_string (env->cfg, | ||
2981 | "nat", | ||
2982 | "INTERNAL_ADDRESS", | ||
2983 | &internal_address); | ||
2984 | } | ||
2985 | |||
2986 | if ( (internal_address != NULL) && | ||
2987 | (inet_pton(AF_INET, internal_address, &in_addr.sin_addr) != 1) ) | ||
2988 | { | ||
2989 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | ||
2990 | "tcp", | ||
2991 | _("Malformed %s `%s' given in configuration!\n"), | ||
2992 | "INTERNAL_ADDRESS", | ||
2993 | internal_address); | ||
2994 | GNUNET_free_non_null(internal_address); | ||
2995 | GNUNET_free_non_null(external_address); | ||
2996 | return NULL; | ||
2997 | } | ||
2998 | |||
2999 | if ((bind_address != NULL) && (internal_address != NULL)) | ||
3000 | { | ||
3001 | if (0 != strcmp(internal_address, bind_address )) | ||
3002 | { | ||
3003 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
3004 | "tcp", | ||
3005 | "Specific bind address `%s' and internal address `%s' must not differ, forcing internal address to bind address!\n", | ||
3006 | bind_address, internal_address); | ||
3007 | GNUNET_free (internal_address); | ||
3008 | internal_address = bind_address; | ||
3009 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
3010 | "tcp","New internal address `%s'\n", internal_address); | ||
3011 | } | ||
3012 | } | ||
3013 | if (GNUNET_OK != | 2009 | if (GNUNET_OK != |
3014 | GNUNET_CONFIGURATION_get_value_number (env->cfg, | 2010 | GNUNET_CONFIGURATION_get_value_number (env->cfg, |
3015 | "transport-tcp", | 2011 | "transport-tcp", |
3016 | "MAX_CONNECTIONS", | 2012 | "MAX_CONNECTIONS", |
3017 | &max_connections)) | 2013 | &max_connections)) |
3018 | max_connections = 128; | 2014 | max_connections = 128; |
3019 | 2015 | ||
3020 | aport = 0; | 2016 | aport = 0; |
@@ -3035,25 +2031,15 @@ libgnunet_plugin_transport_tcp_init (void *cls) | |||
3035 | "tcp", | 2031 | "tcp", |
3036 | _("Require valid port number for service `%s' in configuration!\n"), | 2032 | _("Require valid port number for service `%s' in configuration!\n"), |
3037 | "transport-tcp"); | 2033 | "transport-tcp"); |
3038 | GNUNET_free_non_null(external_address); | ||
3039 | GNUNET_free_non_null(internal_address); | ||
3040 | return NULL; | 2034 | return NULL; |
3041 | } | 2035 | } |
3042 | |||
3043 | use_localaddresses = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
3044 | "transport-tcp", | ||
3045 | "USE_LOCALADDR"); | ||
3046 | if (use_localaddresses == GNUNET_SYSERR) | ||
3047 | use_localaddresses = GNUNET_NO; | ||
3048 | |||
3049 | if (aport == 0) | 2036 | if (aport == 0) |
3050 | aport = bport; | 2037 | aport = bport; |
3051 | if (bport == 0) | 2038 | if (bport == 0) |
3052 | aport = 0; | 2039 | aport = 0; |
3053 | |||
3054 | if (bport != 0) | 2040 | if (bport != 0) |
3055 | { | 2041 | { |
3056 | service = GNUNET_SERVICE_start ("transport-tcp", env->cfg); | 2042 | service = GNUNET_SERVICE_start ("transport-tcp", env->cfg); |
3057 | if (service == NULL) | 2043 | if (service == NULL) |
3058 | { | 2044 | { |
3059 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, | 2045 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, |
@@ -3065,21 +2051,45 @@ libgnunet_plugin_transport_tcp_init (void *cls) | |||
3065 | else | 2051 | else |
3066 | service = NULL; | 2052 | service = NULL; |
3067 | 2053 | ||
2054 | |||
2055 | |||
3068 | plugin = GNUNET_malloc (sizeof (struct Plugin)); | 2056 | plugin = GNUNET_malloc (sizeof (struct Plugin)); |
3069 | plugin->max_connections = max_connections; | 2057 | plugin->max_connections = max_connections; |
3070 | plugin->open_port = bport; | 2058 | plugin->open_port = bport; |
3071 | plugin->adv_port = aport; | 2059 | plugin->adv_port = aport; |
3072 | plugin->bind_address = bind_address; | ||
3073 | plugin->external_address = external_address; | ||
3074 | plugin->internal_address = internal_address; | ||
3075 | plugin->behind_nat = behind_nat; | ||
3076 | plugin->nat_punched = nat_punched; | ||
3077 | plugin->enable_nat_client = enable_nat_client; | ||
3078 | plugin->enable_nat_server = enable_nat_server; | ||
3079 | plugin->enable_upnp = enable_upnp; | ||
3080 | plugin->use_localaddresses = use_localaddresses; | ||
3081 | plugin->env = env; | 2060 | plugin->env = env; |
3082 | plugin->lsock = NULL; | 2061 | plugin->lsock = NULL; |
2062 | if ( (service != NULL) && | ||
2063 | (GNUNET_SYSERR != | ||
2064 | (ret = GNUNET_SERVICE_get_server_addresses ("transport-tcp", | ||
2065 | env->cfg, | ||
2066 | &addrs, | ||
2067 | &addrlens))) ) | ||
2068 | { | ||
2069 | plugin->nat = GNUNET_NAT_register (env->cfg, | ||
2070 | GNUNET_YES, | ||
2071 | aport, | ||
2072 | (unsigned int) ret, | ||
2073 | (const struct sockaddr **) addrs, | ||
2074 | addrlens, | ||
2075 | &tcp_nat_port_map_callback, | ||
2076 | &try_connection_reversal, | ||
2077 | plugin); | ||
2078 | while (ret > 0) | ||
2079 | GNUNET_free (addrs[--ret]); | ||
2080 | GNUNET_free_non_null (addrs); | ||
2081 | GNUNET_free_non_null (addrlens); | ||
2082 | } | ||
2083 | else | ||
2084 | { | ||
2085 | plugin->nat = GNUNET_NAT_register (env->cfg, | ||
2086 | GNUNET_YES, | ||
2087 | 0, | ||
2088 | 0, NULL, NULL, | ||
2089 | NULL, | ||
2090 | &try_connection_reversal, | ||
2091 | plugin); | ||
2092 | } | ||
3083 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | 2093 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); |
3084 | api->cls = plugin; | 2094 | api->cls = plugin; |
3085 | api->send = &tcp_plugin_send; | 2095 | api->send = &tcp_plugin_send; |
@@ -3105,8 +2115,9 @@ libgnunet_plugin_transport_tcp_init (void *cls) | |||
3105 | _("Failed to find option %s in section %s!\n"), | 2115 | _("Failed to find option %s in section %s!\n"), |
3106 | "TIMEOUT", | 2116 | "TIMEOUT", |
3107 | "transport-tcp"); | 2117 | "transport-tcp"); |
3108 | GNUNET_free_non_null(external_address); | 2118 | if (plugin->nat != NULL) |
3109 | GNUNET_free_non_null(internal_address); | 2119 | GNUNET_NAT_unregister (plugin->nat); |
2120 | GNUNET_free (plugin); | ||
3110 | GNUNET_free (api); | 2121 | GNUNET_free (api); |
3111 | return NULL; | 2122 | return NULL; |
3112 | } | 2123 | } |
@@ -3123,33 +2134,7 @@ libgnunet_plugin_transport_tcp_init (void *cls) | |||
3123 | GNUNET_SERVER_disconnect_notify (plugin->server, | 2134 | GNUNET_SERVER_disconnect_notify (plugin->server, |
3124 | &disconnect_notify, | 2135 | &disconnect_notify, |
3125 | plugin); | 2136 | plugin); |
3126 | GNUNET_OS_network_interfaces_list (&process_interfaces, plugin); | 2137 | plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create(16); |
3127 | |||
3128 | if ( (plugin->behind_nat == GNUNET_YES) && | ||
3129 | (plugin->enable_nat_server == GNUNET_YES) && | ||
3130 | (GNUNET_YES != tcp_transport_start_nat_server(plugin)) ) | ||
3131 | { | ||
3132 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, | ||
3133 | "tcp", | ||
3134 | _("Failed to start %s required for NAT in %s!\n"), | ||
3135 | "gnunet-nat-server" | ||
3136 | "transport-tcp"); | ||
3137 | GNUNET_free_non_null(external_address); | ||
3138 | GNUNET_free_non_null(internal_address); | ||
3139 | if (service != NULL) | ||
3140 | GNUNET_SERVICE_stop (service); | ||
3141 | else | ||
3142 | GNUNET_SERVER_destroy (plugin->server); | ||
3143 | GNUNET_free (api); | ||
3144 | return NULL; | ||
3145 | } | ||
3146 | |||
3147 | if (enable_nat_client == GNUNET_YES) | ||
3148 | { | ||
3149 | plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create(16); | ||
3150 | GNUNET_assert (plugin->nat_wait_conns != NULL); | ||
3151 | } | ||
3152 | |||
3153 | if (bport != 0) | 2138 | if (bport != 0) |
3154 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, | 2139 | GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, |
3155 | "tcp", | 2140 | "tcp", |
@@ -3164,20 +2149,6 @@ libgnunet_plugin_transport_tcp_init (void *cls) | |||
3164 | "tcp", | 2149 | "tcp", |
3165 | _("TCP transport advertises itself as being on port %llu\n"), | 2150 | _("TCP transport advertises itself as being on port %llu\n"), |
3166 | aport); | 2151 | aport); |
3167 | |||
3168 | plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, | ||
3169 | HOSTNAME_RESOLVE_TIMEOUT, | ||
3170 | &process_hostname_ips, | ||
3171 | plugin); | ||
3172 | |||
3173 | if (plugin->external_address != NULL) | ||
3174 | { | ||
3175 | plugin->ext_dns = GNUNET_RESOLVER_ip_get (plugin->external_address, | ||
3176 | AF_INET, | ||
3177 | GNUNET_TIME_UNIT_MINUTES, | ||
3178 | &process_external_ip, | ||
3179 | plugin); | ||
3180 | } | ||
3181 | return api; | 2152 | return api; |
3182 | } | 2153 | } |
3183 | 2154 | ||
@@ -3191,36 +2162,17 @@ libgnunet_plugin_transport_tcp_done (void *cls) | |||
3191 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; | 2162 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; |
3192 | struct Plugin *plugin = api->cls; | 2163 | struct Plugin *plugin = api->cls; |
3193 | struct Session *session; | 2164 | struct Session *session; |
3194 | struct LocalAddrList *lal; | ||
3195 | struct TCPProbeContext *tcp_probe; | 2165 | struct TCPProbeContext *tcp_probe; |
3196 | 2166 | ||
3197 | if (plugin->ext_dns != NULL) | ||
3198 | { | ||
3199 | GNUNET_RESOLVER_request_cancel (plugin->ext_dns); | ||
3200 | plugin->ext_dns = NULL; | ||
3201 | } | ||
3202 | while (NULL != (session = plugin->sessions)) | 2167 | while (NULL != (session = plugin->sessions)) |
3203 | disconnect_session (session); | 2168 | disconnect_session (session); |
3204 | if (NULL != plugin->hostname_dns) | ||
3205 | { | ||
3206 | GNUNET_RESOLVER_request_cancel (plugin->hostname_dns); | ||
3207 | plugin->hostname_dns = NULL; | ||
3208 | } | ||
3209 | if (plugin->service != NULL) | 2169 | if (plugin->service != NULL) |
3210 | GNUNET_SERVICE_stop (plugin->service); | 2170 | GNUNET_SERVICE_stop (plugin->service); |
3211 | else | 2171 | else |
3212 | GNUNET_SERVER_destroy (plugin->server); | 2172 | GNUNET_SERVER_destroy (plugin->server); |
3213 | GNUNET_free (plugin->handlers); | 2173 | GNUNET_free (plugin->handlers); |
3214 | while (NULL != (lal = plugin->lal_head)) | 2174 | if (plugin->nat != NULL) |
3215 | { | 2175 | GNUNET_NAT_unregister (plugin->nat); |
3216 | GNUNET_CONTAINER_DLL_remove (plugin->lal_head, | ||
3217 | plugin->lal_tail, | ||
3218 | lal); | ||
3219 | if (lal->nat != NULL) | ||
3220 | GNUNET_NAT_unregister (lal->nat); | ||
3221 | GNUNET_free_non_null (lal->external_nat_address); | ||
3222 | GNUNET_free (lal); | ||
3223 | } | ||
3224 | while (NULL != (tcp_probe = plugin->probe_head)) | 2176 | while (NULL != (tcp_probe = plugin->probe_head)) |
3225 | { | 2177 | { |
3226 | GNUNET_CONTAINER_DLL_remove (plugin->probe_head, | 2178 | GNUNET_CONTAINER_DLL_remove (plugin->probe_head, |
@@ -3229,19 +2181,6 @@ libgnunet_plugin_transport_tcp_done (void *cls) | |||
3229 | GNUNET_CONNECTION_destroy (tcp_probe->sock, GNUNET_NO); | 2181 | GNUNET_CONNECTION_destroy (tcp_probe->sock, GNUNET_NO); |
3230 | GNUNET_free (tcp_probe); | 2182 | GNUNET_free (tcp_probe); |
3231 | } | 2183 | } |
3232 | |||
3233 | if ((plugin->behind_nat == GNUNET_YES) && | ||
3234 | (plugin->enable_nat_server == GNUNET_YES)) | ||
3235 | { | ||
3236 | if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM)) | ||
3237 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
3238 | GNUNET_OS_process_wait (plugin->server_proc); | ||
3239 | GNUNET_OS_process_close (plugin->server_proc); | ||
3240 | plugin->server_proc = NULL; | ||
3241 | } | ||
3242 | GNUNET_free_non_null(plugin->bind_address); | ||
3243 | GNUNET_free_non_null(plugin->internal_address); | ||
3244 | GNUNET_free_non_null(plugin->external_address); | ||
3245 | GNUNET_free (plugin); | 2184 | GNUNET_free (plugin); |
3246 | GNUNET_free (api); | 2185 | GNUNET_free (api); |
3247 | return NULL; | 2186 | return NULL; |
diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c index 2366a2e16..e5e741df3 100644 --- a/src/transport/plugin_transport_udp.c +++ b/src/transport/plugin_transport_udp.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include "gnunet_hello_lib.h" | 41 | #include "gnunet_hello_lib.h" |
42 | #include "gnunet_connection_lib.h" | 42 | #include "gnunet_connection_lib.h" |
43 | #include "gnunet_container_lib.h" | 43 | #include "gnunet_container_lib.h" |
44 | #include "gnunet_nat_lib.h" | ||
44 | #include "gnunet_os_lib.h" | 45 | #include "gnunet_os_lib.h" |
45 | #include "gnunet_peerinfo_service.h" | 46 | #include "gnunet_peerinfo_service.h" |
46 | #include "gnunet_protocols.h" | 47 | #include "gnunet_protocols.h" |
@@ -103,7 +104,7 @@ struct IPv4UdpAddress | |||
103 | /** | 104 | /** |
104 | * Port number, in network byte order. | 105 | * Port number, in network byte order. |
105 | */ | 106 | */ |
106 | uint16_t u_port GNUNET_PACKED; | 107 | uint16_t u4_port GNUNET_PACKED; |
107 | }; | 108 | }; |
108 | 109 | ||
109 | 110 | ||
@@ -211,31 +212,6 @@ struct UDP_NAT_ProbeMessageConfirmation | |||
211 | 212 | ||
212 | 213 | ||
213 | /** | 214 | /** |
214 | * Local network addresses (actual IP address follows this struct). | ||
215 | * PORT is NOT included! | ||
216 | */ | ||
217 | struct LocalAddrList | ||
218 | { | ||
219 | |||
220 | /** | ||
221 | * This is a doubly linked list. | ||
222 | */ | ||
223 | struct LocalAddrList *next; | ||
224 | |||
225 | /** | ||
226 | * This is a doubly linked list. | ||
227 | */ | ||
228 | struct LocalAddrList *prev; | ||
229 | |||
230 | /** | ||
231 | * Number of bytes of the address that follow | ||
232 | */ | ||
233 | size_t size; | ||
234 | |||
235 | }; | ||
236 | |||
237 | |||
238 | /** | ||
239 | * UDP NAT "Session" | 215 | * UDP NAT "Session" |
240 | */ | 216 | */ |
241 | struct PeerSession | 217 | struct PeerSession |
@@ -295,11 +271,6 @@ struct UDP_NAT_Probes | |||
295 | struct UDP_NAT_Probes *next; | 271 | struct UDP_NAT_Probes *next; |
296 | 272 | ||
297 | /** | 273 | /** |
298 | * Address string that the server process returned to us | ||
299 | */ | ||
300 | char *address_string; | ||
301 | |||
302 | /** | ||
303 | * Timeout for this set of probes | 274 | * Timeout for this set of probes |
304 | */ | 275 | */ |
305 | struct GNUNET_TIME_Absolute timeout; | 276 | struct GNUNET_TIME_Absolute timeout; |
@@ -360,16 +331,6 @@ struct Plugin | |||
360 | struct PeerSession *sessions; | 331 | struct PeerSession *sessions; |
361 | 332 | ||
362 | /** | 333 | /** |
363 | * Handle for request of hostname resolution, non-NULL if pending. | ||
364 | */ | ||
365 | struct GNUNET_RESOLVER_RequestHandle *hostname_dns; | ||
366 | |||
367 | /** | ||
368 | * ID of task used to update our addresses when one expires. | ||
369 | */ | ||
370 | GNUNET_SCHEDULER_TaskIdentifier address_update_task; | ||
371 | |||
372 | /** | ||
373 | * ID of select task | 334 | * ID of select task |
374 | */ | 335 | */ |
375 | GNUNET_SCHEDULER_TaskIdentifier select_task; | 336 | GNUNET_SCHEDULER_TaskIdentifier select_task; |
@@ -380,17 +341,6 @@ struct Plugin | |||
380 | uint16_t port; | 341 | uint16_t port; |
381 | 342 | ||
382 | /** | 343 | /** |
383 | * The external address given to us by the user. Must be actual | ||
384 | * outside visible address for NAT punching to work. | ||
385 | */ | ||
386 | char *external_address; | ||
387 | |||
388 | /** | ||
389 | * The internal address given to us by the user (or discovered). | ||
390 | */ | ||
391 | char *internal_address; | ||
392 | |||
393 | /** | ||
394 | * Address we were told to bind to exclusively (IPv4). | 344 | * Address we were told to bind to exclusively (IPv4). |
395 | */ | 345 | */ |
396 | char *bind_address; | 346 | char *bind_address; |
@@ -401,14 +351,9 @@ struct Plugin | |||
401 | char *bind6_address; | 351 | char *bind6_address; |
402 | 352 | ||
403 | /** | 353 | /** |
404 | * List of our IP addresses. | 354 | * Handle to NAT traversal support. |
405 | */ | 355 | */ |
406 | struct LocalAddrList *lal_head; | 356 | struct GNUNET_NAT_Handle *nat; |
407 | |||
408 | /** | ||
409 | * Tail of our IP address list. | ||
410 | */ | ||
411 | struct LocalAddrList *lal_tail; | ||
412 | 357 | ||
413 | /** | 358 | /** |
414 | * FD Read set | 359 | * FD Read set |
@@ -416,16 +361,6 @@ struct Plugin | |||
416 | struct GNUNET_NETWORK_FDSet *rs; | 361 | struct GNUNET_NETWORK_FDSet *rs; |
417 | 362 | ||
418 | /** | 363 | /** |
419 | * stdout pipe handle for the gnunet-nat-server process | ||
420 | */ | ||
421 | struct GNUNET_DISK_PipeHandle *server_stdout; | ||
422 | |||
423 | /** | ||
424 | * stdout file handle (for reading) for the gnunet-nat-server process | ||
425 | */ | ||
426 | const struct GNUNET_DISK_FileHandle *server_stdout_handle; | ||
427 | |||
428 | /** | ||
429 | * Probes in flight | 364 | * Probes in flight |
430 | */ | 365 | */ |
431 | struct UDP_NAT_Probes *probes; | 366 | struct UDP_NAT_Probes *probes; |
@@ -440,45 +375,13 @@ struct Plugin | |||
440 | */ | 375 | */ |
441 | struct UDP_Sock_Info udp_sockv6; | 376 | struct UDP_Sock_Info udp_sockv6; |
442 | 377 | ||
443 | /** | ||
444 | * ID of select gnunet-nat-server stdout read task | ||
445 | */ | ||
446 | GNUNET_SCHEDULER_TaskIdentifier server_read_task; | ||
447 | |||
448 | /** | ||
449 | * Is this transport configured to be behind a NAT? | ||
450 | */ | ||
451 | int behind_nat; | ||
452 | |||
453 | /** | ||
454 | * Is this transport configured to allow connections to NAT'd peers? | ||
455 | */ | ||
456 | int allow_nat; | ||
457 | |||
458 | /** | ||
459 | * Should this transport advertise only NAT addresses (port set to 0)? | ||
460 | * If not, all addresses will be duplicated for NAT punching and regular | ||
461 | * ports. | ||
462 | */ | ||
463 | int only_nat_addresses; | ||
464 | |||
465 | /** | ||
466 | * use local addresses? | ||
467 | */ | ||
468 | int use_localaddresses; | ||
469 | |||
470 | /** | ||
471 | * The process id of the server process (if behind NAT) | ||
472 | */ | ||
473 | struct GNUNET_OS_Process *server_proc; | ||
474 | |||
475 | }; | 378 | }; |
476 | 379 | ||
477 | 380 | ||
478 | /** | 381 | /** |
479 | * Forward declaration. | 382 | * Forward declaration. |
480 | */ | 383 | */ |
481 | void | 384 | static void |
482 | udp_probe_continuation (void *cls, const struct GNUNET_PeerIdentity *target, int result); | 385 | udp_probe_continuation (void *cls, const struct GNUNET_PeerIdentity *target, int result); |
483 | 386 | ||
484 | 387 | ||
@@ -489,53 +392,13 @@ udp_probe_continuation (void *cls, const struct GNUNET_PeerIdentity *target, int | |||
489 | * @param target the peeridentity of the peer to disconnect | 392 | * @param target the peeridentity of the peer to disconnect |
490 | * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed | 393 | * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed |
491 | */ | 394 | */ |
492 | void | 395 | static void |
493 | udp_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) | 396 | udp_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) |
494 | { | 397 | { |
495 | /** TODO: Implement! */ | 398 | /** TODO: Implement! */ |
496 | return; | 399 | return; |
497 | } | 400 | } |
498 | 401 | ||
499 | /** | ||
500 | * Shutdown the server process (stop receiving inbound traffic). Maybe | ||
501 | * restarted later! | ||
502 | * | ||
503 | * @param cls Handle to the plugin for this transport | ||
504 | * | ||
505 | * @return returns the number of sockets successfully closed, | ||
506 | * should equal the number of sockets successfully opened | ||
507 | */ | ||
508 | static int | ||
509 | udp_transport_server_stop (void *cls) | ||
510 | { | ||
511 | struct Plugin *plugin = cls; | ||
512 | |||
513 | if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) | ||
514 | { | ||
515 | GNUNET_SCHEDULER_cancel (plugin->select_task); | ||
516 | plugin->select_task = GNUNET_SCHEDULER_NO_TASK; | ||
517 | } | ||
518 | if (plugin->udp_sockv4.desc != NULL) | ||
519 | { | ||
520 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->udp_sockv4.desc)); | ||
521 | plugin->udp_sockv4.desc = NULL; | ||
522 | } | ||
523 | if (plugin->udp_sockv6.desc != NULL) | ||
524 | { | ||
525 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->udp_sockv6.desc)); | ||
526 | plugin->udp_sockv6.desc = NULL; | ||
527 | } | ||
528 | if (plugin->behind_nat == GNUNET_YES) | ||
529 | { | ||
530 | if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM)) | ||
531 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
532 | GNUNET_OS_process_wait (plugin->server_proc); | ||
533 | GNUNET_OS_process_close (plugin->server_proc); | ||
534 | plugin->server_proc = NULL; | ||
535 | } | ||
536 | return GNUNET_OK; | ||
537 | } | ||
538 | |||
539 | 402 | ||
540 | struct PeerSession * | 403 | struct PeerSession * |
541 | find_session (struct Plugin *plugin, | 404 | find_session (struct Plugin *plugin, |
@@ -650,7 +513,7 @@ udp_real_send (void *cls, | |||
650 | a4.sin_len = sizeof (a4); | 513 | a4.sin_len = sizeof (a4); |
651 | #endif | 514 | #endif |
652 | a4.sin_family = AF_INET; | 515 | a4.sin_family = AF_INET; |
653 | a4.sin_port = t4->u_port; | 516 | a4.sin_port = t4->u4_port; |
654 | a4.sin_addr.s_addr = t4->ipv4_addr; | 517 | a4.sin_addr.s_addr = t4->ipv4_addr; |
655 | sb = &a4; | 518 | sb = &a4; |
656 | sbs = sizeof (a4); | 519 | sbs = sizeof (a4); |
@@ -689,51 +552,6 @@ udp_real_send (void *cls, | |||
689 | return sent; | 552 | return sent; |
690 | } | 553 | } |
691 | 554 | ||
692 | /** | ||
693 | * We learned about a peer (possibly behind NAT) so run the | ||
694 | * gnunet-nat-client to send dummy ICMP responses | ||
695 | * | ||
696 | * @param plugin the plugin for this transport | ||
697 | * @param addr the address of the peer | ||
698 | * @param addrlen the length of the address | ||
699 | */ | ||
700 | void | ||
701 | run_gnunet_nat_client (struct Plugin *plugin, const char *addr, size_t addrlen) | ||
702 | { | ||
703 | char addr_buf[INET_ADDRSTRLEN]; | ||
704 | char *address_as_string; | ||
705 | char *port_as_string; | ||
706 | struct GNUNET_OS_Process *proc; | ||
707 | const struct IPv4UdpAddress *t4; | ||
708 | |||
709 | GNUNET_assert(addrlen == sizeof(struct IPv4UdpAddress)); | ||
710 | t4 = (struct IPv4UdpAddress *)addr; | ||
711 | |||
712 | if (NULL == inet_ntop (AF_INET, | ||
713 | &t4->ipv4_addr, | ||
714 | addr_buf, INET_ADDRSTRLEN)) | ||
715 | { | ||
716 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); | ||
717 | return; | ||
718 | } | ||
719 | address_as_string = GNUNET_strdup (addr_buf); | ||
720 | GNUNET_asprintf(&port_as_string, "%d", plugin->port); | ||
721 | #if DEBUG_UDP | ||
722 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
723 | _("Running gnunet-nat-client with arguments: %s %s %d\n"), plugin->external_address, address_as_string, plugin->port); | ||
724 | #endif | ||
725 | |||
726 | /* Start the server process */ | ||
727 | proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-nat-client", "gnunet-nat-client", plugin->external_address, address_as_string, port_as_string, NULL); | ||
728 | GNUNET_free(address_as_string); | ||
729 | GNUNET_free(port_as_string); | ||
730 | if (proc != NULL) | ||
731 | { | ||
732 | GNUNET_OS_process_wait (proc); | ||
733 | GNUNET_OS_process_close (proc); | ||
734 | proc = NULL; | ||
735 | } | ||
736 | } | ||
737 | 555 | ||
738 | /** | 556 | /** |
739 | * Function that can be used by the transport service to transmit | 557 | * Function that can be used by the transport service to transmit |
@@ -778,6 +596,7 @@ udp_plugin_send (void *cls, | |||
778 | struct PeerSession *peer_session; | 596 | struct PeerSession *peer_session; |
779 | int other_peer_natd; | 597 | int other_peer_natd; |
780 | const struct IPv4UdpAddress *t4; | 598 | const struct IPv4UdpAddress *t4; |
599 | struct sockaddr_in sin4; | ||
781 | 600 | ||
782 | if (force_address == GNUNET_SYSERR) | 601 | if (force_address == GNUNET_SYSERR) |
783 | return GNUNET_SYSERR; | 602 | return GNUNET_SYSERR; |
@@ -787,7 +606,7 @@ udp_plugin_send (void *cls, | |||
787 | if (addrlen == sizeof(struct IPv4UdpAddress)) | 606 | if (addrlen == sizeof(struct IPv4UdpAddress)) |
788 | { | 607 | { |
789 | t4 = addr; | 608 | t4 = addr; |
790 | if (ntohs(t4->u_port) == 0) | 609 | if (ntohs(t4->u4_port) == 0) |
791 | other_peer_natd = GNUNET_YES; | 610 | other_peer_natd = GNUNET_YES; |
792 | } | 611 | } |
793 | else if (addrlen != sizeof(struct IPv6UdpAddress)) | 612 | else if (addrlen != sizeof(struct IPv6UdpAddress)) |
@@ -797,7 +616,8 @@ udp_plugin_send (void *cls, | |||
797 | } | 616 | } |
798 | 617 | ||
799 | sent = 0; | 618 | sent = 0; |
800 | if ((other_peer_natd == GNUNET_YES) && (plugin->allow_nat == GNUNET_YES)) | 619 | if ( (other_peer_natd == GNUNET_YES) && |
620 | (addrlen == sizeof(struct IPv4UdpAddress)) ) | ||
801 | { | 621 | { |
802 | peer_session = find_session(plugin, target); | 622 | peer_session = find_session(plugin, target); |
803 | if (peer_session == NULL) /* We have a new peer to add */ | 623 | if (peer_session == NULL) /* We have a new peer to add */ |
@@ -830,7 +650,14 @@ udp_plugin_send (void *cls, | |||
830 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 650 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
831 | _("Other peer is NAT'd, set up peer session for peer %s\n"), GNUNET_i2s(target)); | 651 | _("Other peer is NAT'd, set up peer session for peer %s\n"), GNUNET_i2s(target)); |
832 | #endif | 652 | #endif |
833 | run_gnunet_nat_client(plugin, addr, addrlen); | 653 | memset (&sin4, 0, sizeof (sin4)); |
654 | sin4.sin_family = AF_INET; | ||
655 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
656 | sin4.sin_len = sizeof (sin4); | ||
657 | #endif | ||
658 | sin4.sin_port = t4->u4_port; | ||
659 | sin4.sin_addr.s_addr = t4->ipv4_addr; | ||
660 | GNUNET_NAT_run_client (plugin->nat, &sin4); | ||
834 | } | 661 | } |
835 | else | 662 | else |
836 | { | 663 | { |
@@ -881,244 +708,6 @@ udp_plugin_send (void *cls, | |||
881 | } | 708 | } |
882 | 709 | ||
883 | 710 | ||
884 | static void | ||
885 | add_to_address_list (struct Plugin *plugin, | ||
886 | const void *arg, | ||
887 | size_t arg_size) | ||
888 | { | ||
889 | struct LocalAddrList *lal; | ||
890 | |||
891 | lal = plugin->lal_head; | ||
892 | while (NULL != lal) | ||
893 | { | ||
894 | if ( (lal->size == arg_size) && | ||
895 | (0 == memcmp (&lal[1], arg, arg_size)) ) | ||
896 | return; | ||
897 | lal = lal->next; | ||
898 | } | ||
899 | lal = GNUNET_malloc (sizeof (struct LocalAddrList) + arg_size); | ||
900 | lal->size = arg_size; | ||
901 | memcpy (&lal[1], arg, arg_size); | ||
902 | GNUNET_CONTAINER_DLL_insert (plugin->lal_head, | ||
903 | plugin->lal_tail, | ||
904 | lal); | ||
905 | } | ||
906 | |||
907 | |||
908 | static int | ||
909 | check_local_addr (struct Plugin *plugin, | ||
910 | const void *arg, | ||
911 | size_t arg_size) | ||
912 | { | ||
913 | struct LocalAddrList *lal; | ||
914 | |||
915 | lal = plugin->lal_head; | ||
916 | while (NULL != lal) | ||
917 | { | ||
918 | if ( (lal->size == arg_size) && | ||
919 | (0 == memcmp (&lal[1], arg, arg_size)) ) | ||
920 | return GNUNET_OK; | ||
921 | lal = lal->next; | ||
922 | } | ||
923 | return GNUNET_SYSERR; | ||
924 | } | ||
925 | |||
926 | static int check_localaddress (const struct sockaddr *addr, socklen_t addrlen) | ||
927 | { | ||
928 | uint32_t res = 0; | ||
929 | int local = GNUNET_NO; | ||
930 | int af = addr->sa_family; | ||
931 | switch (af) | ||
932 | { | ||
933 | case AF_INET: | ||
934 | { | ||
935 | uint32_t netmask = 0x7F000000; | ||
936 | uint32_t address = ntohl (((struct sockaddr_in *) addr)->sin_addr.s_addr); | ||
937 | res = (address >> 24) ^ (netmask >> 24); | ||
938 | if (res != 0) | ||
939 | local = GNUNET_NO; | ||
940 | else | ||
941 | local = GNUNET_YES; | ||
942 | #if DEBUG_UDP | ||
943 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
944 | "Checking IPv4 address `%s': %s\n", GNUNET_a2s (addr, addrlen), (local==GNUNET_YES) ? "local" : "global"); | ||
945 | #endif | ||
946 | break; | ||
947 | } | ||
948 | case AF_INET6: | ||
949 | { | ||
950 | if (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr) || | ||
951 | IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) | ||
952 | local = GNUNET_YES; | ||
953 | else | ||
954 | local = GNUNET_NO; | ||
955 | #if DEBUG_UDP | ||
956 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
957 | "Checking IPv6 address `%s' : %s\n", GNUNET_a2s (addr, addrlen), (local==GNUNET_YES) ? "local" : "global"); | ||
958 | #endif | ||
959 | break; | ||
960 | } | ||
961 | } | ||
962 | return local; | ||
963 | } | ||
964 | |||
965 | |||
966 | /** | ||
967 | * Add the IP of our network interface to the list of | ||
968 | * our external IP addresses. | ||
969 | */ | ||
970 | static int | ||
971 | process_interfaces (void *cls, | ||
972 | const char *name, | ||
973 | int isDefault, | ||
974 | const struct sockaddr *addr, socklen_t addrlen) | ||
975 | { | ||
976 | struct Plugin *plugin = cls; | ||
977 | int af; | ||
978 | struct IPv4UdpAddress t4; | ||
979 | struct IPv6UdpAddress t6; | ||
980 | void *arg; | ||
981 | uint16_t args; | ||
982 | void *addr_nat; | ||
983 | char buf[INET6_ADDRSTRLEN]; | ||
984 | |||
985 | addr_nat = NULL; | ||
986 | af = addr->sa_family; | ||
987 | |||
988 | if (plugin->use_localaddresses == GNUNET_NO) | ||
989 | { | ||
990 | if (GNUNET_YES == check_localaddress (addr, addrlen)) | ||
991 | { | ||
992 | #if DEBUG_UDP | ||
993 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | ||
994 | "udp", | ||
995 | "Not notifying transport of address `%s' (local address)\n", | ||
996 | GNUNET_a2s (addr, addrlen)); | ||
997 | #endif | ||
998 | return GNUNET_OK; | ||
999 | } | ||
1000 | } | ||
1001 | |||
1002 | memset(buf, 0, INET6_ADDRSTRLEN); | ||
1003 | if (af == AF_INET) | ||
1004 | { | ||
1005 | t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; | ||
1006 | GNUNET_assert(NULL != inet_ntop(AF_INET, &t4.ipv4_addr, &buf[0], INET_ADDRSTRLEN)); | ||
1007 | if ((plugin->bind6_address != NULL) || ((plugin->bind_address != NULL) && (0 != strcmp(buf, plugin->bind_address)))) | ||
1008 | { | ||
1009 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s: Not notifying transport of address %s\n", "UDP", GNUNET_a2s (addr, addrlen)); | ||
1010 | return GNUNET_OK; | ||
1011 | } | ||
1012 | add_to_address_list (plugin, &t4.ipv4_addr, sizeof (uint32_t)); | ||
1013 | if ((plugin->behind_nat == GNUNET_YES) && (plugin->only_nat_addresses == GNUNET_YES)) | ||
1014 | { | ||
1015 | t4.u_port = htons (DEFAULT_NAT_PORT); | ||
1016 | } | ||
1017 | else if (plugin->behind_nat == GNUNET_YES) /* We are behind NAT, but will advertise NAT and normal addresses */ | ||
1018 | { | ||
1019 | addr_nat = GNUNET_malloc(sizeof(t4)); | ||
1020 | t4.u_port = htons (DEFAULT_NAT_PORT); | ||
1021 | memcpy(addr_nat, &t4, sizeof(t4)); | ||
1022 | t4.u_port = plugin->port; | ||
1023 | } | ||
1024 | else | ||
1025 | { | ||
1026 | t4.u_port = htons(plugin->port); | ||
1027 | } | ||
1028 | arg = &t4; | ||
1029 | args = sizeof (t4); | ||
1030 | } | ||
1031 | else if (af == AF_INET6) | ||
1032 | { | ||
1033 | if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) | ||
1034 | { | ||
1035 | /* skip link local addresses */ | ||
1036 | return GNUNET_OK; | ||
1037 | } | ||
1038 | memcpy (&t6.ipv6_addr, | ||
1039 | &((struct sockaddr_in6 *) addr)->sin6_addr, | ||
1040 | sizeof (struct in6_addr)); | ||
1041 | GNUNET_assert(NULL != inet_ntop(AF_INET6, &t6.ipv6_addr, &buf[0], INET6_ADDRSTRLEN)); | ||
1042 | if (((plugin->bind_address != NULL) && (0 != strcmp(buf, plugin->bind_address))) | ||
1043 | || ((plugin->bind6_address != NULL) && (0 != strcmp(buf, plugin->bind6_address)))) | ||
1044 | { | ||
1045 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s: Not notifying transport of address %s\n", "UDP", GNUNET_a2s (addr, addrlen)); | ||
1046 | return GNUNET_OK; | ||
1047 | } | ||
1048 | add_to_address_list (plugin, &t6.ipv6_addr, sizeof (struct in6_addr)); | ||
1049 | if ((plugin->behind_nat == GNUNET_YES) && (plugin->only_nat_addresses == GNUNET_YES)) | ||
1050 | { | ||
1051 | t6.u6_port = htons (DEFAULT_NAT_PORT); | ||
1052 | } | ||
1053 | else if (plugin->behind_nat == GNUNET_YES) | ||
1054 | { | ||
1055 | addr_nat = GNUNET_malloc(sizeof(t6)); | ||
1056 | t6.u6_port = htons (DEFAULT_NAT_PORT); | ||
1057 | memcpy(addr_nat, &t6, sizeof(t6)); | ||
1058 | t6.u6_port = plugin->port; | ||
1059 | } | ||
1060 | else | ||
1061 | { | ||
1062 | t6.u6_port = htons (plugin->port); | ||
1063 | } | ||
1064 | |||
1065 | arg = &t6; | ||
1066 | args = sizeof (t6); | ||
1067 | } | ||
1068 | else | ||
1069 | { | ||
1070 | GNUNET_break (0); | ||
1071 | return GNUNET_OK; | ||
1072 | } | ||
1073 | |||
1074 | GNUNET_log (GNUNET_ERROR_TYPE_INFO | | ||
1075 | GNUNET_ERROR_TYPE_BULK, | ||
1076 | _("Found address `%s' (%s)\n"), | ||
1077 | GNUNET_a2s (addr, addrlen), name); | ||
1078 | |||
1079 | if (addr_nat != NULL) | ||
1080 | { | ||
1081 | plugin->env->notify_address (plugin->env->cls, | ||
1082 | "udp", | ||
1083 | addr_nat, args, GNUNET_TIME_UNIT_FOREVER_REL); | ||
1084 | GNUNET_log (GNUNET_ERROR_TYPE_INFO | | ||
1085 | GNUNET_ERROR_TYPE_BULK, | ||
1086 | _("Found NAT address `%s' (%s)\n"), | ||
1087 | GNUNET_a2s (addr_nat, args), name); | ||
1088 | GNUNET_free(addr_nat); | ||
1089 | } | ||
1090 | |||
1091 | plugin->env->notify_address (plugin->env->cls, | ||
1092 | "udp", | ||
1093 | arg, args, GNUNET_TIME_UNIT_FOREVER_REL); | ||
1094 | return GNUNET_OK; | ||
1095 | } | ||
1096 | |||
1097 | |||
1098 | /** | ||
1099 | * Function called by the resolver for each address obtained from DNS | ||
1100 | * for our own hostname. Add the addresses to the list of our | ||
1101 | * external IP addresses. | ||
1102 | * | ||
1103 | * @param cls closure | ||
1104 | * @param addr one of the addresses of the host, NULL for the last address | ||
1105 | * @param addrlen length of the address | ||
1106 | */ | ||
1107 | static void | ||
1108 | process_hostname_ips (void *cls, | ||
1109 | const struct sockaddr *addr, socklen_t addrlen) | ||
1110 | { | ||
1111 | struct Plugin *plugin = cls; | ||
1112 | |||
1113 | if (addr == NULL) | ||
1114 | { | ||
1115 | plugin->hostname_dns = NULL; | ||
1116 | return; | ||
1117 | } | ||
1118 | process_interfaces (plugin, "<hostname>", GNUNET_YES, addr, addrlen); | ||
1119 | } | ||
1120 | |||
1121 | |||
1122 | /** | 711 | /** |
1123 | * Send UDP probe messages or UDP keepalive messages, depending on the | 712 | * Send UDP probe messages or UDP keepalive messages, depending on the |
1124 | * state of the connection. | 713 | * state of the connection. |
@@ -1127,7 +716,8 @@ process_hostname_ips (void *cls, | |||
1127 | * @param tc task context for running this | 716 | * @param tc task context for running this |
1128 | */ | 717 | */ |
1129 | static void | 718 | static void |
1130 | send_udp_probe_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 719 | send_udp_probe_message (void *cls, |
720 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1131 | { | 721 | { |
1132 | struct UDP_NAT_Probes *probe = cls; | 722 | struct UDP_NAT_Probes *probe = cls; |
1133 | struct UDP_NAT_ProbeMessage message; | 723 | struct UDP_NAT_ProbeMessage message; |
@@ -1137,12 +727,12 @@ send_udp_probe_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc | |||
1137 | message.header.size = htons(sizeof(struct UDP_NAT_ProbeMessage)); | 727 | message.header.size = htons(sizeof(struct UDP_NAT_ProbeMessage)); |
1138 | message.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_NAT_PROBE); | 728 | message.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_NAT_PROBE); |
1139 | /* If they gave us a port, use that. If not, try our port. */ | 729 | /* If they gave us a port, use that. If not, try our port. */ |
1140 | if (ntohs(probe->addr.u_port) == 0) | 730 | if (ntohs(probe->addr.u4_port) == 0) |
1141 | probe->addr.u_port = htons(plugin->port); | 731 | probe->addr.u4_port = htons(plugin->port); |
1142 | 732 | ||
1143 | #if DEBUG_UDP | 733 | #if DEBUG_UDP |
1144 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 734 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1145 | _("Sending a probe to port %d\n"), ntohs(probe->addr.u_port)); | 735 | _("Sending a probe to port %d\n"), ntohs(probe->addr.u4_port)); |
1146 | #endif | 736 | #endif |
1147 | probe->count++; | 737 | probe->count++; |
1148 | udp_real_send(plugin, | 738 | udp_real_send(plugin, |
@@ -1158,10 +748,12 @@ send_udp_probe_message (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc | |||
1158 | /** | 748 | /** |
1159 | * Continuation for probe sends. If the last probe was sent | 749 | * Continuation for probe sends. If the last probe was sent |
1160 | * "successfully", schedule sending of another one. If not, | 750 | * "successfully", schedule sending of another one. If not, |
1161 | * | 751 | * FIXME... |
1162 | */ | 752 | */ |
1163 | void | 753 | static void |
1164 | udp_probe_continuation (void *cls, const struct GNUNET_PeerIdentity *target, int result) | 754 | udp_probe_continuation (void *cls, |
755 | const struct GNUNET_PeerIdentity *target, | ||
756 | int result) | ||
1165 | { | 757 | { |
1166 | struct UDP_NAT_Probes *probe = cls; | 758 | struct UDP_NAT_Probes *probe = cls; |
1167 | /*struct Plugin *plugin = probe->plugin;*/ | 759 | /*struct Plugin *plugin = probe->plugin;*/ |
@@ -1170,137 +762,48 @@ udp_probe_continuation (void *cls, const struct GNUNET_PeerIdentity *target, int | |||
1170 | { | 762 | { |
1171 | #if DEBUG_UDP | 763 | #if DEBUG_UDP |
1172 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 764 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1173 | _("Scheduling next probe for 10000 milliseconds\n")); | 765 | _("Scheduling next probe for 10000 milliseconds\n")); |
1174 | #endif | 766 | #endif |
1175 | probe->task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 10000), &send_udp_probe_message, probe); | 767 | probe->task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10), |
768 | &send_udp_probe_message, probe); | ||
1176 | } | 769 | } |
1177 | else /* Destroy the probe context. */ | 770 | else /* Destroy the probe context. */ |
1178 | { | 771 | { |
1179 | #if DEBUG_UDP | 772 | #if DEBUG_UDP |
1180 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 773 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1181 | _("Sending probe didn't go well...\n")); | 774 | _("Sending probe didn't go well...\n")); |
1182 | #endif | 775 | #endif |
1183 | } | 776 | } |
1184 | } | 777 | } |
1185 | 778 | ||
1186 | /** | ||
1187 | * Find probe message by address | ||
1188 | * | ||
1189 | * @param plugin the plugin for this transport | ||
1190 | * @param address_string the ip address as a string | ||
1191 | */ | ||
1192 | struct UDP_NAT_Probes * | ||
1193 | find_probe(struct Plugin *plugin, char * address_string) | ||
1194 | { | ||
1195 | struct UDP_NAT_Probes *pos; | ||
1196 | 779 | ||
1197 | pos = plugin->probes; | 780 | /** |
1198 | while (pos != NULL) | 781 | * FIXME. |
1199 | if (strcmp(pos->address_string, address_string) == 0) | ||
1200 | return pos; | ||
1201 | |||
1202 | return pos; | ||
1203 | } | ||
1204 | |||
1205 | |||
1206 | /* | ||
1207 | * @param cls the plugin handle | ||
1208 | * @param tc the scheduling context (for rescheduling this function again) | ||
1209 | * | ||
1210 | * We have been notified that gnunet-nat-server has written something to stdout. | ||
1211 | * Handle the output, then reschedule this function to be called again once | ||
1212 | * more is available. | ||
1213 | * | ||
1214 | */ | 782 | */ |
1215 | static void | 783 | static void |
1216 | udp_plugin_server_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 784 | udp_plugin_reversal_callback (void *cls, |
785 | const struct sockaddr *addr, | ||
786 | socklen_t addrlen) | ||
1217 | { | 787 | { |
1218 | struct Plugin *plugin = cls; | 788 | struct Plugin *plugin = cls; |
1219 | char mybuf[40]; | ||
1220 | ssize_t bytes; | ||
1221 | memset(&mybuf, 0, sizeof(mybuf)); | ||
1222 | int i; | ||
1223 | struct UDP_NAT_Probes *temp_probe; | 789 | struct UDP_NAT_Probes *temp_probe; |
1224 | int port; | 790 | const struct sockaddr_in *inaddr; |
1225 | char *port_start; | ||
1226 | struct IPv4UdpAddress a4; | ||
1227 | 791 | ||
1228 | if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | 792 | if (sizeof (struct sockaddr_in) != addrlen) |
1229 | return; | ||
1230 | |||
1231 | bytes = GNUNET_DISK_file_read(plugin->server_stdout_handle, &mybuf, sizeof(mybuf)); | ||
1232 | |||
1233 | if (bytes < 1) | ||
1234 | { | ||
1235 | #if DEBUG_UDP | ||
1236 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1237 | _("Finished reading from server stdout with code: %d\n"), bytes); | ||
1238 | #endif | ||
1239 | return; | ||
1240 | } | ||
1241 | |||
1242 | port_start = NULL; | ||
1243 | for (i = 0; i < sizeof(mybuf); i++) | ||
1244 | { | 793 | { |
1245 | if (mybuf[i] == '\n') | 794 | GNUNET_break (0); |
1246 | mybuf[i] = '\0'; | ||
1247 | |||
1248 | if ((mybuf[i] == ':') && (i + 1 < sizeof(mybuf))) | ||
1249 | { | ||
1250 | mybuf[i] = '\0'; | ||
1251 | port_start = &mybuf[i + 1]; | ||
1252 | } | ||
1253 | } | ||
1254 | |||
1255 | if (port_start != NULL) | ||
1256 | port = atoi(port_start); | ||
1257 | else | ||
1258 | { | ||
1259 | plugin->server_read_task = | ||
1260 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1261 | plugin->server_stdout_handle, &udp_plugin_server_read, plugin); | ||
1262 | return; | ||
1263 | } | ||
1264 | |||
1265 | #if DEBUG_UDP | ||
1266 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1267 | _("nat-server-read read: %s port %d\n"), &mybuf, port); | ||
1268 | #endif | ||
1269 | |||
1270 | /** | ||
1271 | * We have received an ICMP response, ostensibly from a non-NAT'd peer | ||
1272 | * that wants to connect to us! Send a message to establish a connection. | ||
1273 | */ | ||
1274 | if (inet_pton(AF_INET, &mybuf[0], &a4.ipv4_addr) != 1) | ||
1275 | { | ||
1276 | |||
1277 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1278 | _("nat-server-read malformed address\n"), &mybuf, port); | ||
1279 | |||
1280 | plugin->server_read_task = | ||
1281 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1282 | plugin->server_stdout_handle, &udp_plugin_server_read, plugin); | ||
1283 | return; | 795 | return; |
1284 | } | 796 | } |
1285 | 797 | inaddr = (const struct sockaddr_in *) addr; | |
1286 | temp_probe = find_probe(plugin, &mybuf[0]); | 798 | temp_probe = GNUNET_malloc(sizeof(struct UDP_NAT_Probes)); |
1287 | 799 | temp_probe->addr.ipv4_addr = inaddr->sin_addr.s_addr; | |
1288 | if (temp_probe == NULL) | 800 | temp_probe->addr.u4_port = inaddr->sin_port; |
1289 | { | 801 | temp_probe->next = plugin->probes; |
1290 | temp_probe = GNUNET_malloc(sizeof(struct UDP_NAT_Probes)); | 802 | temp_probe->plugin = plugin; |
1291 | temp_probe->address_string = strdup(&mybuf[0]); | 803 | temp_probe->task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500), |
1292 | GNUNET_assert (1 == inet_pton(AF_INET, &mybuf[0], &temp_probe->addr.ipv4_addr)); | 804 | &send_udp_probe_message, |
1293 | temp_probe->addr.u_port = htons(port); | 805 | temp_probe); |
1294 | temp_probe->next = plugin->probes; | 806 | plugin->probes = temp_probe; |
1295 | temp_probe->plugin = plugin; | ||
1296 | temp_probe->task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 500), &send_udp_probe_message, temp_probe); | ||
1297 | plugin->probes = temp_probe; | ||
1298 | } | ||
1299 | |||
1300 | plugin->server_read_task = | ||
1301 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1302 | plugin->server_stdout_handle, &udp_plugin_server_read, plugin); | ||
1303 | |||
1304 | } | 807 | } |
1305 | 808 | ||
1306 | 809 | ||
@@ -1322,9 +825,6 @@ udp_demultiplexer(struct Plugin *plugin, | |||
1322 | size_t fromlen, struct UDP_Sock_Info *sockinfo) | 825 | size_t fromlen, struct UDP_Sock_Info *sockinfo) |
1323 | { | 826 | { |
1324 | struct UDP_NAT_ProbeMessageReply *outgoing_probe_reply; | 827 | struct UDP_NAT_ProbeMessageReply *outgoing_probe_reply; |
1325 | struct UDP_NAT_ProbeMessageConfirmation *outgoing_probe_confirmation; | ||
1326 | char addr_buf[INET_ADDRSTRLEN]; | ||
1327 | struct UDP_NAT_Probes *outgoing_probe; | ||
1328 | struct PeerSession *peer_session; | 828 | struct PeerSession *peer_session; |
1329 | struct MessageQueue *pending_message; | 829 | struct MessageQueue *pending_message; |
1330 | struct MessageQueue *pending_message_temp; | 830 | struct MessageQueue *pending_message_temp; |
@@ -1343,7 +843,7 @@ udp_demultiplexer(struct Plugin *plugin, | |||
1343 | GNUNET_assert(sender_addr != NULL); /* Can recvfrom have a NULL address? */ | 843 | GNUNET_assert(sender_addr != NULL); /* Can recvfrom have a NULL address? */ |
1344 | if (fromlen == sizeof(struct IPv4UdpAddress)) | 844 | if (fromlen == sizeof(struct IPv4UdpAddress)) |
1345 | { | 845 | { |
1346 | incoming_port = ntohs(((struct IPv4UdpAddress *)sender_addr)->u_port); | 846 | incoming_port = ntohs(((struct IPv4UdpAddress *)sender_addr)->u4_port); |
1347 | } | 847 | } |
1348 | else if (fromlen == sizeof(struct IPv6UdpAddress)) | 848 | else if (fromlen == sizeof(struct IPv6UdpAddress)) |
1349 | { | 849 | { |
@@ -1386,14 +886,10 @@ udp_demultiplexer(struct Plugin *plugin, | |||
1386 | #endif | 886 | #endif |
1387 | if (fromlen == sizeof(struct IPv4UdpAddress)) | 887 | if (fromlen == sizeof(struct IPv4UdpAddress)) |
1388 | { | 888 | { |
1389 | memset(&addr_buf, 0, sizeof(addr_buf)); | 889 | /* FIXME! */ |
1390 | if (NULL == inet_ntop (AF_INET, | 890 | #if 0 |
1391 | &((struct IPv4UdpAddress *) sender_addr)->ipv4_addr, addr_buf, | 891 | struct UDP_NAT_ProbeMessageConfirmation *outgoing_probe_confirmation; |
1392 | INET_ADDRSTRLEN)) | 892 | struct UDP_NAT_Probes *outgoing_probe; |
1393 | { | ||
1394 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); | ||
1395 | return; | ||
1396 | } | ||
1397 | outgoing_probe = find_probe(plugin, &addr_buf[0]); | 893 | outgoing_probe = find_probe(plugin, &addr_buf[0]); |
1398 | if (outgoing_probe != NULL) | 894 | if (outgoing_probe != NULL) |
1399 | { | 895 | { |
@@ -1425,6 +921,7 @@ udp_demultiplexer(struct Plugin *plugin, | |||
1425 | _("Received a probe reply, but have no record of a sent probe!\n")); | 921 | _("Received a probe reply, but have no record of a sent probe!\n")); |
1426 | #endif | 922 | #endif |
1427 | } | 923 | } |
924 | #endif | ||
1428 | } | 925 | } |
1429 | else | 926 | else |
1430 | { | 927 | { |
@@ -1466,7 +963,7 @@ udp_demultiplexer(struct Plugin *plugin, | |||
1466 | peer_session->sock = sockinfo->desc; | 963 | peer_session->sock = sockinfo->desc; |
1467 | if (peer_session->connect_alen == sizeof(struct IPv4UdpAddress)) | 964 | if (peer_session->connect_alen == sizeof(struct IPv4UdpAddress)) |
1468 | { | 965 | { |
1469 | ((struct IPv4UdpAddress *)peer_session->connect_addr)->u_port = htons(incoming_port); | 966 | ((struct IPv4UdpAddress *)peer_session->connect_addr)->u4_port = htons(incoming_port); |
1470 | } | 967 | } |
1471 | else if (peer_session->connect_alen == sizeof(struct IPv4UdpAddress)) | 968 | else if (peer_session->connect_alen == sizeof(struct IPv4UdpAddress)) |
1472 | { | 969 | { |
@@ -1550,13 +1047,12 @@ udp_demultiplexer(struct Plugin *plugin, | |||
1550 | 1047 | ||
1551 | 1048 | ||
1552 | /* | 1049 | /* |
1553 | * @param cls the plugin handle | ||
1554 | * @param tc the scheduling context (for rescheduling this function again) | ||
1555 | * | ||
1556 | * We have been notified that our writeset has something to read. We don't | 1050 | * We have been notified that our writeset has something to read. We don't |
1557 | * know which socket needs to be read, so we have to check each one | 1051 | * know which socket needs to be read, so we have to check each one |
1558 | * Then reschedule this function to be called again once more is available. | 1052 | * Then reschedule this function to be called again once more is available. |
1559 | * | 1053 | * |
1054 | * @param cls the plugin handle | ||
1055 | * @param tc the scheduling context (for rescheduling this function again) | ||
1560 | */ | 1056 | */ |
1561 | static void | 1057 | static void |
1562 | udp_plugin_select (void *cls, | 1058 | udp_plugin_select (void *cls, |
@@ -1606,7 +1102,7 @@ udp_plugin_select (void *cls, | |||
1606 | if (AF_INET == ((struct sockaddr *)addr)->sa_family) | 1102 | if (AF_INET == ((struct sockaddr *)addr)->sa_family) |
1607 | { | 1103 | { |
1608 | s4 = (const struct sockaddr_in*) &addr; | 1104 | s4 = (const struct sockaddr_in*) &addr; |
1609 | t4.u_port = s4->sin_port; | 1105 | t4.u4_port = s4->sin_port; |
1610 | t4.ipv4_addr = s4->sin_addr.s_addr; | 1106 | t4.ipv4_addr = s4->sin_addr.s_addr; |
1611 | ca = &t4; | 1107 | ca = &t4; |
1612 | calen = sizeof (t4); | 1108 | calen = sizeof (t4); |
@@ -1676,187 +1172,6 @@ udp_plugin_select (void *cls, | |||
1676 | 1172 | ||
1677 | } | 1173 | } |
1678 | 1174 | ||
1679 | /** | ||
1680 | * Create a slew of UDP sockets. If possible, use IPv6 and IPv4. | ||
1681 | * | ||
1682 | * @param cls closure for server start, should be a struct Plugin * | ||
1683 | * @return number of sockets created or GNUNET_SYSERR on error | ||
1684 | */ | ||
1685 | static int | ||
1686 | udp_transport_server_start (void *cls) | ||
1687 | { | ||
1688 | struct Plugin *plugin = cls; | ||
1689 | struct sockaddr_in serverAddrv4; | ||
1690 | struct sockaddr_in6 serverAddrv6; | ||
1691 | struct sockaddr *serverAddr; | ||
1692 | socklen_t addrlen; | ||
1693 | int sockets_created; | ||
1694 | int tries; | ||
1695 | |||
1696 | |||
1697 | sockets_created = 0; | ||
1698 | if (plugin->behind_nat == GNUNET_YES) | ||
1699 | { | ||
1700 | /* Pipe to read from started processes stdout (on read end) */ | ||
1701 | plugin->server_stdout = GNUNET_DISK_pipe(GNUNET_YES, GNUNET_NO, GNUNET_YES); | ||
1702 | if (plugin->server_stdout == NULL) | ||
1703 | return sockets_created; | ||
1704 | #if DEBUG_UDP | ||
1705 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1706 | "Starting gnunet-nat-server process cmd: %s %s\n", | ||
1707 | "gnunet-nat-server", | ||
1708 | plugin->internal_address); | ||
1709 | #endif | ||
1710 | /* Start the server process */ | ||
1711 | plugin->server_proc = GNUNET_OS_start_process(NULL, | ||
1712 | plugin->server_stdout, | ||
1713 | "gnunet-nat-server", | ||
1714 | "gnunet-nat-server", | ||
1715 | plugin->internal_address, NULL); | ||
1716 | if (plugin->server_proc == NULL) | ||
1717 | { | ||
1718 | #if DEBUG_UDP | ||
1719 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1720 | "Failed to start gnunet-nat-server process\n"); | ||
1721 | #endif | ||
1722 | return GNUNET_SYSERR; | ||
1723 | } | ||
1724 | /* Close the write end of the read pipe */ | ||
1725 | GNUNET_DISK_pipe_close_end(plugin->server_stdout, GNUNET_DISK_PIPE_END_WRITE); | ||
1726 | |||
1727 | plugin->server_stdout_handle = GNUNET_DISK_pipe_handle(plugin->server_stdout, GNUNET_DISK_PIPE_END_READ); | ||
1728 | plugin->server_read_task = | ||
1729 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1730 | plugin->server_stdout_handle, &udp_plugin_server_read, plugin); | ||
1731 | } | ||
1732 | |||
1733 | if ( (GNUNET_YES != | ||
1734 | GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, "nat", | ||
1735 | "DISABLEV6"))) | ||
1736 | { | ||
1737 | plugin->udp_sockv6.desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 0); | ||
1738 | if (NULL == plugin->udp_sockv6.desc) | ||
1739 | { | ||
1740 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "udp", "socket"); | ||
1741 | } | ||
1742 | else | ||
1743 | { | ||
1744 | memset (&serverAddrv6, 0, sizeof (serverAddrv6)); | ||
1745 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1746 | serverAddrv6.sin6_len = sizeof (serverAddrv6); | ||
1747 | #endif | ||
1748 | |||
1749 | serverAddrv6.sin6_family = AF_INET6; | ||
1750 | serverAddrv6.sin6_addr = in6addr_any; | ||
1751 | if (plugin->bind6_address != NULL) | ||
1752 | { | ||
1753 | if (1 != inet_pton(AF_INET6, plugin->bind6_address, &serverAddrv6.sin6_addr)) | ||
1754 | return 0; | ||
1755 | } | ||
1756 | |||
1757 | serverAddrv6.sin6_port = htons (plugin->port); | ||
1758 | addrlen = sizeof (serverAddrv6); | ||
1759 | serverAddr = (struct sockaddr *) &serverAddrv6; | ||
1760 | #if DEBUG_UDP | ||
1761 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1762 | "Binding to IPv6 port %d\n", | ||
1763 | ntohs(serverAddrv6.sin6_port)); | ||
1764 | #endif | ||
1765 | tries = 0; | ||
1766 | while (GNUNET_NETWORK_socket_bind (plugin->udp_sockv6.desc, serverAddr, addrlen) != | ||
1767 | GNUNET_OK) | ||
1768 | { | ||
1769 | serverAddrv6.sin6_port = htons (GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ | ||
1770 | #if DEBUG_UDP | ||
1771 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1772 | "IPv6 Binding failed, trying new port %d\n", | ||
1773 | ntohs(serverAddrv6.sin6_port)); | ||
1774 | #endif | ||
1775 | tries++; | ||
1776 | if (tries > 10) | ||
1777 | { | ||
1778 | GNUNET_NETWORK_socket_close (plugin->udp_sockv6.desc); | ||
1779 | plugin->udp_sockv6.desc = NULL; | ||
1780 | break; | ||
1781 | } | ||
1782 | } | ||
1783 | if (plugin->udp_sockv6.desc != NULL) | ||
1784 | { | ||
1785 | plugin->udp_sockv6.port = ntohs(serverAddrv6.sin6_port); | ||
1786 | sockets_created++; | ||
1787 | } | ||
1788 | } | ||
1789 | } | ||
1790 | |||
1791 | plugin->udp_sockv4.desc = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 0); | ||
1792 | if (NULL == plugin->udp_sockv4.desc) | ||
1793 | { | ||
1794 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "socket"); | ||
1795 | } | ||
1796 | else | ||
1797 | { | ||
1798 | memset (&serverAddrv4, 0, sizeof (serverAddrv4)); | ||
1799 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1800 | serverAddrv4.sin_len = sizeof (serverAddrv4); | ||
1801 | #endif | ||
1802 | serverAddrv4.sin_family = AF_INET; | ||
1803 | serverAddrv4.sin_addr.s_addr = INADDR_ANY; | ||
1804 | if (plugin->bind_address != NULL) | ||
1805 | { | ||
1806 | if (1 != inet_pton(AF_INET, plugin->bind_address, &serverAddrv4.sin_addr)) | ||
1807 | return 0; | ||
1808 | } | ||
1809 | serverAddrv4.sin_port = htons (plugin->port); | ||
1810 | addrlen = sizeof (serverAddrv4); | ||
1811 | serverAddr = (struct sockaddr *) &serverAddrv4; | ||
1812 | #if DEBUG_UDP | ||
1813 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1814 | "Binding to IPv4 port %d\n", | ||
1815 | ntohs(serverAddrv4.sin_port)); | ||
1816 | #endif | ||
1817 | tries = 0; | ||
1818 | while (GNUNET_NETWORK_socket_bind (plugin->udp_sockv4.desc, serverAddr, addrlen) != | ||
1819 | GNUNET_OK) | ||
1820 | { | ||
1821 | serverAddrv4.sin_port = htons (GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ | ||
1822 | #if DEBUG_UDP | ||
1823 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1824 | "IPv4 Binding failed, trying new port %d\n", | ||
1825 | ntohs(serverAddrv4.sin_port)); | ||
1826 | #endif | ||
1827 | tries++; | ||
1828 | if (tries > 10) | ||
1829 | { | ||
1830 | GNUNET_NETWORK_socket_close (plugin->udp_sockv4.desc); | ||
1831 | plugin->udp_sockv4.desc = NULL; | ||
1832 | break; | ||
1833 | } | ||
1834 | } | ||
1835 | if (plugin->udp_sockv4.desc != NULL) | ||
1836 | { | ||
1837 | plugin->udp_sockv4.port = ntohs(serverAddrv4.sin_port); | ||
1838 | sockets_created++; | ||
1839 | } | ||
1840 | } | ||
1841 | |||
1842 | plugin->rs = GNUNET_NETWORK_fdset_create (); | ||
1843 | GNUNET_NETWORK_fdset_zero (plugin->rs); | ||
1844 | if (NULL != plugin->udp_sockv4.desc) | ||
1845 | GNUNET_NETWORK_fdset_set (plugin->rs, | ||
1846 | plugin->udp_sockv4.desc); | ||
1847 | if (NULL != plugin->udp_sockv6.desc) | ||
1848 | GNUNET_NETWORK_fdset_set (plugin->rs, | ||
1849 | plugin->udp_sockv6.desc); | ||
1850 | |||
1851 | plugin->select_task = | ||
1852 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1853 | GNUNET_SCHEDULER_NO_TASK, | ||
1854 | GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs, | ||
1855 | NULL, &udp_plugin_select, plugin); | ||
1856 | return sockets_created; | ||
1857 | } | ||
1858 | |||
1859 | |||
1860 | 1175 | ||
1861 | /** | 1176 | /** |
1862 | * Check if the given port is plausible (must be either | 1177 | * Check if the given port is plausible (must be either |
@@ -1870,11 +1185,8 @@ udp_transport_server_start (void *cls) | |||
1870 | static int | 1185 | static int |
1871 | check_port (struct Plugin *plugin, uint16_t in_port) | 1186 | check_port (struct Plugin *plugin, uint16_t in_port) |
1872 | { | 1187 | { |
1873 | if ( (plugin->behind_nat == GNUNET_YES) && (in_port == 0) ) | 1188 | if (in_port == 0) |
1874 | return GNUNET_OK; | 1189 | return GNUNET_OK; |
1875 | if ( (plugin->only_nat_addresses == GNUNET_YES) && | ||
1876 | (plugin->behind_nat == GNUNET_YES) ) | ||
1877 | return GNUNET_SYSERR; /* odd case... */ | ||
1878 | if (in_port == plugin->port) | 1190 | if (in_port == plugin->port) |
1879 | return GNUNET_OK; | 1191 | return GNUNET_OK; |
1880 | return GNUNET_SYSERR; | 1192 | return GNUNET_SYSERR; |
@@ -1898,16 +1210,11 @@ check_port (struct Plugin *plugin, uint16_t in_port) | |||
1898 | * | 1210 | * |
1899 | */ | 1211 | */ |
1900 | static int | 1212 | static int |
1901 | udp_check_address (void *cls, | 1213 | udp_plugin_check_address (void *cls, |
1902 | const void *addr, | 1214 | const void *addr, |
1903 | size_t addrlen) | 1215 | size_t addrlen) |
1904 | { | 1216 | { |
1905 | struct Plugin *plugin = cls; | 1217 | struct Plugin *plugin = cls; |
1906 | |||
1907 | const void *sb; | ||
1908 | struct in_addr a4; | ||
1909 | struct in6_addr a6; | ||
1910 | int af; | ||
1911 | struct IPv4UdpAddress *v4; | 1218 | struct IPv4UdpAddress *v4; |
1912 | struct IPv6UdpAddress *v6; | 1219 | struct IPv6UdpAddress *v6; |
1913 | 1220 | ||
@@ -1917,20 +1224,16 @@ udp_check_address (void *cls, | |||
1917 | GNUNET_break_op (0); | 1224 | GNUNET_break_op (0); |
1918 | return GNUNET_SYSERR; | 1225 | return GNUNET_SYSERR; |
1919 | } | 1226 | } |
1920 | |||
1921 | if (addrlen == sizeof (struct IPv4UdpAddress)) | 1227 | if (addrlen == sizeof (struct IPv4UdpAddress)) |
1922 | { | 1228 | { |
1923 | v4 = (struct IPv4UdpAddress *) addr; | 1229 | v4 = (struct IPv4UdpAddress *) addr; |
1924 | if (GNUNET_OK != | 1230 | if (GNUNET_OK != |
1925 | check_port (plugin, ntohs (v4->u_port))) | 1231 | check_port (plugin, ntohs (v4->u4_port))) |
1926 | return GNUNET_SYSERR; | 1232 | return GNUNET_SYSERR; |
1927 | if (GNUNET_OK != | 1233 | if (GNUNET_OK != |
1928 | check_local_addr (plugin, &v4->ipv4_addr, sizeof (uint32_t))) | 1234 | GNUNET_NAT_test_address (plugin->nat, |
1235 | &v4->ipv4_addr, sizeof (struct in_addr))) | ||
1929 | return GNUNET_SYSERR; | 1236 | return GNUNET_SYSERR; |
1930 | |||
1931 | af = AF_INET; | ||
1932 | memcpy (&a4, &v4->ipv4_addr, sizeof (a4)); | ||
1933 | sb = &a4; | ||
1934 | } | 1237 | } |
1935 | else | 1238 | else |
1936 | { | 1239 | { |
@@ -1944,14 +1247,10 @@ udp_check_address (void *cls, | |||
1944 | check_port (plugin, ntohs (v6->u6_port))) | 1247 | check_port (plugin, ntohs (v6->u6_port))) |
1945 | return GNUNET_SYSERR; | 1248 | return GNUNET_SYSERR; |
1946 | if (GNUNET_OK != | 1249 | if (GNUNET_OK != |
1947 | check_local_addr (plugin, &v6->ipv6_addr, sizeof (struct in6_addr))) | 1250 | GNUNET_NAT_test_address (plugin->nat, |
1251 | &v6->ipv6_addr, sizeof (struct in6_addr))) | ||
1948 | return GNUNET_SYSERR; | 1252 | return GNUNET_SYSERR; |
1949 | |||
1950 | af = AF_INET6; | ||
1951 | memcpy (&a6, &v6->ipv6_addr, sizeof (a6)); | ||
1952 | sb = &a6; | ||
1953 | } | 1253 | } |
1954 | |||
1955 | return GNUNET_OK; | 1254 | return GNUNET_OK; |
1956 | } | 1255 | } |
1957 | 1256 | ||
@@ -2028,9 +1327,9 @@ udp_plugin_address_pretty_printer (void *cls, | |||
2028 | u4 = addr; | 1327 | u4 = addr; |
2029 | memset (&a4, 0, sizeof (a4)); | 1328 | memset (&a4, 0, sizeof (a4)); |
2030 | a4.sin_family = AF_INET; | 1329 | a4.sin_family = AF_INET; |
2031 | a4.sin_port = u4->u_port; | 1330 | a4.sin_port = u4->u4_port; |
2032 | a4.sin_addr.s_addr = u4->ipv4_addr; | 1331 | a4.sin_addr.s_addr = u4->ipv4_addr; |
2033 | port = ntohs (u4->u_port); | 1332 | port = ntohs (u4->u4_port); |
2034 | sb = &a4; | 1333 | sb = &a4; |
2035 | sbs = sizeof (a4); | 1334 | sbs = sizeof (a4); |
2036 | } | 1335 | } |
@@ -2050,99 +1349,6 @@ udp_plugin_address_pretty_printer (void *cls, | |||
2050 | !numeric, timeout, &append_port, ppc); | 1349 | !numeric, timeout, &append_port, ppc); |
2051 | } | 1350 | } |
2052 | 1351 | ||
2053 | /** | ||
2054 | * Return the actual path to a file found in the current | ||
2055 | * PATH environment variable. | ||
2056 | * | ||
2057 | * @param binary the name of the file to find | ||
2058 | */ | ||
2059 | static char * | ||
2060 | get_path_from_PATH (char *binary) | ||
2061 | { | ||
2062 | char *path; | ||
2063 | char *pos; | ||
2064 | char *end; | ||
2065 | char *buf; | ||
2066 | const char *p; | ||
2067 | |||
2068 | p = getenv ("PATH"); | ||
2069 | if (p == NULL) | ||
2070 | return NULL; | ||
2071 | path = GNUNET_strdup (p); /* because we write on it */ | ||
2072 | buf = GNUNET_malloc (strlen (path) + 20); | ||
2073 | pos = path; | ||
2074 | |||
2075 | while (NULL != (end = strchr (pos, PATH_SEPARATOR))) | ||
2076 | { | ||
2077 | *end = '\0'; | ||
2078 | sprintf (buf, "%s/%s", pos, binary); | ||
2079 | if (GNUNET_DISK_file_test (buf) == GNUNET_YES) | ||
2080 | { | ||
2081 | GNUNET_free (path); | ||
2082 | return buf; | ||
2083 | } | ||
2084 | pos = end + 1; | ||
2085 | } | ||
2086 | sprintf (buf, "%s/%s", pos, binary); | ||
2087 | if (GNUNET_DISK_file_test (buf) == GNUNET_YES) | ||
2088 | { | ||
2089 | GNUNET_free (path); | ||
2090 | return buf; | ||
2091 | } | ||
2092 | GNUNET_free (buf); | ||
2093 | GNUNET_free (path); | ||
2094 | return NULL; | ||
2095 | } | ||
2096 | |||
2097 | /** | ||
2098 | * Check whether the suid bit is set on a file. | ||
2099 | * Attempts to find the file using the current | ||
2100 | * PATH environment variable as a search path. | ||
2101 | * | ||
2102 | * @param binary the name of the file to check | ||
2103 | */ | ||
2104 | static int | ||
2105 | check_gnunet_nat_binary(char *binary) | ||
2106 | { | ||
2107 | struct stat statbuf; | ||
2108 | char *p; | ||
2109 | #ifdef MINGW | ||
2110 | SOCKET rawsock; | ||
2111 | #endif | ||
2112 | |||
2113 | #ifdef MINGW | ||
2114 | char *binaryexe; | ||
2115 | GNUNET_asprintf (&binaryexe, "%s.exe", binary); | ||
2116 | p = get_path_from_PATH (binaryexe); | ||
2117 | free (binaryexe); | ||
2118 | #else | ||
2119 | p = get_path_from_PATH (binary); | ||
2120 | #endif | ||
2121 | if (p == NULL) | ||
2122 | return GNUNET_NO; | ||
2123 | if (0 != STAT (p, &statbuf)) | ||
2124 | { | ||
2125 | GNUNET_free (p); | ||
2126 | return GNUNET_SYSERR; | ||
2127 | } | ||
2128 | GNUNET_free (p); | ||
2129 | #ifndef MINGW | ||
2130 | if ( (0 != (statbuf.st_mode & S_ISUID)) && | ||
2131 | (statbuf.st_uid == 0) ) | ||
2132 | return GNUNET_YES; | ||
2133 | return GNUNET_NO; | ||
2134 | #else | ||
2135 | rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); | ||
2136 | if (INVALID_SOCKET == rawsock) | ||
2137 | { | ||
2138 | DWORD err = GetLastError (); | ||
2139 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) have failed! GLE = %d\n", err); | ||
2140 | return GNUNET_NO; /* not running as administrator */ | ||
2141 | } | ||
2142 | closesocket (rawsock); | ||
2143 | return GNUNET_YES; | ||
2144 | #endif | ||
2145 | } | ||
2146 | 1352 | ||
2147 | /** | 1353 | /** |
2148 | * Function called for a quick conversion of the binary address to | 1354 | * Function called for a quick conversion of the binary address to |
@@ -2182,7 +1388,7 @@ udp_address_to_string (void *cls, | |||
2182 | { | 1388 | { |
2183 | t4 = addr; | 1389 | t4 = addr; |
2184 | af = AF_INET; | 1390 | af = AF_INET; |
2185 | port = ntohs (t4->u_port); | 1391 | port = ntohs (t4->u4_port); |
2186 | memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); | 1392 | memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); |
2187 | sb = &a4; | 1393 | sb = &a4; |
2188 | } | 1394 | } |
@@ -2197,6 +1403,58 @@ udp_address_to_string (void *cls, | |||
2197 | return rbuf; | 1403 | return rbuf; |
2198 | } | 1404 | } |
2199 | 1405 | ||
1406 | |||
1407 | /** | ||
1408 | * Our external IP address/port mapping has changed. | ||
1409 | * | ||
1410 | * @param cls closure, the 'struct LocalAddrList' | ||
1411 | * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean | ||
1412 | * the previous (now invalid) one | ||
1413 | * @param addr either the previous or the new public IP address | ||
1414 | * @param addrlen actual lenght of the address | ||
1415 | */ | ||
1416 | static void | ||
1417 | udp_nat_port_map_callback (void *cls, | ||
1418 | int add_remove, | ||
1419 | const struct sockaddr *addr, | ||
1420 | socklen_t addrlen) | ||
1421 | { | ||
1422 | struct Plugin *plugin = cls; | ||
1423 | struct IPv4UdpAddress u4; | ||
1424 | struct IPv6UdpAddress u6; | ||
1425 | void *arg; | ||
1426 | size_t args; | ||
1427 | |||
1428 | /* convert 'addr' to our internal format */ | ||
1429 | switch (addr->sa_family) | ||
1430 | { | ||
1431 | case AF_INET: | ||
1432 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); | ||
1433 | u4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; | ||
1434 | u4.u4_port = ((struct sockaddr_in *) addr)->sin_port; | ||
1435 | arg = &u4; | ||
1436 | args = sizeof (u4); | ||
1437 | break; | ||
1438 | case AF_INET6: | ||
1439 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); | ||
1440 | memcpy (&u6.ipv6_addr, | ||
1441 | &((struct sockaddr_in6 *) addr)->sin6_addr, | ||
1442 | sizeof (struct in6_addr)); | ||
1443 | u6.u6_port = ((struct sockaddr_in6 *) addr)->sin6_port; | ||
1444 | arg = &u6; | ||
1445 | args = sizeof (u6); | ||
1446 | break; | ||
1447 | default: | ||
1448 | GNUNET_break (0); | ||
1449 | return; | ||
1450 | } | ||
1451 | /* modify our published address list */ | ||
1452 | plugin->env->notify_address (plugin->env->cls, | ||
1453 | add_remove, | ||
1454 | arg, args); | ||
1455 | } | ||
1456 | |||
1457 | |||
2200 | /** | 1458 | /** |
2201 | * The exported method. Makes the core api available via a global and | 1459 | * The exported method. Makes the core api available via a global and |
2202 | * returns the udp transport API. | 1460 | * returns the udp transport API. |
@@ -2210,89 +1468,13 @@ libgnunet_plugin_transport_udp_init (void *cls) | |||
2210 | struct GNUNET_TRANSPORT_PluginFunctions *api; | 1468 | struct GNUNET_TRANSPORT_PluginFunctions *api; |
2211 | struct Plugin *plugin; | 1469 | struct Plugin *plugin; |
2212 | int sockets_created; | 1470 | int sockets_created; |
2213 | int behind_nat; | 1471 | struct sockaddr_in serverAddrv4; |
2214 | int allow_nat; | 1472 | struct sockaddr_in6 serverAddrv6; |
2215 | int only_nat_addresses; | 1473 | struct sockaddr *serverAddr; |
2216 | int use_localaddresses; | 1474 | struct sockaddr *addrs[2]; |
2217 | char *internal_address; | 1475 | socklen_t addrlens[2]; |
2218 | char *external_address; | 1476 | socklen_t addrlen; |
2219 | struct IPv4UdpAddress v4_address; | 1477 | unsigned int tries; |
2220 | |||
2221 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2222 | "nat", | ||
2223 | "BEHIND_NAT")) | ||
2224 | { | ||
2225 | /* We are behind nat (according to the user) */ | ||
2226 | if (check_gnunet_nat_binary("gnunet-nat-server") == GNUNET_YES) | ||
2227 | behind_nat = GNUNET_YES; | ||
2228 | else | ||
2229 | { | ||
2230 | behind_nat = GNUNET_NO; | ||
2231 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Configuration specified you are behind a NAT, but gnunet-nat-server is not installed properly (suid bit not set)!\n"); | ||
2232 | } | ||
2233 | } | ||
2234 | else | ||
2235 | behind_nat = GNUNET_NO; /* We are not behind nat! */ | ||
2236 | |||
2237 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2238 | "nat", | ||
2239 | "ALLOW_NAT")) | ||
2240 | { | ||
2241 | if (check_gnunet_nat_binary("gnunet-nat-client") == GNUNET_YES) | ||
2242 | allow_nat = GNUNET_YES; /* We will try to connect to NAT'd peers */ | ||
2243 | else | ||
2244 | { | ||
2245 | allow_nat = GNUNET_NO; | ||
2246 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Configuration specified you want to connect to NAT'd peers, but gnunet-nat-client is not installed properly (suid bit not set)!\n"); | ||
2247 | } | ||
2248 | |||
2249 | } | ||
2250 | else | ||
2251 | allow_nat = GNUNET_NO; /* We don't want to try to help NAT'd peers */ | ||
2252 | |||
2253 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2254 | "nat", | ||
2255 | "ONLY_NAT_ADDRESSES")) | ||
2256 | only_nat_addresses = GNUNET_YES; /* We will only report our addresses as NAT'd */ | ||
2257 | else | ||
2258 | only_nat_addresses = GNUNET_NO; /* We will report our addresses as NAT'd and non-NAT'd */ | ||
2259 | |||
2260 | external_address = NULL; | ||
2261 | if (((GNUNET_YES == behind_nat) || (GNUNET_YES == allow_nat)) && (GNUNET_OK != | ||
2262 | GNUNET_CONFIGURATION_get_value_string (env->cfg, | ||
2263 | "nat", | ||
2264 | "EXTERNAL_ADDRESS", | ||
2265 | &external_address))) | ||
2266 | { | ||
2267 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2268 | _("Require EXTERNAL_ADDRESS in section `%s' in configuration (either BEHIND_NAT or ALLOW_NAT set to YES)!\n"), | ||
2269 | "nat"); | ||
2270 | return NULL; | ||
2271 | } | ||
2272 | |||
2273 | if ((external_address != NULL) && (inet_pton(AF_INET, external_address, &v4_address.ipv4_addr) != 1)) | ||
2274 | { | ||
2275 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Malformed EXTERNAL_ADDRESS %s given in configuration!\n", external_address); | ||
2276 | } | ||
2277 | |||
2278 | internal_address = NULL; | ||
2279 | if ((GNUNET_YES == behind_nat) && (GNUNET_OK != | ||
2280 | GNUNET_CONFIGURATION_get_value_string (env->cfg, | ||
2281 | "nat", | ||
2282 | "INTERNAL_ADDRESS", | ||
2283 | &internal_address))) | ||
2284 | { | ||
2285 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2286 | _("Require INTERNAL_ADDRESS in section `%s' in configuration!\n"), | ||
2287 | "nat"); | ||
2288 | GNUNET_free_non_null(external_address); | ||
2289 | return NULL; | ||
2290 | } | ||
2291 | |||
2292 | if ((internal_address != NULL) && (inet_pton(AF_INET, internal_address, &v4_address.ipv4_addr) != 1)) | ||
2293 | { | ||
2294 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Malformed INTERNAL_ADDRESS %s given in configuration!\n", internal_address); | ||
2295 | } | ||
2296 | 1478 | ||
2297 | if (GNUNET_OK != | 1479 | if (GNUNET_OK != |
2298 | GNUNET_CONFIGURATION_get_value_number (env->cfg, | 1480 | GNUNET_CONFIGURATION_get_value_number (env->cfg, |
@@ -2300,15 +1482,13 @@ libgnunet_plugin_transport_udp_init (void *cls) | |||
2300 | "PORT", | 1482 | "PORT", |
2301 | &port)) | 1483 | &port)) |
2302 | port = UDP_NAT_DEFAULT_PORT; | 1484 | port = UDP_NAT_DEFAULT_PORT; |
2303 | else if (port > 65535) | 1485 | if (port > 65535) |
2304 | { | 1486 | { |
2305 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 1487 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
2306 | _("Given `%s' option is out of range: %llu > %u\n"), | 1488 | _("Given `%s' option is out of range: %llu > %u\n"), |
2307 | "PORT", | 1489 | "PORT", |
2308 | port, | 1490 | port, |
2309 | 65535); | 1491 | 65535); |
2310 | GNUNET_free_non_null(external_address); | ||
2311 | GNUNET_free_non_null(internal_address); | ||
2312 | return NULL; | 1492 | return NULL; |
2313 | } | 1493 | } |
2314 | 1494 | ||
@@ -2317,26 +1497,9 @@ libgnunet_plugin_transport_udp_init (void *cls) | |||
2317 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1497 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
2318 | _("MTU %llu for `%s' is probably too low!\n"), mtu, | 1498 | _("MTU %llu for `%s' is probably too low!\n"), mtu, |
2319 | "UDP"); | 1499 | "UDP"); |
2320 | |||
2321 | use_localaddresses = GNUNET_NO; | ||
2322 | if (GNUNET_CONFIGURATION_have_value (env->cfg, | ||
2323 | "transport-udp", "USE_LOCALADDR")) | ||
2324 | { | ||
2325 | use_localaddresses = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, | ||
2326 | "transport-udp", | ||
2327 | "USE_LOCALADDR"); | ||
2328 | } | ||
2329 | |||
2330 | plugin = GNUNET_malloc (sizeof (struct Plugin)); | 1500 | plugin = GNUNET_malloc (sizeof (struct Plugin)); |
2331 | plugin->external_address = external_address; | ||
2332 | plugin->internal_address = internal_address; | ||
2333 | plugin->port = port; | 1501 | plugin->port = port; |
2334 | plugin->behind_nat = behind_nat; | ||
2335 | plugin->allow_nat = allow_nat; | ||
2336 | plugin->only_nat_addresses = only_nat_addresses; | ||
2337 | plugin->env = env; | 1502 | plugin->env = env; |
2338 | plugin->use_localaddresses = use_localaddresses; | ||
2339 | |||
2340 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | 1503 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); |
2341 | api->cls = plugin; | 1504 | api->cls = plugin; |
2342 | 1505 | ||
@@ -2344,70 +1507,191 @@ libgnunet_plugin_transport_udp_init (void *cls) | |||
2344 | api->disconnect = &udp_disconnect; | 1507 | api->disconnect = &udp_disconnect; |
2345 | api->address_pretty_printer = &udp_plugin_address_pretty_printer; | 1508 | api->address_pretty_printer = &udp_plugin_address_pretty_printer; |
2346 | api->address_to_string = &udp_address_to_string; | 1509 | api->address_to_string = &udp_address_to_string; |
2347 | api->check_address = &udp_check_address; | 1510 | api->check_address = &udp_plugin_check_address; |
2348 | 1511 | ||
2349 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string(env->cfg, "transport-udp", "BINDTO", &plugin->bind_address)) | 1512 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string(env->cfg, |
2350 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Binding udp plugin to specific address: `%s'\n", plugin->bind_address); | 1513 | "transport-udp", |
2351 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string(env->cfg, "transport-udp", "BINDTO6", &plugin->bind6_address)) | 1514 | "BINDTO", |
2352 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Binding udp plugin to specific address: `%s'\n", plugin->bind6_address); | 1515 | &plugin->bind_address)) |
1516 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, | ||
1517 | "Binding udp plugin to specific address: `%s'\n", | ||
1518 | plugin->bind_address); | ||
1519 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string(env->cfg, | ||
1520 | "transport-udp", | ||
1521 | "BINDTO6", | ||
1522 | &plugin->bind6_address)) | ||
1523 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, | ||
1524 | "Binding udp plugin to specific address: `%s'\n", | ||
1525 | plugin->bind6_address); | ||
2353 | 1526 | ||
2354 | if (plugin->behind_nat == GNUNET_NO) | 1527 | sockets_created = 0; |
1528 | if ( (GNUNET_YES != | ||
1529 | GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, | ||
1530 | "gnunetd", | ||
1531 | "DISABLEV6"))) | ||
2355 | { | 1532 | { |
2356 | GNUNET_OS_network_interfaces_list (&process_interfaces, plugin); | 1533 | plugin->udp_sockv6.desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 0); |
2357 | } | 1534 | if (NULL == plugin->udp_sockv6.desc) |
1535 | { | ||
1536 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "udp", "socket"); | ||
1537 | } | ||
1538 | else | ||
1539 | { | ||
1540 | memset (&serverAddrv6, 0, sizeof (serverAddrv6)); | ||
1541 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1542 | serverAddrv6.sin6_len = sizeof (serverAddrv6); | ||
1543 | #endif | ||
2358 | 1544 | ||
2359 | plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, | 1545 | serverAddrv6.sin6_family = AF_INET6; |
2360 | HOSTNAME_RESOLVE_TIMEOUT, | 1546 | serverAddrv6.sin6_addr = in6addr_any; |
2361 | &process_hostname_ips, | 1547 | if (plugin->bind6_address != NULL) |
2362 | plugin); | 1548 | { |
1549 | if (1 != inet_pton(AF_INET6, plugin->bind6_address, &serverAddrv6.sin6_addr)) | ||
1550 | return 0; | ||
1551 | } | ||
1552 | serverAddrv6.sin6_port = htons (plugin->port); | ||
1553 | addrlen = sizeof (serverAddrv6); | ||
1554 | serverAddr = (struct sockaddr *) &serverAddrv6; | ||
1555 | #if DEBUG_UDP | ||
1556 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1557 | "Binding to IPv6 port %d\n", | ||
1558 | ntohs(serverAddrv6.sin6_port)); | ||
1559 | #endif | ||
1560 | tries = 0; | ||
1561 | while (GNUNET_NETWORK_socket_bind (plugin->udp_sockv6.desc, serverAddr, addrlen) != | ||
1562 | GNUNET_OK) | ||
1563 | { | ||
1564 | serverAddrv6.sin6_port | ||
1565 | = htons (GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ | ||
1566 | #if DEBUG_UDP | ||
1567 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1568 | "IPv6 Binding failed, trying new port %d\n", | ||
1569 | ntohs(serverAddrv6.sin6_port)); | ||
1570 | #endif | ||
1571 | tries++; | ||
1572 | if (tries > 10) | ||
1573 | { | ||
1574 | GNUNET_NETWORK_socket_close (plugin->udp_sockv6.desc); | ||
1575 | plugin->udp_sockv6.desc = NULL; | ||
1576 | break; | ||
1577 | } | ||
1578 | } | ||
1579 | if (plugin->udp_sockv6.desc != NULL) | ||
1580 | { | ||
1581 | plugin->udp_sockv6.port = ntohs(serverAddrv6.sin6_port); | ||
1582 | addrs[sockets_created] = (struct sockaddr*) &serverAddrv6; | ||
1583 | addrlens[sockets_created] = sizeof (serverAddrv6); | ||
1584 | sockets_created++; | ||
1585 | } | ||
1586 | } | ||
1587 | } | ||
2363 | 1588 | ||
2364 | if ((plugin->behind_nat == GNUNET_YES) && (inet_pton(AF_INET, plugin->external_address, &v4_address.ipv4_addr) == 1)) | 1589 | plugin->udp_sockv4.desc = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 0); |
1590 | if (NULL == plugin->udp_sockv4.desc) | ||
2365 | { | 1591 | { |
2366 | v4_address.u_port = htons(0); | 1592 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "socket"); |
2367 | plugin->env->notify_address (plugin->env->cls, | ||
2368 | "udp", | ||
2369 | &v4_address, sizeof(v4_address), GNUNET_TIME_UNIT_FOREVER_REL); | ||
2370 | add_to_address_list (plugin, &v4_address.ipv4_addr, sizeof (uint32_t)); | ||
2371 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Notifying plugin of address %s:0\n", plugin->external_address); | ||
2372 | } | 1593 | } |
2373 | else if ((plugin->external_address != NULL) && (inet_pton(AF_INET, plugin->external_address, &v4_address.ipv4_addr) == 1)) | 1594 | else |
2374 | { | 1595 | { |
2375 | v4_address.u_port = htons(plugin->port); | 1596 | memset (&serverAddrv4, 0, sizeof (serverAddrv4)); |
2376 | plugin->env->notify_address (plugin->env->cls, | 1597 | #if HAVE_SOCKADDR_IN_SIN_LEN |
2377 | "udp", | 1598 | serverAddrv4.sin_len = sizeof (serverAddrv4); |
2378 | &v4_address, sizeof(v4_address), GNUNET_TIME_UNIT_FOREVER_REL); | 1599 | #endif |
2379 | add_to_address_list (plugin, &v4_address.ipv4_addr, sizeof (uint32_t)); | 1600 | serverAddrv4.sin_family = AF_INET; |
1601 | serverAddrv4.sin_addr.s_addr = INADDR_ANY; | ||
1602 | if (plugin->bind_address != NULL) | ||
1603 | { | ||
1604 | if (1 != inet_pton(AF_INET, plugin->bind_address, &serverAddrv4.sin_addr)) | ||
1605 | return 0; | ||
1606 | } | ||
1607 | serverAddrv4.sin_port = htons (plugin->port); | ||
1608 | addrlen = sizeof (serverAddrv4); | ||
1609 | serverAddr = (struct sockaddr *) &serverAddrv4; | ||
1610 | #if DEBUG_UDP | ||
1611 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1612 | "Binding to IPv4 port %d\n", | ||
1613 | ntohs(serverAddrv4.sin_port)); | ||
1614 | #endif | ||
1615 | tries = 0; | ||
1616 | while (GNUNET_NETWORK_socket_bind (plugin->udp_sockv4.desc, serverAddr, addrlen) != | ||
1617 | GNUNET_OK) | ||
1618 | { | ||
1619 | serverAddrv4.sin_port = htons (GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */ | ||
1620 | #if DEBUG_UDP | ||
1621 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1622 | "IPv4 Binding failed, trying new port %d\n", | ||
1623 | ntohs(serverAddrv4.sin_port)); | ||
1624 | #endif | ||
1625 | tries++; | ||
1626 | if (tries > 10) | ||
1627 | { | ||
1628 | GNUNET_NETWORK_socket_close (plugin->udp_sockv4.desc); | ||
1629 | plugin->udp_sockv4.desc = NULL; | ||
1630 | break; | ||
1631 | } | ||
1632 | } | ||
1633 | if (plugin->udp_sockv4.desc != NULL) | ||
1634 | { | ||
1635 | plugin->udp_sockv4.port = ntohs(serverAddrv4.sin_port); | ||
1636 | addrs[sockets_created] = (struct sockaddr*) &serverAddrv4; | ||
1637 | addrlens[sockets_created] = sizeof (serverAddrv4); | ||
1638 | sockets_created++; | ||
1639 | } | ||
2380 | } | 1640 | } |
2381 | 1641 | ||
2382 | sockets_created = udp_transport_server_start (plugin); | 1642 | plugin->rs = GNUNET_NETWORK_fdset_create (); |
1643 | GNUNET_NETWORK_fdset_zero (plugin->rs); | ||
1644 | if (NULL != plugin->udp_sockv4.desc) | ||
1645 | GNUNET_NETWORK_fdset_set (plugin->rs, | ||
1646 | plugin->udp_sockv4.desc); | ||
1647 | if (NULL != plugin->udp_sockv6.desc) | ||
1648 | GNUNET_NETWORK_fdset_set (plugin->rs, | ||
1649 | plugin->udp_sockv6.desc); | ||
1650 | |||
1651 | plugin->select_task = | ||
1652 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1653 | GNUNET_SCHEDULER_NO_TASK, | ||
1654 | GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs, | ||
1655 | NULL, &udp_plugin_select, plugin); | ||
2383 | if (sockets_created == 0) | 1656 | if (sockets_created == 0) |
2384 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 1657 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
2385 | _("Failed to open UDP sockets\n")); | 1658 | _("Failed to open UDP sockets\n")); |
1659 | plugin->nat = GNUNET_NAT_register (env->cfg, | ||
1660 | GNUNET_NO, | ||
1661 | port, | ||
1662 | sockets_created, | ||
1663 | (const struct sockaddr**) addrs, addrlens, | ||
1664 | &udp_nat_port_map_callback, | ||
1665 | &udp_plugin_reversal_callback, | ||
1666 | plugin); | ||
2386 | return api; | 1667 | return api; |
2387 | } | 1668 | } |
2388 | 1669 | ||
1670 | |||
2389 | void * | 1671 | void * |
2390 | libgnunet_plugin_transport_udp_done (void *cls) | 1672 | libgnunet_plugin_transport_udp_done (void *cls) |
2391 | { | 1673 | { |
2392 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; | 1674 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; |
2393 | struct Plugin *plugin = api->cls; | 1675 | struct Plugin *plugin = api->cls; |
2394 | struct LocalAddrList *lal; | ||
2395 | 1676 | ||
2396 | udp_transport_server_stop (plugin); | 1677 | if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK) |
2397 | if (NULL != plugin->hostname_dns) | ||
2398 | { | 1678 | { |
2399 | GNUNET_RESOLVER_request_cancel (plugin->hostname_dns); | 1679 | GNUNET_SCHEDULER_cancel (plugin->select_task); |
2400 | plugin->hostname_dns = NULL; | 1680 | plugin->select_task = GNUNET_SCHEDULER_NO_TASK; |
2401 | } | 1681 | } |
2402 | 1682 | if (plugin->udp_sockv4.desc != NULL) | |
2403 | GNUNET_NETWORK_fdset_destroy (plugin->rs); | 1683 | { |
2404 | while (NULL != (lal = plugin->lal_head)) | 1684 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->udp_sockv4.desc)); |
1685 | plugin->udp_sockv4.desc = NULL; | ||
1686 | } | ||
1687 | if (plugin->udp_sockv6.desc != NULL) | ||
2405 | { | 1688 | { |
2406 | GNUNET_CONTAINER_DLL_remove (plugin->lal_head, | 1689 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->udp_sockv6.desc)); |
2407 | plugin->lal_tail, | 1690 | plugin->udp_sockv6.desc = NULL; |
2408 | lal); | ||
2409 | GNUNET_free (lal); | ||
2410 | } | 1691 | } |
1692 | GNUNET_NETWORK_fdset_destroy (plugin->rs); | ||
1693 | GNUNET_NAT_unregister (plugin->nat); | ||
1694 | plugin->nat = NULL; | ||
2411 | GNUNET_free (plugin); | 1695 | GNUNET_free (plugin); |
2412 | GNUNET_free (api); | 1696 | GNUNET_free (api); |
2413 | return NULL; | 1697 | return NULL; |
diff --git a/src/transport/plugin_transport_unix.c b/src/transport/plugin_transport_unix.c index 835f01611..27187a9d6 100644 --- a/src/transport/plugin_transport_unix.c +++ b/src/transport/plugin_transport_unix.c | |||
@@ -217,29 +217,6 @@ struct RetrySendContext | |||
217 | struct RetryList *retry_list_entry; | 217 | struct RetryList *retry_list_entry; |
218 | }; | 218 | }; |
219 | 219 | ||
220 | /** | ||
221 | * Local network addresses (actual unix path follows). | ||
222 | */ | ||
223 | struct LocalAddrList | ||
224 | { | ||
225 | |||
226 | /** | ||
227 | * This is a doubly linked list. | ||
228 | */ | ||
229 | struct LocalAddrList *next; | ||
230 | |||
231 | /** | ||
232 | * This is a doubly linked list. | ||
233 | */ | ||
234 | struct LocalAddrList *prev; | ||
235 | |||
236 | /** | ||
237 | * Number of bytes of the address that follow | ||
238 | */ | ||
239 | size_t size; | ||
240 | |||
241 | }; | ||
242 | |||
243 | 220 | ||
244 | /** | 221 | /** |
245 | * UNIX NAT "Session" | 222 | * UNIX NAT "Session" |
@@ -340,16 +317,6 @@ struct Plugin | |||
340 | uint16_t port; | 317 | uint16_t port; |
341 | 318 | ||
342 | /** | 319 | /** |
343 | * List of our IP addresses. | ||
344 | */ | ||
345 | struct LocalAddrList *lal_head; | ||
346 | |||
347 | /** | ||
348 | * Tail of our IP address list. | ||
349 | */ | ||
350 | struct LocalAddrList *lal_tail; | ||
351 | |||
352 | /** | ||
353 | * FD Read set | 320 | * FD Read set |
354 | */ | 321 | */ |
355 | struct GNUNET_NETWORK_FDSet *rs; | 322 | struct GNUNET_NETWORK_FDSet *rs; |
@@ -763,30 +730,6 @@ unix_plugin_send (void *cls, | |||
763 | } | 730 | } |
764 | 731 | ||
765 | 732 | ||
766 | static void | ||
767 | add_to_address_list (struct Plugin *plugin, | ||
768 | const void *arg, | ||
769 | size_t arg_size) | ||
770 | { | ||
771 | struct LocalAddrList *lal; | ||
772 | |||
773 | lal = plugin->lal_head; | ||
774 | while (NULL != lal) | ||
775 | { | ||
776 | if ( (lal->size == arg_size) && | ||
777 | (0 == memcmp (&lal[1], arg, arg_size)) ) | ||
778 | return; | ||
779 | lal = lal->next; | ||
780 | } | ||
781 | lal = GNUNET_malloc (sizeof (struct LocalAddrList) + arg_size); | ||
782 | lal->size = arg_size; | ||
783 | memcpy (&lal[1], arg, arg_size); | ||
784 | GNUNET_CONTAINER_DLL_insert (plugin->lal_head, | ||
785 | plugin->lal_tail, | ||
786 | lal); | ||
787 | } | ||
788 | |||
789 | |||
790 | /** | 733 | /** |
791 | * Demultiplexer for UNIX messages | 734 | * Demultiplexer for UNIX messages |
792 | * | 735 | * |
@@ -1197,8 +1140,10 @@ libgnunet_plugin_transport_unix_init (void *cls) | |||
1197 | plugin = GNUNET_malloc (sizeof (struct Plugin)); | 1140 | plugin = GNUNET_malloc (sizeof (struct Plugin)); |
1198 | plugin->port = port; | 1141 | plugin->port = port; |
1199 | plugin->env = env; | 1142 | plugin->env = env; |
1200 | GNUNET_asprintf(&plugin->unix_socket_path, "/tmp/unix-plugin-sock.%d", plugin->port); | 1143 | GNUNET_asprintf (&plugin->unix_socket_path, |
1201 | 1144 | "/tmp/unix-plugin-sock.%d", | |
1145 | plugin->port); | ||
1146 | |||
1202 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); | 1147 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); |
1203 | api->cls = plugin; | 1148 | api->cls = plugin; |
1204 | 1149 | ||
@@ -1207,19 +1152,15 @@ libgnunet_plugin_transport_unix_init (void *cls) | |||
1207 | api->address_pretty_printer = &unix_plugin_address_pretty_printer; | 1152 | api->address_pretty_printer = &unix_plugin_address_pretty_printer; |
1208 | api->address_to_string = &unix_address_to_string; | 1153 | api->address_to_string = &unix_address_to_string; |
1209 | api->check_address = &unix_check_address; | 1154 | api->check_address = &unix_check_address; |
1210 | |||
1211 | add_to_address_list (plugin, plugin->unix_socket_path, strlen(plugin->unix_socket_path) + 1); | ||
1212 | |||
1213 | sockets_created = unix_transport_server_start (plugin); | 1155 | sockets_created = unix_transport_server_start (plugin); |
1214 | if (sockets_created == 0) | 1156 | if (sockets_created == 0) |
1215 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 1157 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
1216 | _("Failed to open UNIX sockets\n")); | 1158 | _("Failed to open UNIX sockets\n")); |
1217 | 1159 | ||
1218 | plugin->env->notify_address(plugin->env->cls, | 1160 | plugin->env->notify_address(plugin->env->cls, |
1219 | "unix", | 1161 | GNUNET_YES, |
1220 | plugin->unix_socket_path, | 1162 | plugin->unix_socket_path, |
1221 | strlen(plugin->unix_socket_path) + 1, | 1163 | strlen(plugin->unix_socket_path) + 1); |
1222 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
1223 | return api; | 1164 | return api; |
1224 | } | 1165 | } |
1225 | 1166 | ||
@@ -1228,18 +1169,10 @@ libgnunet_plugin_transport_unix_done (void *cls) | |||
1228 | { | 1169 | { |
1229 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; | 1170 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; |
1230 | struct Plugin *plugin = api->cls; | 1171 | struct Plugin *plugin = api->cls; |
1231 | struct LocalAddrList *lal; | ||
1232 | 1172 | ||
1233 | unix_transport_server_stop (plugin); | 1173 | unix_transport_server_stop (plugin); |
1234 | 1174 | ||
1235 | GNUNET_NETWORK_fdset_destroy (plugin->rs); | 1175 | GNUNET_NETWORK_fdset_destroy (plugin->rs); |
1236 | while (NULL != (lal = plugin->lal_head)) | ||
1237 | { | ||
1238 | GNUNET_CONTAINER_DLL_remove (plugin->lal_head, | ||
1239 | plugin->lal_tail, | ||
1240 | lal); | ||
1241 | GNUNET_free (lal); | ||
1242 | } | ||
1243 | GNUNET_free (plugin); | 1176 | GNUNET_free (plugin); |
1244 | GNUNET_free (api); | 1177 | GNUNET_free (api); |
1245 | return NULL; | 1178 | return NULL; |
diff --git a/src/transport/test_plugin_transport.c b/src/transport/test_plugin_transport.c index ca69b7601..0c335d6ba 100644 --- a/src/transport/test_plugin_transport.c +++ b/src/transport/test_plugin_transport.c | |||
@@ -37,7 +37,7 @@ | |||
37 | #include "gnunet_transport_plugin.h" | 37 | #include "gnunet_transport_plugin.h" |
38 | #include "transport.h" | 38 | #include "transport.h" |
39 | 39 | ||
40 | #define VERBOSE GNUNET_NO | 40 | #define VERBOSE GNUNET_YES |
41 | 41 | ||
42 | /** | 42 | /** |
43 | * How long until we give up on transmitting the message? | 43 | * How long until we give up on transmitting the message? |
diff --git a/src/transport/test_transport_api.c b/src/transport/test_transport_api.c index f51e96ff2..ac818d557 100644 --- a/src/transport/test_transport_api.c +++ b/src/transport/test_transport_api.c | |||
@@ -37,7 +37,7 @@ | |||
37 | #include "transport.h" | 37 | #include "transport.h" |
38 | #include "transport-testing.h" | 38 | #include "transport-testing.h" |
39 | 39 | ||
40 | #define VERBOSE GNUNET_NO | 40 | #define VERBOSE GNUNET_YES |
41 | 41 | ||
42 | #define VERBOSE_ARM GNUNET_NO | 42 | #define VERBOSE_ARM GNUNET_NO |
43 | 43 | ||
@@ -385,6 +385,7 @@ try_connect (void *cls, | |||
385 | { | 385 | { |
386 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 386 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
387 | "Asking peers to connect...\n"); | 387 | "Asking peers to connect...\n"); |
388 | /* FIXME: 'pX.id' may still be all-zeros here... */ | ||
388 | GNUNET_TRANSPORT_try_connect (p2.th, | 389 | GNUNET_TRANSPORT_try_connect (p2.th, |
389 | &p1.id); | 390 | &p1.id); |
390 | GNUNET_TRANSPORT_try_connect (p1.th, | 391 | GNUNET_TRANSPORT_try_connect (p1.th, |
diff --git a/src/transport/test_transport_api_tcp_peer1.conf b/src/transport/test_transport_api_tcp_peer1.conf index f677f9001..d6b0cc8ab 100644 --- a/src/transport/test_transport_api_tcp_peer1.conf +++ b/src/transport/test_transport_api_tcp_peer1.conf | |||
@@ -1,5 +1,4 @@ | |||
1 | [transport-tcp] | 1 | [transport-tcp] |
2 | USE_LOCALADDR = YES | ||
3 | PORT = 12000 | 2 | PORT = 12000 |
4 | 3 | ||
5 | [nat] | 4 | [nat] |
@@ -32,14 +31,14 @@ MINIMUM-FRIENDS = 0 | |||
32 | 31 | ||
33 | [transport] | 32 | [transport] |
34 | PLUGINS = tcp | 33 | PLUGINS = tcp |
35 | #DEBUG = YES | 34 | DEBUG = YES |
36 | #PREFIX = xterm -T transport2 -e gdb --command=cmd --args | 35 | #PREFIX = xterm -T transport2 -e gdb --command=cmd --args |
37 | #PREFIX = valgrind --tool=memcheck --leak-check=full --log-file=transport%p | 36 | #PREFIX = valgrind --tool=memcheck --leak-check=full --log-file=transport%p.vg |
38 | ACCEPT_FROM6 = ::1; | 37 | ACCEPT_FROM6 = ::1; |
39 | ACCEPT_FROM = 127.0.0.1; | 38 | ACCEPT_FROM = 127.0.0.1; |
40 | NEIGHBOUR_LIMIT = 50 | 39 | NEIGHBOUR_LIMIT = 50 |
41 | BINARY = gnunet-service-transport | 40 | #BINARY = gnunet-service-transport |
42 | #BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/transport/.libs/gnunet-service-transport | 41 | #BINARY = /home/grothoff/bin/gnunet-service-transport |
43 | CONFIG = $DEFAULTCONFIG | 42 | CONFIG = $DEFAULTCONFIG |
44 | HOME = $SERVICEHOME | 43 | HOME = $SERVICEHOME |
45 | HOSTNAME = localhost | 44 | HOSTNAME = localhost |
diff --git a/src/transport/test_transport_api_tcp_peer2.conf b/src/transport/test_transport_api_tcp_peer2.conf index a0074f155..19b8b42d3 100644 --- a/src/transport/test_transport_api_tcp_peer2.conf +++ b/src/transport/test_transport_api_tcp_peer2.conf | |||
@@ -1,6 +1,5 @@ | |||
1 | [transport-tcp] | 1 | [transport-tcp] |
2 | PORT = 0 | 2 | PORT = 0 |
3 | USE_LOCALADDR = YES | ||
4 | 3 | ||
5 | [nat] | 4 | [nat] |
6 | DISABLEV6 = YES | 5 | DISABLEV6 = YES |
@@ -32,18 +31,18 @@ MINIMUM-FRIENDS = 0 | |||
32 | 31 | ||
33 | [transport] | 32 | [transport] |
34 | PLUGINS = tcp | 33 | PLUGINS = tcp |
35 | #DEBUG = YES | 34 | DEBUG = YES |
36 | ACCEPT_FROM6 = ::1; | 35 | ACCEPT_FROM6 = ::1; |
37 | ACCEPT_FROM = 127.0.0.1; | 36 | ACCEPT_FROM = 127.0.0.1; |
38 | NEIGHBOUR_LIMIT = 50 | 37 | NEIGHBOUR_LIMIT = 50 |
39 | #BINARY = /home/mrwiggles/documents/research/gnunet/gnunet-ng/src/transport/.libs/gnunet-service-transport | 38 | #BINARY = /home/grothoff/bin/gnunet-service-transport |
40 | BINARY = gnunet-service-transport | 39 | #BINARY = gnunet-service-transport |
41 | CONFIG = $DEFAULTCONFIG | 40 | CONFIG = $DEFAULTCONFIG |
42 | HOME = $SERVICEHOME | 41 | HOME = $SERVICEHOME |
43 | HOSTNAME = localhost | 42 | HOSTNAME = localhost |
44 | PORT = 12010 | 43 | PORT = 12010 |
45 | UNIXPATH = /tmp/gnunet-p2-service-transport.sock | 44 | UNIXPATH = /tmp/gnunet-p2-service-transport.sock |
46 | #PREFIX = valgrind --tool=callgrind | 45 | #PREFIX = valgrind --tool=memcheck --leak-check=full --log-file=transport%p.vg |
47 | #PREFIX = xterm -T transport2 -e gdb --command=cmd --args | 46 | #PREFIX = xterm -T transport2 -e gdb --command=cmd --args |
48 | #PREFIX = valgrind --leak-check=full | 47 | #PREFIX = valgrind --leak-check=full |
49 | 48 | ||
diff --git a/src/transport/transport.h b/src/transport/transport.h index f05ef3d55..504cbe62b 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h | |||
@@ -36,7 +36,7 @@ | |||
36 | #define ATS_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3) | 36 | #define ATS_MAX_EXEC_DURATION GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3) |
37 | #define ATS_MAX_ITERATIONS INT_MAX | 37 | #define ATS_MAX_ITERATIONS INT_MAX |
38 | 38 | ||
39 | #define DEBUG_TRANSPORT GNUNET_NO | 39 | #define DEBUG_TRANSPORT GNUNET_YES |
40 | 40 | ||
41 | #define DEBUG_TRANSPORT_TIMEOUT GNUNET_NO | 41 | #define DEBUG_TRANSPORT_TIMEOUT GNUNET_NO |
42 | 42 | ||
diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c index 6127badeb..4261f495c 100644 --- a/src/util/resolver_api.c +++ b/src/util/resolver_api.c | |||
@@ -348,9 +348,14 @@ handle_response (void *cls, | |||
348 | #endif | 348 | #endif |
349 | if (msg == NULL) | 349 | if (msg == NULL) |
350 | { | 350 | { |
351 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 351 | if (NULL != rh->name_callback) |
352 | _("Timeout trying to resolve IP address `%s'.\n"), | 352 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
353 | GNUNET_a2s ((const void*) &rh[1], rh->data_len)); | 353 | _("Timeout trying to resolve IP address `%s'.\n"), |
354 | GNUNET_a2s ((const void*) &rh[1], rh->data_len)); | ||
355 | else | ||
356 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
357 | _("Timeout trying to resolve hostname `%s'.\n"), | ||
358 | (const char *) &rh[1]); | ||
354 | if (rh->was_transmitted != GNUNET_SYSERR) | 359 | if (rh->was_transmitted != GNUNET_SYSERR) |
355 | { | 360 | { |
356 | if (NULL != rh->name_callback) | 361 | if (NULL != rh->name_callback) |