X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fvpn%2Fgnunet-daemon-vpn.c;h=cc8001eae412119f28ab7389e5e26f443e17b2b4;hb=83b19539f4d322b43683f5838b72e9ec2c8e6073;hp=e84600e4ab6a39aee674d277c78bae7f1a1883b2;hpb=11c2830064ec60af2b84a9b7f885b2f9d31a1b0d;p=oweals%2Fgnunet.git diff --git a/src/vpn/gnunet-daemon-vpn.c b/src/vpn/gnunet-daemon-vpn.c index e84600e4a..cc8001eae 100644 --- a/src/vpn/gnunet-daemon-vpn.c +++ b/src/vpn/gnunet-daemon-vpn.c @@ -20,433 +20,1262 @@ /** * @file vpn/gnunet-daemon-vpn.c - * @brief - * @author Philipp Tölke + * @brief + * @author Philipp Toelke */ #include "platform.h" #include "gnunet_getopt_lib.h" #include "gnunet_program_lib.h" -#include "gnunet_os_lib.h" -#include "gnunet-vpn-helper-p.h" #include "gnunet-vpn-packet.h" -#include "gnunet-vpn-pretty-print.h" #include "gnunet_common.h" #include "gnunet_protocols.h" -#include "gnunet_server_lib.h" -#include "gnunet-service-dns-p.h" +#include "gnunet_applications.h" +#include #include "gnunet_client_lib.h" #include "gnunet_container_lib.h" -#include "block_dns.h" +#include "gnunet_constants.h" +#include +#include "gnunet-daemon-vpn-helper.h" +#include "gnunet-daemon-vpn-dns.h" +#include "gnunet-daemon-vpn.h" +#include "gnunet-vpn-checksum.h" + +const struct GNUNET_CONFIGURATION_Handle *cfg; +struct GNUNET_MESH_Handle *mesh_handle; +struct GNUNET_CONTAINER_MultiHashMap *hashmap; +static struct GNUNET_CONTAINER_Heap *heap; + +struct tunnel_notify_queue +{ + struct tunnel_notify_queue *next; + struct tunnel_notify_queue *prev; + size_t len; + void *cls; +}; /** - * Final status code. + * If there are at least this many address-mappings, old ones will be removed */ -static int ret; +static long long unsigned int max_mappings = 200; /** - * The scheduler to use throughout the daemon + * Final status code. */ -static struct GNUNET_SCHEDULER_Handle *sched; +static int ret; /** - * The configuration to use + * This hashmap contains the mapping from peer, service-descriptor, + * source-port and destination-port to a socket */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; +static struct GNUNET_CONTAINER_MultiHashMap *udp_connections; -/** - * PipeHandle to receive data from the helper - */ -static struct GNUNET_DISK_PipeHandle* helper_in; +GNUNET_SCHEDULER_TaskIdentifier conn_task; -/** - * PipeHandle to send data to the helper - */ -static struct GNUNET_DISK_PipeHandle* helper_out; +GNUNET_SCHEDULER_TaskIdentifier shs_task; /** - * FileHandle to receive data from the helper + * Function scheduled as very last function, cleans up after us + *{{{ */ -static const struct GNUNET_DISK_FileHandle* fh_from_helper; +static void +cleanup (void *cls + __attribute__ ((unused)), + const struct GNUNET_SCHEDULER_TaskContext *tskctx) +{ + GNUNET_assert (0 != (tskctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)); -/** - * FileHandle to send data to the helper - */ -static const struct GNUNET_DISK_FileHandle* fh_to_helper; + /* stop the helper */ + cleanup_helper (helper_handle); + + /* close the connection to the service-dns */ + if (dns_connection != NULL) + { + GNUNET_CLIENT_disconnect (dns_connection, GNUNET_NO); + dns_connection = NULL; + } + + if (mesh_handle != NULL) + { + GNUNET_MESH_disconnect (mesh_handle); + mesh_handle = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != shs_task) + { + GNUNET_SCHEDULER_cancel (shs_task); + shs_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != conn_task) + { + GNUNET_SCHEDULER_cancel (conn_task); + conn_task = GNUNET_SCHEDULER_NO_TASK; + } +} + +/*}}}*/ /** - * The Message-Tokenizer that tokenizes the messages comming from the helper + * @return the hash of the IP-Address if a mapping exists, NULL otherwise */ -static struct GNUNET_SERVER_MessageStreamTokenizer* mst; +GNUNET_HashCode * +address6_mapping_exists (unsigned char addr[]) +{ + GNUNET_HashCode *key = GNUNET_malloc (sizeof (GNUNET_HashCode)); + unsigned char *k = (unsigned char *) key; + + memset (key, 0, sizeof (GNUNET_HashCode)); + unsigned int i; + + for (i = 0; i < 16; i++) + k[15 - i] = addr[i]; + + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (hashmap, key)) + return key; + else + { + GNUNET_free (key); + return NULL; + } +} /** - * The connection to the service-dns + * @return the hash of the IP-Address if a mapping exists, NULL otherwise */ -static struct GNUNET_CLIENT_Connection *dns_connection; +GNUNET_HashCode * +address4_mapping_exists (uint32_t addr) +{ + GNUNET_HashCode *key = GNUNET_malloc (sizeof (GNUNET_HashCode)); + + memset (key, 0, sizeof (GNUNET_HashCode)); + unsigned char *c = (unsigned char *) &addr; + unsigned char *k = (unsigned char *) key; + unsigned int i; + + for (i = 0; i < 4; i++) + k[3 - i] = c[i]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "a4_m_e: getting with key %08x, addr is %08x, %d.%d.%d.%d\n", + *((uint32_t *) (key)), addr, c[0], c[1], c[2], c[3]); + + if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (hashmap, key)) + return key; + else + { + GNUNET_free (key); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Mapping not found!\n"); + return NULL; + } +} + +static void +collect_mappings (void *cls + __attribute__ ((unused)), + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + struct map_entry *me = GNUNET_CONTAINER_heap_remove_root (heap); + + /* This is free()ed memory! */ + me->heap_node = NULL; + + /* FIXME! GNUNET_MESH_close_tunnel(me->tunnel); */ + + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (hashmap, &me->hash, me)); + + GNUNET_free (me); +} + +void +send_icmp4_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + struct ip_icmp *request = cls; + + struct ip_icmp *response = alloca (ntohs (request->shdr.size)); + + GNUNET_assert (response != NULL); + memset (response, 0, ntohs (request->shdr.size)); + + response->shdr.size = request->shdr.size; + response->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + + response->tun.flags = 0; + response->tun.type = htons (0x0800); + + response->ip_hdr.hdr_lngth = 5; + response->ip_hdr.version = 4; + response->ip_hdr.proto = 0x01; + response->ip_hdr.dadr = request->ip_hdr.sadr; + response->ip_hdr.sadr = request->ip_hdr.dadr; + response->ip_hdr.tot_lngth = request->ip_hdr.tot_lngth; + + response->ip_hdr.chks = + calculate_ip_checksum ((uint16_t *) & response->ip_hdr, 20); + + response->icmp_hdr.code = 0; + response->icmp_hdr.type = 0x0; + + /* Magic, more Magic! */ + response->icmp_hdr.chks = request->icmp_hdr.chks + 0x8; + + /* Copy the rest of the packet */ + memcpy (response + 1, request + 1, + ntohs (request->shdr.size) - sizeof (struct ip_icmp)); + + write_to_helper (response, ntohs (response->shdr.size)); + + GNUNET_free (request); +} + +void +send_icmp6_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + struct ip6_icmp *request = cls; + + struct ip6_icmp *response = alloca (ntohs (request->shdr.size)); + + GNUNET_assert (response != NULL); + memset (response, 0, ntohs (request->shdr.size)); + + response->shdr.size = request->shdr.size; + response->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + + response->tun.flags = 0; + response->tun.type = htons (0x86dd); + + response->ip6_hdr.hoplmt = 255; + response->ip6_hdr.paylgth = request->ip6_hdr.paylgth; + response->ip6_hdr.nxthdr = 0x3a; + response->ip6_hdr.version = 6; + memcpy (&response->ip6_hdr.sadr, &request->ip6_hdr.dadr, 16); + memcpy (&response->ip6_hdr.dadr, &request->ip6_hdr.sadr, 16); + + response->icmp_hdr.code = 0; + response->icmp_hdr.type = 0x81; + + /* Magic, more Magic! */ + response->icmp_hdr.chks = request->icmp_hdr.chks - 0x1; + + /* Copy the rest of the packet */ + memcpy (response + 1, request + 1, + ntohs (request->shdr.size) - sizeof (struct ip6_icmp)); + + write_to_helper (response, ntohs (response->shdr.size)); + + GNUNET_free (request); +} /** - * A flag to show that the service-dns has to rehijack the outbound dns-packets - * - * This gets set when the helper restarts as the routing-tables are flushed when - * the interface vanishes. + * cls is the pointer to a GNUNET_MessageHeader that is + * followed by the service-descriptor and the packet that should be sent; */ -static unsigned char restart_hijack; +static size_t +send_pkt_to_peer_notify_callback (void *cls, size_t size, void *buf) +{ + struct GNUNET_MESH_Tunnel **tunnel = cls; + + struct tunnel_state *ts = GNUNET_MESH_tunnel_get_data (*tunnel); + + ts->th = NULL; + + if (NULL != buf) + { + struct GNUNET_MessageHeader *hdr = + (struct GNUNET_MessageHeader *) (tunnel + 1); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "send_pkt_to_peer_notify_callback: buf = %x; size = %u;\n", buf, + size); + GNUNET_assert (size >= ntohs (hdr->size)); + memcpy (buf, hdr, ntohs (hdr->size)); + size = ntohs (hdr->size); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent!\n"); + } + else + size = 0; + + if (NULL != ts->head) + { + struct tunnel_notify_queue *element = ts->head; + + GNUNET_CONTAINER_DLL_remove (ts->head, ts->tail, element); + + ts->th = + GNUNET_MESH_notify_transmit_ready (*tunnel, GNUNET_NO, 42, + GNUNET_TIME_relative_divide + (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), + (const struct GNUNET_PeerIdentity *) + NULL, element->len, + send_pkt_to_peer_notify_callback, + element->cls); + + /* save the handle */ + GNUNET_free (element); + } + GNUNET_free (cls); + + return size; +} + +unsigned int +port_in_ports (uint64_t ports, uint16_t port) +{ + uint16_t *ps = (uint16_t *) & ports; + + return ports == 0 || ps[0] == port || ps[1] == port || ps[2] == port || + ps[3] == port; +} + +void +send_pkt_to_peer (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi + __attribute__ ((unused))) +{ + /* peer == NULL means that all peers in this request are connected */ + if (peer == NULL) + return; + struct GNUNET_MESH_Tunnel **tunnel = cls; + struct GNUNET_MessageHeader *hdr = + (struct GNUNET_MessageHeader *) (tunnel + 1); + + GNUNET_assert (NULL != tunnel); + GNUNET_assert (NULL != *tunnel); + + struct tunnel_state *ts = GNUNET_MESH_tunnel_get_data (*tunnel); + + if (NULL == ts->th) + { + ts->th = + GNUNET_MESH_notify_transmit_ready (*tunnel, GNUNET_NO, 42, + GNUNET_TIME_relative_divide + (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), + (const struct GNUNET_PeerIdentity *) + NULL, ntohs (hdr->size), + send_pkt_to_peer_notify_callback, + cls); + } + else + { + struct tunnel_notify_queue *element = GNUNET_malloc (sizeof *element); + + element->cls = cls; + element->len = ntohs (hdr->size); + + GNUNET_CONTAINER_DLL_insert_tail (ts->head, ts->tail, element); + } +} /** - * The process id of the helper + * Create a new Address from an answer-packet */ -static pid_t helper_pid; +void +new_ip6addr (unsigned char *buf, const GNUNET_HashCode * peer, + const GNUNET_HashCode * service_desc) +{ /* {{{ */ + char *ipv6addr; + unsigned long long ipv6prefix; + + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR", + &ipv6addr)); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", + "IPV6PREFIX", + &ipv6prefix)); + GNUNET_assert (ipv6prefix < 127); + ipv6prefix = (ipv6prefix + 7) / 8; + + inet_pton (AF_INET6, ipv6addr, buf); + GNUNET_free (ipv6addr); + + int peer_length = 16 - ipv6prefix - 6; + + if (peer_length <= 0) + peer_length = 0; + + int service_length = 16 - ipv6prefix - peer_length; + + if (service_length <= 0) + service_length = 0; + + memcpy (buf + ipv6prefix, service_desc, service_length); + memcpy (buf + ipv6prefix + service_length, peer, peer_length); +} + +/*}}}*/ + /** - * a list of outgoing dns-query-packets + * Create a new Address from an answer-packet */ -static struct query_packet_list *head; +void +new_ip6addr_remote (unsigned char *buf, unsigned char *addr, char addrlen) +{ /* {{{ */ + char *ipv6addr; + unsigned long long ipv6prefix; + + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV6ADDR", + &ipv6addr)); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", + "IPV6PREFIX", + &ipv6prefix)); + GNUNET_assert (ipv6prefix < 127); + ipv6prefix = (ipv6prefix + 7) / 8; + + inet_pton (AF_INET6, ipv6addr, buf); + GNUNET_free (ipv6addr); + + int local_length = 16 - ipv6prefix; + + memcpy (buf + ipv6prefix, addr, GNUNET_MIN (addrlen, local_length)); +} + +/*}}}*/ /** - * The last element of the list of outgoing dns-query-packets + * Create a new Address from an answer-packet */ -static struct query_packet_list *tail; +void +new_ip4addr_remote (unsigned char *buf, unsigned char *addr, char addrlen) +{ /* {{{ */ + char *ipv4addr; + char *ipv4mask; + + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4ADDR", + &ipv4addr)); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "IPV4MASK", + &ipv4mask)); + uint32_t mask; + + inet_pton (AF_INET, ipv4addr, buf); + int r = inet_pton (AF_INET, ipv4mask, &mask); + + mask = htonl (mask); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "inet_pton: %d; %m; mask: %08x\n", r, + mask); + + GNUNET_free (ipv4addr); + + int c; + + if (mask) + { + mask = (mask ^ (mask - 1)) >> 1; + for (c = 0; mask; c++) + { + mask >>= 1; + } + } + else + { + c = CHAR_BIT * sizeof (mask); + } + + c = 32 - c; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "The mask %s has %d leading 1s.\n", + ipv4mask, c); + + GNUNET_free (ipv4mask); + + if (c % 8 == 0) + c = c / 8; + else + GNUNET_assert (0); + + memcpy (buf + c, addr, GNUNET_MIN (addrlen, 4 - c)); +} + +/*}}}*/ /** - * A list of processed dns-responses. + * This gets scheduled with cls pointing to an answer_packet and does everything + * needed in order to send it to the helper. * - * "processed" means that the packet is complete and can be sent out via udp - * directly + * At the moment this means "inventing" and IPv6-Address for .gnunet-services and + * doing nothing for "real" services. */ -static struct answer_packet_list *answer_proc_head; +void +process_answer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; -/** - * The last element of the list of processed dns-responses. - */ -static struct answer_packet_list *answer_proc_tail; + struct answer_packet *pkt = cls; + struct answer_packet_list *list; -size_t send_query(void* cls, size_t size, void* buf); + /* This answer is about a .gnunet-service + * + * It contains an almost complete DNS-Response, we have to fill in the ip + * at the offset pkt->addroffset + */ + if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_SERVICE) + { + pkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP; -static void cleanup(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) { - GNUNET_assert (0 != (tskctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)); - PLIBC_KILL(helper_pid, SIGTERM); - GNUNET_OS_process_wait(helper_pid); - if (dns_connection != NULL) + GNUNET_HashCode key; + + memset (&key, 0, sizeof (GNUNET_HashCode)); + + unsigned char *c = ((unsigned char *) pkt) + ntohs (pkt->addroffset); + unsigned char *k = (unsigned char *) &key; + + new_ip6addr (c, &pkt->service_descr.peer, + &pkt->service_descr.service_descriptor); + /* + * Copy the newly generated ip-address to the key backwarts (as only the first part is hashed) + */ + unsigned int i; + + for (i = 0; i < 16; i++) + k[15 - i] = c[i]; + + uint16_t namelen = strlen ((char *) pkt->data + 12) + 1; + + struct map_entry *value = + GNUNET_malloc (sizeof (struct map_entry) + namelen); + char *name = (char *) (value + 1); + + value->namelen = namelen; + memcpy (name, pkt->data + 12, namelen); + + memcpy (&value->desc, &pkt->service_descr, + sizeof (struct GNUNET_vpn_service_descriptor)); + + memset (value->additional_ports, 0, 8192); + + memcpy (&value->hash, &key, sizeof (GNUNET_HashCode)); + + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (hashmap, &key)) { - GNUNET_CLIENT_disconnect (dns_connection, GNUNET_NO); - dns_connection = NULL; + GNUNET_CONTAINER_multihashmap_put (hashmap, &key, value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + + value->heap_node = + GNUNET_CONTAINER_heap_insert (heap, value, + GNUNET_TIME_absolute_get ().abs_value); + if (GNUNET_CONTAINER_heap_get_size (heap) > max_mappings) + GNUNET_SCHEDULER_add_now (collect_mappings, NULL); } -} + else + GNUNET_free (value); -static void helper_read(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tsdkctx); -static void start_helper_and_schedule(void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) { + list = + GNUNET_malloc (htons (pkt->hdr.size) + + sizeof (struct answer_packet_list) - + sizeof (struct answer_packet)); - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; + memcpy (&list->pkt, pkt, htons (pkt->hdr.size)); - helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO); - helper_out = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES); + } + else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_REV) + { + GNUNET_HashCode key; - if (helper_in == NULL || helper_out == NULL) return; + memset (&key, 0, sizeof key); + unsigned char *k = (unsigned char *) &key; + unsigned char *s = pkt->data + 12; + int i = 0; - helper_pid = GNUNET_OS_start_process(helper_in, helper_out, "gnunet-helper-vpn", "gnunet-helper-vpn", NULL); + /* Whoever designed the reverse IPv6-lookup is batshit insane */ + for (i = 0; i < 16; i++) + { + unsigned char c1 = s[(4 * i) + 1]; + unsigned char c2 = s[(4 * i) + 3]; + + if (c1 <= '9') + k[i] = c1 - '0'; + else + k[i] = c1 - 87; /* 87 is the difference between 'a' and 10 */ + if (c2 <= '9') + k[i] += 16 * (c2 - '0'); + else + k[i] += 16 * (c2 - 87); + } - fh_from_helper = GNUNET_DISK_pipe_handle (helper_out, GNUNET_DISK_PIPE_END_READ); - fh_to_helper = GNUNET_DISK_pipe_handle (helper_in, GNUNET_DISK_PIPE_END_WRITE); + struct map_entry *map_entry = + GNUNET_CONTAINER_multihashmap_get (hashmap, &key); + uint16_t offset = ntohs (pkt->addroffset); - GNUNET_DISK_pipe_close_end(helper_out, GNUNET_DISK_PIPE_END_WRITE); - GNUNET_DISK_pipe_close_end(helper_in, GNUNET_DISK_PIPE_END_READ); + if (map_entry == NULL) + { + GNUNET_free (pkt); + return; + } - GNUNET_SCHEDULER_add_read_file (sched, GNUNET_TIME_UNIT_FOREVER_REL, fh_from_helper, &helper_read, NULL); -} + GNUNET_CONTAINER_heap_update_cost (heap, map_entry->heap_node, + GNUNET_TIME_absolute_get ().abs_value); -static void restart_helper(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) { - // Kill the helper - PLIBC_KILL(helper_pid, SIGKILL); - GNUNET_OS_process_wait(helper_pid); + unsigned short namelen = htons (map_entry->namelen); + char *name = (char *) (map_entry + 1); - /* Tell the dns-service to rehijack the dns-port - * The routing-table gets flushed if an interface disappears. - */ - restart_hijack = 1; - GNUNET_CLIENT_notify_transmit_ready(dns_connection, sizeof(struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL); + list = + GNUNET_malloc (sizeof (struct answer_packet_list) - + sizeof (struct answer_packet) + offset + 2 + + ntohs (namelen)); - GNUNET_DISK_pipe_close(helper_in); - GNUNET_DISK_pipe_close(helper_out); + struct answer_packet *rpkt = &list->pkt; - // Restart the helper - GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_UNIT_SECONDS, start_helper_and_schedule, NULL); + /* The offset points to the first byte belonging to the address */ + memcpy (rpkt, pkt, offset - 1); -} + rpkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP; + rpkt->hdr.size = ntohs (offset + 2 + ntohs (namelen)); -static void helper_read(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tsdkctx) { - char buf[65535]; + memcpy (((char *) rpkt) + offset, &namelen, 2); + memcpy (((char *) rpkt) + offset + 2, name, ntohs (namelen)); - if (tsdkctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) - return; + } + else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_IP) + { + list = + GNUNET_malloc (htons (pkt->hdr.size) + + sizeof (struct answer_packet_list) - + sizeof (struct answer_packet)); + memcpy (&list->pkt, pkt, htons (pkt->hdr.size)); + } + else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_REMOTE_AAAA) + { + pkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP; - int t = GNUNET_DISK_file_read(fh_from_helper, &buf, 65535); - if (t<=0) { - GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read error for header from vpn-helper: %m\n"); - GNUNET_SCHEDULER_add_now(sched, restart_helper, cls); - return; - } + GNUNET_HashCode key; - /* FIXME */ GNUNET_SERVER_mst_receive(mst, NULL, buf, t, 0, 0); + memset (&key, 0, sizeof (GNUNET_HashCode)); - GNUNET_SCHEDULER_add_read_file (sched, GNUNET_TIME_UNIT_FOREVER_REL, fh_from_helper, &helper_read, NULL); -} + unsigned char *c = ((unsigned char *) pkt) + ntohs (pkt->addroffset); -static uint16_t calculate_ip_checksum(uint16_t* hdr, short len) { - uint32_t sum = 0; - for(; len >= 2; len -= 2) - sum += *(hdr++); - if (len == 1) - sum += *((unsigned char*)hdr); + new_ip6addr_remote (c, pkt->addr, pkt->addrsize); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "New mapping to %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", + c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], + c[10], c[11], c[12], c[13], c[14], c[15]); + unsigned char *k = (unsigned char *) &key; - sum = (sum >> 16) + (sum & 0xFFFF); + /* + * Copy the newly generated ip-address to the key backwards (as only the first part is used in the hash-table) + */ + unsigned int i; - return ~sum; -} + for (i = 0; i < 16; i++) + k[15 - i] = c[i]; + + uint16_t namelen = strlen ((char *) pkt->data + 12) + 1; -static void helper_write(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tsdkctx) { - if (tsdkctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) - return; - struct answer_packet_list* ans = answer_proc_head; - size_t len = ntohs(ans->pkt.hdr.size); + struct map_entry *value = + GNUNET_malloc (sizeof (struct map_entry) + namelen); + char *name = (char *) (value + 1); - GNUNET_assert(ans->pkt.subtype == GNUNET_DNS_ANSWER_TYPE_IP); + value->namelen = namelen; + memcpy (name, pkt->data + 12, namelen); - size_t data_len = len - sizeof(struct answer_packet) + 1; - size_t net_len = sizeof(struct ip_hdr) + sizeof(struct udp_dns) + data_len; - size_t pkt_len = sizeof(struct GNUNET_MessageHeader) + sizeof(struct pkt_tun) + net_len; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting addrlen to %d\n", + pkt->addrsize); + value->addrlen = pkt->addrsize; + memcpy (&value->addr, &pkt->addr, pkt->addrsize); + memset (value->additional_ports, 0, 8192); - struct ip_udp_dns* pkt = alloca(pkt_len); - memset(pkt, 0, pkt_len); + memcpy (&value->hash, &key, sizeof (GNUNET_HashCode)); - pkt->shdr.size = htons(pkt_len); - pkt->shdr.type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER); + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (hashmap, &key)) + { + GNUNET_CONTAINER_multihashmap_put (hashmap, &key, value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + value->heap_node = + GNUNET_CONTAINER_heap_insert (heap, value, + GNUNET_TIME_absolute_get ().abs_value); + if (GNUNET_CONTAINER_heap_get_size (heap) > max_mappings) + GNUNET_SCHEDULER_add_now (collect_mappings, NULL); + } + else + GNUNET_free (value); - pkt->tun.flags = 0; - pkt->tun.type = htons(0x0800); + list = + GNUNET_malloc (htons (pkt->hdr.size) + + sizeof (struct answer_packet_list) - + sizeof (struct answer_packet)); - pkt->ip_hdr.version = 4; - pkt->ip_hdr.hdr_lngth = 5; - pkt->ip_hdr.diff_serv = 0; - pkt->ip_hdr.tot_lngth = htons(net_len); - pkt->ip_hdr.ident = 0; - pkt->ip_hdr.flags = 0; - pkt->ip_hdr.frag_off = 0; - pkt->ip_hdr.ttl = 255; - pkt->ip_hdr.proto = 0x11; /* UDP */ - pkt->ip_hdr.chks = 0; /* Will be calculated later*/ - pkt->ip_hdr.sadr = ans->pkt.from; - pkt->ip_hdr.dadr = ans->pkt.to; + memcpy (&list->pkt, pkt, htons (pkt->hdr.size)); + } + else if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_REMOTE_A) + { + pkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP; - pkt->ip_hdr.chks = calculate_ip_checksum((uint16_t*)&pkt->ip_hdr, 5*4); + GNUNET_HashCode key; - pkt->udp_dns.udp_hdr.spt = htons(53); - pkt->udp_dns.udp_hdr.dpt = ans->pkt.dst_port; - pkt->udp_dns.udp_hdr.len = htons(net_len - sizeof(struct ip_hdr)); - pkt->udp_dns.udp_hdr.crc = 0; /* Optional for IPv4 */ + memset (&key, 0, sizeof (GNUNET_HashCode)); - memcpy(&pkt->udp_dns.data, ans->pkt.data, data_len); - - GNUNET_CONTAINER_DLL_remove (answer_proc_head, answer_proc_tail, ans); - GNUNET_free(ans); + unsigned char *c = ((unsigned char *) pkt) + ntohs (pkt->addroffset); - /* FIXME */ GNUNET_DISK_file_write(fh_to_helper, pkt, pkt_len); + new_ip4addr_remote (c, pkt->addr, pkt->addrsize); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New mapping to %d.%d.%d.%d\n", c[0], + c[1], c[2], c[3]); + unsigned char *k = (unsigned char *) &key; - if (answer_proc_head != NULL) - GNUNET_SCHEDULER_add_write_file (sched, GNUNET_TIME_UNIT_FOREVER_REL, fh_to_helper, &helper_write, NULL); -} + /* + * Copy the newly generated ip-address to the key backwards (as only the first part is used in the hash-table) + */ + unsigned int i; -size_t send_query(void* cls, size_t size, void* buf) -{ - size_t len; - if (restart_hijack == 1) + for (i = 0; i < 4; i++) + k[3 - i] = c[i]; + + uint16_t namelen = strlen ((char *) pkt->data + 12) + 1; + + struct map_entry *value = + GNUNET_malloc (sizeof (struct map_entry) + namelen); + char *name = (char *) (value + 1); + + value->namelen = namelen; + memcpy (name, pkt->data + 12, namelen); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting addrlen to %d\n", + pkt->addrsize); + value->addrlen = pkt->addrsize; + memcpy (&value->addr, &pkt->addr, pkt->addrsize); + memset (value->additional_ports, 0, 8192); + + memcpy (&value->hash, &key, sizeof (GNUNET_HashCode)); + + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (hashmap, &key)) { - restart_hijack = 0; - GNUNET_assert(sizeof(struct GNUNET_MessageHeader) >= size); - struct GNUNET_MessageHeader* hdr = buf; - len = sizeof(struct GNUNET_MessageHeader); - hdr->size = htons(len); - hdr->type = htons(GNUNET_MESSAGE_TYPE_REHIJACK); + GNUNET_CONTAINER_multihashmap_put (hashmap, &key, value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + value->heap_node = + GNUNET_CONTAINER_heap_insert (heap, value, + GNUNET_TIME_absolute_get ().abs_value); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Mapping is saved in the hashmap with key %08x.\n", + *((uint32_t *) (&key))); + if (GNUNET_CONTAINER_heap_get_size (heap) > max_mappings) + GNUNET_SCHEDULER_add_now (collect_mappings, NULL); } + else + GNUNET_free (value); + + list = + GNUNET_malloc (htons (pkt->hdr.size) + + sizeof (struct answer_packet_list) - + sizeof (struct answer_packet)); + + memcpy (&list->pkt, pkt, htons (pkt->hdr.size)); + } else - { - struct query_packet_list* query = head; - len = ntohs(query->pkt.hdr.size); + { + GNUNET_break (0); + GNUNET_free (pkt); + return; + } - GNUNET_assert(len <= size); + GNUNET_free (pkt); - memcpy(buf, &query->pkt.hdr, len); + GNUNET_CONTAINER_DLL_insert_after (answer_proc_head, answer_proc_tail, + answer_proc_tail, list); - GNUNET_CONTAINER_DLL_remove (head, tail, query); + schedule_helper_write (GNUNET_TIME_UNIT_FOREVER_REL, NULL); - GNUNET_free(query); - } + return; +} - if (head != NULL || restart_hijack == 1) { - GNUNET_CLIENT_notify_transmit_ready(dns_connection, ntohs(head->pkt.hdr.size), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL); - } +/** + * Sets a bit active in a bitArray. + * + * @param bitArray memory area to set the bit in + * @param bitIdx which bit to set + */ +void +setBit (char *bitArray, unsigned int bitIdx) +{ + size_t arraySlot; + unsigned int targetBit; - return len; + arraySlot = bitIdx / 8; + targetBit = (1L << (bitIdx % 8)); + bitArray[arraySlot] |= targetBit; } -static void message_token(void *cls, void *client, const struct GNUNET_MessageHeader *message) { - if (ntohs(message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) return; - - struct tun_pkt *pkt_tun = (struct tun_pkt*) message; - - if (ntohs(pkt_tun->tun.type) == 0x86dd) { - struct ip6_pkt *pkt6 = (struct ip6_pkt*) message; - struct ip6_tcp *pkt6_tcp; - struct ip6_udp *pkt6_udp; - - pkt_printf(pkt6); - switch(pkt6->ip6_hdr.nxthdr) { - case 0x06: - pkt6_tcp = (struct ip6_tcp*)pkt6; - pkt_printf_ip6tcp(pkt6_tcp); - break; - case 0x11: - pkt6_udp = (struct ip6_udp*)pkt6; - pkt_printf_ip6udp(pkt6_udp); - if (ntohs(pkt6_udp->udp_hdr.dpt) == 53) { - pkt_printf_ip6dns((struct ip6_udp_dns*)pkt6_udp); - } - break; - } - } else if (ntohs(pkt_tun->tun.type) == 0x0800) { - struct ip_pkt *pkt = (struct ip_pkt*) message; - struct ip_udp *udp = (struct ip_udp*) message; - GNUNET_assert(pkt->ip_hdr.version == 4); - if (pkt->ip_hdr.proto == 0x11 && ntohs(udp->udp_hdr.dpt) == 53 ) { - size_t len = sizeof(struct query_packet) + ntohs(udp->udp_hdr.len) - 9; /* 9 = 8 for the udp-header + 1 for the unsigned char data[1]; */ - struct query_packet_list* query = GNUNET_malloc(len + 2*sizeof(struct query_packet_list*)); - query->pkt.hdr.type = htons(GNUNET_MESSAGE_TYPE_LOCAL_QUERY_DNS); - query->pkt.hdr.size = htons(len); - query->pkt.orig_to = pkt->ip_hdr.dadr; - query->pkt.orig_from = pkt->ip_hdr.sadr; - query->pkt.src_port = udp->udp_hdr.spt; - memcpy(query->pkt.data, udp->data, ntohs(udp->udp_hdr.len) - 8); - - GNUNET_CONTAINER_DLL_insert_after(head, tail, tail, query); - - if (dns_connection != NULL) - /* struct GNUNET_CLIENT_TransmitHandle* th = */ GNUNET_CLIENT_notify_transmit_ready(dns_connection, len, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL); - } - } +/** + * Clears a bit from bitArray. + * + * @param bitArray memory area to set the bit in + * @param bitIdx which bit to unset + */ +void +clearBit (char *bitArray, unsigned int bitIdx) +{ + size_t slot; + unsigned int targetBit; + slot = bitIdx / 8; + targetBit = (1L << (bitIdx % 8)); + bitArray[slot] = bitArray[slot] & (~targetBit); } -static void -dns_answer_handler(void* cls, const struct GNUNET_MessageHeader *msg); +/** + * Checks if a bit is active in the bitArray + * + * @param bitArray memory area to set the bit in + * @param bitIdx which bit to test + * @return GNUNET_YES if the bit is set, GNUNET_NO if not. + */ +int +testBit (char *bitArray, unsigned int bitIdx) +{ + size_t slot; + unsigned int targetBit; -static void -reconnect_to_service_dns (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) { - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Connecting\n"); - GNUNET_assert (dns_connection == NULL); - dns_connection = GNUNET_CLIENT_connect (sched, "dns", cfg); - GNUNET_CLIENT_receive(dns_connection, &dns_answer_handler, NULL, GNUNET_TIME_UNIT_FOREVER_REL); - if (head != NULL) - /* struct GNUNET_CLIENT_TransmitHandle* th = */ GNUNET_CLIENT_notify_transmit_ready(dns_connection, ntohs(head->pkt.hdr.size), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL); + slot = bitIdx / 8; + targetBit = (1L << (bitIdx % 8)); + if (bitArray[slot] & targetBit) + return GNUNET_YES; + else + return GNUNET_NO; } +/** + * @brief Add the port to the list of additional ports in the map_entry + * + * @param me the map_entry + * @param port the port in host-byte-order + */ static void -process_answer(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tc) { - struct answer_packet* pkt = cls; +add_additional_port (struct map_entry *me, uint16_t port) +{ + setBit (me->additional_ports, port); +} + +static int +receive_udp_back (void *cls + __attribute__ ((unused)), struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi + __attribute__ ((unused))) +{ + GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); + struct remote_addr *s = (struct remote_addr *) desc; + struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1); + const struct GNUNET_PeerIdentity *other = sender; + struct tunnel_state *ts = *tunnel_ctx; + + if (16 == ts->addrlen) + { + size_t size = + sizeof (struct ip6_udp) + ntohs (pkt->len) - 1 - + sizeof (struct udp_pkt); + + struct ip6_udp *pkt6 = alloca (size); + + GNUNET_assert (pkt6 != NULL); + + if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK) + new_ip6addr (pkt6->ip6_hdr.sadr, &other->hashPubKey, desc); + else + new_ip6addr_remote (pkt6->ip6_hdr.sadr, s->addr, s->addrlen); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Relaying calc:%d gnu:%d udp:%d bytes!\n", size, + ntohs (message->size), ntohs (pkt->len)); + + pkt6->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + pkt6->shdr.size = htons (size); + + pkt6->tun.flags = 0; + pkt6->tun.type = htons (0x86dd); + + pkt6->ip6_hdr.version = 6; + pkt6->ip6_hdr.tclass_h = 0; + pkt6->ip6_hdr.tclass_l = 0; + pkt6->ip6_hdr.flowlbl = 0; + pkt6->ip6_hdr.paylgth = pkt->len; + pkt6->ip6_hdr.nxthdr = IPPROTO_UDP; + pkt6->ip6_hdr.hoplmt = 0xff; + + { + char *ipv6addr; + + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", + "IPV6ADDR", + &ipv6addr)); + inet_pton (AF_INET6, ipv6addr, pkt6->ip6_hdr.dadr); + GNUNET_free (ipv6addr); + } + memcpy (&pkt6->udp_hdr, pkt, ntohs (pkt->len)); + + GNUNET_HashCode *key = address6_mapping_exists (pkt6->ip6_hdr.sadr); - if (pkt->subtype == GNUNET_DNS_ANSWER_TYPE_SERVICE) + GNUNET_assert (key != NULL); + + struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); + + GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, + GNUNET_TIME_absolute_get ().abs_value); + + GNUNET_free (key); + + GNUNET_assert (me != NULL); + if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK) + { + GNUNET_assert (me->desc. + service_type & htonl (GNUNET_DNS_SERVICE_TYPE_UDP)); + if (!port_in_ports (me->desc.ports, pkt6->udp_hdr.spt) && + !testBit (me->additional_ports, ntohs (pkt6->udp_hdr.spt))) { - unsigned char ip6addr[16]; - - pkt->subtype = GNUNET_DNS_ANSWER_TYPE_IP; - memcpy(ip6addr, (int[]){htons(0x1234)}, 2); - memcpy(ip6addr+2, &pkt->peer, 7); - memcpy(ip6addr+9, &pkt->service_descriptor, 7); - - memcpy(((char*)pkt)+ntohs(pkt->addroffset), ip6addr, 16); - - /*FIXME: - * -save DNS_Record into hashmap, pointed to by ip - * -regularily walk through hashmap, deleting old entries - * when is an entry old? - * have a last-used field - * don't remove if last-used "recent", ask dht again if record expired - */ + add_additional_port (me, ntohs (pkt6->udp_hdr.spt)); } + } + + pkt6->udp_hdr.crc = 0; + uint32_t sum = 0; + + sum = + calculate_checksum_update (sum, (uint16_t *) & pkt6->ip6_hdr.sadr, 16); + sum = + calculate_checksum_update (sum, (uint16_t *) & pkt6->ip6_hdr.dadr, 16); + uint32_t tmp = (pkt6->udp_hdr.len & 0xffff); + + sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4); + tmp = htons (((pkt6->ip6_hdr.nxthdr & 0x00ff))); + sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4); + + sum = + calculate_checksum_update (sum, (uint16_t *) & pkt6->udp_hdr, + ntohs (pkt->len)); + pkt6->udp_hdr.crc = calculate_checksum_end (sum); + + write_to_helper (pkt6, size); + } + else + { + size_t size = + sizeof (struct ip_udp) + ntohs (pkt->len) - 1 - sizeof (struct udp_pkt); + + struct ip_udp *pkt4 = alloca (size); + + GNUNET_assert (pkt4 != NULL); + + GNUNET_assert (ntohs (message->type) == + GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK); + uint32_t sadr; + + new_ip4addr_remote ((unsigned char *) &sadr, s->addr, s->addrlen); + pkt4->ip_hdr.sadr = sadr; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Relaying calc:%d gnu:%d udp:%d bytes!\n", size, + ntohs (message->size), ntohs (pkt->len)); - struct answer_packet_list* list = GNUNET_malloc(htons(pkt->hdr.size) + 2*sizeof(struct answer_packet_list*)); + pkt4->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + pkt4->shdr.size = htons (size); - memcpy(&list->pkt, pkt, htons(pkt->hdr.size)); + pkt4->tun.flags = 0; + pkt4->tun.type = htons (0x0800); - GNUNET_CONTAINER_DLL_insert_after(answer_proc_head, answer_proc_tail, answer_proc_tail, list); + pkt4->ip_hdr.version = 4; + pkt4->ip_hdr.hdr_lngth = 5; + pkt4->ip_hdr.diff_serv = 0; + pkt4->ip_hdr.tot_lngth = htons (20 + ntohs (pkt->len)); + pkt4->ip_hdr.ident = 0; + pkt4->ip_hdr.flags = 0; + pkt4->ip_hdr.frag_off = 0; + pkt4->ip_hdr.ttl = 255; + pkt4->ip_hdr.proto = IPPROTO_UDP; + pkt4->ip_hdr.chks = 0; /* Will be calculated later */ - GNUNET_SCHEDULER_add_write_file (sched, GNUNET_TIME_UNIT_FOREVER_REL, fh_to_helper, &helper_write, NULL); + { + char *ipv4addr; + uint32_t dadr; + + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", + "IPV4ADDR", + &ipv4addr)); + inet_pton (AF_INET, ipv4addr, &dadr); + GNUNET_free (ipv4addr); + pkt4->ip_hdr.dadr = dadr; + } + memcpy (&pkt4->udp_hdr, pkt, ntohs (pkt->len)); + + GNUNET_HashCode *key = address4_mapping_exists (pkt4->ip_hdr.sadr); + + GNUNET_assert (key != NULL); + + struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); + + GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, + GNUNET_TIME_absolute_get ().abs_value); + + GNUNET_free (key); + + GNUNET_assert (me != NULL); + + pkt4->udp_hdr.crc = 0; /* Optional for IPv4 */ - return; + pkt4->ip_hdr.chks = + calculate_ip_checksum ((uint16_t *) & pkt4->ip_hdr, 5 * 4); + + write_to_helper (pkt4, size); + } + + return GNUNET_OK; } -static void -dns_answer_handler(void* cls, const struct GNUNET_MessageHeader *msg) +static int +receive_tcp_back (void *cls + __attribute__ ((unused)), struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, const struct GNUNET_PeerIdentity *sender + __attribute__ ((unused)), + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi + __attribute__ ((unused))) { - if (msg == NULL) + GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); + struct remote_addr *s = (struct remote_addr *) desc; + struct tcp_pkt *pkt = (struct tcp_pkt *) (desc + 1); + const struct GNUNET_PeerIdentity *other = sender; + struct tunnel_state *ts = *tunnel_ctx; + + size_t pktlen = + ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - + sizeof (GNUNET_HashCode); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received TCP-Packet back, addrlen = %d\n", s->addrlen); + + if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK || + ts->addrlen == 16) + { + size_t size = pktlen + sizeof (struct ip6_tcp) - 1; + + struct ip6_tcp *pkt6 = alloca (size); + + memset (pkt6, 0, size); + + GNUNET_assert (pkt6 != NULL); + + if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK) + new_ip6addr (pkt6->ip6_hdr.sadr, &other->hashPubKey, desc); + else + new_ip6addr_remote (pkt6->ip6_hdr.sadr, s->addr, s->addrlen); + + pkt6->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + pkt6->shdr.size = htons (size); + + pkt6->tun.flags = 0; + pkt6->tun.type = htons (0x86dd); + + pkt6->ip6_hdr.version = 6; + pkt6->ip6_hdr.tclass_h = 0; + pkt6->ip6_hdr.tclass_l = 0; + pkt6->ip6_hdr.flowlbl = 0; + pkt6->ip6_hdr.paylgth = htons (pktlen); + pkt6->ip6_hdr.nxthdr = IPPROTO_TCP; + pkt6->ip6_hdr.hoplmt = 0xff; + { - GNUNET_CLIENT_disconnect(dns_connection, GNUNET_NO); - dns_connection = NULL; - GNUNET_SCHEDULER_add_delayed (sched, - GNUNET_TIME_UNIT_SECONDS, - &reconnect_to_service_dns, - NULL); - return; + char *ipv6addr; + + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", + "IPV6ADDR", + &ipv6addr)); + inet_pton (AF_INET6, ipv6addr, pkt6->ip6_hdr.dadr); + GNUNET_free (ipv6addr); } + memcpy (&pkt6->tcp_hdr, pkt, pktlen); + + GNUNET_HashCode *key = address6_mapping_exists (pkt6->ip6_hdr.sadr); + + GNUNET_assert (key != NULL); + + struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); + + GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, + GNUNET_TIME_absolute_get ().abs_value); + + GNUNET_free (key); + + GNUNET_assert (me != NULL); + if (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK) + GNUNET_assert (me->desc. + service_type & htonl (GNUNET_DNS_SERVICE_TYPE_TCP)); + + pkt6->tcp_hdr.crc = 0; + uint32_t sum = 0; + uint32_t tmp; + + sum = + calculate_checksum_update (sum, (uint16_t *) & pkt6->ip6_hdr.sadr, 16); + sum = + calculate_checksum_update (sum, (uint16_t *) & pkt6->ip6_hdr.dadr, 16); + tmp = htonl (pktlen); + sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4); + tmp = htonl (((pkt6->ip6_hdr.nxthdr & 0x000000ff))); + sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4); + + sum = + calculate_checksum_update (sum, (uint16_t *) & pkt6->tcp_hdr, + ntohs (pkt6->ip6_hdr.paylgth)); + pkt6->tcp_hdr.crc = calculate_checksum_end (sum); + + write_to_helper (pkt6, size); + } + else + { + size_t size = pktlen + sizeof (struct ip_tcp) - 1; + + struct ip_tcp *pkt4 = alloca (size); + + GNUNET_assert (pkt4 != NULL); + memset (pkt4, 0, size); + + GNUNET_assert (ntohs (message->type) == + GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK); + uint32_t sadr; + + new_ip4addr_remote ((unsigned char *) &sadr, s->addr, s->addrlen); + pkt4->ip_hdr.sadr = sadr; + + pkt4->shdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + pkt4->shdr.size = htons (size); + + pkt4->tun.flags = 0; + pkt4->tun.type = htons (0x0800); + + pkt4->ip_hdr.version = 4; + pkt4->ip_hdr.hdr_lngth = 5; + pkt4->ip_hdr.diff_serv = 0; + pkt4->ip_hdr.tot_lngth = htons (20 + pktlen); + pkt4->ip_hdr.ident = 0; + pkt4->ip_hdr.flags = 0; + pkt4->ip_hdr.frag_off = 0; + pkt4->ip_hdr.ttl = 255; + pkt4->ip_hdr.proto = IPPROTO_TCP; + pkt4->ip_hdr.chks = 0; /* Will be calculated later */ - if (msg->type != htons(GNUNET_MESSAGE_TYPE_LOCAL_RESPONSE_DNS)) { - GNUNET_break (0); - GNUNET_CLIENT_disconnect(dns_connection, GNUNET_NO); - dns_connection = NULL; - GNUNET_SCHEDULER_add_now (sched, - &reconnect_to_service_dns, - NULL); - return; + char *ipv4addr; + uint32_t dadr; + + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", + "IPV4ADDR", + &ipv4addr)); + inet_pton (AF_INET, ipv4addr, &dadr); + GNUNET_free (ipv4addr); + pkt4->ip_hdr.dadr = dadr; } - void *pkt = GNUNET_malloc(ntohs(msg->size)); - memcpy(pkt, msg, ntohs(msg->size)); + memcpy (&pkt4->tcp_hdr, pkt, pktlen); + + GNUNET_HashCode *key = address4_mapping_exists (pkt4->ip_hdr.sadr); + + GNUNET_assert (key != NULL); + + struct map_entry *me = GNUNET_CONTAINER_multihashmap_get (hashmap, key); + + GNUNET_CONTAINER_heap_update_cost (heap, me->heap_node, + GNUNET_TIME_absolute_get ().abs_value); + + GNUNET_free (key); + + GNUNET_assert (me != NULL); + pkt4->tcp_hdr.crc = 0; + uint32_t sum = 0; + uint32_t tmp; + + tmp = pkt4->ip_hdr.sadr; + sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4); + tmp = pkt4->ip_hdr.dadr; + sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4); + + tmp = (0x06 << 16) | (0xffff & pktlen); // 0x06 for TCP? - GNUNET_SCHEDULER_add_now(sched, process_answer, pkt); - GNUNET_CLIENT_receive(dns_connection, &dns_answer_handler, NULL, GNUNET_TIME_UNIT_FOREVER_REL); + tmp = htonl (tmp); + + sum = calculate_checksum_update (sum, (uint16_t *) & tmp, 4); + + sum = calculate_checksum_update (sum, (uint16_t *) & pkt4->tcp_hdr, pktlen); + pkt4->tcp_hdr.crc = calculate_checksum_end (sum); + + pkt4->ip_hdr.chks = + calculate_ip_checksum ((uint16_t *) & pkt4->ip_hdr, 5 * 4); + + write_to_helper (pkt4, size); + } + + return GNUNET_OK; +} + +static void * +new_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel, + const struct GNUNET_PeerIdentity *initiator, + const struct GNUNET_ATS_Information *atsi) +{ + /* Why should anyone open an inbound tunnel to vpn? */ + GNUNET_break (0); + return NULL; +} + +static void +cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel, void *tunnel_ctx) +{ + /* Why should anyone open an inbound tunnel to vpn? */ + GNUNET_break (0); } /** * Main function that will be run by the scheduler. * * @param cls closure - * @param sched the scheduler to use * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param cfg configuration + * @param cfg_ configuration */ static void -run (void *cls, - struct GNUNET_SCHEDULER_Handle *sched_, - char *const *args, - const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg_) +run (void *cls, char *const *args __attribute__ ((unused)), const char *cfgfilep + __attribute__ ((unused)), const struct GNUNET_CONFIGURATION_Handle *cfg_) { - sched = sched_; - mst = GNUNET_SERVER_mst_create(&message_token, NULL); + static const struct GNUNET_MESH_MessageHandler handlers[] = { + {receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK, 0}, + {receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK, 0}, + {receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK, 0}, + {receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK, 0}, + {NULL, 0, 0} + }; + + static const GNUNET_MESH_ApplicationType types[] = { + GNUNET_APPLICATION_TYPE_END + }; + + mesh_handle = + GNUNET_MESH_connect (cfg_, 42, NULL, new_tunnel, cleaner, handlers, + types); cfg = cfg_; restart_hijack = 0; - GNUNET_SCHEDULER_add_now (sched, &reconnect_to_service_dns, NULL); - GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); - GNUNET_SCHEDULER_add_now (sched, start_helper_and_schedule, NULL); + hashmap = GNUNET_CONTAINER_multihashmap_create (65536); + heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); + GNUNET_CONFIGURATION_get_value_number (cfg, "vpn", "MAX_MAPPINGg", + &max_mappings); + udp_connections = GNUNET_CONTAINER_multihashmap_create (65536); + conn_task = GNUNET_SCHEDULER_add_now (connect_to_service_dns, NULL); + shs_task = + GNUNET_SCHEDULER_add_after (conn_task, start_helper_and_schedule, NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); } - /** * The main function to obtain template from gnunetd. * @@ -462,10 +1291,7 @@ main (int argc, char *const *argv) }; return (GNUNET_OK == - GNUNET_PROGRAM_run (argc, - argv, - "gnunet-daemon-vpn", - gettext_noop ("help text"), + GNUNET_PROGRAM_run (argc, argv, "vpn", gettext_noop ("help text"), options, &run, NULL)) ? ret : 1; }