diff options
Diffstat (limited to 'src/nat')
29 files changed, 0 insertions, 8379 deletions
diff --git a/src/nat/.gitignore b/src/nat/.gitignore deleted file mode 100644 index 868abab4b..000000000 --- a/src/nat/.gitignore +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | gnunet-service-nat | ||
2 | gnunet-helper-nat-client | ||
3 | gnunet-helper-nat-server | ||
4 | gnunet-nat | ||
5 | gnunet-nat-server | ||
diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am deleted file mode 100644 index 3eea5e2a4..000000000 --- a/src/nat/Makefile.am +++ /dev/null | |||
@@ -1,118 +0,0 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | libexecdir= $(pkglibdir)/libexec/ | ||
5 | |||
6 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
7 | |||
8 | pkgcfg_DATA = \ | ||
9 | nat.conf | ||
10 | |||
11 | if LINUX | ||
12 | NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client | ||
13 | NATSERVER = gnunet-helper-nat-server.c | ||
14 | NATCLIENT = gnunet-helper-nat-client.c | ||
15 | else | ||
16 | if XFREEBSD | ||
17 | NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client | ||
18 | NATSERVER = gnunet-helper-nat-server.c | ||
19 | NATCLIENT = gnunet-helper-nat-client.c | ||
20 | endif | ||
21 | else | ||
22 | install-exec-hook: | ||
23 | endif | ||
24 | |||
25 | bin_PROGRAMS = \ | ||
26 | gnunet-nat | ||
27 | |||
28 | libexec_PROGRAMS = \ | ||
29 | $(NATBIN) \ | ||
30 | gnunet-service-nat | ||
31 | |||
32 | |||
33 | gnunet_helper_nat_server_SOURCES = \ | ||
34 | $(NATSERVER) | ||
35 | |||
36 | gnunet_helper_nat_client_SOURCES = \ | ||
37 | $(NATCLIENT) | ||
38 | |||
39 | |||
40 | gnunet_nat_SOURCES = \ | ||
41 | gnunet-nat.c nat.h | ||
42 | gnunet_nat_LDADD = \ | ||
43 | libgnunetnatnew.la \ | ||
44 | $(top_builddir)/src/util/libgnunetutil.la | ||
45 | gnunet_nat_LDFLAGS = \ | ||
46 | $(GN_LIBINTL) | ||
47 | |||
48 | |||
49 | if USE_COVERAGE | ||
50 | AM_CFLAGS = -fprofile-arcs -ftest-coverage | ||
51 | endif | ||
52 | |||
53 | lib_LTLIBRARIES = \ | ||
54 | libgnunetnatnew.la | ||
55 | |||
56 | libgnunetnatnew_la_SOURCES = \ | ||
57 | nat_api.c \ | ||
58 | nat_api_stun.c nat_stun.h \ | ||
59 | nat.h | ||
60 | libgnunetnatnew_la_LIBADD = \ | ||
61 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
62 | $(GN_LIBINTL) @EXT_LIBS@ | ||
63 | libgnunetnatnew_la_LDFLAGS = \ | ||
64 | $(GN_LIB_LDFLAGS) \ | ||
65 | -version-info 2:0:0 | ||
66 | |||
67 | gnunet_service_nat_SOURCES = \ | ||
68 | gnunet-service-nat.c gnunet-service-nat.h \ | ||
69 | gnunet-service-nat_externalip.c gnunet-service-nat_externalip.h \ | ||
70 | gnunet-service-nat_stun.c gnunet-service-nat_stun.h \ | ||
71 | gnunet-service-nat_mini.c gnunet-service-nat_mini.h \ | ||
72 | gnunet-service-nat_helper.c gnunet-service-nat_helper.h | ||
73 | gnunet_service_nat_LDADD = \ | ||
74 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
75 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
76 | $(LIBGCRYPT_LIBS) \ | ||
77 | -lgcrypt \ | ||
78 | $(GN_LIBINTL) | ||
79 | |||
80 | #check_PROGRAMS = \ | ||
81 | # test_nat \ | ||
82 | # test_nat_mini \ | ||
83 | # test_nat_test \ | ||
84 | # test_stun | ||
85 | |||
86 | if ENABLE_TEST_RUN | ||
87 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | ||
88 | TESTS = $(check_PROGRAMS) | ||
89 | endif | ||
90 | |||
91 | #test_nat_SOURCES = \ | ||
92 | # test_nat.c | ||
93 | #test_nat_LDADD = \ | ||
94 | # libgnunetnat.la \ | ||
95 | # $(top_builddir)/src/util/libgnunetutil.la | ||
96 | |||
97 | #test_nat_mini_SOURCES = \ | ||
98 | # test_nat_mini.c | ||
99 | #test_nat_mini_LDADD = \ | ||
100 | # libgnunetnat.la \ | ||
101 | # $(top_builddir)/src/util/libgnunetutil.la | ||
102 | |||
103 | #test_nat_test_SOURCES = \ | ||
104 | # test_nat_test.c | ||
105 | #test_nat_test_LDADD = \ | ||
106 | # libgnunetnat.la \ | ||
107 | # $(top_builddir)/src/util/libgnunetutil.la | ||
108 | |||
109 | #test_stun_SOURCES = \ | ||
110 | # test_stun.c | ||
111 | #test_stun_LDADD = \ | ||
112 | # libgnunetnat.la \ | ||
113 | # $(top_builddir)/src/util/libgnunetutil.la | ||
114 | |||
115 | EXTRA_DIST = \ | ||
116 | test_nat_data.conf \ | ||
117 | test_nat_test_data.conf \ | ||
118 | test_stun.conf | ||
diff --git a/src/nat/gnunet-helper-nat-client.c b/src/nat/gnunet-helper-nat-client.c deleted file mode 100644 index 0271d6e0f..000000000 --- a/src/nat/gnunet-helper-nat-client.c +++ /dev/null | |||
@@ -1,546 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file src/nat/gnunet-helper-nat-client.c | ||
23 | * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) | ||
24 | * This code will work under GNU/Linux only. | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * This program will send ONE ICMP message using RAW sockets | ||
28 | * to the IP address specified as the second argument. Since | ||
29 | * it uses RAW sockets, it must be installed SUID or run as 'root'. | ||
30 | * In order to keep the security risk of the resulting SUID binary | ||
31 | * minimal, the program ONLY opens the RAW socket with root | ||
32 | * privileges, then drops them and only then starts to process | ||
33 | * command line arguments. The code also does not link against | ||
34 | * any shared libraries (except libc) and is strictly minimal | ||
35 | * (except for checking for errors). The following list of people | ||
36 | * have reviewed this code and considered it safe since the last | ||
37 | * modification (if you reviewed it, please have your name added | ||
38 | * to the list): | ||
39 | * | ||
40 | * - Christian Grothoff | ||
41 | * - Nathan Evans | ||
42 | * - Benjamin Kuperman (22 Aug 2010) | ||
43 | */ | ||
44 | #if HAVE_CONFIG_H | ||
45 | /* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ | ||
46 | #include "gnunet_config.h" | ||
47 | #else | ||
48 | #define _GNU_SOURCE | ||
49 | #endif | ||
50 | #include <sys/types.h> | ||
51 | #include <sys/socket.h> | ||
52 | #include <arpa/inet.h> | ||
53 | #include <sys/types.h> | ||
54 | #include <unistd.h> | ||
55 | #include <stdio.h> | ||
56 | #include <string.h> | ||
57 | #include <errno.h> | ||
58 | #include <stdlib.h> | ||
59 | #include <stdint.h> | ||
60 | #include <netinet/ip.h> | ||
61 | #include <netinet/ip_icmp.h> | ||
62 | #include <netinet/in.h> | ||
63 | |||
64 | /* The following constant is missing from FreeBSD 9.2 */ | ||
65 | #ifndef ICMP_TIME_EXCEEDED | ||
66 | #define ICMP_TIME_EXCEEDED 11 | ||
67 | #endif | ||
68 | |||
69 | /** | ||
70 | * Call memcpy() but check for @a n being 0 first. In the latter | ||
71 | * case, it is now safe to pass NULL for @a src or @a dst. | ||
72 | * Unlike traditional memcpy(), returns nothing. | ||
73 | * | ||
74 | * @param dst destination of the copy, may be NULL if @a n is zero | ||
75 | * @param src source of the copy, may be NULL if @a n is zero | ||
76 | * @param n number of bytes to copy | ||
77 | */ | ||
78 | #define GNUNET_memcpy(dst, src, n) do { if (0 != n) { (void) memcpy (dst, src, \ | ||
79 | n); \ | ||
80 | } } while (0) | ||
81 | |||
82 | /** | ||
83 | * Must match IP given in the server. | ||
84 | */ | ||
85 | #define DUMMY_IP "192.0.2.86" | ||
86 | |||
87 | #define NAT_TRAV_PORT 22225 | ||
88 | |||
89 | /** | ||
90 | * Must match packet ID used by gnunet-helper-nat-server.c | ||
91 | */ | ||
92 | #define PACKET_ID 256 | ||
93 | |||
94 | /** | ||
95 | * IPv4 header. | ||
96 | */ | ||
97 | struct ip_header | ||
98 | { | ||
99 | /** | ||
100 | * Version (4 bits) + Internet header length (4 bits) | ||
101 | */ | ||
102 | uint8_t vers_ihl; | ||
103 | |||
104 | /** | ||
105 | * Type of service | ||
106 | */ | ||
107 | uint8_t tos; | ||
108 | |||
109 | /** | ||
110 | * Total length | ||
111 | */ | ||
112 | uint16_t pkt_len; | ||
113 | |||
114 | /** | ||
115 | * Identification | ||
116 | */ | ||
117 | uint16_t id; | ||
118 | |||
119 | /** | ||
120 | * Flags (3 bits) + Fragment offset (13 bits) | ||
121 | */ | ||
122 | uint16_t flags_frag_offset; | ||
123 | |||
124 | /** | ||
125 | * Time to live | ||
126 | */ | ||
127 | uint8_t ttl; | ||
128 | |||
129 | /** | ||
130 | * Protocol | ||
131 | */ | ||
132 | uint8_t proto; | ||
133 | |||
134 | /** | ||
135 | * Header checksum | ||
136 | */ | ||
137 | uint16_t checksum; | ||
138 | |||
139 | /** | ||
140 | * Source address | ||
141 | */ | ||
142 | uint32_t src_ip; | ||
143 | |||
144 | /** | ||
145 | * Destination address | ||
146 | */ | ||
147 | uint32_t dst_ip; | ||
148 | }; | ||
149 | |||
150 | /** | ||
151 | * Format of ICMP packet. | ||
152 | */ | ||
153 | struct icmp_ttl_exceeded_header | ||
154 | { | ||
155 | uint8_t type; | ||
156 | |||
157 | uint8_t code; | ||
158 | |||
159 | uint16_t checksum; | ||
160 | |||
161 | uint32_t unused; | ||
162 | |||
163 | /* followed by original payload */ | ||
164 | }; | ||
165 | |||
166 | struct icmp_echo_header | ||
167 | { | ||
168 | uint8_t type; | ||
169 | |||
170 | uint8_t code; | ||
171 | |||
172 | uint16_t checksum; | ||
173 | |||
174 | uint32_t reserved; | ||
175 | }; | ||
176 | |||
177 | /** | ||
178 | * Beginning of UDP packet. | ||
179 | */ | ||
180 | struct udp_header | ||
181 | { | ||
182 | uint16_t src_port; | ||
183 | |||
184 | uint16_t dst_port; | ||
185 | |||
186 | uint16_t length; | ||
187 | |||
188 | uint16_t crc; | ||
189 | }; | ||
190 | |||
191 | /** | ||
192 | * Socket we use to send our fake ICMP replies. | ||
193 | */ | ||
194 | static int rawsock; | ||
195 | |||
196 | /** | ||
197 | * Target "dummy" address of the packet we pretend to respond to. | ||
198 | */ | ||
199 | static struct in_addr dummy; | ||
200 | |||
201 | /** | ||
202 | * Our "source" port. | ||
203 | */ | ||
204 | static uint16_t port; | ||
205 | |||
206 | |||
207 | /** | ||
208 | * CRC-16 for IP/ICMP headers. | ||
209 | * | ||
210 | * @param data what to calculate the CRC over | ||
211 | * @param bytes number of bytes in data (must be multiple of 2) | ||
212 | * @return the CRC 16. | ||
213 | */ | ||
214 | static uint16_t | ||
215 | calc_checksum (const uint16_t *data, unsigned int bytes) | ||
216 | { | ||
217 | uint32_t sum; | ||
218 | unsigned int i; | ||
219 | |||
220 | sum = 0; | ||
221 | for (i = 0; i < bytes / 2; i++) | ||
222 | sum += data[i]; | ||
223 | sum = (sum & 0xffff) + (sum >> 16); | ||
224 | sum = htons (0xffff - sum); | ||
225 | return sum; | ||
226 | } | ||
227 | |||
228 | |||
229 | /** | ||
230 | * Send an ICMP message to the target. | ||
231 | * | ||
232 | * @param my_ip source address | ||
233 | * @param other target address | ||
234 | */ | ||
235 | static void | ||
236 | send_icmp_udp (const struct in_addr *my_ip, const struct in_addr *other) | ||
237 | { | ||
238 | char packet[sizeof(struct ip_header) * 2 | ||
239 | + sizeof(struct icmp_ttl_exceeded_header) | ||
240 | + sizeof(struct udp_header)]; | ||
241 | struct ip_header ip_pkt; | ||
242 | struct icmp_ttl_exceeded_header icmp_pkt; | ||
243 | struct udp_header udp_pkt; | ||
244 | struct sockaddr_in dst; | ||
245 | size_t off; | ||
246 | int err; | ||
247 | |||
248 | /* ip header: send to (known) ip address */ | ||
249 | off = 0; | ||
250 | ip_pkt.vers_ihl = 0x45; | ||
251 | ip_pkt.tos = 0; | ||
252 | /* should this be BSD only? */ | ||
253 | #if defined(BSD) && defined(__FreeBSD__) && defined(__FreeBSD_kernel__) | ||
254 | ip_pkt.pkt_len = sizeof(packet); /* Workaround PR kern/21737 */ | ||
255 | #else | ||
256 | ip_pkt.pkt_len = htons (sizeof(packet)); | ||
257 | #endif | ||
258 | ip_pkt.id = htons (PACKET_ID); | ||
259 | ip_pkt.flags_frag_offset = 0; | ||
260 | ip_pkt.ttl = 128; | ||
261 | ip_pkt.proto = IPPROTO_ICMP; | ||
262 | ip_pkt.checksum = 0; | ||
263 | ip_pkt.src_ip = my_ip->s_addr; | ||
264 | ip_pkt.dst_ip = other->s_addr; | ||
265 | ip_pkt.checksum = | ||
266 | htons (calc_checksum ((uint16_t *) &ip_pkt, sizeof(struct ip_header))); | ||
267 | GNUNET_memcpy (&packet[off], | ||
268 | &ip_pkt, | ||
269 | sizeof(struct ip_header)); | ||
270 | off += sizeof(struct ip_header); | ||
271 | |||
272 | icmp_pkt.type = ICMP_TIME_EXCEEDED; | ||
273 | icmp_pkt.code = 0; | ||
274 | icmp_pkt.checksum = 0; | ||
275 | icmp_pkt.unused = 0; | ||
276 | GNUNET_memcpy (&packet[off], | ||
277 | &icmp_pkt, | ||
278 | sizeof(struct icmp_ttl_exceeded_header)); | ||
279 | off += sizeof(struct icmp_ttl_exceeded_header); | ||
280 | |||
281 | /* ip header of the presumably 'lost' udp packet */ | ||
282 | ip_pkt.vers_ihl = 0x45; | ||
283 | ip_pkt.tos = 0; | ||
284 | ip_pkt.pkt_len = | ||
285 | htons (sizeof(struct ip_header) + sizeof(struct udp_header)); | ||
286 | ip_pkt.id = htons (0); | ||
287 | ip_pkt.flags_frag_offset = 0; | ||
288 | ip_pkt.ttl = 128; | ||
289 | ip_pkt.proto = IPPROTO_UDP; | ||
290 | ip_pkt.checksum = 0; | ||
291 | ip_pkt.src_ip = other->s_addr; | ||
292 | ip_pkt.dst_ip = dummy.s_addr; | ||
293 | ip_pkt.checksum = | ||
294 | htons (calc_checksum ((uint16_t *) &ip_pkt, sizeof(struct ip_header))); | ||
295 | GNUNET_memcpy (&packet[off], | ||
296 | &ip_pkt, | ||
297 | sizeof(struct ip_header)); | ||
298 | off += sizeof(struct ip_header); | ||
299 | |||
300 | /* build UDP header */ | ||
301 | udp_pkt.src_port = htons (NAT_TRAV_PORT); | ||
302 | udp_pkt.dst_port = htons (NAT_TRAV_PORT); | ||
303 | udp_pkt.length = htons (port); | ||
304 | udp_pkt.crc = 0; | ||
305 | GNUNET_memcpy (&packet[off], | ||
306 | &udp_pkt, | ||
307 | sizeof(struct udp_header)); | ||
308 | off += sizeof(struct udp_header); | ||
309 | |||
310 | /* set ICMP checksum */ | ||
311 | icmp_pkt.checksum = | ||
312 | htons (calc_checksum | ||
313 | ((uint16_t *) &packet[sizeof(struct ip_header)], | ||
314 | sizeof(struct icmp_ttl_exceeded_header) | ||
315 | + sizeof(struct ip_header) + sizeof(struct udp_header))); | ||
316 | GNUNET_memcpy (&packet[sizeof(struct ip_header)], | ||
317 | &icmp_pkt, | ||
318 | sizeof(struct icmp_ttl_exceeded_header)); | ||
319 | |||
320 | memset (&dst, 0, sizeof(dst)); | ||
321 | dst.sin_family = AF_INET; | ||
322 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
323 | dst.sin_len = sizeof(struct sockaddr_in); | ||
324 | #endif | ||
325 | dst.sin_addr = *other; | ||
326 | err = | ||
327 | sendto (rawsock, packet, sizeof(packet), 0, (struct sockaddr *) &dst, | ||
328 | sizeof(dst)); | ||
329 | if (err < 0) | ||
330 | { | ||
331 | fprintf (stderr, "sendto failed: %s\n", strerror (errno)); | ||
332 | } | ||
333 | else if (sizeof(packet) != (size_t) err) | ||
334 | { | ||
335 | fprintf (stderr, "Error: partial send of ICMP message with size %lu\n", | ||
336 | (unsigned long) off); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | |||
341 | /** | ||
342 | * Send an ICMP message to the target. | ||
343 | * | ||
344 | * @param my_ip source address | ||
345 | * @param other target address | ||
346 | */ | ||
347 | static void | ||
348 | send_icmp (const struct in_addr *my_ip, const struct in_addr *other) | ||
349 | { | ||
350 | struct ip_header ip_pkt; | ||
351 | struct icmp_ttl_exceeded_header icmp_ttl; | ||
352 | struct icmp_echo_header icmp_echo; | ||
353 | struct sockaddr_in dst; | ||
354 | char packet[sizeof(struct ip_header) * 2 | ||
355 | + sizeof(struct icmp_ttl_exceeded_header) | ||
356 | + sizeof(struct icmp_echo_header)]; | ||
357 | size_t off; | ||
358 | int err; | ||
359 | |||
360 | /* ip header: send to (known) ip address */ | ||
361 | off = 0; | ||
362 | ip_pkt.vers_ihl = 0x45; | ||
363 | ip_pkt.tos = 0; | ||
364 | #if defined(BSD) && defined(__FreeBSD__) && defined(__FreeBSD_kernel__) | ||
365 | ip_pkt.pkt_len = sizeof(packet); /* Workaround PR kern/21737 */ | ||
366 | #else | ||
367 | ip_pkt.pkt_len = htons (sizeof(packet)); | ||
368 | #endif | ||
369 | ip_pkt.id = htons (PACKET_ID); | ||
370 | ip_pkt.flags_frag_offset = 0; | ||
371 | ip_pkt.ttl = IPDEFTTL; | ||
372 | ip_pkt.proto = IPPROTO_ICMP; | ||
373 | ip_pkt.checksum = 0; | ||
374 | ip_pkt.src_ip = my_ip->s_addr; | ||
375 | ip_pkt.dst_ip = other->s_addr; | ||
376 | ip_pkt.checksum = | ||
377 | htons (calc_checksum ((uint16_t *) &ip_pkt, sizeof(struct ip_header))); | ||
378 | GNUNET_memcpy (&packet[off], | ||
379 | &ip_pkt, | ||
380 | sizeof(struct ip_header)); | ||
381 | off = sizeof(ip_pkt); | ||
382 | |||
383 | /* icmp reply: time exceeded */ | ||
384 | icmp_ttl.type = ICMP_TIME_EXCEEDED; | ||
385 | icmp_ttl.code = 0; | ||
386 | icmp_ttl.checksum = 0; | ||
387 | icmp_ttl.unused = 0; | ||
388 | GNUNET_memcpy (&packet[off], | ||
389 | &icmp_ttl, | ||
390 | sizeof(struct icmp_ttl_exceeded_header)); | ||
391 | off += sizeof(struct icmp_ttl_exceeded_header); | ||
392 | |||
393 | /* ip header of the presumably 'lost' udp packet */ | ||
394 | ip_pkt.vers_ihl = 0x45; | ||
395 | ip_pkt.tos = 0; | ||
396 | ip_pkt.pkt_len = | ||
397 | htons (sizeof(struct ip_header) + sizeof(struct icmp_echo_header)); | ||
398 | ip_pkt.id = htons (PACKET_ID); | ||
399 | ip_pkt.flags_frag_offset = 0; | ||
400 | ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ | ||
401 | ip_pkt.proto = IPPROTO_ICMP; | ||
402 | ip_pkt.src_ip = other->s_addr; | ||
403 | ip_pkt.dst_ip = dummy.s_addr; | ||
404 | ip_pkt.checksum = 0; | ||
405 | ip_pkt.checksum = | ||
406 | htons (calc_checksum ((uint16_t *) &ip_pkt, sizeof(struct ip_header))); | ||
407 | GNUNET_memcpy (&packet[off], | ||
408 | &ip_pkt, | ||
409 | sizeof(struct ip_header)); | ||
410 | off += sizeof(struct ip_header); | ||
411 | |||
412 | icmp_echo.type = ICMP_ECHO; | ||
413 | icmp_echo.code = 0; | ||
414 | icmp_echo.reserved = htonl (port); | ||
415 | icmp_echo.checksum = 0; | ||
416 | icmp_echo.checksum = | ||
417 | htons (calc_checksum | ||
418 | ((uint16_t *) &icmp_echo, sizeof(struct icmp_echo_header))); | ||
419 | GNUNET_memcpy (&packet[off], | ||
420 | &icmp_echo, | ||
421 | sizeof(struct icmp_echo_header)); | ||
422 | |||
423 | /* no go back to calculate ICMP packet checksum */ | ||
424 | off = sizeof(struct ip_header); | ||
425 | icmp_ttl.checksum = | ||
426 | htons (calc_checksum | ||
427 | ((uint16_t *) &packet[off], | ||
428 | sizeof(struct icmp_ttl_exceeded_header) | ||
429 | + sizeof(struct ip_header) + sizeof(struct icmp_echo_header))); | ||
430 | GNUNET_memcpy (&packet[off], | ||
431 | &icmp_ttl, | ||
432 | sizeof(struct icmp_ttl_exceeded_header)); | ||
433 | |||
434 | /* prepare for transmission */ | ||
435 | memset (&dst, 0, sizeof(dst)); | ||
436 | dst.sin_family = AF_INET; | ||
437 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
438 | dst.sin_len = sizeof(struct sockaddr_in); | ||
439 | #endif | ||
440 | dst.sin_addr = *other; | ||
441 | err = | ||
442 | sendto (rawsock, packet, sizeof(packet), 0, (struct sockaddr *) &dst, | ||
443 | sizeof(dst)); | ||
444 | if (err < 0) | ||
445 | { | ||
446 | fprintf (stderr, "sendto failed: %s\n", strerror (errno)); | ||
447 | } | ||
448 | else if (sizeof(packet) != (size_t) err) | ||
449 | { | ||
450 | fprintf (stderr, "Error: partial send of ICMP message\n"); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | |||
455 | int | ||
456 | main (int argc, char *const *argv) | ||
457 | { | ||
458 | const int one = 1; | ||
459 | struct in_addr external; | ||
460 | struct in_addr target; | ||
461 | uid_t uid; | ||
462 | unsigned int p; | ||
463 | int raw_eno; | ||
464 | int global_ret; | ||
465 | |||
466 | /* Create an ICMP raw socket for writing (only operation that requires root) */ | ||
467 | rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); | ||
468 | raw_eno = errno; /* for later error checking */ | ||
469 | |||
470 | /* now drop root privileges */ | ||
471 | uid = getuid (); | ||
472 | #ifdef HAVE_SETRESUID | ||
473 | if (0 != setresuid (uid, uid, uid)) | ||
474 | { | ||
475 | fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); | ||
476 | global_ret = 1; | ||
477 | goto cleanup; | ||
478 | } | ||
479 | #else | ||
480 | if (0 != (setuid (uid) | seteuid (uid))) | ||
481 | { | ||
482 | fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); | ||
483 | global_ret = 2; | ||
484 | goto cleanup; | ||
485 | } | ||
486 | #endif | ||
487 | if (-1 == rawsock) | ||
488 | { | ||
489 | fprintf (stderr, "Error opening RAW socket: %s\n", strerror (raw_eno)); | ||
490 | global_ret = 3; | ||
491 | goto cleanup; | ||
492 | } | ||
493 | if (0 != | ||
494 | setsockopt (rawsock, SOL_SOCKET, SO_BROADCAST, (char *) &one, | ||
495 | sizeof(one))) | ||
496 | { | ||
497 | fprintf (stderr, "setsockopt failed: %s\n", strerror (errno)); | ||
498 | global_ret = 4; | ||
499 | goto cleanup; | ||
500 | } | ||
501 | if (0 != | ||
502 | setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, (char *) &one, sizeof(one))) | ||
503 | { | ||
504 | fprintf (stderr, "setsockopt failed: %s\n", strerror (errno)); | ||
505 | global_ret = 5; | ||
506 | goto cleanup; | ||
507 | } | ||
508 | |||
509 | if (4 != argc) | ||
510 | { | ||
511 | fprintf (stderr, | ||
512 | "This program must be started with our IP, the targets external IP, and our port as arguments.\n"); | ||
513 | global_ret = 6; | ||
514 | goto cleanup; | ||
515 | } | ||
516 | if ((1 != inet_pton (AF_INET, argv[1], &external)) || | ||
517 | (1 != inet_pton (AF_INET, argv[2], &target))) | ||
518 | { | ||
519 | fprintf (stderr, "Error parsing IPv4 address: %s\n", strerror (errno)); | ||
520 | global_ret = 7; | ||
521 | goto cleanup; | ||
522 | } | ||
523 | if ((1 != sscanf (argv[3], "%u", &p)) || (0 == p) || (0xFFFF < p)) | ||
524 | { | ||
525 | fprintf (stderr, "Error parsing port value `%s'\n", argv[3]); | ||
526 | global_ret = 8; | ||
527 | goto cleanup; | ||
528 | } | ||
529 | port = (uint16_t) p; | ||
530 | if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) | ||
531 | { | ||
532 | fprintf (stderr, "Internal error converting dummy IP to binary.\n"); | ||
533 | global_ret = 9; | ||
534 | goto cleanup; | ||
535 | } | ||
536 | send_icmp (&external, &target); | ||
537 | send_icmp_udp (&external, &target); | ||
538 | global_ret = 0; | ||
539 | cleanup: | ||
540 | if (-1 != rawsock) | ||
541 | (void) close (rawsock); | ||
542 | return global_ret; | ||
543 | } | ||
544 | |||
545 | |||
546 | /* end of gnunet-helper-nat-client.c */ | ||
diff --git a/src/nat/gnunet-helper-nat-server.c b/src/nat/gnunet-helper-nat-server.c deleted file mode 100644 index 38d7d22c8..000000000 --- a/src/nat/gnunet-helper-nat-server.c +++ /dev/null | |||
@@ -1,714 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file src/nat/gnunet-helper-nat-server.c | ||
23 | * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) | ||
24 | * This code will work under GNU/Linux only (or maybe BSDs, but never W32) | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | * This program will send ONE ICMP message every 500 ms RAW sockets | ||
28 | * to a DUMMY IP address and also listens for ICMP replies. Since | ||
29 | * it uses RAW sockets, it must be installed SUID or run as 'root'. | ||
30 | * In order to keep the security risk of the resulting SUID binary | ||
31 | * minimal, the program ONLY opens the two RAW sockets with root | ||
32 | * privileges, then drops them and only then starts to process | ||
33 | * command line arguments. The code also does not link against | ||
34 | * any shared libraries (except libc) and is strictly minimal | ||
35 | * (except for checking for errors). The following list of people | ||
36 | * have reviewed this code and considered it safe since the last | ||
37 | * modification (if you reviewed it, please have your name added | ||
38 | * to the list): | ||
39 | * | ||
40 | * - Christian Grothoff | ||
41 | * - Nathan Evans | ||
42 | * - Benjamin Kuperman (22 Aug 2010) | ||
43 | * - Jacob Appelbaum (19 Dec 2011) | ||
44 | */ | ||
45 | #if HAVE_CONFIG_H | ||
46 | /* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ | ||
47 | #include "gnunet_config.h" | ||
48 | #else | ||
49 | #define _GNU_SOURCE | ||
50 | #endif | ||
51 | #include <sys/types.h> | ||
52 | #include <sys/socket.h> | ||
53 | #include <arpa/inet.h> | ||
54 | #include <sys/select.h> | ||
55 | #include <sys/time.h> | ||
56 | #include <sys/types.h> | ||
57 | #include <unistd.h> | ||
58 | #include <stdio.h> | ||
59 | #include <string.h> | ||
60 | #include <errno.h> | ||
61 | #include <stdlib.h> | ||
62 | #include <stdint.h> | ||
63 | #include <time.h> | ||
64 | #include <netinet/ip.h> | ||
65 | #include <netinet/ip_icmp.h> | ||
66 | #include <netinet/in.h> | ||
67 | |||
68 | /* The following constant is missing from FreeBSD 9.2 */ | ||
69 | #ifndef ICMP_TIME_EXCEEDED | ||
70 | #define ICMP_TIME_EXCEEDED 11 | ||
71 | #endif | ||
72 | |||
73 | /** | ||
74 | * Call memcpy() but check for @a n being 0 first. In the latter | ||
75 | * case, it is now safe to pass NULL for @a src or @a dst. | ||
76 | * Unlike traditional memcpy(), returns nothing. | ||
77 | * | ||
78 | * @param dst destination of the copy, may be NULL if @a n is zero | ||
79 | * @param src source of the copy, may be NULL if @a n is zero | ||
80 | * @param n number of bytes to copy | ||
81 | */ | ||
82 | #define GNUNET_memcpy(dst, src, n) do { if (0 != n) { (void) memcpy (dst, src, \ | ||
83 | n); \ | ||
84 | } } while (0) | ||
85 | |||
86 | /** | ||
87 | * Should we print some debug output? | ||
88 | */ | ||
89 | #define VERBOSE 0 | ||
90 | |||
91 | /** | ||
92 | * Must match packet ID used by gnunet-helper-nat-client.c | ||
93 | */ | ||
94 | #define PACKET_ID 256 | ||
95 | |||
96 | /** | ||
97 | * Must match IP given in the client. | ||
98 | */ | ||
99 | #define DUMMY_IP "192.0.2.86" | ||
100 | |||
101 | /** | ||
102 | * Port for UDP | ||
103 | */ | ||
104 | #define NAT_TRAV_PORT 22225 | ||
105 | |||
106 | /** | ||
107 | * How often do we send our ICMP messages to receive replies? | ||
108 | */ | ||
109 | #define ICMP_SEND_FREQUENCY_MS 500 | ||
110 | |||
111 | /** | ||
112 | * IPv4 header. | ||
113 | */ | ||
114 | struct ip_header | ||
115 | { | ||
116 | /** | ||
117 | * Version (4 bits) + Internet header length (4 bits) | ||
118 | */ | ||
119 | uint8_t vers_ihl; | ||
120 | |||
121 | /** | ||
122 | * Type of service | ||
123 | */ | ||
124 | uint8_t tos; | ||
125 | |||
126 | /** | ||
127 | * Total length | ||
128 | */ | ||
129 | uint16_t pkt_len; | ||
130 | |||
131 | /** | ||
132 | * Identification | ||
133 | */ | ||
134 | uint16_t id; | ||
135 | |||
136 | /** | ||
137 | * Flags (3 bits) + Fragment offset (13 bits) | ||
138 | */ | ||
139 | uint16_t flags_frag_offset; | ||
140 | |||
141 | /** | ||
142 | * Time to live | ||
143 | */ | ||
144 | uint8_t ttl; | ||
145 | |||
146 | /** | ||
147 | * Protocol | ||
148 | */ | ||
149 | uint8_t proto; | ||
150 | |||
151 | /** | ||
152 | * Header checksum | ||
153 | */ | ||
154 | uint16_t checksum; | ||
155 | |||
156 | /** | ||
157 | * Source address | ||
158 | */ | ||
159 | uint32_t src_ip; | ||
160 | |||
161 | /** | ||
162 | * Destination address | ||
163 | */ | ||
164 | uint32_t dst_ip; | ||
165 | }; | ||
166 | |||
167 | /** | ||
168 | * Format of ICMP packet. | ||
169 | */ | ||
170 | struct icmp_ttl_exceeded_header | ||
171 | { | ||
172 | uint8_t type; | ||
173 | |||
174 | uint8_t code; | ||
175 | |||
176 | uint16_t checksum; | ||
177 | |||
178 | uint32_t unused; | ||
179 | |||
180 | /* followed by original payload */ | ||
181 | }; | ||
182 | |||
183 | struct icmp_echo_header | ||
184 | { | ||
185 | uint8_t type; | ||
186 | |||
187 | uint8_t code; | ||
188 | |||
189 | uint16_t checksum; | ||
190 | |||
191 | uint32_t reserved; | ||
192 | }; | ||
193 | |||
194 | |||
195 | /** | ||
196 | * Beginning of UDP packet. | ||
197 | */ | ||
198 | struct udp_header | ||
199 | { | ||
200 | uint16_t src_port; | ||
201 | |||
202 | uint16_t dst_port; | ||
203 | |||
204 | uint16_t length; | ||
205 | |||
206 | uint16_t crc; | ||
207 | }; | ||
208 | |||
209 | /** | ||
210 | * Socket we use to receive "fake" ICMP replies. | ||
211 | */ | ||
212 | static int icmpsock; | ||
213 | |||
214 | /** | ||
215 | * Socket we use to send our ICMP requests. | ||
216 | */ | ||
217 | static int rawsock; | ||
218 | |||
219 | /** | ||
220 | * Socket we use to send our UDP requests. | ||
221 | */ | ||
222 | static int udpsock; | ||
223 | |||
224 | /** | ||
225 | * Target "dummy" address. | ||
226 | */ | ||
227 | static struct in_addr dummy; | ||
228 | |||
229 | |||
230 | /** | ||
231 | * CRC-16 for IP/ICMP headers. | ||
232 | * | ||
233 | * @param data what to calculate the CRC over | ||
234 | * @param bytes number of bytes in data (must be multiple of 2) | ||
235 | * @return the CRC 16. | ||
236 | */ | ||
237 | static uint16_t | ||
238 | calc_checksum (const uint16_t *data, unsigned int bytes) | ||
239 | { | ||
240 | uint32_t sum; | ||
241 | unsigned int i; | ||
242 | |||
243 | sum = 0; | ||
244 | for (i = 0; i < bytes / 2; i++) | ||
245 | sum += data[i]; | ||
246 | sum = (sum & 0xffff) + (sum >> 16); | ||
247 | sum = htons (0xffff - sum); | ||
248 | return sum; | ||
249 | } | ||
250 | |||
251 | |||
252 | /** | ||
253 | * Send an ICMP message to the dummy IP. | ||
254 | * | ||
255 | * @param my_ip source address (our ip address) | ||
256 | */ | ||
257 | static void | ||
258 | send_icmp_echo (const struct in_addr *my_ip) | ||
259 | { | ||
260 | char packet[sizeof(struct ip_header) + sizeof(struct icmp_echo_header)]; | ||
261 | struct icmp_echo_header icmp_echo; | ||
262 | struct ip_header ip_pkt; | ||
263 | struct sockaddr_in dst; | ||
264 | size_t off; | ||
265 | int err; | ||
266 | |||
267 | off = 0; | ||
268 | ip_pkt.vers_ihl = 0x45; | ||
269 | ip_pkt.tos = 0; | ||
270 | ip_pkt.pkt_len = htons (sizeof(packet)); | ||
271 | ip_pkt.id = htons (PACKET_ID); | ||
272 | ip_pkt.flags_frag_offset = 0; | ||
273 | ip_pkt.ttl = IPDEFTTL; | ||
274 | ip_pkt.proto = IPPROTO_ICMP; | ||
275 | ip_pkt.checksum = 0; | ||
276 | ip_pkt.src_ip = my_ip->s_addr; | ||
277 | ip_pkt.dst_ip = dummy.s_addr; | ||
278 | ip_pkt.checksum = | ||
279 | htons (calc_checksum ((uint16_t *) &ip_pkt, | ||
280 | sizeof(struct ip_header))); | ||
281 | GNUNET_memcpy (&packet[off], | ||
282 | &ip_pkt, | ||
283 | sizeof(struct ip_header)); | ||
284 | off += sizeof(struct ip_header); | ||
285 | |||
286 | icmp_echo.type = ICMP_ECHO; | ||
287 | icmp_echo.code = 0; | ||
288 | icmp_echo.checksum = 0; | ||
289 | icmp_echo.reserved = 0; | ||
290 | icmp_echo.checksum = | ||
291 | htons (calc_checksum | ||
292 | ((uint16_t *) &icmp_echo, | ||
293 | sizeof(struct icmp_echo_header))); | ||
294 | GNUNET_memcpy (&packet[off], | ||
295 | &icmp_echo, | ||
296 | sizeof(struct icmp_echo_header)); | ||
297 | off += sizeof(struct icmp_echo_header); | ||
298 | |||
299 | memset (&dst, 0, sizeof(dst)); | ||
300 | dst.sin_family = AF_INET; | ||
301 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
302 | dst.sin_len = sizeof(struct sockaddr_in); | ||
303 | #endif | ||
304 | dst.sin_addr = dummy; | ||
305 | err = sendto (rawsock, | ||
306 | packet, | ||
307 | off, | ||
308 | 0, | ||
309 | (struct sockaddr *) &dst, | ||
310 | sizeof(dst)); | ||
311 | if (err < 0) | ||
312 | { | ||
313 | #if VERBOSE | ||
314 | fprintf (stderr, | ||
315 | "sendto failed: %s\n", | ||
316 | strerror (errno)); | ||
317 | #endif | ||
318 | } | ||
319 | else if (sizeof(packet) != err) | ||
320 | { | ||
321 | fprintf (stderr, | ||
322 | "Error: partial send of ICMP message\n"); | ||
323 | } | ||
324 | } | ||
325 | |||
326 | |||
327 | /** | ||
328 | * Send a UDP message to the dummy IP. | ||
329 | */ | ||
330 | static void | ||
331 | send_udp () | ||
332 | { | ||
333 | struct sockaddr_in dst; | ||
334 | ssize_t err; | ||
335 | |||
336 | memset (&dst, 0, sizeof(dst)); | ||
337 | dst.sin_family = AF_INET; | ||
338 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
339 | dst.sin_len = sizeof(struct sockaddr_in); | ||
340 | #endif | ||
341 | dst.sin_addr = dummy; | ||
342 | dst.sin_port = htons (NAT_TRAV_PORT); | ||
343 | err = sendto (udpsock, | ||
344 | NULL, | ||
345 | 0, | ||
346 | 0, | ||
347 | (struct sockaddr *) &dst, | ||
348 | sizeof(dst)); | ||
349 | if (err < 0) | ||
350 | { | ||
351 | #if VERBOSE | ||
352 | fprintf (stderr, | ||
353 | "sendto failed: %s\n", | ||
354 | strerror (errno)); | ||
355 | #endif | ||
356 | } | ||
357 | else if (0 != err) | ||
358 | { | ||
359 | fprintf (stderr, | ||
360 | "Error: partial send of ICMP message\n"); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | |||
365 | /** | ||
366 | * We've received an ICMP response. Process it. | ||
367 | */ | ||
368 | static void | ||
369 | process_icmp_response () | ||
370 | { | ||
371 | char buf[65536]; | ||
372 | ssize_t have; | ||
373 | struct in_addr source_ip; | ||
374 | struct ip_header ip_pkt; | ||
375 | struct icmp_ttl_exceeded_header icmp_ttl; | ||
376 | struct icmp_echo_header icmp_echo; | ||
377 | struct udp_header udp_pkt; | ||
378 | size_t off; | ||
379 | uint16_t port; | ||
380 | |||
381 | have = read (icmpsock, buf, sizeof(buf)); | ||
382 | if (-1 == have) | ||
383 | { | ||
384 | fprintf (stderr, | ||
385 | "Error reading raw socket: %s\n", | ||
386 | strerror (errno)); | ||
387 | return; | ||
388 | } | ||
389 | #if VERBOSE | ||
390 | fprintf (stderr, | ||
391 | "Received message of %u bytes\n", | ||
392 | (unsigned int) have); | ||
393 | #endif | ||
394 | if (have < | ||
395 | (ssize_t) (sizeof(struct ip_header) | ||
396 | + sizeof(struct icmp_ttl_exceeded_header) | ||
397 | + sizeof(struct ip_header))) | ||
398 | { | ||
399 | /* malformed */ | ||
400 | return; | ||
401 | } | ||
402 | off = 0; | ||
403 | GNUNET_memcpy (&ip_pkt, | ||
404 | &buf[off], | ||
405 | sizeof(struct ip_header)); | ||
406 | off += sizeof(struct ip_header); | ||
407 | GNUNET_memcpy (&icmp_ttl, | ||
408 | &buf[off], | ||
409 | sizeof(struct icmp_ttl_exceeded_header)); | ||
410 | off += sizeof(struct icmp_ttl_exceeded_header); | ||
411 | if ((ICMP_TIME_EXCEEDED != icmp_ttl.type) || (0 != icmp_ttl.code)) | ||
412 | { | ||
413 | /* different type than what we want */ | ||
414 | return; | ||
415 | } | ||
416 | /* grab source IP of 1st IP header */ | ||
417 | source_ip.s_addr = ip_pkt.src_ip; | ||
418 | |||
419 | /* skip 2nd IP header */ | ||
420 | GNUNET_memcpy (&ip_pkt, | ||
421 | &buf[off], | ||
422 | sizeof(struct ip_header)); | ||
423 | off += sizeof(struct ip_header); | ||
424 | |||
425 | switch (ip_pkt.proto) | ||
426 | { | ||
427 | case IPPROTO_ICMP: | ||
428 | if (have != | ||
429 | (sizeof(struct ip_header) * 2 | ||
430 | + sizeof(struct icmp_ttl_exceeded_header) | ||
431 | + sizeof(struct icmp_echo_header))) | ||
432 | { | ||
433 | /* malformed */ | ||
434 | return; | ||
435 | } | ||
436 | /* grab ICMP ECHO content */ | ||
437 | GNUNET_memcpy (&icmp_echo, | ||
438 | &buf[off], | ||
439 | sizeof(struct icmp_echo_header)); | ||
440 | port = (uint16_t) ntohl (icmp_echo.reserved); | ||
441 | break; | ||
442 | |||
443 | case IPPROTO_UDP: | ||
444 | if (have != | ||
445 | (sizeof(struct ip_header) * 2 | ||
446 | + sizeof(struct icmp_ttl_exceeded_header) + sizeof(struct udp_header))) | ||
447 | { | ||
448 | /* malformed */ | ||
449 | return; | ||
450 | } | ||
451 | /* grab UDP content */ | ||
452 | GNUNET_memcpy (&udp_pkt, | ||
453 | &buf[off], | ||
454 | sizeof(struct udp_header)); | ||
455 | port = ntohs (udp_pkt.length); | ||
456 | break; | ||
457 | |||
458 | default: | ||
459 | /* different type than what we want */ | ||
460 | return; | ||
461 | } | ||
462 | |||
463 | if (port == 0) | ||
464 | fprintf (stdout, "%s\n", | ||
465 | inet_ntop (AF_INET, &source_ip, buf, sizeof(buf))); | ||
466 | else | ||
467 | fprintf (stdout, "%s:%u\n", | ||
468 | inet_ntop (AF_INET, &source_ip, buf, sizeof(buf)), | ||
469 | (unsigned int) port); | ||
470 | fflush (stdout); | ||
471 | } | ||
472 | |||
473 | |||
474 | /** | ||
475 | * Fully initialize the raw socket. | ||
476 | * | ||
477 | * @return -1 on error, 0 on success | ||
478 | */ | ||
479 | static int | ||
480 | setup_raw_socket () | ||
481 | { | ||
482 | const int one = 1; | ||
483 | |||
484 | if (-1 == | ||
485 | setsockopt (rawsock, | ||
486 | SOL_SOCKET, | ||
487 | SO_BROADCAST, | ||
488 | (char *) &one, | ||
489 | sizeof(one))) | ||
490 | { | ||
491 | fprintf (stderr, | ||
492 | "setsockopt failed: %s\n", | ||
493 | strerror (errno)); | ||
494 | return -1; | ||
495 | } | ||
496 | if (-1 == | ||
497 | setsockopt (rawsock, | ||
498 | IPPROTO_IP, | ||
499 | IP_HDRINCL, | ||
500 | (char *) &one, | ||
501 | sizeof(one))) | ||
502 | { | ||
503 | fprintf (stderr, | ||
504 | "setsockopt failed: %s\n", | ||
505 | strerror (errno)); | ||
506 | return -1; | ||
507 | } | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | |||
512 | /** | ||
513 | * Create a UDP socket for writing. | ||
514 | * | ||
515 | * @param my_ip source address (our ip address) | ||
516 | * @return -1 on error | ||
517 | */ | ||
518 | static int | ||
519 | make_udp_socket (const struct in_addr *my_ip) | ||
520 | { | ||
521 | int ret; | ||
522 | struct sockaddr_in addr; | ||
523 | |||
524 | ret = socket (AF_INET, SOCK_DGRAM, 0); | ||
525 | if (-1 == ret) | ||
526 | { | ||
527 | fprintf (stderr, | ||
528 | "Error opening UDP socket: %s\n", | ||
529 | strerror (errno)); | ||
530 | return -1; | ||
531 | } | ||
532 | memset (&addr, 0, sizeof(addr)); | ||
533 | addr.sin_family = AF_INET; | ||
534 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
535 | addr.sin_len = sizeof(struct sockaddr_in); | ||
536 | #endif | ||
537 | addr.sin_addr = *my_ip; | ||
538 | addr.sin_port = htons (NAT_TRAV_PORT); | ||
539 | |||
540 | if (0 != bind (ret, | ||
541 | (struct sockaddr *) &addr, | ||
542 | sizeof(addr))) | ||
543 | { | ||
544 | fprintf (stderr, | ||
545 | "Error binding UDP socket to port %u: %s\n", | ||
546 | NAT_TRAV_PORT, | ||
547 | strerror (errno)); | ||
548 | (void) close (ret); | ||
549 | return -1; | ||
550 | } | ||
551 | return ret; | ||
552 | } | ||
553 | |||
554 | |||
555 | int | ||
556 | main (int argc, | ||
557 | char *const *argv) | ||
558 | { | ||
559 | struct in_addr external; | ||
560 | fd_set rs; | ||
561 | struct timeval tv; | ||
562 | uid_t uid; | ||
563 | unsigned int alt; | ||
564 | int icmp_eno; | ||
565 | int raw_eno; | ||
566 | int global_ret; | ||
567 | |||
568 | /* Create an ICMP raw socket for reading (we'll check errors later) */ | ||
569 | icmpsock = socket (AF_INET, | ||
570 | SOCK_RAW, | ||
571 | IPPROTO_ICMP); | ||
572 | icmp_eno = errno; | ||
573 | |||
574 | /* Create an (ICMP) raw socket for writing (we'll check errors later) */ | ||
575 | rawsock = socket (AF_INET, | ||
576 | SOCK_RAW, | ||
577 | IPPROTO_RAW); | ||
578 | raw_eno = errno; | ||
579 | udpsock = -1; | ||
580 | |||
581 | /* drop root rights */ | ||
582 | uid = getuid (); | ||
583 | #ifdef HAVE_SETRESUID | ||
584 | if (0 != setresuid (uid, uid, uid)) | ||
585 | { | ||
586 | fprintf (stderr, | ||
587 | "Failed to setresuid: %s\n", | ||
588 | strerror (errno)); | ||
589 | global_ret = 1; | ||
590 | goto error_exit; | ||
591 | } | ||
592 | #else | ||
593 | if (0 != (setuid (uid) | seteuid (uid))) | ||
594 | { | ||
595 | fprintf (stderr, | ||
596 | "Failed to setuid: %s\n", | ||
597 | strerror (errno)); | ||
598 | global_ret = 2; | ||
599 | goto error_exit; | ||
600 | } | ||
601 | #endif | ||
602 | |||
603 | /* Now that we run without root rights, we can do error checking... */ | ||
604 | if (2 != argc) | ||
605 | { | ||
606 | fprintf (stderr, | ||
607 | "This program must be started with our (internal NAT) IP as the only argument.\n"); | ||
608 | global_ret = 3; | ||
609 | goto error_exit; | ||
610 | } | ||
611 | if (1 != inet_pton (AF_INET, argv[1], &external)) | ||
612 | { | ||
613 | fprintf (stderr, | ||
614 | "Error parsing IPv4 address: %s\n", | ||
615 | strerror (errno)); | ||
616 | global_ret = 4; | ||
617 | goto error_exit; | ||
618 | } | ||
619 | if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) | ||
620 | { | ||
621 | fprintf (stderr, | ||
622 | "Internal error converting dummy IP to binary.\n"); | ||
623 | global_ret = 5; | ||
624 | goto error_exit; | ||
625 | } | ||
626 | |||
627 | /* error checking icmpsock */ | ||
628 | if (-1 == icmpsock) | ||
629 | { | ||
630 | fprintf (stderr, | ||
631 | "Error opening RAW socket: %s\n", | ||
632 | strerror (icmp_eno)); | ||
633 | global_ret = 6; | ||
634 | goto error_exit; | ||
635 | } | ||
636 | if (icmpsock >= FD_SETSIZE) | ||
637 | { | ||
638 | /* this could happen if we were started with a large number of already-open | ||
639 | file descriptors... */ | ||
640 | fprintf (stderr, | ||
641 | "Socket number too large (%d > %u)\n", | ||
642 | icmpsock, | ||
643 | (unsigned int) FD_SETSIZE); | ||
644 | global_ret = 7; | ||
645 | goto error_exit; | ||
646 | } | ||
647 | |||
648 | /* error checking rawsock */ | ||
649 | if (-1 == rawsock) | ||
650 | { | ||
651 | fprintf (stderr, | ||
652 | "Error opening RAW socket: %s\n", | ||
653 | strerror (raw_eno)); | ||
654 | global_ret = 8; | ||
655 | goto error_exit; | ||
656 | } | ||
657 | /* no need to check 'rawsock' against FD_SETSIZE as it is never used | ||
658 | with 'select' */ | ||
659 | |||
660 | if (0 != setup_raw_socket ()) | ||
661 | { | ||
662 | global_ret = 9; | ||
663 | goto error_exit; | ||
664 | } | ||
665 | |||
666 | if (-1 == (udpsock = make_udp_socket (&external))) | ||
667 | { | ||
668 | global_ret = 10; | ||
669 | goto error_exit; | ||
670 | } | ||
671 | |||
672 | alt = 0; | ||
673 | while (1) | ||
674 | { | ||
675 | FD_ZERO (&rs); | ||
676 | FD_SET (icmpsock, &rs); | ||
677 | tv.tv_sec = 0; | ||
678 | tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000; | ||
679 | if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv)) | ||
680 | { | ||
681 | if (errno == EINTR) | ||
682 | continue; | ||
683 | fprintf (stderr, | ||
684 | "select failed: %s\n", | ||
685 | strerror (errno)); | ||
686 | break; | ||
687 | } | ||
688 | if (1 == getppid ()) /* Check the parent process id, if 1 the parent has died, so we should die too */ | ||
689 | break; | ||
690 | if (FD_ISSET (icmpsock, &rs)) | ||
691 | { | ||
692 | process_icmp_response (); | ||
693 | continue; | ||
694 | } | ||
695 | if (0 == (++alt % 2)) | ||
696 | send_icmp_echo (&external); | ||
697 | else | ||
698 | send_udp (); | ||
699 | } | ||
700 | |||
701 | /* select failed (internal error or OS out of resources) */ | ||
702 | global_ret = 11; | ||
703 | error_exit: | ||
704 | if (-1 != icmpsock) | ||
705 | (void) close (icmpsock); | ||
706 | if (-1 != rawsock) | ||
707 | (void) close (rawsock); | ||
708 | if (-1 != udpsock) | ||
709 | (void) close (udpsock); | ||
710 | return global_ret; | ||
711 | } | ||
712 | |||
713 | |||
714 | /* end of gnunet-helper-nat-server.c */ | ||
diff --git a/src/nat/gnunet-nat-client-script.sh b/src/nat/gnunet-nat-client-script.sh deleted file mode 100755 index 4e4ccafad..000000000 --- a/src/nat/gnunet-nat-client-script.sh +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | IP=`ifconfig | grep inet | head -n1 | awk '{print $2}' | sed -e "s/addr://"` | ||
3 | echo "Using IP $IP, trying to connect to $1" | ||
4 | ./gnunet-nat-client-udp $IP $1 | ||
diff --git a/src/nat/gnunet-nat-server-script.sh b/src/nat/gnunet-nat-server-script.sh deleted file mode 100755 index 42a8e639a..000000000 --- a/src/nat/gnunet-nat-server-script.sh +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | IP=`ifconfig | grep inet | head -n1 | awk '{print $2}' | sed -e "s/addr://"` | ||
3 | echo "Using IP $IP" | ||
4 | ./gnunet-nat-server $IP | sed -u -e "s/.*/.\/gnunet-nat-server-udp $IP &\&/" | sh | ||
diff --git a/src/nat/gnunet-nat.c b/src/nat/gnunet-nat.c deleted file mode 100644 index 0743a478d..000000000 --- a/src/nat/gnunet-nat.c +++ /dev/null | |||
@@ -1,476 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2015, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file src/nat/gnunet-nat.c | ||
23 | * @brief Command-line tool to interact with the NAT service | ||
24 | * @author Christian Grothoff | ||
25 | * @author Bruno Cabral | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_nat_service.h" | ||
30 | |||
31 | /** | ||
32 | * Value to return from #main(). | ||
33 | */ | ||
34 | static int global_ret; | ||
35 | |||
36 | /** | ||
37 | * Name of section in configuration file to use for | ||
38 | * additional options. | ||
39 | */ | ||
40 | static char *section_name; | ||
41 | |||
42 | /** | ||
43 | * Flag set to 1 if we use IPPROTO_UDP. | ||
44 | */ | ||
45 | static int use_udp; | ||
46 | |||
47 | /** | ||
48 | * Flag set to 1 if we are to listen for connection reversal requests. | ||
49 | */ | ||
50 | static int listen_reversal; | ||
51 | |||
52 | /** | ||
53 | * Flag set to 1 if we use IPPROTO_TCP. | ||
54 | */ | ||
55 | static int use_tcp; | ||
56 | |||
57 | /** | ||
58 | * Protocol to use. | ||
59 | */ | ||
60 | static uint8_t proto; | ||
61 | |||
62 | /** | ||
63 | * Local address to use for connection reversal request. | ||
64 | */ | ||
65 | static char *local_addr; | ||
66 | |||
67 | /** | ||
68 | * Remote address to use for connection reversal request. | ||
69 | */ | ||
70 | static char *remote_addr; | ||
71 | |||
72 | /** | ||
73 | * Should we actually bind to #bind_addr and receive and process STUN requests? | ||
74 | */ | ||
75 | static int do_stun; | ||
76 | |||
77 | /** | ||
78 | * Handle to NAT operation. | ||
79 | */ | ||
80 | static struct GNUNET_NAT_Handle *nh; | ||
81 | |||
82 | /** | ||
83 | * Listen socket for STUN processing. | ||
84 | */ | ||
85 | static struct GNUNET_NETWORK_Handle *ls; | ||
86 | |||
87 | /** | ||
88 | * Task for reading STUN packets. | ||
89 | */ | ||
90 | static struct GNUNET_SCHEDULER_Task *rtask; | ||
91 | |||
92 | |||
93 | /** | ||
94 | * Test if all activities have finished, and if so, | ||
95 | * terminate. | ||
96 | */ | ||
97 | static void | ||
98 | test_finished () | ||
99 | { | ||
100 | if (NULL != nh) | ||
101 | return; | ||
102 | if (NULL != rtask) | ||
103 | return; | ||
104 | GNUNET_SCHEDULER_shutdown (); | ||
105 | } | ||
106 | |||
107 | |||
108 | /** | ||
109 | * Signature of the callback passed to #GNUNET_NAT_register() for | ||
110 | * a function to call whenever our set of 'valid' addresses changes. | ||
111 | * | ||
112 | * @param cls closure, NULL | ||
113 | * @param app_ctx[in,out] location where the app can store stuff | ||
114 | * on add and retrieve it on remove | ||
115 | * @param add_remove #GNUNET_YES to add a new public IP address, | ||
116 | * #GNUNET_NO to remove a previous (now invalid) one | ||
117 | * @param ac address class the address belongs to | ||
118 | * @param addr either the previous or the new public IP address | ||
119 | * @param addrlen actual length of the @a addr | ||
120 | */ | ||
121 | static void | ||
122 | address_cb (void *cls, | ||
123 | void **app_ctx, | ||
124 | int add_remove, | ||
125 | enum GNUNET_NAT_AddressClass ac, | ||
126 | const struct sockaddr *addr, | ||
127 | socklen_t addrlen) | ||
128 | { | ||
129 | (void) cls; | ||
130 | (void) app_ctx; | ||
131 | |||
132 | fprintf (stdout, | ||
133 | "%s %s (%d)\n", | ||
134 | add_remove ? "+" : "-", | ||
135 | GNUNET_a2s (addr, addrlen), | ||
136 | (int) ac); | ||
137 | } | ||
138 | |||
139 | |||
140 | /** | ||
141 | * Signature of the callback passed to #GNUNET_NAT_register(). | ||
142 | * for a function to call whenever someone asks us to do connection | ||
143 | * reversal. | ||
144 | * | ||
145 | * @param cls closure, NULL | ||
146 | * @param remote_addr public IP address of the other peer | ||
147 | * @param remote_addrlen actual length of the @a remote_addr | ||
148 | */ | ||
149 | static void | ||
150 | reversal_cb (void *cls, | ||
151 | const struct sockaddr *remote_addr, | ||
152 | socklen_t remote_addrlen) | ||
153 | { | ||
154 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
155 | "Connection reversal requested by %s\n", | ||
156 | GNUNET_a2s (remote_addr, remote_addrlen)); | ||
157 | } | ||
158 | |||
159 | |||
160 | /** | ||
161 | * Task run on shutdown. | ||
162 | * | ||
163 | * @param cls NULL | ||
164 | */ | ||
165 | static void | ||
166 | do_shutdown (void *cls) | ||
167 | { | ||
168 | if (NULL != nh) | ||
169 | { | ||
170 | GNUNET_NAT_unregister (nh); | ||
171 | nh = NULL; | ||
172 | } | ||
173 | if (NULL != ls) | ||
174 | { | ||
175 | GNUNET_NETWORK_socket_close (ls); | ||
176 | ls = NULL; | ||
177 | } | ||
178 | if (NULL != rtask) | ||
179 | { | ||
180 | GNUNET_SCHEDULER_cancel (rtask); | ||
181 | rtask = NULL; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | |||
186 | /** | ||
187 | * Task to receive incoming packets for STUN processing. | ||
188 | */ | ||
189 | static void | ||
190 | stun_read_task (void *cls) | ||
191 | { | ||
192 | ssize_t size; | ||
193 | |||
194 | rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
195 | ls, | ||
196 | &stun_read_task, | ||
197 | NULL); | ||
198 | size = GNUNET_NETWORK_socket_recvfrom_amount (ls); | ||
199 | if (size > 0) | ||
200 | { | ||
201 | GNUNET_break (0); | ||
202 | GNUNET_SCHEDULER_shutdown (); | ||
203 | global_ret = 1; | ||
204 | return; | ||
205 | } | ||
206 | { | ||
207 | char buf[size + 1]; | ||
208 | struct sockaddr_storage sa; | ||
209 | socklen_t salen = sizeof(sa); | ||
210 | ssize_t ret; | ||
211 | |||
212 | ret = GNUNET_NETWORK_socket_recvfrom (ls, | ||
213 | buf, | ||
214 | size + 1, | ||
215 | (struct sockaddr *) &sa, | ||
216 | &salen); | ||
217 | if (ret != size) | ||
218 | { | ||
219 | GNUNET_break (0); | ||
220 | GNUNET_SCHEDULER_shutdown (); | ||
221 | global_ret = 1; | ||
222 | return; | ||
223 | } | ||
224 | (void) GNUNET_NAT_stun_handle_packet (nh, | ||
225 | (const struct sockaddr *) &sa, | ||
226 | salen, | ||
227 | buf, | ||
228 | ret); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | |||
233 | /** | ||
234 | * Main function that will be run. | ||
235 | * | ||
236 | * @param cls closure | ||
237 | * @param args remaining command-line arguments | ||
238 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
239 | * @param c configuration | ||
240 | */ | ||
241 | static void | ||
242 | run (void *cls, | ||
243 | char *const *args, | ||
244 | const char *cfgfile, | ||
245 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
246 | { | ||
247 | uint8_t af; | ||
248 | struct sockaddr *local_sa; | ||
249 | struct sockaddr *remote_sa; | ||
250 | socklen_t local_len; | ||
251 | size_t remote_len; | ||
252 | |||
253 | if (use_tcp && use_udp) | ||
254 | { | ||
255 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Cannot use TCP and UDP\n"); | ||
256 | global_ret = 1; | ||
257 | return; | ||
258 | } | ||
259 | proto = 0; | ||
260 | if (use_tcp) | ||
261 | proto = IPPROTO_TCP; | ||
262 | if (use_udp) | ||
263 | proto = IPPROTO_UDP; | ||
264 | |||
265 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); | ||
266 | |||
267 | if (0 == proto) | ||
268 | { | ||
269 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Must specify either TCP or UDP\n"); | ||
270 | global_ret = 1; | ||
271 | return; | ||
272 | } | ||
273 | local_len = 0; | ||
274 | local_sa = NULL; | ||
275 | remote_len = 0; | ||
276 | remote_sa = NULL; | ||
277 | if (NULL != local_addr) | ||
278 | { | ||
279 | local_len = | ||
280 | (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr, &af, &local_sa); | ||
281 | if (0 == local_len) | ||
282 | { | ||
283 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
284 | "Invalid socket address `%s'\n", | ||
285 | local_addr); | ||
286 | goto fail_and_shutdown; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | if (NULL != remote_addr) | ||
291 | { | ||
292 | remote_len = | ||
293 | GNUNET_STRINGS_parse_socket_addr (remote_addr, &af, &remote_sa); | ||
294 | if (0 == remote_len) | ||
295 | { | ||
296 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
297 | "Invalid socket address `%s'\n", | ||
298 | remote_addr); | ||
299 | goto fail_and_shutdown; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | if (NULL != local_addr) | ||
304 | { | ||
305 | if (NULL == section_name) | ||
306 | section_name = GNUNET_strdup ("undefined"); | ||
307 | nh = GNUNET_NAT_register (c, | ||
308 | section_name, | ||
309 | proto, | ||
310 | 1, | ||
311 | (const struct sockaddr **) &local_sa, | ||
312 | &local_len, | ||
313 | &address_cb, | ||
314 | (listen_reversal) ? &reversal_cb : NULL, | ||
315 | NULL); | ||
316 | } | ||
317 | else if (listen_reversal) | ||
318 | { | ||
319 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
320 | "Use of `-W` only effective in combination with `-i`\n"); | ||
321 | goto fail_and_shutdown; | ||
322 | } | ||
323 | |||
324 | if (NULL != remote_addr) | ||
325 | { | ||
326 | int ret; | ||
327 | |||
328 | if ((NULL == nh) || (sizeof(struct sockaddr_in) != local_len)) | ||
329 | { | ||
330 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
331 | "Require IPv4 local address to initiate connection reversal\n"); | ||
332 | goto fail_and_shutdown; | ||
333 | } | ||
334 | if (sizeof(struct sockaddr_in) != remote_len) | ||
335 | { | ||
336 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
337 | "Require IPv4 reversal target address\n"); | ||
338 | goto fail_and_shutdown; | ||
339 | } | ||
340 | GNUNET_assert (AF_INET == local_sa->sa_family); | ||
341 | GNUNET_assert (AF_INET == remote_sa->sa_family); | ||
342 | ret = GNUNET_NAT_request_reversal (nh, | ||
343 | (const struct sockaddr_in *) local_sa, | ||
344 | (const struct sockaddr_in *) remote_sa); | ||
345 | switch (ret) | ||
346 | { | ||
347 | case GNUNET_SYSERR: | ||
348 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
349 | "Connection reversal internal error\n"); | ||
350 | break; | ||
351 | |||
352 | case GNUNET_NO: | ||
353 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
354 | "Connection reversal unavailable\n"); | ||
355 | break; | ||
356 | |||
357 | case GNUNET_OK: | ||
358 | /* operation in progress */ | ||
359 | break; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | if (do_stun) | ||
364 | { | ||
365 | if (NULL == local_addr) | ||
366 | { | ||
367 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
368 | "Require local address to support STUN requests\n"); | ||
369 | goto fail_and_shutdown; | ||
370 | } | ||
371 | if (IPPROTO_UDP != proto) | ||
372 | { | ||
373 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "STUN only supported over UDP\n"); | ||
374 | goto fail_and_shutdown; | ||
375 | } | ||
376 | ls = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, IPPROTO_UDP); | ||
377 | if (NULL == ls) | ||
378 | { | ||
379 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Failed to create socket\n"); | ||
380 | goto fail_and_shutdown; | ||
381 | } | ||
382 | if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ls, local_sa, local_len)) | ||
383 | { | ||
384 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
385 | "Failed to bind to %s: %s\n", | ||
386 | GNUNET_a2s (local_sa, local_len), | ||
387 | strerror (errno)); | ||
388 | goto fail_and_shutdown; | ||
389 | } | ||
390 | rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
391 | ls, | ||
392 | &stun_read_task, | ||
393 | NULL); | ||
394 | } | ||
395 | GNUNET_free (remote_sa); | ||
396 | GNUNET_free (local_sa); | ||
397 | test_finished (); | ||
398 | return; | ||
399 | fail_and_shutdown: | ||
400 | global_ret = 1; | ||
401 | GNUNET_SCHEDULER_shutdown (); | ||
402 | GNUNET_free (remote_sa); | ||
403 | GNUNET_free (local_sa); | ||
404 | } | ||
405 | |||
406 | |||
407 | /** | ||
408 | * Main function of gnunet-nat | ||
409 | * | ||
410 | * @param argc number of command-line arguments | ||
411 | * @param argv command line | ||
412 | * @return 0 on success, -1 on error | ||
413 | */ | ||
414 | int | ||
415 | main (int argc, char *const argv[]) | ||
416 | { | ||
417 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
418 | GNUNET_GETOPT_option_string ( | ||
419 | 'i', | ||
420 | "in", | ||
421 | "ADDRESS", | ||
422 | gettext_noop ("which IP and port are we locally using to bind/listen to"), | ||
423 | &local_addr), | ||
424 | |||
425 | GNUNET_GETOPT_option_string ( | ||
426 | 'r', | ||
427 | "remote", | ||
428 | "ADDRESS", | ||
429 | gettext_noop ( | ||
430 | "which remote IP and port should be asked for connection reversal"), | ||
431 | &remote_addr), | ||
432 | |||
433 | GNUNET_GETOPT_option_string ( | ||
434 | 'S', | ||
435 | "section", | ||
436 | NULL, | ||
437 | gettext_noop ( | ||
438 | "name of configuration section to find additional options, such as manual host punching data"), | ||
439 | §ion_name), | ||
440 | |||
441 | GNUNET_GETOPT_option_flag ('s', | ||
442 | "stun", | ||
443 | gettext_noop ("enable STUN processing"), | ||
444 | &do_stun), | ||
445 | |||
446 | GNUNET_GETOPT_option_flag ('t', "tcp", gettext_noop ("use TCP"), &use_tcp), | ||
447 | |||
448 | GNUNET_GETOPT_option_flag ('u', "udp", gettext_noop ("use UDP"), &use_udp), | ||
449 | |||
450 | GNUNET_GETOPT_option_flag ('W', | ||
451 | "watch", | ||
452 | gettext_noop ( | ||
453 | "watch for connection reversal requests"), | ||
454 | &listen_reversal), | ||
455 | GNUNET_GETOPT_OPTION_END | ||
456 | }; | ||
457 | |||
458 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
459 | return 2; | ||
460 | if (GNUNET_OK != | ||
461 | GNUNET_PROGRAM_run (argc, | ||
462 | argv, | ||
463 | "gnunet-nat [options]", | ||
464 | _ ("GNUnet NAT traversal autoconfigure daemon"), | ||
465 | options, | ||
466 | &run, | ||
467 | NULL)) | ||
468 | { | ||
469 | global_ret = 1; | ||
470 | } | ||
471 | GNUNET_free_nz ((void *) argv); | ||
472 | return global_ret; | ||
473 | } | ||
474 | |||
475 | |||
476 | /* end of gnunet-nat.c */ | ||
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c deleted file mode 100644 index 4dcc0312f..000000000 --- a/src/nat/gnunet-service-nat.c +++ /dev/null | |||
@@ -1,2083 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2016, 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file nat/gnunet-service-nat.c | ||
23 | * @brief network address translation traversal service | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * The purpose of this service is to enable transports to | ||
27 | * traverse NAT routers, by providing traversal options and | ||
28 | * knowledge about the local network topology. | ||
29 | * | ||
30 | * TODO: | ||
31 | * - migrate test cases to new NAT service | ||
32 | * - add new traceroute-based logic for external IP detection | ||
33 | * | ||
34 | * - implement & test STUN processing to classify NAT; | ||
35 | * basically, open port & try different methods. | ||
36 | */ | ||
37 | #include "platform.h" | ||
38 | #include <math.h> | ||
39 | #include "gnunet_util_lib.h" | ||
40 | #include "gnunet_protocols.h" | ||
41 | #include "gnunet_signatures.h" | ||
42 | #include "gnunet_statistics_service.h" | ||
43 | #include "gnunet_resolver_service.h" | ||
44 | #include "gnunet_nat_service.h" | ||
45 | #include "gnunet-service-nat.h" | ||
46 | #include "gnunet-service-nat_externalip.h" | ||
47 | #include "gnunet-service-nat_stun.h" | ||
48 | #include "gnunet-service-nat_mini.h" | ||
49 | #include "gnunet-service-nat_helper.h" | ||
50 | #include "nat.h" | ||
51 | #include <gcrypt.h> | ||
52 | |||
53 | |||
54 | /** | ||
55 | * How often should we ask the OS about a list of active | ||
56 | * network interfaces? | ||
57 | */ | ||
58 | #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) | ||
59 | |||
60 | /** | ||
61 | * How long do we wait until we forcefully terminate autoconfiguration? | ||
62 | */ | ||
63 | #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply ( \ | ||
64 | GNUNET_TIME_UNIT_SECONDS, 5) | ||
65 | |||
66 | /** | ||
67 | * How often do we scan for changes in how our external (dyndns) hostname resolves? | ||
68 | */ | ||
69 | #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply ( \ | ||
70 | GNUNET_TIME_UNIT_MINUTES, 7) | ||
71 | |||
72 | |||
73 | /** | ||
74 | * Information we track per client address. | ||
75 | */ | ||
76 | struct ClientAddress | ||
77 | { | ||
78 | /** | ||
79 | * Network address used by the client. | ||
80 | */ | ||
81 | struct sockaddr_storage ss; | ||
82 | |||
83 | /** | ||
84 | * Handle to active UPnP request where we asked upnpc to open | ||
85 | * a port at the NAT. NULL if we do not have such a request | ||
86 | * pending. | ||
87 | */ | ||
88 | struct GNUNET_NAT_MiniHandle *mh; | ||
89 | }; | ||
90 | |||
91 | |||
92 | /** | ||
93 | * List of local addresses this system has. | ||
94 | */ | ||
95 | struct LocalAddressList | ||
96 | { | ||
97 | /** | ||
98 | * This is a linked list. | ||
99 | */ | ||
100 | struct LocalAddressList *next; | ||
101 | |||
102 | /** | ||
103 | * Previous entry. | ||
104 | */ | ||
105 | struct LocalAddressList *prev; | ||
106 | |||
107 | /** | ||
108 | * Context for a gnunet-helper-nat-server used to listen | ||
109 | * for ICMP messages to this client for connection reversal. | ||
110 | */ | ||
111 | struct HelperContext *hc; | ||
112 | |||
113 | /** | ||
114 | * The address itself (i.e. `struct sockaddr_in` or `struct | ||
115 | * sockaddr_in6`, in the respective byte order). | ||
116 | */ | ||
117 | struct sockaddr_storage addr; | ||
118 | |||
119 | /** | ||
120 | * Address family. (FIXME: redundant, addr.ss_family! Remove!?) | ||
121 | */ | ||
122 | int af; | ||
123 | |||
124 | /** | ||
125 | * #GNUNET_YES if we saw this one in the previous iteration, | ||
126 | * but not in the current iteration and thus might need to | ||
127 | * remove it at the end. | ||
128 | */ | ||
129 | int old; | ||
130 | |||
131 | /** | ||
132 | * What type of address is this? | ||
133 | */ | ||
134 | enum GNUNET_NAT_AddressClass ac; | ||
135 | }; | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Internal data structure we track for each of our clients. | ||
140 | */ | ||
141 | struct ClientHandle | ||
142 | { | ||
143 | /** | ||
144 | * Kept in a DLL. | ||
145 | */ | ||
146 | struct ClientHandle *next; | ||
147 | |||
148 | /** | ||
149 | * Kept in a DLL. | ||
150 | */ | ||
151 | struct ClientHandle *prev; | ||
152 | |||
153 | /** | ||
154 | * Underlying handle for this client with the service. | ||
155 | */ | ||
156 | struct GNUNET_SERVICE_Client *client; | ||
157 | |||
158 | /** | ||
159 | * Message queue for communicating with the client. | ||
160 | */ | ||
161 | struct GNUNET_MQ_Handle *mq; | ||
162 | |||
163 | /** | ||
164 | * Array of addresses used by the service. | ||
165 | */ | ||
166 | struct ClientAddress *caddrs; | ||
167 | |||
168 | /** | ||
169 | * External DNS name and port given by user due to manual | ||
170 | * hole punching. Special DNS name 'AUTO' is used to indicate | ||
171 | * desire for automatic determination of the external IP | ||
172 | * (instead of DNS or manual configuration, i.e. to be used | ||
173 | * if the IP keeps changing and we have no DynDNS, but we do | ||
174 | * have a hole punched). | ||
175 | */ | ||
176 | char *hole_external; | ||
177 | |||
178 | /** | ||
179 | * Name of the configuration section this client cares about. | ||
180 | */ | ||
181 | char *section_name; | ||
182 | |||
183 | /** | ||
184 | * Task for periodically re-running the @e ext_dns DNS lookup. | ||
185 | */ | ||
186 | struct GNUNET_SCHEDULER_Task *ext_dns_task; | ||
187 | |||
188 | /** | ||
189 | * Handle for (DYN)DNS lookup of our external IP as given in | ||
190 | * @e hole_external. | ||
191 | */ | ||
192 | struct GNUNET_RESOLVER_RequestHandle *ext_dns; | ||
193 | |||
194 | /** | ||
195 | * Handle for monitoring external IP changes. | ||
196 | */ | ||
197 | struct GN_ExternalIPMonitor *external_monitor; | ||
198 | |||
199 | /** | ||
200 | * DLL of external IP addresses as given in @e hole_external. | ||
201 | */ | ||
202 | struct LocalAddressList *ext_addr_head; | ||
203 | |||
204 | /** | ||
205 | * DLL of external IP addresses as given in @e hole_external. | ||
206 | */ | ||
207 | struct LocalAddressList *ext_addr_tail; | ||
208 | |||
209 | /** | ||
210 | * Port number we found in @e hole_external. | ||
211 | */ | ||
212 | uint16_t ext_dns_port; | ||
213 | |||
214 | /** | ||
215 | * What does this client care about? | ||
216 | */ | ||
217 | enum GNUNET_NAT_RegisterFlags flags; | ||
218 | |||
219 | /** | ||
220 | * Is any of the @e caddrs in a reserved subnet for NAT? | ||
221 | */ | ||
222 | int natted_address; | ||
223 | |||
224 | /** | ||
225 | * Number of addresses that this service is bound to. | ||
226 | * Length of the @e caddrs array. | ||
227 | */ | ||
228 | uint16_t num_caddrs; | ||
229 | |||
230 | /** | ||
231 | * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP. | ||
232 | */ | ||
233 | uint8_t proto; | ||
234 | }; | ||
235 | |||
236 | |||
237 | /** | ||
238 | * External IP address as given to us via some STUN server. | ||
239 | */ | ||
240 | struct StunExternalIP | ||
241 | { | ||
242 | /** | ||
243 | * Kept in a DLL. | ||
244 | */ | ||
245 | struct StunExternalIP *next; | ||
246 | |||
247 | /** | ||
248 | * Kept in a DLL. | ||
249 | */ | ||
250 | struct StunExternalIP *prev; | ||
251 | |||
252 | /** | ||
253 | * Task we run to remove this entry when it is stale. | ||
254 | */ | ||
255 | struct GNUNET_SCHEDULER_Task *timeout_task; | ||
256 | |||
257 | /** | ||
258 | * Our external IP address as reported by the | ||
259 | * STUN server. | ||
260 | */ | ||
261 | struct sockaddr_in external_addr; | ||
262 | |||
263 | /** | ||
264 | * Address of the reporting STUN server. Used to | ||
265 | * detect when a STUN server changes its opinion | ||
266 | * to more quickly remove stale results. | ||
267 | */ | ||
268 | struct sockaddr_storage stun_server_addr; | ||
269 | |||
270 | /** | ||
271 | * Number of bytes used in @e stun_server_addr. | ||
272 | */ | ||
273 | size_t stun_server_addr_len; | ||
274 | }; | ||
275 | |||
276 | |||
277 | /** | ||
278 | * Timeout to use when STUN data is considered stale. | ||
279 | */ | ||
280 | static struct GNUNET_TIME_Relative stun_stale_timeout; | ||
281 | |||
282 | /** | ||
283 | * How often do we scan for changes in how our external (dyndns) hostname resolves? | ||
284 | */ | ||
285 | static struct GNUNET_TIME_Relative dyndns_frequency; | ||
286 | |||
287 | /** | ||
288 | * Handle to our current configuration. | ||
289 | */ | ||
290 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
291 | |||
292 | /** | ||
293 | * Handle to the statistics service. | ||
294 | */ | ||
295 | static struct GNUNET_STATISTICS_Handle *stats; | ||
296 | |||
297 | /** | ||
298 | * Task scheduled to periodically scan our network interfaces. | ||
299 | */ | ||
300 | static struct GNUNET_SCHEDULER_Task *scan_task; | ||
301 | |||
302 | /** | ||
303 | * Head of client DLL. | ||
304 | */ | ||
305 | static struct ClientHandle *ch_head; | ||
306 | |||
307 | /** | ||
308 | * Tail of client DLL. | ||
309 | */ | ||
310 | static struct ClientHandle *ch_tail; | ||
311 | |||
312 | /** | ||
313 | * Head of DLL of local addresses. | ||
314 | */ | ||
315 | static struct LocalAddressList *lal_head; | ||
316 | |||
317 | /** | ||
318 | * Tail of DLL of local addresses. | ||
319 | */ | ||
320 | static struct LocalAddressList *lal_tail; | ||
321 | |||
322 | /** | ||
323 | * Kept in a DLL. | ||
324 | */ | ||
325 | static struct StunExternalIP *se_head; | ||
326 | |||
327 | /** | ||
328 | * Kept in a DLL. | ||
329 | */ | ||
330 | static struct StunExternalIP *se_tail; | ||
331 | |||
332 | /** | ||
333 | * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled, | ||
334 | * #GNUNET_SYSERR if configuration enabled but binary is unavailable. | ||
335 | */ | ||
336 | int enable_upnp; | ||
337 | |||
338 | /** | ||
339 | * Is IP Scanning enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled, | ||
340 | * without, only explicitly specified IPs will be handled (HOLE_EXTERNAL) | ||
341 | */ | ||
342 | int enable_ipscan; | ||
343 | |||
344 | /** | ||
345 | * Remove and free an entry from the #lal_head DLL. | ||
346 | * | ||
347 | * @param lal entry to free | ||
348 | */ | ||
349 | static void | ||
350 | free_lal (struct LocalAddressList *lal) | ||
351 | { | ||
352 | GNUNET_CONTAINER_DLL_remove (lal_head, | ||
353 | lal_tail, | ||
354 | lal); | ||
355 | if (NULL != lal->hc) | ||
356 | { | ||
357 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
358 | "Lost NATed local address %s, stopping NAT server\n", | ||
359 | GNUNET_a2s ((const struct sockaddr *) &lal->addr, | ||
360 | sizeof(struct sockaddr_in))); | ||
361 | |||
362 | GN_stop_gnunet_nat_server_ (lal->hc); | ||
363 | lal->hc = NULL; | ||
364 | } | ||
365 | GNUNET_free (lal); | ||
366 | } | ||
367 | |||
368 | |||
369 | /** | ||
370 | * Free the DLL starting at #lal_head. | ||
371 | */ | ||
372 | static void | ||
373 | destroy_lal () | ||
374 | { | ||
375 | struct LocalAddressList *lal; | ||
376 | |||
377 | while (NULL != (lal = lal_head)) | ||
378 | free_lal (lal); | ||
379 | } | ||
380 | |||
381 | |||
382 | /** | ||
383 | * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from | ||
384 | * client. | ||
385 | * | ||
386 | * @param cls client who sent the message | ||
387 | * @param message the message received | ||
388 | * @return #GNUNET_OK if message is well-formed | ||
389 | */ | ||
390 | static int | ||
391 | check_register (void *cls, | ||
392 | const struct GNUNET_NAT_RegisterMessage *message) | ||
393 | { | ||
394 | uint16_t num_addrs = ntohs (message->num_addrs); | ||
395 | const char *off = (const char *) &message[1]; | ||
396 | size_t left = ntohs (message->header.size) - sizeof(*message); | ||
397 | |||
398 | for (unsigned int i = 0; i < num_addrs; i++) | ||
399 | { | ||
400 | size_t alen; | ||
401 | const struct sockaddr *sa = (const struct sockaddr *) off; | ||
402 | |||
403 | if (sizeof(sa_family_t) > left) | ||
404 | { | ||
405 | GNUNET_break (0); | ||
406 | return GNUNET_SYSERR; | ||
407 | } | ||
408 | switch (sa->sa_family) | ||
409 | { | ||
410 | case AF_INET: | ||
411 | alen = sizeof(struct sockaddr_in); | ||
412 | break; | ||
413 | |||
414 | case AF_INET6: | ||
415 | alen = sizeof(struct sockaddr_in6); | ||
416 | break; | ||
417 | |||
418 | #if AF_UNIX | ||
419 | case AF_UNIX: | ||
420 | alen = sizeof(struct sockaddr_un); | ||
421 | break; | ||
422 | #endif | ||
423 | default: | ||
424 | GNUNET_break (0); | ||
425 | return GNUNET_SYSERR; | ||
426 | } | ||
427 | if (alen > left) | ||
428 | { | ||
429 | GNUNET_break (0); | ||
430 | return GNUNET_SYSERR; | ||
431 | } | ||
432 | off += alen; | ||
433 | left -= alen; | ||
434 | } | ||
435 | if (left != ntohs (message->str_len)) | ||
436 | { | ||
437 | GNUNET_break (0); | ||
438 | return GNUNET_SYSERR; | ||
439 | } | ||
440 | return GNUNET_OK; | ||
441 | } | ||
442 | |||
443 | |||
444 | /** | ||
445 | * Check if @a ip is in @a network with @a bits netmask. | ||
446 | * | ||
447 | * @param network to test | ||
448 | * @param ip IP address to test | ||
449 | * @param bits bitmask for the network | ||
450 | * @return #GNUNET_YES if @a ip is in @a network | ||
451 | */ | ||
452 | static int | ||
453 | match_ipv4 (const char *network, | ||
454 | const struct in_addr *ip, | ||
455 | uint8_t bits) | ||
456 | { | ||
457 | struct in_addr net; | ||
458 | |||
459 | if (0 == ip->s_addr) | ||
460 | return GNUNET_YES; | ||
461 | if (0 == bits) | ||
462 | return GNUNET_YES; | ||
463 | GNUNET_assert (1 == inet_pton (AF_INET, | ||
464 | network, | ||
465 | &net)); | ||
466 | return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits))); | ||
467 | } | ||
468 | |||
469 | |||
470 | /** | ||
471 | * Check if @a ip is in @a network with @a bits netmask. | ||
472 | * | ||
473 | * @param network to test | ||
474 | * @param ip IP address to test | ||
475 | * @param bits bitmask for the network | ||
476 | * @return #GNUNET_YES if @a ip is in @a network | ||
477 | */ | ||
478 | static int | ||
479 | match_ipv6 (const char *network, | ||
480 | const struct in6_addr *ip, | ||
481 | uint8_t bits) | ||
482 | { | ||
483 | struct in6_addr net; | ||
484 | struct in6_addr mask; | ||
485 | unsigned int off; | ||
486 | |||
487 | if (0 == bits) | ||
488 | return GNUNET_YES; | ||
489 | GNUNET_assert (1 == inet_pton (AF_INET6, | ||
490 | network, | ||
491 | &net)); | ||
492 | memset (&mask, 0, sizeof(mask)); | ||
493 | if (0 == GNUNET_memcmp (&mask, | ||
494 | ip)) | ||
495 | return GNUNET_YES; | ||
496 | off = 0; | ||
497 | while (bits > 8) | ||
498 | { | ||
499 | mask.s6_addr[off++] = 0xFF; | ||
500 | bits -= 8; | ||
501 | } | ||
502 | while (bits > 0) | ||
503 | { | ||
504 | mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80; | ||
505 | bits--; | ||
506 | } | ||
507 | for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++) | ||
508 | if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) != | ||
509 | (((uint32_t *) &net)[j] & ((int *) &mask)[j])) | ||
510 | return GNUNET_NO; | ||
511 | return GNUNET_YES; | ||
512 | } | ||
513 | |||
514 | |||
515 | /** | ||
516 | * Test if the given IPv4 address is in a known range | ||
517 | * for private networks. | ||
518 | * | ||
519 | * @param ip address to test | ||
520 | * @return #GNUNET_YES if @a ip is in a NAT range | ||
521 | */ | ||
522 | static int | ||
523 | is_nat_v4 (const struct in_addr *ip) | ||
524 | { | ||
525 | return | ||
526 | match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */ | ||
527 | match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */ | ||
528 | match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */ | ||
529 | match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */ | ||
530 | match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */ | ||
531 | } | ||
532 | |||
533 | |||
534 | /** | ||
535 | * Test if the given IPv6 address is in a known range | ||
536 | * for private networks. | ||
537 | * | ||
538 | * @param ip address to test | ||
539 | * @return #GNUNET_YES if @a ip is in a NAT range | ||
540 | */ | ||
541 | static int | ||
542 | is_nat_v6 (const struct in6_addr *ip) | ||
543 | { | ||
544 | return | ||
545 | match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */ | ||
546 | match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */ | ||
547 | match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */ | ||
548 | } | ||
549 | |||
550 | |||
551 | /** | ||
552 | * Closure for #ifc_proc. | ||
553 | */ | ||
554 | struct IfcProcContext | ||
555 | { | ||
556 | /** | ||
557 | * Head of DLL of local addresses. | ||
558 | */ | ||
559 | struct LocalAddressList *lal_head; | ||
560 | |||
561 | /** | ||
562 | * Tail of DLL of local addresses. | ||
563 | */ | ||
564 | struct LocalAddressList *lal_tail; | ||
565 | }; | ||
566 | |||
567 | |||
568 | /** | ||
569 | * Callback function invoked for each interface found. Adds them | ||
570 | * to our new address list. | ||
571 | * | ||
572 | * @param cls a `struct IfcProcContext *` | ||
573 | * @param name name of the interface (can be NULL for unknown) | ||
574 | * @param isDefault is this presumably the default interface | ||
575 | * @param addr address of this interface (can be NULL for unknown or unassigned) | ||
576 | * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) | ||
577 | * @param netmask the network mask (can be NULL for unknown or unassigned) | ||
578 | * @param addrlen length of the address | ||
579 | * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort | ||
580 | */ | ||
581 | static int | ||
582 | ifc_proc (void *cls, | ||
583 | const char *name, | ||
584 | int isDefault, | ||
585 | const struct sockaddr *addr, | ||
586 | const struct sockaddr *broadcast_addr, | ||
587 | const struct sockaddr *netmask, | ||
588 | socklen_t addrlen) | ||
589 | { | ||
590 | struct IfcProcContext *ifc_ctx = cls; | ||
591 | struct LocalAddressList *lal; | ||
592 | size_t alen; | ||
593 | const struct in_addr *ip4; | ||
594 | const struct in6_addr *ip6; | ||
595 | enum GNUNET_NAT_AddressClass ac; | ||
596 | |||
597 | switch (addr->sa_family) | ||
598 | { | ||
599 | case AF_INET: | ||
600 | alen = sizeof(struct sockaddr_in); | ||
601 | ip4 = &((const struct sockaddr_in *) addr)->sin_addr; | ||
602 | if (match_ipv4 ("127.0.0.0", ip4, 8)) | ||
603 | ac = GNUNET_NAT_AC_LOOPBACK; | ||
604 | else if (is_nat_v4 (ip4)) | ||
605 | ac = GNUNET_NAT_AC_LAN; | ||
606 | else | ||
607 | ac = GNUNET_NAT_AC_GLOBAL; | ||
608 | break; | ||
609 | |||
610 | case AF_INET6: | ||
611 | alen = sizeof(struct sockaddr_in6); | ||
612 | ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr; | ||
613 | if (match_ipv6 ("::1", ip6, 128)) | ||
614 | ac = GNUNET_NAT_AC_LOOPBACK; | ||
615 | else if (is_nat_v6 (ip6)) | ||
616 | ac = GNUNET_NAT_AC_LAN; | ||
617 | else | ||
618 | ac = GNUNET_NAT_AC_GLOBAL; | ||
619 | if ((ip6->s6_addr[11] == 0xFF) && | ||
620 | (ip6->s6_addr[12] == 0xFE)) | ||
621 | { | ||
622 | /* contains a MAC, be extra careful! */ | ||
623 | ac |= GNUNET_NAT_AC_PRIVATE; | ||
624 | } | ||
625 | break; | ||
626 | |||
627 | #if AF_UNIX | ||
628 | case AF_UNIX: | ||
629 | GNUNET_break (0); | ||
630 | return GNUNET_OK; | ||
631 | #endif | ||
632 | default: | ||
633 | GNUNET_break (0); | ||
634 | return GNUNET_OK; | ||
635 | } | ||
636 | lal = GNUNET_malloc (sizeof(*lal)); | ||
637 | lal->af = addr->sa_family; | ||
638 | lal->ac = ac; | ||
639 | GNUNET_memcpy (&lal->addr, | ||
640 | addr, | ||
641 | alen); | ||
642 | GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head, | ||
643 | ifc_ctx->lal_tail, | ||
644 | lal); | ||
645 | return GNUNET_OK; | ||
646 | } | ||
647 | |||
648 | |||
649 | /** | ||
650 | * Notify client about a change in the list of addresses this peer | ||
651 | * has. | ||
652 | * | ||
653 | * @param ac address class of the entry in the list that changed | ||
654 | * @param ch client to contact | ||
655 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
656 | * @param addr the address that changed | ||
657 | * @param addr_len number of bytes in @a addr | ||
658 | */ | ||
659 | static void | ||
660 | notify_client (enum GNUNET_NAT_AddressClass ac, | ||
661 | struct ClientHandle *ch, | ||
662 | int add, | ||
663 | const void *addr, | ||
664 | size_t addr_len) | ||
665 | { | ||
666 | struct GNUNET_MQ_Envelope *env; | ||
667 | struct GNUNET_NAT_AddressChangeNotificationMessage *msg; | ||
668 | |||
669 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
670 | "Notifying client about %s of IP %s\n", | ||
671 | add ? "addition" : "removal", | ||
672 | GNUNET_a2s (addr, | ||
673 | addr_len)); | ||
674 | env = GNUNET_MQ_msg_extra (msg, | ||
675 | addr_len, | ||
676 | GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); | ||
677 | msg->add_remove = htonl (add); | ||
678 | msg->addr_class = htonl (ac); | ||
679 | GNUNET_memcpy (&msg[1], | ||
680 | addr, | ||
681 | addr_len); | ||
682 | GNUNET_MQ_send (ch->mq, | ||
683 | env); | ||
684 | } | ||
685 | |||
686 | |||
687 | /** | ||
688 | * Check if we should bother to notify this client about this | ||
689 | * address change, and if so, do it. | ||
690 | * | ||
691 | * @param delta the entry in the list that changed | ||
692 | * @param ch client to check | ||
693 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
694 | */ | ||
695 | static void | ||
696 | check_notify_client (struct LocalAddressList *delta, | ||
697 | struct ClientHandle *ch, | ||
698 | int add) | ||
699 | { | ||
700 | size_t alen; | ||
701 | struct sockaddr_in v4; | ||
702 | struct sockaddr_in6 v6; | ||
703 | |||
704 | if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES)) | ||
705 | { | ||
706 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
707 | "Not notifying client as it does not care about addresses\n"); | ||
708 | return; | ||
709 | } | ||
710 | switch (delta->af) | ||
711 | { | ||
712 | case AF_INET: | ||
713 | alen = sizeof(struct sockaddr_in); | ||
714 | GNUNET_memcpy (&v4, | ||
715 | &delta->addr, | ||
716 | alen); | ||
717 | |||
718 | /* Check for client notifications */ | ||
719 | for (unsigned int i = 0; i < ch->num_caddrs; i++) | ||
720 | { | ||
721 | const struct sockaddr_in *c4; | ||
722 | |||
723 | if (AF_INET != ch->caddrs[i].ss.ss_family) | ||
724 | continue; /* IPv4 not relevant */ | ||
725 | c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss; | ||
726 | if (match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) && | ||
727 | (0 != c4->sin_addr.s_addr) && | ||
728 | (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))) | ||
729 | continue; /* bound to loopback, but this is not loopback */ | ||
730 | if ((! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8)) && | ||
731 | match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) | ||
732 | continue; /* bound to non-loopback, but this is loopback */ | ||
733 | if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) && | ||
734 | (0 != c4->sin_addr.s_addr) && | ||
735 | (! is_nat_v4 (&v4.sin_addr))) | ||
736 | continue; /* based on external-IP, but this IP is not | ||
737 | from private address range. */ | ||
738 | if ((0 != GNUNET_memcmp (&v4.sin_addr, | ||
739 | &c4->sin_addr)) && | ||
740 | (0 != c4->sin_addr.s_addr) && | ||
741 | (! is_nat_v4 (&c4->sin_addr))) | ||
742 | continue; /* this IP is not from private address range, | ||
743 | and IP does not match. */ | ||
744 | |||
745 | /* OK, IP seems relevant, notify client */ | ||
746 | if (0 == htons (v4.sin_port)) | ||
747 | v4.sin_port = c4->sin_port; | ||
748 | notify_client (delta->ac, | ||
749 | ch, | ||
750 | add, | ||
751 | &v4, | ||
752 | alen); | ||
753 | } | ||
754 | break; | ||
755 | |||
756 | case AF_INET6: | ||
757 | alen = sizeof(struct sockaddr_in6); | ||
758 | GNUNET_memcpy (&v6, | ||
759 | &delta->addr, | ||
760 | alen); | ||
761 | for (unsigned int i = 0; i < ch->num_caddrs; i++) | ||
762 | { | ||
763 | const struct sockaddr_in6 *c6; | ||
764 | |||
765 | if (AF_INET6 != ch->caddrs[i].ss.ss_family) | ||
766 | continue; /* IPv4 not relevant */ | ||
767 | c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss; | ||
768 | if (match_ipv6 ("::1", &c6->sin6_addr, 128) && | ||
769 | (0 != GNUNET_memcmp (&c6->sin6_addr, | ||
770 | &in6addr_any)) && | ||
771 | (! match_ipv6 ("::1", &v6.sin6_addr, 128))) | ||
772 | continue; /* bound to loopback, but this is not loopback */ | ||
773 | if ((! match_ipv6 ("::1", &c6->sin6_addr, 128)) && | ||
774 | match_ipv6 ("::1", &v6.sin6_addr, 128)) | ||
775 | continue; /* bound to non-loopback, but this is loopback */ | ||
776 | if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) && | ||
777 | (0 != GNUNET_memcmp (&c6->sin6_addr, | ||
778 | &in6addr_any)) && | ||
779 | (! is_nat_v6 (&v6.sin6_addr))) | ||
780 | continue; /* based on external-IP, but this IP is not | ||
781 | from private address range. */ | ||
782 | if ((0 != GNUNET_memcmp (&v6.sin6_addr, | ||
783 | &c6->sin6_addr)) && | ||
784 | (0 != GNUNET_memcmp (&c6->sin6_addr, | ||
785 | &in6addr_any)) && | ||
786 | (! is_nat_v6 (&c6->sin6_addr))) | ||
787 | continue; /* this IP is not from private address range, | ||
788 | and IP does not match. */ | ||
789 | if ((match_ipv6 ("fe80::", &c6->sin6_addr, 10)) && | ||
790 | (0 != GNUNET_memcmp (&c6->sin6_addr, | ||
791 | &in6addr_any)) && | ||
792 | (0 != GNUNET_memcmp (&v6.sin6_addr, | ||
793 | &c6->sin6_addr)) && | ||
794 | (0 == (delta->ac & GNUNET_NAT_AC_EXTERN))) | ||
795 | continue; /* client bound to link-local, and the other address | ||
796 | does not match and is not an external IP */ | ||
797 | |||
798 | /* OK, IP seems relevant, notify client */ | ||
799 | if (0 == htons (v6.sin6_port)) | ||
800 | v6.sin6_port = c6->sin6_port; | ||
801 | notify_client (delta->ac, | ||
802 | ch, | ||
803 | add, | ||
804 | &v6, | ||
805 | alen); | ||
806 | } | ||
807 | break; | ||
808 | |||
809 | default: | ||
810 | GNUNET_break (0); | ||
811 | return; | ||
812 | } | ||
813 | } | ||
814 | |||
815 | |||
816 | /** | ||
817 | * Notify all clients about a change in the list | ||
818 | * of addresses this peer has. | ||
819 | * | ||
820 | * @param delta the entry in the list that changed | ||
821 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
822 | */ | ||
823 | static void | ||
824 | notify_clients (struct LocalAddressList *delta, | ||
825 | int add) | ||
826 | { | ||
827 | for (struct ClientHandle *ch = ch_head; | ||
828 | NULL != ch; | ||
829 | ch = ch->next) | ||
830 | check_notify_client (delta, | ||
831 | ch, | ||
832 | add); | ||
833 | } | ||
834 | |||
835 | |||
836 | /** | ||
837 | * Tell relevant client about a change in our external | ||
838 | * IPv4 address. | ||
839 | * | ||
840 | * @param cls client to check if it cares and possibly notify | ||
841 | * @param v4 the external address that changed | ||
842 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
843 | */ | ||
844 | static void | ||
845 | notify_client_external_ipv4_change (void *cls, | ||
846 | const struct in_addr *v4, | ||
847 | int add) | ||
848 | { | ||
849 | struct ClientHandle *ch = cls; | ||
850 | struct sockaddr_in sa; | ||
851 | int have_v4; | ||
852 | |||
853 | /* (0) check if this impacts 'hole_external' */ | ||
854 | if ((NULL != ch->hole_external) && | ||
855 | (0 == strcasecmp (ch->hole_external, | ||
856 | "AUTO"))) | ||
857 | { | ||
858 | struct LocalAddressList lal; | ||
859 | struct sockaddr_in *s4; | ||
860 | |||
861 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
862 | "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n", | ||
863 | (unsigned int) ch->ext_dns_port, | ||
864 | ch->section_name); | ||
865 | memset (&lal, 0, sizeof(lal)); | ||
866 | s4 = (struct sockaddr_in *) &lal.addr; | ||
867 | s4->sin_family = AF_INET; | ||
868 | s4->sin_port = htons (ch->ext_dns_port); | ||
869 | s4->sin_addr = *v4; | ||
870 | lal.af = AF_INET; | ||
871 | lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL; | ||
872 | check_notify_client (&lal, | ||
873 | ch, | ||
874 | add); | ||
875 | } | ||
876 | |||
877 | /* (1) check if client cares. */ | ||
878 | if (! ch->natted_address) | ||
879 | return; | ||
880 | have_v4 = GNUNET_NO; | ||
881 | for (unsigned int i = 0; i < ch->num_caddrs; i++) | ||
882 | { | ||
883 | const struct sockaddr_storage *ss = &ch->caddrs[i].ss; | ||
884 | |||
885 | if (AF_INET != ss->ss_family) | ||
886 | continue; | ||
887 | have_v4 = GNUNET_YES; | ||
888 | break; | ||
889 | } | ||
890 | if (GNUNET_NO == have_v4) | ||
891 | return; /* IPv6-only */ | ||
892 | |||
893 | /* (2) build address info */ | ||
894 | memset (&sa, | ||
895 | 0, | ||
896 | sizeof(sa)); | ||
897 | sa.sin_family = AF_INET; | ||
898 | sa.sin_addr = *v4; | ||
899 | sa.sin_port = htons (0); | ||
900 | |||
901 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
902 | "Detected eternal IP %s, notifying client of external IP (without port)\n", | ||
903 | GNUNET_a2s ((const struct sockaddr *) &sa, | ||
904 | sizeof(sa))); | ||
905 | /* (3) notify client of change */ | ||
906 | notify_client (is_nat_v4 (v4) | ||
907 | ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN | ||
908 | : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL, | ||
909 | ch, | ||
910 | add, | ||
911 | &sa, | ||
912 | sizeof(sa)); | ||
913 | } | ||
914 | |||
915 | |||
916 | /** | ||
917 | * We got a connection reversal request from another peer. | ||
918 | * Notify applicable clients. | ||
919 | * | ||
920 | * @param cls closure with the `struct LocalAddressList` | ||
921 | * @param ra IP address of the peer who wants us to connect to it | ||
922 | */ | ||
923 | static void | ||
924 | reversal_callback (void *cls, | ||
925 | const struct sockaddr_in *ra) | ||
926 | { | ||
927 | struct LocalAddressList *lal = cls; | ||
928 | const struct sockaddr_in *l4; | ||
929 | |||
930 | GNUNET_assert (AF_INET == lal->af); | ||
931 | l4 = (const struct sockaddr_in *) &lal->addr; | ||
932 | for (struct ClientHandle *ch = ch_head; | ||
933 | NULL != ch; | ||
934 | ch = ch->next) | ||
935 | { | ||
936 | struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm; | ||
937 | struct GNUNET_MQ_Envelope *env; | ||
938 | int match; | ||
939 | |||
940 | /* Check if client is in applicable range for ICMP NAT traversal | ||
941 | for this local address */ | ||
942 | if (! ch->natted_address) | ||
943 | continue; | ||
944 | match = GNUNET_NO; | ||
945 | for (unsigned int i = 0; i < ch->num_caddrs; i++) | ||
946 | { | ||
947 | struct ClientAddress *ca = &ch->caddrs[i]; | ||
948 | const struct sockaddr_in *c4; | ||
949 | |||
950 | if (AF_INET != ca->ss.ss_family) | ||
951 | continue; | ||
952 | c4 = (const struct sockaddr_in *) &ca->ss; | ||
953 | if ((0 != c4->sin_addr.s_addr) && | ||
954 | (l4->sin_addr.s_addr != c4->sin_addr.s_addr)) | ||
955 | continue; | ||
956 | match = GNUNET_YES; | ||
957 | break; | ||
958 | } | ||
959 | if (! match) | ||
960 | continue; | ||
961 | |||
962 | /* Notify applicable client about connection reversal request */ | ||
963 | env = GNUNET_MQ_msg_extra (crrm, | ||
964 | sizeof(struct sockaddr_in), | ||
965 | GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED); | ||
966 | GNUNET_memcpy (&crrm[1], | ||
967 | ra, | ||
968 | sizeof(struct sockaddr_in)); | ||
969 | GNUNET_MQ_send (ch->mq, | ||
970 | env); | ||
971 | } | ||
972 | } | ||
973 | |||
974 | |||
975 | /** | ||
976 | * Task we run periodically to scan for network interfaces. | ||
977 | * | ||
978 | * @param cls NULL | ||
979 | */ | ||
980 | static void | ||
981 | run_scan (void *cls) | ||
982 | { | ||
983 | struct IfcProcContext ifc_ctx; | ||
984 | int found; | ||
985 | int have_nat; | ||
986 | struct LocalAddressList *lnext; | ||
987 | |||
988 | scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ, | ||
989 | &run_scan, | ||
990 | NULL); | ||
991 | memset (&ifc_ctx, | ||
992 | 0, | ||
993 | sizeof(ifc_ctx)); | ||
994 | GNUNET_OS_network_interfaces_list (&ifc_proc, | ||
995 | &ifc_ctx); | ||
996 | /* remove addresses that disappeared */ | ||
997 | for (struct LocalAddressList *lal = lal_head; | ||
998 | NULL != lal; | ||
999 | lal = lnext) | ||
1000 | { | ||
1001 | lnext = lal->next; | ||
1002 | found = GNUNET_NO; | ||
1003 | for (struct LocalAddressList *pos = ifc_ctx.lal_head; | ||
1004 | NULL != pos; | ||
1005 | pos = pos->next) | ||
1006 | { | ||
1007 | if ((pos->af == lal->af) && | ||
1008 | (0 == memcmp (&lal->addr, | ||
1009 | &pos->addr, | ||
1010 | (AF_INET == lal->af) | ||
1011 | ? sizeof(struct sockaddr_in) | ||
1012 | : sizeof(struct sockaddr_in6)))) | ||
1013 | { | ||
1014 | found = GNUNET_YES; | ||
1015 | } | ||
1016 | } | ||
1017 | if (GNUNET_NO == found) | ||
1018 | { | ||
1019 | notify_clients (lal, | ||
1020 | GNUNET_NO); | ||
1021 | free_lal (lal); | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | /* add addresses that appeared */ | ||
1026 | have_nat = GNUNET_NO; | ||
1027 | for (struct LocalAddressList *pos = ifc_ctx.lal_head; | ||
1028 | NULL != pos; | ||
1029 | pos = ifc_ctx.lal_head) | ||
1030 | { | ||
1031 | found = GNUNET_NO; | ||
1032 | if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac)) | ||
1033 | have_nat = GNUNET_YES; | ||
1034 | for (struct LocalAddressList *lal = lal_head; | ||
1035 | NULL != lal; | ||
1036 | lal = lal->next) | ||
1037 | { | ||
1038 | if ((pos->af == lal->af) && | ||
1039 | (0 == memcmp (&lal->addr, | ||
1040 | &pos->addr, | ||
1041 | (AF_INET == lal->af) | ||
1042 | ? sizeof(struct sockaddr_in) | ||
1043 | : sizeof(struct sockaddr_in6)))) | ||
1044 | found = GNUNET_YES; | ||
1045 | } | ||
1046 | GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head, | ||
1047 | ifc_ctx.lal_tail, | ||
1048 | pos); | ||
1049 | if (GNUNET_YES == found) | ||
1050 | { | ||
1051 | GNUNET_free (pos); | ||
1052 | } | ||
1053 | else | ||
1054 | { | ||
1055 | notify_clients (pos, | ||
1056 | GNUNET_YES); | ||
1057 | GNUNET_CONTAINER_DLL_insert (lal_head, | ||
1058 | lal_tail, | ||
1059 | pos); | ||
1060 | if ((AF_INET == pos->af) && | ||
1061 | (NULL == pos->hc) && | ||
1062 | (0 != (GNUNET_NAT_AC_LAN & pos->ac))) | ||
1063 | { | ||
1064 | const struct sockaddr_in *s4 | ||
1065 | = (const struct sockaddr_in *) &pos->addr; | ||
1066 | |||
1067 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1068 | "Found NATed local address %s, starting NAT server\n", | ||
1069 | GNUNET_a2s ((const struct sockaddr *) &pos->addr, | ||
1070 | sizeof(*s4))); | ||
1071 | pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr, | ||
1072 | &reversal_callback, | ||
1073 | pos, | ||
1074 | cfg); | ||
1075 | } | ||
1076 | } | ||
1077 | } | ||
1078 | GN_nat_status_changed (have_nat); | ||
1079 | } | ||
1080 | |||
1081 | |||
1082 | /** | ||
1083 | * Function called whenever our set of external addresses | ||
1084 | * as created by `upnpc` changes. | ||
1085 | * | ||
1086 | * @param cls closure with our `struct ClientHandle *` | ||
1087 | * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean | ||
1088 | * the previous (now invalid) one, #GNUNET_SYSERR indicates an error | ||
1089 | * @param addr either the previous or the new public IP address | ||
1090 | * @param addrlen actual length of the @a addr | ||
1091 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code | ||
1092 | */ | ||
1093 | static void | ||
1094 | upnp_addr_change_cb (void *cls, | ||
1095 | int add_remove, | ||
1096 | const struct sockaddr *addr, | ||
1097 | socklen_t addrlen, | ||
1098 | enum GNUNET_NAT_StatusCode result) | ||
1099 | { | ||
1100 | struct ClientHandle *ch = cls; | ||
1101 | enum GNUNET_NAT_AddressClass ac; | ||
1102 | |||
1103 | switch (result) | ||
1104 | { | ||
1105 | case GNUNET_NAT_ERROR_SUCCESS: | ||
1106 | GNUNET_assert (NULL != addr); | ||
1107 | break; | ||
1108 | |||
1109 | case GNUNET_NAT_ERROR_UPNPC_FAILED: | ||
1110 | case GNUNET_NAT_ERROR_UPNPC_TIMEOUT: | ||
1111 | case GNUNET_NAT_ERROR_IPC_FAILURE: | ||
1112 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1113 | "Running upnpc failed: %d\n", | ||
1114 | result); | ||
1115 | return; | ||
1116 | |||
1117 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND: | ||
1118 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1119 | "external-ip binary not found\n"); | ||
1120 | return; | ||
1121 | |||
1122 | case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND: | ||
1123 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1124 | "upnpc binary not found\n"); | ||
1125 | return; | ||
1126 | |||
1127 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED: | ||
1128 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1129 | "external-ip binary could not be run\n"); | ||
1130 | return; | ||
1131 | |||
1132 | case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED: | ||
1133 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1134 | "upnpc failed to create port mapping\n"); | ||
1135 | return; | ||
1136 | |||
1137 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID: | ||
1138 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1139 | "Invalid output from upnpc\n"); | ||
1140 | return; | ||
1141 | |||
1142 | case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID: | ||
1143 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1144 | "Invalid address returned by upnpc\n"); | ||
1145 | return; | ||
1146 | |||
1147 | default: | ||
1148 | GNUNET_break (0); /* should not be possible */ | ||
1149 | return; | ||
1150 | } | ||
1151 | switch (addr->sa_family) | ||
1152 | { | ||
1153 | case AF_INET: | ||
1154 | ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr) | ||
1155 | ? GNUNET_NAT_AC_LAN | ||
1156 | : GNUNET_NAT_AC_EXTERN; | ||
1157 | break; | ||
1158 | |||
1159 | case AF_INET6: | ||
1160 | ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr) | ||
1161 | ? GNUNET_NAT_AC_LAN | ||
1162 | : GNUNET_NAT_AC_EXTERN; | ||
1163 | break; | ||
1164 | |||
1165 | default: | ||
1166 | GNUNET_break (0); | ||
1167 | return; | ||
1168 | } | ||
1169 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1170 | "upnp external address %s: %s\n", | ||
1171 | add_remove ? "added" : "removed", | ||
1172 | GNUNET_a2s (addr, | ||
1173 | addrlen)); | ||
1174 | notify_client (ac, | ||
1175 | ch, | ||
1176 | add_remove, | ||
1177 | addr, | ||
1178 | addrlen); | ||
1179 | } | ||
1180 | |||
1181 | |||
1182 | /** | ||
1183 | * Resolve the `hole_external` name to figure out our | ||
1184 | * external address from a manually punched hole. The | ||
1185 | * port number has already been parsed, this task is | ||
1186 | * responsible for periodically doing a DNS lookup. | ||
1187 | * | ||
1188 | * @param ch client handle to act upon | ||
1189 | */ | ||
1190 | static void | ||
1191 | dyndns_lookup (void *cls); | ||
1192 | |||
1193 | |||
1194 | /** | ||
1195 | * Our (external) hostname was resolved. Update lists of | ||
1196 | * current external IPs (note that DNS may return multiple | ||
1197 | * addresses!) and notify client accordingly. | ||
1198 | * | ||
1199 | * @param cls the `struct ClientHandle` | ||
1200 | * @param addr NULL on error, otherwise result of DNS lookup | ||
1201 | * @param addrlen number of bytes in @a addr | ||
1202 | */ | ||
1203 | static void | ||
1204 | process_external_ip (void *cls, | ||
1205 | const struct sockaddr *addr, | ||
1206 | socklen_t addrlen) | ||
1207 | { | ||
1208 | struct ClientHandle *ch = cls; | ||
1209 | struct LocalAddressList *lal; | ||
1210 | struct sockaddr_storage ss; | ||
1211 | struct sockaddr_in *v4; | ||
1212 | struct sockaddr_in6 *v6; | ||
1213 | |||
1214 | if (NULL == addr) | ||
1215 | { | ||
1216 | struct LocalAddressList *laln; | ||
1217 | |||
1218 | ch->ext_dns = NULL; | ||
1219 | ch->ext_dns_task | ||
1220 | = GNUNET_SCHEDULER_add_delayed (dyndns_frequency, | ||
1221 | &dyndns_lookup, | ||
1222 | ch); | ||
1223 | /* Current iteration is over, remove 'old' IPs now */ | ||
1224 | for (lal = ch->ext_addr_head; NULL != lal; lal = laln) | ||
1225 | { | ||
1226 | laln = lal->next; | ||
1227 | if (GNUNET_YES == lal->old) | ||
1228 | { | ||
1229 | GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head, | ||
1230 | ch->ext_addr_tail, | ||
1231 | lal); | ||
1232 | check_notify_client (lal, | ||
1233 | ch, | ||
1234 | GNUNET_NO); | ||
1235 | GNUNET_free (lal); | ||
1236 | } | ||
1237 | } | ||
1238 | return; | ||
1239 | } | ||
1240 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1241 | "Got IP `%s' for external address `%s'\n", | ||
1242 | GNUNET_a2s (addr, | ||
1243 | addrlen), | ||
1244 | ch->hole_external); | ||
1245 | |||
1246 | /* build sockaddr storage with port number */ | ||
1247 | memset (&ss, | ||
1248 | 0, | ||
1249 | sizeof(ss)); | ||
1250 | GNUNET_memcpy (&ss, | ||
1251 | addr, | ||
1252 | addrlen); | ||
1253 | switch (addr->sa_family) | ||
1254 | { | ||
1255 | case AF_INET: | ||
1256 | v4 = (struct sockaddr_in *) &ss; | ||
1257 | v4->sin_port = htons (ch->ext_dns_port); | ||
1258 | break; | ||
1259 | |||
1260 | case AF_INET6: | ||
1261 | v6 = (struct sockaddr_in6 *) &ss; | ||
1262 | v6->sin6_port = htons (ch->ext_dns_port); | ||
1263 | break; | ||
1264 | |||
1265 | default: | ||
1266 | GNUNET_break (0); | ||
1267 | return; | ||
1268 | } | ||
1269 | /* See if 'ss' matches any of our known addresses */ | ||
1270 | for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next) | ||
1271 | { | ||
1272 | if (GNUNET_NO == lal->old) | ||
1273 | continue; /* already processed, skip */ | ||
1274 | if ((addr->sa_family == lal->addr.ss_family) && | ||
1275 | (0 == memcmp (&ss, | ||
1276 | &lal->addr, | ||
1277 | addrlen))) | ||
1278 | { | ||
1279 | /* Address unchanged, remember so we do not remove */ | ||
1280 | lal->old = GNUNET_NO; | ||
1281 | return; /* done here */ | ||
1282 | } | ||
1283 | } | ||
1284 | /* notify client, and remember IP for later removal! */ | ||
1285 | lal = GNUNET_new (struct LocalAddressList); | ||
1286 | lal->addr = ss; | ||
1287 | lal->af = ss.ss_family; | ||
1288 | lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL; | ||
1289 | GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head, | ||
1290 | ch->ext_addr_tail, | ||
1291 | lal); | ||
1292 | check_notify_client (lal, | ||
1293 | ch, | ||
1294 | GNUNET_YES); | ||
1295 | } | ||
1296 | |||
1297 | |||
1298 | /** | ||
1299 | * Resolve the `hole_external` name to figure out our | ||
1300 | * external address from a manually punched hole. The | ||
1301 | * port number has already been parsed, this task is | ||
1302 | * responsible for periodically doing a DNS lookup. | ||
1303 | * | ||
1304 | * @param ch client handle to act upon | ||
1305 | */ | ||
1306 | static void | ||
1307 | dyndns_lookup (void *cls) | ||
1308 | { | ||
1309 | struct ClientHandle *ch = cls; | ||
1310 | struct LocalAddressList *lal; | ||
1311 | |||
1312 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1313 | "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n", | ||
1314 | ch->section_name, | ||
1315 | ch->hole_external, | ||
1316 | (unsigned int) ch->ext_dns_port); | ||
1317 | for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next) | ||
1318 | lal->old = GNUNET_YES; | ||
1319 | ch->ext_dns_task = NULL; | ||
1320 | ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external, | ||
1321 | AF_UNSPEC, | ||
1322 | GNUNET_TIME_UNIT_MINUTES, | ||
1323 | &process_external_ip, | ||
1324 | ch); | ||
1325 | } | ||
1326 | |||
1327 | |||
1328 | /** | ||
1329 | * Resolve the `hole_external` name to figure out our | ||
1330 | * external address from a manually punched hole. The | ||
1331 | * given name may be "AUTO" in which case we should use | ||
1332 | * the IP address(es) we have from upnpc or other methods. | ||
1333 | * The name can also be an IP address, in which case we | ||
1334 | * do not need to do DNS resolution. Finally, we also | ||
1335 | * need to parse the port number. | ||
1336 | * | ||
1337 | * @param ch client handle to act upon | ||
1338 | */ | ||
1339 | static void | ||
1340 | lookup_hole_external (struct ClientHandle *ch) | ||
1341 | { | ||
1342 | char *port; | ||
1343 | unsigned int pnum; | ||
1344 | struct sockaddr_in *s4; | ||
1345 | struct LocalAddressList *lal; | ||
1346 | |||
1347 | port = strrchr (ch->hole_external, ':'); | ||
1348 | if (NULL == port) | ||
1349 | { | ||
1350 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1351 | _ ("Malformed punched hole specification `%s' (lacks port)\n"), | ||
1352 | ch->hole_external); | ||
1353 | return; | ||
1354 | } | ||
1355 | if ((1 != sscanf (port + 1, | ||
1356 | "%u", | ||
1357 | &pnum)) || | ||
1358 | (pnum > 65535)) | ||
1359 | { | ||
1360 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1361 | _ ( | ||
1362 | "Invalid port number in punched hole specification `%s' (lacks port)\n"), | ||
1363 | port + 1); | ||
1364 | return; | ||
1365 | } | ||
1366 | ch->ext_dns_port = (uint16_t) pnum; | ||
1367 | *port = '\0'; | ||
1368 | |||
1369 | lal = GNUNET_new (struct LocalAddressList); | ||
1370 | if ('[' == *ch->hole_external) | ||
1371 | { | ||
1372 | struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr; | ||
1373 | |||
1374 | s6->sin6_family = AF_INET6; | ||
1375 | if (']' != (ch->hole_external[strlen (ch->hole_external) - 1])) | ||
1376 | { | ||
1377 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1378 | _ ("Malformed punched hole specification `%s' (lacks `]')\n"), | ||
1379 | ch->hole_external); | ||
1380 | GNUNET_free (lal); | ||
1381 | return; | ||
1382 | } | ||
1383 | ch->hole_external[strlen (ch->hole_external) - 1] = '\0'; | ||
1384 | if (1 != inet_pton (AF_INET6, | ||
1385 | ch->hole_external + 1, | ||
1386 | &s6->sin6_addr)) | ||
1387 | { | ||
1388 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1389 | _ ( | ||
1390 | "Malformed punched hole specification `%s' (IPv6 address invalid)"), | ||
1391 | ch->hole_external + 1); | ||
1392 | GNUNET_free (lal); | ||
1393 | return; | ||
1394 | } | ||
1395 | s6->sin6_port = htons (ch->ext_dns_port); | ||
1396 | lal->af = AF_INET6; | ||
1397 | lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL; | ||
1398 | GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head, | ||
1399 | ch->ext_addr_tail, | ||
1400 | lal); | ||
1401 | check_notify_client (lal, | ||
1402 | ch, | ||
1403 | GNUNET_YES); | ||
1404 | return; | ||
1405 | } | ||
1406 | |||
1407 | s4 = (struct sockaddr_in *) &lal->addr; | ||
1408 | s4->sin_family = AF_INET; | ||
1409 | if (1 == inet_pton (AF_INET, | ||
1410 | ch->hole_external, | ||
1411 | &s4->sin_addr)) | ||
1412 | { | ||
1413 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1414 | "IPv4 punched hole given for `%s' via `%s:%u'\n", | ||
1415 | ch->section_name, | ||
1416 | ch->hole_external, | ||
1417 | (unsigned int) ch->ext_dns_port); | ||
1418 | s4->sin_port = htons (ch->ext_dns_port); | ||
1419 | lal->af = AF_INET; | ||
1420 | lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL; | ||
1421 | GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head, | ||
1422 | ch->ext_addr_tail, | ||
1423 | lal); | ||
1424 | check_notify_client (lal, | ||
1425 | ch, | ||
1426 | GNUNET_YES); | ||
1427 | return; | ||
1428 | } | ||
1429 | if (0 == strcasecmp (ch->hole_external, | ||
1430 | "AUTO")) | ||
1431 | { | ||
1432 | /* handled in #notify_client_external_ipv4_change() */ | ||
1433 | GNUNET_free (lal); | ||
1434 | return; | ||
1435 | } | ||
1436 | /* got a DNS name, trigger lookup! */ | ||
1437 | GNUNET_free (lal); | ||
1438 | ch->ext_dns_task | ||
1439 | = GNUNET_SCHEDULER_add_now (&dyndns_lookup, | ||
1440 | ch); | ||
1441 | } | ||
1442 | |||
1443 | |||
1444 | /** | ||
1445 | * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client. | ||
1446 | * We remember the client for updates upon future NAT events. | ||
1447 | * | ||
1448 | * @param cls client who sent the message | ||
1449 | * @param message the message received | ||
1450 | */ | ||
1451 | static void | ||
1452 | handle_register (void *cls, | ||
1453 | const struct GNUNET_NAT_RegisterMessage *message) | ||
1454 | { | ||
1455 | struct ClientHandle *ch = cls; | ||
1456 | const char *off; | ||
1457 | size_t left; | ||
1458 | |||
1459 | if ((0 != ch->proto) || | ||
1460 | (NULL != ch->caddrs)) | ||
1461 | { | ||
1462 | /* double registration not allowed */ | ||
1463 | GNUNET_break (0); | ||
1464 | GNUNET_SERVICE_client_drop (ch->client); | ||
1465 | return; | ||
1466 | } | ||
1467 | ch->flags = message->flags; | ||
1468 | ch->proto = message->proto; | ||
1469 | ch->num_caddrs = ntohs (message->num_addrs); | ||
1470 | ch->caddrs = GNUNET_new_array (ch->num_caddrs, | ||
1471 | struct ClientAddress); | ||
1472 | left = ntohs (message->header.size) - sizeof(*message); | ||
1473 | off = (const char *) &message[1]; | ||
1474 | for (unsigned int i = 0; i < ch->num_caddrs; i++) | ||
1475 | { | ||
1476 | const struct sockaddr *sa = (const struct sockaddr *) off; | ||
1477 | size_t alen; | ||
1478 | uint16_t port; | ||
1479 | int is_nat; | ||
1480 | |||
1481 | if (sizeof(sa_family_t) > left) | ||
1482 | { | ||
1483 | GNUNET_break (0); | ||
1484 | GNUNET_SERVICE_client_drop (ch->client); | ||
1485 | return; | ||
1486 | } | ||
1487 | is_nat = GNUNET_NO; | ||
1488 | switch (sa->sa_family) | ||
1489 | { | ||
1490 | case AF_INET: | ||
1491 | { | ||
1492 | struct sockaddr_in s4; | ||
1493 | |||
1494 | GNUNET_memcpy (&s4, | ||
1495 | off, | ||
1496 | sizeof(struct sockaddr_in)); | ||
1497 | alen = sizeof(struct sockaddr_in); | ||
1498 | if (is_nat_v4 (&s4.sin_addr)) | ||
1499 | is_nat = GNUNET_YES; | ||
1500 | port = ntohs (s4.sin_port); | ||
1501 | } | ||
1502 | break; | ||
1503 | |||
1504 | case AF_INET6: | ||
1505 | { | ||
1506 | struct sockaddr_in6 s6; | ||
1507 | |||
1508 | GNUNET_memcpy (&s6, | ||
1509 | off, | ||
1510 | sizeof(struct sockaddr_in6)); | ||
1511 | alen = sizeof(struct sockaddr_in6); | ||
1512 | if (is_nat_v6 (&s6.sin6_addr)) | ||
1513 | is_nat = GNUNET_YES; | ||
1514 | port = ntohs (s6.sin6_port); | ||
1515 | } | ||
1516 | break; | ||
1517 | |||
1518 | #if AF_UNIX | ||
1519 | case AF_UNIX: | ||
1520 | alen = sizeof(struct sockaddr_un); | ||
1521 | port = 0; | ||
1522 | break; | ||
1523 | #endif | ||
1524 | default: | ||
1525 | GNUNET_break (0); | ||
1526 | GNUNET_SERVICE_client_drop (ch->client); | ||
1527 | return; | ||
1528 | } | ||
1529 | /* store address */ | ||
1530 | GNUNET_assert (alen <= left); | ||
1531 | GNUNET_assert (alen <= sizeof(struct sockaddr_storage)); | ||
1532 | GNUNET_memcpy (&ch->caddrs[i].ss, | ||
1533 | off, | ||
1534 | alen); | ||
1535 | |||
1536 | /* If applicable, try UPNPC NAT punching */ | ||
1537 | if ((is_nat) && | ||
1538 | (enable_upnp) && | ||
1539 | ((IPPROTO_TCP == ch->proto) || | ||
1540 | (IPPROTO_UDP == ch->proto))) | ||
1541 | { | ||
1542 | ch->natted_address = GNUNET_YES; | ||
1543 | ch->caddrs[i].mh | ||
1544 | = GNUNET_NAT_mini_map_start (port, | ||
1545 | IPPROTO_TCP == ch->proto, | ||
1546 | &upnp_addr_change_cb, | ||
1547 | ch); | ||
1548 | } | ||
1549 | |||
1550 | off += alen; | ||
1551 | } | ||
1552 | |||
1553 | ch->section_name | ||
1554 | = GNUNET_strndup (off, | ||
1555 | ntohs (message->str_len)); | ||
1556 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1557 | "Received REGISTER message from client for subsystem `%s'\n", | ||
1558 | ch->section_name); | ||
1559 | if (GNUNET_OK == | ||
1560 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
1561 | ch->section_name, | ||
1562 | "HOLE_EXTERNAL", | ||
1563 | &ch->hole_external)) | ||
1564 | lookup_hole_external (ch); | ||
1565 | |||
1566 | /* Actually send IP address list to client */ | ||
1567 | for (struct LocalAddressList *lal = lal_head; | ||
1568 | NULL != lal; | ||
1569 | lal = lal->next) | ||
1570 | { | ||
1571 | check_notify_client (lal, | ||
1572 | ch, | ||
1573 | GNUNET_YES); | ||
1574 | } | ||
1575 | /* Also consider IPv4 determined by `external-ip` */ | ||
1576 | ch->external_monitor | ||
1577 | = GN_external_ipv4_monitor_start (¬ify_client_external_ipv4_change, | ||
1578 | ch); | ||
1579 | GNUNET_SERVICE_client_continue (ch->client); | ||
1580 | } | ||
1581 | |||
1582 | |||
1583 | /** | ||
1584 | * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from | ||
1585 | * client. | ||
1586 | * | ||
1587 | * @param cls client who sent the message | ||
1588 | * @param message the message received | ||
1589 | * @return #GNUNET_OK if message is well-formed | ||
1590 | */ | ||
1591 | static int | ||
1592 | check_stun (void *cls, | ||
1593 | const struct GNUNET_NAT_HandleStunMessage *message) | ||
1594 | { | ||
1595 | size_t sa_len = ntohs (message->sender_addr_size); | ||
1596 | size_t expect = sa_len + ntohs (message->payload_size); | ||
1597 | |||
1598 | if (ntohs (message->header.size) - sizeof(*message) != expect) | ||
1599 | { | ||
1600 | GNUNET_break (0); | ||
1601 | return GNUNET_SYSERR; | ||
1602 | } | ||
1603 | if (sa_len < sizeof(sa_family_t)) | ||
1604 | { | ||
1605 | GNUNET_break (0); | ||
1606 | return GNUNET_SYSERR; | ||
1607 | } | ||
1608 | return GNUNET_OK; | ||
1609 | } | ||
1610 | |||
1611 | |||
1612 | /** | ||
1613 | * Notify all clients about our external IP address | ||
1614 | * as reported by the STUN server. | ||
1615 | * | ||
1616 | * @param ip the external IP | ||
1617 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
1618 | */ | ||
1619 | static void | ||
1620 | notify_clients_stun_change (const struct sockaddr_in *ip, | ||
1621 | int add) | ||
1622 | { | ||
1623 | for (struct ClientHandle *ch = ch_head; | ||
1624 | NULL != ch; | ||
1625 | ch = ch->next) | ||
1626 | { | ||
1627 | struct sockaddr_in v4; | ||
1628 | struct GNUNET_NAT_AddressChangeNotificationMessage *msg; | ||
1629 | struct GNUNET_MQ_Envelope *env; | ||
1630 | |||
1631 | if (! ch->natted_address) | ||
1632 | continue; | ||
1633 | v4 = *ip; | ||
1634 | v4.sin_port = htons (0); | ||
1635 | env = GNUNET_MQ_msg_extra (msg, | ||
1636 | sizeof(v4), | ||
1637 | GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); | ||
1638 | msg->add_remove = htonl ((int32_t) add); | ||
1639 | msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN | ||
1640 | | GNUNET_NAT_AC_GLOBAL); | ||
1641 | GNUNET_memcpy (&msg[1], | ||
1642 | &v4, | ||
1643 | sizeof(v4)); | ||
1644 | GNUNET_MQ_send (ch->mq, | ||
1645 | env); | ||
1646 | } | ||
1647 | } | ||
1648 | |||
1649 | |||
1650 | /** | ||
1651 | * Function to be called when we decide that an | ||
1652 | * external IP address as told to us by a STUN | ||
1653 | * server has gone stale. | ||
1654 | * | ||
1655 | * @param cls the `struct StunExternalIP` to drop | ||
1656 | */ | ||
1657 | static void | ||
1658 | stun_ip_timeout (void *cls) | ||
1659 | { | ||
1660 | struct StunExternalIP *se = cls; | ||
1661 | |||
1662 | se->timeout_task = NULL; | ||
1663 | notify_clients_stun_change (&se->external_addr, | ||
1664 | GNUNET_NO); | ||
1665 | GNUNET_CONTAINER_DLL_remove (se_head, | ||
1666 | se_tail, | ||
1667 | se); | ||
1668 | GNUNET_free (se); | ||
1669 | } | ||
1670 | |||
1671 | |||
1672 | /** | ||
1673 | * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from | ||
1674 | * client. | ||
1675 | * | ||
1676 | * @param cls client who sent the message | ||
1677 | * @param message the message received | ||
1678 | */ | ||
1679 | static void | ||
1680 | handle_stun (void *cls, | ||
1681 | const struct GNUNET_NAT_HandleStunMessage *message) | ||
1682 | { | ||
1683 | struct ClientHandle *ch = cls; | ||
1684 | const char *buf = (const char *) &message[1]; | ||
1685 | const struct sockaddr *sa; | ||
1686 | const void *payload; | ||
1687 | size_t sa_len; | ||
1688 | size_t payload_size; | ||
1689 | struct sockaddr_in external_addr; | ||
1690 | |||
1691 | sa_len = ntohs (message->sender_addr_size); | ||
1692 | payload_size = ntohs (message->payload_size); | ||
1693 | sa = (const struct sockaddr *) &buf[0]; | ||
1694 | payload = (const struct sockaddr *) &buf[sa_len]; | ||
1695 | switch (sa->sa_family) | ||
1696 | { | ||
1697 | case AF_INET: | ||
1698 | if (sa_len != sizeof(struct sockaddr_in)) | ||
1699 | { | ||
1700 | GNUNET_break (0); | ||
1701 | GNUNET_SERVICE_client_drop (ch->client); | ||
1702 | return; | ||
1703 | } | ||
1704 | break; | ||
1705 | |||
1706 | case AF_INET6: | ||
1707 | if (sa_len != sizeof(struct sockaddr_in6)) | ||
1708 | { | ||
1709 | GNUNET_break (0); | ||
1710 | GNUNET_SERVICE_client_drop (ch->client); | ||
1711 | return; | ||
1712 | } | ||
1713 | break; | ||
1714 | } | ||
1715 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1716 | "Received HANDLE_STUN message from client\n"); | ||
1717 | if (GNUNET_OK == | ||
1718 | GNUNET_NAT_stun_handle_packet_ (payload, | ||
1719 | payload_size, | ||
1720 | &external_addr)) | ||
1721 | { | ||
1722 | /* We now know that a server at "sa" claims that | ||
1723 | we are visible at IP "external_addr". | ||
1724 | |||
1725 | We should (for some fixed period of time) tell | ||
1726 | all of our clients that listen to a NAT'ed address | ||
1727 | that they might want to consider the given 'external_ip' | ||
1728 | as their public IP address (this includes TCP and UDP | ||
1729 | clients, even if only UDP sends STUN requests). | ||
1730 | |||
1731 | If we do not get a renewal, the "external_addr" should be | ||
1732 | removed again. The timeout frequency should be configurable | ||
1733 | (with a sane default), so that the UDP plugin can tell how | ||
1734 | often to re-request STUN. | ||
1735 | */struct StunExternalIP *se; | ||
1736 | |||
1737 | /* Check if we had a prior response from this STUN server */ | ||
1738 | for (se = se_head; NULL != se; se = se->next) | ||
1739 | { | ||
1740 | if ((se->stun_server_addr_len != sa_len) || | ||
1741 | (0 != memcmp (sa, | ||
1742 | &se->stun_server_addr, | ||
1743 | sa_len))) | ||
1744 | continue; /* different STUN server */ | ||
1745 | if (0 != GNUNET_memcmp (&external_addr, | ||
1746 | &se->external_addr)) | ||
1747 | { | ||
1748 | /* external IP changed, update! */ | ||
1749 | notify_clients_stun_change (&se->external_addr, | ||
1750 | GNUNET_NO); | ||
1751 | se->external_addr = external_addr; | ||
1752 | notify_clients_stun_change (&se->external_addr, | ||
1753 | GNUNET_YES); | ||
1754 | } | ||
1755 | /* update timeout */ | ||
1756 | GNUNET_SCHEDULER_cancel (se->timeout_task); | ||
1757 | se->timeout_task | ||
1758 | = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout, | ||
1759 | &stun_ip_timeout, | ||
1760 | se); | ||
1761 | return; | ||
1762 | } | ||
1763 | /* STUN server is completely new, create fresh entry */ | ||
1764 | se = GNUNET_new (struct StunExternalIP); | ||
1765 | se->external_addr = external_addr; | ||
1766 | GNUNET_memcpy (&se->stun_server_addr, | ||
1767 | sa, | ||
1768 | sa_len); | ||
1769 | se->stun_server_addr_len = sa_len; | ||
1770 | se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout, | ||
1771 | &stun_ip_timeout, | ||
1772 | se); | ||
1773 | GNUNET_CONTAINER_DLL_insert (se_head, | ||
1774 | se_tail, | ||
1775 | se); | ||
1776 | notify_clients_stun_change (&se->external_addr, | ||
1777 | GNUNET_NO); | ||
1778 | } | ||
1779 | GNUNET_SERVICE_client_continue (ch->client); | ||
1780 | } | ||
1781 | |||
1782 | |||
1783 | /** | ||
1784 | * Check validity of | ||
1785 | * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from | ||
1786 | * client. | ||
1787 | * | ||
1788 | * @param cls client who sent the message | ||
1789 | * @param message the message received | ||
1790 | * @return #GNUNET_OK if message is well-formed | ||
1791 | */ | ||
1792 | static int | ||
1793 | check_request_connection_reversal (void *cls, | ||
1794 | const struct | ||
1795 | GNUNET_NAT_RequestConnectionReversalMessage * | ||
1796 | message) | ||
1797 | { | ||
1798 | size_t expect; | ||
1799 | |||
1800 | expect = ntohs (message->local_addr_size) | ||
1801 | + ntohs (message->remote_addr_size); | ||
1802 | if (ntohs (message->header.size) - sizeof(*message) != expect) | ||
1803 | { | ||
1804 | GNUNET_break (0); | ||
1805 | return GNUNET_SYSERR; | ||
1806 | } | ||
1807 | return GNUNET_OK; | ||
1808 | } | ||
1809 | |||
1810 | |||
1811 | /** | ||
1812 | * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL | ||
1813 | * message from client. | ||
1814 | * | ||
1815 | * @param cls client who sent the message | ||
1816 | * @param message the message received | ||
1817 | */ | ||
1818 | static void | ||
1819 | handle_request_connection_reversal (void *cls, | ||
1820 | const struct | ||
1821 | GNUNET_NAT_RequestConnectionReversalMessage | ||
1822 | *message) | ||
1823 | { | ||
1824 | struct ClientHandle *ch = cls; | ||
1825 | const char *buf = (const char *) &message[1]; | ||
1826 | size_t local_sa_len = ntohs (message->local_addr_size); | ||
1827 | size_t remote_sa_len = ntohs (message->remote_addr_size); | ||
1828 | struct sockaddr_in l4; | ||
1829 | struct sockaddr_in r4; | ||
1830 | int ret; | ||
1831 | |||
1832 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1833 | "Received REQUEST CONNECTION REVERSAL message from client\n"); | ||
1834 | if (local_sa_len != sizeof(struct sockaddr_in)) | ||
1835 | { | ||
1836 | GNUNET_break_op (0); | ||
1837 | GNUNET_SERVICE_client_drop (ch->client); | ||
1838 | return; | ||
1839 | } | ||
1840 | if (remote_sa_len != sizeof(struct sockaddr_in)) | ||
1841 | { | ||
1842 | GNUNET_break_op (0); | ||
1843 | GNUNET_SERVICE_client_drop (ch->client); | ||
1844 | return; | ||
1845 | } | ||
1846 | GNUNET_memcpy (&l4, | ||
1847 | buf, | ||
1848 | sizeof(struct sockaddr_in)); | ||
1849 | GNUNET_break_op (AF_INET == l4.sin_family); | ||
1850 | buf += sizeof(struct sockaddr_in); | ||
1851 | GNUNET_memcpy (&r4, | ||
1852 | buf, | ||
1853 | sizeof(struct sockaddr_in)); | ||
1854 | GNUNET_break_op (AF_INET == r4.sin_family); | ||
1855 | ret = GN_request_connection_reversal (&l4.sin_addr, | ||
1856 | ntohs (l4.sin_port), | ||
1857 | &r4.sin_addr, | ||
1858 | cfg); | ||
1859 | if (GNUNET_OK != ret) | ||
1860 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1861 | _ ("Connection reversal request failed\n")); | ||
1862 | GNUNET_SERVICE_client_continue (ch->client); | ||
1863 | } | ||
1864 | |||
1865 | |||
1866 | /** | ||
1867 | * Task run during shutdown. | ||
1868 | * | ||
1869 | * @param cls unused | ||
1870 | */ | ||
1871 | static void | ||
1872 | shutdown_task (void *cls) | ||
1873 | { | ||
1874 | struct StunExternalIP *se; | ||
1875 | |||
1876 | while (NULL != (se = se_head)) | ||
1877 | { | ||
1878 | GNUNET_CONTAINER_DLL_remove (se_head, | ||
1879 | se_tail, | ||
1880 | se); | ||
1881 | GNUNET_SCHEDULER_cancel (se->timeout_task); | ||
1882 | GNUNET_free (se); | ||
1883 | } | ||
1884 | GN_nat_status_changed (GNUNET_NO); | ||
1885 | if (NULL != scan_task) | ||
1886 | { | ||
1887 | GNUNET_SCHEDULER_cancel (scan_task); | ||
1888 | scan_task = NULL; | ||
1889 | } | ||
1890 | if (NULL != stats) | ||
1891 | { | ||
1892 | GNUNET_STATISTICS_destroy (stats, | ||
1893 | GNUNET_NO); | ||
1894 | stats = NULL; | ||
1895 | } | ||
1896 | destroy_lal (); | ||
1897 | } | ||
1898 | |||
1899 | |||
1900 | /** | ||
1901 | * Setup NAT service. | ||
1902 | * | ||
1903 | * @param cls closure | ||
1904 | * @param c configuration to use | ||
1905 | * @param service the initialized service | ||
1906 | */ | ||
1907 | static void | ||
1908 | run (void *cls, | ||
1909 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
1910 | struct GNUNET_SERVICE_Handle *service) | ||
1911 | { | ||
1912 | cfg = c; | ||
1913 | if (GNUNET_OK != | ||
1914 | GNUNET_CONFIGURATION_get_value_time (cfg, | ||
1915 | "NAT", | ||
1916 | "STUN_STALE", | ||
1917 | &stun_stale_timeout)) | ||
1918 | stun_stale_timeout = GNUNET_TIME_UNIT_HOURS; | ||
1919 | |||
1920 | /* Check for UPnP */ | ||
1921 | enable_upnp | ||
1922 | = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
1923 | "NAT", | ||
1924 | "ENABLE_UPNP"); | ||
1925 | if (GNUNET_YES == enable_upnp) | ||
1926 | { | ||
1927 | /* check if it works */ | ||
1928 | if (GNUNET_SYSERR == | ||
1929 | GNUNET_OS_check_helper_binary ("upnpc", | ||
1930 | GNUNET_NO, | ||
1931 | NULL)) | ||
1932 | { | ||
1933 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1934 | _ ( | ||
1935 | "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n")); | ||
1936 | enable_upnp = GNUNET_SYSERR; | ||
1937 | } | ||
1938 | } | ||
1939 | if (GNUNET_OK != | ||
1940 | GNUNET_CONFIGURATION_get_value_time (cfg, | ||
1941 | "nat", | ||
1942 | "DYNDNS_FREQUENCY", | ||
1943 | &dyndns_frequency)) | ||
1944 | dyndns_frequency = DYNDNS_FREQUENCY; | ||
1945 | |||
1946 | enable_ipscan | ||
1947 | = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
1948 | "NAT", | ||
1949 | "ENABLE_IPSCAN"); | ||
1950 | |||
1951 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
1952 | NULL); | ||
1953 | stats = GNUNET_STATISTICS_create ("nat", | ||
1954 | cfg); | ||
1955 | if (GNUNET_YES == enable_ipscan) | ||
1956 | scan_task = GNUNET_SCHEDULER_add_now (&run_scan, | ||
1957 | NULL); | ||
1958 | } | ||
1959 | |||
1960 | |||
1961 | /** | ||
1962 | * Callback called when a client connects to the service. | ||
1963 | * | ||
1964 | * @param cls closure for the service | ||
1965 | * @param c the new client that connected to the service | ||
1966 | * @param mq the message queue used to send messages to the client | ||
1967 | * @return a `struct ClientHandle` | ||
1968 | */ | ||
1969 | static void * | ||
1970 | client_connect_cb (void *cls, | ||
1971 | struct GNUNET_SERVICE_Client *c, | ||
1972 | struct GNUNET_MQ_Handle *mq) | ||
1973 | { | ||
1974 | struct ClientHandle *ch; | ||
1975 | |||
1976 | ch = GNUNET_new (struct ClientHandle); | ||
1977 | ch->mq = mq; | ||
1978 | ch->client = c; | ||
1979 | GNUNET_CONTAINER_DLL_insert (ch_head, | ||
1980 | ch_tail, | ||
1981 | ch); | ||
1982 | return ch; | ||
1983 | } | ||
1984 | |||
1985 | |||
1986 | /** | ||
1987 | * Callback called when a client disconnected from the service | ||
1988 | * | ||
1989 | * @param cls closure for the service | ||
1990 | * @param c the client that disconnected | ||
1991 | * @param internal_cls a `struct ClientHandle *` | ||
1992 | */ | ||
1993 | static void | ||
1994 | client_disconnect_cb (void *cls, | ||
1995 | struct GNUNET_SERVICE_Client *c, | ||
1996 | void *internal_cls) | ||
1997 | { | ||
1998 | struct ClientHandle *ch = internal_cls; | ||
1999 | struct LocalAddressList *lal; | ||
2000 | |||
2001 | GNUNET_CONTAINER_DLL_remove (ch_head, | ||
2002 | ch_tail, | ||
2003 | ch); | ||
2004 | for (unsigned int i = 0; i < ch->num_caddrs; i++) | ||
2005 | { | ||
2006 | if (NULL != ch->caddrs[i].mh) | ||
2007 | { | ||
2008 | GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh); | ||
2009 | ch->caddrs[i].mh = NULL; | ||
2010 | } | ||
2011 | } | ||
2012 | GNUNET_free (ch->caddrs); | ||
2013 | while (NULL != (lal = ch->ext_addr_head)) | ||
2014 | { | ||
2015 | GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head, | ||
2016 | ch->ext_addr_tail, | ||
2017 | lal); | ||
2018 | GNUNET_free (lal); | ||
2019 | } | ||
2020 | if (NULL != ch->ext_dns_task) | ||
2021 | { | ||
2022 | GNUNET_SCHEDULER_cancel (ch->ext_dns_task); | ||
2023 | ch->ext_dns_task = NULL; | ||
2024 | } | ||
2025 | if (NULL != ch->external_monitor) | ||
2026 | { | ||
2027 | GN_external_ipv4_monitor_stop (ch->external_monitor); | ||
2028 | ch->external_monitor = NULL; | ||
2029 | } | ||
2030 | if (NULL != ch->ext_dns) | ||
2031 | { | ||
2032 | GNUNET_RESOLVER_request_cancel (ch->ext_dns); | ||
2033 | ch->ext_dns = NULL; | ||
2034 | } | ||
2035 | GNUNET_free (ch->hole_external); | ||
2036 | GNUNET_free (ch->section_name); | ||
2037 | GNUNET_free (ch); | ||
2038 | } | ||
2039 | |||
2040 | |||
2041 | /** | ||
2042 | * Define "main" method using service macro. | ||
2043 | */ | ||
2044 | GNUNET_SERVICE_MAIN | ||
2045 | ("nat", | ||
2046 | GNUNET_SERVICE_OPTION_NONE, | ||
2047 | &run, | ||
2048 | &client_connect_cb, | ||
2049 | &client_disconnect_cb, | ||
2050 | NULL, | ||
2051 | GNUNET_MQ_hd_var_size (register, | ||
2052 | GNUNET_MESSAGE_TYPE_NAT_REGISTER, | ||
2053 | struct GNUNET_NAT_RegisterMessage, | ||
2054 | NULL), | ||
2055 | GNUNET_MQ_hd_var_size (stun, | ||
2056 | GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN, | ||
2057 | struct GNUNET_NAT_HandleStunMessage, | ||
2058 | NULL), | ||
2059 | GNUNET_MQ_hd_var_size (request_connection_reversal, | ||
2060 | GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL, | ||
2061 | struct GNUNET_NAT_RequestConnectionReversalMessage, | ||
2062 | NULL), | ||
2063 | GNUNET_MQ_handler_end ()); | ||
2064 | |||
2065 | |||
2066 | #if defined(__linux__) && defined(__GLIBC__) | ||
2067 | #include <malloc.h> | ||
2068 | |||
2069 | /** | ||
2070 | * MINIMIZE heap size (way below 128k) since this process doesn't need much. | ||
2071 | */ | ||
2072 | void __attribute__ ((constructor)) | ||
2073 | GNUNET_ARM_memory_init () | ||
2074 | { | ||
2075 | mallopt (M_TRIM_THRESHOLD, 4 * 1024); | ||
2076 | mallopt (M_TOP_PAD, 1 * 1024); | ||
2077 | malloc_trim (0); | ||
2078 | } | ||
2079 | |||
2080 | |||
2081 | #endif | ||
2082 | |||
2083 | /* end of gnunet-service-nat.c */ | ||
diff --git a/src/nat/gnunet-service-nat.h b/src/nat/gnunet-service-nat.h deleted file mode 100644 index 5717306bb..000000000 --- a/src/nat/gnunet-service-nat.h +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2016, 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file nat/gnunet-service-nat.h | ||
23 | * @brief network address translation traversal service | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_NAT_H | ||
27 | #define GNUNET_SERVICE_NAT_H | ||
28 | |||
29 | /** | ||
30 | * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled, | ||
31 | * #GNUNET_SYSERR if configuration enabled but binary is unavailable. | ||
32 | */ | ||
33 | extern int enable_upnp; | ||
34 | |||
35 | #endif | ||
diff --git a/src/nat/gnunet-service-nat_externalip.c b/src/nat/gnunet-service-nat_externalip.c deleted file mode 100644 index c2625be2d..000000000 --- a/src/nat/gnunet-service-nat_externalip.c +++ /dev/null | |||
@@ -1,316 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2015, 2016, 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * Code to figure out what our external IPv4 address(es) might | ||
22 | * be (external IPv4s are what is seen on the rest of the Internet). | ||
23 | * | ||
24 | * This can be implemented using different methods, and we allow | ||
25 | * the main service to be notified about changes to what we believe | ||
26 | * is our external IPv4 address. | ||
27 | * | ||
28 | * Note that this is explicitly only about NATed systems; if one | ||
29 | * of our network interfaces has a global IP address this does | ||
30 | * not count as "external". | ||
31 | * | ||
32 | * @file nat/gnunet-service-nat_externalip.c | ||
33 | * @brief Functions for monitoring external IPv4 addresses | ||
34 | * @author Christian Grothoff | ||
35 | */ | ||
36 | #include "platform.h" | ||
37 | #include <math.h> | ||
38 | #include "gnunet_util_lib.h" | ||
39 | #include "gnunet_protocols.h" | ||
40 | #include "gnunet_signatures.h" | ||
41 | #include "gnunet_statistics_service.h" | ||
42 | #include "gnunet_resolver_service.h" | ||
43 | #include "gnunet_nat_service.h" | ||
44 | #include "gnunet-service-nat.h" | ||
45 | #include "gnunet-service-nat_externalip.h" | ||
46 | #include "gnunet-service-nat_stun.h" | ||
47 | #include "gnunet-service-nat_mini.h" | ||
48 | #include "gnunet-service-nat_helper.h" | ||
49 | #include "nat.h" | ||
50 | #include <gcrypt.h> | ||
51 | |||
52 | |||
53 | /** | ||
54 | * How long do we wait until we re-try running `external-ip` if the | ||
55 | * command failed to terminate nicely? | ||
56 | */ | ||
57 | #define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply ( \ | ||
58 | GNUNET_TIME_UNIT_MINUTES, 15) | ||
59 | |||
60 | /** | ||
61 | * How long do we wait until we re-try running `external-ip` if the | ||
62 | * command failed (but terminated)? | ||
63 | */ | ||
64 | #define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply ( \ | ||
65 | GNUNET_TIME_UNIT_MINUTES, 30) | ||
66 | |||
67 | /** | ||
68 | * How long do we wait until we re-try running `external-ip` if the | ||
69 | * command succeeded? | ||
70 | */ | ||
71 | #define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply ( \ | ||
72 | GNUNET_TIME_UNIT_MINUTES, 5) | ||
73 | |||
74 | |||
75 | /** | ||
76 | * Handle to monitor for external IP changes. | ||
77 | */ | ||
78 | struct GN_ExternalIPMonitor | ||
79 | { | ||
80 | /** | ||
81 | * Kept in DLL. | ||
82 | */ | ||
83 | struct GN_ExternalIPMonitor *next; | ||
84 | |||
85 | /** | ||
86 | * Kept in DLL. | ||
87 | */ | ||
88 | struct GN_ExternalIPMonitor *prev; | ||
89 | |||
90 | /** | ||
91 | * Function to call when we believe our external IPv4 address changed. | ||
92 | */ | ||
93 | GN_NotifyExternalIPv4Change cb; | ||
94 | |||
95 | /** | ||
96 | * Closure for @e cb. | ||
97 | */ | ||
98 | void *cb_cls; | ||
99 | }; | ||
100 | |||
101 | |||
102 | /** | ||
103 | * List of monitors, kept in DLL. | ||
104 | */ | ||
105 | static struct GN_ExternalIPMonitor *mon_head; | ||
106 | |||
107 | /** | ||
108 | * List of monitors, kept in DLL. | ||
109 | */ | ||
110 | static struct GN_ExternalIPMonitor *mon_tail; | ||
111 | |||
112 | /** | ||
113 | * Task run to obtain our external IP (if #enable_upnp is set | ||
114 | * and if we find we have a NATed IP address). | ||
115 | */ | ||
116 | static struct GNUNET_SCHEDULER_Task *probe_external_ip_task; | ||
117 | |||
118 | /** | ||
119 | * Handle to our operation to run `external-ip`. | ||
120 | */ | ||
121 | static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op; | ||
122 | |||
123 | /** | ||
124 | * What is our external IP address as claimed by `external-ip`? | ||
125 | * 0 for unknown. | ||
126 | */ | ||
127 | static struct in_addr mini_external_ipv4; | ||
128 | |||
129 | |||
130 | /** | ||
131 | * Tell relevant clients about a change in our external | ||
132 | * IPv4 address. | ||
133 | * | ||
134 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
135 | * @param v4 the external address that changed | ||
136 | */ | ||
137 | static void | ||
138 | notify_monitors_external_ipv4_change (int add, | ||
139 | const struct in_addr *v4) | ||
140 | { | ||
141 | for (struct GN_ExternalIPMonitor *mon = mon_head; | ||
142 | NULL != mon; | ||
143 | mon = mon->next) | ||
144 | mon->cb (mon->cb_cls, | ||
145 | v4, | ||
146 | add); | ||
147 | } | ||
148 | |||
149 | |||
150 | /** | ||
151 | * Task used to run `external-ip` to get our external IPv4 | ||
152 | * address and pass it to NATed clients if possible. | ||
153 | * | ||
154 | * @param cls NULL | ||
155 | */ | ||
156 | static void | ||
157 | run_external_ip (void *cls); | ||
158 | |||
159 | |||
160 | /** | ||
161 | * We learn our current external IP address. If it changed, | ||
162 | * notify all of our applicable clients. Also re-schedule | ||
163 | * #run_external_ip with an appropriate timeout. | ||
164 | * | ||
165 | * @param cls NULL | ||
166 | * @param addr the address, NULL on errors | ||
167 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code | ||
168 | */ | ||
169 | static void | ||
170 | handle_external_ip (void *cls, | ||
171 | const struct in_addr *addr, | ||
172 | enum GNUNET_NAT_StatusCode result) | ||
173 | { | ||
174 | char buf[INET_ADDRSTRLEN]; | ||
175 | |||
176 | probe_external_ip_op = NULL; | ||
177 | GNUNET_SCHEDULER_cancel (probe_external_ip_task); | ||
178 | probe_external_ip_task | ||
179 | = GNUNET_SCHEDULER_add_delayed ((NULL == addr) | ||
180 | ? EXTERN_IP_RETRY_FAILURE | ||
181 | : EXTERN_IP_RETRY_SUCCESS, | ||
182 | &run_external_ip, | ||
183 | NULL); | ||
184 | switch (result) | ||
185 | { | ||
186 | case GNUNET_NAT_ERROR_SUCCESS: | ||
187 | GNUNET_assert (NULL != addr); | ||
188 | if (addr->s_addr == mini_external_ipv4.s_addr) | ||
189 | return; /* not change */ | ||
190 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
191 | "Our external IP is now %s\n", | ||
192 | inet_ntop (AF_INET, | ||
193 | addr, | ||
194 | buf, | ||
195 | sizeof(buf))); | ||
196 | if (0 != mini_external_ipv4.s_addr) | ||
197 | notify_monitors_external_ipv4_change (GNUNET_NO, | ||
198 | &mini_external_ipv4); | ||
199 | mini_external_ipv4 = *addr; | ||
200 | notify_monitors_external_ipv4_change (GNUNET_YES, | ||
201 | &mini_external_ipv4); | ||
202 | break; | ||
203 | |||
204 | default: | ||
205 | if (0 != mini_external_ipv4.s_addr) | ||
206 | notify_monitors_external_ipv4_change (GNUNET_NO, | ||
207 | &mini_external_ipv4); | ||
208 | mini_external_ipv4.s_addr = 0; | ||
209 | break; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | |||
214 | /** | ||
215 | * Task used to run `external-ip` to get our external IPv4 | ||
216 | * address and pass it to NATed clients if possible. | ||
217 | * | ||
218 | * @param cls NULL | ||
219 | */ | ||
220 | static void | ||
221 | run_external_ip (void *cls) | ||
222 | { | ||
223 | probe_external_ip_task | ||
224 | = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT, | ||
225 | &run_external_ip, | ||
226 | NULL); | ||
227 | if (NULL != probe_external_ip_op) | ||
228 | { | ||
229 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op); | ||
230 | probe_external_ip_op = NULL; | ||
231 | } | ||
232 | probe_external_ip_op | ||
233 | = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip, | ||
234 | NULL); | ||
235 | } | ||
236 | |||
237 | |||
238 | /** | ||
239 | * We have changed our opinion about being NATed in the first | ||
240 | * place. Adapt our probing. | ||
241 | * | ||
242 | * @param have_nat #GNUNET_YES if we believe we are behind NAT | ||
243 | */ | ||
244 | void | ||
245 | GN_nat_status_changed (int have_nat) | ||
246 | { | ||
247 | if (GNUNET_YES != enable_upnp) | ||
248 | return; | ||
249 | if ((GNUNET_YES == have_nat) && | ||
250 | (NULL == probe_external_ip_task) && | ||
251 | (NULL == probe_external_ip_op)) | ||
252 | { | ||
253 | probe_external_ip_task | ||
254 | = GNUNET_SCHEDULER_add_now (&run_external_ip, | ||
255 | NULL); | ||
256 | return; | ||
257 | } | ||
258 | if (GNUNET_NO == have_nat) | ||
259 | { | ||
260 | if (NULL != probe_external_ip_task) | ||
261 | { | ||
262 | GNUNET_SCHEDULER_cancel (probe_external_ip_task); | ||
263 | probe_external_ip_task = NULL; | ||
264 | } | ||
265 | if (NULL != probe_external_ip_op) | ||
266 | { | ||
267 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op); | ||
268 | probe_external_ip_op = NULL; | ||
269 | } | ||
270 | } | ||
271 | } | ||
272 | |||
273 | |||
274 | /** | ||
275 | * Start monitoring external IPv4 addresses. | ||
276 | * | ||
277 | * @param cb function to call on changes | ||
278 | * @param cb_cls closure for @a cb | ||
279 | * @return handle to cancel | ||
280 | */ | ||
281 | struct GN_ExternalIPMonitor * | ||
282 | GN_external_ipv4_monitor_start (GN_NotifyExternalIPv4Change cb, | ||
283 | void *cb_cls) | ||
284 | { | ||
285 | struct GN_ExternalIPMonitor *mon; | ||
286 | |||
287 | mon = GNUNET_new (struct GN_ExternalIPMonitor); | ||
288 | mon->cb = cb; | ||
289 | mon->cb_cls = cb_cls; | ||
290 | GNUNET_CONTAINER_DLL_insert (mon_head, | ||
291 | mon_tail, | ||
292 | mon); | ||
293 | if (0 != mini_external_ipv4.s_addr) | ||
294 | cb (cb_cls, | ||
295 | &mini_external_ipv4, | ||
296 | GNUNET_YES); | ||
297 | return mon; | ||
298 | } | ||
299 | |||
300 | |||
301 | /** | ||
302 | * Stop calling monitor. | ||
303 | * | ||
304 | * @param mon monitor to call | ||
305 | */ | ||
306 | void | ||
307 | GN_external_ipv4_monitor_stop (struct GN_ExternalIPMonitor *mon) | ||
308 | { | ||
309 | GNUNET_CONTAINER_DLL_remove (mon_head, | ||
310 | mon_tail, | ||
311 | mon); | ||
312 | GNUNET_free (mon); | ||
313 | } | ||
314 | |||
315 | |||
316 | /* end of gnunet-service-nat_externalip.c */ | ||
diff --git a/src/nat/gnunet-service-nat_externalip.h b/src/nat/gnunet-service-nat_externalip.h deleted file mode 100644 index 6b3467fab..000000000 --- a/src/nat/gnunet-service-nat_externalip.h +++ /dev/null | |||
@@ -1,92 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2015, 2016, 2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * Code to figure out what our external IPv4 address(es) might | ||
22 | * be (external IPv4s are what is seen on the rest of the Internet). | ||
23 | * | ||
24 | * This can be implemented using different methods, and we allow | ||
25 | * the main service to be notified about changes to what we believe | ||
26 | * is our external IPv4 address. | ||
27 | * | ||
28 | * Note that this is explicitly only about NATed systems; if one | ||
29 | * of our network interfaces has a global IP address this does | ||
30 | * not count as "external". | ||
31 | * | ||
32 | * @file nat/gnunet-service-nat_externalip.h | ||
33 | * @brief Functions for monitoring external IPv4 addresses | ||
34 | * @author Christian Grothoff | ||
35 | */ | ||
36 | #ifndef GNUNET_SERVICE_NAT_EXTERNALIP_H | ||
37 | #define GNUNET_SERVICE_NAT_EXTERNALIP_H | ||
38 | |||
39 | #include "platform.h" | ||
40 | |||
41 | |||
42 | /** | ||
43 | * We have changed our opinion about being NATed in the first | ||
44 | * place. Adapt our probing. | ||
45 | * | ||
46 | * @param have_nat #GNUNET_YES if we believe we are behind NAT | ||
47 | */ | ||
48 | void | ||
49 | GN_nat_status_changed (int have_nat); | ||
50 | |||
51 | |||
52 | /** | ||
53 | * Function we call when we believe our external IPv4 address changed. | ||
54 | * | ||
55 | * @param cls closure | ||
56 | * @param ip address to add/remove | ||
57 | * @param add_remove #GNUNET_YES to add, #GNUNET_NO to remove | ||
58 | */ | ||
59 | typedef void | ||
60 | (*GN_NotifyExternalIPv4Change)(void *cls, | ||
61 | const struct in_addr *ip, | ||
62 | int add_remove); | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Handle to monitor for external IP changes. | ||
67 | */ | ||
68 | struct GN_ExternalIPMonitor; | ||
69 | |||
70 | |||
71 | /** | ||
72 | * Start monitoring external IPv4 addresses. | ||
73 | * | ||
74 | * @param cb function to call on changes | ||
75 | * @param cb_cls closure for @a cb | ||
76 | * @return handle to cancel | ||
77 | */ | ||
78 | struct GN_ExternalIPMonitor * | ||
79 | GN_external_ipv4_monitor_start (GN_NotifyExternalIPv4Change cb, | ||
80 | void *cb_cls); | ||
81 | |||
82 | |||
83 | /** | ||
84 | * Stop calling monitor. | ||
85 | * | ||
86 | * @param mon monitor to call | ||
87 | */ | ||
88 | void | ||
89 | GN_external_ipv4_monitor_stop (struct GN_ExternalIPMonitor *mon); | ||
90 | |||
91 | |||
92 | #endif | ||
diff --git a/src/nat/gnunet-service-nat_helper.c b/src/nat/gnunet-service-nat_helper.c deleted file mode 100644 index bd1645d25..000000000 --- a/src/nat/gnunet-service-nat_helper.c +++ /dev/null | |||
@@ -1,401 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file nat/gnunet-service-nat_helper.c | ||
23 | * @brief runs the gnunet-helper-nat-server | ||
24 | * @author Milan Bouchet-Valat | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet-service-nat_helper.h" | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Information we keep per NAT helper process. | ||
34 | */ | ||
35 | struct HelperContext | ||
36 | { | ||
37 | /** | ||
38 | * IP address we pass to the NAT helper. | ||
39 | */ | ||
40 | struct in_addr internal_address; | ||
41 | |||
42 | /** | ||
43 | * Function to call if we receive a reversal request. | ||
44 | */ | ||
45 | GN_ReversalCallback cb; | ||
46 | |||
47 | /** | ||
48 | * Closure for @e cb. | ||
49 | */ | ||
50 | void *cb_cls; | ||
51 | |||
52 | /** | ||
53 | * How long do we wait for restarting a crashed gnunet-helper-nat-server? | ||
54 | */ | ||
55 | struct GNUNET_TIME_Relative server_retry_delay; | ||
56 | |||
57 | /** | ||
58 | * ID of select gnunet-helper-nat-server stdout read task | ||
59 | */ | ||
60 | struct GNUNET_SCHEDULER_Task *server_read_task; | ||
61 | |||
62 | /** | ||
63 | * The process id of the server process (if behind NAT) | ||
64 | */ | ||
65 | struct GNUNET_OS_Process *server_proc; | ||
66 | |||
67 | /** | ||
68 | * stdout pipe handle for the gnunet-helper-nat-server process | ||
69 | */ | ||
70 | struct GNUNET_DISK_PipeHandle *server_stdout; | ||
71 | |||
72 | /** | ||
73 | * stdout file handle (for reading) for the gnunet-helper-nat-server process | ||
74 | */ | ||
75 | const struct GNUNET_DISK_FileHandle *server_stdout_handle; | ||
76 | |||
77 | /** | ||
78 | * Handle to the GNUnet configuration | ||
79 | */ | ||
80 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
81 | }; | ||
82 | |||
83 | |||
84 | /** | ||
85 | * Task that restarts the gnunet-helper-nat-server process after a crash | ||
86 | * after a certain delay. | ||
87 | * | ||
88 | * @param cls a `struct HelperContext` | ||
89 | */ | ||
90 | static void | ||
91 | restart_nat_server (void *cls); | ||
92 | |||
93 | |||
94 | /** | ||
95 | * Try again starting the helper later | ||
96 | * | ||
97 | * @param h context of the helper | ||
98 | */ | ||
99 | static void | ||
100 | try_again (struct HelperContext *h) | ||
101 | { | ||
102 | GNUNET_assert (NULL == h->server_read_task); | ||
103 | h->server_retry_delay = GNUNET_TIME_STD_BACKOFF (h->server_retry_delay); | ||
104 | h->server_read_task = GNUNET_SCHEDULER_add_delayed (h->server_retry_delay, | ||
105 | &restart_nat_server, | ||
106 | h); | ||
107 | } | ||
108 | |||
109 | |||
110 | /** | ||
111 | * We have been notified that gnunet-helper-nat-server has written | ||
112 | * something to stdout. Handle the output, then reschedule this | ||
113 | * function to be called again once more is available. | ||
114 | * | ||
115 | * @param cls the `struct HelperContext` | ||
116 | */ | ||
117 | static void | ||
118 | nat_server_read (void *cls) | ||
119 | { | ||
120 | struct HelperContext *h = cls; | ||
121 | char mybuf[40]; | ||
122 | ssize_t bytes; | ||
123 | int port; | ||
124 | const char *port_start; | ||
125 | struct sockaddr_in sin_addr; | ||
126 | |||
127 | h->server_read_task = NULL; | ||
128 | memset (mybuf, 0, sizeof(mybuf)); | ||
129 | bytes = | ||
130 | GNUNET_DISK_file_read (h->server_stdout_handle, mybuf, sizeof(mybuf)); | ||
131 | if (bytes < 1) | ||
132 | { | ||
133 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
134 | "Finished reading from server stdout with code: %d\n", | ||
135 | (int) bytes); | ||
136 | if (0 != GNUNET_OS_process_kill (h->server_proc, GNUNET_TERM_SIG)) | ||
137 | GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "kill"); | ||
138 | GNUNET_OS_process_wait (h->server_proc); | ||
139 | GNUNET_OS_process_destroy (h->server_proc); | ||
140 | h->server_proc = NULL; | ||
141 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
142 | h->server_stdout = NULL; | ||
143 | h->server_stdout_handle = NULL; | ||
144 | try_again (h); | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | port_start = NULL; | ||
149 | for (size_t i = 0; i < sizeof(mybuf); i++) | ||
150 | { | ||
151 | if (mybuf[i] == '\n') | ||
152 | { | ||
153 | mybuf[i] = '\0'; | ||
154 | break; | ||
155 | } | ||
156 | if ((mybuf[i] == ':') && (i + 1 < sizeof(mybuf))) | ||
157 | { | ||
158 | mybuf[i] = '\0'; | ||
159 | port_start = &mybuf[i + 1]; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | /* construct socket address of sender */ | ||
164 | memset (&sin_addr, 0, sizeof(sin_addr)); | ||
165 | sin_addr.sin_family = AF_INET; | ||
166 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
167 | sin_addr.sin_len = sizeof(sin_addr); | ||
168 | #endif | ||
169 | if ((NULL == port_start) || (1 != sscanf (port_start, "%d", &port)) || | ||
170 | (-1 == inet_pton (AF_INET, mybuf, &sin_addr.sin_addr))) | ||
171 | { | ||
172 | /* should we restart gnunet-helper-nat-server? */ | ||
173 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
174 | _ ( | ||
175 | "gnunet-helper-nat-server generated malformed address `%s'\n"), | ||
176 | mybuf); | ||
177 | h->server_read_task = | ||
178 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
179 | h->server_stdout_handle, | ||
180 | &nat_server_read, | ||
181 | h); | ||
182 | return; | ||
183 | } | ||
184 | sin_addr.sin_port = htons ((uint16_t) port); | ||
185 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
186 | "gnunet-helper-nat-server read: %s:%d\n", | ||
187 | mybuf, | ||
188 | port); | ||
189 | h->cb (h->cb_cls, &sin_addr); | ||
190 | h->server_read_task = | ||
191 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
192 | h->server_stdout_handle, | ||
193 | &nat_server_read, | ||
194 | h); | ||
195 | } | ||
196 | |||
197 | |||
198 | /** | ||
199 | * Task that restarts the gnunet-helper-nat-server process after a crash | ||
200 | * after a certain delay. | ||
201 | * | ||
202 | * @param cls a `struct HelperContext` | ||
203 | */ | ||
204 | static void | ||
205 | restart_nat_server (void *cls) | ||
206 | { | ||
207 | struct HelperContext *h = cls; | ||
208 | char *binary; | ||
209 | char ia[INET_ADDRSTRLEN]; | ||
210 | |||
211 | h->server_read_task = NULL; | ||
212 | GNUNET_assert (NULL != | ||
213 | inet_ntop (AF_INET, &h->internal_address, ia, sizeof(ia))); | ||
214 | /* Start the server process */ | ||
215 | binary = GNUNET_OS_get_suid_binary_path (h->cfg, "gnunet-helper-nat-server"); | ||
216 | if (GNUNET_YES != GNUNET_OS_check_helper_binary (binary, GNUNET_YES, ia)) | ||
217 | { | ||
218 | /* move instantly to max delay, as this is unlikely to be fixed */ | ||
219 | h->server_retry_delay = GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD; | ||
220 | GNUNET_free (binary); | ||
221 | try_again (h); | ||
222 | return; | ||
223 | } | ||
224 | h->server_stdout = | ||
225 | GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW); | ||
226 | if (NULL == h->server_stdout) | ||
227 | { | ||
228 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "pipe"); | ||
229 | GNUNET_free (binary); | ||
230 | try_again (h); | ||
231 | return; | ||
232 | } | ||
233 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
234 | "Starting `%s' at `%s'\n", | ||
235 | "gnunet-helper-nat-server", | ||
236 | ia); | ||
237 | h->server_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_NONE, | ||
238 | NULL, | ||
239 | h->server_stdout, | ||
240 | NULL, | ||
241 | binary, | ||
242 | "gnunet-helper-nat-server", | ||
243 | ia, | ||
244 | NULL); | ||
245 | GNUNET_free (binary); | ||
246 | if (NULL == h->server_proc) | ||
247 | { | ||
248 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
249 | _ ("Failed to start %s\n"), | ||
250 | "gnunet-helper-nat-server"); | ||
251 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
252 | h->server_stdout = NULL; | ||
253 | try_again (h); | ||
254 | return; | ||
255 | } | ||
256 | /* Close the write end of the read pipe */ | ||
257 | GNUNET_DISK_pipe_close_end (h->server_stdout, GNUNET_DISK_PIPE_END_WRITE); | ||
258 | h->server_stdout_handle = | ||
259 | GNUNET_DISK_pipe_handle (h->server_stdout, GNUNET_DISK_PIPE_END_READ); | ||
260 | h->server_read_task = | ||
261 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
262 | h->server_stdout_handle, | ||
263 | &nat_server_read, | ||
264 | h); | ||
265 | } | ||
266 | |||
267 | |||
268 | /** | ||
269 | * Start the gnunet-helper-nat-server and process incoming | ||
270 | * requests. | ||
271 | * | ||
272 | * @param internal_address | ||
273 | * @param cb function to call if we receive a request | ||
274 | * @param cb_cls closure for @a cb | ||
275 | * @param cfg Handle to the GNUnet configuration | ||
276 | * @return NULL on error | ||
277 | */ | ||
278 | struct HelperContext * | ||
279 | GN_start_gnunet_nat_server_ (const struct in_addr *internal_address, | ||
280 | GN_ReversalCallback cb, | ||
281 | void *cb_cls, | ||
282 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
283 | { | ||
284 | struct HelperContext *h; | ||
285 | |||
286 | h = GNUNET_new (struct HelperContext); | ||
287 | h->cb = cb; | ||
288 | h->cb_cls = cb_cls; | ||
289 | h->internal_address = *internal_address; | ||
290 | h->cfg = cfg; | ||
291 | restart_nat_server (h); | ||
292 | if (NULL == h->server_stdout) | ||
293 | { | ||
294 | GN_stop_gnunet_nat_server_ (h); | ||
295 | return NULL; | ||
296 | } | ||
297 | return h; | ||
298 | } | ||
299 | |||
300 | |||
301 | /** | ||
302 | * Start the gnunet-helper-nat-server and process incoming | ||
303 | * requests. | ||
304 | * | ||
305 | * @param h helper context to stop | ||
306 | */ | ||
307 | void | ||
308 | GN_stop_gnunet_nat_server_ (struct HelperContext *h) | ||
309 | { | ||
310 | if (NULL != h->server_read_task) | ||
311 | { | ||
312 | GNUNET_SCHEDULER_cancel (h->server_read_task); | ||
313 | h->server_read_task = NULL; | ||
314 | } | ||
315 | if (NULL != h->server_proc) | ||
316 | { | ||
317 | if (0 != GNUNET_OS_process_kill (h->server_proc, GNUNET_TERM_SIG)) | ||
318 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
319 | GNUNET_OS_process_wait (h->server_proc); | ||
320 | GNUNET_OS_process_destroy (h->server_proc); | ||
321 | h->server_proc = NULL; | ||
322 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
323 | h->server_stdout = NULL; | ||
324 | h->server_stdout_handle = NULL; | ||
325 | } | ||
326 | if (NULL != h->server_stdout) | ||
327 | { | ||
328 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
329 | h->server_stdout = NULL; | ||
330 | h->server_stdout_handle = NULL; | ||
331 | } | ||
332 | GNUNET_free (h); | ||
333 | } | ||
334 | |||
335 | |||
336 | /** | ||
337 | * We want to connect to a peer that is behind NAT. Run the | ||
338 | * gnunet-helper-nat-client to send dummy ICMP responses to cause | ||
339 | * that peer to connect to us (connection reversal). | ||
340 | * | ||
341 | * @param internal_address out internal address to use | ||
342 | * @param internal_port port to use | ||
343 | * @param remote_v4 the address of the peer (IPv4-only) | ||
344 | * @param cfg handle to the GNUnet configuration | ||
345 | * @return #GNUNET_SYSERR on error, | ||
346 | * #GNUNET_OK otherwise | ||
347 | */ | ||
348 | int | ||
349 | GN_request_connection_reversal (const struct in_addr *internal_address, | ||
350 | uint16_t internal_port, | ||
351 | const struct in_addr *remote_v4, | ||
352 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
353 | { | ||
354 | char intv4[INET_ADDRSTRLEN]; | ||
355 | char remv4[INET_ADDRSTRLEN]; | ||
356 | char port_as_string[6]; | ||
357 | struct GNUNET_OS_Process *proc; | ||
358 | char *binary; | ||
359 | |||
360 | if (NULL == inet_ntop (AF_INET, internal_address, intv4, INET_ADDRSTRLEN)) | ||
361 | { | ||
362 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); | ||
363 | return GNUNET_SYSERR; | ||
364 | } | ||
365 | if (NULL == inet_ntop (AF_INET, remote_v4, remv4, INET_ADDRSTRLEN)) | ||
366 | { | ||
367 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop"); | ||
368 | return GNUNET_SYSERR; | ||
369 | } | ||
370 | GNUNET_snprintf (port_as_string, | ||
371 | sizeof(port_as_string), | ||
372 | "%d", | ||
373 | internal_port); | ||
374 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
375 | "Running gnunet-helper-nat-client %s %s %u\n", | ||
376 | intv4, | ||
377 | remv4, | ||
378 | internal_port); | ||
379 | binary = GNUNET_OS_get_suid_binary_path (cfg, "gnunet-helper-nat-client"); | ||
380 | proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_NONE, | ||
381 | NULL, | ||
382 | NULL, | ||
383 | NULL, | ||
384 | binary, | ||
385 | "gnunet-helper-nat-client", | ||
386 | intv4, | ||
387 | remv4, | ||
388 | port_as_string, | ||
389 | NULL); | ||
390 | GNUNET_free (binary); | ||
391 | if (NULL == proc) | ||
392 | return GNUNET_SYSERR; | ||
393 | /* we know that the gnunet-helper-nat-client will terminate virtually | ||
394 | * instantly */ | ||
395 | GNUNET_OS_process_wait (proc); | ||
396 | GNUNET_OS_process_destroy (proc); | ||
397 | return GNUNET_OK; | ||
398 | } | ||
399 | |||
400 | |||
401 | /* end of gnunet-service-nat_helper.c */ | ||
diff --git a/src/nat/gnunet-service-nat_helper.h b/src/nat/gnunet-service-nat_helper.h deleted file mode 100644 index dc6b9ae61..000000000 --- a/src/nat/gnunet-service-nat_helper.h +++ /dev/null | |||
@@ -1,95 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file nat/gnunet-service-nat_helper.h | ||
23 | * @brief runs the gnunet-helper-nat-server | ||
24 | * @author Milan Bouchet-Valat | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * Information we keep per NAT helper process. | ||
33 | */ | ||
34 | struct HelperContext; | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Function called whenever we get a connection reversal | ||
39 | * request from another peer. | ||
40 | * | ||
41 | * @param cls closure | ||
42 | * @param ra IP address of the peer who wants us to connect to it | ||
43 | */ | ||
44 | typedef void | ||
45 | (*GN_ReversalCallback) (void *cls, | ||
46 | const struct sockaddr_in *ra); | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Start the gnunet-helper-nat-server and process incoming | ||
51 | * requests. | ||
52 | * | ||
53 | * @param internal_address | ||
54 | * @param cb function to call if we receive a request | ||
55 | * @param cb_cls closure for @a cb | ||
56 | * @param cfg handle to the GNUnet configuration | ||
57 | * @return NULL on error | ||
58 | */ | ||
59 | struct HelperContext * | ||
60 | GN_start_gnunet_nat_server_ (const struct in_addr *internal_address, | ||
61 | GN_ReversalCallback cb, | ||
62 | void *cb_cls, | ||
63 | const struct GNUNET_CONFIGURATION_Handle *cfg); | ||
64 | |||
65 | |||
66 | /** | ||
67 | * Start the gnunet-helper-nat-server and process incoming | ||
68 | * requests. | ||
69 | * | ||
70 | * @param h helper context to stop | ||
71 | */ | ||
72 | void | ||
73 | GN_stop_gnunet_nat_server_ (struct HelperContext *h); | ||
74 | |||
75 | |||
76 | /** | ||
77 | * We want to connect to a peer that is behind NAT. Run the | ||
78 | * gnunet-helper-nat-client to send dummy ICMP responses to cause | ||
79 | * that peer to connect to us (connection reversal). | ||
80 | * | ||
81 | * @param internal_address out internal address to use | ||
82 | * @param internal_port internal port to use | ||
83 | * @param remote_v4 the address of the peer (IPv4-only) | ||
84 | * @param cfg handle to the GNUnet configuration | ||
85 | * @return #GNUNET_SYSERR on error, | ||
86 | * #GNUNET_OK otherwise | ||
87 | */ | ||
88 | int | ||
89 | GN_request_connection_reversal (const struct in_addr *internal_address, | ||
90 | uint16_t internal_port, | ||
91 | const struct in_addr *remote_v4, | ||
92 | const struct GNUNET_CONFIGURATION_Handle *cfg); | ||
93 | |||
94 | |||
95 | /* end of gnunet-service-nat_helper.h */ | ||
diff --git a/src/nat/gnunet-service-nat_mini.c b/src/nat/gnunet-service-nat_mini.c deleted file mode 100644 index 24f77d9cc..000000000 --- a/src/nat/gnunet-service-nat_mini.c +++ /dev/null | |||
@@ -1,707 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011-2014, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file nat/gnunet-service-nat_mini.c | ||
23 | * @brief functions for interaction with miniupnp; tested with miniupnpc 1.5 | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_nat_service.h" | ||
29 | #include "gnunet-service-nat_mini.h" | ||
30 | #include "nat.h" | ||
31 | |||
32 | #define LOG(kind, ...) GNUNET_log_from (kind, "nat", __VA_ARGS__) | ||
33 | |||
34 | /** | ||
35 | * How long do we give upnpc to create a mapping? | ||
36 | */ | ||
37 | #define MAP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) | ||
38 | |||
39 | /** | ||
40 | * How long do we give upnpc to remove a mapping? | ||
41 | */ | ||
42 | #define UNMAP_TIMEOUT \ | ||
43 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) | ||
44 | |||
45 | /** | ||
46 | * How often do we check for changes in the mapping? | ||
47 | */ | ||
48 | #define MAP_REFRESH_FREQ \ | ||
49 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) | ||
50 | |||
51 | |||
52 | /* ************************* external-ip calling ************************ */ | ||
53 | |||
54 | /** | ||
55 | * Opaque handle to cancel "GNUNET_NAT_mini_get_external_ipv4" operation. | ||
56 | */ | ||
57 | struct GNUNET_NAT_ExternalHandle | ||
58 | { | ||
59 | /** | ||
60 | * Function to call with the result. | ||
61 | */ | ||
62 | GNUNET_NAT_IPCallback cb; | ||
63 | |||
64 | /** | ||
65 | * Closure for @e cb. | ||
66 | */ | ||
67 | void *cb_cls; | ||
68 | |||
69 | /** | ||
70 | * Read task. | ||
71 | */ | ||
72 | struct GNUNET_SCHEDULER_Task *task; | ||
73 | |||
74 | /** | ||
75 | * Handle to `external-ip` process. | ||
76 | */ | ||
77 | struct GNUNET_OS_Process *eip; | ||
78 | |||
79 | /** | ||
80 | * Handle to stdout pipe of `external-ip`. | ||
81 | */ | ||
82 | struct GNUNET_DISK_PipeHandle *opipe; | ||
83 | |||
84 | /** | ||
85 | * Read handle of @e opipe. | ||
86 | */ | ||
87 | const struct GNUNET_DISK_FileHandle *r; | ||
88 | |||
89 | /** | ||
90 | * Number of bytes in @e buf that are valid. | ||
91 | */ | ||
92 | size_t off; | ||
93 | |||
94 | /** | ||
95 | * Destination of our read operation (output of 'external-ip'). | ||
96 | */ | ||
97 | char buf[17]; | ||
98 | |||
99 | /** | ||
100 | * Error code for better debugging and user feedback | ||
101 | */ | ||
102 | enum GNUNET_NAT_StatusCode ret; | ||
103 | }; | ||
104 | |||
105 | |||
106 | /** | ||
107 | * Read the output of `external-ip` into `buf`. When complete, parse | ||
108 | * the address and call our callback. | ||
109 | * | ||
110 | * @param cls the `struct GNUNET_NAT_ExternalHandle` | ||
111 | */ | ||
112 | static void | ||
113 | read_external_ipv4 (void *cls) | ||
114 | { | ||
115 | struct GNUNET_NAT_ExternalHandle *eh = cls; | ||
116 | ssize_t ret; | ||
117 | struct in_addr addr; | ||
118 | |||
119 | eh->task = NULL; | ||
120 | ret = GNUNET_DISK_file_read (eh->r, | ||
121 | &eh->buf[eh->off], | ||
122 | sizeof(eh->buf) - eh->off); | ||
123 | if (ret > 0) | ||
124 | { | ||
125 | /* try to read more */ | ||
126 | eh->off += ret; | ||
127 | eh->task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
128 | eh->r, | ||
129 | &read_external_ipv4, | ||
130 | eh); | ||
131 | return; | ||
132 | } | ||
133 | eh->ret = GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID; | ||
134 | if ((eh->off > 7) && (eh->buf[eh->off - 1] == '\n')) | ||
135 | { | ||
136 | eh->buf[eh->off - 1] = '\0'; | ||
137 | if (1 == inet_pton (AF_INET, eh->buf, &addr)) | ||
138 | { | ||
139 | if (0 == addr.s_addr) | ||
140 | eh->ret = | ||
141 | GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID; /* got 0.0.0.0 */ | ||
142 | else | ||
143 | eh->ret = GNUNET_NAT_ERROR_SUCCESS; | ||
144 | } | ||
145 | } | ||
146 | eh->cb (eh->cb_cls, | ||
147 | (GNUNET_NAT_ERROR_SUCCESS == eh->ret) ? &addr : NULL, | ||
148 | eh->ret); | ||
149 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (eh); | ||
150 | } | ||
151 | |||
152 | |||
153 | /** | ||
154 | * (Asynchronously) signal error invoking `external-ip` to client. | ||
155 | * | ||
156 | * @param cls the `struct GNUNET_NAT_ExternalHandle` (freed) | ||
157 | */ | ||
158 | static void | ||
159 | signal_external_ip_error (void *cls) | ||
160 | { | ||
161 | struct GNUNET_NAT_ExternalHandle *eh = cls; | ||
162 | |||
163 | eh->task = NULL; | ||
164 | eh->cb (eh->cb_cls, NULL, eh->ret); | ||
165 | GNUNET_free (eh); | ||
166 | } | ||
167 | |||
168 | |||
169 | /** | ||
170 | * Try to get the external IPv4 address of this peer. | ||
171 | * | ||
172 | * @param cb function to call with result | ||
173 | * @param cb_cls closure for @a cb | ||
174 | * @return handle for cancellation (can only be used until @a cb is called), never NULL | ||
175 | */ | ||
176 | struct GNUNET_NAT_ExternalHandle * | ||
177 | GNUNET_NAT_mini_get_external_ipv4_ (GNUNET_NAT_IPCallback cb, void *cb_cls) | ||
178 | { | ||
179 | struct GNUNET_NAT_ExternalHandle *eh; | ||
180 | |||
181 | eh = GNUNET_new (struct GNUNET_NAT_ExternalHandle); | ||
182 | eh->cb = cb; | ||
183 | eh->cb_cls = cb_cls; | ||
184 | eh->ret = GNUNET_NAT_ERROR_SUCCESS; | ||
185 | if (GNUNET_SYSERR == | ||
186 | GNUNET_OS_check_helper_binary ("external-ip", GNUNET_NO, NULL)) | ||
187 | { | ||
188 | LOG (GNUNET_ERROR_TYPE_INFO, _ ("`external-ip' command not found\n")); | ||
189 | eh->ret = GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND; | ||
190 | eh->task = GNUNET_SCHEDULER_add_now (&signal_external_ip_error, eh); | ||
191 | return eh; | ||
192 | } | ||
193 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
194 | "Running `external-ip' to determine our external IP\n"); | ||
195 | eh->opipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW); | ||
196 | if (NULL == eh->opipe) | ||
197 | { | ||
198 | eh->ret = GNUNET_NAT_ERROR_IPC_FAILURE; | ||
199 | eh->task = GNUNET_SCHEDULER_add_now (&signal_external_ip_error, eh); | ||
200 | return eh; | ||
201 | } | ||
202 | eh->eip = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_NONE, | ||
203 | NULL, | ||
204 | eh->opipe, | ||
205 | NULL, | ||
206 | "external-ip", | ||
207 | "external-ip", | ||
208 | NULL); | ||
209 | if (NULL == eh->eip) | ||
210 | { | ||
211 | GNUNET_DISK_pipe_close (eh->opipe); | ||
212 | eh->ret = GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED; | ||
213 | eh->task = GNUNET_SCHEDULER_add_now (&signal_external_ip_error, eh); | ||
214 | return eh; | ||
215 | } | ||
216 | GNUNET_DISK_pipe_close_end (eh->opipe, GNUNET_DISK_PIPE_END_WRITE); | ||
217 | eh->r = GNUNET_DISK_pipe_handle (eh->opipe, GNUNET_DISK_PIPE_END_READ); | ||
218 | eh->task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
219 | eh->r, | ||
220 | &read_external_ipv4, | ||
221 | eh); | ||
222 | return eh; | ||
223 | } | ||
224 | |||
225 | |||
226 | /** | ||
227 | * Cancel operation. | ||
228 | * | ||
229 | * @param eh operation to cancel | ||
230 | */ | ||
231 | void | ||
232 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (struct GNUNET_NAT_ExternalHandle *eh) | ||
233 | { | ||
234 | if (NULL != eh->eip) | ||
235 | { | ||
236 | (void) GNUNET_OS_process_kill (eh->eip, SIGKILL); | ||
237 | GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (eh->eip)); | ||
238 | GNUNET_OS_process_destroy (eh->eip); | ||
239 | } | ||
240 | if (NULL != eh->opipe) | ||
241 | { | ||
242 | GNUNET_DISK_pipe_close (eh->opipe); | ||
243 | eh->opipe = NULL; | ||
244 | } | ||
245 | if (NULL != eh->task) | ||
246 | { | ||
247 | GNUNET_SCHEDULER_cancel (eh->task); | ||
248 | eh->task = NULL; | ||
249 | } | ||
250 | GNUNET_free (eh); | ||
251 | } | ||
252 | |||
253 | |||
254 | /* ************************* upnpc calling ************************ */ | ||
255 | |||
256 | |||
257 | /** | ||
258 | * Handle to a mapping created with upnpc. | ||
259 | */ | ||
260 | struct GNUNET_NAT_MiniHandle | ||
261 | { | ||
262 | /** | ||
263 | * Function to call on mapping changes. | ||
264 | */ | ||
265 | GNUNET_NAT_MiniAddressCallback ac; | ||
266 | |||
267 | /** | ||
268 | * Closure for @e ac. | ||
269 | */ | ||
270 | void *ac_cls; | ||
271 | |||
272 | /** | ||
273 | * Command used to install the map. | ||
274 | */ | ||
275 | struct GNUNET_OS_CommandHandle *map_cmd; | ||
276 | |||
277 | /** | ||
278 | * Command used to refresh our map information. | ||
279 | */ | ||
280 | struct GNUNET_OS_CommandHandle *refresh_cmd; | ||
281 | |||
282 | /** | ||
283 | * Command used to remove the mapping. | ||
284 | */ | ||
285 | struct GNUNET_OS_CommandHandle *unmap_cmd; | ||
286 | |||
287 | /** | ||
288 | * Our current external mapping (if we have one). | ||
289 | */ | ||
290 | struct sockaddr_in current_addr; | ||
291 | |||
292 | /** | ||
293 | * We check the mapping periodically to see if it | ||
294 | * still works. This task triggers the check. | ||
295 | */ | ||
296 | struct GNUNET_SCHEDULER_Task *refresh_task; | ||
297 | |||
298 | /** | ||
299 | * Are we mapping TCP or UDP? | ||
300 | */ | ||
301 | int is_tcp; | ||
302 | |||
303 | /** | ||
304 | * Did we succeed with creating a mapping? | ||
305 | */ | ||
306 | int did_map; | ||
307 | |||
308 | /** | ||
309 | * Did we find our mapping during refresh scan? | ||
310 | */ | ||
311 | int found; | ||
312 | |||
313 | /** | ||
314 | * Which port are we mapping? | ||
315 | */ | ||
316 | uint16_t port; | ||
317 | }; | ||
318 | |||
319 | |||
320 | /** | ||
321 | * Run "upnpc -l" to find out if our mapping changed. | ||
322 | * | ||
323 | * @param cls the `struct GNUNET_NAT_MiniHandle` | ||
324 | */ | ||
325 | static void | ||
326 | do_refresh (void *cls); | ||
327 | |||
328 | |||
329 | /** | ||
330 | * Process the output from the "upnpc -r" command. | ||
331 | * | ||
332 | * @param cls the `struct GNUNET_NAT_MiniHandle` | ||
333 | * @param line line of output, NULL at the end | ||
334 | */ | ||
335 | static void | ||
336 | process_map_output (void *cls, const char *line); | ||
337 | |||
338 | |||
339 | /** | ||
340 | * Run "upnpc -r" to map our internal port. | ||
341 | * | ||
342 | * @param mini our handle | ||
343 | */ | ||
344 | static void | ||
345 | run_upnpc_r (struct GNUNET_NAT_MiniHandle *mini) | ||
346 | { | ||
347 | char pstr[6]; | ||
348 | |||
349 | GNUNET_snprintf (pstr, sizeof(pstr), "%u", (unsigned int) mini->port); | ||
350 | mini->map_cmd = GNUNET_OS_command_run (&process_map_output, | ||
351 | mini, | ||
352 | MAP_TIMEOUT, | ||
353 | "upnpc", | ||
354 | "upnpc", | ||
355 | "-r", | ||
356 | pstr, | ||
357 | mini->is_tcp ? "tcp" : "udp", | ||
358 | NULL); | ||
359 | if (NULL == mini->map_cmd) | ||
360 | { | ||
361 | mini->ac (mini->ac_cls, | ||
362 | GNUNET_SYSERR, | ||
363 | NULL, | ||
364 | 0, | ||
365 | GNUNET_NAT_ERROR_UPNPC_FAILED); | ||
366 | return; | ||
367 | } | ||
368 | } | ||
369 | |||
370 | |||
371 | /** | ||
372 | * Process the output from "upnpc -l" to see if our | ||
373 | * external mapping changed. If so, do the notifications. | ||
374 | * | ||
375 | * @param cls the `struct GNUNET_NAT_MiniHandle` | ||
376 | * @param line line of output, NULL at the end | ||
377 | */ | ||
378 | static void | ||
379 | process_refresh_output (void *cls, const char *line) | ||
380 | { | ||
381 | struct GNUNET_NAT_MiniHandle *mini = cls; | ||
382 | char pstr[9]; | ||
383 | const char *s; | ||
384 | unsigned int nport; | ||
385 | struct in_addr exip; | ||
386 | |||
387 | if (NULL == line) | ||
388 | { | ||
389 | GNUNET_OS_command_stop (mini->refresh_cmd); | ||
390 | mini->refresh_cmd = NULL; | ||
391 | if (GNUNET_NO == mini->found) | ||
392 | { | ||
393 | /* mapping disappeared, try to re-create */ | ||
394 | if (GNUNET_YES == mini->did_map) | ||
395 | { | ||
396 | mini->ac (mini->ac_cls, | ||
397 | GNUNET_NO, | ||
398 | (const struct sockaddr *) &mini->current_addr, | ||
399 | sizeof(mini->current_addr), | ||
400 | GNUNET_NAT_ERROR_SUCCESS); | ||
401 | mini->did_map = GNUNET_NO; | ||
402 | } | ||
403 | run_upnpc_r (mini); | ||
404 | } | ||
405 | return; | ||
406 | } | ||
407 | if (! mini->did_map) | ||
408 | return; /* never mapped, won't find our mapping anyway */ | ||
409 | |||
410 | /* we're looking for output of the form: | ||
411 | * "ExternalIPAddress = 12.134.41.124" */ | ||
412 | |||
413 | s = strstr (line, "ExternalIPAddress = "); | ||
414 | if (NULL != s) | ||
415 | { | ||
416 | s += strlen ("ExternalIPAddress = "); | ||
417 | if (1 != inet_pton (AF_INET, s, &exip)) | ||
418 | return; /* skip */ | ||
419 | if (exip.s_addr == mini->current_addr.sin_addr.s_addr) | ||
420 | return; /* no change */ | ||
421 | /* update mapping */ | ||
422 | mini->ac (mini->ac_cls, | ||
423 | GNUNET_NO, | ||
424 | (const struct sockaddr *) &mini->current_addr, | ||
425 | sizeof(mini->current_addr), | ||
426 | GNUNET_NAT_ERROR_SUCCESS); | ||
427 | mini->current_addr.sin_addr = exip; | ||
428 | mini->ac (mini->ac_cls, | ||
429 | GNUNET_YES, | ||
430 | (const struct sockaddr *) &mini->current_addr, | ||
431 | sizeof(mini->current_addr), | ||
432 | GNUNET_NAT_ERROR_SUCCESS); | ||
433 | return; | ||
434 | } | ||
435 | /* | ||
436 | * we're looking for output of the form: | ||
437 | * | ||
438 | * "0 TCP 3000->192.168.2.150:3000 'libminiupnpc' ''" | ||
439 | * "1 UDP 3001->192.168.2.150:3001 'libminiupnpc' ''" | ||
440 | * | ||
441 | * the pattern we look for is: | ||
442 | * | ||
443 | * "%s TCP PORT->STRING:OURPORT *" or | ||
444 | * "%s UDP PORT->STRING:OURPORT *" | ||
445 | */GNUNET_snprintf (pstr, sizeof(pstr), ":%u ", mini->port); | ||
446 | if (NULL == (s = strstr (line, "->"))) | ||
447 | return; /* skip */ | ||
448 | if (NULL == strstr (s, pstr)) | ||
449 | return; /* skip */ | ||
450 | if (1 != sscanf (line, | ||
451 | (mini->is_tcp) ? "%*u TCP %u->%*s:%*u %*s" | ||
452 | : "%*u UDP %u->%*s:%*u %*s", | ||
453 | &nport)) | ||
454 | return; /* skip */ | ||
455 | mini->found = GNUNET_YES; | ||
456 | if (nport == ntohs (mini->current_addr.sin_port)) | ||
457 | return; /* no change */ | ||
458 | |||
459 | /* external port changed, update mapping */ | ||
460 | mini->ac (mini->ac_cls, | ||
461 | GNUNET_NO, | ||
462 | (const struct sockaddr *) &mini->current_addr, | ||
463 | sizeof(mini->current_addr), | ||
464 | GNUNET_NAT_ERROR_SUCCESS); | ||
465 | mini->current_addr.sin_port = htons ((uint16_t) nport); | ||
466 | mini->ac (mini->ac_cls, | ||
467 | GNUNET_YES, | ||
468 | (const struct sockaddr *) &mini->current_addr, | ||
469 | sizeof(mini->current_addr), | ||
470 | GNUNET_NAT_ERROR_SUCCESS); | ||
471 | } | ||
472 | |||
473 | |||
474 | /** | ||
475 | * Run "upnpc -l" to find out if our mapping changed. | ||
476 | * | ||
477 | * @param cls the 'struct GNUNET_NAT_MiniHandle' | ||
478 | */ | ||
479 | static void | ||
480 | do_refresh (void *cls) | ||
481 | { | ||
482 | struct GNUNET_NAT_MiniHandle *mini = cls; | ||
483 | int ac; | ||
484 | |||
485 | mini->refresh_task = | ||
486 | GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, &do_refresh, mini); | ||
487 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
488 | "Running `upnpc' to check if our mapping still exists\n"); | ||
489 | mini->found = GNUNET_NO; | ||
490 | ac = GNUNET_NO; | ||
491 | if (NULL != mini->map_cmd) | ||
492 | { | ||
493 | /* took way too long, abort it! */ | ||
494 | GNUNET_OS_command_stop (mini->map_cmd); | ||
495 | mini->map_cmd = NULL; | ||
496 | ac = GNUNET_YES; | ||
497 | } | ||
498 | if (NULL != mini->refresh_cmd) | ||
499 | { | ||
500 | /* took way too long, abort it! */ | ||
501 | GNUNET_OS_command_stop (mini->refresh_cmd); | ||
502 | mini->refresh_cmd = NULL; | ||
503 | ac = GNUNET_YES; | ||
504 | } | ||
505 | mini->refresh_cmd = GNUNET_OS_command_run (&process_refresh_output, | ||
506 | mini, | ||
507 | MAP_TIMEOUT, | ||
508 | "upnpc", | ||
509 | "upnpc", | ||
510 | "-l", | ||
511 | NULL); | ||
512 | if (GNUNET_YES == ac) | ||
513 | mini->ac (mini->ac_cls, | ||
514 | GNUNET_SYSERR, | ||
515 | NULL, | ||
516 | 0, | ||
517 | GNUNET_NAT_ERROR_UPNPC_TIMEOUT); | ||
518 | } | ||
519 | |||
520 | |||
521 | /** | ||
522 | * Process the output from the 'upnpc -r' command. | ||
523 | * | ||
524 | * @param cls the `struct GNUNET_NAT_MiniHandle` | ||
525 | * @param line line of output, NULL at the end | ||
526 | */ | ||
527 | static void | ||
528 | process_map_output (void *cls, const char *line) | ||
529 | { | ||
530 | struct GNUNET_NAT_MiniHandle *mini = cls; | ||
531 | const char *ipaddr; | ||
532 | char *ipa; | ||
533 | const char *pstr; | ||
534 | unsigned int port; | ||
535 | |||
536 | if (NULL == line) | ||
537 | { | ||
538 | GNUNET_OS_command_stop (mini->map_cmd); | ||
539 | mini->map_cmd = NULL; | ||
540 | if (GNUNET_YES != mini->did_map) | ||
541 | mini->ac (mini->ac_cls, | ||
542 | GNUNET_SYSERR, | ||
543 | NULL, | ||
544 | 0, | ||
545 | GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED); | ||
546 | if (NULL == mini->refresh_task) | ||
547 | mini->refresh_task = | ||
548 | GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, &do_refresh, mini); | ||
549 | return; | ||
550 | } | ||
551 | /* | ||
552 | * The upnpc output we're after looks like this: | ||
553 | * | ||
554 | * "external 87.123.42.204:3000 TCP is redirected to internal 192.168.2.150:3000" | ||
555 | */if ((NULL == (ipaddr = strstr (line, " "))) || | ||
556 | (NULL == (pstr = strstr (ipaddr, ":"))) || | ||
557 | (1 != sscanf (pstr + 1, "%u", &port))) | ||
558 | { | ||
559 | return; /* skip line */ | ||
560 | } | ||
561 | ipa = GNUNET_strdup (ipaddr + 1); | ||
562 | strstr (ipa, ":")[0] = '\0'; | ||
563 | if (1 != inet_pton (AF_INET, ipa, &mini->current_addr.sin_addr)) | ||
564 | { | ||
565 | GNUNET_free (ipa); | ||
566 | return; /* skip line */ | ||
567 | } | ||
568 | GNUNET_free (ipa); | ||
569 | |||
570 | mini->current_addr.sin_port = htons (port); | ||
571 | mini->current_addr.sin_family = AF_INET; | ||
572 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
573 | mini->current_addr.sin_len = sizeof(struct sockaddr_in); | ||
574 | #endif | ||
575 | mini->did_map = GNUNET_YES; | ||
576 | mini->ac (mini->ac_cls, | ||
577 | GNUNET_YES, | ||
578 | (const struct sockaddr *) &mini->current_addr, | ||
579 | sizeof(mini->current_addr), | ||
580 | GNUNET_NAT_ERROR_SUCCESS); | ||
581 | } | ||
582 | |||
583 | |||
584 | /** | ||
585 | * Start mapping the given port using (mini)upnpc. This function | ||
586 | * should typically not be used directly (it is used within the | ||
587 | * general-purpose #GNUNET_NAT_register() code). However, it can be | ||
588 | * used if specifically UPnP-based NAT traversal is to be used or | ||
589 | * tested. | ||
590 | * | ||
591 | * @param port port to map | ||
592 | * @param is_tcp #GNUNET_YES to map TCP, #GNUNET_NO for UDP | ||
593 | * @param ac function to call with mapping result | ||
594 | * @param ac_cls closure for @a ac | ||
595 | * @return NULL on error (no 'upnpc' installed) | ||
596 | */ | ||
597 | struct GNUNET_NAT_MiniHandle * | ||
598 | GNUNET_NAT_mini_map_start (uint16_t port, | ||
599 | int is_tcp, | ||
600 | GNUNET_NAT_MiniAddressCallback ac, | ||
601 | void *ac_cls) | ||
602 | { | ||
603 | struct GNUNET_NAT_MiniHandle *ret; | ||
604 | |||
605 | if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary ("upnpc", GNUNET_NO, NULL)) | ||
606 | { | ||
607 | LOG (GNUNET_ERROR_TYPE_INFO, _ ("`upnpc' command not found\n")); | ||
608 | ac (ac_cls, GNUNET_SYSERR, NULL, 0, GNUNET_NAT_ERROR_UPNPC_NOT_FOUND); | ||
609 | return NULL; | ||
610 | } | ||
611 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Running `upnpc' to install mapping\n"); | ||
612 | ret = GNUNET_new (struct GNUNET_NAT_MiniHandle); | ||
613 | ret->ac = ac; | ||
614 | ret->ac_cls = ac_cls; | ||
615 | ret->is_tcp = is_tcp; | ||
616 | ret->port = port; | ||
617 | ret->refresh_task = | ||
618 | GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, &do_refresh, ret); | ||
619 | run_upnpc_r (ret); | ||
620 | return ret; | ||
621 | } | ||
622 | |||
623 | |||
624 | /** | ||
625 | * Process output from our 'unmap' command. | ||
626 | * | ||
627 | * @param cls the `struct GNUNET_NAT_MiniHandle` | ||
628 | * @param line line of output, NULL at the end | ||
629 | */ | ||
630 | static void | ||
631 | process_unmap_output (void *cls, const char *line) | ||
632 | { | ||
633 | struct GNUNET_NAT_MiniHandle *mini = cls; | ||
634 | |||
635 | if (NULL == line) | ||
636 | { | ||
637 | LOG (GNUNET_ERROR_TYPE_DEBUG, "UPnP unmap done\n"); | ||
638 | GNUNET_OS_command_stop (mini->unmap_cmd); | ||
639 | mini->unmap_cmd = NULL; | ||
640 | GNUNET_free (mini); | ||
641 | return; | ||
642 | } | ||
643 | /* we don't really care about the output... */ | ||
644 | } | ||
645 | |||
646 | |||
647 | /** | ||
648 | * Remove a mapping created with (mini)upnpc. Calling | ||
649 | * this function will give 'upnpc' 1s to remove tha mapping, | ||
650 | * so while this function is non-blocking, a task will be | ||
651 | * left with the scheduler for up to 1s past this call. | ||
652 | * | ||
653 | * @param mini the handle | ||
654 | */ | ||
655 | void | ||
656 | GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini) | ||
657 | { | ||
658 | char pstr[6]; | ||
659 | |||
660 | if (NULL != mini->refresh_task) | ||
661 | { | ||
662 | GNUNET_SCHEDULER_cancel (mini->refresh_task); | ||
663 | mini->refresh_task = NULL; | ||
664 | } | ||
665 | if (NULL != mini->refresh_cmd) | ||
666 | { | ||
667 | GNUNET_OS_command_stop (mini->refresh_cmd); | ||
668 | mini->refresh_cmd = NULL; | ||
669 | } | ||
670 | if (NULL != mini->map_cmd) | ||
671 | { | ||
672 | GNUNET_OS_command_stop (mini->map_cmd); | ||
673 | mini->map_cmd = NULL; | ||
674 | } | ||
675 | if (GNUNET_NO == mini->did_map) | ||
676 | { | ||
677 | GNUNET_free (mini); | ||
678 | return; | ||
679 | } | ||
680 | mini->ac (mini->ac_cls, | ||
681 | GNUNET_NO, | ||
682 | (const struct sockaddr *) &mini->current_addr, | ||
683 | sizeof(mini->current_addr), | ||
684 | GNUNET_NAT_ERROR_SUCCESS); | ||
685 | /* Note: oddly enough, deletion uses the external port whereas | ||
686 | * addition uses the internal port; this rarely matters since they | ||
687 | * often are the same, but it might... */ | ||
688 | GNUNET_snprintf (pstr, | ||
689 | sizeof(pstr), | ||
690 | "%u", | ||
691 | (unsigned int) ntohs (mini->current_addr.sin_port)); | ||
692 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
693 | "Unmapping port %u with UPnP\n", | ||
694 | ntohs (mini->current_addr.sin_port)); | ||
695 | mini->unmap_cmd = GNUNET_OS_command_run (&process_unmap_output, | ||
696 | mini, | ||
697 | UNMAP_TIMEOUT, | ||
698 | "upnpc", | ||
699 | "upnpc", | ||
700 | "-d", | ||
701 | pstr, | ||
702 | mini->is_tcp ? "tcp" : "udp", | ||
703 | NULL); | ||
704 | } | ||
705 | |||
706 | |||
707 | /* end of gnunet-service-nat_mini.c */ | ||
diff --git a/src/nat/gnunet-service-nat_mini.h b/src/nat/gnunet-service-nat_mini.h deleted file mode 100644 index dffc9758a..000000000 --- a/src/nat/gnunet-service-nat_mini.h +++ /dev/null | |||
@@ -1,128 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011-2014, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file nat/gnunet-service-nat_mini.c | ||
23 | * @brief functions for interaction with miniupnp; tested with miniupnpc 1.5 | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_NAT_MINI_H | ||
27 | #define GNUNET_SERVICE_NAT_MINI_H | ||
28 | |||
29 | |||
30 | /** | ||
31 | * Signature of a callback that is given an IP address. | ||
32 | * | ||
33 | * @param cls closure | ||
34 | * @param addr the address, NULL on errors | ||
35 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code | ||
36 | */ | ||
37 | typedef void | ||
38 | (*GNUNET_NAT_IPCallback) (void *cls, | ||
39 | const struct in_addr *addr, | ||
40 | enum GNUNET_NAT_StatusCode result); | ||
41 | |||
42 | |||
43 | /** | ||
44 | * Opaque handle to cancel #GNUNET_NAT_mini_get_external_ipv4() operation. | ||
45 | */ | ||
46 | struct GNUNET_NAT_ExternalHandle; | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Try to get the external IPv4 address of this peer. | ||
51 | * | ||
52 | * @param cb function to call with result | ||
53 | * @param cb_cls closure for @a cb | ||
54 | * @return handle for cancellation (can only be used until @a cb is called), NULL on error | ||
55 | */ | ||
56 | struct GNUNET_NAT_ExternalHandle * | ||
57 | GNUNET_NAT_mini_get_external_ipv4_ (GNUNET_NAT_IPCallback cb, | ||
58 | void *cb_cls); | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Cancel operation. | ||
63 | * | ||
64 | * @param eh operation to cancel | ||
65 | */ | ||
66 | void | ||
67 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (struct | ||
68 | GNUNET_NAT_ExternalHandle *eh); | ||
69 | |||
70 | |||
71 | /** | ||
72 | * Handle to a mapping created with upnpc. | ||
73 | */ | ||
74 | struct GNUNET_NAT_MiniHandle; | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Signature of the callback passed to #GNUNET_NAT_register() for | ||
79 | * a function to call whenever our set of 'valid' addresses changes. | ||
80 | * | ||
81 | * @param cls closure | ||
82 | * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean | ||
83 | * the previous (now invalid) one, #GNUNET_SYSERR indicates an error | ||
84 | * @param addr either the previous or the new public IP address | ||
85 | * @param addrlen actual length of the @a addr | ||
86 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code | ||
87 | */ | ||
88 | typedef void | ||
89 | (*GNUNET_NAT_MiniAddressCallback) (void *cls, | ||
90 | int add_remove, | ||
91 | const struct sockaddr *addr, | ||
92 | socklen_t addrlen, | ||
93 | enum GNUNET_NAT_StatusCode result); | ||
94 | |||
95 | |||
96 | /** | ||
97 | * Start mapping the given port using (mini)upnpc. This function | ||
98 | * should typically not be used directly (it is used within the | ||
99 | * general-purpose #GNUNET_NAT_register() code). However, it can be | ||
100 | * used if specifically UPnP-based NAT traversal is to be used or | ||
101 | * tested. | ||
102 | * | ||
103 | * @param port port to map | ||
104 | * @param is_tcp #GNUNET_YES to map TCP, #GNUNET_NO for UDP | ||
105 | * @param ac function to call with mapping result | ||
106 | * @param ac_cls closure for @a ac | ||
107 | * @return NULL on error | ||
108 | */ | ||
109 | struct GNUNET_NAT_MiniHandle * | ||
110 | GNUNET_NAT_mini_map_start (uint16_t port, | ||
111 | int is_tcp, | ||
112 | GNUNET_NAT_MiniAddressCallback ac, | ||
113 | void *ac_cls); | ||
114 | |||
115 | |||
116 | /** | ||
117 | * Remove a mapping created with (mini)upnpc. Calling | ||
118 | * this function will give 'upnpc' 1s to remove the mapping, | ||
119 | * so while this function is non-blocking, a task will be | ||
120 | * left with the scheduler for up to 1s past this call. | ||
121 | * | ||
122 | * @param mini the handle | ||
123 | */ | ||
124 | void | ||
125 | GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini); | ||
126 | |||
127 | |||
128 | #endif | ||
diff --git a/src/nat/gnunet-service-nat_stun.c b/src/nat/gnunet-service-nat_stun.c deleted file mode 100644 index 203728ebf..000000000 --- a/src/nat/gnunet-service-nat_stun.c +++ /dev/null | |||
@@ -1,215 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2015, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * This code provides some support for doing STUN transactions. We | ||
22 | * receive the simplest possible packet as the STUN server and try | ||
23 | * to respond properly. | ||
24 | * | ||
25 | * All STUN packets start with a simple header made of a type, | ||
26 | * length (excluding the header) and a 16-byte random transaction id. | ||
27 | * Following the header we may have zero or more attributes, each | ||
28 | * structured as a type, length and a value (whose format depends | ||
29 | * on the type, but often contains addresses). | ||
30 | * Of course all fields are in network format. | ||
31 | * | ||
32 | * This code was based on ministun.c. | ||
33 | * | ||
34 | * @file nat/gnunet-service-nat_stun.c | ||
35 | * @brief Functions for STUN functionality | ||
36 | * @author Bruno Souza Cabral | ||
37 | */ | ||
38 | |||
39 | #include "platform.h" | ||
40 | #include "gnunet_util_lib.h" | ||
41 | #include "nat_stun.h" | ||
42 | |||
43 | #define LOG(kind, ...) GNUNET_log_from (kind, "stun", __VA_ARGS__) | ||
44 | |||
45 | |||
46 | /** | ||
47 | * Context for #stun_get_mapped(). | ||
48 | * Used to store state across processing attributes. | ||
49 | */ | ||
50 | struct StunState | ||
51 | { | ||
52 | uint16_t attr; | ||
53 | }; | ||
54 | |||
55 | |||
56 | /** | ||
57 | * Extract the STUN_MAPPED_ADDRESS from the stun response. | ||
58 | * This is used as a callback for stun_handle_response | ||
59 | * when called from stun_request. | ||
60 | * | ||
61 | * @param[out] st pointer where we will set the type | ||
62 | * @param attr received stun attribute | ||
63 | * @param magic Magic cookie | ||
64 | * @param[out] arg pointer to a sockaddr_in where we will set the reported IP and port | ||
65 | * @return #GNUNET_OK if @a arg was initialized | ||
66 | */ | ||
67 | static int | ||
68 | stun_get_mapped (struct StunState *st, | ||
69 | const struct stun_attr *attr, | ||
70 | uint32_t magic, | ||
71 | struct sockaddr_in *arg) | ||
72 | { | ||
73 | const struct stun_addr *returned_addr; | ||
74 | struct sockaddr_in *sa = (struct sockaddr_in *) arg; | ||
75 | uint16_t type = ntohs (attr->attr); | ||
76 | |||
77 | switch (type) | ||
78 | { | ||
79 | case STUN_MAPPED_ADDRESS: | ||
80 | if ((st->attr == STUN_XOR_MAPPED_ADDRESS) || | ||
81 | (st->attr == STUN_MS_XOR_MAPPED_ADDRESS)) | ||
82 | return GNUNET_NO; | ||
83 | magic = 0; | ||
84 | break; | ||
85 | |||
86 | case STUN_MS_XOR_MAPPED_ADDRESS: | ||
87 | if (st->attr == STUN_XOR_MAPPED_ADDRESS) | ||
88 | return GNUNET_NO; | ||
89 | break; | ||
90 | |||
91 | case STUN_XOR_MAPPED_ADDRESS: | ||
92 | break; | ||
93 | |||
94 | default: | ||
95 | return GNUNET_NO; | ||
96 | } | ||
97 | |||
98 | if (ntohs (attr->len) < sizeof(struct stun_addr)) | ||
99 | return GNUNET_NO; | ||
100 | returned_addr = (const struct stun_addr *) (attr + 1); | ||
101 | if (AF_INET != returned_addr->family) | ||
102 | return GNUNET_NO; | ||
103 | st->attr = type; | ||
104 | sa->sin_family = AF_INET; | ||
105 | sa->sin_port = returned_addr->port ^ htons (ntohl (magic) >> 16); | ||
106 | sa->sin_addr.s_addr = returned_addr->addr ^ magic; | ||
107 | return GNUNET_OK; | ||
108 | } | ||
109 | |||
110 | |||
111 | /** | ||
112 | * Handle an incoming STUN response. Do some basic sanity checks on | ||
113 | * packet size and content, try to extract information. | ||
114 | * At the moment this only processes BIND requests, | ||
115 | * and returns the externally visible address of the original | ||
116 | * request. | ||
117 | * | ||
118 | * @param data the packet | ||
119 | * @param len the length of the packet in @a data | ||
120 | * @param[out] arg sockaddr_in where we will set our discovered address | ||
121 | * @return #GNUNET_OK on success, | ||
122 | * #GNUNET_NO if the packet is invalid (not a stun packet) | ||
123 | */ | ||
124 | int | ||
125 | GNUNET_NAT_stun_handle_packet_ (const void *data, | ||
126 | size_t len, | ||
127 | struct sockaddr_in *arg) | ||
128 | { | ||
129 | const struct stun_header *hdr; | ||
130 | const struct stun_attr *attr; | ||
131 | struct StunState st; | ||
132 | uint32_t advertised_message_size; | ||
133 | uint32_t message_magic_cookie; | ||
134 | int ret = GNUNET_SYSERR; | ||
135 | |||
136 | /* On entry, 'len' is the length of the UDP payload. After the | ||
137 | * initial checks it becomes the size of unprocessed options, | ||
138 | * while 'data' is advanced accordingly. | ||
139 | */ | ||
140 | if (len < sizeof(struct stun_header)) | ||
141 | { | ||
142 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
143 | "Packet too short to be a STUN packet\n"); | ||
144 | return GNUNET_NO; | ||
145 | } | ||
146 | hdr = data; | ||
147 | /* Skip header as it is already in hdr */ | ||
148 | len -= sizeof(struct stun_header); | ||
149 | data += sizeof(struct stun_header); | ||
150 | |||
151 | /* len as advertised in the message */ | ||
152 | advertised_message_size = ntohs (hdr->msglen); | ||
153 | message_magic_cookie = ntohl (hdr->magic); | ||
154 | /* Compare if the cookie match */ | ||
155 | if (STUN_MAGIC_COOKIE != message_magic_cookie) | ||
156 | { | ||
157 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
158 | "Invalid magic cookie for STUN packet\n"); | ||
159 | return GNUNET_NO; | ||
160 | } | ||
161 | |||
162 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
163 | "STUN Packet, msg %s (%04x), length: %d\n", | ||
164 | stun_msg2str (ntohs (hdr->msgtype)), | ||
165 | ntohs (hdr->msgtype), | ||
166 | advertised_message_size); | ||
167 | if (advertised_message_size > len) | ||
168 | { | ||
169 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
170 | "Scrambled STUN packet length (got %d, expecting %d)\n", | ||
171 | advertised_message_size, | ||
172 | (int) len); | ||
173 | return GNUNET_NO; | ||
174 | } | ||
175 | len = advertised_message_size; | ||
176 | memset (&st, 0, sizeof(st)); | ||
177 | |||
178 | while (len > 0) | ||
179 | { | ||
180 | if (len < sizeof(struct stun_attr)) | ||
181 | { | ||
182 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
183 | "Attribute too short (got %d, expecting %d)\n", | ||
184 | (int) len, | ||
185 | (int) sizeof(struct stun_attr)); | ||
186 | break; | ||
187 | } | ||
188 | attr = (const struct stun_attr *) data; | ||
189 | |||
190 | /* compute total attribute length */ | ||
191 | advertised_message_size = ntohs (attr->len) + sizeof(struct stun_attr); | ||
192 | |||
193 | /* Check if we still have space in our buffer */ | ||
194 | if (advertised_message_size > len) | ||
195 | { | ||
196 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
197 | "Inconsistent attribute (length %d exceeds remaining msg len %d)\n", | ||
198 | advertised_message_size, | ||
199 | (int) len); | ||
200 | break; | ||
201 | } | ||
202 | if (GNUNET_OK == | ||
203 | stun_get_mapped (&st, | ||
204 | attr, | ||
205 | hdr->magic, | ||
206 | arg)) | ||
207 | ret = GNUNET_OK; | ||
208 | data += advertised_message_size; | ||
209 | len -= advertised_message_size; | ||
210 | } | ||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | |||
215 | /* end of gnunet-service-nat_stun.c */ | ||
diff --git a/src/nat/gnunet-service-nat_stun.h b/src/nat/gnunet-service-nat_stun.h deleted file mode 100644 index 912fc3b46..000000000 --- a/src/nat/gnunet-service-nat_stun.h +++ /dev/null | |||
@@ -1,61 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2015, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * This code provides some support for doing STUN transactions. We | ||
22 | * receive the simplest possible packet as the STUN server and try | ||
23 | * to respond properly. | ||
24 | * | ||
25 | * All STUN packets start with a simple header made of a type, | ||
26 | * length (excluding the header) and a 16-byte random transaction id. | ||
27 | * Following the header we may have zero or more attributes, each | ||
28 | * structured as a type, length and a value (whose format depends | ||
29 | * on the type, but often contains addresses). | ||
30 | * Of course all fields are in network format. | ||
31 | * | ||
32 | * This code was based on ministun.c. | ||
33 | * | ||
34 | * @file nat/gnunet-service-nat_stun.h | ||
35 | * @brief Functions for STUN functionality | ||
36 | * @author Bruno Souza Cabral | ||
37 | */ | ||
38 | #ifndef GNUNET_SERVICE_NAT_STUN_H | ||
39 | #define GNUNET_SERVICE_NAT_STUN_H | ||
40 | |||
41 | #include "platform.h" | ||
42 | |||
43 | /** | ||
44 | * Handle an incoming STUN response. Do some basic sanity checks on | ||
45 | * packet size and content, try to extract information. | ||
46 | * At the moment this only processes BIND requests, | ||
47 | * and returns the externally visible address of the original | ||
48 | * request. | ||
49 | * | ||
50 | * @param data the packet | ||
51 | * @param len the length of the packet in @a data | ||
52 | * @param[out] arg sockaddr_in where we will set our discovered address | ||
53 | * @return #GNUNET_OK on success, | ||
54 | * #GNUNET_NO if the packet is invalid (not a stun packet) | ||
55 | */ | ||
56 | int | ||
57 | GNUNET_NAT_stun_handle_packet_ (const void *data, | ||
58 | size_t len, | ||
59 | struct sockaddr_in *arg); | ||
60 | |||
61 | #endif | ||
diff --git a/src/nat/nat.conf.in b/src/nat/nat.conf.in deleted file mode 100644 index 4c068c394..000000000 --- a/src/nat/nat.conf.in +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | [nat] | ||
2 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
3 | @UNIXONLY@ PORT = 2121 | ||
4 | HOSTNAME = localhost | ||
5 | BINARY = gnunet-service-nat | ||
6 | ACCEPT_FROM = 127.0.0.1; | ||
7 | ACCEPT_FROM6 = ::1; | ||
8 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-nat.sock | ||
9 | UNIX_MATCH_UID = YES | ||
10 | UNIX_MATCH_GID = YES | ||
11 | |||
12 | # Enable UPNP by default? | ||
13 | ENABLE_UPNP = YES | ||
14 | |||
15 | # Enable scanning for all system IP addresses? | ||
16 | ENABLE_IPSCAN = YES | ||
17 | |||
18 | # Disable IPv6 support | ||
19 | # FIXME: move entirely to transport plugins! | ||
20 | DISABLEV6 = NO | ||
21 | |||
22 | # How often do we query the DNS resolver | ||
23 | # for our hostname (to get our own IP) | ||
24 | HOSTNAME_DNS_FREQUENCY = 20 min | ||
25 | |||
26 | # How often do we iterate over our | ||
27 | # network interfaces to check for changes | ||
28 | # in our IP address? | ||
29 | IFC_SCAN_FREQUENCY = 15 min | ||
30 | |||
31 | # How often do we query the DNS resolver | ||
32 | # for our hostname (to get our own IP) | ||
33 | DYNDNS_FREQUENCY = 7 min | ||
34 | |||
35 | # SHOULD USE STUN ? | ||
36 | USE_STUN = YES | ||
37 | STUN_FREQUENCY = 5 min | ||
38 | # Default list of stun servers | ||
39 | STUN_SERVERS = stun.gnunet.org stun.services.mozilla.com:3478 stun.ekiga.net:3478 | ||
40 | |||
41 | # After how long do we consider STUN data stale? | ||
42 | STUN_STALE = 60 min | ||
43 | |||
diff --git a/src/nat/nat.h b/src/nat/nat.h deleted file mode 100644 index 1d8648aaf..000000000 --- a/src/nat/nat.h +++ /dev/null | |||
@@ -1,223 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file src/nat/nat.h | ||
23 | * @brief Messages for interaction with gnunet-nat-server and gnunet-nat-service | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | */ | ||
27 | #ifndef NAT_H | ||
28 | #define NAT_H | ||
29 | #include "gnunet_util_lib.h" | ||
30 | |||
31 | |||
32 | GNUNET_NETWORK_STRUCT_BEGIN | ||
33 | |||
34 | /** | ||
35 | * Request to test NAT traversal, sent to the gnunet-nat-server | ||
36 | * (not the service!). | ||
37 | */ | ||
38 | struct GNUNET_NAT_TestMessage | ||
39 | { | ||
40 | /** | ||
41 | * Header with type #GNUNET_MESSAGE_TYPE_NAT_TEST | ||
42 | */ | ||
43 | struct GNUNET_MessageHeader header; | ||
44 | |||
45 | /** | ||
46 | * IPv4 target IP address | ||
47 | */ | ||
48 | uint32_t dst_ipv4; | ||
49 | |||
50 | /** | ||
51 | * Port to use, 0 to send dummy ICMP response. | ||
52 | */ | ||
53 | uint16_t dport; | ||
54 | |||
55 | /** | ||
56 | * Data to send OR advertised-port (in NBO) to use for dummy ICMP. | ||
57 | */ | ||
58 | uint16_t data; | ||
59 | |||
60 | /** | ||
61 | * #GNUNET_YES for TCP, #GNUNET_NO for UDP. | ||
62 | */ | ||
63 | int32_t is_tcp; | ||
64 | }; | ||
65 | |||
66 | |||
67 | /** | ||
68 | * Flags specifying the events this client would be | ||
69 | * interested in being told about. | ||
70 | */ | ||
71 | enum GNUNET_NAT_RegisterFlags | ||
72 | { | ||
73 | /** | ||
74 | * This client does not want any notifications. | ||
75 | */ | ||
76 | GNUNET_NAT_RF_NONE = 0, | ||
77 | |||
78 | /** | ||
79 | * This client wants to be informed about changes to our | ||
80 | * applicable addresses. | ||
81 | */ | ||
82 | GNUNET_NAT_RF_ADDRESSES = 1, | ||
83 | |||
84 | /** | ||
85 | * This client supports address reversal. | ||
86 | */ | ||
87 | GNUNET_NAT_RF_REVERSAL = 2 | ||
88 | }; | ||
89 | |||
90 | |||
91 | /** | ||
92 | * Message sent by a client to register with its addresses. | ||
93 | */ | ||
94 | struct GNUNET_NAT_RegisterMessage | ||
95 | { | ||
96 | /** | ||
97 | * Header with type #GNUNET_MESSAGE_TYPE_NAT_REGISTER | ||
98 | */ | ||
99 | struct GNUNET_MessageHeader header; | ||
100 | |||
101 | /** | ||
102 | * An `enum GNUNET_NAT_RegisterFlags`. | ||
103 | */ | ||
104 | uint8_t flags; | ||
105 | |||
106 | /** | ||
107 | * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP. | ||
108 | */ | ||
109 | uint8_t proto; | ||
110 | |||
111 | /** | ||
112 | * Number of bytes in the string that follow which | ||
113 | * specifies a section name in the configuration. | ||
114 | */ | ||
115 | uint16_t str_len GNUNET_PACKED; | ||
116 | |||
117 | /** | ||
118 | * Number of addresses that this service is bound to that follow. | ||
119 | * Given as an array of "struct sockaddr" entries, the size of | ||
120 | * each entry being determined by the "sa_family" at the beginning. | ||
121 | */ | ||
122 | uint16_t num_addrs GNUNET_PACKED; | ||
123 | |||
124 | /* Followed by @e num_addrs addresses of type 'struct | ||
125 | sockaddr' */ | ||
126 | |||
127 | /* Followed by @e str_len section name to use for options */ | ||
128 | }; | ||
129 | |||
130 | |||
131 | /** | ||
132 | * Client telling the service to (possibly) handle a STUN message. | ||
133 | */ | ||
134 | struct GNUNET_NAT_HandleStunMessage | ||
135 | { | ||
136 | /** | ||
137 | * Header with type #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN | ||
138 | */ | ||
139 | struct GNUNET_MessageHeader header; | ||
140 | |||
141 | /** | ||
142 | * Size of the sender address included, in NBO. | ||
143 | */ | ||
144 | uint16_t sender_addr_size; | ||
145 | |||
146 | /** | ||
147 | * Number of bytes of payload included, in NBO. | ||
148 | */ | ||
149 | uint16_t payload_size; | ||
150 | |||
151 | /* followed by a `struct sockaddr` of @e sender_addr_size bytes */ | ||
152 | |||
153 | /* followed by payload with @e payload_size bytes */ | ||
154 | }; | ||
155 | |||
156 | |||
157 | /** | ||
158 | * Client asking the service to initiate connection reversal. | ||
159 | */ | ||
160 | struct GNUNET_NAT_RequestConnectionReversalMessage | ||
161 | { | ||
162 | /** | ||
163 | * Header with type #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL | ||
164 | */ | ||
165 | struct GNUNET_MessageHeader header; | ||
166 | |||
167 | /** | ||
168 | * Size of the local address included, in NBO. | ||
169 | */ | ||
170 | uint16_t local_addr_size; | ||
171 | |||
172 | /** | ||
173 | * Size of the remote address included, in NBO. | ||
174 | */ | ||
175 | uint16_t remote_addr_size; | ||
176 | |||
177 | /* followed by a `struct sockaddr` of @e local_addr_size bytes */ | ||
178 | |||
179 | /* followed by a `struct sockaddr` of @e remote_addr_size bytes */ | ||
180 | }; | ||
181 | |||
182 | |||
183 | /** | ||
184 | * Service telling a client that connection reversal was requested. | ||
185 | */ | ||
186 | struct GNUNET_NAT_ConnectionReversalRequestedMessage | ||
187 | { | ||
188 | /** | ||
189 | * Header with type #GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED | ||
190 | */ | ||
191 | struct GNUNET_MessageHeader header; | ||
192 | |||
193 | /* followed by a `struct sockaddr_in` */ | ||
194 | }; | ||
195 | |||
196 | |||
197 | /** | ||
198 | * Service notifying the client about changes in the set of | ||
199 | * addresses it has. | ||
200 | */ | ||
201 | struct GNUNET_NAT_AddressChangeNotificationMessage | ||
202 | { | ||
203 | /** | ||
204 | * Header with type #GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE | ||
205 | */ | ||
206 | struct GNUNET_MessageHeader header; | ||
207 | |||
208 | /** | ||
209 | * #GNUNET_YES to add, #GNUNET_NO to remove the address from the list. | ||
210 | */ | ||
211 | int32_t add_remove GNUNET_PACKED; | ||
212 | |||
213 | /** | ||
214 | * Type of the address, an `enum GNUNET_NAT_AddressClass` in NBO. | ||
215 | */ | ||
216 | uint32_t addr_class GNUNET_PACKED; | ||
217 | /* followed by a `struct sockaddr` */ | ||
218 | }; | ||
219 | |||
220 | |||
221 | GNUNET_NETWORK_STRUCT_END | ||
222 | |||
223 | #endif | ||
diff --git a/src/nat/nat_api.c b/src/nat/nat_api.c deleted file mode 100644 index 20e7b6ec6..000000000 --- a/src/nat/nat_api.c +++ /dev/null | |||
@@ -1,718 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2007-2017 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @author Christian Grothoff | ||
23 | * @author Milan Bouchet-Valat | ||
24 | * | ||
25 | * @file nat/nat_api.c | ||
26 | * Service for handling UPnP and NAT-PMP port forwarding | ||
27 | * and external IP address retrieval | ||
28 | */ | ||
29 | #include "platform.h" | ||
30 | #include "gnunet_nat_service.h" | ||
31 | #include "nat.h" | ||
32 | #include "nat_stun.h" | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Entry in DLL of addresses of this peer. | ||
37 | */ | ||
38 | struct AddrEntry | ||
39 | { | ||
40 | /** | ||
41 | * DLL. | ||
42 | */ | ||
43 | struct AddrEntry *next; | ||
44 | |||
45 | /** | ||
46 | * DLL. | ||
47 | */ | ||
48 | struct AddrEntry *prev; | ||
49 | |||
50 | /** | ||
51 | * Place where the application can store data (on add, | ||
52 | * and retrieve on remove). | ||
53 | */ | ||
54 | void *app_ctx; | ||
55 | |||
56 | /** | ||
57 | * Address class of the address. | ||
58 | */ | ||
59 | enum GNUNET_NAT_AddressClass ac; | ||
60 | |||
61 | /** | ||
62 | * Number of bytes that follow. | ||
63 | */ | ||
64 | socklen_t addrlen; | ||
65 | }; | ||
66 | |||
67 | |||
68 | /** | ||
69 | * Handle for active NAT registrations. | ||
70 | */ | ||
71 | struct GNUNET_NAT_Handle | ||
72 | { | ||
73 | /** | ||
74 | * Configuration we use. | ||
75 | */ | ||
76 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
77 | |||
78 | /** | ||
79 | * Message queue for communicating with the NAT service. | ||
80 | */ | ||
81 | struct GNUNET_MQ_Handle *mq; | ||
82 | |||
83 | /** | ||
84 | * Our registration message. | ||
85 | */ | ||
86 | struct GNUNET_MessageHeader *reg; | ||
87 | |||
88 | /** | ||
89 | * Head of address DLL. | ||
90 | */ | ||
91 | struct AddrEntry *ae_head; | ||
92 | |||
93 | /** | ||
94 | * Tail of address DLL. | ||
95 | */ | ||
96 | struct AddrEntry *ae_tail; | ||
97 | |||
98 | /** | ||
99 | * Function to call when our addresses change. | ||
100 | */ | ||
101 | GNUNET_NAT_AddressCallback address_callback; | ||
102 | |||
103 | /** | ||
104 | * Function to call when another peer requests connection reversal. | ||
105 | */ | ||
106 | GNUNET_NAT_ReversalCallback reversal_callback; | ||
107 | |||
108 | /** | ||
109 | * Closure for the various callbacks. | ||
110 | */ | ||
111 | void *callback_cls; | ||
112 | |||
113 | /** | ||
114 | * Task scheduled to reconnect to the service. | ||
115 | */ | ||
116 | struct GNUNET_SCHEDULER_Task *reconnect_task; | ||
117 | |||
118 | /** | ||
119 | * How long to wait until we reconnect. | ||
120 | */ | ||
121 | struct GNUNET_TIME_Relative reconnect_delay; | ||
122 | }; | ||
123 | |||
124 | |||
125 | /** | ||
126 | * Task to connect to the NAT service. | ||
127 | * | ||
128 | * @param cls our `struct GNUNET_NAT_Handle *` | ||
129 | */ | ||
130 | static void | ||
131 | do_connect (void *cls); | ||
132 | |||
133 | |||
134 | /** | ||
135 | * Task to connect to the NAT service. | ||
136 | * | ||
137 | * @param nh handle to reconnect | ||
138 | */ | ||
139 | static void | ||
140 | reconnect (struct GNUNET_NAT_Handle *nh) | ||
141 | { | ||
142 | struct AddrEntry *ae; | ||
143 | |||
144 | if (NULL != nh->mq) | ||
145 | { | ||
146 | GNUNET_MQ_destroy (nh->mq); | ||
147 | nh->mq = NULL; | ||
148 | } | ||
149 | while (NULL != (ae = nh->ae_head)) | ||
150 | { | ||
151 | GNUNET_CONTAINER_DLL_remove (nh->ae_head, nh->ae_tail, ae); | ||
152 | nh->address_callback (nh->callback_cls, | ||
153 | &ae->app_ctx, | ||
154 | GNUNET_NO, | ||
155 | ae->ac, | ||
156 | (const struct sockaddr *) &ae[1], | ||
157 | ae->addrlen); | ||
158 | GNUNET_free (ae); | ||
159 | } | ||
160 | nh->reconnect_delay = GNUNET_TIME_STD_BACKOFF (nh->reconnect_delay); | ||
161 | nh->reconnect_task = | ||
162 | GNUNET_SCHEDULER_add_delayed (nh->reconnect_delay, &do_connect, nh); | ||
163 | } | ||
164 | |||
165 | |||
166 | /** | ||
167 | * Check connection reversal request. | ||
168 | * | ||
169 | * @param cls our `struct GNUNET_NAT_Handle` | ||
170 | * @param crm the message | ||
171 | * @return #GNUNET_OK if @a crm is well-formed | ||
172 | */ | ||
173 | static int | ||
174 | check_connection_reversal_request ( | ||
175 | void *cls, | ||
176 | const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm) | ||
177 | { | ||
178 | if (ntohs (crm->header.size) != sizeof(*crm) + sizeof(struct sockaddr_in)) | ||
179 | { | ||
180 | GNUNET_break (0); | ||
181 | return GNUNET_SYSERR; | ||
182 | } | ||
183 | return GNUNET_OK; | ||
184 | } | ||
185 | |||
186 | |||
187 | /** | ||
188 | * Handle connection reversal request. | ||
189 | * | ||
190 | * @param cls our `struct GNUNET_NAT_Handle` | ||
191 | * @param crm the message | ||
192 | */ | ||
193 | static void | ||
194 | handle_connection_reversal_request ( | ||
195 | void *cls, | ||
196 | const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm) | ||
197 | { | ||
198 | struct GNUNET_NAT_Handle *nh = cls; | ||
199 | |||
200 | nh->reversal_callback (nh->callback_cls, | ||
201 | (const struct sockaddr *) &crm[1], | ||
202 | sizeof(struct sockaddr_in)); | ||
203 | } | ||
204 | |||
205 | |||
206 | /** | ||
207 | * Check address change notification. | ||
208 | * | ||
209 | * @param cls our `struct GNUNET_NAT_Handle` | ||
210 | * @param acn the message | ||
211 | * @return #GNUNET_OK if @a crm is well-formed | ||
212 | */ | ||
213 | static int | ||
214 | check_address_change_notification ( | ||
215 | void *cls, | ||
216 | const struct GNUNET_NAT_AddressChangeNotificationMessage *acn) | ||
217 | { | ||
218 | size_t alen = ntohs (acn->header.size) - sizeof(*acn); | ||
219 | |||
220 | switch (alen) | ||
221 | { | ||
222 | case sizeof(struct sockaddr_in): { | ||
223 | const struct sockaddr_in *s4 = (const struct sockaddr_in *) &acn[1]; | ||
224 | if (AF_INET != s4->sin_family) | ||
225 | { | ||
226 | GNUNET_break (0); | ||
227 | return GNUNET_SYSERR; | ||
228 | } | ||
229 | } | ||
230 | break; | ||
231 | |||
232 | case sizeof(struct sockaddr_in6): { | ||
233 | const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) &acn[1]; | ||
234 | if (AF_INET6 != s6->sin6_family) | ||
235 | { | ||
236 | GNUNET_break (0); | ||
237 | return GNUNET_SYSERR; | ||
238 | } | ||
239 | } | ||
240 | break; | ||
241 | |||
242 | default: | ||
243 | GNUNET_break (0); | ||
244 | return GNUNET_SYSERR; | ||
245 | } | ||
246 | return GNUNET_OK; | ||
247 | } | ||
248 | |||
249 | |||
250 | /** | ||
251 | * Handle connection reversal request. | ||
252 | * | ||
253 | * @param cls our `struct GNUNET_NAT_Handle` | ||
254 | * @param acn the message | ||
255 | */ | ||
256 | static void | ||
257 | handle_address_change_notification ( | ||
258 | void *cls, | ||
259 | const struct GNUNET_NAT_AddressChangeNotificationMessage *acn) | ||
260 | { | ||
261 | struct GNUNET_NAT_Handle *nh = cls; | ||
262 | size_t alen = ntohs (acn->header.size) - sizeof(*acn); | ||
263 | const struct sockaddr *sa = (const struct sockaddr *) &acn[1]; | ||
264 | enum GNUNET_NAT_AddressClass ac; | ||
265 | struct AddrEntry *ae; | ||
266 | |||
267 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
268 | "Received address change notification\n"); | ||
269 | ac = (enum GNUNET_NAT_AddressClass) ntohl (acn->addr_class); | ||
270 | if (GNUNET_YES == ntohl (acn->add_remove)) | ||
271 | { | ||
272 | ae = GNUNET_malloc (sizeof(*ae) + alen); | ||
273 | ae->ac = ac; | ||
274 | ae->addrlen = alen; | ||
275 | GNUNET_memcpy (&ae[1], sa, alen); | ||
276 | GNUNET_CONTAINER_DLL_insert (nh->ae_head, nh->ae_tail, ae); | ||
277 | nh->address_callback (nh->callback_cls, | ||
278 | &ae->app_ctx, | ||
279 | ntohl (acn->add_remove), | ||
280 | ac, | ||
281 | sa, | ||
282 | alen); | ||
283 | } | ||
284 | else | ||
285 | { | ||
286 | for (ae = nh->ae_head; NULL != ae; ae = ae->next) | ||
287 | if ((ae->addrlen == alen) && (0 == memcmp (&ae[1], sa, alen))) | ||
288 | break; | ||
289 | if (NULL == ae) | ||
290 | { | ||
291 | GNUNET_break (0); | ||
292 | reconnect (nh); | ||
293 | return; | ||
294 | } | ||
295 | GNUNET_CONTAINER_DLL_remove (nh->ae_head, nh->ae_tail, ae); | ||
296 | nh->address_callback (nh->callback_cls, | ||
297 | &ae->app_ctx, | ||
298 | ntohl (acn->add_remove), | ||
299 | ac, | ||
300 | sa, | ||
301 | alen); | ||
302 | GNUNET_free (ae); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | |||
307 | /** | ||
308 | * Handle queue errors by reconnecting to NAT. | ||
309 | * | ||
310 | * @param cls the `struct GNUNET_NAT_Handle *` | ||
311 | * @param error details about the error | ||
312 | */ | ||
313 | static void | ||
314 | mq_error_handler (void *cls, | ||
315 | enum GNUNET_MQ_Error error) | ||
316 | { | ||
317 | struct GNUNET_NAT_Handle *nh = cls; | ||
318 | |||
319 | reconnect (nh); | ||
320 | } | ||
321 | |||
322 | |||
323 | /** | ||
324 | * Task to connect to the NAT service. | ||
325 | * | ||
326 | * @param cls our `struct GNUNET_NAT_Handle *` | ||
327 | */ | ||
328 | static void | ||
329 | do_connect (void *cls) | ||
330 | { | ||
331 | struct GNUNET_NAT_Handle *nh = cls; | ||
332 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
333 | GNUNET_MQ_hd_var_size ( | ||
334 | connection_reversal_request, | ||
335 | GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED, | ||
336 | struct GNUNET_NAT_ConnectionReversalRequestedMessage, | ||
337 | nh), | ||
338 | GNUNET_MQ_hd_var_size ( | ||
339 | address_change_notification, | ||
340 | GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE, | ||
341 | struct GNUNET_NAT_AddressChangeNotificationMessage, | ||
342 | nh), | ||
343 | GNUNET_MQ_handler_end () | ||
344 | }; | ||
345 | struct GNUNET_MQ_Envelope *env; | ||
346 | |||
347 | nh->reconnect_task = NULL; | ||
348 | nh->mq = | ||
349 | GNUNET_CLIENT_connect (nh->cfg, | ||
350 | "nat", | ||
351 | handlers, | ||
352 | &mq_error_handler, | ||
353 | nh); | ||
354 | if (NULL == nh->mq) | ||
355 | { | ||
356 | reconnect (nh); | ||
357 | return; | ||
358 | } | ||
359 | env = GNUNET_MQ_msg_copy (nh->reg); | ||
360 | GNUNET_MQ_send (nh->mq, | ||
361 | env); | ||
362 | } | ||
363 | |||
364 | |||
365 | /** | ||
366 | * Attempt to enable port redirection and detect public IP address | ||
367 | * contacting UPnP or NAT-PMP routers on the local network. Use @a | ||
368 | * addr to specify to which of the local host's addresses should the | ||
369 | * external port be mapped. The port is taken from the corresponding | ||
370 | * sockaddr_in[6] field. The NAT module should call the given @a | ||
371 | * address_callback for any 'plausible' external address. | ||
372 | * | ||
373 | * @param cfg configuration to use | ||
374 | * @param config_section name of the configuration section for optionsx | ||
375 | * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP | ||
376 | * @param num_addrs number of addresses in @a addrs | ||
377 | * @param addrs list of local addresses packets should be redirected to | ||
378 | * @param addrlens actual lengths of the addresses in @a addrs | ||
379 | * @param address_callback function to call every time the public IP address changes | ||
380 | * @param reversal_callback function to call if someone wants connection reversal from us, | ||
381 | * NULL if connection reversal is not supported | ||
382 | * @param callback_cls closure for callbacks | ||
383 | * @return NULL on error, otherwise handle that can be used to unregister | ||
384 | */ | ||
385 | struct GNUNET_NAT_Handle * | ||
386 | GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
387 | const char *config_section, | ||
388 | uint8_t proto, | ||
389 | unsigned int num_addrs, | ||
390 | const struct sockaddr **addrs, | ||
391 | const socklen_t *addrlens, | ||
392 | GNUNET_NAT_AddressCallback address_callback, | ||
393 | GNUNET_NAT_ReversalCallback reversal_callback, | ||
394 | void *callback_cls) | ||
395 | { | ||
396 | struct GNUNET_NAT_Handle *nh; | ||
397 | struct GNUNET_NAT_RegisterMessage *rm; | ||
398 | size_t len; | ||
399 | size_t str_len; | ||
400 | char *off; | ||
401 | |||
402 | len = 0; | ||
403 | for (unsigned int i = 0; i < num_addrs; i++) | ||
404 | len += addrlens[i]; | ||
405 | str_len = strlen (config_section) + 1; | ||
406 | len += str_len; | ||
407 | if ( (len > GNUNET_MAX_MESSAGE_SIZE - sizeof(*rm)) || | ||
408 | (num_addrs > UINT16_MAX) || | ||
409 | (str_len > UINT16_MAX) ) | ||
410 | { | ||
411 | GNUNET_break (0); | ||
412 | return NULL; | ||
413 | } | ||
414 | rm = GNUNET_malloc (sizeof(*rm) + len); | ||
415 | rm->header.size = htons (sizeof(*rm) + len); | ||
416 | rm->header.type = htons (GNUNET_MESSAGE_TYPE_NAT_REGISTER); | ||
417 | rm->flags = GNUNET_NAT_RF_NONE; | ||
418 | if (NULL != address_callback) | ||
419 | rm->flags |= GNUNET_NAT_RF_ADDRESSES; | ||
420 | if (NULL != reversal_callback) | ||
421 | rm->flags |= GNUNET_NAT_RF_REVERSAL; | ||
422 | rm->proto = proto; | ||
423 | rm->str_len = htons (str_len); | ||
424 | rm->num_addrs = htons ((uint16_t) num_addrs); | ||
425 | off = (char *) &rm[1]; | ||
426 | for (unsigned int i = 0; i < num_addrs; i++) | ||
427 | { | ||
428 | switch (addrs[i]->sa_family) | ||
429 | { | ||
430 | case AF_INET: | ||
431 | if (sizeof(struct sockaddr_in) != addrlens[i]) | ||
432 | { | ||
433 | GNUNET_break (0); | ||
434 | GNUNET_free (rm); | ||
435 | return NULL; | ||
436 | } | ||
437 | break; | ||
438 | |||
439 | case AF_INET6: | ||
440 | if (sizeof(struct sockaddr_in6) != addrlens[i]) | ||
441 | { | ||
442 | GNUNET_break (0); | ||
443 | GNUNET_free (rm); | ||
444 | return NULL; | ||
445 | } | ||
446 | break; | ||
447 | |||
448 | #if AF_UNIX | ||
449 | case AF_UNIX: | ||
450 | if (sizeof(struct sockaddr_un) != addrlens[i]) | ||
451 | { | ||
452 | GNUNET_break (0); | ||
453 | GNUNET_free (rm); | ||
454 | return NULL; | ||
455 | } | ||
456 | break; | ||
457 | #endif | ||
458 | default: | ||
459 | GNUNET_break (0); | ||
460 | GNUNET_free (rm); | ||
461 | return NULL; | ||
462 | } | ||
463 | GNUNET_memcpy (off, addrs[i], addrlens[i]); | ||
464 | off += addrlens[i]; | ||
465 | } | ||
466 | GNUNET_memcpy (off, config_section, str_len); | ||
467 | |||
468 | nh = GNUNET_new (struct GNUNET_NAT_Handle); | ||
469 | nh->reg = &rm->header; | ||
470 | nh->cfg = cfg; | ||
471 | nh->address_callback = address_callback; | ||
472 | nh->reversal_callback = reversal_callback; | ||
473 | nh->callback_cls = callback_cls; | ||
474 | do_connect (nh); | ||
475 | return nh; | ||
476 | } | ||
477 | |||
478 | |||
479 | /** | ||
480 | * Check if an incoming message is a STUN message. | ||
481 | * | ||
482 | * @param data the packet | ||
483 | * @param len the length of the packet in @a data | ||
484 | * @return #GNUNET_YES if @a data is a STUN packet, | ||
485 | * #GNUNET_NO if the packet is invalid (not a stun packet) | ||
486 | */ | ||
487 | static enum GNUNET_GenericReturnValue | ||
488 | test_stun_packet (const void *data, size_t len) | ||
489 | { | ||
490 | const struct stun_header *hdr; | ||
491 | const struct stun_attr *attr; | ||
492 | uint32_t advertised_message_size; | ||
493 | uint32_t message_magic_cookie; | ||
494 | |||
495 | /* On entry, 'len' is the length of the UDP payload. After the | ||
496 | * initial checks it becomes the size of unprocessed options, | ||
497 | * while 'data' is advanced accordingly. | ||
498 | */ | ||
499 | if (len < sizeof(struct stun_header)) | ||
500 | { | ||
501 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
502 | "STUN packet too short (only %d, wanting at least %d)\n", | ||
503 | (int) len, | ||
504 | (int) sizeof(struct stun_header)); | ||
505 | return GNUNET_NO; | ||
506 | } | ||
507 | hdr = (const struct stun_header *) data; | ||
508 | /* Skip header as it is already in hdr */ | ||
509 | len -= sizeof(struct stun_header); | ||
510 | data += sizeof(struct stun_header); | ||
511 | |||
512 | /* len as advertised in the message */ | ||
513 | advertised_message_size = ntohs (hdr->msglen); | ||
514 | |||
515 | message_magic_cookie = ntohl (hdr->magic); | ||
516 | /* Compare if the cookie match */ | ||
517 | if (STUN_MAGIC_COOKIE != message_magic_cookie) | ||
518 | { | ||
519 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Invalid magic cookie for STUN\n"); | ||
520 | return GNUNET_NO; | ||
521 | } | ||
522 | |||
523 | if (advertised_message_size > len) | ||
524 | { | ||
525 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
526 | "Scrambled STUN packet length (got %d, expecting %d)\n", | ||
527 | advertised_message_size, | ||
528 | (int) len); | ||
529 | return GNUNET_NO; | ||
530 | } | ||
531 | len = advertised_message_size; | ||
532 | while (len > 0) | ||
533 | { | ||
534 | if (len < sizeof(struct stun_attr)) | ||
535 | { | ||
536 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
537 | "Attribute too short in STUN packet (got %d, expecting %d)\n", | ||
538 | (int) len, | ||
539 | (int) sizeof(struct stun_attr)); | ||
540 | return GNUNET_NO; | ||
541 | } | ||
542 | attr = (const struct stun_attr *) data; | ||
543 | |||
544 | /* compute total attribute length */ | ||
545 | advertised_message_size = ntohs (attr->len) + sizeof(struct stun_attr); | ||
546 | |||
547 | /* Check if we still have space in our buffer */ | ||
548 | if (advertised_message_size > len) | ||
549 | { | ||
550 | GNUNET_log ( | ||
551 | GNUNET_ERROR_TYPE_DEBUG, | ||
552 | "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n", | ||
553 | advertised_message_size, | ||
554 | (int) len); | ||
555 | return GNUNET_NO; | ||
556 | } | ||
557 | data += advertised_message_size; | ||
558 | len -= advertised_message_size; | ||
559 | } | ||
560 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
561 | "STUN Packet, msg %04x, length: %d\n", | ||
562 | ntohs (hdr->msgtype), | ||
563 | advertised_message_size); | ||
564 | return GNUNET_OK; | ||
565 | } | ||
566 | |||
567 | |||
568 | /** | ||
569 | * Handle an incoming STUN message. This function is useful as | ||
570 | * some GNUnet service may be listening on a UDP port and might | ||
571 | * thus receive STUN messages while trying to receive other data. | ||
572 | * In this case, this function can be used to process replies | ||
573 | * to STUN requests. | ||
574 | * | ||
575 | * The function does some basic sanity checks on packet size and | ||
576 | * content, try to extract a bit of information. | ||
577 | * | ||
578 | * At the moment this only processes BIND requests, and returns the | ||
579 | * externally visible address of the request to the rest of the | ||
580 | * NAT logic. | ||
581 | * | ||
582 | * @param nh handle to the NAT service | ||
583 | * @param sender_addr address from which we got @a data | ||
584 | * @param sender_addr_len number of bytes in @a sender_addr | ||
585 | * @param data the packet | ||
586 | * @param data_size number of bytes in @a data | ||
587 | * @return #GNUNET_OK on success | ||
588 | * #GNUNET_NO if the packet is not a STUN packet | ||
589 | * #GNUNET_SYSERR on internal error handling the packet | ||
590 | */ | ||
591 | int | ||
592 | GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh, | ||
593 | const struct sockaddr *sender_addr, | ||
594 | size_t sender_addr_len, | ||
595 | const void *data, | ||
596 | size_t data_size) | ||
597 | { | ||
598 | struct GNUNET_MQ_Envelope *env; | ||
599 | struct GNUNET_NAT_HandleStunMessage *hsn; | ||
600 | char *buf; | ||
601 | |||
602 | if (GNUNET_YES != test_stun_packet (data, data_size)) | ||
603 | return GNUNET_NO; | ||
604 | if (NULL == nh->mq) | ||
605 | return GNUNET_SYSERR; | ||
606 | env = GNUNET_MQ_msg_extra (hsn, | ||
607 | data_size + sender_addr_len, | ||
608 | GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN); | ||
609 | hsn->sender_addr_size = htons ((uint16_t) sender_addr_len); | ||
610 | hsn->payload_size = htons ((uint16_t) data_size); | ||
611 | buf = (char *) &hsn[1]; | ||
612 | GNUNET_memcpy (buf, sender_addr, sender_addr_len); | ||
613 | buf += sender_addr_len; | ||
614 | GNUNET_memcpy (buf, data, data_size); | ||
615 | GNUNET_MQ_send (nh->mq, env); | ||
616 | return GNUNET_OK; | ||
617 | } | ||
618 | |||
619 | |||
620 | /** | ||
621 | * Test if the given address is (currently) a plausible IP address for | ||
622 | * this peer. Mostly a convenience function so that clients do not | ||
623 | * have to explicitly track all IPs that the #GNUNET_NAT_AddressCallback | ||
624 | * has returned so far. | ||
625 | * | ||
626 | * @param nh the handle returned by register | ||
627 | * @param addr IP address to test (IPv4 or IPv6) | ||
628 | * @param addrlen number of bytes in @a addr | ||
629 | * @return #GNUNET_YES if the address is plausible, | ||
630 | * #GNUNET_NO if the address is not plausible, | ||
631 | * #GNUNET_SYSERR if the address is malformed | ||
632 | */ | ||
633 | int | ||
634 | GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh, | ||
635 | const void *addr, | ||
636 | socklen_t addrlen) | ||
637 | { | ||
638 | struct AddrEntry *ae; | ||
639 | |||
640 | if ((addrlen != sizeof(struct sockaddr_in)) && | ||
641 | (addrlen != sizeof(struct sockaddr_in6))) | ||
642 | { | ||
643 | GNUNET_break (0); | ||
644 | return GNUNET_SYSERR; | ||
645 | } | ||
646 | for (ae = nh->ae_head; NULL != ae; ae = ae->next) | ||
647 | if ((addrlen == ae->addrlen) && (0 == memcmp (addr, &ae[1], addrlen))) | ||
648 | return GNUNET_YES; | ||
649 | return GNUNET_NO; | ||
650 | } | ||
651 | |||
652 | |||
653 | /** | ||
654 | * We learned about a peer (possibly behind NAT) so run the | ||
655 | * gnunet-nat-client to send dummy ICMP responses to cause | ||
656 | * that peer to connect to us (connection reversal). | ||
657 | * | ||
658 | * @param nh handle (used for configuration) | ||
659 | * @param local_sa our local address of the peer (IPv4-only) | ||
660 | * @param remote_sa the remote address of the peer (IPv4-only) | ||
661 | * @return #GNUNET_SYSERR on error, | ||
662 | * #GNUNET_NO if connection reversal is unavailable, | ||
663 | * #GNUNET_OK otherwise (presumably in progress) | ||
664 | */ | ||
665 | int | ||
666 | GNUNET_NAT_request_reversal (struct GNUNET_NAT_Handle *nh, | ||
667 | const struct sockaddr_in *local_sa, | ||
668 | const struct sockaddr_in *remote_sa) | ||
669 | { | ||
670 | struct GNUNET_MQ_Envelope *env; | ||
671 | struct GNUNET_NAT_RequestConnectionReversalMessage *req; | ||
672 | char *buf; | ||
673 | |||
674 | if (NULL == nh->mq) | ||
675 | return GNUNET_SYSERR; | ||
676 | GNUNET_break (AF_INET == local_sa->sin_family); | ||
677 | GNUNET_break (AF_INET == remote_sa->sin_family); | ||
678 | env = | ||
679 | GNUNET_MQ_msg_extra (req, | ||
680 | 2 * sizeof(struct sockaddr_in), | ||
681 | GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL); | ||
682 | req->local_addr_size = htons (sizeof(struct sockaddr_in)); | ||
683 | req->remote_addr_size = htons (sizeof(struct sockaddr_in)); | ||
684 | buf = (char *) &req[1]; | ||
685 | GNUNET_memcpy (buf, local_sa, sizeof(struct sockaddr_in)); | ||
686 | buf += sizeof(struct sockaddr_in); | ||
687 | GNUNET_memcpy (buf, remote_sa, sizeof(struct sockaddr_in)); | ||
688 | GNUNET_MQ_send (nh->mq, env); | ||
689 | return GNUNET_OK; | ||
690 | } | ||
691 | |||
692 | |||
693 | /** | ||
694 | * Stop port redirection and public IP address detection for the given | ||
695 | * handle. This frees the handle, after having sent the needed | ||
696 | * commands to close open ports. | ||
697 | * | ||
698 | * @param nh the handle to stop | ||
699 | */ | ||
700 | void | ||
701 | GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh) | ||
702 | { | ||
703 | if (NULL != nh->mq) | ||
704 | { | ||
705 | GNUNET_MQ_destroy (nh->mq); | ||
706 | nh->mq = NULL; | ||
707 | } | ||
708 | if (NULL != nh->reconnect_task) | ||
709 | { | ||
710 | GNUNET_SCHEDULER_cancel (nh->reconnect_task); | ||
711 | nh->reconnect_task = NULL; | ||
712 | } | ||
713 | GNUNET_free (nh->reg); | ||
714 | GNUNET_free (nh); | ||
715 | } | ||
716 | |||
717 | |||
718 | /* end of nat_api.c */ | ||
diff --git a/src/nat/nat_api_stun.c b/src/nat/nat_api_stun.c deleted file mode 100644 index 0bc2c5fbd..000000000 --- a/src/nat/nat_api_stun.c +++ /dev/null | |||
@@ -1,259 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2015, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * This code provides some support for doing STUN transactions. | ||
22 | * We send simplest possible packet ia REQUEST with BIND to a STUN server. | ||
23 | * | ||
24 | * All STUN packets start with a simple header made of a type, | ||
25 | * length (excluding the header) and a 16-byte random transaction id. | ||
26 | * Following the header we may have zero or more attributes, each | ||
27 | * structured as a type, length and a value (whose format depends | ||
28 | * on the type, but often contains addresses). | ||
29 | * Of course all fields are in network format. | ||
30 | * | ||
31 | * This code was based on ministun.c. | ||
32 | * | ||
33 | * @file nat/nat_api_stun.c | ||
34 | * @brief Functions for STUN functionality | ||
35 | * @author Bruno Souza Cabral | ||
36 | */ | ||
37 | |||
38 | #include "platform.h" | ||
39 | #include "gnunet_util_lib.h" | ||
40 | #include "gnunet_resolver_service.h" | ||
41 | #include "gnunet_nat_service.h" | ||
42 | |||
43 | |||
44 | #include "nat_stun.h" | ||
45 | |||
46 | #define LOG(kind, ...) GNUNET_log_from (kind, "stun", __VA_ARGS__) | ||
47 | |||
48 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) | ||
49 | |||
50 | |||
51 | /** | ||
52 | * Handle to a request given to the resolver. Can be used to cancel | ||
53 | * the request prior to the timeout or successful execution. Also | ||
54 | * used to track our internal state for the request. | ||
55 | */ | ||
56 | struct GNUNET_NAT_STUN_Handle | ||
57 | { | ||
58 | /** | ||
59 | * Handle to a pending DNS lookup request. | ||
60 | */ | ||
61 | struct GNUNET_RESOLVER_RequestHandle *dns_active; | ||
62 | |||
63 | /** | ||
64 | * Handle to the listen socket | ||
65 | */ | ||
66 | struct GNUNET_NETWORK_Handle *sock; | ||
67 | |||
68 | /** | ||
69 | * Stun server address | ||
70 | */ | ||
71 | char *stun_server; | ||
72 | |||
73 | /** | ||
74 | * Function to call when a error occurs | ||
75 | */ | ||
76 | GNUNET_NAT_TestCallback cb; | ||
77 | |||
78 | /** | ||
79 | * Closure for @e cb. | ||
80 | */ | ||
81 | void *cb_cls; | ||
82 | |||
83 | /** | ||
84 | * Do we got a DNS resolution successfully? | ||
85 | */ | ||
86 | int dns_success; | ||
87 | |||
88 | /** | ||
89 | * STUN port | ||
90 | */ | ||
91 | uint16_t stun_port; | ||
92 | }; | ||
93 | |||
94 | |||
95 | /** | ||
96 | * Encode a class and method to a compatible STUN format | ||
97 | * | ||
98 | * @param msg_class class to be converted | ||
99 | * @param method method to be converted | ||
100 | * @return message in a STUN compatible format | ||
101 | */ | ||
102 | static int | ||
103 | encode_message (enum StunClasses msg_class, | ||
104 | enum StunMethods method) | ||
105 | { | ||
106 | return ((msg_class & 1) << 4) | ((msg_class & 2) << 7) | ||
107 | | (method & 0x000f) | ((method & 0x0070) << 1) | ((method & 0x0f800) | ||
108 | << 2); | ||
109 | } | ||
110 | |||
111 | |||
112 | /** | ||
113 | * Fill the stun_header with a random request_id | ||
114 | * | ||
115 | * @param req, stun header to be filled | ||
116 | */ | ||
117 | static void | ||
118 | generate_request_id (struct stun_header *req) | ||
119 | { | ||
120 | req->magic = htonl (STUN_MAGIC_COOKIE); | ||
121 | for (unsigned int x = 0; x < 3; x++) | ||
122 | req->id.id[x] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, | ||
123 | UINT32_MAX); | ||
124 | } | ||
125 | |||
126 | |||
127 | /** | ||
128 | * Try to establish a connection given the specified address. | ||
129 | * | ||
130 | * @param cls our `struct GNUNET_NAT_STUN_Handle *` | ||
131 | * @param addr address to try, NULL for "last call" | ||
132 | * @param addrlen length of @a addr | ||
133 | */ | ||
134 | static void | ||
135 | stun_dns_callback (void *cls, | ||
136 | const struct sockaddr *addr, | ||
137 | socklen_t addrlen) | ||
138 | { | ||
139 | struct GNUNET_NAT_STUN_Handle *rh = cls; | ||
140 | struct stun_header req; | ||
141 | struct sockaddr_in server; | ||
142 | |||
143 | if (NULL == addr) | ||
144 | { | ||
145 | rh->dns_active = NULL; | ||
146 | if (GNUNET_NO == rh->dns_success) | ||
147 | { | ||
148 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
149 | "Error resolving host %s\n", | ||
150 | rh->stun_server); | ||
151 | rh->cb (rh->cb_cls, | ||
152 | GNUNET_NAT_ERROR_NOT_ONLINE); | ||
153 | } | ||
154 | else if (GNUNET_SYSERR == rh->dns_success) | ||
155 | { | ||
156 | rh->cb (rh->cb_cls, | ||
157 | GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR); | ||
158 | } | ||
159 | else | ||
160 | { | ||
161 | rh->cb (rh->cb_cls, | ||
162 | GNUNET_NAT_ERROR_SUCCESS); | ||
163 | } | ||
164 | GNUNET_NAT_stun_make_request_cancel (rh); | ||
165 | return; | ||
166 | } | ||
167 | |||
168 | rh->dns_success = GNUNET_YES; | ||
169 | memset (&server, 0, sizeof(server)); | ||
170 | server.sin_family = AF_INET; | ||
171 | server.sin_addr = ((struct sockaddr_in *) addr)->sin_addr; | ||
172 | server.sin_port = htons (rh->stun_port); | ||
173 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
174 | server.sin_len = (u_char) sizeof(struct sockaddr_in); | ||
175 | #endif | ||
176 | |||
177 | /* Craft the simplest possible STUN packet. A request binding */ | ||
178 | generate_request_id (&req); | ||
179 | req.msglen = htons (0); | ||
180 | req.msgtype = htons (encode_message (STUN_REQUEST, | ||
181 | STUN_BINDING)); | ||
182 | |||
183 | /* Send the packet */ | ||
184 | if (-1 == | ||
185 | GNUNET_NETWORK_socket_sendto (rh->sock, | ||
186 | &req, | ||
187 | sizeof(req), | ||
188 | (const struct sockaddr *) &server, | ||
189 | sizeof(server))) | ||
190 | { | ||
191 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, | ||
192 | "sendto"); | ||
193 | rh->dns_success = GNUNET_SYSERR; | ||
194 | return; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | |||
199 | /** | ||
200 | * Make Generic STUN request. Sends a generic stun request to the | ||
201 | * server specified using the specified socket. | ||
202 | * | ||
203 | * @param server the address of the stun server | ||
204 | * @param port port of the stun server, in host byte order | ||
205 | * @param sock the socket used to send the request | ||
206 | * @param cb callback in case of error | ||
207 | * @param cb_cls closure for @a cb | ||
208 | * @return NULL on error | ||
209 | */ | ||
210 | struct GNUNET_NAT_STUN_Handle * | ||
211 | GNUNET_NAT_stun_make_request (const char *server, | ||
212 | uint16_t port, | ||
213 | struct GNUNET_NETWORK_Handle *sock, | ||
214 | GNUNET_NAT_TestCallback cb, | ||
215 | void *cb_cls) | ||
216 | { | ||
217 | struct GNUNET_NAT_STUN_Handle *rh; | ||
218 | |||
219 | rh = GNUNET_new (struct GNUNET_NAT_STUN_Handle); | ||
220 | rh->sock = sock; | ||
221 | rh->cb = cb; | ||
222 | rh->cb_cls = cb_cls; | ||
223 | rh->stun_server = GNUNET_strdup (server); | ||
224 | rh->stun_port = port; | ||
225 | rh->dns_success = GNUNET_NO; | ||
226 | rh->dns_active = GNUNET_RESOLVER_ip_get (rh->stun_server, | ||
227 | AF_INET, | ||
228 | TIMEOUT, | ||
229 | &stun_dns_callback, | ||
230 | rh); | ||
231 | if (NULL == rh->dns_active) | ||
232 | { | ||
233 | GNUNET_NAT_stun_make_request_cancel (rh); | ||
234 | return NULL; | ||
235 | } | ||
236 | return rh; | ||
237 | } | ||
238 | |||
239 | |||
240 | /** | ||
241 | * Cancel active STUN request. Frees associated resources | ||
242 | * and ensures that the callback is no longer invoked. | ||
243 | * | ||
244 | * @param rh request to cancel | ||
245 | */ | ||
246 | void | ||
247 | GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh) | ||
248 | { | ||
249 | if (NULL != rh->dns_active) | ||
250 | { | ||
251 | GNUNET_RESOLVER_request_cancel (rh->dns_active); | ||
252 | rh->dns_active = NULL; | ||
253 | } | ||
254 | GNUNET_free (rh->stun_server); | ||
255 | GNUNET_free (rh); | ||
256 | } | ||
257 | |||
258 | |||
259 | /* end of nat_stun.c */ | ||
diff --git a/src/nat/nat_stun.h b/src/nat/nat_stun.h deleted file mode 100644 index a31e0f8d6..000000000 --- a/src/nat/nat_stun.h +++ /dev/null | |||
@@ -1,267 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2015, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * Message types for STUN server resolution | ||
22 | * | ||
23 | * @file nat/nat_stun.h | ||
24 | * @brief Testcase for STUN library | ||
25 | * @author Bruno Souza Cabral | ||
26 | * @author Mark Spencer (Original code borrowed from Asterisk) | ||
27 | * @author Christian Grothoff | ||
28 | */ | ||
29 | |||
30 | |||
31 | #define STUN_IGNORE (0) | ||
32 | #define STUN_ACCEPT (1) | ||
33 | |||
34 | #define STUN_MAGIC_COOKIE 0x2112A442 | ||
35 | |||
36 | typedef struct | ||
37 | { | ||
38 | uint32_t id[3]; | ||
39 | } GNUNET_PACKED stun_trans_id; | ||
40 | |||
41 | |||
42 | struct stun_header | ||
43 | { | ||
44 | uint16_t msgtype; | ||
45 | uint16_t msglen; | ||
46 | uint32_t magic; | ||
47 | stun_trans_id id; | ||
48 | } GNUNET_PACKED; | ||
49 | |||
50 | |||
51 | struct stun_attr | ||
52 | { | ||
53 | uint16_t attr; | ||
54 | uint16_t len; | ||
55 | } GNUNET_PACKED; | ||
56 | |||
57 | |||
58 | /** | ||
59 | * The format normally used for addresses carried by STUN messages. | ||
60 | */ | ||
61 | struct stun_addr | ||
62 | { | ||
63 | uint8_t unused; | ||
64 | |||
65 | /** | ||
66 | * Address family, we expect AF_INET. | ||
67 | */ | ||
68 | uint8_t family; | ||
69 | |||
70 | /** | ||
71 | * Port number. | ||
72 | */ | ||
73 | uint16_t port; | ||
74 | |||
75 | /** | ||
76 | * IPv4 address. Should this be "struct in_addr"? | ||
77 | */ | ||
78 | uint32_t addr; | ||
79 | } GNUNET_PACKED; | ||
80 | |||
81 | |||
82 | /** | ||
83 | * STUN message classes | ||
84 | */ | ||
85 | enum StunClasses | ||
86 | { | ||
87 | INVALID_CLASS = 0, | ||
88 | STUN_REQUEST = 0x0000, | ||
89 | STUN_INDICATION = 0x0001, | ||
90 | STUN_RESPONSE = 0x0002, | ||
91 | STUN_ERROR_RESPONSE = 0x0003 | ||
92 | }; | ||
93 | |||
94 | enum StunMethods | ||
95 | { | ||
96 | INVALID_METHOD = 0, | ||
97 | STUN_BINDING = 0x0001, | ||
98 | STUN_SHARED_SECRET = 0x0002, | ||
99 | STUN_ALLOCATE = 0x0003, | ||
100 | STUN_REFRESH = 0x0004, | ||
101 | STUN_SEND = 0x0006, | ||
102 | STUN_DATA = 0x0007, | ||
103 | STUN_CREATE_PERMISSION = 0x0008, | ||
104 | STUN_CHANNEL_BIND = 0x0009 | ||
105 | }; | ||
106 | |||
107 | |||
108 | /** | ||
109 | * Basic attribute types in stun messages. | ||
110 | * Messages can also contain custom attributes (codes above 0x7fff) | ||
111 | */ | ||
112 | enum StunAttributes | ||
113 | { | ||
114 | STUN_MAPPED_ADDRESS = 0x0001, | ||
115 | STUN_RESPONSE_ADDRESS = 0x0002, | ||
116 | STUN_CHANGE_ADDRESS = 0x0003, | ||
117 | STUN_SOURCE_ADDRESS = 0x0004, | ||
118 | STUN_CHANGED_ADDRESS = 0x0005, | ||
119 | STUN_USERNAME = 0x0006, | ||
120 | STUN_PASSWORD = 0x0007, | ||
121 | STUN_MESSAGE_INTEGRITY = 0x0008, | ||
122 | STUN_ERROR_CODE = 0x0009, | ||
123 | STUN_UNKNOWN_ATTRIBUTES = 0x000a, | ||
124 | STUN_REFLECTED_FROM = 0x000b, | ||
125 | STUN_REALM = 0x0014, | ||
126 | STUN_NONCE = 0x0015, | ||
127 | STUN_XOR_MAPPED_ADDRESS = 0x0020, | ||
128 | STUN_MS_VERSION = 0x8008, | ||
129 | STUN_MS_XOR_MAPPED_ADDRESS = 0x8020, | ||
130 | STUN_SOFTWARE = 0x8022, | ||
131 | STUN_ALTERNATE_SERVER = 0x8023, | ||
132 | STUN_FINGERPRINT = 0x8028 | ||
133 | }; | ||
134 | |||
135 | |||
136 | /** | ||
137 | * Convert a message to a StunClass | ||
138 | * | ||
139 | * @param msg the received message | ||
140 | * @return the converted StunClass | ||
141 | */ | ||
142 | static enum StunClasses | ||
143 | decode_class (int msg) | ||
144 | { | ||
145 | /* Sorry for the magic, but this maps the class according to rfc5245 */ | ||
146 | return (enum StunClasses) ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7); | ||
147 | } | ||
148 | |||
149 | |||
150 | /** | ||
151 | * Convert a message to a StunMethod | ||
152 | * | ||
153 | * @param msg the received message | ||
154 | * @return the converted StunMethod | ||
155 | */ | ||
156 | static enum StunMethods | ||
157 | decode_method (int msg) | ||
158 | { | ||
159 | return (enum StunMethods) (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg | ||
160 | & 0x3e00) | ||
161 | >> 2); | ||
162 | } | ||
163 | |||
164 | |||
165 | /** | ||
166 | * Print a class and method from a STUN message | ||
167 | * | ||
168 | * @param msg | ||
169 | * @return string with the message class and method | ||
170 | */ | ||
171 | GNUNET_UNUSED | ||
172 | static const char * | ||
173 | stun_msg2str (int msg) | ||
174 | { | ||
175 | static const struct | ||
176 | { | ||
177 | enum StunClasses value; | ||
178 | const char *name; | ||
179 | } classes[] = { | ||
180 | { STUN_REQUEST, "Request" }, | ||
181 | { STUN_INDICATION, "Indication" }, | ||
182 | { STUN_RESPONSE, "Response" }, | ||
183 | { STUN_ERROR_RESPONSE, "Error Response" }, | ||
184 | { INVALID_CLASS, NULL } | ||
185 | }; | ||
186 | static const struct | ||
187 | { | ||
188 | enum StunMethods value; | ||
189 | const char *name; | ||
190 | } methods[] = { | ||
191 | { STUN_BINDING, "Binding" }, | ||
192 | { INVALID_METHOD, NULL } | ||
193 | }; | ||
194 | static char result[64]; | ||
195 | const char *msg_class = NULL; | ||
196 | const char *method = NULL; | ||
197 | enum StunClasses cvalue; | ||
198 | enum StunMethods mvalue; | ||
199 | |||
200 | cvalue = decode_class (msg); | ||
201 | for (unsigned int i = 0; classes[i].name; i++) | ||
202 | if (classes[i].value == cvalue) | ||
203 | { | ||
204 | msg_class = classes[i].name; | ||
205 | break; | ||
206 | } | ||
207 | mvalue = decode_method (msg); | ||
208 | for (unsigned int i = 0; methods[i].name; i++) | ||
209 | if (methods[i].value == mvalue) | ||
210 | { | ||
211 | method = methods[i].name; | ||
212 | break; | ||
213 | } | ||
214 | GNUNET_snprintf (result, | ||
215 | sizeof(result), | ||
216 | "%s %s", | ||
217 | method ? : "Unknown Method", | ||
218 | msg_class ? : "Unknown Class Message"); | ||
219 | return result; | ||
220 | } | ||
221 | |||
222 | |||
223 | /** | ||
224 | * Print attribute name | ||
225 | * | ||
226 | * @param msg with a attribute type | ||
227 | * @return string with the attribute name | ||
228 | */ | ||
229 | GNUNET_UNUSED | ||
230 | static const char * | ||
231 | stun_attr2str (enum StunAttributes msg) | ||
232 | { | ||
233 | static const struct | ||
234 | { | ||
235 | enum StunAttributes value; | ||
236 | const char *name; | ||
237 | } attrs[] = { | ||
238 | { STUN_MAPPED_ADDRESS, "Mapped Address" }, | ||
239 | { STUN_RESPONSE_ADDRESS, "Response Address" }, | ||
240 | { STUN_CHANGE_ADDRESS, "Change Address" }, | ||
241 | { STUN_SOURCE_ADDRESS, "Source Address" }, | ||
242 | { STUN_CHANGED_ADDRESS, "Changed Address" }, | ||
243 | { STUN_USERNAME, "Username" }, | ||
244 | { STUN_PASSWORD, "Password" }, | ||
245 | { STUN_MESSAGE_INTEGRITY, "Message Integrity" }, | ||
246 | { STUN_ERROR_CODE, "Error Code" }, | ||
247 | { STUN_UNKNOWN_ATTRIBUTES, "Unknown Attributes" }, | ||
248 | { STUN_REFLECTED_FROM, "Reflected From" }, | ||
249 | { STUN_REALM, "Realm" }, | ||
250 | { STUN_NONCE, "Nonce" }, | ||
251 | { STUN_XOR_MAPPED_ADDRESS, "XOR Mapped Address" }, | ||
252 | { STUN_MS_VERSION, "MS Version" }, | ||
253 | { STUN_MS_XOR_MAPPED_ADDRESS, "MS XOR Mapped Address" }, | ||
254 | { STUN_SOFTWARE, "Software" }, | ||
255 | { STUN_ALTERNATE_SERVER, "Alternate Server" }, | ||
256 | { STUN_FINGERPRINT, "Fingerprint" }, | ||
257 | { 0, NULL } | ||
258 | }; | ||
259 | |||
260 | for (unsigned int i = 0; attrs[i].name; i++) | ||
261 | if (attrs[i].value == msg) | ||
262 | return attrs[i].name; | ||
263 | return "Unknown Attribute"; | ||
264 | } | ||
265 | |||
266 | |||
267 | /* end of nat_stun.h */ | ||
diff --git a/src/nat/test_nat.c b/src/nat/test_nat.c deleted file mode 100644 index a3072f712..000000000 --- a/src/nat/test_nat.c +++ /dev/null | |||
@@ -1,192 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * Testcase for port redirection and public IP address retrieval. | ||
23 | * This test never fails, because there need to be a NAT box set up for that. | ||
24 | * So we only get IP address and open the 2086 port using any NAT traversal | ||
25 | * method available, wait for 30s, close ports and return. | ||
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! | ||
34 | */ | ||
35 | |||
36 | #include "platform.h" | ||
37 | #include "gnunet_util_lib.h" | ||
38 | #include "gnunet_program_lib.h" | ||
39 | #include "gnunet_scheduler_lib.h" | ||
40 | #include "gnunet_nat_lib.h" | ||
41 | |||
42 | |||
43 | /** | ||
44 | * Time to wait before stopping NAT, in seconds | ||
45 | */ | ||
46 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Function called on each address that the NAT service | ||
51 | * believes to be valid for the transport. | ||
52 | */ | ||
53 | static void | ||
54 | addr_callback (void *cls, int add_remove, const struct sockaddr *addr, | ||
55 | socklen_t addrlen) | ||
56 | { | ||
57 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
58 | "Address changed: %s `%s' (%u bytes)\n", | ||
59 | add_remove == GNUNET_YES ? "added" : "removed", | ||
60 | GNUNET_a2s (addr, | ||
61 | addrlen), | ||
62 | (unsigned int) addrlen); | ||
63 | } | ||
64 | |||
65 | |||
66 | /** | ||
67 | * Function that terminates the test. | ||
68 | */ | ||
69 | static void | ||
70 | stop (void *cls) | ||
71 | { | ||
72 | struct GNUNET_NAT_Handle *nat = cls; | ||
73 | |||
74 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
75 | "Stopping NAT and quitting...\n"); | ||
76 | GNUNET_NAT_unregister (nat); | ||
77 | } | ||
78 | |||
79 | |||
80 | struct addr_cls | ||
81 | { | ||
82 | struct sockaddr *addr; | ||
83 | socklen_t addrlen; | ||
84 | }; | ||
85 | |||
86 | |||
87 | /** | ||
88 | * Return the address of the default interface, | ||
89 | * or any interface with a valid address if the default is not valid | ||
90 | * | ||
91 | * @param cls the 'struct addr_cls' | ||
92 | * @param name name of the interface | ||
93 | * @param isDefault do we think this may be our default interface | ||
94 | * @param addr address of the interface | ||
95 | * @param addrlen number of bytes in @a addr | ||
96 | * @return #GNUNET_OK to continue iterating | ||
97 | */ | ||
98 | static int | ||
99 | process_if (void *cls, | ||
100 | const char *name, | ||
101 | int isDefault, | ||
102 | const struct sockaddr *addr, | ||
103 | const struct sockaddr *broadcast_addr, | ||
104 | const struct sockaddr *netmask, | ||
105 | socklen_t addrlen) | ||
106 | { | ||
107 | struct addr_cls *data = cls; | ||
108 | |||
109 | if (addr == NULL) | ||
110 | return GNUNET_OK; | ||
111 | GNUNET_free (data->addr); | ||
112 | data->addr = GNUNET_malloc (addrlen); | ||
113 | GNUNET_memcpy (data->addr, addr, addrlen); | ||
114 | data->addrlen = addrlen; | ||
115 | if (isDefault) | ||
116 | return GNUNET_SYSERR; | ||
117 | return GNUNET_OK; | ||
118 | } | ||
119 | |||
120 | |||
121 | /** | ||
122 | * Main function run with scheduler. | ||
123 | */ | ||
124 | static void | ||
125 | run (void *cls, | ||
126 | char *const *args, | ||
127 | const char *cfgfile, | ||
128 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
129 | { | ||
130 | struct GNUNET_NAT_Handle *nat; | ||
131 | struct addr_cls data; | ||
132 | struct sockaddr *addr; | ||
133 | |||
134 | data.addr = NULL; | ||
135 | GNUNET_OS_network_interfaces_list (process_if, &data); | ||
136 | if (NULL == data.addr) | ||
137 | { | ||
138 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
139 | "Could not find a valid interface address!\n"); | ||
140 | exit (77); /* marks test as skipped */ | ||
141 | } | ||
142 | addr = data.addr; | ||
143 | GNUNET_assert (addr->sa_family == AF_INET || addr->sa_family == AF_INET6); | ||
144 | if (addr->sa_family == AF_INET) | ||
145 | ((struct sockaddr_in *) addr)->sin_port = htons (2086); | ||
146 | else | ||
147 | ((struct sockaddr_in6 *) addr)->sin6_port = htons (2086); | ||
148 | |||
149 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
150 | "Requesting NAT redirection from address %s...\n", | ||
151 | GNUNET_a2s (addr, data.addrlen)); | ||
152 | |||
153 | nat = GNUNET_NAT_register (cfg, GNUNET_YES /* tcp */, | ||
154 | 2086, 1, (const struct sockaddr **) &addr, | ||
155 | &data.addrlen, &addr_callback, NULL, NULL, NULL); | ||
156 | GNUNET_free (addr); | ||
157 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, &stop, nat); | ||
158 | } | ||
159 | |||
160 | |||
161 | int | ||
162 | main (int argc, char *const argv[]) | ||
163 | { | ||
164 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
165 | GNUNET_GETOPT_OPTION_END | ||
166 | }; | ||
167 | |||
168 | char *const argv_prog[] = { | ||
169 | "test-nat", | ||
170 | "-c", | ||
171 | "test_nat_data.conf", | ||
172 | NULL | ||
173 | }; | ||
174 | |||
175 | GNUNET_log_setup ("test-nat", | ||
176 | "WARNING", | ||
177 | NULL); | ||
178 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
179 | "Testing NAT library, timeout set to %s\n", | ||
180 | GNUNET_STRINGS_relative_time_to_string (TIMEOUT, | ||
181 | GNUNET_YES)); | ||
182 | GNUNET_PROGRAM_run (3, | ||
183 | argv_prog, | ||
184 | "test-nat", | ||
185 | "nohelp", | ||
186 | options, | ||
187 | &run, NULL); | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | |||
192 | /* end of test_nat.c */ | ||
diff --git a/src/nat/test_nat_data.conf b/src/nat/test_nat_data.conf deleted file mode 100644 index e139d0c05..000000000 --- a/src/nat/test_nat_data.conf +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | [PATHS] | ||
2 | GNUNET_TEST_HOME = $GNUNET_TMP/nat-test | ||
3 | # GNUNET_TEST_HOME = /var/lib/gnunet/ | ||
4 | # configuration file is assumed to be the default, | ||
5 | # which is what we want by default... | ||
6 | |||
7 | [nat] | ||
8 | # Are we behind NAT? | ||
9 | BEHIND_NAT = YES | ||
10 | |||
11 | # Is the NAT hole-punched? | ||
12 | PUNCHED_NAT = NO | ||
13 | |||
14 | # Disable UPNP by default until it gets cleaner! | ||
15 | ENABLE_UPNP = YES | ||
16 | |||
17 | # Use addresses from the local network interfaces (including loopback, but also others) | ||
18 | USE_LOCALADDR = YES | ||
19 | |||
20 | # External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) | ||
21 | # normal interface IP address for non-NATed peers; | ||
22 | # possibly auto-detected (using UPnP) if possible if not specified | ||
23 | # EXTERNAL_ADDRESS = | ||
24 | |||
25 | # Should we use ICMP-based NAT traversal to try connect to NATed peers | ||
26 | # or, if we are behind NAT, to allow connections to us? | ||
27 | ENABLE_ICMP_CLIENT = NO | ||
28 | ENABLE_ICMP_SERVER = NO | ||
29 | |||
30 | # IP address of the interface connected to the NAT box; IPv4 dotted-decimal ONLY; | ||
31 | # normal interface IP address for non-NATed peers; | ||
32 | # likely auto-detected (via interface list) if not specified (!) | ||
33 | # INTERNAL_ADDRESS = | ||
34 | |||
35 | # Disable IPv6 support | ||
36 | DISABLEV6 = NO | ||
diff --git a/src/nat/test_nat_mini.c b/src/nat/test_nat_mini.c deleted file mode 100644 index 528815e1a..000000000 --- a/src/nat/test_nat_mini.c +++ /dev/null | |||
@@ -1,134 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file nat/test_nat_mini.c | ||
22 | * @brief Testcase for NAT library - mini | ||
23 | * @author Christian Grothoff | ||
24 | * | ||
25 | * Testcase for port redirection and public IP address retrieval. | ||
26 | * This test never fails, because there need to be a NAT box set up for that | ||
27 | * | ||
28 | * TODO: actually use ARM to start resolver service to make DNS work! | ||
29 | */ | ||
30 | |||
31 | #include "platform.h" | ||
32 | #include "gnunet_util_lib.h" | ||
33 | #include "gnunet_program_lib.h" | ||
34 | #include "gnunet_scheduler_lib.h" | ||
35 | #include "gnunet_nat_lib.h" | ||
36 | |||
37 | /* Time to wait before stopping NAT, in seconds */ | ||
38 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
39 | |||
40 | /** | ||
41 | * Function called on each address that the NAT service | ||
42 | * believes to be valid for the transport. | ||
43 | */ | ||
44 | static void | ||
45 | addr_callback (void *cls, int add_remove, | ||
46 | const struct sockaddr *addr, | ||
47 | socklen_t addrlen, | ||
48 | enum GNUNET_NAT_StatusCode ret) | ||
49 | { | ||
50 | if (GNUNET_NAT_ERROR_SUCCESS == ret) | ||
51 | { | ||
52 | fprintf (stderr, | ||
53 | "Address changed: %s `%s' (%u bytes)\n", | ||
54 | add_remove == GNUNET_YES | ||
55 | ? "added" : "removed", | ||
56 | GNUNET_a2s (addr, | ||
57 | addrlen), | ||
58 | (unsigned int) addrlen); | ||
59 | } | ||
60 | else | ||
61 | ; | ||
62 | // TODO: proper error handling! | ||
63 | } | ||
64 | |||
65 | |||
66 | /** | ||
67 | * Function that terminates the test. | ||
68 | */ | ||
69 | static void | ||
70 | stop (void *cls) | ||
71 | { | ||
72 | struct GNUNET_NAT_MiniHandle *mini = cls; | ||
73 | |||
74 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping NAT and quitting...\n"); | ||
75 | GNUNET_NAT_mini_map_stop (mini); | ||
76 | } | ||
77 | |||
78 | |||
79 | #define PORT 10000 | ||
80 | |||
81 | /** | ||
82 | * Main function run with scheduler. | ||
83 | */ | ||
84 | static void | ||
85 | run (void *cls, char *const *args, const char *cfgfile, | ||
86 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
87 | { | ||
88 | struct GNUNET_NAT_MiniHandle *mini; | ||
89 | |||
90 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
91 | "Requesting NAT redirection for port %u...\n", | ||
92 | PORT); | ||
93 | mini = GNUNET_NAT_mini_map_start (PORT, GNUNET_YES /* tcp */, | ||
94 | &addr_callback, NULL); | ||
95 | if (NULL == mini) | ||
96 | { | ||
97 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Could not start UPnP interaction\n"); | ||
98 | return; | ||
99 | } | ||
100 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, &stop, mini); | ||
101 | } | ||
102 | |||
103 | |||
104 | int | ||
105 | main (int argc, char *const argv[]) | ||
106 | { | ||
107 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
108 | GNUNET_GETOPT_OPTION_END | ||
109 | }; | ||
110 | |||
111 | char *const argv_prog[] = { | ||
112 | "test-nat-mini", | ||
113 | "-c", | ||
114 | "test_nat_data.conf", | ||
115 | "-L", | ||
116 | "WARNING", | ||
117 | NULL | ||
118 | }; | ||
119 | |||
120 | GNUNET_log_setup ("test-nat-mini", | ||
121 | "WARNING", | ||
122 | NULL); | ||
123 | |||
124 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
125 | "UPnP test for NAT library, timeout set to %s\n", | ||
126 | GNUNET_STRINGS_relative_time_to_string (TIMEOUT, | ||
127 | GNUNET_YES)); | ||
128 | GNUNET_PROGRAM_run (5, argv_prog, "test-nat-mini", "nohelp", options, &run, | ||
129 | NULL); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | |||
134 | /* end of test_nat_mini.c */ | ||
diff --git a/src/nat/test_nat_test.c b/src/nat/test_nat_test.c deleted file mode 100644 index 2abab4d5f..000000000 --- a/src/nat/test_nat_test.c +++ /dev/null | |||
@@ -1,142 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2011, 2014 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file nat/test_nat_test.c | ||
22 | * @brief Testcase for NAT testing functions | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | #include "gnunet_nat_lib.h" | ||
28 | |||
29 | /** | ||
30 | * Time to wait before stopping NAT test, in seconds | ||
31 | */ | ||
32 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) | ||
33 | |||
34 | |||
35 | static int ret = 1; | ||
36 | |||
37 | static struct GNUNET_NAT_Test *tst; | ||
38 | |||
39 | static struct GNUNET_SCHEDULER_Task *tsk; | ||
40 | |||
41 | |||
42 | static void | ||
43 | report_result (void *cls, | ||
44 | enum GNUNET_NAT_StatusCode aret) | ||
45 | { | ||
46 | if (GNUNET_NAT_ERROR_TIMEOUT == aret) | ||
47 | fprintf (stderr, | ||
48 | "NAT test timed out\n"); | ||
49 | else if (GNUNET_NAT_ERROR_SUCCESS != aret) | ||
50 | fprintf (stderr, | ||
51 | "NAT test reported error %d\n", aret); | ||
52 | else | ||
53 | ret = 0; | ||
54 | GNUNET_NAT_test_stop (tst); | ||
55 | tst = NULL; | ||
56 | GNUNET_SCHEDULER_cancel (tsk); | ||
57 | tsk = NULL; | ||
58 | } | ||
59 | |||
60 | |||
61 | static void | ||
62 | failed_timeout (void *cls) | ||
63 | { | ||
64 | tsk = NULL; | ||
65 | fprintf (stderr, | ||
66 | "NAT test failed to terminate on timeout\n"); | ||
67 | ret = 2; | ||
68 | GNUNET_NAT_test_stop (tst); | ||
69 | tst = NULL; | ||
70 | } | ||
71 | |||
72 | |||
73 | /** | ||
74 | * Main function run with scheduler. | ||
75 | */ | ||
76 | static void | ||
77 | run (void *cls, char *const *args, const char *cfgfile, | ||
78 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
79 | { | ||
80 | tst = | ||
81 | GNUNET_NAT_test_start (cfg, GNUNET_YES, 1285, 1285, TIMEOUT, | ||
82 | &report_result, | ||
83 | NULL); | ||
84 | tsk = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (TIMEOUT, | ||
85 | 2), | ||
86 | &failed_timeout, | ||
87 | NULL); | ||
88 | } | ||
89 | |||
90 | |||
91 | int | ||
92 | main (int argc, char *const argv[]) | ||
93 | { | ||
94 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
95 | GNUNET_GETOPT_OPTION_END | ||
96 | }; | ||
97 | struct GNUNET_OS_Process *gns; | ||
98 | int nat_res; | ||
99 | char *const argv_prog[] = { | ||
100 | "test-nat-test", | ||
101 | "-c", | ||
102 | "test_nat_test_data.conf", | ||
103 | NULL | ||
104 | }; | ||
105 | |||
106 | GNUNET_log_setup ("test-nat-test", | ||
107 | "WARNING", | ||
108 | NULL); | ||
109 | |||
110 | nat_res = GNUNET_OS_check_helper_binary ("gnunet-nat-server", GNUNET_NO, | ||
111 | NULL); | ||
112 | if (GNUNET_SYSERR == nat_res) | ||
113 | { | ||
114 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
115 | "Cannot run NAT test: `%s' file not found\n", | ||
116 | "gnunet-nat-server"); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | gns = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR | ||
121 | | GNUNET_OS_USE_PIPE_CONTROL, | ||
122 | NULL, NULL, NULL, | ||
123 | "gnunet-nat-server", | ||
124 | "gnunet-nat-server", | ||
125 | "-c", "test_nat_test_data.conf", | ||
126 | "12345", NULL); | ||
127 | GNUNET_assert (NULL != gns); | ||
128 | GNUNET_PROGRAM_run (3, argv_prog, | ||
129 | "test-nat-test", "nohelp", | ||
130 | options, &run, | ||
131 | NULL); | ||
132 | GNUNET_break (0 == GNUNET_OS_process_kill (gns, GNUNET_TERM_SIG)); | ||
133 | GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (gns)); | ||
134 | GNUNET_OS_process_destroy (gns); | ||
135 | if (0 != ret) | ||
136 | fprintf (stderr, | ||
137 | "NAT test failed to report success\n"); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | |||
142 | /* end of test_nat_test.c */ | ||
diff --git a/src/nat/test_nat_test_data.conf b/src/nat/test_nat_test_data.conf deleted file mode 100644 index ca78ca9f3..000000000 --- a/src/nat/test_nat_test_data.conf +++ /dev/null | |||
@@ -1,45 +0,0 @@ | |||
1 | [PATHS] | ||
2 | GNUNET_TEST_HOME = $GNUNET_TMP/nat-test | ||
3 | # GNUNET_TEST_HOME = /var/lib/gnunet/ | ||
4 | # configuration file is assumed to be the default, | ||
5 | # which is what we want by default... | ||
6 | |||
7 | [gnunet-nat-server] | ||
8 | HOSTNAME = localhost | ||
9 | PORT = 57315 | ||
10 | |||
11 | [nat] | ||
12 | # Are we behind NAT? | ||
13 | BEHIND_NAT = NO | ||
14 | |||
15 | # Is the NAT hole-punched? | ||
16 | PUNCHED_NAT = YES | ||
17 | |||
18 | # Disable UPNP by default until it gets cleaner! | ||
19 | ENABLE_UPNP = NO | ||
20 | |||
21 | # Use addresses from the local network interfaces (including loopback, but also others) | ||
22 | USE_LOCALADDR = YES | ||
23 | RETURN_LOCAL_ADDRESSES = YES | ||
24 | |||
25 | # External IP address of the NAT box (if known); IPv4 dotted-decimal ONLY at this time (should allow DynDNS!) | ||
26 | # normal interface IP address for non-NATed peers; | ||
27 | # possibly auto-detected (using UPnP) if possible if not specified | ||
28 | # EXTERNAL_ADDRESS = | ||
29 | |||
30 | # Should we use ICMP-based NAT traversal to try connect to NATed peers | ||
31 | # or, if we are behind NAT, to allow connections to us? | ||
32 | ENABLE_ICMP_CLIENT = NO | ||
33 | ENABLE_ICMP_SERVER = NO | ||
34 | |||
35 | # IP address of the interface connected to the NAT box; IPv4 dotted-decimal ONLY; | ||
36 | # normal interface IP address for non-NATed peers; | ||
37 | # likely auto-detected (via interface list) if not specified (!) | ||
38 | INTERNAL_ADDRESS = 127.0.0.1 | ||
39 | |||
40 | # Disable IPv6 support | ||
41 | DISABLEV6 = YES | ||
42 | |||
43 | |||
44 | [nse] | ||
45 | START_ON_DEMAND = NO | ||
diff --git a/src/nat/test_stun.c b/src/nat/test_stun.c deleted file mode 100644 index 75eb877b3..000000000 --- a/src/nat/test_stun.c +++ /dev/null | |||
@@ -1,313 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2015 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * Testcase for STUN server resolution | ||
23 | * | ||
24 | * @file nat/test_stun.c | ||
25 | * @brief Testcase for STUN library | ||
26 | * @author Bruno Souza Cabral | ||
27 | * @author Christian Grothoff | ||
28 | */ | ||
29 | |||
30 | |||
31 | #include "platform.h" | ||
32 | #include "gnunet_util_lib.h" | ||
33 | #include "gnunet_program_lib.h" | ||
34 | #include "gnunet_scheduler_lib.h" | ||
35 | #include "gnunet_nat_lib.h" | ||
36 | |||
37 | |||
38 | #define LOG(kind, ...) GNUNET_log_from (kind, "test-stun", __VA_ARGS__) | ||
39 | |||
40 | /** | ||
41 | * Time to wait before stopping NAT, in seconds | ||
42 | */ | ||
43 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
44 | |||
45 | |||
46 | /** | ||
47 | * The port the test service is running on (default 7895) | ||
48 | */ | ||
49 | static unsigned long port = 7895; | ||
50 | |||
51 | static int ret = 1; | ||
52 | |||
53 | static const char *stun_server = "stun.gnunet.org"; | ||
54 | |||
55 | static int stun_port = 3478; | ||
56 | |||
57 | /** | ||
58 | * The listen socket of the service for IPv4 | ||
59 | */ | ||
60 | static struct GNUNET_NETWORK_Handle *lsock4; | ||
61 | |||
62 | /** | ||
63 | * The listen task ID for IPv4 | ||
64 | */ | ||
65 | static struct GNUNET_SCHEDULER_Task *ltask4; | ||
66 | |||
67 | /** | ||
68 | * Handle for the STUN request. | ||
69 | */ | ||
70 | static struct GNUNET_NAT_STUN_Handle *rh; | ||
71 | |||
72 | |||
73 | static void | ||
74 | print_answer (struct sockaddr_in*answer) | ||
75 | { | ||
76 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
77 | "External IP is: %s , with port %d\n", | ||
78 | inet_ntoa (answer->sin_addr), | ||
79 | ntohs (answer->sin_port)); | ||
80 | } | ||
81 | |||
82 | |||
83 | /** | ||
84 | * Function that terminates the test. | ||
85 | */ | ||
86 | static void | ||
87 | stop () | ||
88 | { | ||
89 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
90 | "Stopping NAT and quitting...\n"); | ||
91 | if (NULL != ltask4) | ||
92 | { | ||
93 | GNUNET_SCHEDULER_cancel (ltask4); | ||
94 | ltask4 = NULL; | ||
95 | } | ||
96 | if (NULL != lsock4) | ||
97 | { | ||
98 | GNUNET_NETWORK_socket_close (lsock4); | ||
99 | lsock4 = NULL; | ||
100 | } | ||
101 | if (NULL != rh) | ||
102 | { | ||
103 | GNUNET_NAT_stun_make_request_cancel (rh); | ||
104 | rh = NULL; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | |||
109 | /** | ||
110 | * Activity on our incoming socket. Read data from the | ||
111 | * incoming connection. | ||
112 | * | ||
113 | * @param cls | ||
114 | */ | ||
115 | static void | ||
116 | do_udp_read (void *cls) | ||
117 | { | ||
118 | // struct GNUNET_NAT_Test *tst = cls; | ||
119 | unsigned char reply_buf[1024]; | ||
120 | ssize_t rlen; | ||
121 | struct sockaddr_in answer; | ||
122 | const struct GNUNET_SCHEDULER_TaskContext *tc; | ||
123 | |||
124 | ltask4 = NULL; | ||
125 | tc = GNUNET_SCHEDULER_get_task_context (); | ||
126 | if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) || | ||
127 | (! GNUNET_NETWORK_fdset_isset (tc->read_ready, | ||
128 | lsock4))) | ||
129 | { | ||
130 | fprintf (stderr, | ||
131 | "Timeout waiting for STUN response\n"); | ||
132 | stop (); | ||
133 | } | ||
134 | rlen = GNUNET_NETWORK_socket_recv (lsock4, | ||
135 | reply_buf, | ||
136 | sizeof(reply_buf)); | ||
137 | memset (&answer, | ||
138 | 0, | ||
139 | sizeof(struct sockaddr_in)); | ||
140 | if (GNUNET_OK != | ||
141 | GNUNET_NAT_stun_handle_packet (reply_buf, | ||
142 | rlen, | ||
143 | &answer)) | ||
144 | { | ||
145 | fprintf (stderr, | ||
146 | "Unexpected UDP packet, trying to read more\n"); | ||
147 | ltask4 = GNUNET_SCHEDULER_add_read_net (TIMEOUT, | ||
148 | lsock4, | ||
149 | &do_udp_read, NULL); | ||
150 | return; | ||
151 | } | ||
152 | ret = 0; | ||
153 | print_answer (&answer); | ||
154 | stop (); | ||
155 | } | ||
156 | |||
157 | |||
158 | /** | ||
159 | * Create an IPv4 listen socket bound to our port. | ||
160 | * | ||
161 | * @return NULL on error | ||
162 | */ | ||
163 | static struct GNUNET_NETWORK_Handle * | ||
164 | bind_v4 () | ||
165 | { | ||
166 | struct GNUNET_NETWORK_Handle *ls; | ||
167 | struct sockaddr_in sa4; | ||
168 | int eno; | ||
169 | |||
170 | memset (&sa4, 0, sizeof(sa4)); | ||
171 | sa4.sin_family = AF_INET; | ||
172 | sa4.sin_port = htons (port); | ||
173 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
174 | sa4.sin_len = sizeof(sa4); | ||
175 | #endif | ||
176 | ls = GNUNET_NETWORK_socket_create (AF_INET, | ||
177 | SOCK_DGRAM, | ||
178 | 0); | ||
179 | if (NULL == ls) | ||
180 | return NULL; | ||
181 | if (GNUNET_OK != | ||
182 | GNUNET_NETWORK_socket_bind (ls, | ||
183 | (const struct sockaddr *) &sa4, | ||
184 | sizeof(sa4))) | ||
185 | { | ||
186 | eno = errno; | ||
187 | GNUNET_NETWORK_socket_close (ls); | ||
188 | errno = eno; | ||
189 | return NULL; | ||
190 | } | ||
191 | return ls; | ||
192 | } | ||
193 | |||
194 | |||
195 | /** | ||
196 | * Function called with the result of the STUN request transmission attempt. | ||
197 | * | ||
198 | * @param cls unused | ||
199 | * @param error status code from STUN | ||
200 | */ | ||
201 | static void | ||
202 | request_callback (void *cls, | ||
203 | enum GNUNET_NAT_StatusCode error) | ||
204 | { | ||
205 | rh = NULL; | ||
206 | if (GNUNET_NAT_ERROR_SUCCESS == error) | ||
207 | { | ||
208 | /* all good, start to receive */ | ||
209 | ltask4 = GNUNET_SCHEDULER_add_read_net (TIMEOUT, | ||
210 | lsock4, | ||
211 | &do_udp_read, | ||
212 | NULL); | ||
213 | return; | ||
214 | } | ||
215 | if (error == GNUNET_NAT_ERROR_NOT_ONLINE) | ||
216 | { | ||
217 | ret = 77; /* report 'skip' */ | ||
218 | fprintf (stderr, | ||
219 | "System is offline, cannot test STUN request.\n"); | ||
220 | } | ||
221 | else | ||
222 | { | ||
223 | ret = error; | ||
224 | } | ||
225 | stop (); | ||
226 | } | ||
227 | |||
228 | |||
229 | /** | ||
230 | * Main function run with scheduler. | ||
231 | */ | ||
232 | static void | ||
233 | run (void *cls, | ||
234 | char *const *args, | ||
235 | const char *cfgfile, | ||
236 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
237 | { | ||
238 | // Lets create the socket | ||
239 | lsock4 = bind_v4 (); | ||
240 | if (NULL == lsock4) | ||
241 | { | ||
242 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, | ||
243 | "bind"); | ||
244 | GNUNET_SCHEDULER_shutdown (); | ||
245 | return; | ||
246 | } | ||
247 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
248 | "Service listens on port %u\n", | ||
249 | (unsigned int) port); | ||
250 | rh = GNUNET_NAT_stun_make_request (stun_server, | ||
251 | stun_port, | ||
252 | lsock4, | ||
253 | &request_callback, NULL); | ||
254 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
255 | &stop, NULL); | ||
256 | } | ||
257 | |||
258 | |||
259 | int | ||
260 | main (int argc, char *const argv[]) | ||
261 | { | ||
262 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
263 | GNUNET_GETOPT_OPTION_END | ||
264 | }; | ||
265 | char *const argv_prog[] = { | ||
266 | "test-stun", | ||
267 | "-c", | ||
268 | "test_stun.conf", | ||
269 | NULL | ||
270 | }; | ||
271 | char *fn; | ||
272 | struct GNUNET_OS_Process *proc; | ||
273 | |||
274 | GNUNET_log_setup ("test-stun", | ||
275 | "WARNING", | ||
276 | NULL); | ||
277 | |||
278 | /* Lets start resolver */ | ||
279 | fn = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver"); | ||
280 | proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR | ||
281 | | GNUNET_OS_USE_PIPE_CONTROL, | ||
282 | NULL, NULL, NULL, | ||
283 | fn, | ||
284 | "gnunet-service-resolver", | ||
285 | "-c", "test_stun.conf", NULL); | ||
286 | |||
287 | if (NULL == proc) | ||
288 | { | ||
289 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
290 | "This test was unable to start gnunet-service-resolver, and it is required to run ...\n"); | ||
291 | exit (1); | ||
292 | } | ||
293 | |||
294 | GNUNET_PROGRAM_run (3, argv_prog, | ||
295 | "test-stun", "nohelp", | ||
296 | options, | ||
297 | &run, NULL); | ||
298 | |||
299 | /* Now kill the resolver */ | ||
300 | if (0 != GNUNET_OS_process_kill (proc, GNUNET_TERM_SIG)) | ||
301 | { | ||
302 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
303 | } | ||
304 | GNUNET_OS_process_wait (proc); | ||
305 | GNUNET_OS_process_destroy (proc); | ||
306 | proc = NULL; | ||
307 | GNUNET_free (fn); | ||
308 | |||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | |||
313 | /* end of test_stun.c */ | ||
diff --git a/src/nat/test_stun.conf b/src/nat/test_stun.conf deleted file mode 100644 index b03bbfff3..000000000 --- a/src/nat/test_stun.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | [PATHS] | ||
2 | GNUNET_TEST_HOME = $GNUNET_TMP/test-stun | ||
3 | |||
4 | [resolver] | ||
5 | PORT = 22354 | ||
6 | HOSTNAME = localhost | ||
7 | |||