]> granicus.if.org Git - libevent/commitdiff
add a simple regression test for the DNS resolver; requires internet access.
authorNiels Provos <provos@gmail.com>
Sun, 27 Aug 2006 20:04:20 +0000 (20:04 +0000)
committerNiels Provos <provos@gmail.com>
Sun, 27 Aug 2006 20:04:20 +0000 (20:04 +0000)
do some KNF on evdns.c; add checks to prevent potential buffer overflows.
fix one memory leak.

svn:r230

evdns.c
test/Makefile.am
test/regress.c
test/regress.h
test/regress_dns.c [new file with mode: 0644]

diff --git a/evdns.c b/evdns.c
index f2ad750942c73afa9af2f07aba1b8aa049cc4118..40838c6aa7dbdb6f044ada1ff43d34a394b70537 100644 (file)
--- a/evdns.c
+++ b/evdns.c
 #include <stdarg.h>
 
 #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));
        }
 }
 
index 7be0e05431dc8a0f3017043672edb0df7556c18e..66f0e311a9cc8a7ad1d0563b799781ab79165066 100644 (file)
@@ -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
 
index 2480d4257197421c19adc2a2b5d9ede4243f3070..904e4288472e1fd79c674856d608c99b3fd36c8a 100644 (file)
@@ -882,6 +882,8 @@ main (int argc, char **argv)
        event_base = event_init();
 
        http_suite();
+
+       dns_suite();
        
        test_simpleread();
 
index 3006830c7b8f3da832b5b8b125ff6cadd0427648..296c93c529fa6c97675f87e255afcddde476a7c0 100644 (file)
@@ -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 (file)
index 0000000..2e62655
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu>
+ * 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 <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <unistd.h>
+#endif
+#include <netdb.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#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();
+}