From c8fe500945cd968e37f2e6c462689e0ada061bce Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 4 Jan 2012 14:20:36 +0000 Subject: [PATCH] adding missing file --- src/dns/dnsparser.c | 3 + src/dns/gnunet-dns-monitor.c | 300 +++++++++++++++++++++++++++++++ src/dns/gnunet-service-dns_new.c | 32 +++- 3 files changed, 329 insertions(+), 6 deletions(-) create mode 100644 src/dns/gnunet-dns-monitor.c diff --git a/src/dns/dnsparser.c b/src/dns/dnsparser.c index 2a3fd55c0..468c984aa 100644 --- a/src/dns/dnsparser.c +++ b/src/dns/dnsparser.c @@ -86,7 +86,10 @@ parse_name (const char *udp_payload, goto error; len = input[*off]; if (0 == len) + { + (*off)++; break; + } if (len < 64) { if (*off + 1 + len > udp_payload_length) diff --git a/src/dns/gnunet-dns-monitor.c b/src/dns/gnunet-dns-monitor.c new file mode 100644 index 000000000..c8fb646e5 --- /dev/null +++ b/src/dns/gnunet-dns-monitor.c @@ -0,0 +1,300 @@ +/* + This file is part of GNUnet. + (C) 2011 Christian Grothoff (and other contributing authors) + + 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 src/dns/gnunet-dns-monitor.c + * @brief Tool to monitor DNS queries + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_dns_service-new.h" +#include "gnunet_dnsparser_lib.h" + +/** + * Handle to transport service. + */ +static struct GNUNET_DNS_Handle *handle; + +/** + * Option -s. + */ +static int benchmark_send; + +/** + * Global return value (0 success). + */ +static int ret; + +/** + * Selected level of verbosity. + */ +static int verbosity; + + +/** + * Convert numeric DNS record type to a string. + * + * @param type type to convert + * @return type as string, only valid until the next call to this function + */ +static const char * +get_type (uint16_t type) +{ + static char buf[6]; + switch (type) + { + case GNUNET_DNSPARSER_TYPE_A: return "A"; + case GNUNET_DNSPARSER_TYPE_NS: return "NS"; + case GNUNET_DNSPARSER_TYPE_CNAME: return "CNAME"; + case GNUNET_DNSPARSER_TYPE_SOA: return "SOA"; + case GNUNET_DNSPARSER_TYPE_PTR: return "PTR"; + case GNUNET_DNSPARSER_TYPE_MX: return "MX"; + case GNUNET_DNSPARSER_TYPE_TXT: return "TXT"; + case GNUNET_DNSPARSER_TYPE_AAAA: return "AAAA"; + case GNUNET_DNSPARSER_TYPE_IXFR: return "IXFR"; + case GNUNET_DNSPARSER_TYPE_AXFR: return "AXFR"; + } + GNUNET_snprintf (buf, sizeof (buf), "%u", (unsigned int) type); + return buf; +} + + +/** + * Convert numeric DNS record class to a string. + * + * @param class class to convert + * @return class as string, only valid until the next call to this function + */ +static const char * +get_class (uint16_t class) +{ + static char buf[6]; + switch (class) + { + case GNUNET_DNSPARSER_CLASS_INTERNET: return "IN"; + case GNUNET_DNSPARSER_CLASS_CHAOS: return "CHAOS"; + case GNUNET_DNSPARSER_CLASS_HESIOD: return "HESIOD"; + } + GNUNET_snprintf (buf, sizeof (buf), "%u", (unsigned int) class); + return buf; +} + + +/** + * Output the given DNS query to stdout. + * + * @param query query to display. + */ +static void +display_query (const struct GNUNET_DNSPARSER_Query *query) +{ + fprintf (stdout, + "\t\t%s %s: %s\n", + get_class (query->class), + get_type (query->type), + query->name); +} + + +/** + * Output the given DNS query to stdout. + * + * @param query query to display. + */ +static void +display_record (const struct GNUNET_DNSPARSER_Record *record) +{ + const char *format; + char buf[INET6_ADDRSTRLEN]; + char *tmp; + + tmp = NULL; + switch (record->type) + { + case GNUNET_DNSPARSER_TYPE_A: + if (record->data_len != sizeof (struct in_addr)) + format = ""; + else + format = inet_ntop (AF_INET, record->data, buf, sizeof (buf)); + break; + case GNUNET_DNSPARSER_TYPE_AAAA: + if (record->data_len != sizeof (struct in6_addr)) + format = ""; + else + format = inet_ntop (AF_INET6, record->data, buf, sizeof (buf)); + break; + case GNUNET_DNSPARSER_TYPE_CNAME: + tmp = GNUNET_strdup ("FIXME"); + default: + format = ""; + break; + } + fprintf (stdout, + "\t\t%s %s: %s = %s (%u bytes, %u s)\n", + get_class (record->class), + get_type (record->type), + record->name, + format, + (unsigned int) record->data_len, + (unsigned int) (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value / 1000)); + GNUNET_free_non_null (tmp); +} + + +/** + * Signature of a function that is called whenever the DNS service + * encounters a DNS request and needs to do something with it. The + * function has then the chance to generate or modify the response by + * calling one of the three "GNUNET_DNS_request_*" continuations. + * + * When a request is intercepted, this function is called first to + * give the client a chance to do the complete address resolution; + * "rdata" will be NULL for this first call for a DNS request, unless + * some other client has already filled in a response. + * + * If multiple clients exist, all of them are called before the global + * DNS. The global DNS is only called if all of the clients' + * functions call GNUNET_DNS_request_forward. Functions that call + * GNUNET_DNS_request_forward will be called again before a final + * response is returned to the application. If any of the clients' + * functions call GNUNET_DNS_request_drop, the response is dropped. + * + * @param cls closure + * @param rh request handle to user for reply + * @param request_length number of bytes in request + * @param request udp payload of the DNS request + */ +static void +display_request (void *cls, + struct GNUNET_DNS_RequestHandle *rh, + size_t request_length, + const char *request) +{ + static const char *return_codes[] = + { + "No error", "Format error", "Server failure", "Name error", + "Not implemented", "Refused", "YXDomain", "YXRRset", + "NXRRset", "NOT AUTH", "NOT ZONE", "", + "", "", "", "" + }; + static const char *op_codes[] = + { + "Query", "Inverse query", "Status", "", + "", "", "", "", + "", "", "", "", + "", "", "", "" + }; + struct GNUNET_DNSPARSER_Packet *p; + unsigned int i; + + p = GNUNET_DNSPARSER_parse (request, request_length); + if (NULL == p) + { + fprintf (stderr, "Received malformed DNS packet!\n"); + // FIXME: drop instead? + GNUNET_DNS_request_forward (rh); + return; + } + fprintf (stdout, + "%s with ID: %5u Flags: %s%s%s%s%s%s Return Code: %s Opcode: %s\n", + p->flags.query_or_response ? "Response" : "Query", + p->id, + p->flags.recursion_desired ? "RD " : "", + p->flags.message_truncated ? "MT " : "", + p->flags.authoritative_answer ? "AA " : "", + p->flags.checking_disabled ? "CD " : "", + p->flags.authenticated_data ? "AD " : "", + p->flags.recursion_available ? "RA " : "", + return_codes[p->flags.return_code & 15], + op_codes[p->flags.opcode & 15]); + if (p->num_queries > 0) + fprintf (stdout, + "\tQueries:\n"); + for (i=0;inum_queries;i++) + display_query (&p->queries[i]); + + if (p->num_answers > 0) + fprintf (stdout, + "\tAnswers:\n"); + for (i=0;inum_answers;i++) + display_record (&p->answers[i]); + fprintf (stdout, "\n"); + GNUNET_DNSPARSER_free_packet (p); + GNUNET_DNS_request_forward (rh); +} + + +/** + * Shutdown. + */ +static void +do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (NULL != handle) + { + GNUNET_DNS_disconnect (handle); + handle = NULL; + } +} + + +/** + * Main function that will be run by the scheduler. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + handle = + GNUNET_DNS_connect (cfg, + GNUNET_DNS_FLAG_REQUEST_MONITOR | GNUNET_DNS_FLAG_RESPONSE_MONITOR, + &display_request, + NULL); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &do_disconnect, NULL); +} + + +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'s', "testoption", NULL, + gettext_noop ("not useful"), + 0, &GNUNET_GETOPT_set_one, &benchmark_send}, + GNUNET_GETOPT_OPTION_VERBOSE (&verbosity), + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-dns-monitor", + gettext_noop + ("Monitor DNS queries."), options, + &run, NULL)) ? ret : 1; +} + + +/* end of gnunet-dns-monitor.c */ diff --git a/src/dns/gnunet-service-dns_new.c b/src/dns/gnunet-service-dns_new.c index bf2368faa..d814ecb47 100644 --- a/src/dns/gnunet-service-dns_new.c +++ b/src/dns/gnunet-service-dns_new.c @@ -131,7 +131,7 @@ enum RequestPhase * Showing the request to all monitor clients. If * client list is empty, will enter QUERY phase. */ - RP_MONITOR, + RP_REQUEST_MONITOR, /** * Showing the request to PRE-RESOLUTION clients to find an answer. @@ -147,10 +147,16 @@ enum RequestPhase /** * Client (or global DNS request) has resulted in a response. * Forward to all POST-RESOLUTION clients. If client list is empty, - * give the result to the hijacker (and be done). + * will enter RESPONSE_MONITOR phase. */ RP_MODIFY, + /** + * Showing the request to all monitor clients. If + * client list is empty, give the result to the hijacker (and be done). + */ + RP_RESPONSE_MONITOR, + /** * Some client has told us to drop the request. */ @@ -384,7 +390,7 @@ request_done (struct RequestRecord *rr) GNUNET_array_grow (rr->client_wait_list, rr->client_wait_list_length, 0); - if (RP_MODIFY != rr->phase) + if (RP_RESPONSE_MONITOR != rr->phase) { /* no response, drop */ cleanup_rr (rr); @@ -632,7 +638,7 @@ next_phase (struct RequestRecord *rr) switch (rr->phase) { case RP_INIT: - rr->phase = RP_MONITOR; + rr->phase = RP_REQUEST_MONITOR; for (cr = clients_head; NULL != cr; cr = cr->next) { if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR)) @@ -642,7 +648,7 @@ next_phase (struct RequestRecord *rr) } next_phase (rr); return; - case RP_MONITOR: + case RP_REQUEST_MONITOR: rr->phase = RP_QUERY; for (cr = clients_head; NULL != cr; cr = cr->next) { @@ -694,6 +700,17 @@ next_phase (struct RequestRecord *rr) next_phase (rr); return; case RP_MODIFY: + rr->phase = RP_RESPONSE_MONITOR; + for (cr = clients_head; NULL != cr; cr = cr->next) + { + if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR)) + GNUNET_array_append (rr->client_wait_list, + rr->client_wait_list_length, + cr); + } + next_phase (rr); + return; + case RP_RESPONSE_MONITOR: request_done (rr); break; case RP_DROP: @@ -1019,6 +1036,8 @@ handle_client_response (void *cls GNUNET_UNUSED, } for (i=0;iclient_wait_list_length;i++) { + if (NULL == rr->client_wait_list[i]) + continue; if (rr->client_wait_list[i]->client != client) continue; rr->client_wait_list[i] = NULL; @@ -1032,7 +1051,8 @@ handle_client_response (void *cls GNUNET_UNUSED, case 2: /* update */ msize -= sizeof (struct GNUNET_DNS_Response); if ( (sizeof (struct dns_header) > msize) || - (RP_MONITOR == rr->phase) ) + (RP_REQUEST_MONITOR == rr->phase) || + (RP_RESPONSE_MONITOR == rr->phase) ) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); -- 2.25.1