From 7d9aa0ca86bc7c6f3ce26ce3753027738cfcd9dd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Philipp=20T=C3=B6lke?= Date: Mon, 21 Feb 2011 10:03:42 +0000 Subject: [PATCH] Let the -exit use an own tun and not socks --- src/vpn/Makefile.am | 7 +- src/vpn/gnunet-daemon-exit.c | 612 +++++++++++++++++++++++------ src/vpn/gnunet-daemon-vpn-helper.c | 1 + src/vpn/gnunet-daemon-vpn.c | 26 +- src/vpn/gnunet-daemon-vpn.h | 6 - src/vpn/gnunet-service-dns.c | 1 + src/vpn/gnunet-vpn-checksum.c | 51 +++ src/vpn/gnunet-vpn-checksum.h | 16 + 8 files changed, 564 insertions(+), 156 deletions(-) create mode 100644 src/vpn/gnunet-vpn-checksum.c create mode 100644 src/vpn/gnunet-vpn-checksum.h diff --git a/src/vpn/Makefile.am b/src/vpn/Makefile.am index a36f56833..8f33e0925 100644 --- a/src/vpn/Makefile.am +++ b/src/vpn/Makefile.am @@ -37,7 +37,8 @@ gnunet_daemon_vpn_SOURCES = \ 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-helper-vpn-api.c gnunet-helper-vpn-api.h + gnunet-helper-vpn-api.c gnunet-helper-vpn-api.h \ + gnunet-vpn-checksum.c gnunet-vpn-checksum.h gnunet_daemon_vpn_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ @@ -57,7 +58,9 @@ gnunet_service_dns_LDADD = \ $(GN_LIBINTL) gnunet_daemon_exit_SOURCES = \ - gnunet-daemon-exit.c + gnunet-daemon-exit.c \ + gnunet-helper-vpn-api.c gnunet-helper-vpn-api.h \ + gnunet-vpn-checksum.c gnunet-vpn-checksum.h gnunet_daemon_exit_LDADD = \ $(top_builddir)/src/core/libgnunetcore.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ diff --git a/src/vpn/gnunet-daemon-exit.c b/src/vpn/gnunet-daemon-exit.c index ba382a16c..e75e1e6cd 100644 --- a/src/vpn/gnunet-daemon-exit.c +++ b/src/vpn/gnunet-daemon-exit.c @@ -29,8 +29,26 @@ #include #include #include +#include #include "gnunet-vpn-packet.h" +#include "gnunet-helper-vpn-api.h" +#include "gnunet-vpn-checksum.h" + +/** + * The handle to the configuration used throughout the process + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * The handle to the service-configuration + */ +static struct GNUNET_CONFIGURATION_Handle *servicecfg; + +/** + * The handle to the helper + */ +struct GNUNET_VPN_HELPER_Handle *helper_handle; /** * Final status code. @@ -49,25 +67,62 @@ static struct GNUNET_MESH_Handle *mesh_handle; static struct GNUNET_CONTAINER_MultiHashMap *udp_connections; /** - * FIXME + * This struct is saved into the services-hashmap + */ +struct udp_service +{ + /** + * One of 4 or 6 + */ + unsigned int version; + uint16_t my_port; + uint16_t remote_port; + + union + { + struct + { + char ip4address[4]; + } v4; + struct + { + char ip6address[16]; + } v6; + }; +}; + +struct udp_info +{ + /** + * The source-address of this connection. When a packet to this address is + * received, this tunnel is used to forward it. ipv4-addresses will be put + * here left-aligned */ + char addr[16]; + /** + * The source-port of this connection + */ + uint16_t pt; +}; + +/** + * This struct is saved into udp_connections; */ struct udp_state { - struct GNUNET_PeerIdentity peer; struct GNUNET_MESH_Tunnel *tunnel; GNUNET_HashCode desc; - short spt; - short dpt; + struct udp_service *serv; + + /** + * The source-address and -port of this connection + */ + struct udp_info udp_info; }; /** - * FIXME + * This hashmap saves interesting things about the configured services */ -struct send_cls -{ - struct GNUNET_NETWORK_Handle *sock; - struct udp_state state; -}; +static struct GNUNET_CONTAINER_MultiHashMap *udp_services; /** * Function scheduled as very last function, cleans up after us @@ -83,161 +138,457 @@ cleanup(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) { } } +/** + * cls is the pointer to a GNUNET_MessageHeader that is + * followed by the service-descriptor and the udp-packet that should be sent; + */ static size_t -send_udp_service (void *cls, size_t size, void *buf) +send_udp_to_peer_notify_callback (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; + GNUNET_assert (size >= ntohs (hdr->size)); + memcpy (buf, hdr, ntohs (hdr->size)); + size = ntohs(hdr->size); + GNUNET_free (cls); + return size; } -void -receive_from_network (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +/** + * Receive packets from the helper-process + */ +static void +message_token (void *cls, + void *client, const struct GNUNET_MessageHeader *message) { - if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) - { - GNUNET_free(cls); - return; - } - struct send_cls *data = cls; + GNUNET_assert (ntohs (message->type) == GNUNET_MESSAGE_TYPE_VPN_HELPER); - char buf[1400]; + struct tun_pkt *pkt_tun = (struct tun_pkt *) message; - 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); + struct GNUNET_MessageHeader *msg; + struct GNUNET_MESH_Tunnel *tunnel; + uint32_t len; - if (len < 0) { - GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Problem reading from socket: %m\n"); - goto out; - } + struct udp_pkt *udp; + struct udp_info u_i; + memset(&u_i, 0, sizeof(struct udp_info)); - 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); + unsigned int version; - struct GNUNET_MessageHeader *hdr = GNUNET_malloc (len_pkt); - GNUNET_HashCode *desc = (GNUNET_HashCode *) (hdr + 1); - struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1); + /* ethertype is ipv6 */ + if (ntohs (pkt_tun->tun.type) == 0x86dd) + { + struct ip6_udp *pkt6 = (struct ip6_udp*)pkt_tun; + if (pkt6->ip6_hdr.nxthdr != 0x11) return; + /* lookup in udp_connections for dpt/dadr*/ + memcpy(&u_i.addr, pkt6->ip6_hdr.dadr, 16); + udp = &pkt6->udp_hdr; + version = 6; + } + else if (ntohs(pkt_tun->tun.type) == 0x0800) + { + struct ip_udp *pkt4 = (struct ip_udp*)pkt_tun; + if (pkt4->ip_hdr.proto != 0x11) return; + uint32_t tmp = pkt4->ip_hdr.dadr; + memcpy(&u_i.addr, &tmp, 4); + udp = &pkt4->udp_hdr; + version = 4; + } + else + { + return; + } - hdr->size = htons (len_pkt); - hdr->type = htons (GNUNET_MESSAGE_TYPE_SERVICE_UDP_BACK); + u_i.pt = udp->dpt; - 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 */ + /* get tunnel and service-descriptor from this*/ + GNUNET_HashCode hash; + GNUNET_CRYPTO_hash(&u_i, sizeof(struct udp_info), &hash); + struct udp_state *state = GNUNET_CONTAINER_multihashmap_get(udp_connections, &hash); - memcpy (desc, &data->state.desc, sizeof (GNUNET_HashCode)); - memcpy (pkt + 1, buf, len); + tunnel = state->tunnel; - GNUNET_MESH_notify_transmit_ready (data->state.tunnel, 42, + /* check if spt == serv.remote if yes: set spt = serv.myport*/ + if (ntohs(udp->spt) == state->serv->remote_port) + { + udp->spt = htons(state->serv->my_port); + } + else + { + struct udp_service *serv = GNUNET_malloc(sizeof(struct udp_service)); + memcpy(serv, state->serv, sizeof(struct udp_service)); + serv->my_port = ntohs(udp->spt); + serv->remote_port = ntohs(udp->spt); + uint16_t *desc = alloca (sizeof (GNUNET_HashCode) + 2); + memcpy((GNUNET_HashCode *) (desc + 1), &state->desc, sizeof(GNUNET_HashCode)); + *desc = ntohs(udp->spt); + GNUNET_HashCode hash; + GNUNET_CRYPTO_hash (desc, sizeof (GNUNET_HashCode) + 2, &hash); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (udp_services, + &hash, serv, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + state->serv = serv; + } + /* send udp-packet back */ + len = sizeof(struct GNUNET_MessageHeader) + sizeof(GNUNET_HashCode) + ntohs(udp->len); + msg = GNUNET_malloc(len); + msg->size = htons(len); + msg->type = htons(GNUNET_MESSAGE_TYPE_SERVICE_UDP_BACK); + GNUNET_HashCode *desc = (GNUNET_HashCode*)(msg+1); + memcpy(desc, &state->desc, sizeof(GNUNET_HashCode)); + void* _udp = desc+1; + memcpy(_udp, udp, ntohs(udp->len)); + + GNUNET_MESH_notify_transmit_ready (tunnel, GNUNET_NO, + 42, GNUNET_TIME_relative_divide(GNUNET_CONSTANTS_MAX_CORK_DELAY, 2), - len_pkt, - send_udp_service, hdr); - -out: - GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, data->sock, - receive_from_network, cls); + len, + send_udp_to_peer_notify_callback, + msg); } -void -send_to_network (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +/** + * Reads the configuration servicecfg and populates udp_services + */ +static void +read_service_conf (void *cls, const char *section, const char *option, + const char *value) { - 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); - GNUNET_assert (1 == inet_pton (AF_INET, "127.0.0.1", &a4.sin_addr)); - GNUNET_NETWORK_socket_sendto (data->sock, pkt + 1, - ntohs (pkt->len) - sizeof (struct udp_pkt), - (struct sockaddr*)&a4, sizeof a4); - - GNUNET_free(cls); + GNUNET_HashCode hash; + uint16_t *desc = alloca (sizeof (GNUNET_HashCode) + 2); + GNUNET_CRYPTO_hash (section, strlen (section) + 1, + (GNUNET_HashCode *) (desc + 1)); + if (0 == strcmp ("UDP_REDIRECTS", option)) + { + char *saveptr; + char *value_ = alloca (strlen (value) + 1); + memcpy (value_, value, strlen (value) + 1); + char *token = strtok_r (value_, " ", &saveptr); + while (NULL != token) + { + char *isaveptr; + + char *itoken = strtok_r (token, ":", &isaveptr); + GNUNET_assert (NULL != itoken); + int local_port = atoi (itoken); + GNUNET_assert ((local_port > 0) && (local_port < 65536)); + *desc = local_port; + + GNUNET_CRYPTO_hash (desc, sizeof (GNUNET_HashCode) + 2, &hash); + + struct udp_service *serv = + GNUNET_malloc (sizeof (struct udp_service)); + memset (serv, 0, sizeof (struct udp_service)); + serv->my_port = local_port; + + itoken = strtok_r (NULL, ":", &isaveptr); + GNUNET_assert (NULL != itoken); + if (0 == strcmp ("localhost4", itoken)) + { + serv->version = 4; + + char *ip4addr; + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, + "exit", + "IPV4ADDR", + &ip4addr)); + GNUNET_assert (1 == + inet_pton (AF_INET, ip4addr, + serv->v4.ip4address)); + GNUNET_free (ip4addr); + } + else if (0 == strcmp ("localhost6", itoken)) + { + serv->version = 6; + + char *ip6addr; + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, + "exit", + "IPV6ADDR", + &ip6addr)); + GNUNET_assert (1 == + inet_pton (AF_INET6, ip6addr, + serv->v6.ip6address)); + GNUNET_free (ip6addr); + } + else + { + // Lookup, yadayadayada + GNUNET_assert (0); + } + + itoken = strtok_r (NULL, ":", &isaveptr); + GNUNET_assert (NULL != itoken); + serv->remote_port = atoi (itoken); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Store with key1 %x\n", + *((unsigned long long *) (desc + 1))); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Store with key2 %x\n", + *((unsigned long long *) &hash)); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (udp_services, + &hash, serv, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + + token = strtok_r (NULL, " ", &saveptr); + } + } } -/** - * The messages are one GNUNET_HashCode for the service, followed by a struct udp_pkt +/** + * Start the helper-process + * + * If cls != NULL it is assumed that this function is called as a result of a dying + * helper. cls is then taken as handle to the old helper and is cleaned up. */ -static int -receive_udp_service (void *cls, - struct GNUNET_MESH_Tunnel *tunnel, - void **tunnel_ctx, - const struct GNUNET_MessageHeader *message, - const struct GNUNET_TRANSPORT_ATS_Information *atsi) -{ - GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); - struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1); +static void +start_helper_and_schedule(void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + return; - /* FIXME -> check acl etc */ - GNUNET_assert (ntohs (pkt->len) == - ntohs (message->size) - - sizeof (struct GNUNET_MessageHeader) - - sizeof (GNUNET_HashCode)); + if (cls != NULL) + cleanup_helper(cls); + cls = NULL; - 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; + char* ifname; + char* ipv6addr; + char* ipv6prefix; + char* ipv4addr; + char* ipv4mask; - state->tunnel = tunnel; - memcpy (&state->desc, desc, sizeof (GNUNET_HashCode)); - state->spt = ntohs (pkt->spt); + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "exit", "IFNAME", &ifname)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No entry 'IFNAME' in configuration!\n"); + exit(1); + } + + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "exit", "IPV6ADDR", &ipv6addr)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No entry 'IPV6ADDR' in configuration!\n"); + exit(1); + } - /* Hash without the dpt, so that eg tftp works */ - state->dpt = 0; + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "exit", "IPV6PREFIX", &ipv6prefix)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No entry 'IPV6PREFIX' in configuration!\n"); + exit(1); + } - memcpy (send + 1, pkt, ntohs (pkt->len)); + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "exit", "IPV4ADDR", &ipv4addr)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No entry 'IPV4ADDR' in configuration!\n"); + exit(1); + } - GNUNET_HashCode hash; - GNUNET_CRYPTO_hash (state, state_size, &hash); + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "exit", "IPV4MASK", &ipv4mask)) + { + GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No entry 'IPV4MASK' in configuration!\n"); + exit(1); + } - state->dpt = ntohs (pkt->dpt); + /* Start the helper + * Messages get passed to the function message_token + * When the helper dies, this function will be called again with the + * helper_handle as cls. + */ + helper_handle = start_helper(ifname, + ipv6addr, + ipv6prefix, + ipv4addr, + ipv4mask, + "exit-gnunet", + start_helper_and_schedule, + message_token, + NULL, + NULL); + + GNUNET_free(ipv6addr); + GNUNET_free(ipv6prefix); + GNUNET_free(ipv4addr); + GNUNET_free(ipv4mask); + GNUNET_free(ifname); +} - struct GNUNET_NETWORK_Handle *sock = - GNUNET_CONTAINER_multihashmap_get (udp_connections, &hash); +/** + * The messages are one GNUNET_HashCode for the service, followed by a struct udp_pkt + */ +static int +receive_udp_service (void *cls, + struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_TRANSPORT_ATS_Information *atsi) +{ + GNUNET_HashCode hash; + GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1); + struct udp_pkt *pkt = (struct udp_pkt *) (desc + 1); + struct ip6_udp *pkt6; + struct ip_udp *pkt4; - if (sock == NULL) + GNUNET_assert (ntohs (pkt->len) == + ntohs (message->size) - + sizeof (struct GNUNET_MessageHeader) - + sizeof (GNUNET_HashCode)); + + /* Get the configuration from the hashmap */ + uint16_t *udp_desc = alloca(sizeof(GNUNET_HashCode)+2); + memcpy(udp_desc + 1, desc, sizeof(GNUNET_HashCode)); + *udp_desc = ntohs(pkt->dpt); + GNUNET_CRYPTO_hash(udp_desc, sizeof(GNUNET_HashCode)+2, &hash); + struct udp_service *serv = GNUNET_CONTAINER_multihashmap_get(udp_services, &hash); + if (NULL == serv) { - 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; + GNUNET_log(GNUNET_ERROR_TYPE_INFO, "No service found for dpt %d!\n", *udp_desc); + return GNUNET_YES; } - send->sock = sock; + pkt->dpt = htons(serv->remote_port); + /* FIXME -> check acl etc */ - GNUNET_CONTAINER_multihashmap_put (udp_connections, &hash, sock, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + char* buf; + size_t len; + uint32_t tmp, tmp2; + /* Prepare the state. + * This will be saved in the hashmap, so that the receiving procedure knows + * through which tunnel this connection has to be routed. + */ + struct udp_state *state = GNUNET_malloc (sizeof (struct udp_state)); + memset(state, 0, sizeof(struct udp_state)); + state->tunnel = tunnel; + state->serv = serv; + memcpy(&state->desc, desc, sizeof(GNUNET_HashCode)); - if (new) + switch (serv->version) { - 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); + case 4: + len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) + + sizeof (struct ip_hdr) + ntohs (pkt->len); + pkt4 = alloca(len); + memset (pkt4, 0, len); + buf = (char*)pkt4; + + pkt4->shdr.type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER); + pkt4->shdr.size = htons(len); + pkt4->tun.flags = 0; + pkt4->tun.type = htons(0x0800); + + memcpy(&pkt4->udp_hdr, pkt, ntohs(pkt->len)); + + 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 = 0x11; /* UDP */ + pkt4->ip_hdr.chks = 0; /* Will be calculated later*/ + + memcpy(&tmp, &serv->v4.ip4address, 4); + pkt4->ip_hdr.dadr = tmp; + + /* Generate a new src-address */ + char* ipv4addr; + char* ipv4mask; + GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "exit", "IPV4ADDR", &ipv4addr)); + GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "exit", "IPV4MASK", &ipv4mask)); + inet_pton(AF_INET, ipv4addr, &tmp); + inet_pton(AF_INET, ipv4mask, &tmp2); + + /* This should be a noop */ + tmp = tmp & tmp2; + + tmp |= ntohl(*((uint32_t*)tunnel)) & (~tmp2); + + pkt4->ip_hdr.sadr = tmp; + + memcpy(&state->udp_info.addr, &tmp, 4); + state->udp_info.pt = pkt4->udp_hdr.spt; + + pkt4->udp_hdr.crc = 0; /* Optional for IPv4 */ + + pkt4->ip_hdr.chks = calculate_ip_checksum((uint16_t*)&pkt4->ip_hdr, 5*4); + + break; + case 6: + len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) + + sizeof (struct ip6_hdr) + ntohs (pkt->len); + pkt6 = + alloca (len); + memset (pkt6, 0, len); + buf =(char*) pkt6; + + pkt6->shdr.type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER); + pkt6->shdr.size = htons(len); + pkt6->tun.flags = 0; + pkt6->tun.type = htons(0x86dd); + + memcpy (&pkt6->udp_hdr, pkt, ntohs (pkt->len)); + + pkt6->ip6_hdr.version = 6; + pkt6->ip6_hdr.nxthdr = 0x11; //UDP + pkt6->ip6_hdr.paylgth = pkt->len; + pkt6->ip6_hdr.hoplmt = 64; + + memcpy(pkt6->ip6_hdr.dadr, &serv->v6.ip6address, 16); + + /* Generate a new src-address + * This takes as much from the address of the tunnel as fits into + * the host-mask*/ + char* ipv6addr; + unsigned long long ipv6prefix; + GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "exit", "IPV6ADDR", &ipv6addr)); + GNUNET_assert(GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "exit", "IPV6PREFIX", &ipv6prefix)); + GNUNET_assert(ipv6prefix < 127); + ipv6prefix = (ipv6prefix + 7)/8; + + inet_pton (AF_INET6, ipv6addr, &pkt6->ip6_hdr.sadr); + GNUNET_free(ipv6addr); + + if (ipv6prefix < (16 - sizeof(void*))) + ipv6prefix = 16 - sizeof(void*); + + unsigned int offset = ipv6prefix - (16-sizeof(void*)); + memcpy((((char*)&pkt6->ip6_hdr.sadr))+ipv6prefix, ((char*)&tunnel)+offset, 16 - ipv6prefix); + + /* copy the needed information into the state */ + memcpy(&state->udp_info.addr, &pkt6->ip6_hdr.sadr, 16); + state->udp_info.pt = 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); + 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(pkt6->udp_hdr.len)); + pkt6->udp_hdr.crc = calculate_checksum_end(sum); + + break; + default: + GNUNET_assert(0); + break; } - GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, sock, - send_to_network, send); + GNUNET_CRYPTO_hash (&state->udp_info, sizeof(struct udp_info), &hash); + + if (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (udp_connections, &hash)) + GNUNET_CONTAINER_multihashmap_put (udp_connections, &hash, state, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); - return GNUNET_OK; + (void)GNUNET_DISK_file_write(helper_handle->fh_to_helper, buf, len); + return GNUNET_YES; } /** @@ -263,7 +614,22 @@ run (void *cls, NULL, /* FIXME */ handlers); + cfg = cfg_; udp_connections = GNUNET_CONTAINER_multihashmap_create(65536); + udp_services = GNUNET_CONTAINER_multihashmap_create(65536); + + char *services; + GNUNET_CONFIGURATION_get_value_filename(cfg, "dns", "SERVICES", &services); + servicecfg = GNUNET_CONFIGURATION_create(); + if (GNUNET_OK == GNUNET_CONFIGURATION_parse(servicecfg, services)) + { + GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Parsing services %s\n", services); + GNUNET_CONFIGURATION_iterate(servicecfg, read_service_conf, NULL); + } + if (NULL != services) + GNUNET_free(services); + + GNUNET_SCHEDULER_add_now (start_helper_and_schedule, NULL); GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); } @@ -283,7 +649,7 @@ main (int argc, char *const *argv) { return (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, - "gnunet-daemon-exit", + "exit", gettext_noop ("help text"), options, &run, NULL)) ? ret : 1; } diff --git a/src/vpn/gnunet-daemon-vpn-helper.c b/src/vpn/gnunet-daemon-vpn-helper.c index a27060014..1317c9ade 100644 --- a/src/vpn/gnunet-daemon-vpn-helper.c +++ b/src/vpn/gnunet-daemon-vpn-helper.c @@ -39,6 +39,7 @@ #include "gnunet-daemon-vpn-helper.h" #include "gnunet-service-dns-p.h" #include "gnunet-vpn-packet.h" +#include "gnunet-vpn-checksum.h" struct GNUNET_VPN_HELPER_Handle *helper_handle; diff --git a/src/vpn/gnunet-daemon-vpn.c b/src/vpn/gnunet-daemon-vpn.c index 32660047d..0b0558107 100644 --- a/src/vpn/gnunet-daemon-vpn.c +++ b/src/vpn/gnunet-daemon-vpn.c @@ -37,8 +37,8 @@ #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; @@ -81,30 +81,6 @@ cleanup(void* cls, const struct GNUNET_SCHEDULER_TaskContext* tskctx) { } /*}}}*/ -static uint32_t calculate_checksum_update(uint32_t sum, uint16_t *hdr, short len) { - for(; len >= 2; len -= 2) - sum += *(hdr++); - if (len == 1) - sum += *((unsigned char*)hdr); - return sum; -} - -static uint16_t calculate_checksum_end(uint32_t sum) { - while (sum >> 16) - sum = (sum >> 16) + (sum & 0xFFFF); - - return ~sum; -} - -/** - * Calculate the checksum of an IPv4-Header - */ -uint16_t -calculate_ip_checksum(uint16_t* hdr, short len) { - uint32_t sum = calculate_checksum_update(0, hdr, len); - return calculate_checksum_end(sum); -} - /** * @return the hash of the IP-Address if a mapping exists, NULL otherwise */ diff --git a/src/vpn/gnunet-daemon-vpn.h b/src/vpn/gnunet-daemon-vpn.h index b9d6a65ed..36f3dcbe7 100644 --- a/src/vpn/gnunet-daemon-vpn.h +++ b/src/vpn/gnunet-daemon-vpn.h @@ -38,12 +38,6 @@ 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); diff --git a/src/vpn/gnunet-service-dns.c b/src/vpn/gnunet-service-dns.c index 12a85cdd1..66c072c37 100644 --- a/src/vpn/gnunet-service-dns.c +++ b/src/vpn/gnunet-service-dns.c @@ -576,6 +576,7 @@ publish_name (void *cls, data.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_DNS_RECORD; GNUNET_CRYPTO_hash(name, strlen(name)+1, &data.service_descriptor); + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Store with key1 %x\n", *((unsigned long long*)&data.service_descriptor)); data.service_type = htonl(GNUNET_DNS_SERVICE_TYPE_UDP); data.ports = htons(69); diff --git a/src/vpn/gnunet-vpn-checksum.c b/src/vpn/gnunet-vpn-checksum.c new file mode 100644 index 000000000..81ec044dc --- /dev/null +++ b/src/vpn/gnunet-vpn-checksum.c @@ -0,0 +1,51 @@ +/* + 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-vpn-checksum.c + * @brief + * @author Philipp Toelke + */ + +#include "gnunet-vpn-checksum.h" + +uint32_t calculate_checksum_update(uint32_t sum, uint16_t *hdr, short len) { + for(; len >= 2; len -= 2) + sum += *(hdr++); + if (len == 1) + sum += *((unsigned char*)hdr); + return sum; +} + +uint16_t calculate_checksum_end(uint32_t sum) { + while (sum >> 16) + sum = (sum >> 16) + (sum & 0xFFFF); + + return ~sum; +} + +/** + * Calculate the checksum of an IPv4-Header + */ +uint16_t +calculate_ip_checksum(uint16_t* hdr, short len) { + uint32_t sum = calculate_checksum_update(0, hdr, len); + return calculate_checksum_end(sum); +} diff --git a/src/vpn/gnunet-vpn-checksum.h b/src/vpn/gnunet-vpn-checksum.h new file mode 100644 index 000000000..0c0605650 --- /dev/null +++ b/src/vpn/gnunet-vpn-checksum.h @@ -0,0 +1,16 @@ +#ifndef GNUNET_VPN_CHECKSUM_H + +#define GNUNET_VPN_CHECKSUM_H + +#include + +uint32_t calculate_checksum_update(uint32_t sum, uint16_t *hdr, short len); + +uint16_t calculate_checksum_end(uint32_t sum); + +/** + * Calculate the checksum of an IPv4-Header + */ +uint16_t calculate_ip_checksum(uint16_t* hdr, short len); + +#endif /* end of include guard: GNUNET-VPN-CHECKSUM_H */ -- 2.25.1