rbt_serialize_test.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
00003  *
00004  * Permission to use, copy, modify, and/or distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00009  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00010  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00011  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00012  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00013  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00014  * PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 /* $Id: rbt_test.c,v 1.1.14.8 2012/02/10 16:24:37 ckb Exp $ */
00018 
00019 /* ! \file */
00020 
00021 #include <config.h>
00022 #include <atf-c.h>
00023 #include <isc/mem.h>
00024 #include <isc/random.h>
00025 #include <isc/string.h>
00026 #include <fcntl.h>
00027 #include <unistd.h>
00028 #include <sys/mman.h>
00029 
00030 #ifdef HAVE_INTTYPES_H
00031 #include <inttypes.h> /* uintptr_t */
00032 #endif
00033 
00034 #include <dns/rbt.h>
00035 #include <dns/fixedname.h>
00036 #include <dns/result.h>
00037 #include <dns/compress.h>
00038 #include "dnstest.h"
00039 
00040 #include <isc/app.h>
00041 #include <isc/buffer.h>
00042 #include <isc/entropy.h>
00043 #include <isc/file.h>
00044 #include <isc/hash.h>
00045 #include <isc/mem.h>
00046 #include <isc/os.h>
00047 #include <isc/string.h>
00048 #include <isc/socket.h>
00049 #include <isc/stdio.h>
00050 #include <isc/task.h>
00051 #include <isc/timer.h>
00052 #include <isc/util.h>
00053 
00054 #include <dns/log.h>
00055 #include <dns/name.h>
00056 #include <dns/result.h>
00057 
00058 #include <dst/dst.h>
00059 
00060 #ifndef MAP_FILE
00061 #define MAP_FILE 0
00062 #endif
00063 
00064 typedef struct data_holder {
00065         int len;
00066         const char *data;
00067 } data_holder_t;
00068 
00069 typedef struct rbt_testdata {
00070         const char *name;
00071         size_t name_len;
00072         data_holder_t data;
00073 } rbt_testdata_t;
00074 
00075 #define DATA_ITEM(name) { (name), sizeof(name) - 1, { sizeof(name), (name) } }
00076 
00077 rbt_testdata_t testdata[] = {
00078         DATA_ITEM("first.com."),
00079         DATA_ITEM("one.net."),
00080         DATA_ITEM("two.com."),
00081         DATA_ITEM("three.org."),
00082         DATA_ITEM("asdf.com."),
00083         DATA_ITEM("ghjkl.com."),
00084         DATA_ITEM("1.edu."),
00085         DATA_ITEM("2.edu."),
00086         DATA_ITEM("3.edu."),
00087         DATA_ITEM("123.edu."),
00088         DATA_ITEM("1236.com."),
00089         DATA_ITEM("and_so_forth.com."),
00090         DATA_ITEM("thisisalongname.com."),
00091         DATA_ITEM("a.b."),
00092         DATA_ITEM("test.net."),
00093         DATA_ITEM("whoknows.org."),
00094         DATA_ITEM("blargh.com."),
00095         DATA_ITEM("www.joe.com."),
00096         DATA_ITEM("test.com."),
00097         DATA_ITEM("isc.org."),
00098         DATA_ITEM("uiop.mil."),
00099         DATA_ITEM("last.fm."),
00100         { NULL, 0, { 0, NULL } }
00101 };
00102 
00103 static void
00104 delete_data(void *data, void *arg) {
00105         UNUSED(arg);
00106         UNUSED(data);
00107 }
00108 
00109 static isc_result_t
00110 write_data(FILE *file, unsigned char *datap, void *arg, isc_uint64_t *crc) {
00111         isc_result_t result;
00112         size_t ret = 0;
00113         data_holder_t *data = (data_holder_t *)datap;
00114         data_holder_t temp;
00115         off_t where;
00116 
00117         UNUSED(arg);
00118 
00119         REQUIRE(file != NULL);
00120         REQUIRE(crc != NULL);
00121         REQUIRE(data != NULL);
00122         REQUIRE((data->len == 0 && data->data == NULL) ||
00123                 (data->len != 0 && data->data != NULL));
00124 
00125         result = isc_stdio_tell(file, &where);
00126         if (result != ISC_R_SUCCESS)
00127                 return (result);
00128 
00129         temp = *data;
00130         temp.data = (data->len == 0
00131                      ? NULL
00132                      : (char *)((uintptr_t)where + sizeof(data_holder_t)));
00133 
00134         isc_crc64_update(crc, (void *)&temp, sizeof(temp));
00135         ret = fwrite(&temp, sizeof(data_holder_t), 1, file);
00136         if (ret != 1)
00137                 return (ISC_R_FAILURE);
00138         if (data->len > 0) {
00139                 isc_crc64_update(crc, (const void *)data->data, data->len);
00140                 ret = fwrite(data->data, data->len, 1, file);
00141                 if (ret != 1)
00142                         return (ISC_R_FAILURE);
00143         }
00144 
00145         return (ISC_R_SUCCESS);
00146 }
00147 
00148 static isc_result_t
00149 fix_data(dns_rbtnode_t *p, void *base, size_t max, void *arg,
00150          isc_uint64_t *crc)
00151 {
00152         data_holder_t *data = p->data;
00153         size_t size;
00154 
00155         UNUSED(base);
00156         UNUSED(max);
00157         UNUSED(arg);
00158 
00159         REQUIRE(crc != NULL);
00160         REQUIRE(p != NULL);
00161 
00162 
00163         if (data == NULL)
00164                 printf("fixing data: data NULL\n");
00165         else
00166                 printf("fixing data: len %d, data %p\n", data->len, data->data);
00167 
00168         if (data == NULL ||
00169             (data->len == 0 && data->data != NULL) ||
00170             (data->len != 0 && data->data == NULL))
00171                 return (ISC_R_INVALIDFILE);
00172 
00173         size = max - ((char *)p - (char *)base);
00174 
00175         if (data->len > (int) size || data->data > (const char *) max) {
00176                 printf("data invalid\n");
00177                 return (ISC_R_INVALIDFILE);
00178         }
00179 
00180         isc_crc64_update(crc, (void *)data, sizeof(*data));
00181 
00182         data->data = (data->len == 0)
00183                 ? NULL
00184                 : (char *)data + sizeof(data_holder_t);
00185 
00186         if (data->len > 0)
00187                 isc_crc64_update(crc, (const void *)data->data, data->len);
00188 
00189         return (ISC_R_SUCCESS);
00190 }
00191 
00192 /*
00193  * Load test data into the RBT.
00194  */
00195 static void
00196 add_test_data(isc_mem_t *mymctx, dns_rbt_t *rbt) {
00197         char buffer[1024];
00198         isc_buffer_t b;
00199         isc_result_t result;
00200         dns_fixedname_t fname;
00201         dns_name_t *name;
00202         dns_compress_t cctx;
00203         rbt_testdata_t *testdatap = testdata;
00204 
00205         dns_compress_init(&cctx, -1, mymctx);
00206 
00207         while (testdatap->name != NULL && testdatap->data.data != NULL) {
00208                 memmove(buffer, testdatap->name, testdatap->name_len);
00209 
00210                 isc_buffer_init(&b, buffer, testdatap->name_len);
00211                 isc_buffer_add(&b, testdatap->name_len);
00212                 dns_fixedname_init(&fname);
00213                 name = dns_fixedname_name(&fname);
00214                 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
00215                 if (result != ISC_R_SUCCESS) {
00216                         testdatap++;
00217                         continue;
00218                 }
00219 
00220                 if (name != NULL) {
00221                         result = dns_rbt_addname(rbt, name, &testdatap->data);
00222                         ATF_CHECK_STREQ(dns_result_totext(result), "success");
00223                 }
00224                 testdatap++;
00225         }
00226 
00227         dns_compress_invalidate(&cctx);
00228 }
00229 
00230 /*
00231  * Walk the tree and ensure that all the test nodes are present.
00232  */
00233 static void
00234 check_test_data(dns_rbt_t *rbt) {
00235         char buffer[1024];
00236         char *arg;
00237         dns_fixedname_t fname;
00238         dns_fixedname_t fixed;
00239         dns_name_t *name;
00240         isc_buffer_t b;
00241         data_holder_t *data;
00242         isc_result_t result;
00243         dns_name_t *foundname;
00244         rbt_testdata_t *testdatap = testdata;
00245 
00246         dns_fixedname_init(&fixed);
00247         foundname = dns_fixedname_name(&fixed);
00248 
00249         while (testdatap->name != NULL && testdatap->data.data != NULL) {
00250                 memmove(buffer, testdatap->name, testdatap->name_len + 1);
00251                 arg = buffer;
00252 
00253                 isc_buffer_init(&b, arg, testdatap->name_len);
00254                 isc_buffer_add(&b, testdatap->name_len);
00255                 dns_fixedname_init(&fname);
00256                 name = dns_fixedname_name(&fname);
00257                 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
00258                 if (result != ISC_R_SUCCESS) {
00259                         testdatap++;
00260                         continue;
00261                 }
00262 
00263                 data = NULL;
00264                 result = dns_rbt_findname(rbt, name, 0, foundname,
00265                                           (void *) &data);
00266                 ATF_CHECK_STREQ(dns_result_totext(result), "success");
00267 
00268                 testdatap++;
00269         }
00270 }
00271 
00272 static void
00273 data_printer(FILE *out, void *datap)
00274 {
00275         data_holder_t *data = (data_holder_t *)datap;
00276 
00277         fprintf(out, "%d bytes, %s", data->len, data->data);
00278 }
00279 
00280 ATF_TC(serialize);
00281 ATF_TC_HEAD(serialize, tc) {
00282         atf_tc_set_md_var(tc, "descr", "Test writing an rbt to file");
00283 }
00284 ATF_TC_BODY(serialize, tc) {
00285         dns_rbt_t *rbt = NULL;
00286         isc_result_t result;
00287         FILE *rbtfile = NULL;
00288         dns_rbt_t *rbt_deserialized = NULL;
00289         off_t offset;
00290         int fd;
00291         off_t filesize = 0;
00292         char *base;
00293 
00294         UNUSED(tc);
00295 
00296         isc_mem_debugging = ISC_MEM_DEBUGRECORD;
00297 
00298         result = dns_test_begin(NULL, ISC_TRUE);
00299         ATF_CHECK_STREQ(dns_result_totext(result), "success");
00300         result = dns_rbt_create(mctx, delete_data, NULL, &rbt);
00301         ATF_CHECK_STREQ(dns_result_totext(result), "success");
00302 
00303         add_test_data(mctx, rbt);
00304 
00305         dns_rbt_printtext(rbt, data_printer, stdout);
00306 
00307         /*
00308          * Serialize the tree.
00309          */
00310         printf("serialization begins.\n");
00311         rbtfile = fopen("./zone.bin", "w+b");
00312         ATF_REQUIRE(rbtfile != NULL);
00313         result = dns_rbt_serialize_tree(rbtfile, rbt, write_data, NULL,
00314                                         &offset);
00315         ATF_REQUIRE(result == ISC_R_SUCCESS);
00316         dns_rbt_destroy(&rbt);
00317 
00318         /*
00319          * Deserialize the tree
00320          */
00321         printf("deserialization begins.\n");
00322 
00323         /*
00324          * Map in the whole file in one go
00325          */
00326         fd = open("zone.bin", O_RDWR);
00327         isc_file_getsizefd(fd, &filesize);
00328         base = mmap(NULL, filesize,
00329                     PROT_READ|PROT_WRITE,
00330                     MAP_FILE|MAP_PRIVATE, fd, 0);
00331         ATF_REQUIRE(base != NULL && base != MAP_FAILED);
00332         close(fd);
00333 
00334         result = dns_rbt_deserialize_tree(base, filesize, 0, mctx,
00335                                           delete_data, NULL, fix_data, NULL,
00336                                           NULL, &rbt_deserialized);
00337 
00338         /* Test to make sure we have a valid tree */
00339         ATF_REQUIRE(result == ISC_R_SUCCESS);
00340         if (rbt_deserialized == NULL)
00341                 atf_tc_fail("deserialized rbt is null!"); /* Abort execution. */
00342 
00343         check_test_data(rbt_deserialized);
00344 
00345         dns_rbt_printtext(rbt_deserialized, data_printer, stdout);
00346 
00347         dns_rbt_destroy(&rbt_deserialized);
00348         munmap(base, filesize);
00349         unlink("zone.bin");
00350         dns_test_end();
00351 }
00352 
00353 ATF_TC(deserialize_corrupt);
00354 ATF_TC_HEAD(deserialize_corrupt, tc) {
00355         atf_tc_set_md_var(tc, "descr", "Test reading a corrupt map file");
00356 }
00357 ATF_TC_BODY(deserialize_corrupt, tc) {
00358         dns_rbt_t *rbt = NULL;
00359         isc_result_t result;
00360         FILE *rbtfile = NULL;
00361         off_t offset;
00362         int fd;
00363         off_t filesize = 0;
00364         char *base, *p, *q;
00365         isc_uint32_t r;
00366         int i;
00367 
00368         UNUSED(tc);
00369 
00370         isc_mem_debugging = ISC_MEM_DEBUGRECORD;
00371 
00372         result = dns_test_begin(NULL, ISC_TRUE);
00373         ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
00374 
00375         /* Set up map file */
00376         result = dns_rbt_create(mctx, delete_data, NULL, &rbt);
00377         ATF_CHECK_EQ(result, ISC_R_SUCCESS);
00378 
00379         add_test_data(mctx, rbt);
00380         rbtfile = fopen("./zone.bin", "w+b");
00381         ATF_REQUIRE(rbtfile != NULL);
00382         result = dns_rbt_serialize_tree(rbtfile, rbt, write_data, NULL,
00383                                         &offset);
00384         ATF_REQUIRE(result == ISC_R_SUCCESS);
00385         dns_rbt_destroy(&rbt);
00386 
00387         /* Read back with random fuzzing */
00388         for (i = 0; i < 256; i++) {
00389                 dns_rbt_t *rbt_deserialized = NULL;
00390 
00391                 fd = open("zone.bin", O_RDWR);
00392                 isc_file_getsizefd(fd, &filesize);
00393                 base = mmap(NULL, filesize,
00394                             PROT_READ|PROT_WRITE,
00395                             MAP_FILE|MAP_PRIVATE, fd, 0);
00396                 ATF_REQUIRE(base != NULL && base != MAP_FAILED);
00397                 close(fd);
00398 
00399                 /* Randomly fuzz a portion of the memory */
00400                 isc_random_get(&r);
00401                 p = base + (r % filesize);
00402                 q = base + filesize;
00403                 isc_random_get(&r);
00404                 q -= (r % (q - p));
00405                 while (p++ < q) {
00406                         isc_random_get(&r);
00407                         *p = r & 0xff;
00408                 }
00409 
00410                 result = dns_rbt_deserialize_tree(base, filesize, 0, mctx,
00411                                                   delete_data, NULL,
00412                                                   fix_data, NULL,
00413                                                   NULL, &rbt_deserialized);
00414                 printf("%d: %s\n", i, isc_result_totext(result));
00415 
00416                 /* Test to make sure we have a valid tree */
00417                 ATF_REQUIRE(result == ISC_R_SUCCESS ||
00418                             result == ISC_R_INVALIDFILE);
00419                 if (result != ISC_R_SUCCESS)
00420                         ATF_REQUIRE(rbt_deserialized == NULL);
00421 
00422                 if (rbt_deserialized != NULL)
00423                         dns_rbt_destroy(&rbt_deserialized);
00424 
00425                 munmap(base, filesize);
00426         }
00427 
00428         unlink("zone.bin");
00429         dns_test_end();
00430 }
00431 
00432 
00433 ATF_TC(serialize_align);
00434 ATF_TC_HEAD(serialize_align, tc) {
00435         atf_tc_set_md_var(tc, "descr",
00436                           "Test the dns_rbt_serialize_align() function.");
00437 }
00438 ATF_TC_BODY(serialize_align, tc) {
00439         UNUSED(tc);
00440 
00441         ATF_CHECK(dns_rbt_serialize_align(0) == 0);
00442         ATF_CHECK(dns_rbt_serialize_align(1) == 8);
00443         ATF_CHECK(dns_rbt_serialize_align(2) == 8);
00444         ATF_CHECK(dns_rbt_serialize_align(3) == 8);
00445         ATF_CHECK(dns_rbt_serialize_align(4) == 8);
00446         ATF_CHECK(dns_rbt_serialize_align(5) == 8);
00447         ATF_CHECK(dns_rbt_serialize_align(6) == 8);
00448         ATF_CHECK(dns_rbt_serialize_align(7) == 8);
00449         ATF_CHECK(dns_rbt_serialize_align(8) == 8);
00450         ATF_CHECK(dns_rbt_serialize_align(9) == 16);
00451         ATF_CHECK(dns_rbt_serialize_align(0xff) == 0x100);
00452         ATF_CHECK(dns_rbt_serialize_align(0x301) == 0x308);
00453 }
00454 
00455 /*
00456  * Main
00457  */
00458 ATF_TP_ADD_TCS(tp) {
00459         ATF_TP_ADD_TC(tp, serialize);
00460         ATF_TP_ADD_TC(tp, deserialize_corrupt);
00461         ATF_TP_ADD_TC(tp, serialize_align);
00462 
00463         return (atf_no_error());
00464 }

Generated on Tue Apr 28 17:41:01 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha