From bc795e47152af4db3800ffd6ea15c5833c4404ff Mon Sep 17 00:00:00 2001 From: =?utf8?q?Philipp=20T=C3=B6lke?= Date: Mon, 10 Jan 2011 21:41:33 +0000 Subject: [PATCH] split up daemon-vpn in multiple files, remove exit-functionality --- src/vpn/Makefile.am | 6 +- src/vpn/gnunet-daemon-vpn-dns.c | 164 +++++++ src/vpn/gnunet-daemon-vpn-dns.h | 83 ++++ src/vpn/gnunet-daemon-vpn-helper.c | 320 ++++++++++++++ src/vpn/gnunet-daemon-vpn-helper.h | 73 ++++ src/vpn/gnunet-daemon-vpn.c | 679 ++--------------------------- src/vpn/gnunet-daemon-vpn.h | 85 ++++ 7 files changed, 754 insertions(+), 656 deletions(-) create mode 100644 src/vpn/gnunet-daemon-vpn-dns.c create mode 100644 src/vpn/gnunet-daemon-vpn-dns.h create mode 100644 src/vpn/gnunet-daemon-vpn-helper.c create mode 100644 src/vpn/gnunet-daemon-vpn-helper.h create mode 100644 src/vpn/gnunet-daemon-vpn.h diff --git a/src/vpn/Makefile.am b/src/vpn/Makefile.am index 5787a875a..24986b9d0 100644 --- a/src/vpn/Makefile.am +++ b/src/vpn/Makefile.am @@ -34,9 +34,11 @@ gnunet_helper_hijack_dns_SOURCES = \ gnunet-helper-hijack-dns.c gnunet_daemon_vpn_SOURCES = \ - gnunet-daemon-vpn.c \ + gnunet-daemon-vpn.c gnunet-daemon-vpn.h \ gnunet-vpn-pretty-print.c gnunet-vpn-pretty-print.h \ - gnunet-dns-parser.c gnunet-dns-parser.h + gnunet-dns-parser.c gnunet-dns-parser.h \ + gnunet-daemon-vpn-helper.c gnunet-daemon-vpn-helper.h \ + gnunet-daemon-vpn-dns.c gnunet-daemon-vpn-dns.h gnunet_daemon_vpn_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ diff --git a/src/vpn/gnunet-daemon-vpn-dns.c b/src/vpn/gnunet-daemon-vpn-dns.c new file mode 100644 index 000000000..d0b407667 --- /dev/null +++ b/src/vpn/gnunet-daemon-vpn-dns.c @@ -0,0 +1,164 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file vpn/gnunet-daemon-vpn-dns.c + * @brief + * @author Philipp Toelke + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gnunet-daemon-vpn-dns.h" +#include "gnunet-daemon-vpn.h" +#include "gnunet-daemon-vpn-helper.h" +#include "gnunet-service-dns-p.h" +#include "gnunet-vpn-packet.h" + +/** + * Callback called by notify_transmit_ready; sends dns-queries or rehijack-messages + * to the service-dns + * {{{ + */ +size_t +send_query(void* cls, size_t size, void* buf) { + size_t len; + /* + * Send the rehijack-message + */ + if (restart_hijack == 1) + { + restart_hijack = 0; + /* + * The message is just a header + */ + 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); + } + else if (head != NULL) + { + struct query_packet_list* query = head; + len = ntohs(query->pkt.hdr.size); + + GNUNET_assert(len <= size); + + memcpy(buf, &query->pkt.hdr, len); + + GNUNET_CONTAINER_DLL_remove (head, tail, query); + + GNUNET_free(query); + } + else + { + GNUNET_break(0); + len = 0; + } + + /* + * Check whether more data is to be sent + */ + if (head != NULL) + { + GNUNET_CLIENT_notify_transmit_ready(dns_connection, ntohs(head->pkt.hdr.size), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL); + } + else if (restart_hijack == 1) + { + GNUNET_CLIENT_notify_transmit_ready(dns_connection, sizeof(struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL); + } + + return len; +} +/* }}} */ + + +/** + * Connect to the service-dns + */ +void +connect_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 to service-dns\n"); + GNUNET_assert (dns_connection == NULL); + dns_connection = GNUNET_CLIENT_connect ("dns", cfg); + /* This would most likely be a misconfiguration */ + GNUNET_assert(dns_connection != NULL); + GNUNET_CLIENT_receive(dns_connection, &dns_answer_handler, NULL, GNUNET_TIME_UNIT_FOREVER_REL); + + /* If a packet is already in the list, schedule to send it */ + if (head != NULL) + GNUNET_CLIENT_notify_transmit_ready(dns_connection, + ntohs(head->pkt.hdr.size), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, + &send_query, + NULL); + else if (restart_hijack == 1) + { + GNUNET_CLIENT_notify_transmit_ready(dns_connection, sizeof(struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL); + } +} + +/** + * This receives packets from the service-dns and schedules process_answer to + * handle it + */ +void +dns_answer_handler(void* cls, const struct GNUNET_MessageHeader *msg) { + /* the service disconnected, reconnect after short wait */ + if (msg == NULL) + { + GNUNET_CLIENT_disconnect(dns_connection, GNUNET_NO); + dns_connection = NULL; + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &connect_to_service_dns, + NULL); + return; + } + + /* the service did something strange, reconnect immediately */ + 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 (&connect_to_service_dns, + NULL); + return; + } + void *pkt = GNUNET_malloc(ntohs(msg->size)); + + memcpy(pkt, msg, ntohs(msg->size)); + + GNUNET_SCHEDULER_add_now(process_answer, pkt); + GNUNET_CLIENT_receive(dns_connection, &dns_answer_handler, NULL, GNUNET_TIME_UNIT_FOREVER_REL); +} + diff --git a/src/vpn/gnunet-daemon-vpn-dns.h b/src/vpn/gnunet-daemon-vpn-dns.h new file mode 100644 index 000000000..f72a29ad1 --- /dev/null +++ b/src/vpn/gnunet-daemon-vpn-dns.h @@ -0,0 +1,83 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file vpn/gnunet-daemon-vpn-dns.h + * @brief + * @author Philipp Toelke + */ +#ifndef GNUNET_DAEMON_VPN_DNS_H +#define GNUNET_DAEMON_VPN_DNS_H + +/** + * a list of outgoing dns-query-packets + */ +struct query_packet_list *head; + +/** + * The last element of the list of outgoing dns-query-packets + */ +struct query_packet_list *tail; + +/** + * Callback called by notify_transmit_ready; sends dns-queries or rehijack-messages + * to the service-dns + */ +size_t send_query(void* cls, size_t size, void* buf); + +/** + * Connect to the service-dns + */ +void connect_to_service_dns (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * This receives packets from the service-dns and schedules process_answer to + * handle it + */ +void dns_answer_handler(void* cls, const struct GNUNET_MessageHeader *msg); + +/** + * The connection to the service-dns + */ +struct GNUNET_CLIENT_Connection *dns_connection; + +/** + * 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. + */ +unsigned char restart_hijack; + +/** + * A list of processed dns-responses. + * + * "processed" means that the packet is complete and can be sent out via udp + * directly + */ +struct answer_packet_list *answer_proc_head; + +/** + * The last element of the list of processed dns-responses. + */ +struct answer_packet_list *answer_proc_tail; + +#endif /* end of include guard: GNUNET-DAEMON-VPN-DNS_H */ diff --git a/src/vpn/gnunet-daemon-vpn-helper.c b/src/vpn/gnunet-daemon-vpn-helper.c new file mode 100644 index 000000000..8c4eb593d --- /dev/null +++ b/src/vpn/gnunet-daemon-vpn-helper.c @@ -0,0 +1,320 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file vpn/gnunet-daemon-vpn-helper.c + * @brief + * @author Philipp Toelke + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gnunet-daemon-vpn-dns.h" +#include "gnunet-daemon-vpn.h" +#include "gnunet-daemon-vpn-helper.h" +#include "gnunet-service-dns-p.h" +#include "gnunet-vpn-packet.h" + +/** + * PipeHandle to receive data from the helper + */ +static struct GNUNET_DISK_PipeHandle* helper_in; + +/** + * PipeHandle to send data to the helper + */ +static struct GNUNET_DISK_PipeHandle* helper_out; + +/** + * FileHandle to receive data from the helper + */ +static const struct GNUNET_DISK_FileHandle* fh_from_helper; + +/** + * FileHandle to send data to the helper + */ +static const struct GNUNET_DISK_FileHandle* fh_to_helper; + +/** + * Start the helper-process + * {{{ + */ +void +start_helper_and_schedule(void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; + + helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO); + helper_out = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES); + + if (helper_in == NULL || helper_out == NULL) return; + + helper_proc = GNUNET_OS_start_process(helper_in, helper_out, "gnunet-helper-vpn", "gnunet-helper-vpn", NULL); + + 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); + + GNUNET_DISK_pipe_close_end(helper_out, GNUNET_DISK_PIPE_END_WRITE); + GNUNET_DISK_pipe_close_end(helper_in, GNUNET_DISK_PIPE_END_READ); + + /* 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); + + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, fh_from_helper, &helper_read, NULL); +} +/*}}}*/ +/** + * Restart the helper-process + * {{{ + */ +void +restart_helper(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) { + // Kill the helper + GNUNET_OS_process_kill (helper_proc, SIGKILL); + GNUNET_OS_process_wait (helper_proc); + GNUNET_OS_process_close (helper_proc); + helper_proc = NULL; + + GNUNET_DISK_pipe_close(helper_in); + GNUNET_DISK_pipe_close(helper_out); + + /* Restart the helper */ + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, start_helper_and_schedule, NULL); +} +/*}}}*/ + +/** + * Read from the helper-process + * {{{ + */ +void +helper_read(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tsdkctx) { + /* no message can be bigger then 64k */ + char buf[65535]; + + if (tsdkctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) + return; + + int t = GNUNET_DISK_file_read(fh_from_helper, &buf, 65535); + + /* On read-error, restart the helper */ + if (t<=0) { + GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read error for header from vpn-helper: %m\n"); + GNUNET_SCHEDULER_add_now(restart_helper, cls); + return; + } + + /* FIXME */ GNUNET_SERVER_mst_receive(mst, NULL, buf, t, 0, 0); + + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, fh_from_helper, &helper_read, NULL); +} +/*}}}*/ + +/** + * Send an dns-answer-packet to the helper + */ +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); + + GNUNET_assert(ans->pkt.subtype == GNUNET_DNS_ANSWER_TYPE_IP); + + GNUNET_assert (20 == sizeof (struct ip_hdr)); + GNUNET_assert (8 == sizeof (struct udp_pkt)); + 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; + + struct ip_udp_dns* pkt = alloca(pkt_len); + GNUNET_assert(pkt != NULL); + memset(pkt, 0, pkt_len); + + /* set the gnunet-header */ + pkt->shdr.size = htons(pkt_len); + pkt->shdr.type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER); + + /* set the tun-header (no flags and ethertype of IPv4) */ + pkt->tun.flags = 0; + pkt->tun.type = htons(0x0800); + + /* set the ip-header */ + 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; + + pkt->ip_hdr.chks = calculate_ip_checksum((uint16_t*)&pkt->ip_hdr, 5*4); + + /* set the udp-header */ + 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 */ + + memcpy(&pkt->udp_dns.data, ans->pkt.data, data_len); + + GNUNET_CONTAINER_DLL_remove (answer_proc_head, answer_proc_tail, ans); + GNUNET_free(ans); + + /* FIXME */ GNUNET_DISK_file_write(fh_to_helper, pkt, pkt_len); + + /* if more packets are available, reschedule */ + if (answer_proc_head != NULL) + GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + fh_to_helper, + &helper_write, + NULL); +} +/** + * Receive packets from the helper-process + */ +void +message_token(void *cls, + void *client, + const struct GNUNET_MessageHeader *message) { + GNUNET_assert(ntohs(message->type) == GNUNET_MESSAGE_TYPE_VPN_HELPER); + + struct tun_pkt *pkt_tun = (struct tun_pkt*) message; + + /* ethertype is ipv6 */ + if (ntohs(pkt_tun->tun.type) == 0x86dd) + { + struct ip6_pkt *pkt6 = (struct ip6_pkt*) message; + GNUNET_assert(pkt6->ip6_hdr.version == 6); + struct ip6_tcp *pkt6_tcp; + struct ip6_udp *pkt6_udp; + struct ip6_icmp *pkt6_icmp; + GNUNET_HashCode* key; + + switch(pkt6->ip6_hdr.nxthdr) + { + case 0x06: + pkt6_tcp = (struct ip6_tcp*)pkt6; + break; + case 0x11: + pkt6_udp = (struct ip6_udp*)pkt6; + if ((key = address_mapping_exists(pkt6->ip6_hdr.dadr)) != NULL) + { + struct map_entry* me = GNUNET_CONTAINER_multihashmap_get(hashmap, key); + GNUNET_assert(me != NULL); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Mapping exists; type: %d; UDP is %d; port: %x/%x!\n", me->desc.service_type, htonl(GNUNET_DNS_SERVICE_TYPE_UDP), pkt6_udp->udp_hdr.dpt, me->desc.ports); + GNUNET_free(key); + if (me->desc.service_type & htonl(GNUNET_DNS_SERVICE_TYPE_UDP) && + (port_in_ports(me->desc.ports, pkt6_udp->udp_hdr.dpt) || + port_in_ports(me->additional_ports, pkt6_udp->udp_hdr.dpt))) + { + size_t size = sizeof(struct GNUNET_PeerIdentity) + sizeof(struct GNUNET_MessageHeader) + sizeof(GNUNET_HashCode) + ntohs(pkt6_udp->udp_hdr.len); + struct GNUNET_PeerIdentity *cls = GNUNET_malloc(size); + struct GNUNET_MessageHeader *hdr = (struct GNUNET_MessageHeader*)(cls+1); + GNUNET_HashCode* hc = (GNUNET_HashCode*)(hdr + 1); + memcpy(cls, &me->desc.peer, sizeof(struct GNUNET_PeerIdentity)); + memcpy(hc, &me->desc.service_descriptor, sizeof(GNUNET_HashCode)); + memcpy(hc+1, &pkt6_udp->udp_hdr, ntohs(pkt6_udp->udp_hdr.len)); + GNUNET_CORE_peer_request_connect(core_handle, + GNUNET_TIME_UNIT_FOREVER_REL, + (struct GNUNET_PeerIdentity*)&me->desc.peer, + send_udp_to_peer, + cls); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Queued to send to peer %x\n", *((unsigned int*)&me->desc.peer)); + } + } + break; + case 0x3a: + /* ICMPv6 */ + pkt6_icmp = (struct ip6_icmp*)pkt6; + /* If this packet is an icmp-echo-request and a mapping exists, answer */ + if (pkt6_icmp->icmp_hdr.type == 0x80 && (key = address_mapping_exists(pkt6->ip6_hdr.dadr)) != NULL) + { + GNUNET_free(key); + pkt6_icmp = GNUNET_malloc(ntohs(pkt6->shdr.size)); + memcpy(pkt6_icmp, pkt6, ntohs(pkt6->shdr.size)); + GNUNET_SCHEDULER_add_now(&send_icmp_response, pkt6_icmp); + } + break; + } + } + /* ethertype is ipv4 */ + 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); + + /* Send dns-packets to the service-dns */ + if (pkt->ip_hdr.proto == 0x11 && ntohs(udp->udp_hdr.dpt) == 53 ) + { + /* 9 = 8 for the udp-header + 1 for the unsigned char data[1]; */ + size_t len = sizeof(struct query_packet) + ntohs(udp->udp_hdr.len) - 9; + + 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); + + GNUNET_assert(head != NULL); + + if (dns_connection != NULL) + GNUNET_CLIENT_notify_transmit_ready(dns_connection, + len, + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, + &send_query, + NULL); + } + } +} + +void write_to_helper(void* buf, size_t len) +{ + (void)GNUNET_DISK_file_write(fh_to_helper, buf, len); +} + +void schedule_helper_write(struct GNUNET_TIME_Relative time, void* cls) +{ + GNUNET_SCHEDULER_add_write_file (time, fh_to_helper, &helper_write, cls); +} diff --git a/src/vpn/gnunet-daemon-vpn-helper.h b/src/vpn/gnunet-daemon-vpn-helper.h new file mode 100644 index 000000000..c7234c092 --- /dev/null +++ b/src/vpn/gnunet-daemon-vpn-helper.h @@ -0,0 +1,73 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file vpn/gnunet-daemon-vpn-helper.h + * @brief + * @author Philipp Toelke + */ +#ifndef GNUNET_DAEMON_VPN_HELPER_H +#define GNUNET_DAEMON_VPN_HELPER_H + +/** + * The process id of the helper + */ +struct GNUNET_OS_Process *helper_proc; + +/** + * The Message-Tokenizer that tokenizes the messages comming from the helper + */ +struct GNUNET_SERVER_MessageStreamTokenizer* mst; + +/** + * Start the helper-process + */ +void start_helper_and_schedule(void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Restart the helper-process + */ +void restart_helper(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx); + +/** + * Read from the helper-process + */ +void helper_read(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tsdkctx); + +/** + * Send an dns-answer-packet to the helper + */ +void helper_write(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tsdkctx); + +/** + * Receive packets from the helper-process + */ +void message_token(void *cls, + void *client, + const struct GNUNET_MessageHeader *message); + +void write_to_helper(void* buf, size_t len); +// GNUNET_DISK_file_write(fh_to_helper, response, ntohs(response->shdr.size)); + +void schedule_helper_write(struct GNUNET_TIME_Relative, void* cls); +// GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, fh_to_helper, &helper_write, NULL); + +#endif /* end of include guard: GNUNET-DAEMON-VPN-HELPER_H */ diff --git a/src/vpn/gnunet-daemon-vpn.c b/src/vpn/gnunet-daemon-vpn.c index 31513f2c2..2d6fef76e 100644 --- a/src/vpn/gnunet-daemon-vpn.c +++ b/src/vpn/gnunet-daemon-vpn.c @@ -20,184 +20,39 @@ /** * @file vpn/gnunet-daemon-vpn.c - * @brief + * @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-helper-p.h" #include "gnunet-vpn-pretty-print.h" #include "gnunet_common.h" +#include #include "gnunet_protocols.h" -#include "gnunet_server_lib.h" -#include "gnunet-service-dns-p.h" -#include "gnunet_core_service.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" /** * Final status code. */ static int ret; -/** - * The configuration to use - */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * PipeHandle to receive data from the helper - */ -static struct GNUNET_DISK_PipeHandle* helper_in; - -/** - * PipeHandle to send data to the helper - */ -static struct GNUNET_DISK_PipeHandle* helper_out; - -/** - * FileHandle to receive data from the helper - */ -static const struct GNUNET_DISK_FileHandle* fh_from_helper; - -/** - * FileHandle to send data to the helper - */ -static const struct GNUNET_DISK_FileHandle* fh_to_helper; - -/** - * The Message-Tokenizer that tokenizes the messages comming from the helper - */ -static struct GNUNET_SERVER_MessageStreamTokenizer* mst; - -/** - * The connection to the service-dns - */ -static struct GNUNET_CLIENT_Connection *dns_connection; - -/** - * 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. - */ -static unsigned char restart_hijack; - -/** - * The process id of the helper - */ -static struct GNUNET_OS_Process *helper_proc; - -/** - * a list of outgoing dns-query-packets - */ -static struct query_packet_list *head; - -/** - * The last element of the list of outgoing dns-query-packets - */ -static struct query_packet_list *tail; - -/** - * A list of processed dns-responses. - * - * "processed" means that the packet is complete and can be sent out via udp - * directly - */ -static struct answer_packet_list *answer_proc_head; - -/** - * The last element of the list of processed dns-responses. - */ -static struct answer_packet_list *answer_proc_tail; - -/** - * The hashmap containing the mappings from ipv6-addresses to gnunet-descriptors - */ -static struct GNUNET_CONTAINER_MultiHashMap* hashmap; - /** * This hashmap contains the mapping from peer, service-descriptor, * source-port and destination-port to a socket */ static struct GNUNET_CONTAINER_MultiHashMap *udp_connections; -/** - * The handle to core - */ -static struct GNUNET_CORE_Handle *core_handle; - -struct map_entry { - struct GNUNET_vpn_service_descriptor desc; - uint16_t namelen; - uint64_t additional_ports; - /** - * In DNS-Format! - */ - char name[1]; -}; - -static void helper_read(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tsdkctx); -static void dns_answer_handler(void* cls, const struct GNUNET_MessageHeader *msg); - -/** - * Callback called by notify_transmit_ready; sends dns-queries or rehijack-messages - * to the service-dns - * {{{ - */ -static size_t -send_query(void* cls, size_t size, void* buf) { - size_t len; - /* - * Send the rehijack-message - */ - if (restart_hijack == 1) - { - restart_hijack = 0; - /* - * The message is just a header - */ - 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); - } - else - { - struct query_packet_list* query = head; - len = ntohs(query->pkt.hdr.size); - - GNUNET_assert(len <= size); - - memcpy(buf, &query->pkt.hdr, len); - - GNUNET_CONTAINER_DLL_remove (head, tail, query); - - GNUNET_free(query); - } - - /* - * Check whether more data is to be sent - */ - if (head != NULL) - { - GNUNET_CLIENT_notify_transmit_ready(dns_connection, ntohs(head->pkt.hdr.size), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL); - } - else if (restart_hijack == 1) - { - GNUNET_CLIENT_notify_transmit_ready(dns_connection, sizeof(struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL); - } - - return len; -} -/* }}} */ - /** * Function scheduled as very last function, cleans up after us *{{{ @@ -231,86 +86,6 @@ cleanup(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) { } /*}}}*/ -/** - * Start the helper-process - * {{{ - */ -static void -start_helper_and_schedule(void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) { - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - return; - - helper_in = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO); - helper_out = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES); - - if (helper_in == NULL || helper_out == NULL) return; - - helper_proc = GNUNET_OS_start_process(helper_in, helper_out, "gnunet-helper-vpn", "gnunet-helper-vpn", NULL); - - 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); - - GNUNET_DISK_pipe_close_end(helper_out, GNUNET_DISK_PIPE_END_WRITE); - GNUNET_DISK_pipe_close_end(helper_in, GNUNET_DISK_PIPE_END_READ); - - /* 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); - - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, fh_from_helper, &helper_read, NULL); -} -/*}}}*/ - -/** - * Restart the helper-process - * {{{ - */ -static void -restart_helper(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) { - // Kill the helper - GNUNET_OS_process_kill (helper_proc, SIGKILL); - GNUNET_OS_process_wait (helper_proc); - GNUNET_OS_process_close (helper_proc); - helper_proc = NULL; - - GNUNET_DISK_pipe_close(helper_in); - GNUNET_DISK_pipe_close(helper_out); - - /* Restart the helper */ - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, start_helper_and_schedule, NULL); -} -/*}}}*/ - -/** - * Read from the helper-process - * {{{ - */ -static void -helper_read(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tsdkctx) { - /* no message can be bigger then 64k */ - char buf[65535]; - - if (tsdkctx->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) - return; - - int t = GNUNET_DISK_file_read(fh_from_helper, &buf, 65535); - - /* On read-error, restart the helper */ - if (t<=0) { - GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read error for header from vpn-helper: %m\n"); - GNUNET_SCHEDULER_add_now(restart_helper, cls); - return; - } - - /* FIXME */ GNUNET_SERVER_mst_receive(mst, NULL, buf, t, 0, 0); - - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, fh_from_helper, &helper_read, NULL); -} -/*}}}*/ - static uint32_t calculate_checksum_update(uint32_t sum, uint16_t *hdr, short len) { for(; len >= 2; len -= 2) sum += *(hdr++); @@ -329,84 +104,16 @@ static uint16_t calculate_checksum_end(uint32_t sum) { /** * Calculate the checksum of an IPv4-Header */ -static uint16_t +uint16_t calculate_ip_checksum(uint16_t* hdr, short len) { uint32_t sum = calculate_checksum_update(0, hdr, len); return calculate_checksum_end(sum); } -/** - * Send an dns-answer-packet to the helper - */ -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); - - GNUNET_assert(ans->pkt.subtype == GNUNET_DNS_ANSWER_TYPE_IP); - - GNUNET_assert (20 == sizeof (struct ip_hdr)); - GNUNET_assert (8 == sizeof (struct udp_pkt)); - 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; - - struct ip_udp_dns* pkt = alloca(pkt_len); - GNUNET_assert(pkt != NULL); - memset(pkt, 0, pkt_len); - - /* set the gnunet-header */ - pkt->shdr.size = htons(pkt_len); - pkt->shdr.type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER); - - /* set the tun-header (no flags and ethertype of IPv4) */ - pkt->tun.flags = 0; - pkt->tun.type = htons(0x0800); - - /* set the ip-header */ - 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; - - pkt->ip_hdr.chks = calculate_ip_checksum((uint16_t*)&pkt->ip_hdr, 5*4); - - /* set the udp-header */ - 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 */ - - memcpy(&pkt->udp_dns.data, ans->pkt.data, data_len); - - GNUNET_CONTAINER_DLL_remove (answer_proc_head, answer_proc_tail, ans); - GNUNET_free(ans); - - /* FIXME */ GNUNET_DISK_file_write(fh_to_helper, pkt, pkt_len); - - /* if more packets are available, reschedule */ - if (answer_proc_head != NULL) - GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, - fh_to_helper, - &helper_write, - NULL); -} - /** * @return the hash of the IP-Address if a mapping exists, NULL otherwise */ -static GNUNET_HashCode* +GNUNET_HashCode* address_mapping_exists(unsigned char addr[]) { GNUNET_HashCode* key = GNUNET_malloc(sizeof(GNUNET_HashCode)); unsigned char* k = (unsigned char*)key; @@ -424,7 +131,7 @@ address_mapping_exists(unsigned char addr[]) { } } -static void +void send_icmp_response(void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ip6_icmp* request = cls; @@ -454,7 +161,7 @@ send_icmp_response(void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { /* Copy the rest of the packet */ memcpy(response+1, request+1, ntohs(request->shdr.size) - sizeof(struct ip6_icmp)); - /* FIXME */ GNUNET_DISK_file_write(fh_to_helper, response, ntohs(response->shdr.size)); + write_to_helper(response, ntohs(response->shdr.size)); GNUNET_free(request); } @@ -464,7 +171,7 @@ send_icmp_response(void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { * followed by the service-descriptor and the udp-packet that should be sent; */ static size_t -handle_udp (void *cls, size_t size, void *buf) +send_udp_to_peer_notify_callback (void *cls, size_t size, void *buf) { struct GNUNET_PeerIdentity *peer = cls; struct GNUNET_MessageHeader *hdr = @@ -482,7 +189,7 @@ handle_udp (void *cls, size_t size, void *buf) return size; } -static unsigned int +unsigned int port_in_ports (uint64_t ports, uint16_t port) { uint16_t *ps = (uint16_t *) & ports; @@ -490,8 +197,8 @@ port_in_ports (uint64_t ports, uint16_t port) } void -send_udp (void *cls, - int success) +send_udp_to_peer (void *cls, + int success) { struct GNUNET_PeerIdentity *peer = cls; struct GNUNET_MessageHeader *hdr = @@ -505,148 +212,15 @@ send_udp (void *cls, htons (sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + - ntohs (udp->len)), handle_udp, + ntohs (udp->len)), send_udp_to_peer_notify_callback, cls); } -/** - * Receive packets from the helper-process - */ -static void -message_token(void *cls, - void *client, - const struct GNUNET_MessageHeader *message) { - GNUNET_assert(ntohs(message->type) == GNUNET_MESSAGE_TYPE_VPN_HELPER); - - struct tun_pkt *pkt_tun = (struct tun_pkt*) message; - - /* ethertype is ipv6 */ - if (ntohs(pkt_tun->tun.type) == 0x86dd) - { - struct ip6_pkt *pkt6 = (struct ip6_pkt*) message; - GNUNET_assert(pkt6->ip6_hdr.version == 6); - struct ip6_tcp *pkt6_tcp; - struct ip6_udp *pkt6_udp; - struct ip6_icmp *pkt6_icmp; - GNUNET_HashCode* key; - - 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; - if ((key = address_mapping_exists(pkt6->ip6_hdr.dadr)) != NULL) - { - struct map_entry* me = GNUNET_CONTAINER_multihashmap_get(hashmap, key); - GNUNET_assert(me != NULL); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Mapping exists; type: %d; UDP is %d; port: %x/%x!\n", me->desc.service_type, htonl(GNUNET_DNS_SERVICE_TYPE_UDP), pkt6_udp->udp_hdr.dpt, me->desc.ports); - GNUNET_free(key); - if (me->desc.service_type & htonl(GNUNET_DNS_SERVICE_TYPE_UDP) && - (port_in_ports(me->desc.ports, pkt6_udp->udp_hdr.dpt) || - port_in_ports(me->additional_ports, pkt6_udp->udp_hdr.dpt))) - { - size_t size = sizeof(struct GNUNET_PeerIdentity) + sizeof(struct GNUNET_MessageHeader) + sizeof(GNUNET_HashCode) + ntohs(pkt6_udp->udp_hdr.len); - struct GNUNET_PeerIdentity *cls = GNUNET_malloc(size); - struct GNUNET_MessageHeader *hdr = (struct GNUNET_MessageHeader*)(cls+1); - GNUNET_HashCode* hc = (GNUNET_HashCode*)(hdr + 1); - memcpy(cls, &me->desc.peer, sizeof(struct GNUNET_PeerIdentity)); - memcpy(hc, &me->desc.service_descriptor, sizeof(GNUNET_HashCode)); - memcpy(hc+1, &pkt6_udp->udp_hdr, ntohs(pkt6_udp->udp_hdr.len)); - GNUNET_CORE_peer_request_connect(core_handle, - GNUNET_TIME_UNIT_FOREVER_REL, - (struct GNUNET_PeerIdentity*)&me->desc.peer, - send_udp, - cls); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Queued to send to peer %x\n", *((unsigned int*)&me->desc.peer)); - } - } - break; - case 0x3a: - /* ICMPv6 */ - pkt6_icmp = (struct ip6_icmp*)pkt6; - /* If this packet is an icmp-echo-request and a mapping exists, answer */ - if (pkt6_icmp->icmp_hdr.type == 0x80 && (key = address_mapping_exists(pkt6->ip6_hdr.dadr)) != NULL) - { - GNUNET_free(key); - pkt6_icmp = GNUNET_malloc(ntohs(pkt6->shdr.size)); - memcpy(pkt6_icmp, pkt6, ntohs(pkt6->shdr.size)); - GNUNET_SCHEDULER_add_now(&send_icmp_response, pkt6_icmp); - } - break; - } - } - /* ethertype is ipv4 */ - 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); - - /* Send dns-packets to the service-dns */ - if (pkt->ip_hdr.proto == 0x11 && ntohs(udp->udp_hdr.dpt) == 53 ) - { - /* 9 = 8 for the udp-header + 1 for the unsigned char data[1]; */ - size_t len = sizeof(struct query_packet) + ntohs(udp->udp_hdr.len) - 9; - - 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) - GNUNET_CLIENT_notify_transmit_ready(dns_connection, - len, - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_YES, - &send_query, - NULL); - } - } -} - -/** - * Connect to the service-dns - */ -static void -connect_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 to service-dns\n"); - GNUNET_assert (dns_connection == NULL); - dns_connection = GNUNET_CLIENT_connect ("dns", cfg); - /* This would most likely be a misconfiguration */ - GNUNET_assert(dns_connection != NULL); - GNUNET_CLIENT_receive(dns_connection, &dns_answer_handler, NULL, GNUNET_TIME_UNIT_FOREVER_REL); - - /* If a packet is already in the list, schedule to send it */ - if (head != NULL) - GNUNET_CLIENT_notify_transmit_ready(dns_connection, - ntohs(head->pkt.hdr.size), - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_YES, - &send_query, - NULL); - else if (restart_hijack == 1) - { - GNUNET_CLIENT_notify_transmit_ready(dns_connection, sizeof(struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, &send_query, NULL); - } -} - /** * Create a new Address from an answer-packet - * {{{ */ void -new_ip6addr(char* buf, const GNUNET_HashCode *peer, const GNUNET_HashCode *service_desc) { +new_ip6addr(char* buf, const GNUNET_HashCode *peer, const GNUNET_HashCode *service_desc) { /* {{{ */ memcpy(buf+14, (int[]){htons(0x3412)}, 2); memcpy(buf+8, service_desc, 6); memcpy(buf, peer, 8); @@ -660,7 +234,7 @@ new_ip6addr(char* buf, const GNUNET_HashCode *peer, const GNUNET_HashCode *servi * At the moment this means "inventing" and IPv6-Address for .gnunet-services and * doing nothing for "real" services. */ -static void +void process_answer(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tc) { struct answer_packet* pkt = cls; struct answer_packet_list* list; @@ -775,147 +349,11 @@ process_answer(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tc) { GNUNET_CONTAINER_DLL_insert_after(answer_proc_head, answer_proc_tail, answer_proc_tail, list); - GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, fh_to_helper, &helper_write, NULL); + schedule_helper_write(GNUNET_TIME_UNIT_FOREVER_REL, NULL); return; } -/** - * This receives packets from the service-dns and schedules process_answer to - * handle it - */ -static void -dns_answer_handler(void* cls, const struct GNUNET_MessageHeader *msg) { - /* the service disconnected, reconnect after short wait */ - if (msg == NULL) - { - GNUNET_CLIENT_disconnect(dns_connection, GNUNET_NO); - dns_connection = NULL; - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &connect_to_service_dns, - NULL); - return; - } - - /* the service did something strange, reconnect immediately */ - 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 (&connect_to_service_dns, - NULL); - return; - } - void *pkt = GNUNET_malloc(ntohs(msg->size)); - - memcpy(pkt, msg, ntohs(msg->size)); - - GNUNET_SCHEDULER_add_now(process_answer, pkt); - GNUNET_CLIENT_receive(dns_connection, &dns_answer_handler, NULL, GNUNET_TIME_UNIT_FOREVER_REL); -} - -struct udp_state -{ - struct GNUNET_PeerIdentity peer; - GNUNET_HashCode desc; - short spt; - short dpt; -}; - -struct send_cls -{ - struct GNUNET_NETWORK_Handle *sock; - struct udp_state state; -}; - -static size_t -send_udp_service (void *cls, size_t size, void *buf) -{ - struct GNUNET_MessageHeader *hdr = cls; - GNUNET_assert(size >= ntohs(hdr->size)); - - memcpy(buf, cls, ntohs(hdr->size)); - size_t ret = ntohs(hdr->size); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending %d bytes back!\n", ntohs(hdr->size)); - GNUNET_free(cls); - return ret; -} - -void -receive_from_network (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) - { - GNUNET_free(cls); - return; - } - struct send_cls *data = cls; - - char buf[1400]; - - struct sockaddr_in addr_in; - socklen_t addr_len = sizeof(struct sockaddr_in); - ssize_t len = GNUNET_NETWORK_socket_recvfrom (data->sock, buf, 1400, (struct sockaddr*)&addr_in, &addr_len); - - if (len < 0) { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Problem reading from socket: %m\n"); - goto out; - } - - size_t len_udp = len + sizeof (struct udp_pkt); - size_t len_pkt = len_udp + sizeof (struct GNUNET_MessageHeader) + sizeof(GNUNET_HashCode); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending data back: data: %d; udp: %d, pkt:%d\n", len, len_udp, len_pkt); - - struct GNUNET_MessageHeader *hdr = GNUNET_malloc (len_pkt); - GNUNET_HashCode *desc = (GNUNET_HashCode *) (hdr + 1); - struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1); - - hdr->size = htons (len_pkt); - hdr->type = htons (GNUNET_MESSAGE_TYPE_SERVICE_UDP_BACK); - - pkt->dpt = htons(data->state.spt); - pkt->spt = addr_in.sin_port; - pkt->len = htons (len_udp); - GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "UDP from %d to %d\n", ntohs(pkt->spt), ntohs(pkt->dpt)); - /* The chksm can only be computed knowing the ip-addresses */ - - memcpy (desc, &data->state.desc, sizeof (GNUNET_HashCode)); - memcpy (pkt + 1, buf, len); - - GNUNET_CORE_notify_transmit_ready (core_handle, 42, - GNUNET_TIME_relative_divide(GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), - &data->state.peer, len_pkt, - send_udp_service, hdr); - -out: - GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, data->sock, - receive_from_network, cls); -} - -void -send_to_network (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) - return; - struct send_cls *data = cls; - struct udp_pkt *pkt = (struct udp_pkt *) (data + 1); - - struct sockaddr_in a4; - memset(&a4, 0, sizeof(struct sockaddr_in)); - a4.sin_family = AF_INET; - a4.sin_port = htons(data->state.dpt); - memcpy(&a4.sin_addr.s_addr, (char[]){127, 0, 0, 1}, 4); - - GNUNET_NETWORK_socket_sendto (data->sock, pkt + 1, - ntohs (pkt->len) - sizeof (struct udp_pkt), - (struct sockaddr*)&a4, sizeof a4); - - GNUNET_free(cls); - -} - static void add_additional_port (struct map_entry *me, uint16_t port) { @@ -997,75 +435,7 @@ receive_udp_back (void *cls, const struct GNUNET_PeerIdentity *other, sum = calculate_checksum_update(sum, (uint16_t*)&pkt6->udp_hdr, ntohs(pkt->len)); pkt6->udp_hdr.crc = calculate_checksum_end(sum); - - /* FIXME */ GNUNET_DISK_file_write(fh_to_helper, pkt6, size); - - return GNUNET_OK; -} - -static int -receive_udp_service (void *cls, const struct GNUNET_PeerIdentity *other, - const struct GNUNET_MessageHeader *message, - const struct GNUNET_TRANSPORT_ATS_Information *atsi) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received UDP-Packet from peer %s\n", - GNUNET_i2s (other)); - GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); - struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1); - - /* FIXME -> check acl etc */ - GNUNET_assert (ntohs (pkt->len) == - ntohs (message->size) - - sizeof (struct GNUNET_MessageHeader) - - sizeof (GNUNET_HashCode)); - - size_t state_size = sizeof (struct udp_state); - size_t cls_size = sizeof (struct send_cls) + ntohs (pkt->len); - struct send_cls *send = GNUNET_malloc (cls_size); - struct udp_state *state = &send->state; - unsigned int new = GNUNET_NO; - - memcpy (&state->peer, other, sizeof (struct GNUNET_PeerIdentity)); - memcpy (&state->desc, desc, sizeof (GNUNET_HashCode)); - state->spt = ntohs (pkt->spt); - - /* Hash without the dpt, so that eg tftp works */ - state->dpt = 0; - - memcpy (send + 1, pkt, ntohs (pkt->len)); - - GNUNET_HashCode hash; - GNUNET_CRYPTO_hash (state, state_size, &hash); - - state->dpt = ntohs (pkt->dpt); - - struct GNUNET_NETWORK_Handle *sock = - GNUNET_CONTAINER_multihashmap_get (udp_connections, &hash); - - if (sock == NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating new Socket!\n"); - sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0); - GNUNET_assert(sock != NULL); - new = GNUNET_YES; - } - - send->sock = sock; - - GNUNET_CONTAINER_multihashmap_put (udp_connections, &hash, sock, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); - - - if (new) - { - struct send_cls *recv = GNUNET_malloc (sizeof (struct send_cls)); - memcpy (recv, send, sizeof (struct send_cls)); - GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock, - receive_from_network, recv); - } - - GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, sock, - send_to_network, send); + write_to_helper(pkt6, size); return GNUNET_OK; } @@ -1082,9 +452,9 @@ static void run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg_) { + const struct GNUNET_CONFIGURATION_Handle *cfg_) +{ const static struct GNUNET_CORE_MessageHandler handlers[] = { - {receive_udp_service, GNUNET_MESSAGE_TYPE_SERVICE_UDP, 0}, {receive_udp_back, GNUNET_MESSAGE_TYPE_SERVICE_UDP_BACK, 0}, {NULL, 0, 0} }; @@ -1132,3 +502,4 @@ main (int argc, char *const *argv) { } /* end of gnunet-daemon-vpn.c */ + diff --git a/src/vpn/gnunet-daemon-vpn.h b/src/vpn/gnunet-daemon-vpn.h new file mode 100644 index 000000000..a53c296ef --- /dev/null +++ b/src/vpn/gnunet-daemon-vpn.h @@ -0,0 +1,85 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file vpn/gnunet-daemon-vpn.h + * @brief + * @author Philipp Toelke + */ +#ifndef GNUNET_DAEMON_VPN_H +#define GNUNET_DAEMON_VPN_H + +#include "gnunet-service-dns-p.h" + +/** + * This gets scheduled with cls pointing to an answer_packet and does everything + * needed in order to send it to the helper. + * + * At the moment this means "inventing" and IPv6-Address for .gnunet-services and + * doing nothing for "real" services. + */ +void +process_answer(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tc); + +/** + * Calculate the checksum of an IPv4-Header + */ +uint16_t +calculate_ip_checksum(uint16_t* hdr, short len); + +void +send_icmp_response(void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +size_t +send_udp_service (void *cls, size_t size, void *buf); + +GNUNET_HashCode* address_mapping_exists(unsigned char addr[]); + +unsigned int port_in_ports (uint64_t ports, uint16_t port); + +void +send_udp_to_peer (void *cls, int success); + +/** + * The configuration to use + */ +const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * The handle to core + */ +struct GNUNET_CORE_Handle *core_handle; + +/** + * The hashmap containing the mappings from ipv6-addresses to gnunet-descriptors + */ +struct GNUNET_CONTAINER_MultiHashMap* hashmap; + +struct map_entry { + struct GNUNET_vpn_service_descriptor desc; + uint16_t namelen; + uint64_t additional_ports; + /** + * In DNS-Format! + */ + char name[1]; +}; + +#endif /* end of include guard: GNUNET-DAEMON-VPN_H */ -- 2.25.1