diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/exit/exit.conf | 12 | ||||
-rw-r--r-- | src/exit/gnunet-daemon-exit.c | 1912 | ||||
-rw-r--r-- | src/exit/gnunet-helper-exit.c | 596 | ||||
-rw-r--r-- | src/vpn/vpn.conf | 11 |
6 files changed, 2522 insertions, 11 deletions
diff --git a/configure.ac b/configure.ac index d2a6939b3..9ab15c647 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -822,6 +822,7 @@ src/datastore/Makefile | |||
822 | src/dht/Makefile | 822 | src/dht/Makefile |
823 | src/dns/Makefile | 823 | src/dns/Makefile |
824 | src/dv/Makefile | 824 | src/dv/Makefile |
825 | src/exit/Makefile | ||
825 | src/fragmentation/Makefile | 826 | src/fragmentation/Makefile |
826 | src/fs/Makefile | 827 | src/fs/Makefile |
827 | src/hello/Makefile | 828 | src/hello/Makefile |
diff --git a/src/Makefile.am b/src/Makefile.am index 6022f0733..4e1c338aa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am | |||
@@ -31,6 +31,7 @@ SUBDIRS = \ | |||
31 | fs \ | 31 | fs \ |
32 | mesh \ | 32 | mesh \ |
33 | dns \ | 33 | dns \ |
34 | exit \ | ||
34 | vpn \ | 35 | vpn \ |
35 | integration-tests \ | 36 | integration-tests \ |
36 | $(EXP_DIR) | 37 | $(EXP_DIR) |
diff --git a/src/exit/exit.conf b/src/exit/exit.conf new file mode 100644 index 000000000..83dfae888 --- /dev/null +++ b/src/exit/exit.conf | |||
@@ -0,0 +1,12 @@ | |||
1 | [exit] | ||
2 | CONFIG = $DEFAULTCONFIG | ||
3 | BINARY = gnunet-daemon-exit | ||
4 | IPV6ADDR = 1234:1::1 | ||
5 | IPV6PREFIX = 32 | ||
6 | IPV4ADDR = 10.10.1.1 | ||
7 | IPV4MASK = 255.255.0.0 | ||
8 | IFNAME = exit-gnunet | ||
9 | ENABLE_UDP = NO | ||
10 | ENABLE_TCP = NO | ||
11 | |||
12 | # MAX_CONNECTIONS = 256 | ||
diff --git a/src/exit/gnunet-daemon-exit.c b/src/exit/gnunet-daemon-exit.c new file mode 100644 index 000000000..7f502cddf --- /dev/null +++ b/src/exit/gnunet-daemon-exit.c | |||
@@ -0,0 +1,1912 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010, 2012 Christian Grothoff | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file exit/gnunet-daemon-exit.c | ||
23 | * @brief tool to allow IP traffic exit from the GNUnet mesh to the Internet | ||
24 | * @author Philipp Toelke | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include <platform.h> | ||
28 | #include <gnunet_common.h> | ||
29 | #include <gnunet_program_lib.h> | ||
30 | #include <gnunet_protocols.h> | ||
31 | #include <gnunet_applications.h> | ||
32 | #include <gnunet_mesh_service.h> | ||
33 | #include <gnunet_constants.h> | ||
34 | #include <string.h> | ||
35 | |||
36 | |||
37 | /* see http://www.iana.org/assignments/ethernet-numbers */ | ||
38 | #ifndef ETH_P_IPV4 | ||
39 | #define ETH_P_IPV4 0x0800 | ||
40 | #endif | ||
41 | |||
42 | #ifndef ETH_P_IPV6 | ||
43 | #define ETH_P_IPV6 0x86DD | ||
44 | #endif | ||
45 | |||
46 | |||
47 | GNUNET_NETWORK_STRUCT_BEGIN | ||
48 | /** | ||
49 | * Header from Linux TUN interface. | ||
50 | */ | ||
51 | struct tun_header | ||
52 | { | ||
53 | /** | ||
54 | * Some flags (unused). | ||
55 | */ | ||
56 | uint16_t flags; | ||
57 | |||
58 | /** | ||
59 | * Here we get an ETH_P_-number. | ||
60 | */ | ||
61 | uint16_t proto; | ||
62 | }; | ||
63 | |||
64 | /** | ||
65 | * Standard IPv4 header. | ||
66 | */ | ||
67 | struct ip4_header | ||
68 | { | ||
69 | unsigned header_length:4 GNUNET_PACKED; | ||
70 | unsigned version:4 GNUNET_PACKED; | ||
71 | uint8_t diff_serv; | ||
72 | uint16_t total_length GNUNET_PACKED; | ||
73 | uint16_t identification GNUNET_PACKED; | ||
74 | unsigned flags:3 GNUNET_PACKED; | ||
75 | unsigned fragmentation_offset:13 GNUNET_PACKED; | ||
76 | uint8_t ttl; | ||
77 | uint8_t protocol; | ||
78 | uint16_t checksum GNUNET_PACKED; | ||
79 | struct in_addr source_address GNUNET_PACKED; | ||
80 | struct in_addr destination_address GNUNET_PACKED; | ||
81 | }; | ||
82 | |||
83 | /** | ||
84 | * Standard IPv6 header. | ||
85 | */ | ||
86 | struct ip6_header | ||
87 | { | ||
88 | unsigned traffic_class_h:4 GNUNET_PACKED; | ||
89 | unsigned version:4 GNUNET_PACKED; | ||
90 | unsigned traffic_class_l:4 GNUNET_PACKED; | ||
91 | unsigned flow_label:20 GNUNET_PACKED; | ||
92 | uint16_t payload_length GNUNET_PACKED; | ||
93 | uint8_t next_header; | ||
94 | uint8_t hop_limit; | ||
95 | struct in6_addr source_address GNUNET_PACKED; | ||
96 | struct in6_addr destination_address GNUNET_PACKED; | ||
97 | }; | ||
98 | |||
99 | #define TCP_FLAG_SYN 2 | ||
100 | |||
101 | struct tcp_packet | ||
102 | { | ||
103 | unsigned spt:16 GNUNET_PACKED; | ||
104 | unsigned dpt:16 GNUNET_PACKED; | ||
105 | unsigned seq:32 GNUNET_PACKED; | ||
106 | unsigned ack:32 GNUNET_PACKED; | ||
107 | unsigned off:4 GNUNET_PACKED; | ||
108 | unsigned rsv:4 GNUNET_PACKED; | ||
109 | unsigned flg:8 GNUNET_PACKED; | ||
110 | unsigned wsz:16 GNUNET_PACKED; | ||
111 | unsigned crc:16 GNUNET_PACKED; | ||
112 | unsigned urg:16 GNUNET_PACKED; | ||
113 | }; | ||
114 | |||
115 | /** | ||
116 | * UDP packet header. | ||
117 | */ | ||
118 | struct udp_packet | ||
119 | { | ||
120 | uint16_t spt GNUNET_PACKED; | ||
121 | uint16_t dpt GNUNET_PACKED; | ||
122 | uint16_t len GNUNET_PACKED; | ||
123 | uint16_t crc GNUNET_PACKED; | ||
124 | }; | ||
125 | |||
126 | /** | ||
127 | * DNS header. | ||
128 | */ | ||
129 | struct dns_header | ||
130 | { | ||
131 | uint16_t id GNUNET_PACKED; | ||
132 | uint16_t flags GNUNET_PACKED; | ||
133 | uint16_t qdcount GNUNET_PACKED; | ||
134 | uint16_t ancount GNUNET_PACKED; | ||
135 | uint16_t nscount GNUNET_PACKED; | ||
136 | uint16_t arcount GNUNET_PACKED; | ||
137 | }; | ||
138 | GNUNET_NETWORK_STRUCT_END | ||
139 | |||
140 | /** | ||
141 | * Information about a remote address. | ||
142 | */ | ||
143 | struct remote_addr | ||
144 | { | ||
145 | /** | ||
146 | * AF_INET or AF_INET6. | ||
147 | */ | ||
148 | int af; | ||
149 | |||
150 | /** | ||
151 | * Remote address information. | ||
152 | */ | ||
153 | union | ||
154 | { | ||
155 | /** | ||
156 | * Address, if af is AF_INET. | ||
157 | */ | ||
158 | struct in_addr ipv4; | ||
159 | |||
160 | /** | ||
161 | * Address, if af is AF_INET6. | ||
162 | */ | ||
163 | struct in6_addr ipv6; | ||
164 | } address; | ||
165 | |||
166 | /** | ||
167 | * Remote port, in host byte order! | ||
168 | */ | ||
169 | uint16_t port; | ||
170 | |||
171 | /** | ||
172 | * IPPROTO_TCP or IPPROTO_UDP; | ||
173 | */ | ||
174 | uint8_t proto; | ||
175 | |||
176 | }; | ||
177 | |||
178 | /** | ||
179 | * This struct is saved into the services-hashmap | ||
180 | */ | ||
181 | struct redirect_service | ||
182 | { | ||
183 | |||
184 | /** | ||
185 | * Remote address to use for the service. | ||
186 | */ | ||
187 | struct remote_addr address; | ||
188 | |||
189 | /** | ||
190 | * Descriptor for this service (also key of this entry in the service hash map). | ||
191 | */ | ||
192 | GNUNET_HashCode desc; | ||
193 | |||
194 | /** | ||
195 | * Port I am listening on within GNUnet for this service, in host byte order. | ||
196 | */ | ||
197 | uint16_t my_port; | ||
198 | |||
199 | }; | ||
200 | |||
201 | /** | ||
202 | * Information we use to track a connection. | ||
203 | */ | ||
204 | struct redirect_info | ||
205 | { | ||
206 | |||
207 | /** | ||
208 | * Address information for the other party. | ||
209 | */ | ||
210 | struct remote_addr remote_address; | ||
211 | |||
212 | /** | ||
213 | * The source-port of this connection, in host byte order | ||
214 | */ | ||
215 | uint16_t source_port; | ||
216 | |||
217 | }; | ||
218 | |||
219 | /** | ||
220 | * This struct is saved into {tcp,udp}_connections; | ||
221 | */ | ||
222 | struct redirect_state | ||
223 | { | ||
224 | /** | ||
225 | * Mesh tunnel that is used for this connection. | ||
226 | */ | ||
227 | struct GNUNET_MESH_Tunnel *tunnel; | ||
228 | |||
229 | /** | ||
230 | * Heap node for this state in the connections_heap. | ||
231 | */ | ||
232 | struct GNUNET_CONTAINER_HeapNode *heap_node; | ||
233 | |||
234 | /** | ||
235 | * Key this state has in the connections_map. | ||
236 | */ | ||
237 | GNUNET_HashCode state_key; | ||
238 | |||
239 | /** | ||
240 | * Associated service record, or NULL for no service. | ||
241 | */ | ||
242 | struct redirect_service *serv; | ||
243 | |||
244 | /** | ||
245 | * Source port we use for this connection. FIXME: needed? used? | ||
246 | */ | ||
247 | uint16_t source_port__; | ||
248 | |||
249 | }; | ||
250 | |||
251 | /** | ||
252 | * Queue of messages to a tunnel. | ||
253 | */ | ||
254 | struct tunnel_notify_queue | ||
255 | { | ||
256 | /** | ||
257 | * This is a doubly-linked list. | ||
258 | */ | ||
259 | struct tunnel_notify_queue *next; | ||
260 | |||
261 | /** | ||
262 | * This is a doubly-linked list. | ||
263 | */ | ||
264 | struct tunnel_notify_queue *prev; | ||
265 | |||
266 | /** | ||
267 | * Payload to send via the tunnel. | ||
268 | */ | ||
269 | const void *payload; | ||
270 | |||
271 | /** | ||
272 | * Number of bytes in 'cls'. | ||
273 | */ | ||
274 | size_t len; | ||
275 | }; | ||
276 | |||
277 | |||
278 | /** | ||
279 | * Information we track per mesh tunnel. | ||
280 | */ | ||
281 | struct tunnel_state | ||
282 | { | ||
283 | struct tunnel_notify_queue *head; | ||
284 | struct tunnel_notify_queue *tail; | ||
285 | struct GNUNET_MESH_TransmitHandle *th; | ||
286 | struct GNUNET_MESH_Tunnel *tunnel; | ||
287 | }; | ||
288 | |||
289 | |||
290 | /** | ||
291 | * The handle to the configuration used throughout the process | ||
292 | */ | ||
293 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
294 | |||
295 | /** | ||
296 | * The handle to the helper | ||
297 | */ | ||
298 | static struct GNUNET_HELPER_Handle *helper_handle; | ||
299 | |||
300 | /** | ||
301 | * Arguments to the exit helper. | ||
302 | */ | ||
303 | static char *exit_argv[7]; | ||
304 | |||
305 | /** | ||
306 | * IPv6 prefix (0..127) from configuration file. | ||
307 | */ | ||
308 | static unsigned long long ipv6prefix; | ||
309 | |||
310 | /** | ||
311 | * Final status code. | ||
312 | */ | ||
313 | static int ret; | ||
314 | |||
315 | /** | ||
316 | * The handle to mesh | ||
317 | */ | ||
318 | static struct GNUNET_MESH_Handle *mesh_handle; | ||
319 | |||
320 | /** | ||
321 | * This hashmaps contains the mapping from peer, service-descriptor, | ||
322 | * source-port and destination-port to a struct redirect_state | ||
323 | */ | ||
324 | static struct GNUNET_CONTAINER_MultiHashMap *connections_map; | ||
325 | |||
326 | /** | ||
327 | * Heap so we can quickly find "old" connections. | ||
328 | */ | ||
329 | static struct GNUNET_CONTAINER_Heap *connections_heap; | ||
330 | |||
331 | /** | ||
332 | * If there are at least this many connections, old ones will be removed | ||
333 | */ | ||
334 | static long long unsigned int max_connections = 200; | ||
335 | |||
336 | /** | ||
337 | * This hashmaps saves interesting things about the configured UDP services | ||
338 | */ | ||
339 | static struct GNUNET_CONTAINER_MultiHashMap *udp_services; | ||
340 | |||
341 | /** | ||
342 | * This hashmaps saves interesting things about the configured TCP services | ||
343 | */ | ||
344 | static struct GNUNET_CONTAINER_MultiHashMap *tcp_services; | ||
345 | |||
346 | |||
347 | /** | ||
348 | * Given IP information about a connection, calculate the respective | ||
349 | * hash we would use for the 'connections_map'. | ||
350 | * | ||
351 | * @param hash resulting hash | ||
352 | * @param ri information about the connection | ||
353 | */ | ||
354 | static void | ||
355 | hash_redirect_info (GNUNET_HashCode * hash, | ||
356 | const struct redirect_info *ri) | ||
357 | { | ||
358 | char *off; | ||
359 | |||
360 | memset (hash, 0, sizeof (GNUNET_HashCode)); | ||
361 | /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash */ | ||
362 | off = (char*) hash; | ||
363 | switch (ri->remote_address.af) | ||
364 | { | ||
365 | case AF_INET: | ||
366 | memcpy (off, &ri->remote_address.address.ipv4, sizeof (struct in_addr)); | ||
367 | off += sizeof (struct in_addr); | ||
368 | break; | ||
369 | case AF_INET6: | ||
370 | memcpy (off, &ri->remote_address.address.ipv6, sizeof (struct in6_addr)); | ||
371 | off += sizeof (struct in_addr); | ||
372 | break; | ||
373 | default: | ||
374 | GNUNET_assert (0); | ||
375 | } | ||
376 | memcpy (off, &ri->remote_address.port, sizeof (uint16_t)); | ||
377 | memcpy (off, &ri->remote_address.proto, sizeof (uint8_t)); | ||
378 | memcpy (off, &ri->source_port, sizeof (uint8_t)); | ||
379 | } | ||
380 | |||
381 | |||
382 | /** | ||
383 | * Given a service descriptor and a destination port, find the | ||
384 | * respective service entry. | ||
385 | * | ||
386 | * @param service_map map of services (TCP or UDP) | ||
387 | * @param desc service descriptor | ||
388 | * @param dpt destination port | ||
389 | * @return NULL if we are not aware of such a service | ||
390 | */ | ||
391 | static struct redirect_service * | ||
392 | find_service (struct GNUNET_CONTAINER_MultiHashMap *service_map, | ||
393 | const GNUNET_HashCode *desc, | ||
394 | uint16_t dpt) | ||
395 | { | ||
396 | char key[sizeof (GNUNET_HashCode) + sizeof (uint16_t)]; | ||
397 | |||
398 | memcpy (&key[0], &dpt, sizeof (uint16_t)); | ||
399 | memcpy (&key[sizeof(uint16_t)], desc, sizeof (GNUNET_HashCode)); | ||
400 | return GNUNET_CONTAINER_multihashmap_get (service_map, | ||
401 | (GNUNET_HashCode *) key); | ||
402 | } | ||
403 | |||
404 | |||
405 | /** | ||
406 | * Free memory associated with a service record. | ||
407 | * | ||
408 | * @param cls unused | ||
409 | * @param key service descriptor | ||
410 | * @param value service record to free | ||
411 | * @return GNUNET_OK | ||
412 | */ | ||
413 | static int | ||
414 | free_service_record (void *cls, | ||
415 | const GNUNET_HashCode *key, | ||
416 | void *value) | ||
417 | { | ||
418 | struct redirect_service *service = value; | ||
419 | |||
420 | GNUNET_free (service); | ||
421 | return GNUNET_OK; | ||
422 | } | ||
423 | |||
424 | |||
425 | /** | ||
426 | * Given a service descriptor and a destination port, find the | ||
427 | * respective service entry. | ||
428 | * | ||
429 | * @param service_map map of services (TCP or UDP) | ||
430 | * @param name name of the service | ||
431 | * @param dpt destination port | ||
432 | * @param service service information record to store (service->desc will be set). | ||
433 | */ | ||
434 | static void | ||
435 | store_service (struct GNUNET_CONTAINER_MultiHashMap *service_map, | ||
436 | const char *name, | ||
437 | uint16_t dpt, | ||
438 | struct redirect_service *service) | ||
439 | { | ||
440 | char key[sizeof (GNUNET_HashCode) + sizeof (uint16_t)]; | ||
441 | GNUNET_HashCode desc; | ||
442 | |||
443 | GNUNET_CRYPTO_hash (name, strlen (name) + 1, &desc); | ||
444 | service->desc = desc; | ||
445 | memcpy (&key[0], &dpt, sizeof (uint16_t)); | ||
446 | memcpy (&key[sizeof(uint16_t)], &desc, sizeof (GNUNET_HashCode)); | ||
447 | if (GNUNET_OK != | ||
448 | GNUNET_CONTAINER_multihashmap_put (service_map, | ||
449 | (GNUNET_HashCode *) key, | ||
450 | service, | ||
451 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) | ||
452 | { | ||
453 | free_service_record (NULL, (GNUNET_HashCode *) key, service); | ||
454 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
455 | _("Got duplicate service records for `%s:%u'\n"), | ||
456 | name, | ||
457 | (unsigned int) dpt); | ||
458 | } | ||
459 | } | ||
460 | |||
461 | |||
462 | /** | ||
463 | * MESH is ready to receive a message for the tunnel. Transmit it. | ||
464 | * | ||
465 | * @param cls the 'struct tunnel_state'. | ||
466 | * @param size number of bytes available in buf | ||
467 | * @param buf where to copy the message | ||
468 | * @return number of bytes copied to buf | ||
469 | */ | ||
470 | static size_t | ||
471 | send_to_peer_notify_callback (void *cls, size_t size, void *buf) | ||
472 | { | ||
473 | struct tunnel_state *s = cls; | ||
474 | struct GNUNET_MESH_Tunnel *tunnel = s->tunnel; | ||
475 | struct tunnel_notify_queue *tnq; | ||
476 | |||
477 | s->th = NULL; | ||
478 | tnq = s->head; | ||
479 | GNUNET_assert (size >= tnq->len); | ||
480 | memcpy (buf, tnq->payload, tnq->len); | ||
481 | size = tnq->len; | ||
482 | GNUNET_CONTAINER_DLL_remove (s->head, | ||
483 | s->tail, | ||
484 | tnq); | ||
485 | GNUNET_free (tnq); | ||
486 | if (NULL != (tnq = s->head)) | ||
487 | s->th = GNUNET_MESH_notify_transmit_ready (tunnel, | ||
488 | GNUNET_NO /* corking */, | ||
489 | 0 /* priority */, | ||
490 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
491 | NULL, | ||
492 | tnq->len, | ||
493 | &send_to_peer_notify_callback, | ||
494 | s); | ||
495 | return size; | ||
496 | } | ||
497 | |||
498 | |||
499 | /** | ||
500 | * Send the given packet via the mesh tunnel. | ||
501 | * | ||
502 | * @param mesh_tunnel destination | ||
503 | * @param payload message to transmit | ||
504 | * @param payload_length number of bytes in payload | ||
505 | * @param desc descriptor to add | ||
506 | * @param mtype message type to use | ||
507 | */ | ||
508 | static void | ||
509 | send_packet_to_mesh_tunnel (struct GNUNET_MESH_Tunnel *mesh_tunnel, | ||
510 | const void *payload, | ||
511 | size_t payload_length, | ||
512 | const GNUNET_HashCode *desc, | ||
513 | uint16_t mtype) | ||
514 | { | ||
515 | struct tunnel_state *s; | ||
516 | struct tunnel_notify_queue *tnq; | ||
517 | struct GNUNET_MessageHeader *msg; | ||
518 | size_t len; | ||
519 | GNUNET_HashCode *dp; | ||
520 | |||
521 | len = sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + payload_length; | ||
522 | if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
523 | { | ||
524 | GNUNET_break (0); | ||
525 | return; | ||
526 | } | ||
527 | tnq = GNUNET_malloc (sizeof (struct tunnel_notify_queue) + len); | ||
528 | tnq->payload = &tnq[1]; | ||
529 | tnq->len = len; | ||
530 | msg = (struct GNUNET_MessageHeader *) &tnq[1]; | ||
531 | msg->size = htons ((uint16_t) len); | ||
532 | msg->type = htons (mtype); | ||
533 | dp = (GNUNET_HashCode *) &msg[1]; | ||
534 | *dp = *desc; | ||
535 | memcpy (&dp[1], payload, payload_length); | ||
536 | s = GNUNET_MESH_tunnel_get_data (mesh_tunnel); | ||
537 | GNUNET_assert (NULL != s); | ||
538 | GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, tnq); | ||
539 | if (NULL == s->th) | ||
540 | s->th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, GNUNET_NO /* cork */, 0 /* priority */, | ||
541 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
542 | NULL, len, | ||
543 | &send_to_peer_notify_callback, | ||
544 | s); | ||
545 | } | ||
546 | |||
547 | |||
548 | /** | ||
549 | * Get our connection tracking state. Warns if it does not exists, | ||
550 | * refreshes the timestamp if it does exist. | ||
551 | * | ||
552 | * @param af address family | ||
553 | * @param protocol IPPROTO_UDP or IPPROTO_TCP | ||
554 | * @param destination_ip target IP | ||
555 | * @param destination_port target port | ||
556 | * @param source_port source port | ||
557 | * @return NULL if we have no tracking information for this tuple | ||
558 | */ | ||
559 | static struct redirect_state * | ||
560 | get_redirect_state (int af, | ||
561 | int protocol, | ||
562 | const void *destination_ip, | ||
563 | uint16_t destination_port, | ||
564 | uint16_t source_port) | ||
565 | { | ||
566 | struct redirect_info ri; | ||
567 | GNUNET_HashCode state_key; | ||
568 | struct redirect_state *state; | ||
569 | |||
570 | ri.remote_address.af = af; | ||
571 | if (af == AF_INET) | ||
572 | ri.remote_address.address.ipv4 = *((struct in_addr*) destination_ip); | ||
573 | else | ||
574 | ri.remote_address.address.ipv6 = * ((struct in6_addr*) destination_ip); | ||
575 | ri.remote_address.port = destination_port; | ||
576 | ri.remote_address.proto = IPPROTO_UDP; | ||
577 | ri.source_port = source_port; | ||
578 | |||
579 | hash_redirect_info (&state_key, &ri); | ||
580 | state = GNUNET_CONTAINER_multihashmap_get (connections_map, &state_key); | ||
581 | if (NULL == state) | ||
582 | { | ||
583 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
584 | _("Packet dropped, have no matching connection information\n")); | ||
585 | return NULL; | ||
586 | } | ||
587 | /* Mark this connection as freshly used */ | ||
588 | GNUNET_CONTAINER_heap_update_cost (connections_heap, | ||
589 | state->heap_node, | ||
590 | GNUNET_TIME_absolute_get ().abs_value); | ||
591 | return state; | ||
592 | } | ||
593 | |||
594 | |||
595 | /** | ||
596 | * @brief Handles an UDP packet received from the helper. | ||
597 | * | ||
598 | * @param udp A pointer to the Packet | ||
599 | * @param pktlen number of bytes in 'udp' | ||
600 | * @param destination_ip destination IP-address | ||
601 | * @param af address family (AFINET or AF_INET6) | ||
602 | */ | ||
603 | static void | ||
604 | udp_from_helper (const struct udp_packet *udp, | ||
605 | size_t pktlen, | ||
606 | const void *destination_ip, int af) | ||
607 | { | ||
608 | struct redirect_state *state; | ||
609 | struct GNUNET_MESH_Tunnel *tunnel; | ||
610 | GNUNET_HashCode desc; | ||
611 | |||
612 | if (pktlen < sizeof (struct udp_packet)) | ||
613 | { | ||
614 | /* blame kernel */ | ||
615 | GNUNET_break (0); | ||
616 | return; | ||
617 | } | ||
618 | if (pktlen != ntohs (udp->len)) | ||
619 | { | ||
620 | /* blame kernel */ | ||
621 | GNUNET_break (0); | ||
622 | return; | ||
623 | } | ||
624 | state = get_redirect_state (af, IPPROTO_UDP, | ||
625 | destination_ip, | ||
626 | ntohs (udp->dpt), | ||
627 | ntohs (udp->spt)); | ||
628 | if (NULL == state) | ||
629 | return; | ||
630 | tunnel = state->tunnel; | ||
631 | |||
632 | // FIXME... | ||
633 | #if 0 | ||
634 | if (state->type == SERVICE) | ||
635 | { | ||
636 | /* check if spt == serv.remote if yes: set spt = serv.myport ("nat") */ | ||
637 | if (ntohs (udp->spt) == state->serv->remote_port) | ||
638 | { | ||
639 | udp->spt = htons (state->serv->my_port); | ||
640 | } | ||
641 | else | ||
642 | { | ||
643 | /* otherwise the answer came from a different port (tftp does this) | ||
644 | * add this new port to the list of all services, so that the packets | ||
645 | * coming back from the client to this new port will be routed correctly | ||
646 | */ | ||
647 | struct redirect_service *serv = | ||
648 | GNUNET_malloc (sizeof (struct redirect_service)); | ||
649 | memcpy (serv, state->serv, sizeof (struct redirect_service)); | ||
650 | serv->my_port = ntohs (udp->spt); | ||
651 | serv->remote_port = ntohs (udp->spt); | ||
652 | uint16_t *desc = alloca (sizeof (GNUNET_HashCode) + 2); | ||
653 | |||
654 | memcpy ((GNUNET_HashCode *) (desc + 1), &state->desc, | ||
655 | sizeof (GNUNET_HashCode)); | ||
656 | *desc = ntohs (udp->spt); | ||
657 | GNUNET_assert (GNUNET_OK == | ||
658 | GNUNET_CONTAINER_multihashmap_put (udp_services, | ||
659 | (GNUNET_HashCode *) | ||
660 | desc, serv, | ||
661 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
662 | |||
663 | state->serv = serv; | ||
664 | } | ||
665 | } | ||
666 | |||
667 | if (state->type == SERVICE) | ||
668 | memcpy (&desc, &state->desc, sizeof (GNUNET_HashCode)); | ||
669 | else | ||
670 | memcpy (&desc, &state->remote, sizeof (struct remote_addr)); | ||
671 | #else | ||
672 | memset (&desc, 0, sizeof (desc)); | ||
673 | #endif | ||
674 | |||
675 | /* send udp-packet back */ | ||
676 | send_packet_to_mesh_tunnel (tunnel, | ||
677 | udp, pktlen, | ||
678 | &desc, | ||
679 | state->serv != NULL | ||
680 | ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK | ||
681 | : GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK); | ||
682 | } | ||
683 | |||
684 | |||
685 | /** | ||
686 | * @brief Handles a TCP packet received from the helper. | ||
687 | * | ||
688 | * @param tcp A pointer to the Packet | ||
689 | * @param pktlen the length of the packet, including its header | ||
690 | * @param destination_ip destination IP-address | ||
691 | * @param af address family (AFINET or AF_INET6) | ||
692 | */ | ||
693 | static void | ||
694 | tcp_from_helper (const struct tcp_packet *tcp, | ||
695 | size_t pktlen, | ||
696 | const void *destination_ip, int af) | ||
697 | { | ||
698 | struct redirect_state *state; | ||
699 | struct GNUNET_MESH_Tunnel *tunnel; | ||
700 | GNUNET_HashCode desc; | ||
701 | |||
702 | if (pktlen < sizeof (struct tcp_packet)) | ||
703 | { | ||
704 | /* blame kernel */ | ||
705 | GNUNET_break (0); | ||
706 | return; | ||
707 | } | ||
708 | state = get_redirect_state (af, IPPROTO_TCP, | ||
709 | destination_ip, | ||
710 | ntohs (tcp->dpt), | ||
711 | ntohs (tcp->spt)); | ||
712 | if (NULL == state) | ||
713 | return; | ||
714 | tunnel = state->tunnel; | ||
715 | |||
716 | // FIXME... | ||
717 | #if 0 | ||
718 | if (state->type == SERVICE) | ||
719 | { | ||
720 | /* check if spt == serv.remote if yes: set spt = serv.myport ("nat") */ | ||
721 | if (ntohs (tcp->spt) == state->serv->remote_port) | ||
722 | { | ||
723 | tcp->spt = htons (state->serv->my_port); | ||
724 | } | ||
725 | else | ||
726 | { | ||
727 | // This is an illegal packet. | ||
728 | return; | ||
729 | } | ||
730 | } | ||
731 | |||
732 | /* send tcp-packet back */ | ||
733 | if (state->type == SERVICE) | ||
734 | memcpy (&desc, &state->desc, sizeof (GNUNET_HashCode)); | ||
735 | else | ||
736 | memcpy (&desc, &state->remote, sizeof (struct remote_addr)); | ||
737 | #else | ||
738 | memset (&desc, 0, sizeof (desc)); | ||
739 | #endif | ||
740 | |||
741 | |||
742 | send_packet_to_mesh_tunnel (tunnel, | ||
743 | tcp, pktlen, | ||
744 | &desc, | ||
745 | state->serv != NULL | ||
746 | ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK | ||
747 | : GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK); | ||
748 | } | ||
749 | |||
750 | |||
751 | /** | ||
752 | * Receive packets from the helper-process | ||
753 | * | ||
754 | * @param cls unused | ||
755 | * @param client unsued | ||
756 | * @param message message received from helper | ||
757 | */ | ||
758 | static void | ||
759 | message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED, | ||
760 | const struct GNUNET_MessageHeader *message) | ||
761 | { | ||
762 | const struct tun_header *pkt_tun; | ||
763 | size_t size; | ||
764 | |||
765 | if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) | ||
766 | { | ||
767 | GNUNET_break (0); | ||
768 | return; | ||
769 | } | ||
770 | size = ntohs (message->size); | ||
771 | if (size < sizeof (struct tun_header) + sizeof (struct GNUNET_MessageHeader)) | ||
772 | { | ||
773 | GNUNET_break (0); | ||
774 | return; | ||
775 | } | ||
776 | pkt_tun = (const struct tun_header *) &message[1]; | ||
777 | size -= sizeof (struct tun_header) + sizeof (struct GNUNET_MessageHeader); | ||
778 | switch (ntohs (pkt_tun->proto)) | ||
779 | { | ||
780 | case ETH_P_IPV6: | ||
781 | { | ||
782 | const struct ip6_header *pkt6; | ||
783 | |||
784 | if (size < sizeof (struct ip6_header)) | ||
785 | { | ||
786 | /* Kernel to blame? */ | ||
787 | GNUNET_break (0); | ||
788 | return; | ||
789 | } | ||
790 | pkt6 = (struct ip6_header *) &pkt_tun[1]; | ||
791 | if (size != ntohs (pkt6->payload_length)) | ||
792 | { | ||
793 | /* Kernel to blame? */ | ||
794 | GNUNET_break (0); | ||
795 | return; | ||
796 | } | ||
797 | size -= sizeof (struct ip6_header); | ||
798 | switch (pkt6->next_header) | ||
799 | { | ||
800 | case IPPROTO_UDP: | ||
801 | udp_from_helper ( (const struct udp_packet *) &pkt6[1], size, | ||
802 | &pkt6->destination_address, | ||
803 | AF_INET6); | ||
804 | break; | ||
805 | case IPPROTO_TCP: | ||
806 | tcp_from_helper ((const struct tcp_packet *) &pkt6[1], size, | ||
807 | &pkt6->destination_address, | ||
808 | AF_INET6); | ||
809 | break; | ||
810 | default: | ||
811 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
812 | _("IPv6 packet with unsupported next header received. Ignored.\n")); | ||
813 | return; | ||
814 | } | ||
815 | } | ||
816 | break; | ||
817 | case ETH_P_IPV4: | ||
818 | { | ||
819 | const struct ip4_header *pkt4; | ||
820 | |||
821 | if (size < sizeof (struct ip4_header)) | ||
822 | { | ||
823 | /* Kernel to blame? */ | ||
824 | GNUNET_break (0); | ||
825 | return; | ||
826 | } | ||
827 | pkt4 = (const struct ip4_header *) &pkt_tun[1]; | ||
828 | if (size != ntohs (pkt4->total_length)) | ||
829 | { | ||
830 | /* Kernel to blame? */ | ||
831 | GNUNET_break (0); | ||
832 | return; | ||
833 | } | ||
834 | if (pkt4->header_length * 4 != sizeof (struct ip4_header)) | ||
835 | { | ||
836 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
837 | _("IPv4 packet options received. Ignored.\n")); | ||
838 | return; | ||
839 | } | ||
840 | size -= sizeof (struct ip4_header); | ||
841 | switch (pkt4->protocol) | ||
842 | { | ||
843 | case IPPROTO_UDP: | ||
844 | udp_from_helper ((const struct udp_packet *) &pkt4[1], size, | ||
845 | &pkt4->destination_address, AF_INET); | ||
846 | break; | ||
847 | case IPPROTO_TCP: | ||
848 | tcp_from_helper ((const struct tcp_packet *) &pkt4[1], size, | ||
849 | &pkt4->destination_address, AF_INET); | ||
850 | break; | ||
851 | default: | ||
852 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
853 | _("IPv4 packet with unsupported next header received. Ignored.\n")); | ||
854 | return; | ||
855 | } | ||
856 | } | ||
857 | break; | ||
858 | default: | ||
859 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
860 | _("Packet from unknown protocol %u received. Ignored.\n"), | ||
861 | ntohs (pkt_tun->proto)); | ||
862 | break; | ||
863 | } | ||
864 | } | ||
865 | |||
866 | |||
867 | |||
868 | |||
869 | static void | ||
870 | prepare_ipv4_packet (size_t len, uint16_t pktlen, void *payload, | ||
871 | uint8_t protocol, void *ipaddress, void *tunnel, | ||
872 | struct redirect_info *state, struct ip4_header *pkt4) | ||
873 | { | ||
874 | const char *ipv4addr = exit_argv[4]; | ||
875 | const char *ipv4mask = exit_argv[5]; | ||
876 | uint32_t tmp; | ||
877 | uint32_t tmp2; | ||
878 | |||
879 | GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &tmp)); | ||
880 | GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &tmp2)); | ||
881 | memcpy (&pkt4[1], payload, pktlen); | ||
882 | pkt4->version = 4; | ||
883 | pkt4->header_length = sizeof (struct ip4_header) / 4; | ||
884 | pkt4->diff_serv = 0; | ||
885 | pkt4->total_length = htons (sizeof (struct ip4_header) + pktlen); | ||
886 | pkt4->identification = 0; // FIXME! | ||
887 | pkt4->flags = 0; | ||
888 | pkt4->fragmentation_offset = 0; | ||
889 | pkt4->ttl = 255; | ||
890 | pkt4->protocol = protocol; | ||
891 | pkt4->checksum = 0; /* Will be calculated later */ | ||
892 | |||
893 | memcpy (&pkt4->destination_address, ipaddress, sizeof (struct in_addr)); | ||
894 | |||
895 | /* Generate a new src-address -- FIXME: not always, right!? */ | ||
896 | |||
897 | /* This should be a noop */ | ||
898 | tmp = tmp & tmp2; | ||
899 | tmp |= ntohl (*((uint32_t *) tunnel)) & (~tmp2); | ||
900 | |||
901 | pkt4->source_address.s_addr = tmp; | ||
902 | pkt4->checksum = GNUNET_CRYPTO_crc16_n (pkt4, sizeof (struct ip4_header)); | ||
903 | |||
904 | // FIXME: memcpy (&state->addr, &tmp, 4); | ||
905 | |||
906 | switch (protocol) | ||
907 | { | ||
908 | case IPPROTO_UDP: | ||
909 | { | ||
910 | struct udp_packet *pkt4_udp = (struct udp_packet *) &pkt4[1]; | ||
911 | // FIXME: state->pt = pkt4_udp->spt; | ||
912 | pkt4_udp->crc = 0; /* Optional for IPv4 */ | ||
913 | } | ||
914 | break; | ||
915 | case IPPROTO_TCP: | ||
916 | { | ||
917 | struct tcp_packet *pkt4_tcp = (struct tcp_packet *) &pkt4[1]; | ||
918 | |||
919 | // FIXME: state->pt = pkt4_tcp->spt; | ||
920 | pkt4_tcp->crc = 0; | ||
921 | uint32_t sum = 0; | ||
922 | sum = GNUNET_CRYPTO_crc16_step (sum, | ||
923 | &pkt4->source_address, | ||
924 | sizeof (struct in_addr) * 2); | ||
925 | tmp = (protocol << 16) | (0xffff & pktlen); | ||
926 | tmp = htonl (tmp); | ||
927 | sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, 4); | ||
928 | sum = GNUNET_CRYPTO_crc16_step (sum, & pkt4_tcp, pktlen); | ||
929 | pkt4_tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
930 | } | ||
931 | break; | ||
932 | default: | ||
933 | GNUNET_assert (0); | ||
934 | } | ||
935 | } | ||
936 | |||
937 | |||
938 | static void | ||
939 | prepare_ipv6_packet (size_t len, uint16_t pktlen, void *payload, | ||
940 | uint16_t protocol, void *ipaddress, void *tunnel, | ||
941 | struct redirect_info *state, struct ip6_header *pkt6) | ||
942 | { | ||
943 | const char *ipv6addr = exit_argv[2]; | ||
944 | uint32_t tmp; | ||
945 | |||
946 | |||
947 | memcpy (&pkt6[1], payload, pktlen); | ||
948 | |||
949 | pkt6->version = 6; | ||
950 | pkt6->next_header = protocol; | ||
951 | pkt6->payload_length = htons (pktlen); | ||
952 | pkt6->hop_limit = 64; | ||
953 | |||
954 | memcpy (&pkt6->destination_address, ipaddress, sizeof (struct in6_addr)); | ||
955 | |||
956 | /* Generate a new src-address | ||
957 | * This takes as much from the address of the tunnel as fits into | ||
958 | * the host-mask*/ | ||
959 | |||
960 | unsigned long long ipv6prefix_r = (ipv6prefix + 7) / 8; | ||
961 | |||
962 | inet_pton (AF_INET6, ipv6addr, &pkt6->source_address); | ||
963 | |||
964 | if (ipv6prefix_r < (16 - sizeof (void *))) | ||
965 | ipv6prefix_r = 16 - sizeof (void *); | ||
966 | |||
967 | unsigned int offset = ipv6prefix_r - (16 - sizeof (void *)); | ||
968 | |||
969 | memcpy ((((char *) &pkt6->source_address)) + ipv6prefix_r, | ||
970 | ((char *) &tunnel) + offset, 16 - ipv6prefix_r); | ||
971 | |||
972 | /* copy the needed information into the state */ | ||
973 | // FIXME: memcpy (&state->addr, &pkt6->source_address, 16); | ||
974 | |||
975 | switch (protocol) | ||
976 | { | ||
977 | case IPPROTO_UDP: | ||
978 | { | ||
979 | struct udp_packet *pkt6_udp = (struct udp_packet *) &pkt6[1]; | ||
980 | |||
981 | // FIXME: state->pt = pkt6_udp->spt; | ||
982 | pkt6_udp->crc = 0; | ||
983 | uint32_t sum = 0; | ||
984 | sum = | ||
985 | GNUNET_CRYPTO_crc16_step (sum, & pkt6->source_address, | ||
986 | 16 * 2); | ||
987 | tmp = (htons (pktlen) & 0xffff); | ||
988 | sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, 4); | ||
989 | tmp = htons (pkt6->next_header & 0x00ff); | ||
990 | sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, 4); | ||
991 | sum = | ||
992 | GNUNET_CRYPTO_crc16_step (sum, pkt6_udp, | ||
993 | ntohs (pkt6_udp->len)); | ||
994 | pkt6_udp->crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
995 | } | ||
996 | break; | ||
997 | case IPPROTO_TCP: | ||
998 | { | ||
999 | struct tcp_packet *pkt6_tcp = (struct tcp_packet *) pkt6; | ||
1000 | |||
1001 | // FIXME: state->pt = pkt6_tcp->spt; | ||
1002 | pkt6_tcp->crc = 0; | ||
1003 | uint32_t sum = 0; | ||
1004 | |||
1005 | sum = | ||
1006 | GNUNET_CRYPTO_crc16_step (sum, & pkt6->source_address, 16 * 2); | ||
1007 | tmp = htonl (pktlen); | ||
1008 | sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, 4); | ||
1009 | tmp = htonl (((pkt6->next_header & 0x000000ff))); | ||
1010 | sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, 4); | ||
1011 | |||
1012 | sum = | ||
1013 | GNUNET_CRYPTO_crc16_step (sum, pkt6_tcp, | ||
1014 | ntohs (pkt6->payload_length)); | ||
1015 | pkt6_tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
1016 | } | ||
1017 | break; | ||
1018 | default: | ||
1019 | GNUNET_assert (0); | ||
1020 | break; | ||
1021 | } | ||
1022 | } | ||
1023 | |||
1024 | |||
1025 | /** | ||
1026 | * We've just experienced a connection in use. Track it, or if it is | ||
1027 | * already tracked, update the tracking. | ||
1028 | * | ||
1029 | * @param u_i IP-level connection tracking state | ||
1030 | * @param tunnel associated mesh tunnel | ||
1031 | * @param desc service descriptor (or NULL) | ||
1032 | * @param serv service information | ||
1033 | */ | ||
1034 | static void | ||
1035 | update_state_map (const struct redirect_info *ri, | ||
1036 | struct GNUNET_MESH_Tunnel *tunnel, | ||
1037 | const GNUNET_HashCode *desc, | ||
1038 | struct redirect_service *serv) | ||
1039 | { | ||
1040 | struct redirect_state *state; | ||
1041 | GNUNET_HashCode state_key; | ||
1042 | |||
1043 | hash_redirect_info (&state_key, | ||
1044 | ri); | ||
1045 | state = GNUNET_CONTAINER_multihashmap_get (connections_map, &state_key); | ||
1046 | if (NULL == state) | ||
1047 | { | ||
1048 | state = GNUNET_malloc (sizeof (struct redirect_state)); | ||
1049 | state->tunnel = tunnel; | ||
1050 | state->state_key = state_key; | ||
1051 | state->serv = serv; | ||
1052 | // FIXME? if (NULL != desc) state->desc = *desc; | ||
1053 | // FIXME? state->redirect_info = *ri; | ||
1054 | GNUNET_assert (GNUNET_OK == | ||
1055 | GNUNET_CONTAINER_multihashmap_put (connections_map, &state_key, state, | ||
1056 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
1057 | state->heap_node = | ||
1058 | GNUNET_CONTAINER_heap_insert (connections_heap, | ||
1059 | state, | ||
1060 | GNUNET_TIME_absolute_get ().abs_value); | ||
1061 | } | ||
1062 | else | ||
1063 | { | ||
1064 | if (state->tunnel != tunnel) | ||
1065 | { | ||
1066 | /* Stats / warning: two tunnels got exactly the same connection state!? */ | ||
1067 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1068 | _("Two different mesh tunnels got the same connection state. Oops.\n")); | ||
1069 | return; | ||
1070 | } | ||
1071 | GNUNET_CONTAINER_heap_update_cost (connections_heap, | ||
1072 | state->heap_node, | ||
1073 | GNUNET_TIME_absolute_get ().abs_value); | ||
1074 | } | ||
1075 | while (GNUNET_CONTAINER_heap_get_size (connections_heap) > max_connections) | ||
1076 | { | ||
1077 | state = GNUNET_CONTAINER_heap_remove_root (connections_heap); | ||
1078 | state->heap_node = NULL; | ||
1079 | GNUNET_MESH_tunnel_destroy (state->tunnel); | ||
1080 | GNUNET_assert (GNUNET_OK == | ||
1081 | GNUNET_CONTAINER_multihashmap_remove (connections_map, | ||
1082 | &state->state_key, | ||
1083 | state)); | ||
1084 | GNUNET_free (state); | ||
1085 | } | ||
1086 | } | ||
1087 | |||
1088 | |||
1089 | |||
1090 | |||
1091 | /** | ||
1092 | * The messages are one GNUNET_HashCode for the service followed by a struct tcp_packet | ||
1093 | */ | ||
1094 | static int | ||
1095 | receive_tcp_service (void *unused GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
1096 | void **tunnel_ctx GNUNET_UNUSED, | ||
1097 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
1098 | const struct GNUNET_MessageHeader *message, | ||
1099 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
1100 | { | ||
1101 | #if 0 | ||
1102 | const GNUNET_HashCode *desc = (const GNUNET_HashCode *) &message[1]; | ||
1103 | const struct tcp_packet *pkt = (const struct tcp_packet *) &desc[1]; | ||
1104 | uint16_t pkt_len = ntohs (message->size); | ||
1105 | struct redirect_service *serv; | ||
1106 | struct redirect_info u_i; | ||
1107 | GNUNET_HashCode state_key; | ||
1108 | |||
1109 | /* check that we got at least a valid header */ | ||
1110 | if (pkt_len < sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + sizeof (struct tcp_packet)) | ||
1111 | { | ||
1112 | GNUNET_break_op (0); | ||
1113 | return GNUNET_YES; | ||
1114 | } | ||
1115 | pkt_len -= (sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode)); | ||
1116 | |||
1117 | if (NULL == (serv = find_service (tcp_services, desc, ntohs (pkt->dpt)))) | ||
1118 | { | ||
1119 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1120 | _("No service found for %s on port %d!\n"), | ||
1121 | "TCP", | ||
1122 | ntohs (pkt->dpt)); | ||
1123 | return GNUNET_YES; | ||
1124 | } | ||
1125 | pkt->dpt = htons (serv->remote_port); | ||
1126 | |||
1127 | /* At this point it would be possible to check against some kind of ACL. */ | ||
1128 | |||
1129 | switch (serv->version) | ||
1130 | { | ||
1131 | case 4: | ||
1132 | { | ||
1133 | size_t len = | ||
1134 | sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) + | ||
1135 | sizeof (struct ip4_header) + pkt_len; | ||
1136 | char buf[len]; | ||
1137 | struct tun_header *hdr; | ||
1138 | struct GNUNET_MessageHeader *mhdr; | ||
1139 | |||
1140 | memset (buf, 0, len); | ||
1141 | mhdr = (struct GNUNET_MessageHeader*) buf; | ||
1142 | hdr = (struct tun_header *) &mhdr[1]; | ||
1143 | mhdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
1144 | mhdr->size = htons (len); | ||
1145 | hdr->flags = 0; | ||
1146 | hdr->proto = htons (0x0800); | ||
1147 | prepare_ipv4_packet (len, pkt_len, pkt, IPPROTO_TCP, &serv->v4.ip4address, | ||
1148 | tunnel, &u_i, (struct ip4_header *) &hdr[1]); | ||
1149 | /* FIXME: here, flow-control with mesh would be nice to have... */ | ||
1150 | (void) GNUNET_HELPER_send (helper_handle, | ||
1151 | mhdr, | ||
1152 | GNUNET_YES, | ||
1153 | NULL, NULL); | ||
1154 | break; | ||
1155 | } | ||
1156 | case 6: | ||
1157 | { | ||
1158 | size_t len = | ||
1159 | sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) + | ||
1160 | sizeof (struct ip6_header) + pkt_len; | ||
1161 | char buf[len]; | ||
1162 | struct tun_header *hdr; | ||
1163 | struct GNUNET_MessageHeader *mhdr; | ||
1164 | |||
1165 | memset (buf, 0, len); | ||
1166 | mhdr = (struct GNUNET_MessageHeader*) buf; | ||
1167 | hdr = (struct tun_header *) &mhdr[1]; | ||
1168 | mhdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
1169 | mhdr->size = htons (len); | ||
1170 | hdr->flags = 0; | ||
1171 | hdr->proto = htons (0x86dd); | ||
1172 | prepare_ipv6_packet (len, pkt_len, pkt, IPPROTO_TCP, &serv->v6.ip6address, | ||
1173 | tunnel, &u_i, (struct ip6_header *) buf); | ||
1174 | /* FIXME: here, flow-control with mesh would be nice to have... */ | ||
1175 | (void) GNUNET_HELPER_send (helper_handle, | ||
1176 | (const struct GNUNET_MessageHeader*) buf, | ||
1177 | GNUNET_YES, | ||
1178 | NULL, NULL); | ||
1179 | |||
1180 | break; | ||
1181 | } | ||
1182 | default: | ||
1183 | GNUNET_assert (0); | ||
1184 | break; | ||
1185 | } | ||
1186 | |||
1187 | |||
1188 | update_state_map (&u_i, desc, tunnel, serv); | ||
1189 | #endif | ||
1190 | return GNUNET_YES; | ||
1191 | } | ||
1192 | |||
1193 | |||
1194 | static int | ||
1195 | receive_tcp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
1196 | void **tunnel_ctx GNUNET_UNUSED, | ||
1197 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
1198 | const struct GNUNET_MessageHeader *message, | ||
1199 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
1200 | { | ||
1201 | // FIXME | ||
1202 | #if 0 | ||
1203 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); | ||
1204 | struct tcp_packet *pkt = (struct tcp_packet *) (desc + 1); | ||
1205 | struct remote_addr *s = (struct remote_addr *) desc; | ||
1206 | char *buf; | ||
1207 | size_t len; | ||
1208 | uint16_t pkt_len = | ||
1209 | ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - | ||
1210 | sizeof (GNUNET_HashCode); | ||
1211 | |||
1212 | struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state)); | ||
1213 | |||
1214 | state->tunnel = tunnel; | ||
1215 | state->type = REMOTE; | ||
1216 | state->hashmap = tcp_connections; | ||
1217 | memcpy (&state->remote, s, sizeof (struct remote_addr)); | ||
1218 | |||
1219 | hash_redirect_info (&state->hash, &state->redirect_info, s->addrlen); | ||
1220 | |||
1221 | if (GNUNET_NO == | ||
1222 | GNUNET_CONTAINER_multihashmap_contains (tcp_connections, &state->hash)) | ||
1223 | { | ||
1224 | GNUNET_CONTAINER_multihashmap_put (tcp_connections, &state->hash, state, | ||
1225 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1226 | |||
1227 | state->heap_node = | ||
1228 | GNUNET_CONTAINER_heap_insert (tcp_connections_heap, state, | ||
1229 | GNUNET_TIME_absolute_get ().abs_value); | ||
1230 | |||
1231 | if (GNUNET_CONTAINER_heap_get_size (tcp_connections_heap) > | ||
1232 | max_tcp_connections) | ||
1233 | GNUNET_SCHEDULER_add_now (collect_connections, tcp_connections_heap); | ||
1234 | } | ||
1235 | else | ||
1236 | GNUNET_free (state); | ||
1237 | |||
1238 | |||
1239 | |||
1240 | len = | ||
1241 | sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) + | ||
1242 | sizeof (struct ip6_hdr) + pkt_len; | ||
1243 | buf = alloca (len); | ||
1244 | |||
1245 | memset (buf, 0, len); | ||
1246 | |||
1247 | switch (s->addrlen) | ||
1248 | { | ||
1249 | case 4: | ||
1250 | prepare_ipv4_packet (len, pkt_len, pkt, IPPROTO_TCP, &s->addr, tunnel, | ||
1251 | state, (struct ip4_header *) buf); | ||
1252 | break; | ||
1253 | case 16: | ||
1254 | prepare_ipv6_packet (len, pkt_len, pkt, IPPROTO_TCP, &s->addr, tunnel, | ||
1255 | state, (struct ip6_header *) buf); | ||
1256 | break; | ||
1257 | default: | ||
1258 | GNUNET_free (state); | ||
1259 | return GNUNET_SYSERR; | ||
1260 | } | ||
1261 | |||
1262 | /* FIXME: here, flow-control with mesh would be nice to have... */ | ||
1263 | (void) GNUNET_HELPER_send (helper_handle, | ||
1264 | (const struct GNUNET_MessageHeader*) buf, | ||
1265 | GNUNET_YES, | ||
1266 | NULL, NULL); | ||
1267 | |||
1268 | #endif | ||
1269 | return GNUNET_YES; | ||
1270 | } | ||
1271 | |||
1272 | static int | ||
1273 | receive_udp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
1274 | void **tunnel_ctx GNUNET_UNUSED, | ||
1275 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
1276 | const struct GNUNET_MessageHeader *message, | ||
1277 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
1278 | { | ||
1279 | // FIXME | ||
1280 | #if 0 | ||
1281 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); | ||
1282 | struct udp_packet *pkt = (struct udp_packet *) (desc + 1); | ||
1283 | struct remote_addr *s = (struct remote_addr *) desc; | ||
1284 | char *buf; | ||
1285 | size_t len; | ||
1286 | |||
1287 | GNUNET_assert (ntohs (pkt->len) == | ||
1288 | ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - | ||
1289 | sizeof (GNUNET_HashCode)); | ||
1290 | |||
1291 | /* Prepare the state. | ||
1292 | * This will be saved in the hashmap, so that the receiving procedure knows | ||
1293 | * through which tunnel this connection has to be routed. | ||
1294 | */ | ||
1295 | struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state)); | ||
1296 | |||
1297 | state->tunnel = tunnel; | ||
1298 | state->hashmap = udp_connections; | ||
1299 | state->type = REMOTE; | ||
1300 | memcpy (&state->remote, s, sizeof (struct remote_addr)); | ||
1301 | |||
1302 | len = | ||
1303 | sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) + | ||
1304 | sizeof (struct ip6_hdr) + ntohs (pkt->len); | ||
1305 | buf = alloca (len); | ||
1306 | |||
1307 | memset (buf, 0, len); | ||
1308 | |||
1309 | switch (s->addrlen) | ||
1310 | { | ||
1311 | case 4: | ||
1312 | prepare_ipv4_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, &s->addr, | ||
1313 | tunnel, state, (struct ip4_header *) buf); | ||
1314 | break; | ||
1315 | case 16: | ||
1316 | prepare_ipv6_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, &s->addr, | ||
1317 | tunnel, state, (struct ip6_header *) buf); | ||
1318 | break; | ||
1319 | default: | ||
1320 | GNUNET_assert (0); | ||
1321 | break; | ||
1322 | } | ||
1323 | |||
1324 | hash_redirect_info (&state->hash, &state->redirect_info, s->addrlen); | ||
1325 | |||
1326 | (void) GNUNET_HELPER_send (helper_handle, | ||
1327 | (const struct GNUNET_MessageHeader*) buf, | ||
1328 | GNUNET_YES, | ||
1329 | NULL, NULL); | ||
1330 | |||
1331 | |||
1332 | if (GNUNET_NO == | ||
1333 | GNUNET_CONTAINER_multihashmap_contains (udp_connections, &state->hash)) | ||
1334 | { | ||
1335 | GNUNET_CONTAINER_multihashmap_put (udp_connections, &state->hash, state, | ||
1336 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1337 | |||
1338 | state->heap_node = | ||
1339 | GNUNET_CONTAINER_heap_insert (udp_connections_heap, state, | ||
1340 | GNUNET_TIME_absolute_get ().abs_value); | ||
1341 | |||
1342 | if (GNUNET_CONTAINER_heap_get_size (udp_connections_heap) > | ||
1343 | max_udp_connections) | ||
1344 | GNUNET_SCHEDULER_add_now (collect_connections, udp_connections_heap); | ||
1345 | } | ||
1346 | else | ||
1347 | GNUNET_free (state); | ||
1348 | #endif | ||
1349 | return GNUNET_YES; | ||
1350 | } | ||
1351 | |||
1352 | /** | ||
1353 | * The messages are one GNUNET_HashCode for the service, followed by a struct udp_packet | ||
1354 | */ | ||
1355 | static int | ||
1356 | receive_udp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
1357 | void **tunnel_ctx, | ||
1358 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
1359 | const struct GNUNET_MessageHeader *message, | ||
1360 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
1361 | { | ||
1362 | // FIXME | ||
1363 | #if 0 | ||
1364 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); | ||
1365 | struct udp_packet *pkt = (struct udp_packet *) (desc + 1); | ||
1366 | uint16_t pkt_len = ntohs (message->size); | ||
1367 | struct redirect_service *serv; | ||
1368 | |||
1369 | /* check that we got at least a valid header */ | ||
1370 | if (pkt_len < sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + sizeof (struct udp_packet)) | ||
1371 | { | ||
1372 | GNUNET_break_op (0); | ||
1373 | return GNUNET_YES; | ||
1374 | } | ||
1375 | pkt_len -= (sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode)); | ||
1376 | |||
1377 | GNUNET_assert (ntohs (pkt->len) == | ||
1378 | ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - | ||
1379 | sizeof (GNUNET_HashCode)); | ||
1380 | |||
1381 | if (NULL == (serv = find_service (udp_services, desc, ntohs (pkt->dpt)))) | ||
1382 | { | ||
1383 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1384 | _("No service found for %s on port %d!\n"), | ||
1385 | "UDP", | ||
1386 | ntohs (pkt->dpt)); | ||
1387 | return GNUNET_YES; | ||
1388 | } | ||
1389 | pkt->dpt = htons (serv->remote_port); | ||
1390 | |||
1391 | /* | ||
1392 | * At this point it would be possible to check against some kind of ACL. | ||
1393 | */ | ||
1394 | |||
1395 | char *buf; | ||
1396 | size_t len; | ||
1397 | |||
1398 | /* Prepare the state. | ||
1399 | * This will be saved in the hashmap, so that the receiving procedure knows | ||
1400 | * through which tunnel this connection has to be routed. | ||
1401 | */ | ||
1402 | struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state)); | ||
1403 | |||
1404 | state->tunnel = tunnel; | ||
1405 | state->serv = serv; | ||
1406 | state->type = SERVICE; | ||
1407 | state->hashmap = udp_connections; | ||
1408 | memcpy (&state->desc, desc, sizeof (GNUNET_HashCode)); | ||
1409 | |||
1410 | len = | ||
1411 | sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) + | ||
1412 | sizeof (struct ip6_hdr) + ntohs (pkt->len); | ||
1413 | buf = alloca (len); | ||
1414 | |||
1415 | memset (buf, 0, len); | ||
1416 | |||
1417 | switch (serv->version) | ||
1418 | { | ||
1419 | case 4: | ||
1420 | prepare_ipv4_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, | ||
1421 | &serv->v4.ip4address, tunnel, state, | ||
1422 | (struct ip4_header *) buf); | ||
1423 | break; | ||
1424 | case 6: | ||
1425 | prepare_ipv6_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, | ||
1426 | &serv->v6.ip6address, tunnel, state, | ||
1427 | (struct ip6_header *) buf); | ||
1428 | |||
1429 | break; | ||
1430 | default: | ||
1431 | GNUNET_assert (0); | ||
1432 | break; | ||
1433 | } | ||
1434 | |||
1435 | hash_redirect_info (&state->hash, &state->redirect_info, | ||
1436 | serv->version == 4 ? 4 : 16); | ||
1437 | |||
1438 | if (GNUNET_NO == | ||
1439 | GNUNET_CONTAINER_multihashmap_contains (udp_connections, &state->hash)) | ||
1440 | { | ||
1441 | GNUNET_CONTAINER_multihashmap_put (udp_connections, &state->hash, state, | ||
1442 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
1443 | |||
1444 | state->heap_node = | ||
1445 | GNUNET_CONTAINER_heap_insert (udp_connections_heap, state, | ||
1446 | GNUNET_TIME_absolute_get ().abs_value); | ||
1447 | |||
1448 | if (GNUNET_CONTAINER_heap_get_size (udp_connections_heap) > | ||
1449 | max_udp_connections) | ||
1450 | GNUNET_SCHEDULER_add_now (collect_connections, udp_connections_heap); | ||
1451 | } | ||
1452 | else | ||
1453 | GNUNET_free (state); | ||
1454 | |||
1455 | (void) GNUNET_HELPER_send (helper_handle, | ||
1456 | (const struct GNUNET_MessageHeader*) buf, | ||
1457 | GNUNET_YES, | ||
1458 | NULL, NULL); | ||
1459 | #endif | ||
1460 | return GNUNET_YES; | ||
1461 | } | ||
1462 | |||
1463 | |||
1464 | |||
1465 | |||
1466 | |||
1467 | |||
1468 | |||
1469 | /** | ||
1470 | * Callback from GNUNET_MESH for new tunnels. | ||
1471 | * | ||
1472 | * @param cls closure | ||
1473 | * @param tunnel new handle to the tunnel | ||
1474 | * @param initiator peer that started the tunnel | ||
1475 | * @param atsi performance information for the tunnel | ||
1476 | * @return initial tunnel context for the tunnel | ||
1477 | */ | ||
1478 | static void * | ||
1479 | new_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
1480 | const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED, | ||
1481 | const struct GNUNET_ATS_Information *ats GNUNET_UNUSED) | ||
1482 | { | ||
1483 | struct tunnel_state *s = GNUNET_malloc (sizeof (struct tunnel_state)); | ||
1484 | |||
1485 | s->tunnel = tunnel; | ||
1486 | return s; | ||
1487 | } | ||
1488 | |||
1489 | |||
1490 | /** | ||
1491 | * Function called by mesh whenever an inbound tunnel is destroyed. | ||
1492 | * Should clean up any associated state. | ||
1493 | * | ||
1494 | * @param cls closure (set from GNUNET_MESH_connect) | ||
1495 | * @param tunnel connection to the other end (henceforth invalid) | ||
1496 | * @param tunnel_ctx place where local state associated | ||
1497 | * with the tunnel is stored | ||
1498 | */ | ||
1499 | static void | ||
1500 | clean_tunnel (void *cls GNUNET_UNUSED, const struct GNUNET_MESH_Tunnel *tunnel, | ||
1501 | void *tunnel_ctx) | ||
1502 | { | ||
1503 | struct tunnel_state *s = tunnel_ctx; | ||
1504 | struct tunnel_notify_queue *tnq; | ||
1505 | |||
1506 | while (NULL != (tnq = s->head)) | ||
1507 | { | ||
1508 | GNUNET_CONTAINER_DLL_remove (s->head, | ||
1509 | s->tail, | ||
1510 | tnq); | ||
1511 | GNUNET_free (tnq); | ||
1512 | } | ||
1513 | if (NULL != s->th) | ||
1514 | { | ||
1515 | GNUNET_MESH_notify_transmit_ready_cancel (s->th); | ||
1516 | s->th = NULL; | ||
1517 | } | ||
1518 | GNUNET_free (s); | ||
1519 | } | ||
1520 | |||
1521 | |||
1522 | /** | ||
1523 | * Function that frees everything from a hashmap | ||
1524 | * | ||
1525 | * @param cls unused | ||
1526 | * @param hash key | ||
1527 | * @param value value to free | ||
1528 | */ | ||
1529 | static int | ||
1530 | free_iterate (void *cls GNUNET_UNUSED, | ||
1531 | const GNUNET_HashCode * hash GNUNET_UNUSED, void *value) | ||
1532 | { | ||
1533 | GNUNET_free (value); | ||
1534 | return GNUNET_YES; | ||
1535 | } | ||
1536 | |||
1537 | |||
1538 | /** | ||
1539 | * Function scheduled as very last function, cleans up after us | ||
1540 | */ | ||
1541 | static void | ||
1542 | cleanup (void *cls GNUNET_UNUSED, | ||
1543 | const struct GNUNET_SCHEDULER_TaskContext *tskctx) | ||
1544 | { | ||
1545 | unsigned int i; | ||
1546 | |||
1547 | if (helper_handle != NULL) | ||
1548 | { | ||
1549 | GNUNET_HELPER_stop (helper_handle); | ||
1550 | helper_handle = NULL; | ||
1551 | } | ||
1552 | if (mesh_handle != NULL) | ||
1553 | { | ||
1554 | GNUNET_MESH_disconnect (mesh_handle); | ||
1555 | mesh_handle = NULL; | ||
1556 | } | ||
1557 | if (NULL != connections_map) | ||
1558 | { | ||
1559 | GNUNET_CONTAINER_multihashmap_iterate (connections_map, &free_iterate, NULL); | ||
1560 | GNUNET_CONTAINER_multihashmap_destroy (connections_map); | ||
1561 | connections_map = NULL; | ||
1562 | } | ||
1563 | if (NULL != connections_heap) | ||
1564 | { | ||
1565 | GNUNET_CONTAINER_heap_destroy (connections_heap); | ||
1566 | connections_heap = NULL; | ||
1567 | } | ||
1568 | if (NULL != tcp_services) | ||
1569 | { | ||
1570 | GNUNET_CONTAINER_multihashmap_iterate (tcp_services, &free_service_record, NULL); | ||
1571 | GNUNET_CONTAINER_multihashmap_destroy (tcp_services); | ||
1572 | tcp_services = NULL; | ||
1573 | } | ||
1574 | if (NULL != udp_services) | ||
1575 | { | ||
1576 | GNUNET_CONTAINER_multihashmap_iterate (udp_services, &free_service_record, NULL); | ||
1577 | GNUNET_CONTAINER_multihashmap_destroy (udp_services); | ||
1578 | udp_services = NULL; | ||
1579 | } | ||
1580 | for (i=0;i<5;i++) | ||
1581 | GNUNET_free_non_null (exit_argv[i]); | ||
1582 | } | ||
1583 | |||
1584 | |||
1585 | /** | ||
1586 | * Add services to the service map. | ||
1587 | * | ||
1588 | * @param proto IPPROTO_TCP or IPPROTO_UDP | ||
1589 | * @param cpy copy of the service descriptor (can be mutilated) | ||
1590 | * @param name DNS name of the service | ||
1591 | */ | ||
1592 | static void | ||
1593 | add_services (int proto, | ||
1594 | char *cpy, | ||
1595 | const char *name) | ||
1596 | { | ||
1597 | char *redirect; | ||
1598 | char *hostname; | ||
1599 | char *hostport; | ||
1600 | struct redirect_service *serv; | ||
1601 | |||
1602 | for (redirect = strtok (cpy, " "); redirect != NULL; | ||
1603 | redirect = strtok (NULL, " ")) | ||
1604 | { | ||
1605 | if (NULL == (hostname = strstr (redirect, ":"))) | ||
1606 | { | ||
1607 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1608 | "option `%s' for domain `%s' is not formatted correctly!\n", | ||
1609 | redirect, | ||
1610 | name); | ||
1611 | continue; | ||
1612 | } | ||
1613 | hostname[0] = '\0'; | ||
1614 | hostname++; | ||
1615 | if (NULL == (hostport = strstr (hostname, ":"))) | ||
1616 | { | ||
1617 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1618 | "option `%s' for domain `%s' is not formatted correctly!\n", | ||
1619 | redirect, | ||
1620 | name); | ||
1621 | continue; | ||
1622 | } | ||
1623 | hostport[0] = '\0'; | ||
1624 | hostport++; | ||
1625 | |||
1626 | int local_port = atoi (redirect); | ||
1627 | int remote_port = atoi (hostport); | ||
1628 | |||
1629 | if (!((local_port > 0) && (local_port < 65536))) | ||
1630 | { | ||
1631 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1632 | "`%s' is not a valid port number (for domain `%s')!", redirect, | ||
1633 | name); | ||
1634 | continue; | ||
1635 | } | ||
1636 | if (!((remote_port > 0) && (remote_port < 65536))) | ||
1637 | { | ||
1638 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1639 | "`%s' is not a valid port number (for domain `%s')!", hostport, | ||
1640 | name); | ||
1641 | continue; | ||
1642 | } | ||
1643 | |||
1644 | serv = GNUNET_malloc (sizeof (struct redirect_service)); | ||
1645 | serv->my_port = (uint16_t) local_port; | ||
1646 | serv->address.port = remote_port; | ||
1647 | if (0 == strcmp ("localhost4", hostname)) | ||
1648 | { | ||
1649 | const char *ip4addr = exit_argv[4]; | ||
1650 | |||
1651 | serv->address.af = AF_INET; | ||
1652 | GNUNET_assert (1 != inet_pton (AF_INET, ip4addr, &serv->address.address.ipv4)); | ||
1653 | } | ||
1654 | else if (0 == strcmp ("localhost6", hostname)) | ||
1655 | { | ||
1656 | const char *ip6addr = exit_argv[2]; | ||
1657 | |||
1658 | serv->address.af = AF_INET6; | ||
1659 | GNUNET_assert (1 == inet_pton (AF_INET6, ip6addr, &serv->address.address.ipv6)); | ||
1660 | } | ||
1661 | else | ||
1662 | { | ||
1663 | struct addrinfo *res; | ||
1664 | int ret; | ||
1665 | |||
1666 | ret = getaddrinfo (hostname, NULL, NULL, &res); | ||
1667 | if ( (ret != 0) || (res == NULL) ) | ||
1668 | { | ||
1669 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1670 | _("No addresses found for hostname `%s' of service `%s'!\n"), | ||
1671 | hostname, | ||
1672 | name); | ||
1673 | GNUNET_free (serv); | ||
1674 | continue; | ||
1675 | } | ||
1676 | |||
1677 | serv->address.af = res->ai_family; | ||
1678 | switch (res->ai_family) | ||
1679 | { | ||
1680 | case AF_INET: | ||
1681 | serv->address.address.ipv4 = ((struct sockaddr_in *) res->ai_addr)->sin_addr; | ||
1682 | break; | ||
1683 | case AF_INET6: | ||
1684 | serv->address.address.ipv6 = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; | ||
1685 | break; | ||
1686 | default: | ||
1687 | freeaddrinfo (res); | ||
1688 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1689 | _("No IP addresses found for hostname `%s' of service `%s'!\n"), | ||
1690 | hostname, | ||
1691 | name); | ||
1692 | GNUNET_free (serv); | ||
1693 | continue; | ||
1694 | } | ||
1695 | freeaddrinfo (res); | ||
1696 | } | ||
1697 | store_service ((IPPROTO_UDP == proto) ? udp_services : tcp_services, | ||
1698 | name, | ||
1699 | local_port, | ||
1700 | serv); | ||
1701 | } | ||
1702 | } | ||
1703 | |||
1704 | |||
1705 | /** | ||
1706 | * Reads the configuration servicecfg and populates udp_services | ||
1707 | * | ||
1708 | * @param cls unused | ||
1709 | * @param section name of section in config, equal to hostname | ||
1710 | */ | ||
1711 | static void | ||
1712 | read_service_conf (void *cls GNUNET_UNUSED, const char *section) | ||
1713 | { | ||
1714 | char *cpy; | ||
1715 | |||
1716 | if ((strlen (section) < 8) || | ||
1717 | (0 != strcmp (".gnunet.", section + (strlen (section) - 8)))) | ||
1718 | return; | ||
1719 | if (GNUNET_OK == | ||
1720 | GNUNET_CONFIGURATION_get_value_string (cfg, section, "UDP_REDIRECTS", | ||
1721 | &cpy)) | ||
1722 | { | ||
1723 | add_services (IPPROTO_UDP, cpy, section); | ||
1724 | GNUNET_free (cpy); | ||
1725 | } | ||
1726 | if (GNUNET_OK == | ||
1727 | GNUNET_CONFIGURATION_get_value_string (cfg, section, "TCP_REDIRECTS", | ||
1728 | &cpy)) | ||
1729 | { | ||
1730 | add_services (IPPROTO_TCP, cpy, section); | ||
1731 | GNUNET_free (cpy); | ||
1732 | } | ||
1733 | } | ||
1734 | |||
1735 | |||
1736 | /** | ||
1737 | * @brief Main function that will be run by the scheduler. | ||
1738 | * | ||
1739 | * @param cls closure | ||
1740 | * @param args remaining command-line arguments | ||
1741 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
1742 | * @param cfg_ configuration | ||
1743 | */ | ||
1744 | static void | ||
1745 | run (void *cls, char *const *args GNUNET_UNUSED, | ||
1746 | const char *cfgfile GNUNET_UNUSED, | ||
1747 | const struct GNUNET_CONFIGURATION_Handle *cfg_) | ||
1748 | { | ||
1749 | static struct GNUNET_MESH_MessageHandler handlers[] = { | ||
1750 | {&receive_udp_service, GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP, 0}, | ||
1751 | {&receive_tcp_service, GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP, 0}, | ||
1752 | {NULL, 0, 0}, | ||
1753 | {NULL, 0, 0}, | ||
1754 | {NULL, 0, 0} | ||
1755 | }; | ||
1756 | |||
1757 | static GNUNET_MESH_ApplicationType apptypes[] = { | ||
1758 | GNUNET_APPLICATION_TYPE_END, | ||
1759 | GNUNET_APPLICATION_TYPE_END, | ||
1760 | GNUNET_APPLICATION_TYPE_END | ||
1761 | }; | ||
1762 | unsigned int handler_idx; | ||
1763 | unsigned int app_idx; | ||
1764 | int udp; | ||
1765 | int tcp; | ||
1766 | char *ifname; | ||
1767 | char *ipv6addr; | ||
1768 | char *ipv6prefix_s; | ||
1769 | char *ipv4addr; | ||
1770 | char *ipv4mask; | ||
1771 | struct in_addr v4; | ||
1772 | struct in6_addr v6; | ||
1773 | |||
1774 | cfg = cfg_; | ||
1775 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); | ||
1776 | if (GNUNET_OK != | ||
1777 | GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "MAX_CONNECTIONS", | ||
1778 | &max_connections)) | ||
1779 | max_connections = 1024; | ||
1780 | exit_argv[0] = GNUNET_strdup ("exit-gnunet"); | ||
1781 | if (GNUNET_SYSERR == | ||
1782 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IFNAME", &ifname)) | ||
1783 | { | ||
1784 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1785 | "No entry 'IFNAME' in configuration!\n"); | ||
1786 | GNUNET_SCHEDULER_shutdown (); | ||
1787 | return; | ||
1788 | } | ||
1789 | exit_argv[1] = ifname; | ||
1790 | if ( (GNUNET_SYSERR == | ||
1791 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6ADDR", | ||
1792 | &ipv6addr) || | ||
1793 | (1 != inet_pton (AF_INET6, ipv6addr, &v6))) ) | ||
1794 | { | ||
1795 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1796 | "No valid entry 'IPV6ADDR' in configuration!\n"); | ||
1797 | GNUNET_SCHEDULER_shutdown (); | ||
1798 | return; | ||
1799 | } | ||
1800 | exit_argv[2] = ipv6addr; | ||
1801 | if (GNUNET_SYSERR == | ||
1802 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6PREFIX", | ||
1803 | &ipv6prefix_s)) | ||
1804 | { | ||
1805 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1806 | "No entry 'IPV6PREFIX' in configuration!\n"); | ||
1807 | GNUNET_SCHEDULER_shutdown (); | ||
1808 | return; | ||
1809 | } | ||
1810 | exit_argv[3] = ipv6prefix_s; | ||
1811 | if ( (GNUNET_OK != | ||
1812 | GNUNET_CONFIGURATION_get_value_number (cfg, "exit", | ||
1813 | "IPV6PREFIX", | ||
1814 | &ipv6prefix)) || | ||
1815 | (ipv6prefix >= 127) ) | ||
1816 | { | ||
1817 | GNUNET_SCHEDULER_shutdown (); | ||
1818 | return; | ||
1819 | } | ||
1820 | |||
1821 | if ( (GNUNET_SYSERR == | ||
1822 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4ADDR", | ||
1823 | &ipv4addr) || | ||
1824 | (1 != inet_pton (AF_INET, ipv4addr, &v4))) ) | ||
1825 | { | ||
1826 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1827 | "No valid entry for 'IPV4ADDR' in configuration!\n"); | ||
1828 | GNUNET_SCHEDULER_shutdown (); | ||
1829 | return; | ||
1830 | } | ||
1831 | exit_argv[4] = ipv4addr; | ||
1832 | if ( (GNUNET_SYSERR == | ||
1833 | GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4MASK", | ||
1834 | &ipv4mask) || | ||
1835 | (1 != inet_pton (AF_INET, ipv4mask, &v4))) ) | ||
1836 | { | ||
1837 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1838 | "No valid entry 'IPV4MASK' in configuration!\n"); | ||
1839 | GNUNET_SCHEDULER_shutdown (); | ||
1840 | return; | ||
1841 | } | ||
1842 | exit_argv[5] = ipv4mask; | ||
1843 | exit_argv[6] = NULL; | ||
1844 | |||
1845 | app_idx = 0; | ||
1846 | handler_idx = 2; | ||
1847 | udp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_UDP"); | ||
1848 | tcp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_TCP"); | ||
1849 | if (GNUNET_YES == udp) | ||
1850 | { | ||
1851 | handlers[handler_idx].callback = &receive_udp_remote; | ||
1852 | handlers[handler_idx].expected_size = 0; | ||
1853 | handlers[handler_idx].type = GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP; | ||
1854 | apptypes[app_idx] = GNUNET_APPLICATION_TYPE_INTERNET_UDP_GATEWAY; | ||
1855 | handler_idx++; | ||
1856 | app_idx++; | ||
1857 | } | ||
1858 | |||
1859 | if (GNUNET_YES == tcp) | ||
1860 | { | ||
1861 | handlers[handler_idx].callback = &receive_tcp_remote; | ||
1862 | handlers[handler_idx].expected_size = 0; | ||
1863 | handlers[handler_idx].type = GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP; | ||
1864 | apptypes[app_idx] = GNUNET_APPLICATION_TYPE_INTERNET_TCP_GATEWAY; | ||
1865 | handler_idx++; | ||
1866 | app_idx++; | ||
1867 | } | ||
1868 | udp_services = GNUNET_CONTAINER_multihashmap_create (65536); | ||
1869 | tcp_services = GNUNET_CONTAINER_multihashmap_create (65536); | ||
1870 | GNUNET_CONFIGURATION_iterate_sections (cfg, &read_service_conf, NULL); | ||
1871 | |||
1872 | connections_map = GNUNET_CONTAINER_multihashmap_create (65536); | ||
1873 | connections_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
1874 | mesh_handle | ||
1875 | = GNUNET_MESH_connect (cfg, 42 /* queue size */, NULL, | ||
1876 | &new_tunnel, | ||
1877 | &clean_tunnel, handlers, | ||
1878 | apptypes); | ||
1879 | if (NULL == mesh_handle) | ||
1880 | { | ||
1881 | GNUNET_SCHEDULER_shutdown (); | ||
1882 | return; | ||
1883 | } | ||
1884 | helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", | ||
1885 | exit_argv, | ||
1886 | &message_token, NULL); | ||
1887 | } | ||
1888 | |||
1889 | |||
1890 | /** | ||
1891 | * The main function | ||
1892 | * | ||
1893 | * @param argc number of arguments from the command line | ||
1894 | * @param argv command line arguments | ||
1895 | * @return 0 ok, 1 on error | ||
1896 | */ | ||
1897 | int | ||
1898 | main (int argc, char *const *argv) | ||
1899 | { | ||
1900 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
1901 | GNUNET_GETOPT_OPTION_END | ||
1902 | }; | ||
1903 | |||
1904 | return (GNUNET_OK == | ||
1905 | GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-exit", | ||
1906 | gettext_noop | ||
1907 | ("Daemon to run to provide an IP exit node for the VPN"), | ||
1908 | options, &run, NULL)) ? ret : 1; | ||
1909 | } | ||
1910 | |||
1911 | |||
1912 | /* end of gnunet-daemon-exit.c */ | ||
diff --git a/src/exit/gnunet-helper-exit.c b/src/exit/gnunet-helper-exit.c new file mode 100644 index 000000000..b93ce2382 --- /dev/null +++ b/src/exit/gnunet-helper-exit.c | |||
@@ -0,0 +1,596 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010 Christian Grothoff | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file vpn/gnunet-daemon-vpn.c | ||
23 | * @brief the helper for various vpn-daemons. Opens a virtual network-interface, | ||
24 | * sends data received on the if to stdout, sends data received on stdin to the | ||
25 | * interface | ||
26 | * @author Philipp Tölke | ||
27 | * | ||
28 | * The following list of people have reviewed this code and considered | ||
29 | * it safe since the last modification (if you reviewed it, please | ||
30 | * have your name added to the list): | ||
31 | * | ||
32 | * - Philipp Tölke | ||
33 | */ | ||
34 | #include "platform.h" | ||
35 | #include <linux/if_tun.h> | ||
36 | |||
37 | /** | ||
38 | * Need 'struct GNUNET_MessageHeader'. | ||
39 | */ | ||
40 | #include "gnunet_common.h" | ||
41 | |||
42 | /** | ||
43 | * Need VPN message types. | ||
44 | */ | ||
45 | #include "gnunet_protocols.h" | ||
46 | |||
47 | /** | ||
48 | * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
49 | */ | ||
50 | #define MAX_SIZE 65536 | ||
51 | |||
52 | #ifndef _LINUX_IN6_H | ||
53 | /** | ||
54 | * This is in linux/include/net/ipv6.h, but not always exported... | ||
55 | */ | ||
56 | struct in6_ifreq | ||
57 | { | ||
58 | struct in6_addr ifr6_addr; | ||
59 | uint32_t ifr6_prefixlen; | ||
60 | unsigned int ifr6_ifindex; | ||
61 | }; | ||
62 | #endif | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Creates a tun-interface called dev; | ||
67 | * | ||
68 | * @param dev is asumed to point to a char[IFNAMSIZ] | ||
69 | * if *dev == '\\0', uses the name supplied by the kernel; | ||
70 | * @return the fd to the tun or -1 on error | ||
71 | */ | ||
72 | static int | ||
73 | init_tun (char *dev) | ||
74 | { | ||
75 | struct ifreq ifr; | ||
76 | int fd; | ||
77 | |||
78 | if (NULL == dev) | ||
79 | { | ||
80 | errno = EINVAL; | ||
81 | return -1; | ||
82 | } | ||
83 | |||
84 | if (-1 == (fd = open ("/dev/net/tun", O_RDWR))) | ||
85 | { | ||
86 | fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun", | ||
87 | strerror (errno)); | ||
88 | return -1; | ||
89 | } | ||
90 | |||
91 | if (fd >= FD_SETSIZE) | ||
92 | { | ||
93 | fprintf (stderr, "File descriptor to large: %d", fd); | ||
94 | return -1; | ||
95 | } | ||
96 | |||
97 | memset (&ifr, 0, sizeof (ifr)); | ||
98 | ifr.ifr_flags = IFF_TUN; | ||
99 | |||
100 | if ('\0' != *dev) | ||
101 | strncpy (ifr.ifr_name, dev, IFNAMSIZ); | ||
102 | |||
103 | if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr)) | ||
104 | { | ||
105 | fprintf (stderr, "Error with ioctl on `%s': %s\n", "/dev/net/tun", | ||
106 | strerror (errno)); | ||
107 | (void) close (fd); | ||
108 | return -1; | ||
109 | } | ||
110 | strcpy (dev, ifr.ifr_name); | ||
111 | return fd; | ||
112 | } | ||
113 | |||
114 | |||
115 | /** | ||
116 | * @brief Sets the IPv6-Address given in address on the interface dev | ||
117 | * | ||
118 | * @param dev the interface to configure | ||
119 | * @param address the IPv6-Address | ||
120 | * @param prefix_len the length of the network-prefix | ||
121 | */ | ||
122 | static void | ||
123 | set_address6 (const char *dev, const char *address, unsigned long prefix_len) | ||
124 | { | ||
125 | struct ifreq ifr; | ||
126 | struct in6_ifreq ifr6; | ||
127 | struct sockaddr_in6 sa6; | ||
128 | int fd; | ||
129 | |||
130 | /* | ||
131 | * parse the new address | ||
132 | */ | ||
133 | memset (&sa6, 0, sizeof (struct sockaddr_in6)); | ||
134 | sa6.sin6_family = AF_INET6; | ||
135 | if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr)) | ||
136 | { | ||
137 | fprintf (stderr, "Failed to parse address `%s': %s\n", address, | ||
138 | strerror (errno)); | ||
139 | exit (1); | ||
140 | } | ||
141 | |||
142 | if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0))) | ||
143 | { | ||
144 | fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); | ||
145 | exit (1); | ||
146 | } | ||
147 | |||
148 | memset (&ifr, 0, sizeof (struct ifreq)); | ||
149 | /* | ||
150 | * Get the index of the if | ||
151 | */ | ||
152 | strncpy (ifr.ifr_name, dev, IFNAMSIZ); | ||
153 | if (-1 == ioctl (fd, SIOGIFINDEX, &ifr)) | ||
154 | { | ||
155 | fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); | ||
156 | (void) close (fd); | ||
157 | exit (1); | ||
158 | } | ||
159 | |||
160 | memset (&ifr6, 0, sizeof (struct in6_ifreq)); | ||
161 | ifr6.ifr6_addr = sa6.sin6_addr; | ||
162 | ifr6.ifr6_ifindex = ifr.ifr_ifindex; | ||
163 | ifr6.ifr6_prefixlen = prefix_len; | ||
164 | |||
165 | /* | ||
166 | * Set the address | ||
167 | */ | ||
168 | if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6)) | ||
169 | { | ||
170 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
171 | strerror (errno)); | ||
172 | (void) close (fd); | ||
173 | exit (1); | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Get the flags | ||
178 | */ | ||
179 | if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) | ||
180 | { | ||
181 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
182 | strerror (errno)); | ||
183 | (void) close (fd); | ||
184 | exit (1); | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * Add the UP and RUNNING flags | ||
189 | */ | ||
190 | ifr.ifr_flags |= IFF_UP | IFF_RUNNING; | ||
191 | if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) | ||
192 | { | ||
193 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
194 | strerror (errno)); | ||
195 | (void) close (fd); | ||
196 | exit (1); | ||
197 | } | ||
198 | |||
199 | if (0 != close (fd)) | ||
200 | { | ||
201 | fprintf (stderr, "close failed: %s\n", strerror (errno)); | ||
202 | exit (1); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | |||
207 | /** | ||
208 | * @brief Sets the IPv4-Address given in address on the interface dev | ||
209 | * | ||
210 | * @param dev the interface to configure | ||
211 | * @param address the IPv4-Address | ||
212 | * @param mask the netmask | ||
213 | */ | ||
214 | static void | ||
215 | set_address4 (const char *dev, const char *address, const char *mask) | ||
216 | { | ||
217 | int fd; | ||
218 | struct sockaddr_in *addr; | ||
219 | struct ifreq ifr; | ||
220 | |||
221 | memset (&ifr, 0, sizeof (struct ifreq)); | ||
222 | addr = (struct sockaddr_in *) &(ifr.ifr_addr); | ||
223 | addr->sin_family = AF_INET; | ||
224 | |||
225 | /* | ||
226 | * Parse the address | ||
227 | */ | ||
228 | if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr)) | ||
229 | { | ||
230 | fprintf (stderr, "Failed to parse address `%s': %s\n", address, | ||
231 | strerror (errno)); | ||
232 | exit (1); | ||
233 | } | ||
234 | |||
235 | if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0))) | ||
236 | { | ||
237 | fprintf (stderr, "Error creating socket: %s\n", strerror (errno)); | ||
238 | exit (1); | ||
239 | } | ||
240 | |||
241 | strncpy (ifr.ifr_name, dev, IFNAMSIZ); | ||
242 | |||
243 | /* | ||
244 | * Set the address | ||
245 | */ | ||
246 | if (-1 == ioctl (fd, SIOCSIFADDR, &ifr)) | ||
247 | { | ||
248 | fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno)); | ||
249 | (void) close (fd); | ||
250 | exit (1); | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * Parse the netmask | ||
255 | */ | ||
256 | addr = (struct sockaddr_in *) &(ifr.ifr_netmask); | ||
257 | if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr)) | ||
258 | { | ||
259 | fprintf (stderr, "Failed to parse address `%s': %s\n", mask, | ||
260 | strerror (errno)); | ||
261 | (void) close (fd); | ||
262 | exit (1); | ||
263 | } | ||
264 | |||
265 | /* | ||
266 | * Set the netmask | ||
267 | */ | ||
268 | if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr)) | ||
269 | { | ||
270 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
271 | strerror (errno)); | ||
272 | (void) close (fd); | ||
273 | exit (1); | ||
274 | } | ||
275 | |||
276 | /* | ||
277 | * Get the flags | ||
278 | */ | ||
279 | if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr)) | ||
280 | { | ||
281 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
282 | strerror (errno)); | ||
283 | (void) close (fd); | ||
284 | exit (1); | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Add the UP and RUNNING flags | ||
289 | */ | ||
290 | ifr.ifr_flags |= IFF_UP | IFF_RUNNING; | ||
291 | if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr)) | ||
292 | { | ||
293 | fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__, | ||
294 | strerror (errno)); | ||
295 | (void) close (fd); | ||
296 | exit (1); | ||
297 | } | ||
298 | |||
299 | if (0 != close (fd)) | ||
300 | { | ||
301 | fprintf (stderr, "close failed: %s\n", strerror (errno)); | ||
302 | (void) close (fd); | ||
303 | exit (1); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | |||
308 | /** | ||
309 | * Start forwarding to and from the tunnel. | ||
310 | * | ||
311 | * @param fd_tun tunnel FD | ||
312 | */ | ||
313 | static void | ||
314 | run (int fd_tun) | ||
315 | { | ||
316 | /* | ||
317 | * The buffer filled by reading from fd_tun | ||
318 | */ | ||
319 | unsigned char buftun[MAX_SIZE]; | ||
320 | ssize_t buftun_size = 0; | ||
321 | unsigned char *buftun_read = NULL; | ||
322 | |||
323 | /* | ||
324 | * The buffer filled by reading from stdin | ||
325 | */ | ||
326 | unsigned char bufin[MAX_SIZE]; | ||
327 | ssize_t bufin_size = 0; | ||
328 | size_t bufin_rpos = 0; | ||
329 | unsigned char *bufin_read = NULL; | ||
330 | |||
331 | fd_set fds_w; | ||
332 | fd_set fds_r; | ||
333 | |||
334 | /* read refers to reading from fd_tun, writing to stdout */ | ||
335 | int read_open = 1; | ||
336 | |||
337 | /* write refers to reading from stdin, writing to fd_tun */ | ||
338 | int write_open = 1; | ||
339 | |||
340 | while ((1 == read_open) || (1 == write_open)) | ||
341 | { | ||
342 | FD_ZERO (&fds_w); | ||
343 | FD_ZERO (&fds_r); | ||
344 | |||
345 | /* | ||
346 | * We are supposed to read and the buffer is empty | ||
347 | * -> select on read from tun | ||
348 | */ | ||
349 | if (read_open && (0 == buftun_size)) | ||
350 | FD_SET (fd_tun, &fds_r); | ||
351 | |||
352 | /* | ||
353 | * We are supposed to read and the buffer is not empty | ||
354 | * -> select on write to stdout | ||
355 | */ | ||
356 | if (read_open && (0 != buftun_size)) | ||
357 | FD_SET (1, &fds_w); | ||
358 | |||
359 | /* | ||
360 | * We are supposed to write and the buffer is empty | ||
361 | * -> select on read from stdin | ||
362 | */ | ||
363 | if (write_open && (NULL == bufin_read)) | ||
364 | FD_SET (0, &fds_r); | ||
365 | |||
366 | /* | ||
367 | * We are supposed to write and the buffer is not empty | ||
368 | * -> select on write to tun | ||
369 | */ | ||
370 | if (write_open && (NULL != bufin_read)) | ||
371 | FD_SET (fd_tun, &fds_w); | ||
372 | |||
373 | int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL); | ||
374 | |||
375 | if (-1 == r) | ||
376 | { | ||
377 | if (EINTR == errno) | ||
378 | continue; | ||
379 | fprintf (stderr, "select failed: %s\n", strerror (errno)); | ||
380 | exit (1); | ||
381 | } | ||
382 | |||
383 | if (r > 0) | ||
384 | { | ||
385 | if (FD_ISSET (fd_tun, &fds_r)) | ||
386 | { | ||
387 | buftun_size = | ||
388 | read (fd_tun, buftun + sizeof (struct GNUNET_MessageHeader), | ||
389 | MAX_SIZE - sizeof (struct GNUNET_MessageHeader)); | ||
390 | if (-1 == buftun_size) | ||
391 | { | ||
392 | fprintf (stderr, "read-error: %s\n", strerror (errno)); | ||
393 | shutdown (fd_tun, SHUT_RD); | ||
394 | shutdown (1, SHUT_WR); | ||
395 | read_open = 0; | ||
396 | buftun_size = 0; | ||
397 | } | ||
398 | else if (0 == buftun_size) | ||
399 | { | ||
400 | fprintf (stderr, "EOF on tun\n"); | ||
401 | shutdown (fd_tun, SHUT_RD); | ||
402 | shutdown (1, SHUT_WR); | ||
403 | read_open = 0; | ||
404 | buftun_size = 0; | ||
405 | } | ||
406 | else | ||
407 | { | ||
408 | buftun_read = buftun; | ||
409 | struct GNUNET_MessageHeader *hdr = | ||
410 | (struct GNUNET_MessageHeader *) buftun; | ||
411 | buftun_size += sizeof (struct GNUNET_MessageHeader); | ||
412 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
413 | hdr->size = htons (buftun_size); | ||
414 | } | ||
415 | } | ||
416 | else if (FD_ISSET (1, &fds_w)) | ||
417 | { | ||
418 | ssize_t written = write (1, buftun_read, buftun_size); | ||
419 | |||
420 | if (-1 == written) | ||
421 | { | ||
422 | fprintf (stderr, "write-error to stdout: %s\n", strerror (errno)); | ||
423 | shutdown (fd_tun, SHUT_RD); | ||
424 | shutdown (1, SHUT_WR); | ||
425 | read_open = 0; | ||
426 | buftun_size = 0; | ||
427 | } | ||
428 | else if (0 == written) | ||
429 | { | ||
430 | fprintf (stderr, "write returned 0!?\n"); | ||
431 | exit (1); | ||
432 | } | ||
433 | else | ||
434 | { | ||
435 | buftun_size -= written; | ||
436 | buftun_read += written; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | if (FD_ISSET (0, &fds_r)) | ||
441 | { | ||
442 | bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos); | ||
443 | if (-1 == bufin_size) | ||
444 | { | ||
445 | fprintf (stderr, "read-error: %s\n", strerror (errno)); | ||
446 | shutdown (0, SHUT_RD); | ||
447 | shutdown (fd_tun, SHUT_WR); | ||
448 | write_open = 0; | ||
449 | bufin_size = 0; | ||
450 | } | ||
451 | else if (0 == bufin_size) | ||
452 | { | ||
453 | fprintf (stderr, "EOF on stdin\n"); | ||
454 | shutdown (0, SHUT_RD); | ||
455 | shutdown (fd_tun, SHUT_WR); | ||
456 | write_open = 0; | ||
457 | bufin_size = 0; | ||
458 | } | ||
459 | else | ||
460 | { | ||
461 | struct GNUNET_MessageHeader *hdr; | ||
462 | |||
463 | PROCESS_BUFFER: | ||
464 | bufin_rpos += bufin_size; | ||
465 | if (bufin_rpos < sizeof (struct GNUNET_MessageHeader)) | ||
466 | continue; | ||
467 | hdr = (struct GNUNET_MessageHeader *) bufin; | ||
468 | if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) | ||
469 | { | ||
470 | fprintf (stderr, "protocol violation!\n"); | ||
471 | exit (1); | ||
472 | } | ||
473 | if (ntohs (hdr->size) > bufin_rpos) | ||
474 | continue; | ||
475 | bufin_read = bufin + sizeof (struct GNUNET_MessageHeader); | ||
476 | bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader); | ||
477 | bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader); | ||
478 | } | ||
479 | } | ||
480 | else if (FD_ISSET (fd_tun, &fds_w)) | ||
481 | { | ||
482 | ssize_t written = write (fd_tun, bufin_read, bufin_size); | ||
483 | |||
484 | if (-1 == written) | ||
485 | { | ||
486 | fprintf (stderr, "write-error to tun: %s\n", strerror (errno)); | ||
487 | shutdown (0, SHUT_RD); | ||
488 | shutdown (fd_tun, SHUT_WR); | ||
489 | write_open = 0; | ||
490 | bufin_size = 0; | ||
491 | } | ||
492 | else if (0 == written) | ||
493 | { | ||
494 | fprintf (stderr, "write returned 0!?\n"); | ||
495 | exit (1); | ||
496 | } | ||
497 | else | ||
498 | { | ||
499 | bufin_size -= written; | ||
500 | bufin_read += written; | ||
501 | if (0 == bufin_size) | ||
502 | { | ||
503 | memmove (bufin, bufin_read, bufin_rpos); | ||
504 | bufin_read = NULL; /* start reading again */ | ||
505 | bufin_size = 0; | ||
506 | goto PROCESS_BUFFER; | ||
507 | } | ||
508 | } | ||
509 | } | ||
510 | } | ||
511 | } | ||
512 | } | ||
513 | |||
514 | |||
515 | /** | ||
516 | * Open VPN tunnel interface. | ||
517 | * | ||
518 | * @param argc must be 6 | ||
519 | * @param argv 0: binary name (gnunet-helper-vpn) | ||
520 | * 1: tunnel interface name (gnunet-vpn) | ||
521 | * 2: IPv6 address (::1) | ||
522 | * 3: IPv6 netmask length in bits (64) | ||
523 | * 4: IPv4 address (1.2.3.4) | ||
524 | * 5: IPv4 netmask (255.255.0.0) | ||
525 | */ | ||
526 | int | ||
527 | main (int argc, char **argv) | ||
528 | { | ||
529 | char dev[IFNAMSIZ]; | ||
530 | int fd_tun; | ||
531 | int global_ret; | ||
532 | |||
533 | if (6 != argc) | ||
534 | { | ||
535 | fprintf (stderr, "Fatal: must supply 5 arguments!\n"); | ||
536 | return 1; | ||
537 | } | ||
538 | |||
539 | strncpy (dev, argv[1], IFNAMSIZ); | ||
540 | dev[IFNAMSIZ - 1] = '\0'; | ||
541 | |||
542 | if (-1 == (fd_tun = init_tun (dev))) | ||
543 | { | ||
544 | fprintf (stderr, "Fatal: could not initialize tun-interface\n"); | ||
545 | return 1; | ||
546 | } | ||
547 | |||
548 | { | ||
549 | const char *address = argv[2]; | ||
550 | long prefix_len = atol (argv[3]); | ||
551 | |||
552 | if ((prefix_len < 1) || (prefix_len > 127)) | ||
553 | { | ||
554 | fprintf (stderr, "Fatal: prefix_len out of range\n"); | ||
555 | return 1; | ||
556 | } | ||
557 | |||
558 | set_address6 (dev, address, prefix_len); | ||
559 | } | ||
560 | |||
561 | { | ||
562 | const char *address = argv[4]; | ||
563 | const char *mask = argv[5]; | ||
564 | |||
565 | set_address4 (dev, address, mask); | ||
566 | } | ||
567 | |||
568 | uid_t uid = getuid (); | ||
569 | #ifdef HAVE_SETRESUID | ||
570 | if (0 != setresuid (uid, uid, uid)) | ||
571 | { | ||
572 | fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); | ||
573 | global_ret = 2; | ||
574 | goto cleanup; | ||
575 | } | ||
576 | #else | ||
577 | if (0 != (setuid (uid) | seteuid (uid))) | ||
578 | { | ||
579 | fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); | ||
580 | global_ret = 2; | ||
581 | goto cleanup; | ||
582 | } | ||
583 | #endif | ||
584 | |||
585 | if (SIG_ERR == signal (SIGPIPE, SIG_IGN)) | ||
586 | { | ||
587 | fprintf (stderr, "Failed to protect against SIGPIPE: %s\n", | ||
588 | strerror (errno)); | ||
589 | /* no exit, we might as well die with SIGPIPE should it ever happen */ | ||
590 | } | ||
591 | run (fd_tun); | ||
592 | global_ret = 0; | ||
593 | cleanup: | ||
594 | close (fd_tun); | ||
595 | return global_ret; | ||
596 | } | ||
diff --git a/src/vpn/vpn.conf b/src/vpn/vpn.conf index 7b7ff2788..149a25703 100644 --- a/src/vpn/vpn.conf +++ b/src/vpn/vpn.conf | |||
@@ -9,14 +9,3 @@ VIRTDNS = 10.11.10.2 | |||
9 | VIRTDNS6 = 1234::17 | 9 | VIRTDNS6 = 1234::17 |
10 | IFNAME = vpn-gnunet | 10 | IFNAME = vpn-gnunet |
11 | 11 | ||
12 | [exit] | ||
13 | CONFIG = $DEFAULTCONFIG | ||
14 | BINARY = gnunet-daemon-exit | ||
15 | IPV6ADDR = 1234:1::1 | ||
16 | IPV6PREFIX = 32 | ||
17 | IPV4ADDR = 10.10.1.1 | ||
18 | IPV4MASK = 255.255.0.0 | ||
19 | IFNAME = exit-gnunet | ||
20 | ENABLE_UDP = NO | ||
21 | ENABLE_TCP = NO | ||
22 | |||