aboutsummaryrefslogtreecommitdiff
path: root/src/service/exit
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/exit')
-rw-r--r--src/service/exit/.gitignore2
-rw-r--r--src/service/exit/Makefile.am38
-rw-r--r--src/service/exit/exit.conf68
-rw-r--r--src/service/exit/exit.h298
-rw-r--r--src/service/exit/gnunet-daemon-exit.c4121
-rw-r--r--src/service/exit/gnunet-helper-exit.c859
-rw-r--r--src/service/exit/meson.build25
7 files changed, 5411 insertions, 0 deletions
diff --git a/src/service/exit/.gitignore b/src/service/exit/.gitignore
new file mode 100644
index 000000000..9b75bba9a
--- /dev/null
+++ b/src/service/exit/.gitignore
@@ -0,0 +1,2 @@
1gnunet-helper-exit
2gnunet-daemon-exit
diff --git a/src/service/exit/Makefile.am b/src/service/exit/Makefile.am
new file mode 100644
index 000000000..524fe19fa
--- /dev/null
+++ b/src/service/exit/Makefile.am
@@ -0,0 +1,38 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage -O0
6endif
7
8pkgcfgdir= $(pkgdatadir)/config.d/
9
10libexecdir= $(pkglibdir)/libexec/
11
12plugindir = $(libdir)/gnunet
13
14dist_pkgcfg_DATA = \
15 exit.conf
16
17if LINUX
18EXITBIN = gnunet-helper-exit
19endif
20
21
22libexec_PROGRAMS = \
23 gnunet-daemon-exit \
24 $(EXITBIN)
25
26
27gnunet_helper_exit_SOURCES = \
28 gnunet-helper-exit.c
29
30gnunet_daemon_exit_SOURCES = \
31 gnunet-daemon-exit.c exit.h
32gnunet_daemon_exit_LDADD = \
33 $(top_builddir)/src/service/dht/libgnunetdht.la \
34 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
35 $(top_builddir)/src/lib/util/libgnunetutil.la \
36 $(top_builddir)/src/service/cadet/libgnunetcadet.la \
37 $(top_builddir)/src/service/regex/libgnunetregex.la \
38 $(GN_LIBINTL)
diff --git a/src/service/exit/exit.conf b/src/service/exit/exit.conf
new file mode 100644
index 000000000..829c5bf80
--- /dev/null
+++ b/src/service/exit/exit.conf
@@ -0,0 +1,68 @@
1[exit]
2BINARY = gnunet-daemon-exit
3
4# IPv6 address for the TUN interface (must be changed as this
5# must be within the global IPv6 range of your system!)
6IPV6ADDR = 2001:DB8::1
7
8# Prefix for our IPv6 subnet on the TUN interface.
9IPV6PREFIX = 64
10
11# IPv4 address to use on our TUN interface (may need to be
12# changed to avoid conflicts with existing addresses on your system).
13# Use RFC 3927-style link-local address
14IPV4ADDR = 169.254.86.1
15
16# Netmask for the IPv4 subnet on the TUN interface.
17IPV4MASK = 255.255.255.0
18
19# IPv4 networks to which we are allowed to exit.
20# The format is "(network[/netmask][:[!]SPORT-DPORT];)*"
21EXIT_RANGE_IPV4_POLICY = 0.0.0.0/0:!25;
22
23# IPv6 networks to which we are allowed to exit.
24# The format is "(network[/netmask][:[!]SPORT-DPORT];)*"
25EXIT_RANGE_IPV6_POLICY = ::/0:!25;
26
27# Not a service, tell ARM no binding!
28NOARMBIND = YES
29
30# Name of the (virtual) tunnel interface the exit daemon will manage
31TUN_IFNAME = exit-gnunet
32
33# Name of the "real" interface that IPv4 traffic from this system will
34# leave from; this is the name of the interface where we need to
35# enable NAT on postrouting (typically something like 'eth0' or 'eth1'
36# or 'wlan0'). Not needed if EXIT_IPv4 is disabled AND if all
37# offered services run on 'localhost'. In this case, the value
38# of the option can instead be set to "%" (to not enable NAT on any
39# interface).
40EXIT_IFNAME = eth0
41
42# Set this to YES to allow exiting this system via IPv4 to the Internet
43EXIT_IPV4 = NO
44
45# Set this to YES to allow exiting this system via IPv6 to the Internet
46EXIT_IPV6 = NO
47
48# This option should be set to YES to allow the DNS service to
49# perform lookups against the locally configured DNS resolver.
50# (set to "NO" if no normal ISP is locally available and thus
51# requests for normal ".com"/".org"/etc. must be routed via
52# the GNUnet VPN (the GNUNET PT daemon then needs to be configured
53# to intercept and route DNS queries via cadet).
54# Set this to YES to allow using this system for DNS queries.
55EXIT_DNS = NO
56
57# Set this to an IPv4 or IPv6 address of a DNS resolver to use for DNS queries
58DNS_RESOLVER = 8.8.8.8
59
60# For IPv4-services offered by this peer, we need to at least enable IPv4
61ENABLE_IPV4 = YES
62
63# For IPv6-services offered by this peer, we need to at least enable IPv6
64ENABLE_IPV6 = YES
65
66
67# Maximum number of concurrent connections this exit supports.
68MAX_CONNECTIONS = 256
diff --git a/src/service/exit/exit.h b/src/service/exit/exit.h
new file mode 100644
index 000000000..41dad6246
--- /dev/null
+++ b/src/service/exit/exit.h
@@ -0,0 +1,298 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012 Christian Grothoff
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 exit/exit.h
23 * @brief format for cadet messages exchanged between VPN service and exit daemon
24 * @author Christian Grothoff
25 */
26#ifndef EXIT_H
27#define EXIT_H
28
29#include "gnunet_util_lib.h"
30
31GNUNET_NETWORK_STRUCT_BEGIN
32
33/**
34 * Message send via cadet to an exit daemon to initiate forwarding of
35 * TCP data to a local service.
36 */
37struct GNUNET_EXIT_TcpServiceStartMessage
38{
39 /**
40 * Type is #GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START
41 */
42 struct GNUNET_MessageHeader header;
43
44 /**
45 * Always 0.
46 */
47 uint32_t reserved GNUNET_PACKED;
48
49 /**
50 * Skeleton of the TCP header to send. Port numbers are to
51 * be replaced and the checksum may be updated as necessary.
52 */
53 struct GNUNET_TUN_TcpHeader tcp_header;
54
55 /* followed by TCP payload */
56};
57
58
59/**
60 * Message send via cadet to an exit daemon to initiate forwarding of
61 * TCP data to the Internet.
62 */
63struct GNUNET_EXIT_TcpInternetStartMessage
64{
65 /**
66 * Type is #GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START
67 */
68 struct GNUNET_MessageHeader header;
69
70 /**
71 * Address family, AF_INET or AF_INET6, in network byte order.
72 */
73 int32_t af GNUNET_PACKED;
74
75 /**
76 * Skeleton of the TCP header to send. Port numbers are to
77 * be replaced and the checksum may be updated as necessary.
78 */
79 struct GNUNET_TUN_TcpHeader tcp_header;
80
81 /* followed by IP address of the destination; either
82 'struct in_addr' or 'struct in6_addr', depending on af */
83
84 /* followed by TCP payload */
85};
86
87
88/**
89 * Message send via cadet between VPN and entry and an exit daemon to
90 * transmit TCP data between the VPN entry and an exit session. This
91 * format is used for both Internet-exits and service-exits and
92 * in both directions (VPN to exit and exit to VPN).
93 */
94struct GNUNET_EXIT_TcpDataMessage
95{
96 /**
97 * Type is #GNUNET_MESSAGE_TYPE_VPN_TCP_DATA
98 */
99 struct GNUNET_MessageHeader header;
100
101 /**
102 * Always 0.
103 */
104 uint32_t reserved GNUNET_PACKED;
105
106 /**
107 * Skeleton of the TCP header to send. Port numbers are to
108 * be replaced and the checksum may be updated as necessary. (The destination port number should not be changed, as it contains the desired destination port.)
109 */
110 struct GNUNET_TUN_TcpHeader tcp_header;
111
112 /* followed by TCP payload */
113};
114
115
116/**
117 * Message send via cadet to an exit daemon to send
118 * UDP data to a local service.
119 */
120struct GNUNET_EXIT_UdpServiceMessage
121{
122 /**
123 * Type is #GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE
124 */
125 struct GNUNET_MessageHeader header;
126
127 /**
128 * Source port to use for the UDP request (0 to use a random port). In NBO.
129 */
130 uint16_t source_port GNUNET_PACKED;
131
132 /**
133 * Destination port to use for the UDP request. In NBO.
134 */
135 uint16_t destination_port GNUNET_PACKED;
136
137 /* followed by UDP payload */
138};
139
140
141/**
142 * Message send via cadet to an exit daemon to forward
143 * UDP data to the Internet.
144 */
145struct GNUNET_EXIT_UdpInternetMessage
146{
147 /**
148 * Type is #GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET
149 */
150 struct GNUNET_MessageHeader header;
151
152 /**
153 * Address family, AF_INET or AF_INET6, in network byte order.
154 */
155 int32_t af GNUNET_PACKED;
156
157 /**
158 * Source port to use for the UDP request (0 to use a random port). In NBO.
159 */
160 uint16_t source_port GNUNET_PACKED;
161
162 /**
163 * Destination port to use for the UDP request. In NBO.
164 */
165 uint16_t destination_port GNUNET_PACKED;
166
167 /* followed by IP address of the destination; either
168 'struct in_addr' or 'struct in6_addr', depending on af */
169
170 /* followed by UDP payload */
171};
172
173
174/**
175 * Message send from exit daemon back to the UDP entry point
176 * (used for both Internet and Service exit replies).
177 */
178struct GNUNET_EXIT_UdpReplyMessage
179{
180 /**
181 * Type is #GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY
182 */
183 struct GNUNET_MessageHeader header;
184
185 /**
186 * Source port to use for the UDP reply (0 to use the same
187 * port as for the original request). In NBO.
188 */
189 uint16_t source_port GNUNET_PACKED;
190
191 /**
192 * Destination port to use for the UDP reply (0 to use the same
193 * port as for the original request). In NBO.
194 */
195 uint16_t destination_port GNUNET_PACKED;
196
197 /* followed by UDP payload */
198};
199
200
201/**
202 * Message send via cadet to an exit daemon to send
203 * ICMP data to a local service.
204 */
205struct GNUNET_EXIT_IcmpServiceMessage
206{
207 /**
208 * Type is #GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE
209 */
210 struct GNUNET_MessageHeader header;
211
212 /**
213 * Address family, AF_INET or AF_INET6, in network byte order. This
214 * AF value determines if the 'icmp_header' is ICMPv4 or ICMPv6.
215 * The receiver (exit) may still have to translate (PT) to the services'
216 * ICMP version (if possible).
217 */
218 int32_t af GNUNET_PACKED;
219
220 /**
221 * ICMP header to use.
222 */
223 struct GNUNET_TUN_IcmpHeader icmp_header;
224
225 /* followed by ICMP payload; however, for certain ICMP message
226 types where the payload is the original IP packet, the payload
227 is omitted as it is useless for the receiver (who will need
228 to create some fake payload manually) */
229};
230
231
232/**
233 * Message send via cadet to an exit daemon to forward
234 * ICMP data to the Internet.
235 */
236struct GNUNET_EXIT_IcmpInternetMessage
237{
238 /**
239 * Type is #GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET
240 */
241 struct GNUNET_MessageHeader header;
242
243 /**
244 * Address family, AF_INET or AF_INET6, in network byte order.
245 * Determines both the ICMP version used in the 'icmp_header' and
246 * the IP address format that is used for the target IP. If
247 * PT is necessary, the sender has already done it.
248 */
249 int32_t af GNUNET_PACKED;
250
251 /**
252 * ICMP header to use. Must match the target 'af' given
253 * above.
254 */
255 struct GNUNET_TUN_IcmpHeader icmp_header;
256
257 /* followed by IP address of the destination; either
258 'struct in_addr' or 'struct in6_addr', depending on af */
259
260 /* followed by ICMP payload; however, for certain ICMP message
261 types where the payload is the original IP packet, the payload
262 is omitted as it is useless for the receiver (who will need
263 to create some fake payload manually) */
264};
265
266
267/**
268 * Message send via cadet to the vpn service to send
269 * ICMP data to the VPN's TUN interface.
270 */
271struct GNUNET_EXIT_IcmpToVPNMessage
272{
273 /**
274 * Type is #GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN
275 */
276 struct GNUNET_MessageHeader header;
277
278 /**
279 * Address family, AF_INET or AF_INET6, in network byte order.
280 * Useful to determine if this is an ICMPv4 or ICMPv6 header.
281 */
282 int32_t af GNUNET_PACKED;
283
284 /**
285 * ICMP header to use. ICMPv4 or ICMPv6, depending on 'af'.
286 */
287 struct GNUNET_TUN_IcmpHeader icmp_header;
288
289 /* followed by ICMP payload; however, for certain ICMP message
290 types where the payload is the original IP packet, the payload
291 is omitted as it is useless for the receiver (who will need
292 to create some fake payload manually) */
293};
294
295
296GNUNET_NETWORK_STRUCT_END
297
298#endif
diff --git a/src/service/exit/gnunet-daemon-exit.c b/src/service/exit/gnunet-daemon-exit.c
new file mode 100644
index 000000000..eb2380439
--- /dev/null
+++ b/src/service/exit/gnunet-daemon-exit.c
@@ -0,0 +1,4121 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2013, 2017 Christian Grothoff
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 exit/gnunet-daemon-exit.c
23 * @brief tool to allow IP traffic exit from the GNUnet cadet to the Internet
24 * @author Philipp Toelke
25 * @author Christian Grothoff
26 *
27 * TODO:
28 * - test
29 *
30 * Design:
31 * - which code should advertise services? the service model is right
32 * now a bit odd, especially as this code DOES the exit and knows
33 * the DNS "name", but OTOH this is clearly NOT the place to advertise
34 * the service's existence; maybe the daemon should turn into a
35 * service with an API to add local-exit services dynamically?
36 */
37#include "platform.h"
38#include "gnunet_util_lib.h"
39#include "gnunet_protocols.h"
40#include "gnunet_applications.h"
41#include "gnunet_dht_service.h"
42#include "gnunet_cadet_service.h"
43#include "gnunet_statistics_service.h"
44#include "gnunet_constants.h"
45#include "gnunet_signatures.h"
46#include "gnunet_regex_service.h"
47#include "exit.h"
48#include "block_dns.h"
49
50
51/**
52 * Maximum path compression length for cadet regex announcing for IPv4 address
53 * based regex.
54 */
55#define REGEX_MAX_PATH_LEN_IPV4 4
56
57/**
58 * Maximum path compression length for cadet regex announcing for IPv6 address
59 * based regex.
60 */
61#define REGEX_MAX_PATH_LEN_IPV6 8
62
63/**
64 * How frequently do we re-announce the regex for the exit?
65 */
66#define REGEX_REFRESH_FREQUENCY GNUNET_TIME_relative_multiply ( \
67 GNUNET_TIME_UNIT_MINUTES, 30)
68
69/**
70 * How frequently do we re-announce the DNS exit in the DHT?
71 */
72#define DHT_PUT_FREQUENCY GNUNET_TIME_relative_multiply ( \
73 GNUNET_TIME_UNIT_MINUTES, 15)
74
75/**
76 * How long do we typically sign the DNS exit advertisement for?
77 */
78#define DNS_ADVERTISEMENT_TIMEOUT GNUNET_TIME_relative_multiply ( \
79 GNUNET_TIME_UNIT_HOURS, 3)
80
81
82/**
83 * Generic logging shorthand
84 */
85#define LOG(kind, ...) \
86 GNUNET_log_from (kind, "exit", __VA_ARGS__);
87
88
89/**
90 * Information about an address.
91 */
92struct SocketAddress
93{
94 /**
95 * AF_INET or AF_INET6.
96 */
97 int af;
98
99 /**
100 * Remote address information.
101 */
102 union
103 {
104 /**
105 * Address, if af is AF_INET.
106 */
107 struct in_addr ipv4;
108
109 /**
110 * Address, if af is AF_INET6.
111 */
112 struct in6_addr ipv6;
113 } address;
114
115 /**
116 * IPPROTO_TCP or IPPROTO_UDP;
117 */
118 uint8_t proto;
119
120 /**
121 * Remote port, in host byte order!
122 */
123 uint16_t port;
124};
125
126
127/**
128 * This struct is saved into the services-hashmap to represent
129 * a service this peer is specifically offering an exit for
130 * (for a specific domain name).
131 */
132struct LocalService
133{
134 /**
135 * Remote address to use for the service.
136 */
137 struct SocketAddress address;
138
139 /**
140 * Descriptor for the service (CADET port).
141 */
142 struct GNUNET_HashCode descriptor;
143
144 /**
145 * DNS name of the service.
146 */
147 char *name;
148
149 /**
150 * Open port with CADET.
151 */
152 struct GNUNET_CADET_Port *port;
153
154 /**
155 * #GNUNET_YES if this is a UDP service, otherwise TCP.
156 */
157 int16_t is_udp;
158};
159
160
161/**
162 * Information we use to track a connection (the classical 6-tuple of
163 * IP-version, protocol, source-IP, destination-IP, source-port and
164 * destinatin-port.
165 */
166struct RedirectInformation
167{
168 /**
169 * Address information for the other party (equivalent of the
170 * arguments one would give to "connect").
171 */
172 struct SocketAddress remote_address;
173
174 /**
175 * Address information we used locally (AF and proto must match
176 * "remote_address"). Equivalent of the arguments one would give to
177 * "bind".
178 */
179 struct SocketAddress local_address;
180
181 /*
182 Note 1: additional information might be added here in the
183 future to support protocols that require special handling,
184 such as ftp/tftp
185
186 Note 2: we might also sometimes not match on all components
187 of the tuple, to support protocols where things do not always
188 fully map.
189 */
190};
191
192
193/**
194 * This struct is saved into #connections_map to allow finding the
195 * right channel given an IP packet from TUN. It is also associated
196 * with the channel's closure so we can find it again for the next
197 * message from the channel.
198 */
199struct ChannelState
200{
201 /**
202 * Cadet channel that is used for this connection.
203 */
204 struct GNUNET_CADET_Channel *channel;
205
206 /**
207 * Who is the other end of this channel.
208 * FIXME is this needed? Only used for debugging messages
209 */
210 struct GNUNET_PeerIdentity peer;
211
212 /**
213 * #GNUNET_NO if this is a channel for TCP/UDP,
214 * #GNUNET_YES if this is a channel for DNS,
215 * #GNUNET_SYSERR if the channel is not yet initialized.
216 */
217 int is_dns;
218
219 union
220 {
221 struct
222 {
223 /**
224 * Heap node for this state in the connections_heap.
225 */
226 struct GNUNET_CONTAINER_HeapNode *heap_node;
227
228 /**
229 * Key this state has in the #connections_map.
230 */
231 struct GNUNET_HashCode state_key;
232
233 /**
234 * Associated service record, or NULL for no service.
235 */
236 struct LocalService *serv;
237
238 /**
239 * Primary redirection information for this connection.
240 */
241 struct RedirectInformation ri;
242 } tcp_udp;
243
244 struct
245 {
246 /**
247 * Socket we are using to transmit this request (must match if we receive
248 * a response).
249 */
250 struct GNUNET_DNSSTUB_RequestSocket *rs;
251
252 /**
253 * Original DNS request ID as used by the client.
254 */
255 uint16_t original_id;
256
257 /**
258 * DNS request ID that we used for forwarding.
259 */
260 uint16_t my_id;
261 } dns;
262 } specifics;
263};
264
265
266/**
267 * Return value from 'main'.
268 */
269static int global_ret;
270
271/**
272 * Handle to our regex announcement for IPv4.
273 */
274static struct GNUNET_REGEX_Announcement *regex4;
275
276/**
277 * Handle to our regex announcement for IPv4.
278 */
279static struct GNUNET_REGEX_Announcement *regex6;
280
281/**
282 * The handle to the configuration used throughout the process
283 */
284static const struct GNUNET_CONFIGURATION_Handle *cfg;
285
286/**
287 * The handle to the helper
288 */
289static struct GNUNET_HELPER_Handle *helper_handle;
290
291/**
292 * Arguments to the exit helper.
293 */
294static char *exit_argv[8];
295
296/**
297 * IPv6 address of our TUN interface.
298 */
299static struct in6_addr exit_ipv6addr;
300
301/**
302 * IPv6 prefix (0..127) from configuration file.
303 */
304static unsigned long long ipv6prefix;
305
306/**
307 * IPv4 address of our TUN interface.
308 */
309static struct in_addr exit_ipv4addr;
310
311/**
312 * IPv4 netmask of our TUN interface.
313 */
314static struct in_addr exit_ipv4mask;
315
316/**
317 * Statistics.
318 */
319static struct GNUNET_STATISTICS_Handle *stats;
320
321/**
322 * The handle to cadet
323 */
324static struct GNUNET_CADET_Handle *cadet_handle;
325
326/**
327 * This hashmaps contains the mapping from peer, service-descriptor,
328 * source-port and destination-port to a struct ChannelState
329 */
330static struct GNUNET_CONTAINER_MultiHashMap *connections_map;
331
332/**
333 * Heap so we can quickly find "old" connections.
334 */
335static struct GNUNET_CONTAINER_Heap *connections_heap;
336
337/**
338 * If there are at least this many connections, old ones will be removed
339 */
340static unsigned long long max_connections;
341
342/**
343 * This hashmaps saves interesting things about the configured services
344 */
345static struct GNUNET_CONTAINER_MultiHashMap *services;
346
347/**
348 * Array of all open DNS requests from channels.
349 */
350static struct ChannelState *channels[UINT16_MAX + 1];
351
352/**
353 * Handle to the DNS Stub resolver.
354 */
355static struct GNUNET_DNSSTUB_Context *dnsstub;
356
357/**
358 * Handle for ongoing DHT PUT operations to advertise exit service.
359 */
360static struct GNUNET_DHT_PutHandle *dht_put;
361
362/**
363 * Handle to the DHT.
364 */
365static struct GNUNET_DHT_Handle *dht;
366
367/**
368 * Task for doing DHT PUTs to advertise exit service.
369 */
370static struct GNUNET_SCHEDULER_Task *dht_task;
371
372/**
373 * Advertisement message we put into the DHT to advertise us
374 * as a DNS exit.
375 */
376static struct GNUNET_DNS_Advertisement dns_advertisement;
377
378/**
379 * Key we store the DNS advertismenet under.
380 */
381static struct GNUNET_HashCode dht_put_key;
382
383/**
384 * Private key for this peer.
385 */
386static struct GNUNET_CRYPTO_EddsaPrivateKey *peer_key;
387
388/**
389 * Port for DNS exit.
390 */
391static struct GNUNET_CADET_Port *dns_port;
392
393/**
394 * Port for IPv4 exit.
395 */
396static struct GNUNET_CADET_Port *cadet_port4;
397
398/**
399 * Port for IPv6 exit.
400 */
401static struct GNUNET_CADET_Port *cadet_port6;
402
403/**
404 * Are we an IPv4-exit?
405 */
406static int ipv4_exit;
407
408/**
409 * Are we an IPv6-exit?
410 */
411static int ipv6_exit;
412
413/**
414 * Do we support IPv4 at all on the TUN interface?
415 */
416static int ipv4_enabled;
417
418/**
419 * Do we support IPv6 at all on the TUN interface?
420 */
421static int ipv6_enabled;
422
423
424GNUNET_NETWORK_STRUCT_BEGIN
425
426/**
427 * Message with a DNS response.
428 */
429struct DnsResponseMessage
430{
431 /**
432 * GNUnet header, of type #GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET
433 */
434 struct GNUNET_MessageHeader header;
435
436 /**
437 * DNS header.
438 */
439 struct GNUNET_TUN_DnsHeader dns;
440
441 /* Followed by more DNS payload */
442};
443
444GNUNET_NETWORK_STRUCT_END
445
446
447/**
448 * Callback called from DNSSTUB resolver when a resolution
449 * succeeded.
450 *
451 * @param cls NULL
452 * @param dns the response itself
453 * @param r number of bytes in @a dns
454 */
455static void
456process_dns_result (void *cls,
457 const struct GNUNET_TUN_DnsHeader *dns,
458 size_t r)
459{
460 struct ChannelState *ts;
461 struct GNUNET_MQ_Envelope *env;
462 struct DnsResponseMessage *resp;
463
464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
465 "Processing DNS result from stub resolver\n");
466 GNUNET_assert (NULL == cls);
467 if (NULL == dns)
468 return;
469 /* Handle case that this is a reply to a request from a CADET DNS channel */
470 ts = channels[dns->id];
471 if (NULL == ts)
472 return;
473 LOG (GNUNET_ERROR_TYPE_DEBUG,
474 "Got a response from the stub resolver for DNS request received via CADET!\n");
475 channels[dns->id] = NULL;
476 env = GNUNET_MQ_msg_extra (resp,
477 r - sizeof(struct GNUNET_TUN_DnsHeader),
478 GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET);
479 GNUNET_memcpy (&resp->dns,
480 dns,
481 r);
482 resp->dns.id = ts->specifics.dns.original_id;
483 GNUNET_MQ_send (GNUNET_CADET_get_mq (ts->channel),
484 env);
485}
486
487
488/**
489 * Check a request via cadet to perform a DNS query.
490 *
491 * @param cls our `struct ChannelState *`
492 * @param msg the actual message
493 * @return #GNUNET_OK to keep the connection open,
494 * #GNUNET_SYSERR to close it (signal serious error)
495 */
496static int
497check_dns_request (void *cls,
498 const struct DnsResponseMessage *msg)
499{
500 struct ChannelState *ts = cls;
501
502 if (NULL == dnsstub)
503 {
504 GNUNET_break (0);
505 return GNUNET_SYSERR;
506 }
507 if (GNUNET_NO == ts->is_dns)
508 {
509 GNUNET_break_op (0);
510 return GNUNET_SYSERR;
511 }
512 return GNUNET_OK;
513}
514
515
516/**
517 * Process a request via cadet to perform a DNS query.
518 *
519 * @param cls our `struct ChannelState *`
520 * @param msg the actual message
521 */
522static void
523handle_dns_request (void *cls,
524 const struct DnsResponseMessage *msg)
525{
526 struct ChannelState *ts = cls;
527 size_t mlen = ntohs (msg->header.size);
528 size_t dlen = mlen - sizeof(struct GNUNET_MessageHeader);
529 char buf[dlen] GNUNET_ALIGN;
530 struct GNUNET_TUN_DnsHeader *dns_out;
531
532 if (GNUNET_SYSERR == ts->is_dns)
533 {
534 /* channel is DNS from now on */
535 ts->is_dns = GNUNET_YES;
536 }
537 ts->specifics.dns.original_id = msg->dns.id;
538 if (channels[ts->specifics.dns.my_id] == ts)
539 channels[ts->specifics.dns.my_id] = NULL;
540 ts->specifics.dns.my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (
541 GNUNET_CRYPTO_QUALITY_WEAK,
542 UINT16_MAX
543 + 1);
544 channels[ts->specifics.dns.my_id] = ts;
545 GNUNET_memcpy (buf,
546 &msg->dns,
547 dlen);
548 dns_out = (struct GNUNET_TUN_DnsHeader *) buf;
549 dns_out->id = ts->specifics.dns.my_id;
550 ts->specifics.dns.rs = GNUNET_DNSSTUB_resolve (dnsstub,
551 buf,
552 dlen,
553 &process_dns_result,
554 NULL);
555 if (NULL == ts->specifics.dns.rs)
556 {
557 GNUNET_break_op (0);
558 return;
559 }
560 GNUNET_CADET_receive_done (ts->channel);
561}
562
563
564/**
565 * Given IP information about a connection, calculate the respective
566 * hash we would use for the #connections_map.
567 *
568 * @param hash resulting hash
569 * @param ri information about the connection
570 */
571static void
572hash_redirect_info (struct GNUNET_HashCode *hash,
573 const struct RedirectInformation *ri)
574{
575 char *off;
576
577 memset (hash,
578 0,
579 sizeof(struct GNUNET_HashCode));
580 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
581 so we put the IP address in there (and hope for few collisions) */
582 off = (char *) hash;
583 switch (ri->remote_address.af)
584 {
585 case AF_INET:
586 GNUNET_memcpy (off,
587 &ri->remote_address.address.ipv4,
588 sizeof(struct in_addr));
589 off += sizeof(struct in_addr);
590 break;
591
592 case AF_INET6:
593 GNUNET_memcpy (off,
594 &ri->remote_address.address.ipv6,
595 sizeof(struct in6_addr));
596 off += sizeof(struct in_addr);
597 break;
598
599 default:
600 GNUNET_assert (0);
601 }
602 GNUNET_memcpy (off,
603 &ri->remote_address.port,
604 sizeof(uint16_t));
605 off += sizeof(uint16_t);
606 switch (ri->local_address.af)
607 {
608 case AF_INET:
609 GNUNET_memcpy (off,
610 &ri->local_address.address.ipv4,
611 sizeof(struct in_addr));
612 off += sizeof(struct in_addr);
613 break;
614
615 case AF_INET6:
616 GNUNET_memcpy (off,
617 &ri->local_address.address.ipv6,
618 sizeof(struct in6_addr));
619 off += sizeof(struct in_addr);
620 break;
621
622 default:
623 GNUNET_assert (0);
624 }
625 GNUNET_memcpy (off,
626 &ri->local_address.port,
627 sizeof(uint16_t));
628 off += sizeof(uint16_t);
629 GNUNET_memcpy (off,
630 &ri->remote_address.proto,
631 sizeof(uint8_t));
632 /* off += sizeof (uint8_t); */
633}
634
635
636/**
637 * Get our connection tracking state. Warns if it does not exists,
638 * refreshes the timestamp if it does exist.
639 *
640 * @param af address family
641 * @param protocol IPPROTO_UDP or IPPROTO_TCP
642 * @param destination_ip target IP
643 * @param destination_port target port
644 * @param local_ip local IP
645 * @param local_port local port
646 * @param state_key set to hash's state if non-NULL
647 * @return NULL if we have no tracking information for this tuple
648 */
649static struct ChannelState *
650get_redirect_state (int af,
651 int protocol,
652 const void *destination_ip,
653 uint16_t destination_port,
654 const void *local_ip,
655 uint16_t local_port,
656 struct GNUNET_HashCode *state_key)
657{
658 struct RedirectInformation ri;
659 struct GNUNET_HashCode key;
660 struct ChannelState *state;
661
662 if (((af == AF_INET) && (protocol == IPPROTO_ICMP)) ||
663 ((af == AF_INET6) && (protocol == IPPROTO_ICMPV6)))
664 {
665 /* ignore ports */
666 destination_port = 0;
667 local_port = 0;
668 }
669 ri.remote_address.af = af;
670 if (af == AF_INET)
671 ri.remote_address.address.ipv4 = *((struct in_addr*) destination_ip);
672 else
673 ri.remote_address.address.ipv6 = *((struct in6_addr*) destination_ip);
674 ri.remote_address.port = destination_port;
675 ri.remote_address.proto = protocol;
676 ri.local_address.af = af;
677 if (af == AF_INET)
678 ri.local_address.address.ipv4 = *((struct in_addr*) local_ip);
679 else
680 ri.local_address.address.ipv6 = *((struct in6_addr*) local_ip);
681 ri.local_address.port = local_port;
682 ri.local_address.proto = protocol;
683 hash_redirect_info (&key,
684 &ri);
685 if (NULL != state_key)
686 *state_key = key;
687 state = GNUNET_CONTAINER_multihashmap_get (connections_map,
688 &key);
689 if (NULL == state)
690 return NULL;
691 /* Mark this connection as freshly used */
692 if (NULL == state_key)
693 GNUNET_CONTAINER_heap_update_cost (state->specifics.tcp_udp.heap_node,
694 GNUNET_TIME_absolute_get ().abs_value_us);
695 return state;
696}
697
698
699/**
700 * Check a request via cadet to send a request to a TCP service
701 * offered by this system.
702 *
703 * @param cls our `struct ChannelState *`
704 * @param start the actual message
705 * @return #GNUNET_OK to keep the connection open,
706 * #GNUNET_SYSERR to close it (signal serious error)
707 */
708static int
709check_tcp_service (void *cls,
710 const struct GNUNET_EXIT_TcpServiceStartMessage *start)
711{
712 struct ChannelState *state = cls;
713
714 if (NULL == state)
715 {
716 GNUNET_break_op (0);
717 return GNUNET_SYSERR;
718 }
719 if (GNUNET_YES == state->is_dns)
720 {
721 GNUNET_break_op (0);
722 return GNUNET_SYSERR;
723 }
724 if (NULL == state->specifics.tcp_udp.serv)
725 {
726 GNUNET_break_op (0);
727 return GNUNET_SYSERR;
728 }
729 if (NULL != state->specifics.tcp_udp.heap_node)
730 {
731 GNUNET_break_op (0);
732 return GNUNET_SYSERR;
733 }
734 if (start->tcp_header.off * 4 < sizeof(struct GNUNET_TUN_TcpHeader))
735 {
736 GNUNET_break_op (0);
737 return GNUNET_SYSERR;
738 }
739 return GNUNET_OK;
740}
741
742
743/**
744 * Prepare an IPv4 packet for transmission via the TUN interface.
745 * Initializes the IP header and calculates checksums (IP+UDP/TCP).
746 * For UDP, the UDP header will be fully created, whereas for TCP
747 * only the ports and checksum will be filled in. So for TCP,
748 * a skeleton TCP header must be part of the provided payload.
749 *
750 * @param payload payload of the packet (starting with UDP payload or
751 * TCP header, depending on protocol)
752 * @param payload_length number of bytes in @a payload
753 * @param protocol IPPROTO_UDP or IPPROTO_TCP
754 * @param tcp_header skeleton of the TCP header, NULL for UDP
755 * @param src_address source address to use (IP and port)
756 * @param dst_address destination address to use (IP and port)
757 * @param pkt4 where to write the assembled packet; must
758 * contain enough space for the IP header, UDP/TCP header
759 * AND the payload
760 */
761static void
762prepare_ipv4_packet (const void *payload,
763 size_t payload_length,
764 int protocol,
765 const struct GNUNET_TUN_TcpHeader *tcp_header,
766 const struct SocketAddress *src_address,
767 const struct SocketAddress *dst_address,
768 struct GNUNET_TUN_IPv4Header *pkt4)
769{
770 size_t len;
771
772 len = payload_length;
773 switch (protocol)
774 {
775 case IPPROTO_UDP:
776 len += sizeof(struct GNUNET_TUN_UdpHeader);
777 break;
778
779 case IPPROTO_TCP:
780 len += sizeof(struct GNUNET_TUN_TcpHeader);
781 GNUNET_assert (NULL != tcp_header);
782 break;
783
784 default:
785 GNUNET_break (0);
786 return;
787 }
788 if (len + sizeof(struct GNUNET_TUN_IPv4Header) > UINT16_MAX)
789 {
790 GNUNET_break (0);
791 return;
792 }
793
794 GNUNET_TUN_initialize_ipv4_header (pkt4,
795 protocol,
796 len,
797 &src_address->address.ipv4,
798 &dst_address->address.ipv4);
799 switch (protocol)
800 {
801 case IPPROTO_UDP:
802 {
803 struct GNUNET_TUN_UdpHeader *pkt4_udp = (struct
804 GNUNET_TUN_UdpHeader *) &pkt4[1];
805
806 pkt4_udp->source_port = htons (src_address->port);
807 pkt4_udp->destination_port = htons (dst_address->port);
808 pkt4_udp->len = htons ((uint16_t) payload_length);
809 GNUNET_TUN_calculate_udp4_checksum (pkt4,
810 pkt4_udp,
811 payload,
812 payload_length);
813 GNUNET_memcpy (&pkt4_udp[1],
814 payload,
815 payload_length);
816 }
817 break;
818
819 case IPPROTO_TCP:
820 {
821 struct GNUNET_TUN_TcpHeader *pkt4_tcp = (struct
822 GNUNET_TUN_TcpHeader *) &pkt4[1];
823
824 *pkt4_tcp = *tcp_header;
825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
826 "Sending TCP packet from port %u to port %u\n",
827 src_address->port,
828 dst_address->port);
829 pkt4_tcp->source_port = htons (src_address->port);
830 pkt4_tcp->destination_port = htons (dst_address->port);
831 GNUNET_TUN_calculate_tcp4_checksum (pkt4,
832 pkt4_tcp,
833 payload,
834 payload_length);
835 GNUNET_memcpy (&pkt4_tcp[1],
836 payload,
837 payload_length);
838 }
839 break;
840
841 default:
842 GNUNET_assert (0);
843 }
844}
845
846
847/**
848 * Prepare an IPv6 packet for transmission via the TUN interface.
849 * Initializes the IP header and calculates checksums (IP+UDP/TCP).
850 * For UDP, the UDP header will be fully created, whereas for TCP
851 * only the ports and checksum will be filled in. So for TCP,
852 * a skeleton TCP header must be part of the provided payload.
853 *
854 * @param payload payload of the packet (starting with UDP payload or
855 * TCP header, depending on protocol)
856 * @param payload_length number of bytes in @a payload
857 * @param protocol IPPROTO_UDP or IPPROTO_TCP
858 * @param tcp_header skeleton TCP header data to send, NULL for UDP
859 * @param src_address source address to use (IP and port)
860 * @param dst_address destination address to use (IP and port)
861 * @param pkt6 where to write the assembled packet; must
862 * contain enough space for the IP header, UDP/TCP header
863 * AND the payload
864 */
865static void
866prepare_ipv6_packet (const void *payload,
867 size_t payload_length,
868 int protocol,
869 const struct GNUNET_TUN_TcpHeader *tcp_header,
870 const struct SocketAddress *src_address,
871 const struct SocketAddress *dst_address,
872 struct GNUNET_TUN_IPv6Header *pkt6)
873{
874 size_t len;
875
876 len = payload_length;
877 switch (protocol)
878 {
879 case IPPROTO_UDP:
880 len += sizeof(struct GNUNET_TUN_UdpHeader);
881 break;
882
883 case IPPROTO_TCP:
884 len += sizeof(struct GNUNET_TUN_TcpHeader);
885 break;
886
887 default:
888 GNUNET_break (0);
889 return;
890 }
891 if (len > UINT16_MAX)
892 {
893 GNUNET_break (0);
894 return;
895 }
896
897 GNUNET_TUN_initialize_ipv6_header (pkt6,
898 protocol,
899 len,
900 &src_address->address.ipv6,
901 &dst_address->address.ipv6);
902
903 switch (protocol)
904 {
905 case IPPROTO_UDP:
906 {
907 struct GNUNET_TUN_UdpHeader *pkt6_udp = (struct
908 GNUNET_TUN_UdpHeader *) &pkt6[1];
909
910 pkt6_udp->source_port = htons (src_address->port);
911 pkt6_udp->destination_port = htons (dst_address->port);
912 pkt6_udp->len = htons ((uint16_t) payload_length);
913 GNUNET_TUN_calculate_udp6_checksum (pkt6,
914 pkt6_udp,
915 payload,
916 payload_length);
917 GNUNET_memcpy (&pkt6_udp[1],
918 payload,
919 payload_length);
920 }
921 break;
922
923 case IPPROTO_TCP:
924 {
925 struct GNUNET_TUN_TcpHeader *pkt6_tcp = (struct
926 GNUNET_TUN_TcpHeader *) &pkt6[1];
927
928 /* GNUNET_memcpy first here as some TCP header fields are initialized this way! */
929 *pkt6_tcp = *tcp_header;
930 pkt6_tcp->source_port = htons (src_address->port);
931 pkt6_tcp->destination_port = htons (dst_address->port);
932 GNUNET_TUN_calculate_tcp6_checksum (pkt6,
933 pkt6_tcp,
934 payload,
935 payload_length);
936 GNUNET_memcpy (&pkt6_tcp[1],
937 payload,
938 payload_length);
939 }
940 break;
941
942 default:
943 GNUNET_assert (0);
944 break;
945 }
946}
947
948
949/**
950 * Send a TCP packet via the TUN interface.
951 *
952 * @param destination_address IP and port to use for the TCP packet's destination
953 * @param source_address IP and port to use for the TCP packet's source
954 * @param tcp_header header template to use
955 * @param payload payload of the TCP packet
956 * @param payload_length number of bytes in @a payload
957 */
958static void
959send_tcp_packet_via_tun (const struct SocketAddress *destination_address,
960 const struct SocketAddress *source_address,
961 const struct GNUNET_TUN_TcpHeader *tcp_header,
962 const void *payload,
963 size_t payload_length)
964{
965 size_t len;
966
967 GNUNET_STATISTICS_update (stats,
968 gettext_noop ("# TCP packets sent via TUN"),
969 1,
970 GNUNET_NO);
971 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
972 "Sending packet with %u bytes TCP payload via TUN\n",
973 (unsigned int) payload_length);
974 len = sizeof(struct GNUNET_MessageHeader) + sizeof(struct
975 GNUNET_TUN_Layer2PacketHeader);
976 switch (source_address->af)
977 {
978 case AF_INET:
979 len += sizeof(struct GNUNET_TUN_IPv4Header);
980 break;
981
982 case AF_INET6:
983 len += sizeof(struct GNUNET_TUN_IPv6Header);
984 break;
985
986 default:
987 GNUNET_break (0);
988 return;
989 }
990 len += sizeof(struct GNUNET_TUN_TcpHeader);
991 len += payload_length;
992 if (len >= GNUNET_MAX_MESSAGE_SIZE)
993 {
994 GNUNET_break (0);
995 return;
996 }
997 {
998 char buf[len] GNUNET_ALIGN;
999 struct GNUNET_MessageHeader *hdr;
1000 struct GNUNET_TUN_Layer2PacketHeader *tun;
1001
1002 hdr = (struct GNUNET_MessageHeader *) buf;
1003 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1004 hdr->size = htons (len);
1005 tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1];
1006 tun->flags = htons (0);
1007 switch (source_address->af)
1008 {
1009 case AF_INET:
1010 {
1011 struct GNUNET_TUN_IPv4Header *ipv4
1012 = (struct GNUNET_TUN_IPv4Header*) &tun[1];
1013
1014 tun->proto = htons (ETH_P_IPV4);
1015 prepare_ipv4_packet (payload,
1016 payload_length,
1017 IPPROTO_TCP,
1018 tcp_header,
1019 source_address,
1020 destination_address,
1021 ipv4);
1022 }
1023 break;
1024
1025 case AF_INET6:
1026 {
1027 struct GNUNET_TUN_IPv6Header *ipv6
1028 = (struct GNUNET_TUN_IPv6Header*) &tun[1];
1029
1030 tun->proto = htons (ETH_P_IPV6);
1031 prepare_ipv6_packet (payload,
1032 payload_length,
1033 IPPROTO_TCP,
1034 tcp_header,
1035 source_address,
1036 destination_address,
1037 ipv6);
1038 }
1039 break;
1040
1041 default:
1042 GNUNET_assert (0);
1043 break;
1044 }
1045 if (NULL != helper_handle)
1046 (void) GNUNET_HELPER_send (helper_handle,
1047 (const struct GNUNET_MessageHeader*) buf,
1048 GNUNET_YES,
1049 NULL,
1050 NULL);
1051 }
1052}
1053
1054
1055/**
1056 * Send an ICMP packet via the TUN interface.
1057 *
1058 * @param destination_address IP to use for the ICMP packet's destination
1059 * @param source_address IP to use for the ICMP packet's source
1060 * @param icmp_header ICMP header to send
1061 * @param payload payload of the ICMP packet (does NOT include ICMP header)
1062 * @param payload_length number of bytes of data in @a payload
1063 */
1064static void
1065send_icmp_packet_via_tun (const struct SocketAddress *destination_address,
1066 const struct SocketAddress *source_address,
1067 const struct GNUNET_TUN_IcmpHeader *icmp_header,
1068 const void *payload, size_t payload_length)
1069{
1070 size_t len;
1071 struct GNUNET_TUN_IcmpHeader *icmp;
1072
1073 GNUNET_STATISTICS_update (stats,
1074 gettext_noop ("# ICMP packets sent via TUN"),
1075 1, GNUNET_NO);
1076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077 "Sending packet with %u bytes ICMP payload via TUN\n",
1078 (unsigned int) payload_length);
1079 len = sizeof(struct GNUNET_MessageHeader) + sizeof(struct
1080 GNUNET_TUN_Layer2PacketHeader);
1081 switch (destination_address->af)
1082 {
1083 case AF_INET:
1084 len += sizeof(struct GNUNET_TUN_IPv4Header);
1085 break;
1086
1087 case AF_INET6:
1088 len += sizeof(struct GNUNET_TUN_IPv6Header);
1089 break;
1090
1091 default:
1092 GNUNET_break (0);
1093 return;
1094 }
1095 len += sizeof(struct GNUNET_TUN_IcmpHeader);
1096 len += payload_length;
1097 if (len >= GNUNET_MAX_MESSAGE_SIZE)
1098 {
1099 GNUNET_break (0);
1100 return;
1101 }
1102 {
1103 char buf[len] GNUNET_ALIGN;
1104 struct GNUNET_MessageHeader *hdr;
1105 struct GNUNET_TUN_Layer2PacketHeader *tun;
1106
1107 hdr = (struct GNUNET_MessageHeader *) buf;
1108 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1109 hdr->size = htons (len);
1110 tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1];
1111 tun->flags = htons (0);
1112 switch (source_address->af)
1113 {
1114 case AF_INET:
1115 {
1116 struct GNUNET_TUN_IPv4Header *ipv4 = (struct
1117 GNUNET_TUN_IPv4Header*) &tun[1];
1118
1119 tun->proto = htons (ETH_P_IPV4);
1120 GNUNET_TUN_initialize_ipv4_header (ipv4,
1121 IPPROTO_ICMP,
1122 sizeof(struct
1123 GNUNET_TUN_IcmpHeader)
1124 + payload_length,
1125 &source_address->address.ipv4,
1126 &destination_address->address.ipv4);
1127 icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv4[1];
1128 }
1129 break;
1130
1131 case AF_INET6:
1132 {
1133 struct GNUNET_TUN_IPv6Header *ipv6 = (struct
1134 GNUNET_TUN_IPv6Header*) &tun[1];
1135
1136 tun->proto = htons (ETH_P_IPV6);
1137 GNUNET_TUN_initialize_ipv6_header (ipv6,
1138 IPPROTO_ICMPV6,
1139 sizeof(struct
1140 GNUNET_TUN_IcmpHeader)
1141 + payload_length,
1142 &source_address->address.ipv6,
1143 &destination_address->address.ipv6);
1144 icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv6[1];
1145 }
1146 break;
1147
1148 default:
1149 GNUNET_assert (0);
1150 break;
1151 }
1152 *icmp = *icmp_header;
1153 GNUNET_memcpy (&icmp[1],
1154 payload,
1155 payload_length);
1156 GNUNET_TUN_calculate_icmp_checksum (icmp,
1157 payload,
1158 payload_length);
1159 if (NULL != helper_handle)
1160 (void) GNUNET_HELPER_send (helper_handle,
1161 (const struct GNUNET_MessageHeader*) buf,
1162 GNUNET_YES,
1163 NULL, NULL);
1164 }
1165}
1166
1167
1168/**
1169 * We need to create a (unique) fresh local address (IP+port).
1170 * Fill one in.
1171 *
1172 * @param af desired address family
1173 * @param proto desired protocol (IPPROTO_UDP or IPPROTO_TCP)
1174 * @param local_address address to initialize
1175 */
1176static void
1177setup_fresh_address (int af,
1178 uint8_t proto,
1179 struct SocketAddress *local_address)
1180{
1181 local_address->af = af;
1182 local_address->proto = (uint8_t) proto;
1183 /* default "local" port range is often 32768--61000,
1184 so we pick a random value in that range */
1185 if (((af == AF_INET) && (proto == IPPROTO_ICMP)) ||
1186 ((af == AF_INET6) && (proto == IPPROTO_ICMPV6)))
1187 local_address->port = 0;
1188 else
1189 local_address->port
1190 = (uint16_t) 32768 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1191 28232);
1192 switch (af)
1193 {
1194 case AF_INET:
1195 {
1196 struct in_addr addr;
1197 struct in_addr mask;
1198 struct in_addr rnd;
1199
1200 addr = exit_ipv4addr;
1201 mask = exit_ipv4mask;
1202 if (0 == ~mask.s_addr)
1203 {
1204 /* only one valid IP anyway */
1205 local_address->address.ipv4 = addr;
1206 return;
1207 }
1208 /* Given 192.168.0.1/255.255.0.0, we want a mask
1209 of '192.168.255.255', thus: */
1210 mask.s_addr = addr.s_addr | ~mask.s_addr;
1211 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
1212 do
1213 {
1214 rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1215 UINT32_MAX);
1216 local_address->address.ipv4.s_addr = (addr.s_addr | rnd.s_addr)
1217 & mask.s_addr;
1218 }
1219 while ((local_address->address.ipv4.s_addr == addr.s_addr) ||
1220 (local_address->address.ipv4.s_addr == mask.s_addr));
1221 }
1222 break;
1223
1224 case AF_INET6:
1225 {
1226 struct in6_addr addr;
1227 struct in6_addr mask;
1228 struct in6_addr rnd;
1229 int i;
1230
1231 addr = exit_ipv6addr;
1232 GNUNET_assert (ipv6prefix < 128);
1233 if (ipv6prefix == 127)
1234 {
1235 /* only one valid IP anyway */
1236 local_address->address.ipv6 = addr;
1237 return;
1238 }
1239 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
1240 thus: */
1241 mask = addr;
1242 for (i = 127; i >= ipv6prefix; i--)
1243 mask.s6_addr[i / 8] |= (1 << (i % 8));
1244
1245 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
1246 do
1247 {
1248 for (i = 0; i < 16; i++)
1249 {
1250 rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (
1251 GNUNET_CRYPTO_QUALITY_WEAK,
1252 256);
1253 local_address->address.ipv6.s6_addr[i]
1254 = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
1255 }
1256 }
1257 while ((0 == GNUNET_memcmp (&local_address->address.ipv6,
1258 &addr)) ||
1259 (0 == GNUNET_memcmp (&local_address->address.ipv6,
1260 &mask)));
1261 }
1262 break;
1263
1264 default:
1265 GNUNET_assert (0);
1266 }
1267}
1268
1269
1270/**
1271 * We are starting a fresh connection (TCP or UDP) and need
1272 * to pick a source port and IP address (within the correct
1273 * range and address family) to associate replies with the
1274 * connection / correct cadet channel. This function generates
1275 * a "fresh" source IP and source port number for a connection
1276 * After picking a good source address, this function sets up
1277 * the state in the 'connections_map' and 'connections_heap'
1278 * to allow finding the state when needed later. The function
1279 * also makes sure that we remain within memory limits by
1280 * cleaning up 'old' states.
1281 *
1282 * @param state skeleton state to setup a record for; should
1283 * 'state->specifics.tcp_udp.ri.remote_address' filled in so that
1284 * this code can determine which AF/protocol is
1285 * going to be used (the 'channel' should also
1286 * already be set); after calling this function,
1287 * heap_node and the local_address will be
1288 * also initialized (heap_node != NULL can be
1289 * used to test if a state has been fully setup).
1290 */
1291static void
1292setup_state_record (struct ChannelState *state)
1293{
1294 struct GNUNET_HashCode key;
1295 struct ChannelState *s;
1296
1297 /* generate fresh, unique address */
1298 do
1299 {
1300 if (NULL == state->specifics.tcp_udp.serv)
1301 setup_fresh_address (state->specifics.tcp_udp.ri.remote_address.af,
1302 state->specifics.tcp_udp.ri.remote_address.proto,
1303 &state->specifics.tcp_udp.ri.local_address);
1304 else
1305 setup_fresh_address (state->specifics.tcp_udp.serv->address.af,
1306 state->specifics.tcp_udp.serv->address.proto,
1307 &state->specifics.tcp_udp.ri.local_address);
1308 }
1309 while (NULL !=
1310 get_redirect_state (state->specifics.tcp_udp.ri.remote_address.af,
1311 state->specifics.tcp_udp.ri.remote_address.proto,
1312 &state->specifics.tcp_udp.ri.remote_address.address,
1313 state->specifics.tcp_udp.ri.remote_address.port,
1314 &state->specifics.tcp_udp.ri.local_address.address,
1315 state->specifics.tcp_udp.ri.local_address.port,
1316 &key));
1317 {
1318 char buf[INET6_ADDRSTRLEN];
1319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1320 "Picked local address %s:%u for new connection\n",
1321 inet_ntop (state->specifics.tcp_udp.ri.local_address.af,
1322 &state->specifics.tcp_udp.ri.local_address.address,
1323 buf,
1324 sizeof(buf)),
1325 (unsigned int) state->specifics.tcp_udp.ri.local_address.port);
1326 }
1327 state->specifics.tcp_udp.state_key = key;
1328 GNUNET_assert (GNUNET_OK ==
1329 GNUNET_CONTAINER_multihashmap_put (connections_map,
1330 &key, state,
1331 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1332 state->specifics.tcp_udp.heap_node
1333 = GNUNET_CONTAINER_heap_insert (connections_heap,
1334 state,
1335 GNUNET_TIME_absolute_get ().abs_value_us);
1336 while (GNUNET_CONTAINER_heap_get_size (connections_heap) > max_connections)
1337 {
1338 s = GNUNET_CONTAINER_heap_remove_root (connections_heap);
1339 GNUNET_assert (state != s);
1340 s->specifics.tcp_udp.heap_node = NULL;
1341 GNUNET_CADET_channel_destroy (s->channel);
1342 GNUNET_assert (GNUNET_OK ==
1343 GNUNET_CONTAINER_multihashmap_remove (connections_map,
1344 &s->specifics.tcp_udp.
1345 state_key,
1346 s));
1347 GNUNET_free (s);
1348 }
1349}
1350
1351
1352/**
1353 * Send a UDP packet via the TUN interface.
1354 *
1355 * @param destination_address IP and port to use for the UDP packet's destination
1356 * @param source_address IP and port to use for the UDP packet's source
1357 * @param payload payload of the UDP packet (does NOT include UDP header)
1358 * @param payload_length number of bytes of data in @a payload
1359 */
1360static void
1361send_udp_packet_via_tun (const struct SocketAddress *destination_address,
1362 const struct SocketAddress *source_address,
1363 const void *payload, size_t payload_length)
1364{
1365 size_t len;
1366
1367 GNUNET_STATISTICS_update (stats,
1368 gettext_noop ("# UDP packets sent via TUN"),
1369 1, GNUNET_NO);
1370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1371 "Sending packet with %u bytes UDP payload via TUN\n",
1372 (unsigned int) payload_length);
1373 len = sizeof(struct GNUNET_MessageHeader) + sizeof(struct
1374 GNUNET_TUN_Layer2PacketHeader);
1375 switch (source_address->af)
1376 {
1377 case AF_INET:
1378 len += sizeof(struct GNUNET_TUN_IPv4Header);
1379 break;
1380
1381 case AF_INET6:
1382 len += sizeof(struct GNUNET_TUN_IPv6Header);
1383 break;
1384
1385 default:
1386 GNUNET_break (0);
1387 return;
1388 }
1389 len += sizeof(struct GNUNET_TUN_UdpHeader);
1390 len += payload_length;
1391 if (len >= GNUNET_MAX_MESSAGE_SIZE)
1392 {
1393 GNUNET_break (0);
1394 return;
1395 }
1396 {
1397 char buf[len] GNUNET_ALIGN;
1398 struct GNUNET_MessageHeader *hdr;
1399 struct GNUNET_TUN_Layer2PacketHeader *tun;
1400
1401 hdr = (struct GNUNET_MessageHeader *) buf;
1402 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1403 hdr->size = htons (len);
1404 tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1];
1405 tun->flags = htons (0);
1406 switch (source_address->af)
1407 {
1408 case AF_INET:
1409 {
1410 struct GNUNET_TUN_IPv4Header *ipv4 = (struct
1411 GNUNET_TUN_IPv4Header*) &tun[1];
1412
1413 tun->proto = htons (ETH_P_IPV4);
1414 prepare_ipv4_packet (payload,
1415 payload_length,
1416 IPPROTO_UDP,
1417 NULL,
1418 source_address,
1419 destination_address,
1420 ipv4);
1421 }
1422 break;
1423
1424 case AF_INET6:
1425 {
1426 struct GNUNET_TUN_IPv6Header *ipv6 = (struct
1427 GNUNET_TUN_IPv6Header*) &tun[1];
1428
1429 tun->proto = htons (ETH_P_IPV6);
1430 prepare_ipv6_packet (payload,
1431 payload_length,
1432 IPPROTO_UDP,
1433 NULL,
1434 source_address,
1435 destination_address,
1436 ipv6);
1437 }
1438 break;
1439
1440 default:
1441 GNUNET_assert (0);
1442 break;
1443 }
1444 if (NULL != helper_handle)
1445 (void) GNUNET_HELPER_send (helper_handle,
1446 (const struct GNUNET_MessageHeader*) buf,
1447 GNUNET_YES,
1448 NULL, NULL);
1449 }
1450}
1451
1452
1453/**
1454 * Check a request to forward UDP data to the Internet via this peer.
1455 *
1456 * @param cls our `struct ChannelState *`
1457 * @param msg the actual message
1458 * @return #GNUNET_OK to keep the connection open,
1459 * #GNUNET_SYSERR to close it (signal serious error)
1460 */
1461static int
1462check_udp_remote (void *cls,
1463 const struct GNUNET_EXIT_UdpInternetMessage *msg)
1464{
1465 struct ChannelState *state = cls;
1466
1467 if (GNUNET_YES == state->is_dns)
1468 {
1469 GNUNET_break_op (0);
1470 return GNUNET_SYSERR;
1471 }
1472 return GNUNET_OK;
1473}
1474
1475
1476/**
1477 * Process a request to forward UDP data to the Internet via this peer.
1478 *
1479 * @param cls our `struct ChannelState *`
1480 * @param msg the actual message
1481 */
1482static void
1483handle_udp_remote (void *cls,
1484 const struct GNUNET_EXIT_UdpInternetMessage *msg)
1485{
1486 struct ChannelState *state = cls;
1487 uint16_t pkt_len = ntohs (msg->header.size) - sizeof(struct
1488 GNUNET_EXIT_UdpInternetMessage);
1489 const struct in_addr *v4;
1490 const struct in6_addr *v6;
1491 const void *payload;
1492 int af;
1493
1494 if (GNUNET_SYSERR == state->is_dns)
1495 {
1496 /* channel is UDP/TCP from now on */
1497 state->is_dns = GNUNET_NO;
1498 }
1499 GNUNET_STATISTICS_update (stats,
1500 gettext_noop ("# Bytes received from CADET"),
1501 pkt_len, GNUNET_NO);
1502 GNUNET_STATISTICS_update (stats,
1503 gettext_noop (
1504 "# UDP IP-exit requests received via cadet"),
1505 1, GNUNET_NO);
1506 af = (int) ntohl (msg->af);
1507 state->specifics.tcp_udp.ri.remote_address.af = af;
1508 switch (af)
1509 {
1510 case AF_INET:
1511 if (pkt_len < sizeof(struct in_addr))
1512 {
1513 GNUNET_break_op (0);
1514 return;
1515 }
1516 if (! ipv4_exit)
1517 {
1518 GNUNET_break_op (0);
1519 return;
1520 }
1521 v4 = (const struct in_addr*) &msg[1];
1522 payload = &v4[1];
1523 pkt_len -= sizeof(struct in_addr);
1524 state->specifics.tcp_udp.ri.remote_address.address.ipv4 = *v4;
1525 break;
1526
1527 case AF_INET6:
1528 if (pkt_len < sizeof(struct in6_addr))
1529 {
1530 GNUNET_break_op (0);
1531 return;
1532 }
1533 if (! ipv6_exit)
1534 {
1535 GNUNET_break_op (0);
1536 return;
1537 }
1538 v6 = (const struct in6_addr*) &msg[1];
1539 payload = &v6[1];
1540 pkt_len -= sizeof(struct in6_addr);
1541 state->specifics.tcp_udp.ri.remote_address.address.ipv6 = *v6;
1542 break;
1543
1544 default:
1545 GNUNET_break_op (0);
1546 return;
1547 }
1548 {
1549 char buf[INET6_ADDRSTRLEN];
1550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1551 "Received data from %s for forwarding to UDP %s:%u\n",
1552 GNUNET_i2s (&state->peer),
1553 inet_ntop (af,
1554 &state->specifics.tcp_udp.ri.remote_address.address,
1555 buf, sizeof(buf)),
1556 (unsigned int) ntohs (msg->destination_port));
1557 }
1558 state->specifics.tcp_udp.ri.remote_address.proto = IPPROTO_UDP;
1559 state->specifics.tcp_udp.ri.remote_address.port = msg->destination_port;
1560 if (NULL == state->specifics.tcp_udp.heap_node)
1561 setup_state_record (state);
1562 if (0 != ntohs (msg->source_port))
1563 state->specifics.tcp_udp.ri.local_address.port = msg->source_port;
1564 send_udp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address,
1565 &state->specifics.tcp_udp.ri.local_address,
1566 payload,
1567 pkt_len);
1568 GNUNET_CADET_receive_done (state->channel);
1569}
1570
1571
1572/**
1573 * Check a request via cadet to send a request to a UDP service
1574 * offered by this system.
1575 *
1576 * @param cls our `struct ChannelState *`
1577 * @param msg the actual message
1578 * @return #GNUNET_OK to keep the connection open,
1579 * #GNUNET_SYSERR to close it (signal serious error)
1580 */
1581static int
1582check_udp_service (void *cls,
1583 const struct GNUNET_EXIT_UdpServiceMessage *msg)
1584{
1585 struct ChannelState *state = cls;
1586
1587 if (NULL == state->specifics.tcp_udp.serv)
1588 {
1589 GNUNET_break_op (0);
1590 return GNUNET_SYSERR;
1591 }
1592 return GNUNET_OK;
1593}
1594
1595
1596/**
1597 * Process a request via cadet to send a request to a UDP service
1598 * offered by this system.
1599 *
1600 * @param cls our `struct ChannelState *`
1601 * @param msg the actual message
1602 */
1603static void
1604handle_udp_service (void *cls,
1605 const struct GNUNET_EXIT_UdpServiceMessage *msg)
1606{
1607 struct ChannelState *state = cls;
1608 uint16_t pkt_len = ntohs (msg->header.size) - sizeof(struct
1609 GNUNET_EXIT_UdpServiceMessage);
1610
1611 GNUNET_STATISTICS_update (stats,
1612 gettext_noop ("# Bytes received from CADET"),
1613 pkt_len, GNUNET_NO);
1614 GNUNET_STATISTICS_update (stats,
1615 gettext_noop (
1616 "# UDP service requests received via cadet"),
1617 1, GNUNET_NO);
1618 LOG (GNUNET_ERROR_TYPE_DEBUG,
1619 "Received data from %s for forwarding to UDP service %s on port %u\n",
1620 GNUNET_i2s (&state->peer),
1621 GNUNET_h2s (&state->specifics.tcp_udp.serv->descriptor),
1622 (unsigned int) ntohs (msg->destination_port));
1623 setup_state_record (state);
1624 if (0 != ntohs (msg->source_port))
1625 state->specifics.tcp_udp.ri.local_address.port = msg->source_port;
1626 send_udp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address,
1627 &state->specifics.tcp_udp.ri.local_address,
1628 &msg[1],
1629 pkt_len);
1630 GNUNET_CADET_receive_done (state->channel);
1631}
1632
1633
1634/**
1635 * Process a request via cadet to send a request to a TCP service
1636 * offered by this system.
1637 *
1638 * @param cls our `struct ChannelState *`
1639 * @param start the actual message
1640 * @return #GNUNET_OK to keep the connection open,
1641 * #GNUNET_SYSERR to close it (signal serious error)
1642 */
1643static void
1644handle_tcp_service (void *cls,
1645 const struct GNUNET_EXIT_TcpServiceStartMessage *start)
1646{
1647 struct ChannelState *state = cls;
1648 uint16_t pkt_len = ntohs (start->header.size) - sizeof(struct
1649 GNUNET_EXIT_TcpServiceStartMessage);
1650
1651 if (GNUNET_SYSERR == state->is_dns)
1652 {
1653 /* channel is UDP/TCP from now on */
1654 state->is_dns = GNUNET_NO;
1655 }
1656 GNUNET_STATISTICS_update (stats,
1657 gettext_noop (
1658 "# TCP service creation requests received via cadet"),
1659 1,
1660 GNUNET_NO);
1661 GNUNET_STATISTICS_update (stats,
1662 gettext_noop ("# Bytes received from CADET"),
1663 pkt_len,
1664 GNUNET_NO);
1665 GNUNET_break_op (ntohl (start->reserved) == 0);
1666 /* setup fresh connection */
1667 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1668 "Received data from %s for forwarding to TCP service %s on port %u\n",
1669 GNUNET_i2s (&state->peer),
1670 GNUNET_h2s (&state->specifics.tcp_udp.serv->descriptor),
1671 (unsigned int) ntohs (start->tcp_header.destination_port));
1672 setup_state_record (state);
1673 send_tcp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address,
1674 &state->specifics.tcp_udp.ri.local_address,
1675 &start->tcp_header,
1676 &start[1],
1677 pkt_len);
1678 GNUNET_CADET_receive_done (state->channel);
1679}
1680
1681
1682/**
1683 * Check a request to forward TCP data to the Internet via this peer.
1684 *
1685 * @param cls our `struct ChannelState *`
1686 * @param start the actual message
1687 * @return #GNUNET_OK to keep the connection open,
1688 * #GNUNET_SYSERR to close it (signal serious error)
1689 */
1690static int
1691check_tcp_remote (void *cls,
1692 const struct GNUNET_EXIT_TcpInternetStartMessage *start)
1693{
1694 struct ChannelState *state = cls;
1695
1696 if (NULL == state)
1697 {
1698 GNUNET_break_op (0);
1699 return GNUNET_SYSERR;
1700 }
1701 if (GNUNET_YES == state->is_dns)
1702 {
1703 GNUNET_break_op (0);
1704 return GNUNET_SYSERR;
1705 }
1706 if ((NULL != state->specifics.tcp_udp.serv) ||
1707 (NULL != state->specifics.tcp_udp.heap_node))
1708 {
1709 GNUNET_break_op (0);
1710 return GNUNET_SYSERR;
1711 }
1712 if (start->tcp_header.off * 4 < sizeof(struct GNUNET_TUN_TcpHeader))
1713 {
1714 GNUNET_break_op (0);
1715 return GNUNET_SYSERR;
1716 }
1717 return GNUNET_OK;
1718}
1719
1720
1721/**
1722 * Process a request to forward TCP data to the Internet via this peer.
1723 *
1724 * @param cls our `struct ChannelState *`
1725 * @param start the actual message
1726 */
1727static void
1728handle_tcp_remote (void *cls,
1729 const struct GNUNET_EXIT_TcpInternetStartMessage *start)
1730{
1731 struct ChannelState *state = cls;
1732 uint16_t pkt_len = ntohs (start->header.size) - sizeof(struct
1733 GNUNET_EXIT_TcpInternetStartMessage);
1734 const struct in_addr *v4;
1735 const struct in6_addr *v6;
1736 const void *payload;
1737 int af;
1738
1739 if (GNUNET_SYSERR == state->is_dns)
1740 {
1741 /* channel is UDP/TCP from now on */
1742 state->is_dns = GNUNET_NO;
1743 }
1744 GNUNET_STATISTICS_update (stats,
1745 gettext_noop ("# Bytes received from CADET"),
1746 pkt_len, GNUNET_NO);
1747 GNUNET_STATISTICS_update (stats,
1748 gettext_noop (
1749 "# TCP IP-exit creation requests received via cadet"),
1750 1, GNUNET_NO);
1751 af = (int) ntohl (start->af);
1752 state->specifics.tcp_udp.ri.remote_address.af = af;
1753 switch (af)
1754 {
1755 case AF_INET:
1756 if (pkt_len < sizeof(struct in_addr))
1757 {
1758 GNUNET_break_op (0);
1759 return;
1760 }
1761 if (! ipv4_exit)
1762 {
1763 GNUNET_break_op (0);
1764 return;
1765 }
1766 v4 = (const struct in_addr*) &start[1];
1767 payload = &v4[1];
1768 pkt_len -= sizeof(struct in_addr);
1769 state->specifics.tcp_udp.ri.remote_address.address.ipv4 = *v4;
1770 break;
1771
1772 case AF_INET6:
1773 if (pkt_len < sizeof(struct in6_addr))
1774 {
1775 GNUNET_break_op (0);
1776 return;
1777 }
1778 if (! ipv6_exit)
1779 {
1780 GNUNET_break_op (0);
1781 return;
1782 }
1783 v6 = (const struct in6_addr*) &start[1];
1784 payload = &v6[1];
1785 pkt_len -= sizeof(struct in6_addr);
1786 state->specifics.tcp_udp.ri.remote_address.address.ipv6 = *v6;
1787 break;
1788
1789 default:
1790 GNUNET_break_op (0);
1791 return;
1792 }
1793 {
1794 char buf[INET6_ADDRSTRLEN];
1795 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1796 "Received payload from %s for existing TCP stream to %s:%u\n",
1797 GNUNET_i2s (&state->peer),
1798 inet_ntop (af,
1799 &state->specifics.tcp_udp.ri.remote_address.address,
1800 buf, sizeof(buf)),
1801 (unsigned int) ntohs (start->tcp_header.destination_port));
1802 }
1803 state->specifics.tcp_udp.ri.remote_address.proto = IPPROTO_TCP;
1804 state->specifics.tcp_udp.ri.remote_address.port = ntohs (
1805 start->tcp_header.destination_port);
1806 setup_state_record (state);
1807 send_tcp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address,
1808 &state->specifics.tcp_udp.ri.local_address,
1809 &start->tcp_header,
1810 payload,
1811 pkt_len);
1812 GNUNET_CADET_receive_done (state->channel);
1813}
1814
1815
1816/**
1817 * Check a request to forward TCP data on an established
1818 * connection via this peer.
1819 *
1820 * @param cls our `struct ChannelState *`
1821 * @param data the actual message
1822 * @return #GNUNET_OK to keep the connection open,
1823 * #GNUNET_SYSERR to close it (signal serious error)
1824 */
1825static int
1826check_tcp_data (void *cls,
1827 const struct GNUNET_EXIT_TcpDataMessage *data)
1828{
1829 struct ChannelState *state = cls;
1830
1831 if ((NULL == state) ||
1832 (NULL == state->specifics.tcp_udp.heap_node))
1833 {
1834 /* connection should have been up! */
1835 GNUNET_STATISTICS_update (stats,
1836 gettext_noop (
1837 "# TCP DATA requests dropped (no session)"),
1838 1, GNUNET_NO);
1839 GNUNET_break_op (0);
1840 return GNUNET_SYSERR;
1841 }
1842 if (data->tcp_header.off * 4 < sizeof(struct GNUNET_TUN_TcpHeader))
1843 {
1844 GNUNET_break_op (0);
1845 return GNUNET_SYSERR;
1846 }
1847 if (GNUNET_YES == state->is_dns)
1848 {
1849 GNUNET_break_op (0);
1850 return GNUNET_SYSERR;
1851 }
1852 return GNUNET_OK;
1853}
1854
1855
1856/**
1857 * Process a request to forward TCP data on an established
1858 * connection via this peer.
1859 *
1860 * @param cls our `struct ChannelState *`
1861 * @param data the actual message
1862 */
1863static void
1864handle_tcp_data (void *cls,
1865 const struct GNUNET_EXIT_TcpDataMessage *data)
1866{
1867 struct ChannelState *state = cls;
1868 uint16_t pkt_len = ntohs (data->header.size) - sizeof(struct
1869 GNUNET_EXIT_TcpDataMessage);
1870
1871 GNUNET_STATISTICS_update (stats,
1872 gettext_noop ("# Bytes received from CADET"),
1873 pkt_len, GNUNET_NO);
1874 GNUNET_STATISTICS_update (stats,
1875 gettext_noop (
1876 "# TCP data requests received via cadet"),
1877 1, GNUNET_NO);
1878 if (GNUNET_SYSERR == state->is_dns)
1879 {
1880 /* channel is UDP/TCP from now on */
1881 state->is_dns = GNUNET_NO;
1882 }
1883
1884 GNUNET_break_op (ntohl (data->reserved) == 0);
1885 {
1886 char buf[INET6_ADDRSTRLEN];
1887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1888 "Received additional %u bytes of data from %s for TCP stream to %s:%u\n",
1889 pkt_len,
1890 GNUNET_i2s (&state->peer),
1891 inet_ntop (state->specifics.tcp_udp.ri.remote_address.af,
1892 &state->specifics.tcp_udp.ri.remote_address.address,
1893 buf, sizeof(buf)),
1894 (unsigned int) state->specifics.tcp_udp.ri.remote_address.port);
1895 }
1896
1897 send_tcp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address,
1898 &state->specifics.tcp_udp.ri.local_address,
1899 &data->tcp_header,
1900 &data[1], pkt_len);
1901 GNUNET_CADET_receive_done (state->channel);
1902}
1903
1904
1905/**
1906 * Synthesize a plausible ICMP payload for an ICMPv4 error
1907 * response on the given channel.
1908 *
1909 * @param state channel information
1910 * @param ipp IPv6 header to fill in (ICMP payload)
1911 * @param udp "UDP" header to fill in (ICMP payload); might actually
1912 * also be the first 8 bytes of the TCP header
1913 */
1914static void
1915make_up_icmpv4_payload (struct ChannelState *state,
1916 struct GNUNET_TUN_IPv4Header *ipp,
1917 struct GNUNET_TUN_UdpHeader *udp)
1918{
1919 GNUNET_TUN_initialize_ipv4_header (ipp,
1920 state->specifics.tcp_udp.ri.remote_address.
1921 proto,
1922 sizeof(struct GNUNET_TUN_TcpHeader),
1923 &state->specifics.tcp_udp.ri.remote_address
1924 .address.ipv4,
1925 &state->specifics.tcp_udp.ri.local_address.
1926 address.ipv4);
1927 udp->source_port = htons (state->specifics.tcp_udp.ri.remote_address.port);
1928 udp->destination_port = htons (
1929 state->specifics.tcp_udp.ri.local_address.port);
1930 udp->len = htons (0);
1931 udp->crc = htons (0);
1932}
1933
1934
1935/**
1936 * Synthesize a plausible ICMP payload for an ICMPv6 error
1937 * response on the given channel.
1938 *
1939 * @param state channel information
1940 * @param ipp IPv6 header to fill in (ICMP payload)
1941 * @param udp "UDP" header to fill in (ICMP payload); might actually
1942 * also be the first 8 bytes of the TCP header
1943 */
1944static void
1945make_up_icmpv6_payload (struct ChannelState *state,
1946 struct GNUNET_TUN_IPv6Header *ipp,
1947 struct GNUNET_TUN_UdpHeader *udp)
1948{
1949 GNUNET_TUN_initialize_ipv6_header (ipp,
1950 state->specifics.tcp_udp.ri.remote_address.
1951 proto,
1952 sizeof(struct GNUNET_TUN_TcpHeader),
1953 &state->specifics.tcp_udp.ri.remote_address
1954 .address.ipv6,
1955 &state->specifics.tcp_udp.ri.local_address.
1956 address.ipv6);
1957 udp->source_port = htons (state->specifics.tcp_udp.ri.remote_address.port);
1958 udp->destination_port = htons (
1959 state->specifics.tcp_udp.ri.local_address.port);
1960 udp->len = htons (0);
1961 udp->crc = htons (0);
1962}
1963
1964
1965/**
1966 * Check a request to forward ICMP data to the Internet via this peer.
1967 *
1968 * @param cls our `struct ChannelState *`
1969 * @param msg the actual message
1970 * @return #GNUNET_OK to keep the connection open,
1971 * #GNUNET_SYSERR to close it (signal serious error)
1972 */
1973static int
1974check_icmp_remote (void *cls,
1975 const struct GNUNET_EXIT_IcmpInternetMessage *msg)
1976{
1977 struct ChannelState *state = cls;
1978
1979 if (GNUNET_YES == state->is_dns)
1980 {
1981 GNUNET_break_op (0);
1982 return GNUNET_SYSERR;
1983 }
1984 return GNUNET_OK;
1985}
1986
1987
1988/**
1989 * Process a request to forward ICMP data to the Internet via this peer.
1990 *
1991 * @param cls our `struct ChannelState *`
1992 * @param msg the actual message
1993 */
1994static void
1995handle_icmp_remote (void *cls,
1996 const struct GNUNET_EXIT_IcmpInternetMessage *msg)
1997{
1998 struct ChannelState *state = cls;
1999 uint16_t pkt_len = ntohs (msg->header.size) - sizeof(struct
2000 GNUNET_EXIT_IcmpInternetMessage);
2001 const struct in_addr *v4;
2002 const struct in6_addr *v6;
2003 const void *payload;
2004 char buf[sizeof(struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
2005 int af;
2006
2007 if (GNUNET_SYSERR == state->is_dns)
2008 {
2009 /* channel is UDP/TCP from now on */
2010 state->is_dns = GNUNET_NO;
2011 }
2012 GNUNET_STATISTICS_update (stats,
2013 gettext_noop ("# Bytes received from CADET"),
2014 pkt_len, GNUNET_NO);
2015 GNUNET_STATISTICS_update (stats,
2016 gettext_noop (
2017 "# ICMP IP-exit requests received via cadet"),
2018 1, GNUNET_NO);
2019
2020 af = (int) ntohl (msg->af);
2021 if ((NULL != state->specifics.tcp_udp.heap_node) &&
2022 (af != state->specifics.tcp_udp.ri.remote_address.af))
2023 {
2024 /* other peer switched AF on this channel; not allowed */
2025 GNUNET_break_op (0);
2026 return;
2027 }
2028
2029 switch (af)
2030 {
2031 case AF_INET:
2032 if (pkt_len < sizeof(struct in_addr))
2033 {
2034 GNUNET_break_op (0);
2035 return;
2036 }
2037 if (! ipv4_exit)
2038 {
2039 GNUNET_break_op (0);
2040 return;
2041 }
2042 v4 = (const struct in_addr*) &msg[1];
2043 payload = &v4[1];
2044 pkt_len -= sizeof(struct in_addr);
2045 state->specifics.tcp_udp.ri.remote_address.address.ipv4 = *v4;
2046 if (NULL == state->specifics.tcp_udp.heap_node)
2047 {
2048 state->specifics.tcp_udp.ri.remote_address.af = af;
2049 state->specifics.tcp_udp.ri.remote_address.proto = IPPROTO_ICMP;
2050 setup_state_record (state);
2051 }
2052 /* check that ICMP type is something we want to support
2053 and possibly make up payload! */
2054 switch (msg->icmp_header.type)
2055 {
2056 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
2057 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
2058 break;
2059
2060 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
2061 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2062 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
2063 if (0 != pkt_len)
2064 {
2065 GNUNET_break_op (0);
2066 return;
2067 }
2068 /* make up payload */
2069 {
2070 struct GNUNET_TUN_IPv4Header *ipp = (struct
2071 GNUNET_TUN_IPv4Header *) buf;
2072 struct GNUNET_TUN_UdpHeader *udp = (struct
2073 GNUNET_TUN_UdpHeader *) &ipp[1];
2074
2075 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_UdpHeader));
2076 pkt_len = sizeof(struct GNUNET_TUN_IPv4Header) + 8;
2077 make_up_icmpv4_payload (state,
2078 ipp,
2079 udp);
2080 payload = ipp;
2081 }
2082 break;
2083
2084 default:
2085 GNUNET_break_op (0);
2086 GNUNET_STATISTICS_update (stats,
2087 gettext_noop (
2088 "# ICMPv4 packets dropped (type not allowed)"),
2089 1, GNUNET_NO);
2090 return;
2091 }
2092 /* end AF_INET */
2093 break;
2094
2095 case AF_INET6:
2096 if (pkt_len < sizeof(struct in6_addr))
2097 {
2098 GNUNET_break_op (0);
2099 return;
2100 }
2101 if (! ipv6_exit)
2102 {
2103 GNUNET_break_op (0);
2104 return;
2105 }
2106 v6 = (const struct in6_addr*) &msg[1];
2107 payload = &v6[1];
2108 pkt_len -= sizeof(struct in6_addr);
2109 state->specifics.tcp_udp.ri.remote_address.address.ipv6 = *v6;
2110 if (NULL == state->specifics.tcp_udp.heap_node)
2111 {
2112 state->specifics.tcp_udp.ri.remote_address.af = af;
2113 state->specifics.tcp_udp.ri.remote_address.proto = IPPROTO_ICMPV6;
2114 setup_state_record (state);
2115 }
2116 /* check that ICMP type is something we want to support
2117 and possibly make up payload! */
2118 switch (msg->icmp_header.type)
2119 {
2120 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
2121 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2122 break;
2123
2124 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2125 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2126 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2127 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2128 if (0 != pkt_len)
2129 {
2130 GNUNET_break_op (0);
2131 return;
2132 }
2133 /* make up payload */
2134 {
2135 struct GNUNET_TUN_IPv6Header *ipp = (struct
2136 GNUNET_TUN_IPv6Header *) buf;
2137 struct GNUNET_TUN_UdpHeader *udp = (struct
2138 GNUNET_TUN_UdpHeader *) &ipp[1];
2139
2140 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_UdpHeader));
2141 pkt_len = sizeof(struct GNUNET_TUN_IPv6Header) + 8;
2142 make_up_icmpv6_payload (state,
2143 ipp,
2144 udp);
2145 payload = ipp;
2146 }
2147 break;
2148
2149 default:
2150 GNUNET_break_op (0);
2151 GNUNET_STATISTICS_update (stats,
2152 gettext_noop (
2153 "# ICMPv6 packets dropped (type not allowed)"),
2154 1, GNUNET_NO);
2155 return;
2156 }
2157 /* end AF_INET6 */
2158 break;
2159
2160 default:
2161 /* bad AF */
2162 GNUNET_break_op (0);
2163 return;
2164 }
2165
2166 {
2167 char buf[INET6_ADDRSTRLEN];
2168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2169 "Received ICMP data from %s for forwarding to %s\n",
2170 GNUNET_i2s (&state->peer),
2171 inet_ntop (af,
2172 &state->specifics.tcp_udp.ri.remote_address.address,
2173 buf, sizeof(buf)));
2174 }
2175 send_icmp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address,
2176 &state->specifics.tcp_udp.ri.local_address,
2177 &msg->icmp_header,
2178 payload, pkt_len);
2179 GNUNET_CADET_receive_done (state->channel);
2180}
2181
2182
2183/**
2184 * Setup ICMP payload for ICMP error messages. Called
2185 * for both IPv4 and IPv6 addresses.
2186 *
2187 * @param state context for creating the IP Packet
2188 * @param buf where to create the payload, has at least
2189 * sizeof (struct GNUNET_TUN_IPv6Header) + 8 bytes
2190 * @return number of bytes of payload we created in buf
2191 */
2192static uint16_t
2193make_up_icmp_service_payload (struct ChannelState *state,
2194 char *buf)
2195{
2196 switch (state->specifics.tcp_udp.serv->address.af)
2197 {
2198 case AF_INET:
2199 {
2200 struct GNUNET_TUN_IPv4Header *ipv4;
2201 struct GNUNET_TUN_UdpHeader *udp;
2202
2203 ipv4 = (struct GNUNET_TUN_IPv4Header *) buf;
2204 udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2205 make_up_icmpv4_payload (state,
2206 ipv4,
2207 udp);
2208 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_UdpHeader));
2209 return sizeof(struct GNUNET_TUN_IPv4Header) + 8;
2210 }
2211 break;
2212
2213 case AF_INET6:
2214 {
2215 struct GNUNET_TUN_IPv6Header *ipv6;
2216 struct GNUNET_TUN_UdpHeader *udp;
2217
2218 ipv6 = (struct GNUNET_TUN_IPv6Header *) buf;
2219 udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2220 make_up_icmpv6_payload (state,
2221 ipv6,
2222 udp);
2223 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_UdpHeader));
2224 return sizeof(struct GNUNET_TUN_IPv6Header) + 8;
2225 }
2226 break;
2227
2228 default:
2229 GNUNET_break (0);
2230 }
2231 return 0;
2232}
2233
2234
2235/**
2236 * Check a request via cadet to send ICMP data to a service
2237 * offered by this system.
2238 *
2239 * @param cls our `struct ChannelState *`
2240 * @param msg the actual message
2241 * @return #GNUNET_OK to keep the connection open,
2242 * #GNUNET_SYSERR to close it (signal serious error)
2243 */
2244static int
2245check_icmp_service (void *cls,
2246 const struct GNUNET_EXIT_IcmpServiceMessage *msg)
2247{
2248 struct ChannelState *state = cls;
2249
2250 if (GNUNET_YES == state->is_dns)
2251 {
2252 GNUNET_break_op (0);
2253 return GNUNET_SYSERR;
2254 }
2255 if (NULL == state->specifics.tcp_udp.serv)
2256 {
2257 GNUNET_break_op (0);
2258 return GNUNET_SYSERR;
2259 }
2260 return GNUNET_OK;
2261}
2262
2263
2264/**
2265 * Process a request via cadet to send ICMP data to a service
2266 * offered by this system.
2267 *
2268 * @param cls our `struct ChannelState *`
2269 * @param msg the actual message
2270 */
2271static void
2272handle_icmp_service (void *cls,
2273 const struct GNUNET_EXIT_IcmpServiceMessage *msg)
2274{
2275 struct ChannelState *state = cls;
2276 uint16_t pkt_len = ntohs (msg->header.size) - sizeof(struct
2277 GNUNET_EXIT_IcmpServiceMessage);
2278 struct GNUNET_TUN_IcmpHeader icmp;
2279 char buf[sizeof(struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
2280 const void *payload;
2281
2282 GNUNET_STATISTICS_update (stats,
2283 gettext_noop ("# Bytes received from CADET"),
2284 pkt_len, GNUNET_NO);
2285 GNUNET_STATISTICS_update (stats,
2286 gettext_noop (
2287 "# ICMP service requests received via cadet"),
2288 1, GNUNET_NO);
2289 /* check that we got at least a valid header */
2290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2291 "Received data from %s for forwarding to ICMP service %s\n",
2292 GNUNET_i2s (&state->peer),
2293 GNUNET_h2s (&state->specifics.tcp_udp.serv->descriptor));
2294 icmp = msg->icmp_header;
2295 payload = &msg[1];
2296 state->specifics.tcp_udp.ri.remote_address
2297 = state->specifics.tcp_udp.serv->address;
2298 setup_state_record (state);
2299
2300 /* check that ICMP type is something we want to support,
2301 perform ICMP PT if needed and possibly make up payload */
2302 switch (msg->af)
2303 {
2304 case AF_INET:
2305 switch (msg->icmp_header.type)
2306 {
2307 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
2308 if (state->specifics.tcp_udp.serv->address.af == AF_INET6)
2309 icmp.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
2310 break;
2311
2312 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
2313 if (state->specifics.tcp_udp.serv->address.af == AF_INET6)
2314 icmp.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
2315 break;
2316
2317 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
2318 if (state->specifics.tcp_udp.serv->address.af == AF_INET6)
2319 icmp.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
2320 if (0 != pkt_len)
2321 {
2322 GNUNET_break_op (0);
2323 return;
2324 }
2325 payload = buf;
2326 pkt_len = make_up_icmp_service_payload (state, buf);
2327 break;
2328
2329 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
2330 if (state->specifics.tcp_udp.serv->address.af == AF_INET6)
2331 icmp.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
2332 if (0 != pkt_len)
2333 {
2334 GNUNET_break_op (0);
2335 return;
2336 }
2337 payload = buf;
2338 pkt_len = make_up_icmp_service_payload (state, buf);
2339 break;
2340
2341 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2342 if (state->specifics.tcp_udp.serv->address.af == AF_INET6)
2343 {
2344 GNUNET_STATISTICS_update (stats,
2345 gettext_noop (
2346 "# ICMPv4 packets dropped (impossible PT to v6)"),
2347 1, GNUNET_NO);
2348 return;
2349 }
2350 if (0 != pkt_len)
2351 {
2352 GNUNET_break_op (0);
2353 return;
2354 }
2355 payload = buf;
2356 pkt_len = make_up_icmp_service_payload (state, buf);
2357 break;
2358
2359 default:
2360 GNUNET_break_op (0);
2361 GNUNET_STATISTICS_update (stats,
2362 gettext_noop (
2363 "# ICMPv4 packets dropped (type not allowed)"),
2364 1, GNUNET_NO);
2365 return;
2366 }
2367 /* end of AF_INET */
2368 break;
2369
2370 case AF_INET6:
2371 switch (msg->icmp_header.type)
2372 {
2373 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
2374 if (state->specifics.tcp_udp.serv->address.af == AF_INET)
2375 icmp.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
2376 break;
2377
2378 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2379 if (state->specifics.tcp_udp.serv->address.af == AF_INET)
2380 icmp.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
2381 break;
2382
2383 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2384 if (state->specifics.tcp_udp.serv->address.af == AF_INET)
2385 icmp.type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
2386 if (0 != pkt_len)
2387 {
2388 GNUNET_break_op (0);
2389 return;
2390 }
2391 payload = buf;
2392 pkt_len = make_up_icmp_service_payload (state, buf);
2393 break;
2394
2395 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2396 if (state->specifics.tcp_udp.serv->address.af == AF_INET)
2397 icmp.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
2398 if (0 != pkt_len)
2399 {
2400 GNUNET_break_op (0);
2401 return;
2402 }
2403 payload = buf;
2404 pkt_len = make_up_icmp_service_payload (state, buf);
2405 break;
2406
2407 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2408 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2409 if (state->specifics.tcp_udp.serv->address.af == AF_INET)
2410 {
2411 GNUNET_STATISTICS_update (stats,
2412 gettext_noop (
2413 "# ICMPv6 packets dropped (impossible PT to v4)"),
2414 1, GNUNET_NO);
2415 return;
2416 }
2417 if (0 != pkt_len)
2418 {
2419 GNUNET_break_op (0);
2420 return;
2421 }
2422 payload = buf;
2423 pkt_len = make_up_icmp_service_payload (state, buf);
2424 break;
2425
2426 default:
2427 GNUNET_break_op (0);
2428 GNUNET_STATISTICS_update (stats,
2429 gettext_noop (
2430 "# ICMPv6 packets dropped (type not allowed)"),
2431 1, GNUNET_NO);
2432 return;
2433 }
2434 /* end of AF_INET6 */
2435 break;
2436
2437 default:
2438 GNUNET_break_op (0);
2439 return;
2440 }
2441
2442 send_icmp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address,
2443 &state->specifics.tcp_udp.ri.local_address,
2444 &icmp,
2445 payload,
2446 pkt_len);
2447 GNUNET_CADET_receive_done (state->channel);
2448}
2449
2450
2451/**
2452 * Free memory associated with a service record.
2453 *
2454 * @param cls unused
2455 * @param key service descriptor
2456 * @param value service record to free
2457 * @return #GNUNET_OK
2458 */
2459static int
2460free_service_record (void *cls,
2461 const struct GNUNET_HashCode *key,
2462 void *value)
2463{
2464 struct LocalService *service = value;
2465
2466 GNUNET_assert (GNUNET_YES ==
2467 GNUNET_CONTAINER_multihashmap_remove (services,
2468 key,
2469 service));
2470 GNUNET_CADET_close_port (service->port);
2471 GNUNET_free (service->name);
2472 GNUNET_free (service);
2473 return GNUNET_OK;
2474}
2475
2476
2477/**
2478 * Callback from CADET for new channels.
2479 *
2480 * @param cls closure
2481 * @param channel new handle to the channel
2482 * @param initiator peer that started the channel
2483 * @return initial channel context for the channel
2484 */
2485static void *
2486new_service_channel (void *cls,
2487 struct GNUNET_CADET_Channel *channel,
2488 const struct GNUNET_PeerIdentity *initiator)
2489{
2490 struct LocalService *ls = cls;
2491 struct ChannelState *s = GNUNET_new (struct ChannelState);
2492
2493 s->peer = *initiator;
2494 GNUNET_STATISTICS_update (stats,
2495 gettext_noop ("# Inbound CADET channels created"),
2496 1,
2497 GNUNET_NO);
2498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2499 "Received inbound channel from `%s'\n",
2500 GNUNET_i2s (initiator));
2501 s->channel = channel;
2502 s->specifics.tcp_udp.serv = ls;
2503 s->specifics.tcp_udp.ri.remote_address = ls->address;
2504 return s;
2505}
2506
2507
2508/**
2509 * Function called by cadet whenever an inbound channel is destroyed.
2510 * Should clean up any associated state.
2511 *
2512 * @param cls our `struct ChannelState *`
2513 * @param channel connection to the other end (henceforth invalid)
2514 */
2515static void
2516clean_channel (void *cls,
2517 const struct GNUNET_CADET_Channel *channel)
2518{
2519 struct ChannelState *s = cls;
2520
2521 LOG (GNUNET_ERROR_TYPE_DEBUG,
2522 "Channel destroyed\n");
2523 if (GNUNET_SYSERR == s->is_dns)
2524 {
2525 GNUNET_free (s);
2526 return;
2527 }
2528 if (GNUNET_YES == s->is_dns)
2529 {
2530 if (channels[s->specifics.dns.my_id] == s)
2531 channels[s->specifics.dns.my_id] = NULL;
2532 }
2533 else
2534 {
2535 if (NULL != s->specifics.tcp_udp.heap_node)
2536 {
2537 GNUNET_assert (GNUNET_YES ==
2538 GNUNET_CONTAINER_multihashmap_remove (connections_map,
2539 &s->specifics.tcp_udp
2540 .state_key,
2541 s));
2542 GNUNET_CONTAINER_heap_remove_node (s->specifics.tcp_udp.heap_node);
2543 s->specifics.tcp_udp.heap_node = NULL;
2544 }
2545 }
2546 GNUNET_free (s);
2547}
2548
2549
2550/**
2551 * Given a service descriptor and a destination port, find the
2552 * respective service entry.
2553 *
2554 * @param proto IPPROTO_TCP or IPPROTO_UDP
2555 * @param name name of the service
2556 * @param destination_port destination port
2557 * @param service service information record to store (service->name will be set).
2558 */
2559static void
2560store_service (int proto,
2561 const char *name,
2562 uint16_t destination_port,
2563 struct LocalService *service)
2564{
2565 struct GNUNET_MQ_MessageHandler handlers[] = {
2566 GNUNET_MQ_hd_var_size (icmp_service,
2567 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE,
2568 struct GNUNET_EXIT_IcmpServiceMessage,
2569 service),
2570 GNUNET_MQ_hd_var_size (udp_service,
2571 GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE,
2572 struct GNUNET_EXIT_UdpServiceMessage,
2573 service),
2574 GNUNET_MQ_hd_var_size (tcp_service,
2575 GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START,
2576 struct GNUNET_EXIT_TcpServiceStartMessage,
2577 service),
2578 GNUNET_MQ_hd_var_size (tcp_data,
2579 GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT,
2580 struct GNUNET_EXIT_TcpDataMessage,
2581 service),
2582 GNUNET_MQ_handler_end ()
2583 };
2584
2585 struct GNUNET_HashCode cadet_port;
2586
2587 service->name = GNUNET_strdup (name);
2588 GNUNET_TUN_service_name_to_hash (name,
2589 &service->descriptor);
2590 GNUNET_TUN_compute_service_cadet_port (&service->descriptor,
2591 destination_port,
2592 &cadet_port);
2593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2594 "Opening CADET port %s for SERVICE exit %s on port %u\n",
2595 GNUNET_h2s (&cadet_port),
2596 name,
2597 (unsigned int) destination_port);
2598 service->port = GNUNET_CADET_open_port (cadet_handle,
2599 &cadet_port,
2600 &new_service_channel,
2601 service,
2602 NULL,
2603 &clean_channel,
2604 handlers);
2605 service->is_udp = (IPPROTO_UDP == proto);
2606 if (GNUNET_OK !=
2607 GNUNET_CONTAINER_multihashmap_put (services,
2608 &cadet_port,
2609 service,
2610 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
2611 {
2612 GNUNET_CADET_close_port (service->port);
2613 GNUNET_free (service->name);
2614 GNUNET_free (service);
2615 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2616 _ ("Got duplicate service records for `%s:%u'\n"),
2617 name,
2618 (unsigned int) destination_port);
2619 }
2620}
2621
2622
2623/**
2624 * Send the given packet via the cadet channel.
2625 *
2626 * @param s channel destination
2627 * @param env message to queue
2628 */
2629static void
2630send_packet_to_cadet_channel (struct ChannelState *s,
2631 struct GNUNET_MQ_Envelope *env)
2632{
2633 GNUNET_assert (NULL != s);
2634 GNUNET_STATISTICS_update (stats,
2635 gettext_noop (
2636 "# Messages transmitted via cadet channels"),
2637 1,
2638 GNUNET_NO);
2639 GNUNET_MQ_send (GNUNET_CADET_get_mq (s->channel),
2640 env);
2641}
2642
2643
2644/**
2645 * @brief Handles an ICMP packet received from the helper.
2646 *
2647 * @param icmp A pointer to the Packet
2648 * @param pktlen number of bytes in @a icmp
2649 * @param af address family (AFINET or AF_INET6)
2650 * @param destination_ip destination IP-address of the IP packet (should
2651 * be our local address)
2652 * @param source_ip original source IP-address of the IP packet (should
2653 * be the original destination address)
2654 */
2655static void
2656icmp_from_helper (const struct GNUNET_TUN_IcmpHeader *icmp,
2657 size_t pktlen,
2658 int af,
2659 const void *destination_ip,
2660 const void *source_ip)
2661{
2662 struct ChannelState *state;
2663 struct GNUNET_MQ_Envelope *env;
2664 struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
2665 const struct GNUNET_TUN_IPv4Header *ipv4;
2666 const struct GNUNET_TUN_IPv6Header *ipv6;
2667 const struct GNUNET_TUN_UdpHeader *udp;
2668 uint16_t source_port;
2669 uint16_t destination_port;
2670 uint8_t protocol;
2671
2672 {
2673 char sbuf[INET6_ADDRSTRLEN];
2674 char dbuf[INET6_ADDRSTRLEN];
2675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2676 "Received ICMP packet going from %s to %s\n",
2677 inet_ntop (af,
2678 source_ip,
2679 sbuf, sizeof(sbuf)),
2680 inet_ntop (af,
2681 destination_ip,
2682 dbuf, sizeof(dbuf)));
2683 }
2684
2685 if (pktlen < sizeof(struct GNUNET_TUN_IcmpHeader))
2686 {
2687 /* blame kernel */
2688 GNUNET_break (0);
2689 return;
2690 }
2691
2692 /* Find out if this is an ICMP packet in response to an existing
2693 TCP/UDP packet and if so, figure out ports / protocol of the
2694 existing session from the IP data in the ICMP payload */
2695 source_port = 0;
2696 destination_port = 0;
2697 switch (af)
2698 {
2699 case AF_INET:
2700 protocol = IPPROTO_ICMP;
2701 switch (icmp->type)
2702 {
2703 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
2704 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
2705 break;
2706
2707 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
2708 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2709 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
2710 if (pktlen <
2711 sizeof(struct GNUNET_TUN_IcmpHeader)
2712 + sizeof(struct GNUNET_TUN_IPv4Header) + 8)
2713 {
2714 /* blame kernel */
2715 GNUNET_break (0);
2716 return;
2717 }
2718 ipv4 = (const struct GNUNET_TUN_IPv4Header *) &icmp[1];
2719 protocol = ipv4->protocol;
2720 /* could be TCP or UDP, but both have the ports in the right
2721 place, so that doesn't matter here */
2722 udp = (const struct GNUNET_TUN_UdpHeader *) &ipv4[1];
2723 /* swap ports, as they are from the original message */
2724 destination_port = ntohs (udp->source_port);
2725 source_port = ntohs (udp->destination_port);
2726 /* throw away ICMP payload, won't be useful for the other side anyway */
2727 pktlen = sizeof(struct GNUNET_TUN_IcmpHeader);
2728 break;
2729
2730 default:
2731 GNUNET_STATISTICS_update (stats,
2732 gettext_noop (
2733 "# ICMPv4 packets dropped (type not allowed)"),
2734 1, GNUNET_NO);
2735 return;
2736 }
2737 break;
2738
2739 case AF_INET6:
2740 protocol = IPPROTO_ICMPV6;
2741 switch (icmp->type)
2742 {
2743 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2744 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2745 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2746 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2747 if (pktlen <
2748 sizeof(struct GNUNET_TUN_IcmpHeader)
2749 + sizeof(struct GNUNET_TUN_IPv6Header) + 8)
2750 {
2751 /* blame kernel */
2752 GNUNET_break (0);
2753 return;
2754 }
2755 ipv6 = (const struct GNUNET_TUN_IPv6Header *) &icmp[1];
2756 protocol = ipv6->next_header;
2757 /* could be TCP or UDP, but both have the ports in the right
2758 place, so that doesn't matter here */
2759 udp = (const struct GNUNET_TUN_UdpHeader *) &ipv6[1];
2760 /* swap ports, as they are from the original message */
2761 destination_port = ntohs (udp->source_port);
2762 source_port = ntohs (udp->destination_port);
2763 /* throw away ICMP payload, won't be useful for the other side anyway */
2764 pktlen = sizeof(struct GNUNET_TUN_IcmpHeader);
2765 break;
2766
2767 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2768 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
2769 break;
2770
2771 default:
2772 GNUNET_STATISTICS_update (stats,
2773 gettext_noop (
2774 "# ICMPv6 packets dropped (type not allowed)"),
2775 1, GNUNET_NO);
2776 return;
2777 }
2778 break;
2779
2780 default:
2781 GNUNET_assert (0);
2782 }
2783 switch (protocol)
2784 {
2785 case IPPROTO_ICMP:
2786 state = get_redirect_state (af,
2787 IPPROTO_ICMP,
2788 source_ip,
2789 0,
2790 destination_ip,
2791 0,
2792 NULL);
2793 break;
2794
2795 case IPPROTO_ICMPV6:
2796 state = get_redirect_state (af,
2797 IPPROTO_ICMPV6,
2798 source_ip,
2799 0,
2800 destination_ip,
2801 0,
2802 NULL);
2803 break;
2804
2805 case IPPROTO_UDP:
2806 state = get_redirect_state (af,
2807 IPPROTO_UDP,
2808 source_ip,
2809 source_port,
2810 destination_ip,
2811 destination_port,
2812 NULL);
2813 break;
2814
2815 case IPPROTO_TCP:
2816 state = get_redirect_state (af,
2817 IPPROTO_TCP,
2818 source_ip,
2819 source_port,
2820 destination_ip,
2821 destination_port,
2822 NULL);
2823 break;
2824
2825 default:
2826 GNUNET_STATISTICS_update (stats,
2827 gettext_noop (
2828 "# ICMP packets dropped (not allowed)"),
2829 1,
2830 GNUNET_NO);
2831 return;
2832 }
2833 if (NULL == state)
2834 {
2835 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2836 _ (
2837 "ICMP Packet dropped, have no matching connection information\n"));
2838 return;
2839 }
2840 env = GNUNET_MQ_msg_extra (i2v,
2841 pktlen - sizeof(struct GNUNET_TUN_IcmpHeader),
2842 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN);
2843 i2v->af = htonl (af);
2844 GNUNET_memcpy (&i2v->icmp_header,
2845 icmp,
2846 pktlen);
2847 send_packet_to_cadet_channel (state,
2848 env);
2849}
2850
2851
2852/**
2853 * @brief Handles an UDP packet received from the helper.
2854 *
2855 * @param udp A pointer to the Packet
2856 * @param pktlen number of bytes in 'udp'
2857 * @param af address family (AFINET or AF_INET6)
2858 * @param destination_ip destination IP-address of the IP packet (should
2859 * be our local address)
2860 * @param source_ip original source IP-address of the IP packet (should
2861 * be the original destination address)
2862 */
2863static void
2864udp_from_helper (const struct GNUNET_TUN_UdpHeader *udp,
2865 size_t pktlen,
2866 int af,
2867 const void *destination_ip,
2868 const void *source_ip)
2869{
2870 struct ChannelState *state;
2871 struct GNUNET_MQ_Envelope *env;
2872 struct GNUNET_EXIT_UdpReplyMessage *urm;
2873
2874 {
2875 char sbuf[INET6_ADDRSTRLEN];
2876 char dbuf[INET6_ADDRSTRLEN];
2877
2878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2879 "Received UDP packet going from %s:%u to %s:%u\n",
2880 inet_ntop (af,
2881 source_ip,
2882 sbuf, sizeof(sbuf)),
2883 (unsigned int) ntohs (udp->source_port),
2884 inet_ntop (af,
2885 destination_ip,
2886 dbuf, sizeof(dbuf)),
2887 (unsigned int) ntohs (udp->destination_port));
2888 }
2889
2890 if (pktlen < sizeof(struct GNUNET_TUN_UdpHeader))
2891 {
2892 /* blame kernel */
2893 GNUNET_break (0);
2894 return;
2895 }
2896 if (pktlen != ntohs (udp->len))
2897 {
2898 /* blame kernel */
2899 GNUNET_break (0);
2900 return;
2901 }
2902 state = get_redirect_state (af,
2903 IPPROTO_UDP,
2904 source_ip,
2905 ntohs (udp->source_port),
2906 destination_ip,
2907 ntohs (udp->destination_port),
2908 NULL);
2909 if (NULL == state)
2910 {
2911 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2912 _ (
2913 "UDP Packet dropped, have no matching connection information\n"));
2914 return;
2915 }
2916 env = GNUNET_MQ_msg_extra (urm,
2917 pktlen - sizeof(struct GNUNET_TUN_UdpHeader),
2918 GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY);
2919 urm->source_port = htons (0);
2920 urm->destination_port = htons (0);
2921 GNUNET_memcpy (&urm[1],
2922 &udp[1],
2923 pktlen - sizeof(struct GNUNET_TUN_UdpHeader));
2924 send_packet_to_cadet_channel (state,
2925 env);
2926}
2927
2928
2929/**
2930 * @brief Handles a TCP packet received from the helper.
2931 *
2932 * @param tcp A pointer to the Packet
2933 * @param pktlen the length of the packet, including its TCP header
2934 * @param af address family (AFINET or AF_INET6)
2935 * @param destination_ip destination IP-address of the IP packet (should
2936 * be our local address)
2937 * @param source_ip original source IP-address of the IP packet (should
2938 * be the original destination address)
2939 */
2940static void
2941tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp,
2942 size_t pktlen,
2943 int af,
2944 const void *destination_ip,
2945 const void *source_ip)
2946{
2947 struct ChannelState *state;
2948 char buf[pktlen] GNUNET_ALIGN;
2949 struct GNUNET_TUN_TcpHeader *mtcp;
2950 struct GNUNET_EXIT_TcpDataMessage *tdm;
2951 struct GNUNET_MQ_Envelope *env;
2952 size_t mlen;
2953
2954 {
2955 char sbuf[INET6_ADDRSTRLEN];
2956 char dbuf[INET6_ADDRSTRLEN];
2957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2958 "Received TCP packet with %u bytes going from %s:%u to %s:%u\n",
2959 (unsigned int) (pktlen - sizeof(struct GNUNET_TUN_TcpHeader)),
2960 inet_ntop (af,
2961 source_ip,
2962 sbuf, sizeof(sbuf)),
2963 (unsigned int) ntohs (tcp->source_port),
2964 inet_ntop (af,
2965 destination_ip,
2966 dbuf, sizeof(dbuf)),
2967 (unsigned int) ntohs (tcp->destination_port));
2968 }
2969
2970 if (pktlen < sizeof(struct GNUNET_TUN_TcpHeader))
2971 {
2972 /* blame kernel */
2973 GNUNET_break (0);
2974 return;
2975 }
2976 state = get_redirect_state (af,
2977 IPPROTO_TCP,
2978 source_ip,
2979 ntohs (tcp->source_port),
2980 destination_ip,
2981 ntohs (tcp->destination_port),
2982 NULL);
2983 if (NULL == state)
2984 {
2985 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2986 _ (
2987 "TCP Packet dropped, have no matching connection information\n"));
2988
2989 return;
2990 }
2991 /* mug port numbers and crc to avoid information leakage;
2992 sender will need to lookup the correct values anyway */
2993 GNUNET_memcpy (buf, tcp, pktlen);
2994 mtcp = (struct GNUNET_TUN_TcpHeader *) buf;
2995 mtcp->source_port = 0;
2996 mtcp->destination_port = 0;
2997 mtcp->crc = 0;
2998
2999 mlen = sizeof(struct GNUNET_EXIT_TcpDataMessage) + (pktlen - sizeof(struct
3000 GNUNET_TUN_TcpHeader));
3001 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
3002 {
3003 GNUNET_break (0);
3004 return;
3005 }
3006 env = GNUNET_MQ_msg_extra (tdm,
3007 pktlen - sizeof(struct GNUNET_TUN_TcpHeader),
3008 GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN);
3009 tdm->reserved = htonl (0);
3010 GNUNET_memcpy (&tdm->tcp_header,
3011 buf,
3012 pktlen);
3013 send_packet_to_cadet_channel (state,
3014 env);
3015}
3016
3017
3018/**
3019 * Receive packets from the helper-process
3020 *
3021 * @param cls unused
3022 * @param message message received from helper
3023 */
3024static int
3025message_token (void *cls GNUNET_UNUSED,
3026 const struct GNUNET_MessageHeader *message)
3027{
3028 const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun;
3029 size_t size;
3030
3031 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3032 "Got %u-byte message of type %u from gnunet-helper-exit\n",
3033 ntohs (message->size),
3034 ntohs (message->type));
3035 GNUNET_STATISTICS_update (stats,
3036 gettext_noop ("# Packets received from TUN"),
3037 1, GNUNET_NO);
3038 if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
3039 {
3040 GNUNET_break (0);
3041 return GNUNET_OK;
3042 }
3043 size = ntohs (message->size);
3044 if (size < sizeof(struct GNUNET_TUN_Layer2PacketHeader) + sizeof(struct
3045 GNUNET_MessageHeader))
3046 {
3047 GNUNET_break (0);
3048 return GNUNET_OK;
3049 }
3050 GNUNET_STATISTICS_update (stats,
3051 gettext_noop ("# Bytes received from TUN"),
3052 size, GNUNET_NO);
3053 pkt_tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
3054 size -= sizeof(struct GNUNET_TUN_Layer2PacketHeader) + sizeof(struct
3055 GNUNET_MessageHeader);
3056 switch (ntohs (pkt_tun->proto))
3057 {
3058 case ETH_P_IPV4:
3059 {
3060 const struct GNUNET_TUN_IPv4Header *pkt4;
3061
3062 if (size < sizeof(struct GNUNET_TUN_IPv4Header))
3063 {
3064 /* Kernel to blame? */
3065 GNUNET_break (0);
3066 return GNUNET_OK;
3067 }
3068 pkt4 = (const struct GNUNET_TUN_IPv4Header *) &pkt_tun[1];
3069 if (size != ntohs (pkt4->total_length))
3070 {
3071 /* Kernel to blame? */
3072 GNUNET_break (0);
3073 return GNUNET_OK;
3074 }
3075 if (pkt4->header_length * 4 != sizeof(struct GNUNET_TUN_IPv4Header))
3076 {
3077 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3078 _ ("IPv4 packet options received. Ignored.\n"));
3079 return GNUNET_OK;
3080 }
3081
3082 size -= sizeof(struct GNUNET_TUN_IPv4Header);
3083 switch (pkt4->protocol)
3084 {
3085 case IPPROTO_UDP:
3086 udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt4[1], size,
3087 AF_INET,
3088 &pkt4->destination_address,
3089 &pkt4->source_address);
3090 break;
3091
3092 case IPPROTO_TCP:
3093 tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt4[1], size,
3094 AF_INET,
3095 &pkt4->destination_address,
3096 &pkt4->source_address);
3097 break;
3098
3099 case IPPROTO_ICMP:
3100 icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt4[1], size,
3101 AF_INET,
3102 &pkt4->destination_address,
3103 &pkt4->source_address);
3104 break;
3105
3106 default:
3107 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3108 _ (
3109 "IPv4 packet with unsupported next header %u received. Ignored.\n"),
3110 (int) pkt4->protocol);
3111 return GNUNET_OK;
3112 }
3113 }
3114 break;
3115
3116 case ETH_P_IPV6:
3117 {
3118 const struct GNUNET_TUN_IPv6Header *pkt6;
3119
3120 if (size < sizeof(struct GNUNET_TUN_IPv6Header))
3121 {
3122 /* Kernel to blame? */
3123 GNUNET_break (0);
3124 return GNUNET_OK;
3125 }
3126 pkt6 = (struct GNUNET_TUN_IPv6Header *) &pkt_tun[1];
3127 if (size != ntohs (pkt6->payload_length) + sizeof(struct
3128 GNUNET_TUN_IPv6Header))
3129 {
3130 /* Kernel to blame? */
3131 GNUNET_break (0);
3132 return GNUNET_OK;
3133 }
3134 size -= sizeof(struct GNUNET_TUN_IPv6Header);
3135 switch (pkt6->next_header)
3136 {
3137 case IPPROTO_UDP:
3138 udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt6[1], size,
3139 AF_INET6,
3140 &pkt6->destination_address,
3141 &pkt6->source_address);
3142 break;
3143
3144 case IPPROTO_TCP:
3145 tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt6[1], size,
3146 AF_INET6,
3147 &pkt6->destination_address,
3148 &pkt6->source_address);
3149 break;
3150
3151 case IPPROTO_ICMPV6:
3152 icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt6[1], size,
3153 AF_INET6,
3154 &pkt6->destination_address,
3155 &pkt6->source_address);
3156 break;
3157
3158 default:
3159 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3160 _ (
3161 "IPv6 packet with unsupported next header %d received. Ignored.\n"),
3162 pkt6->next_header);
3163 return GNUNET_OK;
3164 }
3165 }
3166 break;
3167
3168 default:
3169 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3170 _ ("Packet from unknown protocol %u received. Ignored.\n"),
3171 ntohs (pkt_tun->proto));
3172 break;
3173 }
3174 return GNUNET_OK;
3175}
3176
3177
3178/**
3179 * Callback from CADET for new channels.
3180 *
3181 * @param cls closure
3182 * @param channel new handle to the channel
3183 * @param initiator peer that started the channel
3184 * @return initial channel context for the channel
3185 */
3186static void *
3187new_channel (void *cls,
3188 struct GNUNET_CADET_Channel *channel,
3189 const struct GNUNET_PeerIdentity *initiator)
3190{
3191 struct ChannelState *s = GNUNET_new (struct ChannelState);
3192
3193 s->is_dns = GNUNET_SYSERR;
3194 s->peer = *initiator;
3195 GNUNET_STATISTICS_update (stats,
3196 gettext_noop ("# Inbound CADET channels created"),
3197 1,
3198 GNUNET_NO);
3199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3200 "Received inbound channel from `%s'\n",
3201 GNUNET_i2s (initiator));
3202 s->channel = channel;
3203 return s;
3204}
3205
3206
3207/**
3208 * Function that frees everything from a hashmap
3209 *
3210 * @param cls unused
3211 * @param hash key
3212 * @param value value to free
3213 */
3214static int
3215free_iterate (void *cls,
3216 const struct GNUNET_HashCode *hash,
3217 void *value)
3218{
3219 GNUNET_free (value);
3220 return GNUNET_YES;
3221}
3222
3223
3224/**
3225 * Function scheduled as very last function if the service
3226 * disabled itself because the helper is not installed
3227 * properly. Does nothing, except for keeping the
3228 * service process alive by virtue of being scheduled.
3229 *
3230 * @param cls NULL
3231 */
3232static void
3233dummy_task (void *cls)
3234{
3235 /* just terminate */
3236}
3237
3238
3239/**
3240 * Function scheduled as very last function, cleans up after us
3241 *
3242 * @param cls NULL
3243 */
3244static void
3245cleanup (void *cls)
3246{
3247 unsigned int i;
3248
3249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3250 "Exit service is shutting down now\n");
3251
3252 if (NULL != helper_handle)
3253 {
3254 GNUNET_HELPER_stop (helper_handle, GNUNET_NO);
3255 helper_handle = NULL;
3256 }
3257 if (NULL != regex4)
3258 {
3259 GNUNET_REGEX_announce_cancel (regex4);
3260 regex4 = NULL;
3261 }
3262 if (NULL != regex6)
3263 {
3264 GNUNET_REGEX_announce_cancel (regex6);
3265 regex6 = NULL;
3266 }
3267 if (NULL != services)
3268 {
3269 GNUNET_CONTAINER_multihashmap_iterate (services,
3270 &free_service_record,
3271 NULL);
3272 GNUNET_CONTAINER_multihashmap_destroy (services);
3273 }
3274 if (NULL != dns_port)
3275 {
3276 GNUNET_CADET_close_port (dns_port);
3277 dns_port = NULL;
3278 }
3279 if (NULL != cadet_port4)
3280 {
3281 GNUNET_CADET_close_port (cadet_port4);
3282 cadet_port4 = NULL;
3283 }
3284 if (NULL != cadet_port6)
3285 {
3286 GNUNET_CADET_close_port (cadet_port6);
3287 cadet_port6 = NULL;
3288 }
3289 if (NULL != cadet_handle)
3290 {
3291 GNUNET_CADET_disconnect (cadet_handle);
3292 cadet_handle = NULL;
3293 }
3294 if (NULL != connections_map)
3295 {
3296 GNUNET_CONTAINER_multihashmap_iterate (connections_map,
3297 &free_iterate,
3298 NULL);
3299 GNUNET_CONTAINER_multihashmap_destroy (connections_map);
3300 connections_map = NULL;
3301 }
3302 if (NULL != connections_heap)
3303 {
3304 GNUNET_CONTAINER_heap_destroy (connections_heap);
3305 connections_heap = NULL;
3306 }
3307 if (NULL != dnsstub)
3308 {
3309 GNUNET_DNSSTUB_stop (dnsstub);
3310 dnsstub = NULL;
3311 }
3312 if (NULL != peer_key)
3313 {
3314 GNUNET_free (peer_key);
3315 peer_key = NULL;
3316 }
3317 if (NULL != dht_task)
3318 {
3319 GNUNET_SCHEDULER_cancel (dht_task);
3320 dht_task = NULL;
3321 }
3322 if (NULL != dht_put)
3323 {
3324 GNUNET_DHT_put_cancel (dht_put);
3325 dht_put = NULL;
3326 }
3327 if (NULL != dht)
3328 {
3329 GNUNET_DHT_disconnect (dht);
3330 dht = NULL;
3331 }
3332 if (NULL != stats)
3333 {
3334 GNUNET_STATISTICS_destroy (stats,
3335 GNUNET_NO);
3336 stats = NULL;
3337 }
3338 for (i = 0; i < 8; i++)
3339 GNUNET_free (exit_argv[i]);
3340}
3341
3342
3343/**
3344 * Add services to the service map.
3345 *
3346 * @param proto IPPROTO_TCP or IPPROTO_UDP
3347 * @param cpy copy of the service descriptor (can be mutilated)
3348 * @param name DNS name of the service
3349 */
3350static void
3351add_services (int proto,
3352 char *cpy,
3353 const char *name)
3354{
3355 char *redirect;
3356 char *hostname;
3357 char *hostport;
3358 struct LocalService *serv;
3359 char *n;
3360 size_t slen;
3361
3362 slen = strlen (name);
3363 GNUNET_assert (slen >= 8);
3364 n = GNUNET_strndup (name, slen - 8 /* remove .gnunet. */);
3365
3366 for (redirect = strtok (cpy, " ;"); redirect != NULL;
3367 redirect = strtok (NULL, " ;"))
3368 {
3369 if (NULL == (hostname = strstr (redirect, ":")))
3370 {
3371 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3372 _ (
3373 "Option `%s' for domain `%s' is not formatted correctly!\n"),
3374 redirect,
3375 name);
3376 continue;
3377 }
3378 hostname[0] = '\0';
3379 hostname++;
3380 if (NULL == (hostport = strstr (hostname, ":")))
3381 {
3382 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3383 _ (
3384 "Option `%s' for domain `%s' is not formatted correctly!\n"),
3385 redirect,
3386 name);
3387 continue;
3388 }
3389 hostport[0] = '\0';
3390 hostport++;
3391
3392 int local_port = atoi (redirect);
3393 int remote_port = atoi (hostport);
3394
3395 if (! ((local_port > 0) && (local_port < 65536)))
3396 {
3397 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3398 _ ("`%s' is not a valid port number (for domain `%s')!"),
3399 redirect,
3400 name);
3401 continue;
3402 }
3403 if (! ((remote_port > 0) && (remote_port < 65536)))
3404 {
3405 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3406 _ ("`%s' is not a valid port number (for domain `%s')!"),
3407 hostport,
3408 name);
3409 continue;
3410 }
3411
3412 serv = GNUNET_new (struct LocalService);
3413 serv->address.proto = proto;
3414 serv->address.port = remote_port;
3415 if (0 == strcmp ("localhost4",
3416 hostname))
3417 {
3418 const char *ip4addr = exit_argv[5];
3419
3420 serv->address.af = AF_INET;
3421 GNUNET_assert (1 == inet_pton (AF_INET,
3422 ip4addr,
3423 &serv->address.address.ipv4));
3424 }
3425 else if (0 == strcmp ("localhost6",
3426 hostname))
3427 {
3428 const char *ip6addr = exit_argv[3];
3429
3430 serv->address.af = AF_INET6;
3431 GNUNET_assert (1 == inet_pton (AF_INET6,
3432 ip6addr,
3433 &serv->address.address.ipv6));
3434 }
3435 else
3436 {
3437 struct addrinfo *res;
3438 int ret;
3439
3440 ret = getaddrinfo (hostname,
3441 NULL,
3442 NULL,
3443 &res);
3444 if ((0 != ret) || (NULL == res))
3445 {
3446 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3447 _ (
3448 "No addresses found for hostname `%s' of service `%s'!\n"),
3449 hostname,
3450 n);
3451 GNUNET_free (serv);
3452 continue;
3453 }
3454
3455 serv->address.af = res->ai_family;
3456 switch (res->ai_family)
3457 {
3458 case AF_INET:
3459 if (! ipv4_enabled)
3460 {
3461 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3462 _ (
3463 "Service `%s' configured for IPv4, but IPv4 is disabled!\n"),
3464 n);
3465 freeaddrinfo (res);
3466 GNUNET_free (serv);
3467 continue;
3468 }
3469 serv->address.address.ipv4
3470 = ((struct sockaddr_in *) res->ai_addr)->sin_addr;
3471 break;
3472
3473 case AF_INET6:
3474 if (! ipv6_enabled)
3475 {
3476 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3477 _ (
3478 "Service `%s' configured for IPv4, but IPv4 is disabled!\n"),
3479 n);
3480 freeaddrinfo (res);
3481 GNUNET_free (serv);
3482 continue;
3483 }
3484 serv->address.address.ipv6
3485 = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
3486 break;
3487
3488 default:
3489 freeaddrinfo (res);
3490 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3491 _ (
3492 "No IP addresses found for hostname `%s' of service `%s'!\n"),
3493 hostname,
3494 n);
3495 GNUNET_free (serv);
3496 continue;
3497 }
3498 freeaddrinfo (res);
3499 }
3500 store_service (proto,
3501 n,
3502 local_port,
3503 serv);
3504 }
3505 GNUNET_free (n);
3506}
3507
3508
3509/**
3510 * Reads the configuration and populates #udp_services and #tcp_services
3511 *
3512 * @param cls unused
3513 * @param section name of section in config
3514 */
3515static void
3516read_service_conf (void *cls,
3517 const char *section)
3518{
3519 char *cpy;
3520
3521 if ((strlen (section) < 8) ||
3522 (0 != strcmp (".gnunet.", section + (strlen (section) - 8))))
3523 return;
3524 if (GNUNET_OK ==
3525 GNUNET_CONFIGURATION_get_value_string (cfg,
3526 section,
3527 "UDP_REDIRECTS",
3528 &cpy))
3529 {
3530 add_services (IPPROTO_UDP,
3531 cpy,
3532 section);
3533 GNUNET_free (cpy);
3534 }
3535 if (GNUNET_OK ==
3536 GNUNET_CONFIGURATION_get_value_string (cfg,
3537 section,
3538 "TCP_REDIRECTS",
3539 &cpy))
3540 {
3541 add_services (IPPROTO_TCP,
3542 cpy,
3543 section);
3544 GNUNET_free (cpy);
3545 }
3546}
3547
3548
3549/**
3550 * We are running a DNS exit service, advertise it in the
3551 * DHT. This task is run periodically to do the DHT PUT.
3552 *
3553 * @param cls closure
3554 */
3555static void
3556do_dht_put (void *cls);
3557
3558
3559/**
3560 * Function called when the DHT PUT operation is complete.
3561 * Schedules the next PUT.
3562 *
3563 * @param cls closure, NULL
3564 */
3565static void
3566dht_put_cont (void *cls)
3567{
3568 dht_put = NULL;
3569}
3570
3571
3572/**
3573 * We are running a DNS exit service, advertise it in the
3574 * DHT. This task is run periodically to do the DHT PUT.
3575 *
3576 * @param cls closure
3577 */
3578static void
3579do_dht_put (void *cls)
3580{
3581 struct GNUNET_TIME_Absolute expiration;
3582
3583 dht_task = GNUNET_SCHEDULER_add_delayed (DHT_PUT_FREQUENCY,
3584 &do_dht_put,
3585 NULL);
3586 expiration = GNUNET_TIME_absolute_ntoh (dns_advertisement.expiration_time);
3587 if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value_us <
3588 GNUNET_TIME_UNIT_HOURS.rel_value_us)
3589 {
3590 /* refresh advertisement */
3591 expiration = GNUNET_TIME_relative_to_absolute (DNS_ADVERTISEMENT_TIMEOUT);
3592 dns_advertisement.expiration_time = GNUNET_TIME_absolute_hton (expiration);
3593 GNUNET_assert (GNUNET_OK ==
3594 GNUNET_CRYPTO_eddsa_sign_ (peer_key,
3595 &dns_advertisement.purpose,
3596 &dns_advertisement.signature));
3597 }
3598 if (NULL != dht_put)
3599 GNUNET_DHT_put_cancel (dht_put);
3600 dht_put = GNUNET_DHT_put (dht,
3601 &dht_put_key,
3602 1 /* replication */,
3603 GNUNET_DHT_RO_NONE,
3604 GNUNET_BLOCK_TYPE_DNS,
3605 sizeof(struct GNUNET_DNS_Advertisement),
3606 &dns_advertisement,
3607 expiration,
3608 &dht_put_cont,
3609 NULL);
3610}
3611
3612
3613/**
3614 * Figure out which IP versions we should support (and which
3615 * are supported by the OS) according to our configuration.
3616 */
3617static void
3618parse_ip_options ()
3619{
3620 ipv4_exit = GNUNET_CONFIGURATION_get_value_yesno (cfg,
3621 "exit",
3622 "EXIT_IPV4");
3623 ipv6_exit = GNUNET_CONFIGURATION_get_value_yesno (cfg,
3624 "exit",
3625 "EXIT_IPV6");
3626 ipv4_enabled = GNUNET_CONFIGURATION_get_value_yesno (cfg,
3627 "exit",
3628 "ENABLE_IPV4");
3629 ipv6_enabled = GNUNET_CONFIGURATION_get_value_yesno (cfg,
3630 "exit",
3631 "ENABLE_IPV6");
3632 if ((ipv4_exit || ipv4_enabled) &&
3633 (GNUNET_OK != GNUNET_NETWORK_test_pf (PF_INET)) )
3634 {
3635 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3636 _ (
3637 "This system does not support IPv4, will disable IPv4 functions despite them being enabled in the configuration\n"));
3638 ipv4_exit = GNUNET_NO;
3639 ipv4_enabled = GNUNET_NO;
3640 }
3641 if ((ipv6_exit || ipv6_enabled) &&
3642 (GNUNET_OK != GNUNET_NETWORK_test_pf (PF_INET6)) )
3643 {
3644 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3645 _ (
3646 "This system does not support IPv6, will disable IPv6 functions despite them being enabled in the configuration\n"));
3647 ipv6_exit = GNUNET_NO;
3648 ipv6_enabled = GNUNET_NO;
3649 }
3650 if (ipv4_exit && (! ipv4_enabled))
3651 {
3652 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3653 _ (
3654 "Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use ENABLE_IPv4=YES\n"));
3655 ipv4_enabled = GNUNET_YES;
3656 }
3657 if (ipv6_exit && (! ipv6_enabled))
3658 {
3659 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3660 _ (
3661 "Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use ENABLE_IPv6=YES\n"));
3662 ipv6_enabled = GNUNET_YES;
3663 }
3664}
3665
3666
3667/**
3668 * Helper function to open the CADET port for DNS exits and to
3669 * advertise the DNS exit (if applicable).
3670 */
3671static void
3672advertise_dns_exit ()
3673{
3674 struct GNUNET_MQ_MessageHandler handlers[] = {
3675 GNUNET_MQ_hd_var_size (dns_request,
3676 GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET,
3677 struct DnsResponseMessage,
3678 NULL),
3679 GNUNET_MQ_handler_end ()
3680 };
3681 char *dns_exit;
3682 struct GNUNET_HashCode port;
3683
3684 if (GNUNET_YES !=
3685 GNUNET_CONFIGURATION_get_value_yesno (cfg,
3686 "exit",
3687 "EXIT_DNS"))
3688 return;
3689 GNUNET_assert (NULL != (dnsstub = GNUNET_DNSSTUB_start (128)));
3690 dns_exit = NULL;
3691 /* TODO: support using multiple DNS resolvers */
3692 if ((GNUNET_OK !=
3693 GNUNET_CONFIGURATION_get_value_string (cfg,
3694 "exit",
3695 "DNS_RESOLVER",
3696 &dns_exit)) ||
3697 (GNUNET_OK !=
3698 GNUNET_DNSSTUB_add_dns_ip (dnsstub,
3699 dns_exit)))
3700 {
3701 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3702 "dns",
3703 "DNS_RESOLVER",
3704 _ ("need a valid IPv4 or IPv6 address\n"));
3705 GNUNET_free (dns_exit);
3706 return;
3707 }
3708 /* open port */
3709 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER,
3710 strlen (GNUNET_APPLICATION_PORT_INTERNET_RESOLVER),
3711 &port);
3712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3713 "Opening CADET port %s for DNS exit service\n",
3714 GNUNET_h2s (&port));
3715 dns_port = GNUNET_CADET_open_port (cadet_handle,
3716 &port,
3717 &new_channel,
3718 NULL,
3719 NULL,
3720 &clean_channel,
3721 handlers);
3722 /* advertise exit */
3723 dht = GNUNET_DHT_connect (cfg,
3724 1);
3725 peer_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
3726 GNUNET_CRYPTO_eddsa_key_get_public (peer_key,
3727 &dns_advertisement.peer.public_key);
3728 dns_advertisement.purpose.size = htonl (sizeof(struct
3729 GNUNET_DNS_Advertisement)
3730 - sizeof(struct
3731 GNUNET_CRYPTO_EddsaSignature));
3732 dns_advertisement.purpose.purpose = htonl (
3733 GNUNET_SIGNATURE_PURPOSE_DNS_RECORD);
3734 GNUNET_CRYPTO_hash ("dns",
3735 strlen ("dns"),
3736 &dht_put_key);
3737 dht_task = GNUNET_SCHEDULER_add_now (&do_dht_put,
3738 NULL);
3739 GNUNET_free (dns_exit);
3740}
3741
3742
3743/**
3744 * Initialize #exit_argv.
3745 *
3746 * @return #GNUNET_OK on success, #GNUNET_SYSERR if we should shutdown
3747 */
3748static int
3749setup_exit_helper_args ()
3750{
3751 char *exit_ifname;
3752 char *tun_ifname;
3753 char *ipv6addr;
3754 char *ipv6prefix_s;
3755 char *ipv4addr;
3756 char *ipv4mask;
3757
3758 exit_argv[0] = GNUNET_strdup ("exit-gnunet");
3759 if (GNUNET_SYSERR ==
3760 GNUNET_CONFIGURATION_get_value_string (cfg,
3761 "exit",
3762 "TUN_IFNAME",
3763 &tun_ifname))
3764 {
3765 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3766 "EXIT",
3767 "TUN_IFNAME");
3768 return GNUNET_SYSERR;
3769 }
3770 exit_argv[1] = tun_ifname;
3771 if (ipv4_enabled)
3772 {
3773 if (GNUNET_SYSERR ==
3774 GNUNET_CONFIGURATION_get_value_string (cfg,
3775 "exit",
3776 "EXIT_IFNAME",
3777 &exit_ifname))
3778 {
3779 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3780 "EXIT",
3781 "EXIT_IFNAME");
3782 return GNUNET_SYSERR;
3783 }
3784 exit_argv[2] = exit_ifname;
3785 }
3786 else
3787 {
3788 exit_argv[2] = GNUNET_strdup ("-");
3789 }
3790
3791 if (GNUNET_YES == ipv6_enabled)
3792 {
3793 ipv6addr = NULL;
3794 if (((GNUNET_SYSERR ==
3795 GNUNET_CONFIGURATION_get_value_string (cfg,
3796 "exit",
3797 "IPV6ADDR",
3798 &ipv6addr)) ||
3799 (1 != inet_pton (AF_INET6,
3800 ipv6addr,
3801 &exit_ipv6addr))))
3802 {
3803 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3804 "EXIT",
3805 "IPV6ADDR");
3806 GNUNET_free (ipv6addr);
3807 return GNUNET_SYSERR;
3808 }
3809 exit_argv[3] = ipv6addr;
3810 if (GNUNET_SYSERR ==
3811 GNUNET_CONFIGURATION_get_value_string (cfg,
3812 "exit",
3813 "IPV6PREFIX",
3814 &ipv6prefix_s))
3815 {
3816 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3817 "EXIT",
3818 "IPV6PREFIX");
3819 return GNUNET_SYSERR;
3820 }
3821 exit_argv[4] = ipv6prefix_s;
3822 if ((GNUNET_OK !=
3823 GNUNET_CONFIGURATION_get_value_number (cfg,
3824 "exit",
3825 "IPV6PREFIX",
3826 &ipv6prefix)) ||
3827 (ipv6prefix >= 127))
3828 {
3829 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3830 "EXIT",
3831 "IPV6PREFIX",
3832 _ ("Must be a number"));
3833 return GNUNET_SYSERR;
3834 }
3835 }
3836 else
3837 {
3838 /* IPv6 explicitly disabled */
3839 exit_argv[3] = GNUNET_strdup ("-");
3840 exit_argv[4] = GNUNET_strdup ("-");
3841 }
3842 if (GNUNET_YES == ipv4_enabled)
3843 {
3844 ipv4addr = NULL;
3845 if (((GNUNET_SYSERR ==
3846 GNUNET_CONFIGURATION_get_value_string (cfg,
3847 "exit",
3848 "IPV4ADDR",
3849 &ipv4addr)) ||
3850 (1 != inet_pton (AF_INET,
3851 ipv4addr,
3852 &exit_ipv4addr))))
3853 {
3854 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3855 "EXIT",
3856 "IPV4ADDR");
3857 GNUNET_free (ipv4addr);
3858 return GNUNET_SYSERR;
3859 }
3860 exit_argv[5] = ipv4addr;
3861 ipv4mask = NULL;
3862 if (((GNUNET_SYSERR ==
3863 GNUNET_CONFIGURATION_get_value_string (cfg,
3864 "exit",
3865 "IPV4MASK",
3866 &ipv4mask)) ||
3867 (1 != inet_pton (AF_INET,
3868 ipv4mask,
3869 &exit_ipv4mask))))
3870 {
3871 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3872 "EXIT",
3873 "IPV4MASK");
3874 GNUNET_free (ipv4mask);
3875 return GNUNET_SYSERR;
3876 }
3877 exit_argv[6] = ipv4mask;
3878 }
3879 else
3880 {
3881 /* IPv4 explicitly disabled */
3882 exit_argv[5] = GNUNET_strdup ("-");
3883 exit_argv[6] = GNUNET_strdup ("-");
3884 }
3885 exit_argv[7] = NULL;
3886 return GNUNET_OK;
3887}
3888
3889
3890/**
3891 * @brief Main function that will be run by the scheduler.
3892 *
3893 * @param cls closure
3894 * @param args remaining command-line arguments
3895 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
3896 * @param cfg_ configuration
3897 */
3898static void
3899run (void *cls,
3900 char *const *args,
3901 const char *cfgfile,
3902 const struct GNUNET_CONFIGURATION_Handle *cfg_)
3903{
3904 struct GNUNET_MQ_MessageHandler handlers[] = {
3905 GNUNET_MQ_hd_var_size (icmp_remote,
3906 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET,
3907 struct GNUNET_EXIT_IcmpInternetMessage,
3908 NULL),
3909 GNUNET_MQ_hd_var_size (udp_remote,
3910 GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET,
3911 struct GNUNET_EXIT_UdpInternetMessage,
3912 NULL),
3913 GNUNET_MQ_hd_var_size (tcp_remote,
3914 GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START,
3915 struct GNUNET_EXIT_TcpInternetStartMessage,
3916 NULL),
3917 GNUNET_MQ_hd_var_size (tcp_data,
3918 GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT,
3919 struct GNUNET_EXIT_TcpDataMessage,
3920 NULL),
3921 GNUNET_MQ_handler_end ()
3922 };
3923 struct GNUNET_HashCode port;
3924 char *policy;
3925 char *binary;
3926 char *regex;
3927 char *prefixed_regex;
3928
3929 cfg = cfg_;
3930 if (GNUNET_OK !=
3931 GNUNET_CONFIGURATION_get_value_number (cfg,
3932 "exit",
3933 "MAX_CONNECTIONS",
3934 &max_connections))
3935 max_connections = 1024;
3936 parse_ip_options ();
3937 binary = GNUNET_OS_get_suid_binary_path (cfg, "gnunet-helper-exit");
3938 if ((ipv4_exit) || (ipv6_exit))
3939 {
3940 if (GNUNET_YES !=
3941 GNUNET_OS_check_helper_binary (binary,
3942 GNUNET_YES,
3943 "gnunet-vpn - - - 169.1.3.7 255.255.255.0")) // no nat, ipv4 only
3944 {
3945 GNUNET_free (binary);
3946 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3947 _ (
3948 "`%s' is not SUID or the path is invalid, EXIT will not work\n"),
3949 "gnunet-helper-exit");
3950 GNUNET_SCHEDULER_add_shutdown (&dummy_task,
3951 NULL);
3952 global_ret = 1;
3953 return;
3954 }
3955 }
3956 if (! (ipv4_enabled || ipv6_enabled))
3957 {
3958 GNUNET_free (binary);
3959 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3960 _ ("No useful service enabled. Exiting.\n"));
3961 GNUNET_SCHEDULER_shutdown ();
3962 return;
3963 }
3964
3965 GNUNET_SCHEDULER_add_shutdown (&cleanup,
3966 NULL);
3967 stats = GNUNET_STATISTICS_create ("exit",
3968 cfg);
3969 cadet_handle = GNUNET_CADET_connect (cfg);
3970 if (NULL == cadet_handle)
3971 {
3972 GNUNET_free (binary);
3973 GNUNET_SCHEDULER_shutdown ();
3974 return;
3975 }
3976 advertise_dns_exit ();
3977 if (GNUNET_OK !=
3978 setup_exit_helper_args ())
3979 {
3980 GNUNET_free (binary);
3981 GNUNET_SCHEDULER_shutdown ();
3982 return;
3983 }
3984
3985 services = GNUNET_CONTAINER_multihashmap_create (65536,
3986 GNUNET_NO);
3987 connections_map = GNUNET_CONTAINER_multihashmap_create (65536,
3988 GNUNET_NO);
3989 connections_heap = GNUNET_CONTAINER_heap_create (
3990 GNUNET_CONTAINER_HEAP_ORDER_MIN);
3991 GNUNET_CONFIGURATION_iterate_sections (cfg,
3992 &read_service_conf,
3993 NULL);
3994
3995 /* Cadet handle acquired, now open ports and announce regular
3996 expressions matching our exit */
3997 if ((GNUNET_YES == ipv4_enabled) &&
3998 (GNUNET_YES == ipv4_exit))
3999 {
4000 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV4_GATEWAY,
4001 strlen (GNUNET_APPLICATION_PORT_IPV4_GATEWAY),
4002 &port);
4003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4004 "Opening CADET port %s for IPv4 gateway service\n",
4005 GNUNET_h2s (&port));
4006 cadet_port4 = GNUNET_CADET_open_port (cadet_handle,
4007 &port,
4008 &new_channel,
4009 NULL,
4010 NULL,
4011 &clean_channel,
4012 handlers);
4013 policy = NULL;
4014 if (GNUNET_OK !=
4015 GNUNET_CONFIGURATION_get_value_string (cfg,
4016 "exit",
4017 "EXIT_RANGE_IPV4_POLICY",
4018 &policy))
4019 regex = NULL;
4020 else
4021 regex = GNUNET_TUN_ipv4policy2regex (policy);
4022 GNUNET_free (policy);
4023 if (NULL != regex)
4024 {
4025 (void) GNUNET_asprintf (&prefixed_regex,
4026 "%s%s",
4027 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
4028 regex);
4029 regex4 = GNUNET_REGEX_announce (cfg,
4030 prefixed_regex,
4031 REGEX_REFRESH_FREQUENCY,
4032 REGEX_MAX_PATH_LEN_IPV4);
4033 GNUNET_free (regex);
4034 GNUNET_free (prefixed_regex);
4035 }
4036 }
4037
4038 if ((GNUNET_YES == ipv6_enabled) && (GNUNET_YES == ipv6_exit))
4039 {
4040 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV6_GATEWAY,
4041 strlen (GNUNET_APPLICATION_PORT_IPV6_GATEWAY),
4042 &port);
4043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4044 "Opening CADET port %s for IPv6 gateway service\n",
4045 GNUNET_h2s (&port));
4046 cadet_port6 = GNUNET_CADET_open_port (cadet_handle,
4047 &port,
4048 &new_channel,
4049 NULL,
4050 NULL,
4051 &clean_channel,
4052 handlers);
4053 policy = NULL;
4054 if (GNUNET_OK !=
4055 GNUNET_CONFIGURATION_get_value_string (cfg,
4056 "exit",
4057 "EXIT_RANGE_IPV6_POLICY",
4058 &policy))
4059 regex = NULL;
4060 else
4061 regex = GNUNET_TUN_ipv6policy2regex (policy);
4062 GNUNET_free (policy);
4063 if (NULL != regex)
4064 {
4065 (void) GNUNET_asprintf (&prefixed_regex,
4066 "%s%s",
4067 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
4068 regex);
4069 regex6 = GNUNET_REGEX_announce (cfg,
4070 prefixed_regex,
4071 REGEX_REFRESH_FREQUENCY,
4072 REGEX_MAX_PATH_LEN_IPV6);
4073 GNUNET_free (regex);
4074 GNUNET_free (prefixed_regex);
4075 }
4076 }
4077 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
4078 binary,
4079 exit_argv,
4080 &message_token,
4081 NULL,
4082 NULL);
4083 GNUNET_free (binary);
4084}
4085
4086
4087/**
4088 * The main function
4089 *
4090 * @param argc number of arguments from the command line
4091 * @param argv command line arguments
4092 * @return 0 ok, 1 on error
4093 */
4094int
4095main (int argc,
4096 char *const *argv)
4097{
4098 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
4099 GNUNET_GETOPT_OPTION_END
4100 };
4101
4102 if (GNUNET_OK !=
4103 GNUNET_STRINGS_get_utf8_args (argc,
4104 argv,
4105 &argc,
4106 &argv))
4107 return 2;
4108
4109 return (GNUNET_OK ==
4110 GNUNET_PROGRAM_run (argc,
4111 argv,
4112 "gnunet-daemon-exit",
4113 gettext_noop (
4114 "Daemon to run to provide an IP exit node for the VPN"),
4115 options,
4116 &run,
4117 NULL)) ? global_ret : 1;
4118}
4119
4120
4121/* end of gnunet-daemon-exit.c */
diff --git a/src/service/exit/gnunet-helper-exit.c b/src/service/exit/gnunet-helper-exit.c
new file mode 100644
index 000000000..d9578cfa0
--- /dev/null
+++ b/src/service/exit/gnunet-helper-exit.c
@@ -0,0 +1,859 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012 Christian Grothoff
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 exit/gnunet-helper-exit.c
23 *
24 * @brief the helper for exit nodes. Opens a virtual
25 * network-interface, sends data received on the if to stdout, sends
26 * data received on stdin to the interface. The code also enables
27 * IPv4/IPv6 forwarding and NAT on the current system (the latter on
28 * an interface specified on the command-line); these changes to the
29 * network configuration are NOT automatically undone when the program
30 * is stopped (this is because we cannot be sure that some other
31 * application didn't enable them before or after us; also, these
32 * changes should be mostly harmless as it simply turns the system
33 * into a router).
34 *
35 * @author Philipp Tölke
36 * @author Christian Grothoff
37 *
38 * The following list of people have reviewed this code and considered
39 * it safe since the last modification (if you reviewed it, please
40 * have your name added to the list):
41 *
42 * - Philipp Tölke
43 */
44#include "platform.h"
45
46#ifdef IF_TUN_HDR
47#include IF_TUN_HDR
48#endif
49
50#if defined(BSD) || defined(SOLARIS)
51#define ifr_netmask ifr_ifru.ifru_addr
52#define SIOGIFINDEX SIOCGIFINDEX
53#endif
54
55/**
56 * Need 'struct GNUNET_MessageHeader'.
57 */
58#include "gnunet_util_lib.h"
59#include "gnunet_common.h"
60
61/**
62 * Need VPN message types.
63 */
64#include "gnunet_protocols.h"
65
66/**
67 * Should we print (interesting|debug) messages that can happen during
68 * normal operation?
69 */
70#define DEBUG GNUNET_NO
71
72/**
73 * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
74 */
75#define MAX_SIZE 65536
76
77/**
78 * Path to 'sysctl' binary.
79 */
80static const char *sbin_sysctl;
81
82/**
83 * Path to 'iptables' binary.
84 */
85static const char *sbin_iptables;
86
87
88#if ! defined(__ANDROID__)
89#if ! defined(_LINUX_IN6_H) && defined(__linux__)
90/**
91 * This is in linux/include/net/ipv6.h, but not always exported.
92 */
93struct in6_ifreq
94{
95 struct in6_addr ifr6_addr;
96 uint32_t ifr6_prefixlen; /* __u32 in the original */
97 int ifr6_ifindex;
98};
99#endif
100#endif
101
102
103/**
104 * Open '/dev/null' and make the result the given
105 * file descriptor.
106 *
107 * @param target_fd desired FD to point to /dev/null
108 * @param flags open flags (O_RDONLY, O_WRONLY)
109 */
110static void
111open_dev_null (int target_fd,
112 int flags)
113{
114 int fd;
115
116 fd = open ("/dev/null", flags);
117 if (-1 == fd)
118 abort ();
119 if (fd == target_fd)
120 return;
121 if (-1 == dup2 (fd, target_fd))
122 {
123 (void) close (fd);
124 abort ();
125 }
126 (void) close (fd);
127}
128
129
130/**
131 * Run the given command and wait for it to complete.
132 *
133 * @param file name of the binary to run
134 * @param cmd command line arguments (as given to 'execv')
135 * @return 0 on success, 1 on any error
136 */
137static int
138fork_and_exec (const char *file,
139 char *const cmd[])
140{
141 int status;
142 pid_t pid;
143 pid_t ret;
144
145 pid = fork ();
146 if (-1 == pid)
147 {
148 fprintf (stderr,
149 "fork failed: %s\n",
150 strerror (errno));
151 return 1;
152 }
153 if (0 == pid)
154 {
155 /* we are the child process */
156 /* close stdin/stdout to not cause interference
157 with the helper's main protocol! */
158 (void) close (0);
159 open_dev_null (0, O_RDONLY);
160 (void) close (1);
161 open_dev_null (1, O_WRONLY);
162 (void) execv (file, cmd);
163 /* can only get here on error */
164 fprintf (stderr,
165 "exec `%s' failed: %s\n",
166 file,
167 strerror (errno));
168 _exit (1);
169 }
170 /* keep running waitpid as long as the only error we get is 'EINTR' */
171 while ((-1 == (ret = waitpid (pid, &status, 0))) &&
172 (errno == EINTR))
173 ;
174 if (-1 == ret)
175 {
176 fprintf (stderr,
177 "waitpid failed: %s\n",
178 strerror (errno));
179 return 1;
180 }
181 if (! (WIFEXITED (status) && (0 == WEXITSTATUS (status))))
182 return 1;
183 /* child process completed and returned success, we're happy */
184 return 0;
185}
186
187
188/**
189 * Creates a tun-interface called dev;
190 *
191 * @param dev is assumed to point to a char[IFNAMSIZ]
192 * if *dev == '\\0', uses the name supplied by the kernel;
193 * @return the fd to the tun or -1 on error
194 */
195#ifdef IFF_TUN /* LINUX */
196static int
197init_tun (char *dev)
198{
199 struct ifreq ifr;
200 int fd;
201
202 if (NULL == dev)
203 {
204 errno = EINVAL;
205 return -1;
206 }
207
208 if (-1 == (fd = open ("/dev/net/tun", O_RDWR)))
209 {
210 fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun",
211 strerror (errno));
212 return -1;
213 }
214
215 if (fd >= FD_SETSIZE)
216 {
217 fprintf (stderr, "File descriptor to large: %d", fd);
218 (void) close (fd);
219 return -1;
220 }
221
222 memset (&ifr, 0, sizeof(ifr));
223 ifr.ifr_flags = IFF_TUN;
224
225 if ('\0' != *dev)
226 strncpy (ifr.ifr_name, dev, IFNAMSIZ);
227
228 if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr))
229 {
230 fprintf (stderr,
231 "Error with ioctl on `%s': %s\n", "/dev/net/tun",
232 strerror (errno));
233 (void) close (fd);
234 return -1;
235 }
236 strcpy (dev, ifr.ifr_name);
237 return fd;
238}
239
240
241#else /* BSD et al, including DARWIN */
242
243#ifdef SIOCIFCREATE
244static int
245init_tun (char *dev)
246{
247 int fd;
248 int s;
249 struct ifreq ifr;
250
251 fd = open (dev, O_RDWR);
252 if (fd == -1)
253 {
254 s = socket (AF_INET, SOCK_DGRAM, 0);
255 if (s < 0)
256 return -1;
257 memset (&ifr, 0, sizeof(ifr));
258 strncpy (ifr.ifr_name, dev + 5, sizeof(ifr.ifr_name) - 1);
259 if (! ioctl (s, SIOCIFCREATE, &ifr))
260 fd = open (dev, O_RDWR);
261 close (s);
262 }
263 return fd;
264}
265
266
267#else
268#define init_tun(dev) open (dev, O_RDWR)
269#endif
270#endif /* !IFF_TUN (BSD) */
271
272/**
273 * @brief Sets the IPv6-Address given in address on the interface dev
274 *
275 * @param dev the interface to configure
276 * @param address the IPv6-Address
277 * @param prefix_len the length of the network-prefix
278 */
279static void
280set_address6 (const char *dev, const char *address, unsigned long prefix_len)
281{
282 struct ifreq ifr;
283 struct sockaddr_in6 sa6;
284 int fd;
285 struct in6_ifreq ifr6;
286
287 /*
288 * parse the new address
289 */
290 memset (&sa6, 0, sizeof(struct sockaddr_in6));
291 sa6.sin6_family = AF_INET6;
292 if (1 != inet_pton (AF_INET6, address, &sa6.sin6_addr))
293 {
294 fprintf (stderr, "Failed to parse address `%s': %s\n", address,
295 strerror (errno));
296 exit (1);
297 }
298
299 if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0)))
300 {
301 fprintf (stderr, "Error creating socket: %s\n", strerror (errno));
302 exit (1);
303 }
304
305 memset (&ifr, 0, sizeof(struct ifreq));
306 /*
307 * Get the index of the if
308 */
309 strncpy (ifr.ifr_name, dev, IFNAMSIZ);
310 if (-1 == ioctl (fd, SIOGIFINDEX, &ifr))
311 {
312 fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno));
313 (void) close (fd);
314 exit (1);
315 }
316
317 memset (&ifr6, 0, sizeof(struct in6_ifreq));
318 ifr6.ifr6_addr = sa6.sin6_addr;
319 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
320 ifr6.ifr6_prefixlen = prefix_len;
321
322 /*
323 * Set the address
324 */
325 if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6))
326 {
327 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
328 strerror (errno));
329 (void) close (fd);
330 exit (1);
331 }
332
333 /*
334 * Get the flags
335 */
336 if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
337 {
338 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
339 strerror (errno));
340 (void) close (fd);
341 exit (1);
342 }
343
344 /*
345 * Add the UP and RUNNING flags
346 */
347 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
348 if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
349 {
350 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
351 strerror (errno));
352 (void) close (fd);
353 exit (1);
354 }
355
356 if (0 != close (fd))
357 {
358 fprintf (stderr, "close failed: %s\n", strerror (errno));
359 exit (1);
360 }
361}
362
363
364/**
365 * @brief Sets the IPv4-Address given in address on the interface dev
366 *
367 * @param dev the interface to configure
368 * @param address the IPv4-Address
369 * @param mask the netmask
370 */
371static void
372set_address4 (const char *dev, const char *address, const char *mask)
373{
374 int fd;
375 struct sockaddr_in *addr;
376 struct ifreq ifr;
377
378 memset (&ifr, 0, sizeof(struct ifreq));
379 addr = (struct sockaddr_in *) &(ifr.ifr_addr);
380 addr->sin_family = AF_INET;
381
382 /*
383 * Parse the address
384 */
385 if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr))
386 {
387 fprintf (stderr, "Failed to parse address `%s': %s\n", address,
388 strerror (errno));
389 exit (1);
390 }
391
392 if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0)))
393 {
394 fprintf (stderr, "Error creating socket: %s\n", strerror (errno));
395 exit (1);
396 }
397
398 strncpy (ifr.ifr_name, dev, IFNAMSIZ);
399
400 /*
401 * Set the address
402 */
403 if (-1 == ioctl (fd, SIOCSIFADDR, &ifr))
404 {
405 fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno));
406 (void) close (fd);
407 exit (1);
408 }
409
410 /*
411 * Parse the netmask
412 */
413 addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
414 if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr))
415 {
416 fprintf (stderr, "Failed to parse address `%s': %s\n", mask,
417 strerror (errno));
418 (void) close (fd);
419 exit (1);
420 }
421
422 /*
423 * Set the netmask
424 */
425 if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr))
426 {
427 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
428 strerror (errno));
429 (void) close (fd);
430 exit (1);
431 }
432
433 /*
434 * Get the flags
435 */
436 if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
437 {
438 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
439 strerror (errno));
440 (void) close (fd);
441 exit (1);
442 }
443
444 /*
445 * Add the UP and RUNNING flags
446 */
447 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
448 if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
449 {
450 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
451 strerror (errno));
452 (void) close (fd);
453 exit (1);
454 }
455
456 if (0 != close (fd))
457 {
458 fprintf (stderr, "close failed: %s\n", strerror (errno));
459 (void) close (fd);
460 exit (1);
461 }
462}
463
464
465/**
466 * Start forwarding to and from the tunnel.
467 *
468 * @param fd_tun tunnel FD
469 */
470static void
471run (int fd_tun)
472{
473 /*
474 * The buffer filled by reading from fd_tun
475 */
476 unsigned char buftun[MAX_SIZE];
477 ssize_t buftun_size = 0;
478 unsigned char *buftun_read = NULL;
479
480 /*
481 * The buffer filled by reading from stdin
482 */
483 unsigned char bufin[MAX_SIZE];
484 ssize_t bufin_size = 0;
485 size_t bufin_rpos = 0;
486 unsigned char *bufin_read = NULL;
487
488 fd_set fds_w;
489 fd_set fds_r;
490
491 /* read refers to reading from fd_tun, writing to stdout */
492 int read_open = 1;
493
494 /* write refers to reading from stdin, writing to fd_tun */
495 int write_open = 1;
496
497 while ((1 == read_open) && (1 == write_open))
498 {
499 FD_ZERO (&fds_w);
500 FD_ZERO (&fds_r);
501
502 /*
503 * We are supposed to read and the buffer is empty
504 * -> select on read from tun
505 */
506 if (read_open && (0 == buftun_size))
507 FD_SET (fd_tun, &fds_r);
508
509 /*
510 * We are supposed to read and the buffer is not empty
511 * -> select on write to stdout
512 */
513 if (read_open && (0 != buftun_size))
514 FD_SET (1, &fds_w);
515
516 /*
517 * We are supposed to write and the buffer is empty
518 * -> select on read from stdin
519 */
520 if (write_open && (NULL == bufin_read))
521 FD_SET (0, &fds_r);
522
523 /*
524 * We are supposed to write and the buffer is not empty
525 * -> select on write to tun
526 */
527 if (write_open && (NULL != bufin_read))
528 FD_SET (fd_tun, &fds_w);
529
530 int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
531
532 if (-1 == r)
533 {
534 if (EINTR == errno)
535 continue;
536 fprintf (stderr, "select failed: %s\n", strerror (errno));
537 exit (1);
538 }
539
540 if (r > 0)
541 {
542 if (FD_ISSET (fd_tun, &fds_r))
543 {
544 buftun_size =
545 read (fd_tun, buftun + sizeof(struct GNUNET_MessageHeader),
546 MAX_SIZE - sizeof(struct GNUNET_MessageHeader));
547 if (-1 == buftun_size)
548 {
549 fprintf (stderr,
550 "read-error: %s\n",
551 strerror (errno));
552 shutdown (fd_tun, SHUT_RD);
553 shutdown (1, SHUT_WR);
554 read_open = 0;
555 buftun_size = 0;
556 }
557 else if (0 == buftun_size)
558 {
559#if DEBUG
560 fprintf (stderr, "EOF on tun\n");
561#endif
562 shutdown (fd_tun, SHUT_RD);
563 shutdown (1, SHUT_WR);
564 read_open = 0;
565 buftun_size = 0;
566 }
567 else
568 {
569 buftun_read = buftun;
570 struct GNUNET_MessageHeader *hdr =
571 (struct GNUNET_MessageHeader *) buftun;
572 buftun_size += sizeof(struct GNUNET_MessageHeader);
573 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
574 hdr->size = htons (buftun_size);
575 }
576 }
577 else if (FD_ISSET (1, &fds_w))
578 {
579 ssize_t written = write (1, buftun_read, buftun_size);
580
581 if (-1 == written)
582 {
583#if ! DEBUG
584 if (errno != EPIPE)
585#endif
586 fprintf (stderr,
587 "write-error to stdout: %s\n",
588 strerror (errno));
589 shutdown (fd_tun, SHUT_RD);
590 shutdown (1, SHUT_WR);
591 read_open = 0;
592 buftun_size = 0;
593 }
594 else if (0 == written)
595 {
596 fprintf (stderr, "write returned 0!?\n");
597 exit (1);
598 }
599 else
600 {
601 buftun_size -= written;
602 buftun_read += written;
603 }
604 }
605
606 if (FD_ISSET (0, &fds_r))
607 {
608 bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
609 if (-1 == bufin_size)
610 {
611 fprintf (stderr, "read-error: %s\n", strerror (errno));
612 shutdown (0, SHUT_RD);
613 shutdown (fd_tun, SHUT_WR);
614 write_open = 0;
615 bufin_size = 0;
616 }
617 else if (0 == bufin_size)
618 {
619#if DEBUG
620 fprintf (stderr, "EOF on stdin\n");
621#endif
622 shutdown (0, SHUT_RD);
623 shutdown (fd_tun, SHUT_WR);
624 write_open = 0;
625 bufin_size = 0;
626 }
627 else
628 {
629 struct GNUNET_MessageHeader *hdr;
630
631PROCESS_BUFFER:
632 bufin_rpos += bufin_size;
633 if (bufin_rpos < sizeof(struct GNUNET_MessageHeader))
634 continue;
635 hdr = (struct GNUNET_MessageHeader *) bufin;
636 if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
637 {
638 fprintf (stderr, "protocol violation!\n");
639 exit (1);
640 }
641 if (ntohs (hdr->size) > bufin_rpos)
642 continue;
643 bufin_read = bufin + sizeof(struct GNUNET_MessageHeader);
644 bufin_size = ntohs (hdr->size) - sizeof(struct GNUNET_MessageHeader);
645 bufin_rpos -= bufin_size + sizeof(struct GNUNET_MessageHeader);
646 }
647 }
648 else if (FD_ISSET (fd_tun, &fds_w))
649 {
650 ssize_t written = write (fd_tun, bufin_read, bufin_size);
651
652 if (-1 == written)
653 {
654 fprintf (stderr, "write-error to tun: %s\n", strerror (errno));
655 shutdown (0, SHUT_RD);
656 shutdown (fd_tun, SHUT_WR);
657 write_open = 0;
658 bufin_size = 0;
659 }
660 else if (0 == written)
661 {
662 fprintf (stderr, "write returned 0!?\n");
663 exit (1);
664 }
665 else
666 {
667 bufin_size -= written;
668 bufin_read += written;
669 if (0 == bufin_size)
670 {
671 memmove (bufin, bufin_read, bufin_rpos);
672 bufin_read = NULL; /* start reading again */
673 bufin_size = 0;
674 goto PROCESS_BUFFER;
675 }
676 }
677 }
678 }
679 }
680}
681
682
683/**
684 * Open VPN tunnel interface.
685 *
686 * @param argc must be 6
687 * @param argv 0: binary name ("gnunet-helper-exit")
688 * 1: tunnel interface name ("gnunet-exit")
689 * 2: "physical" interface name ("eth0"), or "-" to not setup NAT
690 * and routing
691 * 3: IPv6 address ("::1"), or "-" to skip IPv6
692 * 4: IPv6 netmask length in bits ("64") [ignored if #4 is "-"]
693 * 5: IPv4 address ("1.2.3.4"), or "-" to skip IPv4
694 * 6: IPv4 netmask ("255.255.0.0") [ignored if #4 is "-"]
695 */
696int
697main (int argc, char **argv)
698{
699 char dev[IFNAMSIZ];
700 int fd_tun;
701 int global_ret;
702
703 if (7 != argc)
704 {
705 fprintf (stderr, "Fatal: must supply 6 arguments!\n");
706 return 1;
707 }
708 if ((0 == strcmp (argv[3], "-")) &&
709 (0 == strcmp (argv[5], "-")))
710 {
711 fprintf (stderr, "Fatal: disabling both IPv4 and IPv6 makes no sense.\n");
712 return 1;
713 }
714 if (0 != strcmp (argv[2], "-"))
715 {
716#ifdef IPTABLES
717 if (0 == access (IPTABLES, X_OK))
718 sbin_iptables = IPTABLES;
719 else
720#endif
721 if (0 == access ("/sbin/iptables", X_OK))
722 sbin_iptables = "/sbin/iptables";
723 else if (0 == access ("/usr/sbin/iptables", X_OK))
724 sbin_iptables = "/usr/sbin/iptables";
725 else
726 {
727 fprintf (stderr,
728 "Fatal: executable iptables not found in approved directories: %s\n",
729 strerror (errno));
730 return 1;
731 }
732#ifdef SYSCTL
733 if (0 == access (SYSCTL, X_OK))
734 sbin_sysctl = SYSCTL;
735 else
736#endif
737 if (0 == access ("/sbin/sysctl", X_OK))
738 sbin_sysctl = "/sbin/sysctl";
739 else if (0 == access ("/usr/sbin/sysctl", X_OK))
740 sbin_sysctl = "/usr/sbin/sysctl";
741 else
742 {
743 fprintf (stderr,
744 "Fatal: executable sysctl not found in approved directories: %s\n",
745 strerror (errno));
746 return 1;
747 }
748 }
749
750 strncpy (dev, argv[1], IFNAMSIZ);
751 dev[IFNAMSIZ - 1] = '\0';
752
753 if (-1 == (fd_tun = init_tun (dev)))
754 {
755 fprintf (stderr,
756 "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
757 dev,
758 argv[3],
759 argv[4],
760 argv[5],
761 argv[6]);
762 return 1;
763 }
764
765 if (0 != strcmp (argv[3], "-"))
766 {
767 {
768 const char *address = argv[3];
769 long prefix_len = atol (argv[4]);
770
771 if ((prefix_len < 1) || (prefix_len > 127))
772 {
773 fprintf (stderr, "Fatal: prefix_len out of range\n");
774 return 1;
775 }
776 set_address6 (dev, address, prefix_len);
777 }
778 if (0 != strcmp (argv[2], "-"))
779 {
780 char *const sysctl_args[] = {
781 "sysctl", "-w", "net.ipv6.conf.all.forwarding=1", NULL
782 };
783 if (0 != fork_and_exec (sbin_sysctl,
784 sysctl_args))
785 {
786 fprintf (stderr,
787 "Failed to enable IPv6 forwarding. Will continue anyway.\n");
788 }
789 }
790 }
791
792 if (0 != strcmp (argv[5], "-"))
793 {
794 {
795 const char *address = argv[5];
796 const char *mask = argv[6];
797
798 set_address4 (dev, address, mask);
799 }
800 if (0 != strcmp (argv[2], "-"))
801 {
802 {
803 char *const sysctl_args[] = {
804 "sysctl", "-w", "net.ipv4.ip_forward=1", NULL
805 };
806 if (0 != fork_and_exec (sbin_sysctl,
807 sysctl_args))
808 {
809 fprintf (stderr,
810 "Failed to enable IPv4 forwarding. Will continue anyway.\n");
811 }
812 }
813 {
814 char *const iptables_args[] = {
815 "iptables", "-t", "nat", "-A", "POSTROUTING", "-o", argv[2], "-j",
816 "MASQUERADE", NULL
817 };
818 if (0 != fork_and_exec (sbin_iptables,
819 iptables_args))
820 {
821 fprintf (stderr,
822 "Failed to enable IPv4 masquerading (NAT). Will continue anyway.\n");
823 }
824 }
825 }
826 }
827
828 uid_t uid = getuid ();
829#ifdef HAVE_SETRESUID
830 if (0 != setresuid (uid, uid, uid))
831 {
832 fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
833 global_ret = 2;
834 goto cleanup;
835 }
836#else
837 if (0 != (setuid (uid) | seteuid (uid)))
838 {
839 fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
840 global_ret = 2;
841 goto cleanup;
842 }
843#endif
844
845 if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
846 {
847 fprintf (stderr, "Failed to protect against SIGPIPE: %s\n",
848 strerror (errno));
849 /* no exit, we might as well die with SIGPIPE should it ever happen */
850 }
851 run (fd_tun);
852 global_ret = 0;
853cleanup:
854 (void) close (fd_tun);
855 return global_ret;
856}
857
858
859/* end of gnunet-helper-exit.c */
diff --git a/src/service/exit/meson.build b/src/service/exit/meson.build
new file mode 100644
index 000000000..8656986e1
--- /dev/null
+++ b/src/service/exit/meson.build
@@ -0,0 +1,25 @@
1configure_file(input : 'exit.conf',
2 output : 'exit.conf',
3 configuration : cdata,
4 install: true,
5 install_dir: pkgcfgdir)
6
7
8if host_machine.system() == 'linux'
9 executable ('gnunet-helper-exit',
10 ['gnunet-helper-exit.c'],
11 include_directories: [incdir, configuration_inc],
12 install: true,
13 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
14endif
15
16executable ('gnunet-daemon-exit',
17 ['gnunet-daemon-exit.c'],
18 dependencies: [libgnunetdht_dep,
19 libgnunetutil_dep,
20 libgnunetstatistics_dep,
21 libgnunetregex_dep,
22 libgnunetcadet_dep],
23 include_directories: [incdir, configuration_inc],
24 install: true,
25 install_dir: get_option('libdir') / 'gnunet' / 'libexec')