From 07c3fb50675fa9a80b928f24028431e92358df3c Mon Sep 17 00:00:00 2001 From: Niels Provos Date: Sun, 27 Aug 2006 20:04:20 +0000 Subject: [PATCH] add a simple regression test for the DNS resolver; requires internet access. do some KNF on evdns.c; add checks to prevent potential buffer overflows. fix one memory leak. svn:r230 --- evdns.c | 66 +++++++++++++++++++++---------- test/Makefile.am | 2 +- test/regress.c | 2 + test/regress.h | 2 + test/regress_dns.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 147 insertions(+), 21 deletions(-) create mode 100644 test/regress_dns.c diff --git a/evdns.c b/evdns.c index f2ad7509..40838c6a 100644 --- a/evdns.c +++ b/evdns.c @@ -279,6 +279,7 @@ #include #include "evdns.h" +#include "log.h" #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 255 @@ -849,7 +850,8 @@ transaction_id_pick(void) { #ifdef DNS_USE_CPU_CLOCK_FOR_ID struct timespec ts; const u16 trans_id = ts.tv_nsec & 0xffff; - if (clock_gettime(CLOCK_PROF, &ts)) abort(); + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + event_err(1, "clock_gettime"); #endif #ifdef DNS_USE_GETTIMEOFDAY_FOR_ID @@ -1037,15 +1039,21 @@ evdns_request_len(const int name_len) { // // Returns the amount of space used. Negative on error. static int -evdns_request_data_build(const char *const name, const int name_len, const u16 trans_id, - const u16 type, const u16 class, - u8 *const buf) { +evdns_request_data_build(const char *const name, const int name_len, + const u16 trans_id, const u16 type, const u16 class, + u8 *const buf, size_t buf_len) { int j = 0; // current offset into buf u16 _t; // used by the macros u8 *labels; int labels_len; -#define APPEND16(x) do { _t = htons(x); memcpy(buf + j, &_t, 2); j += 2; } while(0); +#define APPEND16(x) do { \ + if (j + 2 > buf_len) \ + return (-1); \ + _t = htons(x); \ + memcpy(buf + j, &_t, 2); j += 2; \ +} while(0) + APPEND16(trans_id); APPEND16(0x0100); // standard query, recusion needed APPEND16(1); // one question @@ -1054,17 +1062,26 @@ evdns_request_data_build(const char *const name, const int name_len, const u16 t APPEND16(0); // no additional labels = (u8 *) malloc(name_len + 2); - if (!labels) return -1; + if (labels == NULL) + return (-1); labels_len = dnsname_to_labels(labels, name, name_len); - if (labels_len < 0) return labels_len; + if (labels_len < 0) { + free(labels); + return (labels_len); + } + if (j + labels_len > buf_len) { + free(labels); + return (-1); + } memcpy(buf + j, labels, labels_len); j += labels_len; - + free(labels); + APPEND16(type); APPEND16(class); #undef APPEND16 - return j; + return (j); } // this is a libevent callback function which is called when a request @@ -1396,14 +1413,17 @@ string_num_dots(const char *s) { } static struct request * -request_new(const char *name, int flags, evdns_callback_type callback, void *ptr) { - const char issuing_now = (global_requests_inflight < global_max_requests_inflight) ? 1 : 0; +request_new(const char *name, int flags, + evdns_callback_type callback, void *ptr) { + const char issuing_now = + (global_requests_inflight < global_max_requests_inflight) ? 1 : 0; const int name_len = strlen(name); const int request_max_len = evdns_request_len(name_len); const u16 trans_id = issuing_now ? transaction_id_pick() : 0xffff; // the request data is alloced in a single block with the header - struct request *const req = (struct request *) malloc(sizeof(struct request) + request_max_len); + struct request *const req = + (struct request *) malloc(sizeof(struct request) + request_max_len); int rlen; (void) flags; @@ -1412,9 +1432,12 @@ request_new(const char *name, int flags, evdns_callback_type callback, void *ptr // request data lives just after the header req->request = ((u8 *) req) + sizeof(struct request); - req->request_appended = 1; // denotes that the request data shouldn't be free()ed - rlen = evdns_request_data_build(name, name_len, trans_id, TYPE_A, CLASS_INET, req->request); - if (rlen < 0) goto err1; + // denotes that the request data shouldn't be free()ed + req->request_appended = 1; + rlen = evdns_request_data_build(name, name_len, trans_id, + TYPE_A, CLASS_INET, req->request, request_max_len); + if (rlen < 0) + goto err1; req->request_len = rlen; req->trans_id = trans_id; req->tx_count = 0; @@ -1444,15 +1467,18 @@ request_submit(struct request *const req) { } // exported function -int evdns_resolve(const char *name, int flags, evdns_callback_type callback, void *ptr) { +int evdns_resolve(const char *name, int flags, + evdns_callback_type callback, void *ptr) { log("Resolve requested for %s", name); if (flags & DNS_QUERY_NO_SEARCH) { - struct request *const req = request_new(name, flags, callback, ptr); - if (!req) return 1; + struct request *const req = + request_new(name, flags, callback, ptr); + if (req == NULL) + return (1); request_submit(req); - return 0; + return (0); } else { - return search_request_new(name, flags, callback, ptr); + return (search_request_new(name, flags, callback, ptr)); } } diff --git a/test/Makefile.am b/test/Makefile.am index 7be0e054..66f0e311 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -13,7 +13,7 @@ test_init_SOURCES = test-init.c test_eof_SOURCES = test-eof.c test_weof_SOURCES = test-weof.c test_time_SOURCES = test-time.c -regress_SOURCES = regress.c regress.h regress_http.c \ +regress_SOURCES = regress.c regress.h regress_http.c regress_dns.c \ regress.gen.c regress.gen.h bench_SOURCES = bench.c diff --git a/test/regress.c b/test/regress.c index 2480d425..904e4288 100644 --- a/test/regress.c +++ b/test/regress.c @@ -882,6 +882,8 @@ main (int argc, char **argv) event_base = event_init(); http_suite(); + + dns_suite(); test_simpleread(); diff --git a/test/regress.h b/test/regress.h index 3006830c..296c93c5 100644 --- a/test/regress.h +++ b/test/regress.h @@ -34,6 +34,8 @@ extern "C" { void http_suite(void); void http_basic_test(void); +void dns_suite(void); + #ifdef __cplusplus } #endif diff --git a/test/regress_dns.c b/test/regress_dns.c new file mode 100644 index 00000000..2e626553 --- /dev/null +++ b/test/regress_dns.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2003-2006 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef WIN32 +#include +#include +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include +#ifndef WIN32 +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "event.h" +#include "evdns.h" +#include "log.h" + +static int dns_ok = 0; + +void +dns_gethostbyname_cb(int result, char type, int count, int ttl, + void *addresses, void *arg) +{ + if (result == DNS_ERR_NONE) + dns_ok = 1; + event_loopexit(NULL); +} + +void +dns_gethostbyname() +{ + fprintf(stdout, "Simple DNS resolve: "); + evdns_resolve("www.monkey.org", 0, dns_gethostbyname_cb, NULL); + event_dispatch(); + + if (dns_ok) { + fprintf(stdout, "OK\n"); + } else { + fprintf(stdout, "FAILED\n"); + exit(1); + } +} + +void +dns_suite(void) +{ +#ifdef WIN32 + evdns_config_windows_nameservers(); +#else + evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf"); +#endif + dns_gethostbyname(); + + evdns_clear_nameservers_and_suspend(); +} -- 2.40.0