From 0bc020d2fe8fa8aa1e6896cd38c7b9d6c2311267 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 3 Jan 2012 22:51:14 +0000 Subject: [PATCH] -misc DNS related bugfixes --- src/dns/Makefile.am | 1 - src/dns/dns.conf | 13 +++- src/dns/gnunet-helper-dns.c | 12 ++- src/dns/gnunet-service-dns_new.c | 127 +++++++++++++++++++++++++++---- src/util/crypto_crc.c | 2 - src/util/helper.c | 8 +- 6 files changed, 139 insertions(+), 24 deletions(-) diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am index 2d5efb2f6..674f4bf57 100644 --- a/src/dns/Makefile.am +++ b/src/dns/Makefile.am @@ -60,7 +60,6 @@ gnunet_service_dns_new_SOURCES = \ gnunet_service_dns_new_LDADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/dns/libgnunetdnsparser.la \ $(GN_LIBINTL) libgnunetdnsparser_la_SOURCES = \ diff --git a/src/dns/dns.conf b/src/dns/dns.conf index 59d827692..f8590bf61 100644 --- a/src/dns/dns.conf +++ b/src/dns/dns.conf @@ -8,4 +8,15 @@ BINARY = gnunet-service-dns ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-dns.sock -PROVIDE_EXIT = NO + +PROVIDE_EXIT = YES +IFNAME = gnunet-dns + +# Use RFC 3849-style documentation IPv6 address (RFC 4773 might provide an alternative in the future) +IPV6ADDR = 2001:DB8::1 +IPV6PREFIX = 126 + +# Use RFC 3927-style link-local address +IPV4ADDR = 169.254.1.1 +IPV4MASK = 255.255.0.0 + diff --git a/src/dns/gnunet-helper-dns.c b/src/dns/gnunet-helper-dns.c index 07cc9647c..56b8713cf 100644 --- a/src/dns/gnunet-helper-dns.c +++ b/src/dns/gnunet-helper-dns.c @@ -760,7 +760,9 @@ main (int argc, char *const*argv) return 6; } } - if (SIG_ERR == signal (SIGTERM, &signal_handler)) + if ( (SIG_ERR == signal (SIGTERM, &signal_handler)) || + (SIG_ERR == signal (SIGINT, &signal_handler)) || + (SIG_ERR == signal (SIGHUP, &signal_handler)) ) { fprintf (stderr, "Fatal: could not initialize signal handler: %s\n", @@ -779,7 +781,9 @@ main (int argc, char *const*argv) if (-1 == (fd_tun = init_tun (dev))) { fprintf (stderr, "Fatal: could not initialize tun-interface\n"); + (void) signal (SIGTERM, SIG_IGN); (void) signal (SIGINT, SIG_IGN); + (void) signal (SIGHUP, SIG_IGN); (void) close (cpipe[0]); (void) close (cpipe[1]); return 5; @@ -793,7 +797,9 @@ main (int argc, char *const*argv) if ((prefix_len < 1) || (prefix_len > 127)) { fprintf (stderr, "Fatal: prefix_len out of range\n"); + (void) signal (SIGTERM, SIG_IGN); (void) signal (SIGINT, SIG_IGN); + (void) signal (SIGHUP, SIG_IGN); (void) close (cpipe[0]); (void) close (cpipe[1]); return 2; @@ -941,8 +947,10 @@ main (int argc, char *const*argv) cleanup_rest: /* close virtual interface */ (void) close (fd_tun); - /* remove SIGINT handler so we can close the pipes */ + /* remove signal handler so we can close the pipes */ + (void) signal (SIGTERM, SIG_IGN); (void) signal (SIGINT, SIG_IGN); + (void) signal (SIGHUP, SIG_IGN); (void) close (cpipe[0]); (void) close (cpipe[1]); return r; diff --git a/src/dns/gnunet-service-dns_new.c b/src/dns/gnunet-service-dns_new.c index 14bb19811..8d9727425 100644 --- a/src/dns/gnunet-service-dns_new.c +++ b/src/dns/gnunet-service-dns_new.c @@ -30,7 +30,35 @@ #include "dns_new.h" #include "gnunet_dns_service-new.h" +/* see http://www.iana.org/assignments/ethernet-numbers */ +#ifndef ETH_P_IPV4 +#define ETH_P_IPV4 0x0800 +#endif + +#ifndef ETH_P_IPV6 +#define ETH_P_IPV6 0x86DD +#endif + GNUNET_NETWORK_STRUCT_BEGIN +/** + * Header from Linux TUN interface. + */ +struct tun_header +{ + /** + * Some flags (unused). + */ + uint16_t flags; + + /** + * Here we get an ETH_P_-number. + */ + uint16_t proto; +}; + +/** + * Standard IPv4 header. + */ struct ip4_header { unsigned header_length:4 GNUNET_PACKED; @@ -47,6 +75,9 @@ struct ip4_header struct in_addr destination_address GNUNET_PACKED; }; +/** + * Standard IPv6 header. + */ struct ip6_header { unsigned traffic_class_h:4 GNUNET_PACKED; @@ -60,6 +91,9 @@ struct ip6_header struct in6_addr destination_address GNUNET_PACKED; }; +/** + * UDP packet header. + */ struct udp_packet { uint16_t spt GNUNET_PACKED; @@ -68,6 +102,9 @@ struct udp_packet uint16_t crc GNUNET_PACKED; }; +/** + * DNS header. + */ struct dns_header { uint16_t id GNUNET_PACKED; @@ -263,7 +300,7 @@ static struct GNUNET_SERVER_NotificationContext *nc; /** * Array of all open requests. */ -static struct RequestRecord requests[UINT16_MAX]; +static struct RequestRecord requests[UINT16_MAX + 1]; /** * Generator for unique request IDs. @@ -279,7 +316,7 @@ static uint64_t request_id_gen; static void cleanup_rr (struct RequestRecord *rr) { - GNUNET_free (rr->payload); + GNUNET_free_non_null (rr->payload); rr->payload = NULL; rr->payload_length = 0; GNUNET_array_grow (rr->client_wait_list, @@ -356,6 +393,7 @@ request_done (struct RequestRecord *rr) /* send response via hijacker */ reply_len = sizeof (struct GNUNET_MessageHeader); + reply_len += sizeof (struct tun_header); switch (rr->src_addr.ss_family) { case AF_INET: @@ -381,6 +419,9 @@ request_done (struct RequestRecord *rr) { char buf[reply_len]; size_t off; + uint16_t *udp_crcp; + char *udp_crc_start; + uint16_t udp_crc_length; /* first, GNUnet message header */ hdr = (struct GNUNET_MessageHeader*) buf; @@ -388,7 +429,22 @@ request_done (struct RequestRecord *rr) hdr->size = htons ((uint16_t) reply_len); off = sizeof (struct GNUNET_MessageHeader); + /* first, TUN header */ + { + struct tun_header tun; + + tun.flags = htons (0); + if (rr->src_addr.ss_family == AF_INET) + tun.proto = htons (ETH_P_IPV4); + else + tun.proto = htons (ETH_P_IPV6); + memcpy (&buf[off], &tun, sizeof (struct tun_header)); + off += sizeof (struct tun_header); + } + /* now IP header */ + udp_crc_start = &buf[off]; + udp_crc_length = reply_len - off; switch (rr->src_addr.ss_family) { case AF_INET: @@ -412,6 +468,8 @@ request_done (struct RequestRecord *rr) ip.checksum = 0; /* checksum is optional */ ip.source_address = dst->sin_addr; ip.destination_address = src->sin_addr; + + ip.checksum = GNUNET_CRYPTO_crc16_n ((uint16_t*) &ip, sizeof (ip)); memcpy (&buf[off], &ip, sizeof (ip)); off += sizeof (ip); break; @@ -448,16 +506,23 @@ request_done (struct RequestRecord *rr) udp.spt = spt; udp.dpt = dpt; udp.len = htons (reply_len - off); - udp.crc = 0; /* checksum is optional */ + udp.crc = 0; /* checksum will be set later */ + memcpy (&buf[off], &udp, sizeof (udp)); + udp_crcp = (uint16_t*) &buf[off + offsetof (struct udp_packet, crc)]; off += sizeof (udp); } /* now DNS header */ { memcpy (&buf[off], rr->payload, rr->payload_length); off += rr->payload_length; + + fprintf (stderr, + "Sending %u bytes UDP packet to TUN\n", + (unsigned int) rr->payload_length); } + *udp_crcp = GNUNET_CRYPTO_crc16_n ((uint16_t *)udp_crc_start, udp_crc_length); /* final checks & sending */ GNUNET_assert (off == reply_len); GNUNET_HELPER_send (hijacker, @@ -579,6 +644,12 @@ next_phase (struct RequestRecord *rr) cleanup_rr (rr); return; } + if (NULL == dnsout) + { + /* fail, FIXME: case for statistics! */ + cleanup_rr (rr); + return; + } GNUNET_NETWORK_socket_sendto (dnsout, rr->payload, rr->payload_length, @@ -735,6 +806,10 @@ read_response (void *cls, GNUNET_free_non_null (rr->payload); rr->payload = GNUNET_malloc (len); memcpy (rr->payload, buf, len); + rr->payload_length = len; + fprintf (stderr, + "Received %u bytes UDP packet from DNS server\n", + (unsigned int) len); next_phase (rr); } } @@ -976,6 +1051,7 @@ process_helper_messages (void *cls GNUNET_UNUSED, void *client, const struct GNUNET_MessageHeader *message) { uint16_t msize; + const struct tun_header *tun; const struct ip4_header *ip4; const struct ip6_header *ip6; const struct udp_packet *udp; @@ -987,29 +1063,52 @@ process_helper_messages (void *cls GNUNET_UNUSED, void *client, struct sockaddr_in6 *dsta6; msize = ntohs (message->size); - if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct ip4_header)) + if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) + sizeof (struct ip4_header)) { /* non-IP packet received on TUN!? */ GNUNET_break (0); return; } msize -= sizeof (struct GNUNET_MessageHeader); - ip4 = (const struct ip4_header *) &message[1]; - ip6 = (const struct ip6_header *) &message[1]; - if (ip4->version == IPVERSION) + tun = (const struct tun_header *) &message[1]; + msize -= sizeof (struct tun_header); + switch (ntohs (tun->proto)) { + case ETH_P_IPV4: + ip4 = (const struct ip4_header *) &tun[1]; + if ( (msize < sizeof (struct ip4_header)) || + (ip4->version != IPVERSION) || + (ip4->header_length != sizeof (struct ip4_header) / 4) || + (ntohs(ip4->total_length) != msize) || + (ip4->protocol != IPPROTO_UDP) ) + { + /* non-IP/UDP packet received on TUN (or with options) */ + GNUNET_break (0); + return; + } udp = (const struct udp_packet*) &ip4[1]; msize -= sizeof (struct ip4_header); - } - else if ( (ip6->version == 6) && - (msize >= sizeof (struct ip6_header)) ) - { + break; + case ETH_P_IPV6: + ip6 = (const struct ip6_header *) &tun[1]; + if ( (msize < sizeof (struct ip6_header)) || + (ip6->version != 6) || + (ntohs (ip6->payload_length) != msize) || + (ip6->next_header != IPPROTO_UDP) ) + { + /* non-IP/UDP packet received on TUN (or with extensions) */ + GNUNET_break (0); + return; + } udp = (const struct udp_packet*) &ip6[1]; msize -= sizeof (struct ip6_header); - } - else - { + break; + default: /* non-IP packet received on TUN!? */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Got packet with %u bytes and protocol %u from TUN\n"), + (unsigned int) msize, + ntohs (tun->proto)); GNUNET_break (0); return; } diff --git a/src/util/crypto_crc.c b/src/util/crypto_crc.c index c26541457..c6cd83a74 100644 --- a/src/util/crypto_crc.c +++ b/src/util/crypto_crc.c @@ -114,7 +114,6 @@ GNUNET_CRYPTO_crc32_n (const void *buf, size_t len) } - /** * Perform an incremental step in a CRC16 (for TCP/IP) calculation. * @@ -126,7 +125,6 @@ GNUNET_CRYPTO_crc32_n (const void *buf, size_t len) uint32_t GNUNET_CRYPTO_crc16_step (uint32_t sum, uint16_t * hdr, size_t len) { - GNUNET_assert (0 == (len & 1)); for (; len >= 2; len -= 2) sum += *(hdr++); if (len == 1) diff --git a/src/util/helper.c b/src/util/helper.c index e5c3be08f..d4d26ba51 100644 --- a/src/util/helper.c +++ b/src/util/helper.c @@ -152,7 +152,7 @@ stop_helper (struct GNUNET_HELPER_Handle *h) if (NULL != h->helper_proc) { - GNUNET_OS_process_kill (h->helper_proc, SIGKILL); + GNUNET_OS_process_kill (h->helper_proc, SIGTERM); GNUNET_OS_process_wait (h->helper_proc); GNUNET_OS_process_close (h->helper_proc); h->helper_proc = NULL; @@ -247,16 +247,16 @@ helper_read (void *cls, } if (0 == t) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + /* this happens if the helper is shut down via a + signal, so it is not a "hard" error */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Got 0 bytes from helper `%s' (EOF)\n"), h->binary_name); -#if 0 stop_helper (h); /* Restart the helper */ h->restart_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &restart_task, h); -#endif return; } if (GNUNET_SYSERR == -- 2.25.1