Add support for the PTR DNS Resource Record type
authorJakub Hrozek <jakub.hrozek@posteo.se>
Thu, 18 Aug 2016 15:49:00 +0000 (17:49 +0200)
committerMichael Adam <obnox@samba.org>
Mon, 29 Aug 2016 06:17:23 +0000 (08:17 +0200)
Signed-off-by: Jakub Hrozek <jakub.hrozek@posteo.se>
Reviewed-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
src/resolv_wrapper.c
tests/fake_hosts.in
tests/test_dns_fake.c

index a2625610e23f54a75ea78b718fc1f5e7ddb25912..455a0afefab081d4dfdf60324517701c91b902fd 100644 (file)
@@ -192,6 +192,7 @@ struct rwrap_fake_rr {
                struct rwrap_uri_rrdata uri_rec;
                struct rwrap_soa_rrdata soa_rec;
                char cname_rec[MAXDNAME];
+               char ptr_rec[MAXDNAME];
        } rrdata;
 
        char key[MAXDNAME];
@@ -381,6 +382,16 @@ static int rwrap_create_fake_cname_rr(const char *key,
        return 0;
 }
 
+static int rwrap_create_fake_ptr_rr(const char *key,
+                                   const char *value,
+                                   struct rwrap_fake_rr *rr)
+{
+       memcpy(rr->rrdata.ptr_rec , value, strlen(value) + 1);
+       memcpy(rr->key, key, strlen(key) + 1);
+       rr->type = ns_t_ptr;
+       return 0;
+}
+
 /* Prepares a fake header with a single response. Advances header_blob */
 static ssize_t rwrap_fake_header(uint8_t **header_blob, size_t remaining,
                                 size_t ancount, size_t arcount)
@@ -734,6 +745,40 @@ static ssize_t rwrap_fake_cname(struct rwrap_fake_rr *rr,
        return resp_size;
 }
 
+static ssize_t rwrap_fake_ptr(struct rwrap_fake_rr *rr,
+                             uint8_t *answer,
+                             size_t anslen)
+{
+       uint8_t *a = answer;
+       ssize_t rdata_size;
+       ssize_t resp_size;
+       unsigned char hostname_compressed[MAXDNAME];
+
+       if (rr->type != ns_t_ptr) {
+               RWRAP_LOG(RWRAP_LOG_ERROR, "Wrong type!\n");
+               return -1;
+       }
+       RWRAP_LOG(RWRAP_LOG_TRACE, "Adding PTR RR");
+
+       /* Prepare the data to write */
+       rdata_size = ns_name_compress(rr->rrdata.ptr_rec,
+                                     hostname_compressed, MAXDNAME,
+                                     NULL, NULL);
+       if (rdata_size < 0) {
+               return -1;
+       }
+
+       resp_size = rwrap_fake_rdata_common(ns_t_ptr, rdata_size,
+                                           rr->key, anslen, &a);
+       if (resp_size < 0) {
+               return -1;
+       }
+
+       memcpy(a, hostname_compressed, rdata_size);
+
+       return resp_size;
+}
+
 #define RESOLV_MATCH(line, name) \
        (strncmp(line, name, sizeof(name) - 1) == 0 && \
        (line[sizeof(name) - 1] == ' ' || \
@@ -873,6 +918,10 @@ static int rwrap_get_record(const char *hostfile, unsigned recursion,
                                                         value, rr + 1);
                        }
                        break;
+               } else if (TYPE_MATCH(type, ns_t_ptr,
+                                     rec_type, "PTR", key, query)) {
+                       rc = rwrap_create_fake_ptr_rr(key, value, rr);
+                       break;
                }
        }
 
@@ -924,6 +973,7 @@ static inline bool rwrap_known_type(int type)
        case ns_t_uri:
        case ns_t_soa:
        case ns_t_cname:
+       case ns_t_ptr:
                return true;
        }
 
@@ -1000,6 +1050,9 @@ static ssize_t rwrap_add_rr(struct rwrap_fake_rr *rr,
        case ns_t_cname:
                resp_data = rwrap_fake_cname(rr, answer, anslen);
                break;
+       case ns_t_ptr:
+               resp_data = rwrap_fake_ptr(rr, answer, anslen);
+               break;
        default:
                return -1;
        }
index d7bf9a27006d99a0765ad39dd86c756201ad4748..181297973c69ff9bad36963fba3fcddf8cf65c5a 100644 (file)
@@ -14,3 +14,4 @@ A ns1.cwrap.org 127.0.0.24
 A ns2.cwrap.org 127.0.0.25
 URI _vpn.cwrap.org https://vpn.cwrap.org/VPN 2 5
 URI _ftp.cwrap.org ftp://ftp.cwrap.org/public
+PTR 22.0.0.127.in-addr.arpa www.cwrap.org
index 0702dc8f2267744a515ea979b39afeac0dc73ad6..d3e9ebe6287cbaaa01ed8d9ff1dc575e912d81fc 100644 (file)
@@ -664,6 +664,49 @@ static void test_res_fake_a_via_cname(void **state)
        assert_string_equal(addr, "127.0.0.22");
 }
 
+static void test_res_fake_ptr_query(void **state)
+{
+       int rv;
+       struct __res_state dnsstate;
+       unsigned char answer[ANSIZE];
+       const uint8_t *rrdata;
+       char ptrname[MAXDNAME];
+       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, "22.0.0.127.in-addr.arpa", ns_c_in, ns_t_ptr,
+                       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 PTR and have the name 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_ptr);
+
+       rrdata = ns_rr_rdata(rr);
+
+       rv = ns_name_uncompress(ns_msg_base(handle),
+                               ns_msg_end(handle),
+                               rrdata,
+                               ptrname, MAXDNAME);
+       assert_int_not_equal(rv, -1);
+
+       assert_string_equal(ptrname, "www.cwrap.org");
+}
+
 int main(void)
 {
        int rc;
@@ -682,6 +725,7 @@ int main(void)
                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),
+               cmocka_unit_test(test_res_fake_ptr_query),
        };
 
        rc = cmocka_run_group_tests(fake_tests, NULL, NULL);