diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-01-06 23:18:26 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-01-06 23:18:26 +0000 |
commit | f07938e02ddc22a8c61e26f0a81d7dc4d5c814b4 (patch) | |
tree | 5589a378f0ccf79e1f09e49f2e0ecaa77fa27f4e /src/vpn | |
parent | 9e4ffd173145ed63e458a6f3c1dbe80c3ff43da6 (diff) | |
download | gnunet-f07938e02ddc22a8c61e26f0a81d7dc4d5c814b4.tar.gz gnunet-f07938e02ddc22a8c61e26f0a81d7dc4d5c814b4.zip |
-importing from gnunet-daemon-vpn to gnunet-service-vpn what can likely be re-used
Diffstat (limited to 'src/vpn')
-rw-r--r-- | src/vpn/Makefile.am | 10 | ||||
-rw-r--r-- | src/vpn/gnunet-service-vpn.c | 1340 |
2 files changed, 1349 insertions, 1 deletions
diff --git a/src/vpn/Makefile.am b/src/vpn/Makefile.am index 1fb1dd3f6..380db4446 100644 --- a/src/vpn/Makefile.am +++ b/src/vpn/Makefile.am | |||
@@ -26,7 +26,7 @@ endif | |||
26 | 26 | ||
27 | 27 | ||
28 | bin_PROGRAMS = \ | 28 | bin_PROGRAMS = \ |
29 | gnunet-daemon-exit gnunet-daemon-vpn $(VPNBIN) $(HIJACKBIN) | 29 | gnunet-daemon-exit gnunet-daemon-vpn $(VPNBIN) gnunet-service-vpn |
30 | 30 | ||
31 | 31 | ||
32 | gnunet_helper_vpn_SOURCES = \ | 32 | gnunet_helper_vpn_SOURCES = \ |
@@ -43,6 +43,14 @@ gnunet_daemon_vpn_LDADD = \ | |||
43 | $(top_builddir)/src/dns/libgnunetdns.la \ | 43 | $(top_builddir)/src/dns/libgnunetdns.la \ |
44 | $(GN_LIBINTL) | 44 | $(GN_LIBINTL) |
45 | 45 | ||
46 | gnunet_service_vpn_SOURCES = \ | ||
47 | gnunet-service-vpn.c | ||
48 | gnunet_service_vpn_LDADD = \ | ||
49 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
50 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
51 | $(top_builddir)/src/mesh/libgnunetmesh.la \ | ||
52 | $(GN_LIBINTL) | ||
53 | |||
46 | gnunet_daemon_exit_SOURCES = \ | 54 | gnunet_daemon_exit_SOURCES = \ |
47 | gnunet-daemon-exit.c | 55 | gnunet-daemon-exit.c |
48 | gnunet_daemon_exit_LDADD = \ | 56 | gnunet_daemon_exit_LDADD = \ |
diff --git a/src/vpn/gnunet-service-vpn.c b/src/vpn/gnunet-service-vpn.c new file mode 100644 index 000000000..098d8b944 --- /dev/null +++ b/src/vpn/gnunet-service-vpn.c | |||
@@ -0,0 +1,1340 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010, 2011, 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 vpn/gnunet-service-vpn.c | ||
23 | * @brief service that opens a virtual interface and allows its clients | ||
24 | * to allocate IPs on the virtual interface and to then redirect | ||
25 | * IP traffic received on those IPs via the GNUnet mesh | ||
26 | * @author Philipp Toelke | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet-vpn-packet.h" | ||
31 | #include "gnunet_common.h" | ||
32 | #include "gnunet_protocols.h" | ||
33 | #include "gnunet_applications.h" | ||
34 | #include "gnunet_mesh_service.h" | ||
35 | #include "gnunet_constants.h" | ||
36 | |||
37 | |||
38 | |||
39 | struct map_entry | ||
40 | { | ||
41 | /** The description of the service (used for service) */ | ||
42 | GNUNET_HashCode desc; | ||
43 | |||
44 | /** The real address of the service (used for remote) */ | ||
45 | char addrlen; | ||
46 | char addr[16]; | ||
47 | |||
48 | struct GNUNET_MESH_Tunnel *tunnel; | ||
49 | uint16_t namelen; | ||
50 | char additional_ports[8192]; | ||
51 | |||
52 | struct GNUNET_CONTAINER_HeapNode *heap_node; | ||
53 | GNUNET_HashCode hash; | ||
54 | |||
55 | }; | ||
56 | |||
57 | |||
58 | struct remote_addr | ||
59 | { | ||
60 | char addrlen; | ||
61 | unsigned char addr[16]; | ||
62 | char proto; | ||
63 | }; | ||
64 | |||
65 | |||
66 | struct tunnel_notify_queue | ||
67 | { | ||
68 | struct tunnel_notify_queue *next; | ||
69 | struct tunnel_notify_queue *prev; | ||
70 | size_t len; | ||
71 | void *cls; | ||
72 | }; | ||
73 | |||
74 | |||
75 | struct tunnel_state | ||
76 | { | ||
77 | struct GNUNET_MESH_TransmitHandle *th; | ||
78 | struct tunnel_notify_queue *head, *tail; | ||
79 | |||
80 | int addrlen; | ||
81 | }; | ||
82 | |||
83 | |||
84 | |||
85 | /** | ||
86 | * Configuration we use. | ||
87 | */ | ||
88 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
89 | |||
90 | /** | ||
91 | * Handle to the mesh service. | ||
92 | */ | ||
93 | static struct GNUNET_MESH_Handle *mesh_handle; | ||
94 | |||
95 | /** | ||
96 | * FIXME | ||
97 | */ | ||
98 | static struct GNUNET_CONTAINER_MultiHashMap *hashmap; | ||
99 | |||
100 | /** | ||
101 | * FIXME | ||
102 | */ | ||
103 | static struct GNUNET_CONTAINER_Heap *heap; | ||
104 | |||
105 | /** | ||
106 | * The handle to the VPN helper process "gnunet-helper-vpn". | ||
107 | */ | ||
108 | static struct GNUNET_HELPER_Handle *helper_handle; | ||
109 | |||
110 | /** | ||
111 | * Arguments to the exit helper. | ||
112 | */ | ||
113 | static char *vpn_argv[7]; | ||
114 | |||
115 | /** | ||
116 | * If there are at least this many address-mappings, old ones will be removed | ||
117 | */ | ||
118 | static unsigned long long max_mappings; | ||
119 | |||
120 | |||
121 | /** | ||
122 | * @return the hash of the IP-Address if a mapping exists, NULL otherwise | ||
123 | */ | ||
124 | static GNUNET_HashCode * | ||
125 | address6_mapping_exists (struct in6_addr *v6addr) | ||
126 | { | ||
127 | unsigned char *addr = (unsigned char*) v6addr; | ||
128 | GNUNET_HashCode *key = GNUNET_malloc (sizeof (GNUNET_HashCode)); | ||
129 | unsigned char *k = (unsigned char *) key; | ||
130 | |||
131 | memset (key, 0, sizeof (GNUNET_HashCode)); | ||
132 | unsigned int i; | ||
133 | |||
134 | for (i = 0; i < 16; i++) | ||
135 | k[15 - i] = addr[i]; | ||
136 | |||
137 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (hashmap, key)) | ||
138 | return key; | ||
139 | else | ||
140 | { | ||
141 | GNUNET_free (key); | ||
142 | return NULL; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | /** | ||
147 | * @return the hash of the IP-Address if a mapping exists, NULL otherwise | ||
148 | */ | ||
149 | static GNUNET_HashCode * | ||
150 | address4_mapping_exists (uint32_t addr) | ||
151 | { | ||
152 | GNUNET_HashCode *key = GNUNET_malloc (sizeof (GNUNET_HashCode)); | ||
153 | |||
154 | memset (key, 0, sizeof (GNUNET_HashCode)); | ||
155 | unsigned char *c = (unsigned char *) &addr; | ||
156 | unsigned char *k = (unsigned char *) key; | ||
157 | unsigned int i; | ||
158 | |||
159 | for (i = 0; i < 4; i++) | ||
160 | k[3 - i] = c[i]; | ||
161 | |||
162 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
163 | "a4_m_e: getting with key %08x, addr is %08x, %d.%d.%d.%d\n", | ||
164 | *((uint32_t *) (key)), addr, c[0], c[1], c[2], c[3]); | ||
165 | |||
166 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (hashmap, key)) | ||
167 | return key; | ||
168 | else | ||
169 | { | ||
170 | GNUNET_free (key); | ||
171 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mapping not found!\n"); | ||
172 | return NULL; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | |||
177 | static void * | ||
178 | initialize_tunnel_state (int addrlen, struct GNUNET_MESH_TransmitHandle *th) | ||
179 | { | ||
180 | struct tunnel_state *ts = GNUNET_malloc (sizeof *ts); | ||
181 | |||
182 | ts->addrlen = addrlen; | ||
183 | ts->th = th; | ||
184 | return ts; | ||
185 | } | ||
186 | |||
187 | |||
188 | static void | ||
189 | send_icmp4_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
190 | { | ||
191 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
192 | return; | ||
193 | |||
194 | struct ip_icmp *request = cls; | ||
195 | |||
196 | struct ip_icmp *response = alloca (ntohs (request->shdr.size)); | ||
197 | |||
198 | GNUNET_assert (response != NULL); | ||
199 | memset (response, 0, ntohs (request->shdr.size)); | ||
200 | |||
201 | response->shdr.size = request->shdr.size; | ||
202 | response->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
203 | |||
204 | response->tun.flags = 0; | ||
205 | response->tun.type = htons (0x0800); | ||
206 | |||
207 | response->ip_hdr.hdr_lngth = 5; | ||
208 | response->ip_hdr.version = 4; | ||
209 | response->ip_hdr.proto = 0x01; | ||
210 | response->ip_hdr.dadr = request->ip_hdr.sadr; | ||
211 | response->ip_hdr.sadr = request->ip_hdr.dadr; | ||
212 | response->ip_hdr.tot_lngth = request->ip_hdr.tot_lngth; | ||
213 | |||
214 | response->ip_hdr.chks = | ||
215 | GNUNET_CRYPTO_crc16_n ((uint16_t *) & response->ip_hdr, 20); | ||
216 | |||
217 | response->icmp_hdr.code = 0; | ||
218 | response->icmp_hdr.type = 0x0; | ||
219 | |||
220 | /* Magic, more Magic! */ | ||
221 | response->icmp_hdr.chks = request->icmp_hdr.chks + 0x8; | ||
222 | |||
223 | /* Copy the rest of the packet */ | ||
224 | memcpy (response + 1, request + 1, | ||
225 | ntohs (request->shdr.size) - sizeof (struct ip_icmp)); | ||
226 | |||
227 | (void) GNUNET_HELPER_send (helper_handle, | ||
228 | &response->shdr, | ||
229 | GNUNET_YES, | ||
230 | NULL, NULL); | ||
231 | GNUNET_free (request); | ||
232 | } | ||
233 | |||
234 | |||
235 | static void | ||
236 | send_icmp6_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
237 | { | ||
238 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
239 | return; | ||
240 | |||
241 | struct ip6_icmp *request = cls; | ||
242 | |||
243 | struct ip6_icmp *response = alloca (ntohs (request->shdr.size)); | ||
244 | |||
245 | GNUNET_assert (response != NULL); | ||
246 | memset (response, 0, ntohs (request->shdr.size)); | ||
247 | |||
248 | response->shdr.size = request->shdr.size; | ||
249 | response->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
250 | |||
251 | response->tun.flags = 0; | ||
252 | response->tun.type = htons (0x86dd); | ||
253 | |||
254 | response->ip6_hdr.hoplmt = 255; | ||
255 | response->ip6_hdr.paylgth = request->ip6_hdr.paylgth; | ||
256 | response->ip6_hdr.nxthdr = 0x3a; | ||
257 | response->ip6_hdr.version = 6; | ||
258 | memcpy (&response->ip6_hdr.sadr, &request->ip6_hdr.dadr, 16); | ||
259 | memcpy (&response->ip6_hdr.dadr, &request->ip6_hdr.sadr, 16); | ||
260 | |||
261 | response->icmp_hdr.code = 0; | ||
262 | response->icmp_hdr.type = 0x81; | ||
263 | |||
264 | /* Magic, more Magic! */ | ||
265 | response->icmp_hdr.chks = request->icmp_hdr.chks - 0x1; | ||
266 | |||
267 | /* Copy the rest of the packet */ | ||
268 | memcpy (response + 1, request + 1, | ||
269 | ntohs (request->shdr.size) - sizeof (struct ip6_icmp)); | ||
270 | |||
271 | (void) GNUNET_HELPER_send (helper_handle, | ||
272 | &response->shdr, | ||
273 | GNUNET_YES, | ||
274 | NULL, NULL); | ||
275 | GNUNET_free (request); | ||
276 | } | ||
277 | |||
278 | |||
279 | /** | ||
280 | * cls is the pointer to a GNUNET_MessageHeader that is | ||
281 | * followed by the service-descriptor and the packet that should be sent; | ||
282 | */ | ||
283 | static size_t | ||
284 | send_pkt_to_peer_notify_callback (void *cls, size_t size, void *buf) | ||
285 | { | ||
286 | struct GNUNET_MESH_Tunnel **tunnel = cls; | ||
287 | |||
288 | struct tunnel_state *ts = GNUNET_MESH_tunnel_get_data (*tunnel); | ||
289 | |||
290 | ts->th = NULL; | ||
291 | |||
292 | if (NULL != buf) | ||
293 | { | ||
294 | struct GNUNET_MessageHeader *hdr = | ||
295 | (struct GNUNET_MessageHeader *) (tunnel + 1); | ||
296 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
297 | "send_pkt_to_peer_notify_callback: buf = %x; size = %u;\n", buf, | ||
298 | size); | ||
299 | GNUNET_assert (size >= ntohs (hdr->size)); | ||
300 | memcpy (buf, hdr, ntohs (hdr->size)); | ||
301 | size = ntohs (hdr->size); | ||
302 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent!\n"); | ||
303 | } | ||
304 | else | ||
305 | size = 0; | ||
306 | |||
307 | if (NULL != ts->head) | ||
308 | { | ||
309 | struct tunnel_notify_queue *element = ts->head; | ||
310 | |||
311 | GNUNET_CONTAINER_DLL_remove (ts->head, ts->tail, element); | ||
312 | |||
313 | ts->th = | ||
314 | GNUNET_MESH_notify_transmit_ready (*tunnel, GNUNET_NO, 42, | ||
315 | GNUNET_TIME_relative_divide | ||
316 | (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), | ||
317 | (const struct GNUNET_PeerIdentity *) | ||
318 | NULL, element->len, | ||
319 | send_pkt_to_peer_notify_callback, | ||
320 | element->cls); | ||
321 | |||
322 | /* save the handle */ | ||
323 | GNUNET_free (element); | ||
324 | } | ||
325 | GNUNET_free (cls); | ||
326 | |||
327 | return size; | ||
328 | } | ||
329 | |||
330 | |||
331 | static void | ||
332 | send_pkt_to_peer (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
333 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
334 | { | ||
335 | /* peer == NULL means that all peers in this request are connected */ | ||
336 | if (peer == NULL) | ||
337 | return; | ||
338 | struct GNUNET_MESH_Tunnel **tunnel = cls; | ||
339 | struct GNUNET_MessageHeader *hdr = | ||
340 | (struct GNUNET_MessageHeader *) (tunnel + 1); | ||
341 | |||
342 | GNUNET_assert (NULL != tunnel); | ||
343 | GNUNET_assert (NULL != *tunnel); | ||
344 | |||
345 | struct tunnel_state *ts = GNUNET_MESH_tunnel_get_data (*tunnel); | ||
346 | |||
347 | if (NULL == ts->th) | ||
348 | { | ||
349 | ts->th = | ||
350 | GNUNET_MESH_notify_transmit_ready (*tunnel, GNUNET_NO, 42, | ||
351 | GNUNET_TIME_relative_divide | ||
352 | (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), | ||
353 | (const struct GNUNET_PeerIdentity *) | ||
354 | NULL, ntohs (hdr->size), | ||
355 | send_pkt_to_peer_notify_callback, | ||
356 | cls); | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | struct tunnel_notify_queue *element = GNUNET_malloc (sizeof *element); | ||
361 | |||
362 | element->cls = cls; | ||
363 | element->len = ntohs (hdr->size); | ||
364 | |||
365 | GNUNET_CONTAINER_DLL_insert_tail (ts->head, ts->tail, element); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | |||
370 | |||
371 | |||
372 | /** | ||
373 | * Receive packets from the helper-process | ||
374 | */ | ||
375 | static void | ||
376 | message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED, | ||
377 | const struct GNUNET_MessageHeader *message) | ||
378 | { | ||
379 | GNUNET_assert (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
380 | |||
381 | struct tun_pkt *pkt_tun = (struct tun_pkt *) message; | ||
382 | GNUNET_HashCode *key; | ||
383 | |||
384 | /* ethertype is ipv6 */ | ||
385 | if (ntohs (pkt_tun->tun.type) == 0x86dd) | ||
386 | { | ||
387 | struct ip6_pkt *pkt6 = (struct ip6_pkt *) message; | ||
388 | |||
389 | GNUNET_assert (pkt6->ip6_hdr.version == 6); | ||
390 | struct ip6_tcp *pkt6_tcp; | ||
391 | struct ip6_udp *pkt6_udp; | ||
392 | struct ip6_icmp *pkt6_icmp; | ||
393 | |||
394 | pkt6_udp = NULL; /* make compiler happy */ | ||
395 | switch (pkt6->ip6_hdr.nxthdr) | ||
396 | { | ||
397 | case IPPROTO_UDP: | ||
398 | pkt6_udp = (struct ip6_udp *) pkt6; | ||
399 | /* Send dns-packets to the service-dns */ | ||
400 | /* fall through */ | ||
401 | case IPPROTO_TCP: | ||
402 | pkt6_tcp = (struct ip6_tcp *) pkt6; | ||
403 | |||
404 | if ((key = address6_mapping_exists (&pkt6->ip6_hdr.dadr)) != NULL) | ||
405 | { | ||
406 | struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
407 | |||
408 | GNUNET_assert (me != NULL); | ||
409 | GNUNET_free (key); | ||
410 | |||
411 | size_t size = | ||
412 | sizeof (struct GNUNET_MESH_Tunnel *) + | ||
413 | sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + | ||
414 | ntohs (pkt6->ip6_hdr.paylgth); | ||
415 | |||
416 | struct GNUNET_MESH_Tunnel **cls = GNUNET_malloc (size); | ||
417 | struct GNUNET_MessageHeader *hdr = | ||
418 | (struct GNUNET_MessageHeader *) (cls + 1); | ||
419 | GNUNET_HashCode *hc = (GNUNET_HashCode *) (hdr + 1); | ||
420 | |||
421 | hdr->size = | ||
422 | htons (sizeof (struct GNUNET_MessageHeader) + | ||
423 | sizeof (GNUNET_HashCode) + ntohs (pkt6->ip6_hdr.paylgth)); | ||
424 | |||
425 | GNUNET_MESH_ApplicationType app_type = 0; /* fix compiler uninitialized warning... */ | ||
426 | |||
427 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "me->addrlen is %d\n", | ||
428 | me->addrlen); | ||
429 | if (me->addrlen == 0) | ||
430 | { | ||
431 | /* This is a mapping to a gnunet-service */ | ||
432 | *hc = me->desc; | ||
433 | |||
434 | if (me->tunnel == NULL && NULL != cls) | ||
435 | { | ||
436 | *cls = | ||
437 | GNUNET_MESH_tunnel_create (mesh_handle, | ||
438 | initialize_tunnel_state (16, NULL), | ||
439 | &send_pkt_to_peer, NULL, cls); | ||
440 | |||
441 | GNUNET_MESH_peer_request_connect_add (*cls, | ||
442 | (struct GNUNET_PeerIdentity *) | ||
443 | &me->desc); | ||
444 | me->tunnel = *cls; | ||
445 | } | ||
446 | else if (NULL != cls) | ||
447 | { | ||
448 | *cls = me->tunnel; | ||
449 | send_pkt_to_peer (cls, (struct GNUNET_PeerIdentity *) 1, NULL); | ||
450 | } | ||
451 | } | ||
452 | else | ||
453 | { | ||
454 | /* This is a mapping to a "real" address */ | ||
455 | struct remote_addr *s = (struct remote_addr *) hc; | ||
456 | |||
457 | s->addrlen = me->addrlen; | ||
458 | memcpy (s->addr, me->addr, me->addrlen); | ||
459 | s->proto = pkt6->ip6_hdr.nxthdr; | ||
460 | if (s->proto == IPPROTO_UDP) | ||
461 | { | ||
462 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP); | ||
463 | memcpy (hc + 1, &pkt6_udp->udp_hdr, ntohs (pkt6_udp->udp_hdr.len)); | ||
464 | app_type = GNUNET_APPLICATION_TYPE_INTERNET_UDP_GATEWAY; | ||
465 | } | ||
466 | else if (s->proto == IPPROTO_TCP) | ||
467 | { | ||
468 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP); | ||
469 | memcpy (hc + 1, &pkt6_tcp->tcp_hdr, ntohs (pkt6->ip6_hdr.paylgth)); | ||
470 | app_type = GNUNET_APPLICATION_TYPE_INTERNET_TCP_GATEWAY; | ||
471 | } | ||
472 | else | ||
473 | { | ||
474 | GNUNET_assert (0); | ||
475 | } | ||
476 | if (me->tunnel == NULL && NULL != cls) | ||
477 | { | ||
478 | *cls = | ||
479 | GNUNET_MESH_tunnel_create (mesh_handle, | ||
480 | initialize_tunnel_state (16, NULL), | ||
481 | &send_pkt_to_peer, NULL, cls); | ||
482 | |||
483 | GNUNET_MESH_peer_request_connect_by_type (*cls, app_type); | ||
484 | me->tunnel = *cls; | ||
485 | } | ||
486 | else if (NULL != cls) | ||
487 | { | ||
488 | *cls = me->tunnel; | ||
489 | send_pkt_to_peer (cls, (struct GNUNET_PeerIdentity *) 1, NULL); | ||
490 | } | ||
491 | } | ||
492 | } | ||
493 | else | ||
494 | { | ||
495 | char pbuf[INET6_ADDRSTRLEN]; | ||
496 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
497 | "Packet to %s, which has no mapping\n", | ||
498 | inet_ntop (AF_INET6, | ||
499 | &pkt6->ip6_hdr.dadr, | ||
500 | pbuf, | ||
501 | sizeof (pbuf))); | ||
502 | } | ||
503 | break; | ||
504 | case 0x3a: | ||
505 | /* ICMPv6 */ | ||
506 | pkt6_icmp = (struct ip6_icmp *) pkt6; | ||
507 | /* If this packet is an icmp-echo-request and a mapping exists, answer */ | ||
508 | if (pkt6_icmp->icmp_hdr.type == 0x80 && | ||
509 | (key = address6_mapping_exists (&pkt6->ip6_hdr.dadr)) != NULL) | ||
510 | { | ||
511 | GNUNET_free (key); | ||
512 | pkt6_icmp = GNUNET_malloc (ntohs (pkt6->shdr.size)); | ||
513 | memcpy (pkt6_icmp, pkt6, ntohs (pkt6->shdr.size)); | ||
514 | GNUNET_SCHEDULER_add_now (&send_icmp6_response, pkt6_icmp); | ||
515 | } | ||
516 | break; | ||
517 | } | ||
518 | } | ||
519 | /* ethertype is ipv4 */ | ||
520 | else if (ntohs (pkt_tun->tun.type) == 0x0800) | ||
521 | { | ||
522 | struct ip_pkt *pkt = (struct ip_pkt *) message; | ||
523 | //struct ip_udp *udp = (struct ip_udp *) message; | ||
524 | struct ip_tcp *pkt_tcp; | ||
525 | struct ip_udp *pkt_udp; | ||
526 | struct ip_icmp *pkt_icmp; | ||
527 | |||
528 | GNUNET_assert (pkt->ip_hdr.version == 4); | ||
529 | |||
530 | { | ||
531 | uint32_t dadr = pkt->ip_hdr.dadr.s_addr; | ||
532 | unsigned char *c = (unsigned char *) &dadr; | ||
533 | |||
534 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Packet to %d.%d.%d.%d, proto %x\n", | ||
535 | c[0], c[1], c[2], c[3], pkt->ip_hdr.proto); | ||
536 | switch (pkt->ip_hdr.proto) | ||
537 | { | ||
538 | case IPPROTO_TCP: | ||
539 | case IPPROTO_UDP: | ||
540 | pkt_tcp = (struct ip_tcp *) pkt; | ||
541 | pkt_udp = (struct ip_udp *) pkt; | ||
542 | |||
543 | if ((key = address4_mapping_exists (dadr)) != NULL) | ||
544 | { | ||
545 | struct map_entry *me = | ||
546 | GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
547 | GNUNET_assert (me != NULL); | ||
548 | GNUNET_free (key); | ||
549 | |||
550 | size_t size = | ||
551 | sizeof (struct GNUNET_MESH_Tunnel *) + | ||
552 | sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + | ||
553 | ntohs (pkt->ip_hdr.tot_lngth) - 4 * pkt->ip_hdr.hdr_lngth; | ||
554 | |||
555 | struct GNUNET_MESH_Tunnel **cls = GNUNET_malloc (size); | ||
556 | struct GNUNET_MessageHeader *hdr = | ||
557 | (struct GNUNET_MessageHeader *) (cls + 1); | ||
558 | GNUNET_HashCode *hc = (GNUNET_HashCode *) (hdr + 1); | ||
559 | |||
560 | hdr->size = | ||
561 | htons (sizeof (struct GNUNET_MessageHeader) + | ||
562 | sizeof (GNUNET_HashCode) + ntohs (pkt->ip_hdr.tot_lngth) - | ||
563 | 4 * pkt->ip_hdr.hdr_lngth); | ||
564 | |||
565 | GNUNET_MESH_ApplicationType app_type = 0; /* make compiler happy */ | ||
566 | |||
567 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "me->addrlen is %d\n", | ||
568 | me->addrlen); | ||
569 | if (me->addrlen == 0) | ||
570 | { | ||
571 | /* This is a mapping to a gnunet-service */ | ||
572 | *hc = me->desc; | ||
573 | |||
574 | if (me->tunnel == NULL && NULL != cls) | ||
575 | { | ||
576 | *cls = | ||
577 | GNUNET_MESH_tunnel_create (mesh_handle, | ||
578 | initialize_tunnel_state (4, NULL), | ||
579 | send_pkt_to_peer, NULL, cls); | ||
580 | GNUNET_MESH_peer_request_connect_add (*cls, | ||
581 | (struct GNUNET_PeerIdentity | ||
582 | *) &me->desc); | ||
583 | me->tunnel = *cls; | ||
584 | } | ||
585 | else if (NULL != cls) | ||
586 | { | ||
587 | *cls = me->tunnel; | ||
588 | send_pkt_to_peer (cls, (struct GNUNET_PeerIdentity *) 1, NULL); | ||
589 | } | ||
590 | } | ||
591 | else | ||
592 | { | ||
593 | /* This is a mapping to a "real" address */ | ||
594 | struct remote_addr *s = (struct remote_addr *) hc; | ||
595 | |||
596 | s->addrlen = me->addrlen; | ||
597 | memcpy (s->addr, me->addr, me->addrlen); | ||
598 | s->proto = pkt->ip_hdr.proto; | ||
599 | if (s->proto == IPPROTO_UDP) | ||
600 | { | ||
601 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP); | ||
602 | memcpy (hc + 1, &pkt_udp->udp_hdr, ntohs (pkt_udp->udp_hdr.len)); | ||
603 | app_type = GNUNET_APPLICATION_TYPE_INTERNET_UDP_GATEWAY; | ||
604 | } | ||
605 | else if (s->proto == IPPROTO_TCP) | ||
606 | { | ||
607 | hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP); | ||
608 | memcpy (hc + 1, &pkt_tcp->tcp_hdr, | ||
609 | ntohs (pkt->ip_hdr.tot_lngth) - | ||
610 | 4 * pkt->ip_hdr.hdr_lngth); | ||
611 | app_type = GNUNET_APPLICATION_TYPE_INTERNET_TCP_GATEWAY; | ||
612 | } | ||
613 | else | ||
614 | GNUNET_assert (0); | ||
615 | if (me->tunnel == NULL && NULL != cls) | ||
616 | { | ||
617 | *cls = | ||
618 | GNUNET_MESH_tunnel_create (mesh_handle, | ||
619 | initialize_tunnel_state (4, NULL), | ||
620 | send_pkt_to_peer, NULL, cls); | ||
621 | |||
622 | GNUNET_MESH_peer_request_connect_by_type (*cls, app_type); | ||
623 | me->tunnel = *cls; | ||
624 | } | ||
625 | else if (NULL != cls) | ||
626 | { | ||
627 | *cls = me->tunnel; | ||
628 | send_pkt_to_peer (cls, (struct GNUNET_PeerIdentity *) 1, NULL); | ||
629 | } | ||
630 | } | ||
631 | } | ||
632 | else | ||
633 | { | ||
634 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
635 | "Packet to %x which has no mapping\n", dadr); | ||
636 | } | ||
637 | break; | ||
638 | case 0x01: | ||
639 | /* ICMP */ | ||
640 | pkt_icmp = (struct ip_icmp *) pkt; | ||
641 | if (pkt_icmp->icmp_hdr.type == 0x8 && | ||
642 | (key = address4_mapping_exists (dadr)) != NULL) | ||
643 | { | ||
644 | GNUNET_free (key); | ||
645 | pkt_icmp = GNUNET_malloc (ntohs (pkt->shdr.size)); | ||
646 | memcpy (pkt_icmp, pkt, ntohs (pkt->shdr.size)); | ||
647 | GNUNET_SCHEDULER_add_now (&send_icmp4_response, pkt_icmp); | ||
648 | } | ||
649 | break; | ||
650 | } | ||
651 | } | ||
652 | } | ||
653 | } | ||
654 | |||
655 | |||
656 | |||
657 | |||
658 | |||
659 | /** | ||
660 | * Create a new Address from an answer-packet | ||
661 | */ | ||
662 | static void | ||
663 | new_ip6addr (struct in6_addr *v6addr, | ||
664 | const GNUNET_HashCode * peer, | ||
665 | const GNUNET_HashCode * service_desc) | ||
666 | { /* {{{ */ | ||
667 | unsigned char *buf = (unsigned char*) v6addr; | ||
668 | char *ipv6addr; | ||
669 | unsigned long long ipv6prefix; | ||
670 | |||
671 | GNUNET_assert (GNUNET_OK == | ||
672 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR", | ||
673 | &ipv6addr)); | ||
674 | GNUNET_assert (GNUNET_OK == | ||
675 | GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", | ||
676 | "IPV6PREFIX", | ||
677 | &ipv6prefix)); | ||
678 | GNUNET_assert (ipv6prefix < 127); | ||
679 | ipv6prefix = (ipv6prefix + 7) / 8; | ||
680 | |||
681 | inet_pton (AF_INET6, ipv6addr, buf); | ||
682 | GNUNET_free (ipv6addr); | ||
683 | |||
684 | int peer_length = 16 - ipv6prefix - 6; | ||
685 | |||
686 | if (peer_length <= 0) | ||
687 | peer_length = 0; | ||
688 | |||
689 | int service_length = 16 - ipv6prefix - peer_length; | ||
690 | |||
691 | if (service_length <= 0) | ||
692 | service_length = 0; | ||
693 | |||
694 | memcpy (buf + ipv6prefix, service_desc, service_length); | ||
695 | memcpy (buf + ipv6prefix + service_length, peer, peer_length); | ||
696 | } | ||
697 | |||
698 | /*}}}*/ | ||
699 | |||
700 | |||
701 | /** | ||
702 | * Create a new Address from an answer-packet | ||
703 | */ | ||
704 | static void | ||
705 | new_ip6addr_remote (struct in6_addr *v6addr, | ||
706 | unsigned char *addr, char addrlen) | ||
707 | { /* {{{ */ | ||
708 | unsigned char *buf = (unsigned char*) v6addr; | ||
709 | char *ipv6addr; | ||
710 | unsigned long long ipv6prefix; | ||
711 | |||
712 | GNUNET_assert (GNUNET_OK == | ||
713 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR", | ||
714 | &ipv6addr)); | ||
715 | GNUNET_assert (GNUNET_OK == | ||
716 | GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", | ||
717 | "IPV6PREFIX", | ||
718 | &ipv6prefix)); | ||
719 | GNUNET_assert (ipv6prefix < 127); | ||
720 | ipv6prefix = (ipv6prefix + 7) / 8; | ||
721 | |||
722 | inet_pton (AF_INET6, ipv6addr, buf); | ||
723 | GNUNET_free (ipv6addr); | ||
724 | |||
725 | int local_length = 16 - ipv6prefix; | ||
726 | |||
727 | memcpy (buf + ipv6prefix, addr, GNUNET_MIN (addrlen, local_length)); | ||
728 | } | ||
729 | |||
730 | /*}}}*/ | ||
731 | |||
732 | /** | ||
733 | * Create a new Address from an answer-packet | ||
734 | */ | ||
735 | static void | ||
736 | new_ip4addr_remote (unsigned char *buf, unsigned char *addr, char addrlen) | ||
737 | { /* {{{ */ | ||
738 | char *ipv4addr; | ||
739 | char *ipv4mask; | ||
740 | |||
741 | GNUNET_assert (GNUNET_OK == | ||
742 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR", | ||
743 | &ipv4addr)); | ||
744 | GNUNET_assert (GNUNET_OK == | ||
745 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK", | ||
746 | &ipv4mask)); | ||
747 | uint32_t mask; | ||
748 | |||
749 | inet_pton (AF_INET, ipv4addr, buf); | ||
750 | int r = inet_pton (AF_INET, ipv4mask, &mask); | ||
751 | |||
752 | mask = htonl (mask); | ||
753 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "inet_pton: %d; %m; mask: %08x\n", r, | ||
754 | mask); | ||
755 | |||
756 | GNUNET_free (ipv4addr); | ||
757 | |||
758 | int c; | ||
759 | |||
760 | if (mask) | ||
761 | { | ||
762 | mask = (mask ^ (mask - 1)) >> 1; | ||
763 | for (c = 0; mask; c++) | ||
764 | { | ||
765 | mask >>= 1; | ||
766 | } | ||
767 | } | ||
768 | else | ||
769 | { | ||
770 | c = CHAR_BIT * sizeof (mask); | ||
771 | } | ||
772 | |||
773 | c = 32 - c; | ||
774 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "The mask %s has %d leading 1s.\n", | ||
775 | ipv4mask, c); | ||
776 | |||
777 | GNUNET_free (ipv4mask); | ||
778 | |||
779 | if (c % 8 == 0) | ||
780 | c = c / 8; | ||
781 | else | ||
782 | GNUNET_assert (0); | ||
783 | |||
784 | memcpy (buf + c, addr, GNUNET_MIN (addrlen, 4 - c)); | ||
785 | } | ||
786 | |||
787 | /*}}}*/ | ||
788 | |||
789 | |||
790 | |||
791 | /** | ||
792 | * FIXME: document. | ||
793 | */ | ||
794 | static int | ||
795 | receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
796 | void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, | ||
797 | const struct GNUNET_MessageHeader *message, | ||
798 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
799 | { | ||
800 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); | ||
801 | struct remote_addr *s = (struct remote_addr *) desc; | ||
802 | struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1); | ||
803 | const struct GNUNET_PeerIdentity *other = sender; | ||
804 | struct tunnel_state *ts = *tunnel_ctx; | ||
805 | |||
806 | if (16 == ts->addrlen) | ||
807 | { | ||
808 | size_t size = | ||
809 | sizeof (struct ip6_udp) + ntohs (pkt->len) - 1 - | ||
810 | sizeof (struct udp_pkt); | ||
811 | |||
812 | struct ip6_udp *pkt6 = alloca (size); | ||
813 | |||
814 | GNUNET_assert (pkt6 != NULL); | ||
815 | |||
816 | if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK) | ||
817 | new_ip6addr (&pkt6->ip6_hdr.sadr, &other->hashPubKey, desc); | ||
818 | else | ||
819 | new_ip6addr_remote (&pkt6->ip6_hdr.sadr, s->addr, s->addrlen); | ||
820 | |||
821 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
822 | "Relaying calc:%d gnu:%d udp:%d bytes!\n", size, | ||
823 | ntohs (message->size), ntohs (pkt->len)); | ||
824 | |||
825 | pkt6->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
826 | pkt6->shdr.size = htons (size); | ||
827 | |||
828 | pkt6->tun.flags = 0; | ||
829 | pkt6->tun.type = htons (0x86dd); | ||
830 | |||
831 | pkt6->ip6_hdr.version = 6; | ||
832 | pkt6->ip6_hdr.tclass_h = 0; | ||
833 | pkt6->ip6_hdr.tclass_l = 0; | ||
834 | pkt6->ip6_hdr.flowlbl = 0; | ||
835 | pkt6->ip6_hdr.paylgth = pkt->len; | ||
836 | pkt6->ip6_hdr.nxthdr = IPPROTO_UDP; | ||
837 | pkt6->ip6_hdr.hoplmt = 0xff; | ||
838 | |||
839 | { | ||
840 | char *ipv6addr; | ||
841 | |||
842 | GNUNET_assert (GNUNET_OK == | ||
843 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", | ||
844 | "IPV6ADDR", | ||
845 | &ipv6addr)); | ||
846 | inet_pton (AF_INET6, ipv6addr, &pkt6->ip6_hdr.dadr); | ||
847 | GNUNET_free (ipv6addr); | ||
848 | } | ||
849 | memcpy (&pkt6->udp_hdr, pkt, ntohs (pkt->len)); | ||
850 | |||
851 | GNUNET_HashCode *key = address6_mapping_exists (&pkt6->ip6_hdr.sadr); | ||
852 | |||
853 | GNUNET_assert (key != NULL); | ||
854 | |||
855 | struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
856 | |||
857 | GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, | ||
858 | GNUNET_TIME_absolute_get ().abs_value); | ||
859 | |||
860 | GNUNET_free (key); | ||
861 | |||
862 | GNUNET_assert (me != NULL); | ||
863 | |||
864 | pkt6->udp_hdr.crc = 0; | ||
865 | uint32_t sum = 0; | ||
866 | |||
867 | sum = | ||
868 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->ip6_hdr.sadr, 16); | ||
869 | sum = | ||
870 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->ip6_hdr.dadr, 16); | ||
871 | uint32_t tmp = (pkt6->udp_hdr.len & 0xffff); | ||
872 | |||
873 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
874 | tmp = htons (((pkt6->ip6_hdr.nxthdr & 0x00ff))); | ||
875 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
876 | |||
877 | sum = | ||
878 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->udp_hdr, | ||
879 | ntohs (pkt->len)); | ||
880 | pkt6->udp_hdr.crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
881 | |||
882 | (void) GNUNET_HELPER_send (helper_handle, | ||
883 | &pkt6->shdr, | ||
884 | GNUNET_YES, | ||
885 | NULL, NULL); | ||
886 | } | ||
887 | else | ||
888 | { | ||
889 | size_t size = | ||
890 | sizeof (struct ip_udp) + ntohs (pkt->len) - 1 - sizeof (struct udp_pkt); | ||
891 | |||
892 | struct ip_udp *pkt4 = alloca (size); | ||
893 | |||
894 | GNUNET_assert (pkt4 != NULL); | ||
895 | |||
896 | GNUNET_assert (ntohs (message->type) == | ||
897 | GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK); | ||
898 | uint32_t sadr; | ||
899 | |||
900 | new_ip4addr_remote ((unsigned char *) &sadr, s->addr, s->addrlen); | ||
901 | pkt4->ip_hdr.sadr.s_addr = sadr; | ||
902 | |||
903 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
904 | "Relaying calc:%d gnu:%d udp:%d bytes!\n", size, | ||
905 | ntohs (message->size), ntohs (pkt->len)); | ||
906 | |||
907 | pkt4->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
908 | pkt4->shdr.size = htons (size); | ||
909 | |||
910 | pkt4->tun.flags = 0; | ||
911 | pkt4->tun.type = htons (0x0800); | ||
912 | |||
913 | pkt4->ip_hdr.version = 4; | ||
914 | pkt4->ip_hdr.hdr_lngth = 5; | ||
915 | pkt4->ip_hdr.diff_serv = 0; | ||
916 | pkt4->ip_hdr.tot_lngth = htons (20 + ntohs (pkt->len)); | ||
917 | pkt4->ip_hdr.ident = 0; | ||
918 | pkt4->ip_hdr.flags = 0; | ||
919 | pkt4->ip_hdr.frag_off = 0; | ||
920 | pkt4->ip_hdr.ttl = 255; | ||
921 | pkt4->ip_hdr.proto = IPPROTO_UDP; | ||
922 | pkt4->ip_hdr.chks = 0; /* Will be calculated later */ | ||
923 | |||
924 | { | ||
925 | char *ipv4addr; | ||
926 | uint32_t dadr; | ||
927 | |||
928 | GNUNET_assert (GNUNET_OK == | ||
929 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", | ||
930 | "IPV4ADDR", | ||
931 | &ipv4addr)); | ||
932 | inet_pton (AF_INET, ipv4addr, &dadr); | ||
933 | GNUNET_free (ipv4addr); | ||
934 | pkt4->ip_hdr.dadr.s_addr = dadr; | ||
935 | } | ||
936 | memcpy (&pkt4->udp_hdr, pkt, ntohs (pkt->len)); | ||
937 | |||
938 | GNUNET_HashCode *key = address4_mapping_exists (pkt4->ip_hdr.sadr.s_addr); | ||
939 | |||
940 | GNUNET_assert (key != NULL); | ||
941 | |||
942 | struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
943 | |||
944 | GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, | ||
945 | GNUNET_TIME_absolute_get ().abs_value); | ||
946 | |||
947 | GNUNET_free (key); | ||
948 | |||
949 | GNUNET_assert (me != NULL); | ||
950 | |||
951 | pkt4->udp_hdr.crc = 0; /* Optional for IPv4 */ | ||
952 | |||
953 | pkt4->ip_hdr.chks = | ||
954 | GNUNET_CRYPTO_crc16_n ((uint16_t *) & pkt4->ip_hdr, 5 * 4); | ||
955 | |||
956 | (void) GNUNET_HELPER_send (helper_handle, | ||
957 | &pkt4->shdr, | ||
958 | GNUNET_YES, | ||
959 | NULL, NULL); | ||
960 | } | ||
961 | |||
962 | return GNUNET_OK; | ||
963 | } | ||
964 | |||
965 | |||
966 | /** | ||
967 | * FIXME: document. | ||
968 | */ | ||
969 | static int | ||
970 | receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, | ||
971 | void **tunnel_ctx, | ||
972 | const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, | ||
973 | const struct GNUNET_MessageHeader *message, | ||
974 | const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) | ||
975 | { | ||
976 | GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); | ||
977 | struct remote_addr *s = (struct remote_addr *) desc; | ||
978 | struct tcp_pkt *pkt = (struct tcp_pkt *) (desc + 1); | ||
979 | const struct GNUNET_PeerIdentity *other = sender; | ||
980 | struct tunnel_state *ts = *tunnel_ctx; | ||
981 | |||
982 | size_t pktlen = | ||
983 | ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - | ||
984 | sizeof (GNUNET_HashCode); | ||
985 | |||
986 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
987 | "Received TCP-Packet back, addrlen = %d\n", s->addrlen); | ||
988 | |||
989 | if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK || | ||
990 | ts->addrlen == 16) | ||
991 | { | ||
992 | size_t size = pktlen + sizeof (struct ip6_tcp) - 1; | ||
993 | |||
994 | struct ip6_tcp *pkt6 = alloca (size); | ||
995 | |||
996 | memset (pkt6, 0, size); | ||
997 | |||
998 | GNUNET_assert (pkt6 != NULL); | ||
999 | |||
1000 | if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK) | ||
1001 | new_ip6addr (&pkt6->ip6_hdr.sadr, &other->hashPubKey, desc); | ||
1002 | else | ||
1003 | new_ip6addr_remote (&pkt6->ip6_hdr.sadr, s->addr, s->addrlen); | ||
1004 | |||
1005 | pkt6->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
1006 | pkt6->shdr.size = htons (size); | ||
1007 | |||
1008 | pkt6->tun.flags = 0; | ||
1009 | pkt6->tun.type = htons (0x86dd); | ||
1010 | |||
1011 | pkt6->ip6_hdr.version = 6; | ||
1012 | pkt6->ip6_hdr.tclass_h = 0; | ||
1013 | pkt6->ip6_hdr.tclass_l = 0; | ||
1014 | pkt6->ip6_hdr.flowlbl = 0; | ||
1015 | pkt6->ip6_hdr.paylgth = htons (pktlen); | ||
1016 | pkt6->ip6_hdr.nxthdr = IPPROTO_TCP; | ||
1017 | pkt6->ip6_hdr.hoplmt = 0xff; | ||
1018 | |||
1019 | { | ||
1020 | char *ipv6addr; | ||
1021 | |||
1022 | GNUNET_assert (GNUNET_OK == | ||
1023 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", | ||
1024 | "IPV6ADDR", | ||
1025 | &ipv6addr)); | ||
1026 | inet_pton (AF_INET6, ipv6addr, &pkt6->ip6_hdr.dadr); | ||
1027 | GNUNET_free (ipv6addr); | ||
1028 | } | ||
1029 | memcpy (&pkt6->tcp_hdr, pkt, pktlen); | ||
1030 | |||
1031 | GNUNET_HashCode *key = address6_mapping_exists (&pkt6->ip6_hdr.sadr); | ||
1032 | |||
1033 | GNUNET_assert (key != NULL); | ||
1034 | |||
1035 | struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
1036 | |||
1037 | GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, | ||
1038 | GNUNET_TIME_absolute_get ().abs_value); | ||
1039 | |||
1040 | GNUNET_free (key); | ||
1041 | |||
1042 | GNUNET_assert (me != NULL); | ||
1043 | |||
1044 | pkt6->tcp_hdr.crc = 0; | ||
1045 | uint32_t sum = 0; | ||
1046 | uint32_t tmp; | ||
1047 | |||
1048 | sum = | ||
1049 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->ip6_hdr.sadr, 16); | ||
1050 | sum = | ||
1051 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->ip6_hdr.dadr, 16); | ||
1052 | tmp = htonl (pktlen); | ||
1053 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
1054 | tmp = htonl (((pkt6->ip6_hdr.nxthdr & 0x000000ff))); | ||
1055 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
1056 | |||
1057 | sum = | ||
1058 | GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt6->tcp_hdr, | ||
1059 | ntohs (pkt6->ip6_hdr.paylgth)); | ||
1060 | pkt6->tcp_hdr.crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
1061 | |||
1062 | (void) GNUNET_HELPER_send (helper_handle, | ||
1063 | &pkt6->shdr, | ||
1064 | GNUNET_YES, | ||
1065 | NULL, NULL); | ||
1066 | } | ||
1067 | else | ||
1068 | { | ||
1069 | size_t size = pktlen + sizeof (struct ip_tcp) - 1; | ||
1070 | |||
1071 | struct ip_tcp *pkt4 = alloca (size); | ||
1072 | |||
1073 | GNUNET_assert (pkt4 != NULL); | ||
1074 | memset (pkt4, 0, size); | ||
1075 | |||
1076 | GNUNET_assert (ntohs (message->type) == | ||
1077 | GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK); | ||
1078 | uint32_t sadr; | ||
1079 | |||
1080 | new_ip4addr_remote ((unsigned char *) &sadr, s->addr, s->addrlen); | ||
1081 | pkt4->ip_hdr.sadr.s_addr = sadr; | ||
1082 | |||
1083 | pkt4->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); | ||
1084 | pkt4->shdr.size = htons (size); | ||
1085 | |||
1086 | pkt4->tun.flags = 0; | ||
1087 | pkt4->tun.type = htons (0x0800); | ||
1088 | |||
1089 | pkt4->ip_hdr.version = 4; | ||
1090 | pkt4->ip_hdr.hdr_lngth = 5; | ||
1091 | pkt4->ip_hdr.diff_serv = 0; | ||
1092 | pkt4->ip_hdr.tot_lngth = htons (20 + pktlen); | ||
1093 | pkt4->ip_hdr.ident = 0; | ||
1094 | pkt4->ip_hdr.flags = 0; | ||
1095 | pkt4->ip_hdr.frag_off = 0; | ||
1096 | pkt4->ip_hdr.ttl = 255; | ||
1097 | pkt4->ip_hdr.proto = IPPROTO_TCP; | ||
1098 | pkt4->ip_hdr.chks = 0; /* Will be calculated later */ | ||
1099 | |||
1100 | { | ||
1101 | char *ipv4addr; | ||
1102 | uint32_t dadr; | ||
1103 | |||
1104 | GNUNET_assert (GNUNET_OK == | ||
1105 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", | ||
1106 | "IPV4ADDR", | ||
1107 | &ipv4addr)); | ||
1108 | inet_pton (AF_INET, ipv4addr, &dadr); | ||
1109 | GNUNET_free (ipv4addr); | ||
1110 | pkt4->ip_hdr.dadr.s_addr = dadr; | ||
1111 | } | ||
1112 | |||
1113 | memcpy (&pkt4->tcp_hdr, pkt, pktlen); | ||
1114 | |||
1115 | GNUNET_HashCode *key = address4_mapping_exists (pkt4->ip_hdr.sadr.s_addr); | ||
1116 | |||
1117 | GNUNET_assert (key != NULL); | ||
1118 | |||
1119 | struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); | ||
1120 | |||
1121 | GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, | ||
1122 | GNUNET_TIME_absolute_get ().abs_value); | ||
1123 | |||
1124 | GNUNET_free (key); | ||
1125 | |||
1126 | GNUNET_assert (me != NULL); | ||
1127 | pkt4->tcp_hdr.crc = 0; | ||
1128 | uint32_t sum = 0; | ||
1129 | uint32_t tmp; | ||
1130 | |||
1131 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) &pkt4->ip_hdr.sadr, 4); | ||
1132 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) &pkt4->ip_hdr.dadr, 4); | ||
1133 | |||
1134 | tmp = (0x06 << 16) | (0xffff & pktlen); // 0x06 for TCP? | ||
1135 | |||
1136 | tmp = htonl (tmp); | ||
1137 | |||
1138 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & tmp, 4); | ||
1139 | |||
1140 | sum = GNUNET_CRYPTO_crc16_step (sum, (uint16_t *) & pkt4->tcp_hdr, pktlen); | ||
1141 | pkt4->tcp_hdr.crc = GNUNET_CRYPTO_crc16_finish (sum); | ||
1142 | |||
1143 | pkt4->ip_hdr.chks = | ||
1144 | GNUNET_CRYPTO_crc16_n ((uint16_t *) & pkt4->ip_hdr, 5 * 4); | ||
1145 | |||
1146 | (void) GNUNET_HELPER_send (helper_handle, | ||
1147 | &pkt4->shdr, | ||
1148 | GNUNET_YES, | ||
1149 | NULL, NULL); | ||
1150 | |||
1151 | } | ||
1152 | |||
1153 | return GNUNET_OK; | ||
1154 | } | ||
1155 | |||
1156 | |||
1157 | /** | ||
1158 | * FIXME: document. | ||
1159 | */ | ||
1160 | static void * | ||
1161 | new_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel, | ||
1162 | const struct GNUNET_PeerIdentity *initiator, | ||
1163 | const struct GNUNET_ATS_Information *atsi) | ||
1164 | { | ||
1165 | /* Why should anyone open an inbound tunnel to vpn? */ | ||
1166 | GNUNET_break (0); | ||
1167 | return NULL; | ||
1168 | } | ||
1169 | |||
1170 | |||
1171 | /** | ||
1172 | * FIXME: document. | ||
1173 | */ | ||
1174 | static void | ||
1175 | tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx) | ||
1176 | { | ||
1177 | /* Why should anyone open an inbound tunnel to vpn? */ | ||
1178 | /* FIXME: is this not also called for outbound tunnels that go down!? */ | ||
1179 | GNUNET_break (0); | ||
1180 | } | ||
1181 | |||
1182 | |||
1183 | /** | ||
1184 | * Function scheduled as very last function, cleans up after us | ||
1185 | */ | ||
1186 | static void | ||
1187 | cleanup (void *cls GNUNET_UNUSED, | ||
1188 | const struct GNUNET_SCHEDULER_TaskContext *tskctx) | ||
1189 | { | ||
1190 | unsigned int i; | ||
1191 | |||
1192 | if (mesh_handle != NULL) | ||
1193 | { | ||
1194 | GNUNET_MESH_disconnect (mesh_handle); | ||
1195 | mesh_handle = NULL; | ||
1196 | } | ||
1197 | if (helper_handle != NULL) | ||
1198 | { | ||
1199 | GNUNET_HELPER_stop (helper_handle); | ||
1200 | helper_handle = NULL; | ||
1201 | } | ||
1202 | for (i=0;i<5;i++) | ||
1203 | GNUNET_free_non_null (vpn_argv[i]); | ||
1204 | } | ||
1205 | |||
1206 | |||
1207 | /** | ||
1208 | * Main function that will be run by the scheduler. | ||
1209 | * | ||
1210 | * @param cls closure | ||
1211 | * @param server the initialized server | ||
1212 | * @param cfg_ configuration | ||
1213 | */ | ||
1214 | static void | ||
1215 | run (void *cls, | ||
1216 | struct GNUNET_SERVER_Handle *server, | ||
1217 | const struct GNUNET_CONFIGURATION_Handle *cfg_) | ||
1218 | { | ||
1219 | static const struct GNUNET_MESH_MessageHandler handlers[] = { | ||
1220 | {receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK, 0}, | ||
1221 | {receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK, 0}, | ||
1222 | {receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK, 0}, | ||
1223 | {receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK, 0}, | ||
1224 | {NULL, 0, 0} | ||
1225 | }; | ||
1226 | static const GNUNET_MESH_ApplicationType types[] = { | ||
1227 | GNUNET_APPLICATION_TYPE_END | ||
1228 | }; | ||
1229 | char *ifname; | ||
1230 | char *ipv6addr; | ||
1231 | char *ipv6prefix_s; | ||
1232 | char *ipv4addr; | ||
1233 | char *ipv4mask; | ||
1234 | struct in_addr v4; | ||
1235 | struct in6_addr v6; | ||
1236 | unsigned long long ipv6prefix; | ||
1237 | |||
1238 | cfg = cfg_; | ||
1239 | hashmap = GNUNET_CONTAINER_multihashmap_create (65536); | ||
1240 | heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
1241 | |||
1242 | if (GNUNET_OK != | ||
1243 | GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPING", | ||
1244 | &max_mappings)) | ||
1245 | max_mappings = 200; | ||
1246 | |||
1247 | vpn_argv[0] = GNUNET_strdup ("vpn-gnunet"); | ||
1248 | if (GNUNET_SYSERR == | ||
1249 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IFNAME", &ifname)) | ||
1250 | { | ||
1251 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1252 | "No entry 'IFNAME' in configuration!\n"); | ||
1253 | GNUNET_SCHEDULER_shutdown (); | ||
1254 | return; | ||
1255 | } | ||
1256 | vpn_argv[1] = ifname; | ||
1257 | if ( (GNUNET_SYSERR == | ||
1258 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR", | ||
1259 | &ipv6addr) || | ||
1260 | (1 != inet_pton (AF_INET6, ipv6addr, &v6))) ) | ||
1261 | { | ||
1262 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1263 | "No valid entry 'IPV6ADDR' in configuration!\n"); | ||
1264 | GNUNET_SCHEDULER_shutdown (); | ||
1265 | return; | ||
1266 | } | ||
1267 | vpn_argv[2] = ipv6addr; | ||
1268 | if (GNUNET_SYSERR == | ||
1269 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6PREFIX", | ||
1270 | &ipv6prefix_s)) | ||
1271 | { | ||
1272 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1273 | "No entry 'IPV6PREFIX' in configuration!\n"); | ||
1274 | GNUNET_SCHEDULER_shutdown (); | ||
1275 | return; | ||
1276 | } | ||
1277 | vpn_argv[3] = ipv6prefix_s; | ||
1278 | if ( (GNUNET_OK != | ||
1279 | GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", | ||
1280 | "IPV6PREFIX", | ||
1281 | &ipv6prefix)) || | ||
1282 | (ipv6prefix >= 127) ) | ||
1283 | { | ||
1284 | GNUNET_SCHEDULER_shutdown (); | ||
1285 | return; | ||
1286 | } | ||
1287 | |||
1288 | if ( (GNUNET_SYSERR == | ||
1289 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR", | ||
1290 | &ipv4addr) || | ||
1291 | (1 != inet_pton (AF_INET, ipv4addr, &v4))) ) | ||
1292 | { | ||
1293 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1294 | "No valid entry for 'IPV4ADDR' in configuration!\n"); | ||
1295 | GNUNET_SCHEDULER_shutdown (); | ||
1296 | return; | ||
1297 | } | ||
1298 | vpn_argv[4] = ipv4addr; | ||
1299 | if ( (GNUNET_SYSERR == | ||
1300 | GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK", | ||
1301 | &ipv4mask) || | ||
1302 | (1 != inet_pton (AF_INET, ipv4mask, &v4))) ) | ||
1303 | { | ||
1304 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1305 | "No valid entry 'IPV4MASK' in configuration!\n"); | ||
1306 | GNUNET_SCHEDULER_shutdown (); | ||
1307 | return; | ||
1308 | } | ||
1309 | vpn_argv[5] = ipv4mask; | ||
1310 | vpn_argv[6] = NULL; | ||
1311 | |||
1312 | mesh_handle = | ||
1313 | GNUNET_MESH_connect (cfg_, 42 /* queue length */, NULL, | ||
1314 | &new_tunnel, | ||
1315 | &tunnel_cleaner, | ||
1316 | handlers, | ||
1317 | types); | ||
1318 | helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", vpn_argv, | ||
1319 | &message_token, NULL); | ||
1320 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); | ||
1321 | } | ||
1322 | |||
1323 | |||
1324 | /** | ||
1325 | * The main function of the VPN service. | ||
1326 | * | ||
1327 | * @param argc number of arguments from the command line | ||
1328 | * @param argv command line arguments | ||
1329 | * @return 0 ok, 1 on error | ||
1330 | */ | ||
1331 | int | ||
1332 | main (int argc, char *const *argv) | ||
1333 | { | ||
1334 | return (GNUNET_OK == | ||
1335 | GNUNET_SERVICE_run (argc, argv, "vpn", | ||
1336 | GNUNET_SERVICE_OPTION_NONE, | ||
1337 | &run, NULL)) ? 0 : 1; | ||
1338 | } | ||
1339 | |||
1340 | /* end of gnunet-service-vpn.c */ | ||