Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / tests / dns_test.c
diff --git a/qemu/roms/ipxe/src/tests/dns_test.c b/qemu/roms/ipxe/src/tests/dns_test.c
new file mode 100644 (file)
index 0000000..52f5f19
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 2 of the
+ * License, or any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * DNS self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <string.h>
+#include <assert.h>
+#include <ipxe/dns.h>
+#include <ipxe/test.h>
+
+/** Define inline data */
+#define DATA(...) { __VA_ARGS__ }
+
+/** A DNS encoding test */
+struct dns_encode_test {
+       /** String */
+       const char *string;
+       /** Encoded string */
+       const void *data;
+       /** Length of encoded string */
+       int len;
+};
+
+/**
+ * Define a DNS encoding test
+ *
+ * @v _name            Test name
+ * @v _string          Test string
+ * @v _data            Expected encoded data
+ * @ret test           DNS encoding test
+ */
+#define DNS_ENCODE( _name, _string, _data )                            \
+       static const uint8_t _name ## __data[] = _data;                 \
+       static struct dns_encode_test _name = {                         \
+               .string = _string,                                      \
+               .data = _name ## __data,                                \
+               .len = sizeof ( _name ## __data ),                      \
+       }
+
+/**
+ * Report DNS encoding test result
+ *
+ * @v test             DNS encoding test
+ * @v file             Test code file
+ * @v line             Test code line
+ */
+static void dns_encode_okx ( struct dns_encode_test *test, const char *file,
+                            unsigned int line ) {
+       uint8_t data[ test->len ];
+       struct dns_name name;
+       int len;
+
+       /* Check ability to determine length with no buffer */
+       memset ( &name, 0, sizeof ( name ) );
+       len = dns_encode ( test->string, &name );
+       okx ( len >= 0, file, line );
+       okx ( len == test->len, file, line );
+
+       /* Check encoded name */
+       name.data = data;
+       name.len = sizeof ( data );
+       len = dns_encode ( test->string, &name );
+       okx ( len >= 0, file, line );
+       if ( len >= 0 ) {
+               okx ( len == test->len, file, line );
+               okx ( memcmp ( data, test->data, test->len ) == 0, file, line );
+               DBGC ( test, "DNS encoded \"%s\" to:\n", test->string );
+               DBGC_HDA ( test, 0, data, len );
+       }
+}
+#define dns_encode_ok( test ) dns_encode_okx ( test, __FILE__, __LINE__ )
+
+/**
+ * Report DNS encoding failure test result
+ *
+ * @v test             DNS encoding test
+ * @v file             Test code file
+ * @v line             Test code line
+ */
+static void dns_encode_fail_okx ( struct dns_encode_test *test,
+                                 const char *file, unsigned int line ) {
+       struct dns_name name = { .data = NULL, .len = 0 };
+       int len;
+
+       len = dns_encode ( test->string, &name );
+       okx ( len < 0, file, line );
+}
+#define dns_encode_fail_ok( test ) \
+       dns_encode_fail_okx ( test, __FILE__, __LINE__ )
+
+/** A DNS decoding test */
+struct dns_decode_test {
+       /** Name */
+       struct dns_name name;
+       /** Expected string */
+       const char *string;
+};
+
+/**
+ * Define a DNS decoding test
+ *
+ * @v _name            Test name
+ * @v _data            RFC1035-encoded data
+ * @v _offset          Starting offset within encoded data
+ * @v _string          Expected decoded string
+ * @ret test           DNS decoding test
+ */
+#define DNS_DECODE( _name, _data, _offset, _string )                   \
+       static uint8_t _name ## __data[] = _data;                       \
+       static struct dns_decode_test _name = {                         \
+               .name = {                                               \
+                       .data = _name ## __data,                        \
+                       .offset = _offset,                              \
+                       .len = sizeof ( _name ## __data ),              \
+               },                                                      \
+               .string = _string,                                      \
+       }
+
+/**
+ * Report DNS decoding test result
+ *
+ * @v test             DNS decoding test
+ * @v file             Test code file
+ * @v line             Test code line
+ */
+static void dns_decode_okx ( struct dns_decode_test *test, const char *file,
+                            unsigned int line ) {
+       char string[ strlen ( test->string ) + 1 /* NUL */ ];
+       int len;
+
+       /* Check ability to determine length with no buffer */
+       len = dns_decode ( &test->name, NULL, 0 );
+       okx ( len >= 0, file, line );
+       okx ( len == ( ( int ) strlen ( test->string ) ), file, line );
+
+       /* Check decoded string */
+       len = dns_decode ( &test->name, string, sizeof ( string ) );
+       okx ( len >= 0, file, line );
+       if ( len >= 0 ) {
+               okx ( strcmp ( string, test->string ) == 0, file, line );
+               DBGC ( test, "DNS decoded \"%s\" from offset %#zx in:\n",
+                      string, test->name.offset );
+               DBGC_HDA ( test, 0, test->name.data, test->name.len );
+       }
+}
+#define dns_decode_ok( test ) dns_decode_okx ( test, __FILE__, __LINE__ )
+
+/**
+ * Report DNS decoding failure test result
+ *
+ * @v test             DNS decoding test
+ * @v file             Test code file
+ * @v line             Test code line
+ */
+static void dns_decode_fail_okx ( struct dns_decode_test *test,
+                                 const char *file, unsigned int line ) {
+       int len;
+
+       len = dns_decode ( &test->name, NULL, 0 );
+       okx ( len < 0, file, line );
+}
+#define dns_decode_fail_ok( test ) \
+       dns_decode_fail_okx ( test, __FILE__, __LINE__ )
+
+/** A DNS comparison test */
+struct dns_compare_test {
+       /** First name */
+       struct dns_name first;
+       /** Second name */
+       struct dns_name second;
+};
+
+/**
+ * Define a DNS comparison test
+ *
+ * @v _name            Test name
+ * @v _first_data      First RFC1035-encoded data
+ * @v _first_offset    Starting offset within first encoded data
+ * @v _second_data     Second RFC1035-encoded data
+ * @v _second_offset   Starting offset within second encoded data
+ * @ret test           DNS comparison test
+ */
+#define DNS_COMPARE( _name, _first_data, _first_offset, _second_data,  \
+                    _second_offset )                                   \
+       static uint8_t _name ## __first_data[] = _first_data;           \
+       static uint8_t _name ## __second_data[] = _second_data;         \
+       static struct dns_compare_test _name = {                        \
+               .first = {                                              \
+                       .data = _name ## __first_data,                  \
+                       .offset = _first_offset,                        \
+                       .len = sizeof ( _name ## __first_data ),        \
+               },                                                      \
+               .second = {                                             \
+                       .data = _name ## __second_data,                 \
+                       .offset = _second_offset,                       \
+                       .len = sizeof ( _name ## __second_data ),       \
+               },                                                      \
+       }
+
+/**
+ * Report DNS comparison test result
+ *
+ * @v test             DNS comparison test
+ * @v file             Test code file
+ * @v line             Test code line
+ */
+static void dns_compare_okx ( struct dns_compare_test *test, const char *file,
+                             unsigned int line ) {
+
+       okx ( dns_compare ( &test->first, &test->second ) == 0, file, line );
+}
+#define dns_compare_ok( test ) dns_compare_okx ( test, __FILE__, __LINE__ )
+
+/**
+ * Report DNS comparison test failure result
+ *
+ * @v test             DNS comparison test
+ * @v file             Test code file
+ * @v line             Test code line
+ */
+static void dns_compare_fail_okx ( struct dns_compare_test *test,
+                                  const char *file, unsigned int line ) {
+
+       okx ( dns_compare ( &test->first, &test->second ) != 0, file, line );
+}
+#define dns_compare_fail_ok( test ) \
+       dns_compare_fail_okx ( test, __FILE__, __LINE__ )
+
+/** A DNS copying test */
+struct dns_copy_test {
+       /** Source name */
+       struct dns_name src;
+       /** Expected copied name */
+       struct dns_name dst;
+};
+
+/**
+ * Define a DNS copying test
+ *
+ * @v _name            Test name
+ * @v _src_data                Source RFC1035-encoded data
+ * @v _src_offset      Starting offset within source encoded data
+ * @v _dst_data                Expected copied RFC1035-encoded data
+ * @v _dst_offset      Starting offset withint copied encoded data
+ * @ret test           DNS copying test
+ */
+#define DNS_COPY( _name, _src_data, _src_offset, _dst_data,            \
+                 _dst_offset )                                         \
+       static uint8_t _name ## __src_data[] = _src_data;               \
+       static uint8_t _name ## __dst_data[] = _dst_data;               \
+       static struct dns_copy_test _name = {                           \
+               .src = {                                                \
+                       .data = _name ## __src_data,                    \
+                       .offset = _src_offset,                          \
+                       .len = sizeof ( _name ## __src_data ),          \
+               },                                                      \
+               .dst = {                                                \
+                       .data = _name ## __dst_data,                    \
+                       .offset = _dst_offset,                          \
+                       .len = sizeof ( _name ## __dst_data ),          \
+               },                                                      \
+       }
+
+/**
+ * Report a DNS copying test result
+ *
+ * @v test             DNS copying test
+ * @v file             Test code file
+ * @v line             Test code line
+ */
+static void dns_copy_okx ( struct dns_copy_test *test,
+                          const char *file, unsigned int line ) {
+       uint8_t data[ test->dst.len ];
+       struct dns_name dst;
+       int len;
+
+       /* Check ability to determine length with no buffer */
+       memset ( &dst, 0, sizeof ( dst ) );
+       len = dns_copy ( &test->src, &dst );
+       okx ( len >= 0, file, line );
+       okx ( len == ( ( int ) ( test->dst.len - test->dst.offset ) ),
+             file, line );
+
+       /* Check copied name */
+       dst.data = data;
+       dst.offset = test->dst.offset;
+       dst.len = sizeof ( data );
+       memcpy ( dst.data, test->dst.data, test->dst.offset );
+       len = dns_copy ( &test->src, &dst );
+       okx ( len >= 0, file, line );
+       okx ( len == ( ( int ) ( test->dst.len - test->dst.offset ) ),
+             file, line );
+       okx ( memcmp ( data, test->dst.data, sizeof ( data ) ) == 0,
+             file, line );
+       DBGC ( test, "DNS copied:\n" );
+       DBGC_HDA ( test, 0, test->src.data, test->src.len );
+       DBGC_HDA ( test, 0, data, ( test->dst.offset + len ) );
+}
+#define dns_copy_ok( test ) dns_copy_okx ( test, __FILE__, __LINE__ )
+
+/**
+ * Report a DNS copying failure test result
+ *
+ * @v test             DNS copying test
+ * @v file             Test code file
+ * @v line             Test code line
+ */
+static void dns_copy_fail_okx ( struct dns_copy_test *test,
+                               const char *file, unsigned int line ) {
+       struct dns_name dst;
+       int len;
+
+       memset ( &dst, 0, sizeof ( dst ) );
+       len = dns_copy ( &test->src, &dst );
+       okx ( len < 0, file, line );
+}
+#define dns_copy_fail_ok( test ) dns_copy_fail_okx ( test, __FILE__, __LINE__ )
+
+/** A DNS search list test */
+struct dns_list_test {
+       /** Search list */
+       struct dns_name list;
+       /** Expected decoded search list */
+       const char **strings;
+       /** Number of expected decoded string */
+       unsigned int count;
+};
+
+/**
+ * Define a DNS search list test
+ *
+ * @v _name            Test name
+ * @v _list            RFC1035-encoded data
+ * @v _strings         Expected decoded strings
+ * @ret test           DNS search list test
+ */
+#define DNS_LIST( _name, _list, _strings )                             \
+       static uint8_t _name ## __list[] = _list;                       \
+       static const char * _name ## __strings[] = _strings;            \
+       static struct dns_list_test _name = {                           \
+               .list = {                                               \
+                       .data = _name ## __list,                        \
+                       .offset = 0,                                    \
+                       .len = sizeof ( _name ## __list ),              \
+               },                                                      \
+               .strings = _name ## __strings,                          \
+               .count = ( sizeof ( _name ## __strings ) /              \
+                          sizeof ( _name ## __strings[0] ) ),          \
+       }
+
+/**
+ * Report DNS search list test result
+ *
+ * @v test             DNS search list test
+ * @v file             Test code file
+ * @v line             Test code line
+ */
+static void dns_list_okx ( struct dns_list_test *test, const char *file,
+                          unsigned int line ) {
+       struct dns_name name;
+       unsigned int i;
+
+       DBGC ( test, "DNS search list:\n" );
+       DBGC_HDA ( test, 0, test->list.data, test->list.len );
+       memcpy ( &name, &test->list, sizeof ( name ) );
+       for ( i = 0 ; i < test->count ; i++ ) {
+               char buf[ strlen ( test->strings[i] ) + 1 /* NUL */ ];
+               int len;
+               int offset;
+
+               /* Decode this name */
+               len = dns_decode ( &name, buf, sizeof ( buf ) );
+               okx ( len >= 0, file, line );
+               if ( len >= 0 ) {
+                       okx ( len == ( ( int ) strlen ( test->strings[i] ) ),
+                             file, line );
+                       okx ( strcmp ( buf, test->strings[i] ) == 0,
+                             file, line );
+                       DBGC ( test, "DNS search list found \"%s\" at offset "
+                              "%#zx\n", buf, name.offset );
+               }
+
+               /* Skip to next name */
+               offset = dns_skip ( &name );
+               okx ( offset >= 0, file, line );
+               name.offset = offset;
+       }
+
+       /* Check that we have consumed the whole search list */
+       okx ( name.offset == name.len, file, line );
+}
+#define dns_list_ok( test ) dns_list_okx ( test, __FILE__, __LINE__ )
+
+/* Simple encoding test */
+DNS_ENCODE ( encode_simple, "ipxe.org",
+            DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ) );
+
+/* Single-word encoding test */
+DNS_ENCODE ( encode_single, "foo", DATA ( 3, 'f', 'o', 'o', 0 ) );
+
+/* Absolute encoding test */
+DNS_ENCODE ( encode_absolute, "git.ipxe.org.",
+            DATA ( 3, 'g', 'i', 't', 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g',
+                   0 ) );
+
+/* Empty string encoding test */
+DNS_ENCODE ( encode_empty, "", DATA ( 0 ) );
+
+/* Root domain encoding test */
+DNS_ENCODE ( encode_root, ".", DATA ( 0 ) );
+
+/* Invalid initial dot encoding test */
+DNS_ENCODE ( encode_initial_dot, ".foo", DATA() );
+
+/* Invalid double dot encoding test */
+DNS_ENCODE ( encode_double_dot, "ipxe..org", DATA() );
+
+/* Invalid solo double dot encoding test */
+DNS_ENCODE ( encode_solo_double_dot, "..", DATA() );
+
+/* Invalid trailing double dot encoding test */
+DNS_ENCODE ( encode_trailing_double_dot, "ipxe.org..", DATA() );
+
+/* Invalid overlength label encoding test */
+DNS_ENCODE ( encode_overlength,
+            "this-label-is-maliciously-long-in-an-attempt-to-overflow-the-"
+            "length-field-and-generate-a-length-which-looks-like-a-"
+            "compression-pointer", DATA() );
+
+/* Simple decoding test */
+DNS_DECODE ( decode_simple,
+            DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
+            "ipxe.org" );
+
+/* Compression pointer decoding test */
+DNS_DECODE ( decode_ptr,
+            DATA ( 3, 'o', 'r', 'g', 0, 3, 'g', 'i', 't', 4, 'i', 'p', 'x',
+                   'e', 0xc0, 0x00 ), 5,
+            "git.ipxe.org" );
+
+/* Root decoding test */
+DNS_DECODE ( decode_root,
+            DATA ( 0 ), 0, "" );
+
+/* Incomplete name decoding test */
+DNS_DECODE ( decode_incomplete_name,
+            DATA ( 4, 'i', 'p', 'x', 'e' ), 0, NULL );
+
+/* Incomplete label decoding test */
+DNS_DECODE ( decode_incomplete_label,
+            DATA ( 4, 'i', 'p', 'x' ), 0, NULL );
+
+/* Incomplete compression pointer decoding test */
+DNS_DECODE ( decode_incomplete_ptr,
+            DATA ( 3, 'o', 'r', 'g', 0, 4, 'i', 'p', 'x', 'e', 0xc0 ), 5,
+            NULL );
+
+/* Forward reference decoding test */
+DNS_DECODE ( decode_forward,
+            DATA ( 0xc0, 0x02, 3, 'f', 'o', 'o', 0 ), 0, NULL );
+
+/* Infinite loop decoding test */
+DNS_DECODE ( decode_infinite,
+            DATA ( 4, 'i', 'p', 'x', 'e', 0xc0, 0x00 ), 0, NULL );
+
+/* Empty decoding test */
+DNS_DECODE ( decode_empty,
+            DATA (), 0, NULL );
+
+/* Simple comparison test */
+DNS_COMPARE ( compare_simple,
+             DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
+             DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0 );
+
+/* Compression pointer comparison test */
+DNS_COMPARE ( compare_ptr,
+             DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
+             DATA ( 3, 'o', 'r', 'g', 0, 4, 'i', 'p', 'x', 'e',
+                    0xc0, 0x00 ), 5 );
+
+/* Case insensitive comparison test */
+DNS_COMPARE ( compare_case,
+             DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
+             DATA ( 4, 'i', 'p', 'x', 'e', 3, 'O', 'R', 'G', 0 ), 0 );
+
+/* Mismatch comparison test */
+DNS_COMPARE ( compare_mismatch,
+             DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
+             DATA ( 4, 'g', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0 );
+
+/* Infinite loop comparison test */
+DNS_COMPARE ( compare_infinite,
+             DATA ( 3, 'f', 'o', 'o', 0xc0, 0x00 ), 0,
+             DATA ( 3, 'f', 'o', 'o', 0xc0, 0x00 ), 0 );
+
+/* Simple copying test */
+DNS_COPY ( copy_simple,
+          DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
+          DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0 );
+
+/* Simple copying test with offset */
+DNS_COPY ( copy_offset,
+          DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0 ), 0,
+          DATA ( 'f', 'o', 'o', 0, 4, 'i', 'p', 'x', 'e',
+                 3, 'o', 'r', 'g', 0 ), 4 );
+
+/* Compression pointer copying test */
+DNS_COPY ( copy_ptr,
+          DATA ( 3, 'o', 'r', 'g', 0, 3, 'g', 'i', 't', 4, 'i', 'p', 'x', 'e',
+                 0xc0, 0x00 ), 5,
+          DATA ( 3, 'g', 'i', 't', 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g',
+                 0 ), 0 );
+
+/* Infinite loop copying test */
+DNS_COPY ( copy_infinite,
+          DATA ( 4, 'l', 'o', 'o', 'p', 7, 'f', 'o', 'r', 'e', 'v', 'e', 'r',
+                 0xc0, 0x05 ), 0,
+          DATA (), 0 );
+
+/* DNS search list test */
+DNS_LIST ( search,
+          DATA ( 4, 'i', 'p', 'x', 'e', 3, 'o', 'r', 'g', 0,
+                 4, 'b', 'o', 'o', 't', 0xc0, 0x00,
+                 3, 'd', 'e', 'v', 0xc0, 0x0a,
+                 11, 'n', 'e', 't', 'w', 'o', 'r', 'k', 'b', 'o', 'o', 't',
+                 0xc0, 0x05 ),
+          DATA ( "ipxe.org", "boot.ipxe.org", "dev.boot.ipxe.org",
+                 "networkboot.org" ) );
+
+/**
+ * Perform DNS self-test
+ *
+ */
+static void dns_test_exec ( void ) {
+
+       /* Encoding tests */
+       dns_encode_ok ( &encode_simple );
+       dns_encode_ok ( &encode_single );
+       dns_encode_ok ( &encode_absolute );
+       dns_encode_ok ( &encode_empty );
+       dns_encode_ok ( &encode_root );
+       dns_encode_fail_ok ( &encode_initial_dot );
+       dns_encode_fail_ok ( &encode_double_dot );
+       dns_encode_fail_ok ( &encode_solo_double_dot );
+       dns_encode_fail_ok ( &encode_trailing_double_dot );
+       dns_encode_fail_ok ( &encode_overlength );
+
+       /* Decoding tests */
+       dns_decode_ok ( &decode_simple );
+       dns_decode_ok ( &decode_ptr );
+       dns_decode_ok ( &decode_root );
+       dns_decode_fail_ok ( &decode_incomplete_name );
+       dns_decode_fail_ok ( &decode_incomplete_label );
+       dns_decode_fail_ok ( &decode_incomplete_ptr );
+       dns_decode_fail_ok ( &decode_forward );
+       dns_decode_fail_ok ( &decode_infinite );
+       dns_decode_fail_ok ( &decode_empty );
+
+       /* Comparison tests */
+       dns_compare_ok ( &compare_simple );
+       dns_compare_ok ( &compare_ptr );
+       dns_compare_ok ( &compare_case );
+       dns_compare_fail_ok ( &compare_mismatch );
+       dns_compare_fail_ok ( &compare_infinite );
+
+       /* Copying tests */
+       dns_copy_ok ( &copy_simple );
+       dns_copy_ok ( &copy_offset );
+       dns_copy_ok ( &copy_ptr );
+       dns_copy_fail_ok ( &copy_infinite );
+
+       /* Search list tets */
+       dns_list_ok ( &search );
+}
+
+/** DNS self-test */
+struct self_test dns_test __self_test = {
+       .name = "dns",
+       .exec = dns_test_exec,
+};