Add support for the URI DNS Resource Record type
[resolv_wrapper.git] / tests / test_dns_fake.c
index b890060e902332502904635afbd7056a25f259b3..0702dc8f2267744a515ea979b39afeac0dc73ad6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) Jakub Hrozek 2014 <jakub.hrozek@gmail.com>
+ * Copyright (C) Jakub Hrozek 2014 <jakub.hrozek@posteo.se>
  *
  * All rights reserved.
  *
@@ -49,6 +49,7 @@
 #include <resolv.h>
 
 #define ANSIZE 256
+#define ns_t_uri 256
 
 static void test_res_fake_a_query(void **state)
 {
@@ -67,7 +68,7 @@ static void test_res_fake_a_query(void **state)
 
        rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_a,
                        answer, sizeof(answer));
-       assert_int_not_equal(rv, -1);
+       assert_in_range(rv, 1, 100);
 
        ns_initparse(answer, sizeof(answer), &handle);
        /* The query must finish w/o an error, have one answer and the answer
@@ -100,7 +101,7 @@ static void test_res_fake_a_query_case_insensitive(void **state)
 
        rv = res_nquery(&dnsstate, "CWRAP.ORG", ns_c_in, ns_t_a,
                        answer, sizeof(answer));
-       assert_int_not_equal(rv, -1);
+       assert_in_range(rv, 1, 100);
 
        ns_initparse(answer, sizeof(answer), &handle);
        /* The query must finish w/o an error, have one answer and the answer
@@ -118,6 +119,40 @@ static void test_res_fake_a_query_case_insensitive(void **state)
        res_nclose(&dnsstate);
 }
 
+static void test_res_fake_a_query_trailing_dot(void **state)
+{
+       int rv;
+       struct __res_state dnsstate;
+       unsigned char answer[ANSIZE];
+       char addr[INET_ADDRSTRLEN];
+       ns_msg handle;
+       ns_rr rr;   /* expanded resource record */
+
+       (void) state; /* unused */
+
+       memset(&dnsstate, 0, sizeof(struct __res_state));
+       rv = res_ninit(&dnsstate);
+       assert_int_equal(rv, 0);
+
+       rv = res_nquery(&dnsstate, "cwrap.org.", ns_c_in, ns_t_a,
+                       answer, ANSIZE);
+       assert_in_range(rv, 1, 100);
+
+       ns_initparse(answer, 256, &handle);
+       /* The query must finish w/o an error, have one answer and the answer
+        * must be a parseable RR of type A and have the address that our
+        * fake hosts file contains
+        */
+       assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
+       assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
+       assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
+       assert_int_equal(ns_rr_type(rr), ns_t_a);
+       assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, 256));
+       assert_string_equal(addr, "127.0.0.21");
+
+       res_nclose(&dnsstate);
+}
+
 static void test_res_fake_a_query_notfound(void **state)
 {
        int rv;
@@ -133,7 +168,7 @@ static void test_res_fake_a_query_notfound(void **state)
 
        rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_a,
                        answer, sizeof(answer));
-       assert_int_not_equal(rv, -1);
+       assert_in_range(rv, 1, 100);
 
        ns_initparse(answer, sizeof(answer), &handle);
        /* The query must finish w/o an error and have no answer */
@@ -158,7 +193,7 @@ static void test_res_fake_aaaa_query(void **state)
 
        rv = res_nquery(&dnsstate, "cwrap6.org", ns_c_in, ns_t_aaaa,
                        answer, sizeof(answer));
-       assert_int_not_equal(rv, -1);
+       assert_in_range(rv, 1, 100);
 
        ns_initparse(answer, sizeof(answer), &handle);
        /* The query must finish w/o an error, have one answer and the answer
@@ -189,7 +224,7 @@ static void test_res_fake_aaaa_query_notfound(void **state)
 
        rv = res_nquery(&dnsstate, "nosuchentry.org", ns_c_in, ns_t_aaaa,
                        answer, sizeof(answer));
-       assert_int_not_equal(rv, -1);
+       assert_in_range(rv, 1, 100);
 
        ns_initparse(answer, sizeof(answer), &handle);
        /* The query must finish w/o an error and have no answer */
@@ -218,7 +253,7 @@ static void test_res_fake_srv_query(void **state)
 
        rv = res_nquery(&dnsstate, "_ldap._tcp.cwrap.org", ns_c_in, ns_t_srv,
                        answer, sizeof(answer));
-       assert_int_not_equal(rv, -1);
+       assert_in_range(rv, 1, 100);
 
        ns_initparse(answer, sizeof(answer), &handle);
 
@@ -267,6 +302,7 @@ static void test_res_fake_srv_query_minimal(void **state)
        int weight;
        int port;
        char hostname[MAXDNAME];
+       char addr[INET_ADDRSTRLEN];
 
        (void) state; /* unused */
 
@@ -276,7 +312,7 @@ static void test_res_fake_srv_query_minimal(void **state)
 
        rv = res_nquery(&dnsstate, "_krb5._tcp.cwrap.org", ns_c_in, ns_t_srv,
                        answer, sizeof(answer));
-       assert_int_not_equal(rv, -1);
+       assert_in_range(rv, 1, 256);
 
        ns_initparse(answer, sizeof(answer), &handle);
 
@@ -305,6 +341,119 @@ static void test_res_fake_srv_query_minimal(void **state)
        assert_int_equal(weight, 100);
        assert_int_equal(port, 88);
        assert_string_equal(hostname, "krb5.cwrap.org");
+
+       /* The additional section contains the A record of krb5.cwrap.org */
+       assert_int_equal(ns_msg_count(handle, ns_s_ar), 1);
+       assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0);
+       assert_int_equal(ns_rr_type(rr), ns_t_a);
+       assert_string_equal(ns_rr_name(rr), "krb5.cwrap.org");
+       assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
+                       addr, sizeof(addr)));
+       assert_string_equal(addr, "127.0.0.23");
+}
+
+static void test_res_fake_uri_query(void **state)
+{
+       int rv;
+       struct __res_state dnsstate;
+       unsigned char answer[ANSIZE];
+       ns_msg handle;
+       ns_rr rr;   /* expanded resource record */
+       const uint8_t *rrdata;
+       int prio;
+       int weight;
+       char uri[MAXDNAME];
+
+       (void) state; /* unused */
+
+       memset(&dnsstate, 0, sizeof(struct __res_state));
+       rv = res_ninit(&dnsstate);
+       assert_int_equal(rv, 0);
+
+       rv = res_nquery(&dnsstate, "_vpn.cwrap.org", ns_c_in, ns_t_uri,
+                       answer, sizeof(answer));
+       assert_in_range(rv, 1, 100);
+
+       ns_initparse(answer, sizeof(answer), &handle);
+
+       /*
+        * The query must finish w/o an error, have one answer and the answer
+        * must be a parseable RR of type SRV and have the priority, weight,
+        * port and hostname as in the fake hosts file
+        */
+       assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
+       assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
+       assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
+       assert_int_equal(ns_rr_type(rr), ns_t_uri);
+
+       rrdata = ns_rr_rdata(rr);
+       NS_GET16(prio, rrdata);
+       NS_GET16(weight, rrdata);
+
+       rv = ns_name_uncompress(ns_msg_base(handle),
+                               ns_msg_end(handle),
+                               rrdata,
+                               uri, MAXDNAME);
+       assert_int_not_equal(rv, -1);
+
+       assert_int_equal(prio, 2);
+       assert_int_equal(weight, 5);
+       assert_string_equal(uri, "https://vpn.cwrap.org/VPN");
+}
+
+/*
+ * Test the case of a URI record query where the
+ * fake hosts file entry is minimal in the sense
+ * that it omits the priority and weight entries.
+ * The server then fills in some default values.
+ */
+static void test_res_fake_uri_query_minimal(void **state)
+{
+       int rv;
+       struct __res_state dnsstate;
+       unsigned char answer[ANSIZE];
+       ns_msg handle;
+       ns_rr rr;   /* expanded resource record */
+       const uint8_t *rrdata;
+       int prio;
+       int weight;
+       char uri[MAXDNAME];
+
+       (void) state; /* unused */
+
+       memset(&dnsstate, 0, sizeof(struct __res_state));
+       rv = res_ninit(&dnsstate);
+       assert_int_equal(rv, 0);
+
+       rv = res_nquery(&dnsstate, "_ftp.cwrap.org", ns_c_in, ns_t_uri,
+                       answer, sizeof(answer));
+       assert_in_range(rv, 1, 256);
+
+       ns_initparse(answer, sizeof(answer), &handle);
+
+       /*
+        * The query must finish w/o an error, have one answer and the answer
+        * must be a parseable RR of type SRV and have the priority, weight,
+        * port and hostname as in the fake hosts file
+        */
+       assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
+       assert_int_equal(ns_msg_count(handle, ns_s_an), 1);
+       assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
+       assert_int_equal(ns_rr_type(rr), ns_t_uri);
+
+       rrdata = ns_rr_rdata(rr);
+       NS_GET16(prio, rrdata);
+       NS_GET16(weight, rrdata);
+
+       rv = ns_name_uncompress(ns_msg_base(handle),
+                               ns_msg_end(handle),
+                               rrdata,
+                               uri, MAXDNAME);
+       assert_int_not_equal(rv, -1);
+
+       assert_int_equal(prio, 1);
+       assert_int_equal(weight, 100);
+       assert_string_equal(uri, "ftp://ftp.cwrap.org/public");
 }
 
 static void test_res_fake_soa_query(void **state)
@@ -331,7 +480,7 @@ static void test_res_fake_soa_query(void **state)
 
        rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_soa,
                        answer, sizeof(answer));
-       assert_int_not_equal(rv, -1);
+       assert_in_range(rv, 1, 100);
 
        ns_initparse(answer, sizeof(answer), &handle);
 
@@ -385,6 +534,7 @@ static void test_res_fake_cname_query(void **state)
        ns_rr rr;   /* expanded resource record */
        const uint8_t *rrdata;
        char cname[MAXDNAME];
+       char addr[INET_ADDRSTRLEN];
 
        (void) state; /* unused */
 
@@ -392,9 +542,9 @@ static void test_res_fake_cname_query(void **state)
        rv = res_ninit(&dnsstate);
        assert_int_equal(rv, 0);
 
-       rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_cname,
+       rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_cname,
                        answer, sizeof(answer));
-       assert_int_not_equal(rv, -1);
+       assert_in_range(rv, 1, 256);
 
        ns_initparse(answer, 256, &handle);
        ns_initparse(answer, sizeof(answer), &handle);
@@ -417,26 +567,124 @@ static void test_res_fake_cname_query(void **state)
                                cname, MAXDNAME);
        assert_int_not_equal(rv, -1);
 
-       assert_string_equal(cname, "therealcwrap.org");
+       assert_string_equal(cname, "web.cwrap.org");
+
+       /* The CNAME points to an A record that's present in the additional
+        * section
+        */
+       assert_int_equal(ns_msg_count(handle, ns_s_ar), 2);
+
+       assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0);
+       assert_int_equal(ns_rr_type(rr), ns_t_cname);
+       assert_string_equal(ns_rr_name(rr), "web.cwrap.org");
+       rrdata = ns_rr_rdata(rr);
+
+       rv = ns_name_uncompress(ns_msg_base(handle),
+                               ns_msg_end(handle),
+                               rrdata,
+                               cname, MAXDNAME);
+       assert_int_not_equal(rv, -1);
+
+       assert_string_equal(cname, "www.cwrap.org");
+
+       assert_int_equal(ns_parserr(&handle, ns_s_ar, 1, &rr), 0);
+       assert_int_equal(ns_rr_type(rr), ns_t_a);
+       assert_string_equal(ns_rr_name(rr), "www.cwrap.org");
+       assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
+                       addr, sizeof(addr)));
+       assert_string_equal(addr, "127.0.0.22");
+}
+
+static void test_res_fake_a_via_cname(void **state)
+{
+       int rv;
+       struct __res_state dnsstate;
+       unsigned char answer[ANSIZE];
+       ns_msg handle;
+       ns_rr rr;   /* expanded resource record */
+       const uint8_t *rrdata;
+       char cname[MAXDNAME];
+       char addr[INET_ADDRSTRLEN];
+
+       (void) state; /* unused */
+
+       memset(&dnsstate, 0, sizeof(struct __res_state));
+       rv = res_ninit(&dnsstate);
+       assert_int_equal(rv, 0);
+
+       /* Query for A record, but the key is a CNAME. The expected result is
+        * that the whole chain of CNAMEs will be included in the answer section
+        * along with the resulting A
+        */
+       rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_a,
+                       answer, sizeof(answer));
+       assert_in_range(rv, 1, 256);
+
+       ns_initparse(answer, sizeof(answer), &handle);
+
+       /*
+        * The query must finish w/o an error, have three answers and the answers
+        * must be a parseable RR of type CNAME and have the cname as in the
+        * fake hosts file
+        */
+       assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror);
+       assert_int_equal(ns_msg_count(handle, ns_s_an), 3);
+
+       assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0);
+       assert_int_equal(ns_rr_type(rr), ns_t_cname);
+
+       rrdata = ns_rr_rdata(rr);
+
+       rv = ns_name_uncompress(ns_msg_base(handle),
+                               ns_msg_end(handle),
+                               rrdata,
+                               cname, MAXDNAME);
+       assert_int_not_equal(rv, -1);
+
+       assert_string_equal(cname, "web.cwrap.org");
+
+       assert_int_equal(ns_parserr(&handle, ns_s_an, 1, &rr), 0);
+       assert_int_equal(ns_rr_type(rr), ns_t_cname);
+
+       rrdata = ns_rr_rdata(rr);
+
+       rv = ns_name_uncompress(ns_msg_base(handle),
+                               ns_msg_end(handle),
+                               rrdata,
+                               cname, MAXDNAME);
+       assert_int_not_equal(rv, -1);
+
+       assert_string_equal(cname, "www.cwrap.org");
+
+       assert_int_equal(ns_parserr(&handle, ns_s_an, 2, &rr), 0);
+       assert_int_equal(ns_rr_type(rr), ns_t_a);
+       assert_string_equal(ns_rr_name(rr), "www.cwrap.org");
+       assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr),
+                       addr, sizeof(addr)));
+       assert_string_equal(addr, "127.0.0.22");
 }
 
 int main(void)
 {
        int rc;
 
-       const UnitTest tests[] = {
-               unit_test(test_res_fake_a_query),
-               unit_test(test_res_fake_a_query_case_insensitive),
-               unit_test(test_res_fake_a_query_notfound),
-               unit_test(test_res_fake_aaaa_query),
-               unit_test(test_res_fake_aaaa_query_notfound),
-               unit_test(test_res_fake_srv_query),
-               unit_test(test_res_fake_srv_query_minimal),
-               unit_test(test_res_fake_soa_query),
-               unit_test(test_res_fake_cname_query),
+       const struct CMUnitTest fake_tests[] = {
+               cmocka_unit_test(test_res_fake_a_query),
+               cmocka_unit_test(test_res_fake_a_query_case_insensitive),
+               cmocka_unit_test(test_res_fake_a_query_trailing_dot),
+               cmocka_unit_test(test_res_fake_a_query_notfound),
+               cmocka_unit_test(test_res_fake_aaaa_query),
+               cmocka_unit_test(test_res_fake_aaaa_query_notfound),
+               cmocka_unit_test(test_res_fake_srv_query),
+               cmocka_unit_test(test_res_fake_srv_query_minimal),
+               cmocka_unit_test(test_res_fake_uri_query),
+               cmocka_unit_test(test_res_fake_uri_query_minimal),
+               cmocka_unit_test(test_res_fake_soa_query),
+               cmocka_unit_test(test_res_fake_cname_query),
+               cmocka_unit_test(test_res_fake_a_via_cname),
        };
 
-       rc = run_tests(tests);
+       rc = cmocka_run_group_tests(fake_tests, NULL, NULL);
 
        return rc;
 }