aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathaniel McCallum <npmccallum@redhat.com>2016-08-16 17:38:32 -0400
committerAndreas Schneider <asn@samba.org>2016-08-18 07:53:19 +0200
commit02535da4b92bfafbd671cb52c3a86d38572b2066 (patch)
treec80af349dc6688927d8772daa9395295324674d4
parent49ef1b11fbf4c361b3af64787b2a93c0713cf7ef (diff)
downloadresolv_wrapper-02535da4b92bfafbd671cb52c3a86d38572b2066.tar.gz
resolv_wrapper-02535da4b92bfafbd671cb52c3a86d38572b2066.tar.xz
resolv_wrapper-02535da4b92bfafbd671cb52c3a86d38572b2066.zip
Add support for the URI DNS Resource Record type
For more information, see RFC 7553. Signed-off-by: Nathaniel McCallum <npmccallum@redhat.com> Reviewed-by: Jakub Hrozek <jakub.hrozek@posteo.se> Reviewed-by: Alexander Bokovoy <ab@samba.org> Reviewed-by: Andreas Schneider <asn@samba.org>
-rw-r--r--doc/resolv_wrapper.11
-rw-r--r--doc/resolv_wrapper.1.txt1
-rw-r--r--src/resolv_wrapper.c95
-rw-r--r--tests/fake_hosts.in2
-rw-r--r--tests/test_dns_fake.c107
5 files changed, 206 insertions, 0 deletions
diff --git a/doc/resolv_wrapper.1 b/doc/resolv_wrapper.1
index 5219713..fccdc5a 100644
--- a/doc/resolv_wrapper.1
+++ b/doc/resolv_wrapper.1
@@ -92,6 +92,7 @@ A dc\&.cwrap\&.org 127\&.0\&.0\&.10
AAAA dc\&.cwrap\&.org fd00::5357:5f0a
CNAME kerberos\&.cwrap\&.org dc\&.cwrap\&.org
SRV _kerberos\&._tcp\&.cwrap\&.org kerberos\&.cwrap\&.org 88
+URI _vpn\&.cwrap\&.org https://vpn\&.cwrap\&.org/VPN
.fi
.if n \{\
.RE
diff --git a/doc/resolv_wrapper.1.txt b/doc/resolv_wrapper.1.txt
index 12f96d0..63e40d4 100644
--- a/doc/resolv_wrapper.1.txt
+++ b/doc/resolv_wrapper.1.txt
@@ -47,6 +47,7 @@ For example:
AAAA dc.cwrap.org fd00::5357:5f0a
CNAME kerberos.cwrap.org dc.cwrap.org
SRV _kerberos._tcp.cwrap.org kerberos.cwrap.org 88
+ URI _vpn.cwrap.org https://vpn.cwrap.org/VPN
*RESOLV_WRAPPER_DEBUGLEVEL*::
diff --git a/src/resolv_wrapper.c b/src/resolv_wrapper.c
index 48018be..a07086a 100644
--- a/src/resolv_wrapper.c
+++ b/src/resolv_wrapper.c
@@ -73,6 +73,8 @@
#define ns_name_compress dn_comp
#endif
+#define ns_t_uri 256
+
enum rwrap_dbglvl_e {
RWRAP_LOG_ERROR = 0,
RWRAP_LOG_WARN,
@@ -156,6 +158,8 @@ static void rwrap_log(enum rwrap_dbglvl_e dbglvl,
*/
#define DFL_SRV_PRIO 1
#define DFL_SRV_WEIGHT 100
+#define DFL_URI_PRIO 1
+#define DFL_URI_WEIGHT 100
struct rwrap_srv_rrdata {
uint16_t port;
@@ -164,6 +168,12 @@ struct rwrap_srv_rrdata {
char hostname[MAXDNAME];
};
+struct rwrap_uri_rrdata {
+ uint16_t prio;
+ uint16_t weight;
+ char uri[MAXDNAME];
+};
+
struct rwrap_soa_rrdata {
uint32_t serial;
uint32_t refresh;
@@ -179,6 +189,7 @@ struct rwrap_fake_rr {
struct in_addr a_rec;
struct in6_addr aaaa_rec;
struct rwrap_srv_rrdata srv_rec;
+ struct rwrap_uri_rrdata uri_rec;
struct rwrap_soa_rrdata soa_rec;
char cname_rec[MAXDNAME];
} rrdata;
@@ -280,6 +291,42 @@ static int rwrap_create_fake_srv_rr(const char *key,
return 0;
}
+static int rwrap_create_fake_uri_rr(const char *key,
+ const char *value,
+ struct rwrap_fake_rr *rr)
+{
+ char *str_prio;
+ char *str_weight;
+ const char *uri;
+
+ /* parse the value into priority, weight, and uri
+ * and check the validity */
+ uri = value;
+ NEXT_KEY(uri, str_prio);
+ NEXT_KEY(str_prio, str_weight);
+ if (uri == NULL) {
+ RWRAP_LOG(RWRAP_LOG_ERROR,
+ "Malformed URI entry [%s]\n", value);
+ return -1;
+ }
+
+ if (str_prio) {
+ rr->rrdata.uri_rec.prio = atoi(str_prio);
+ } else {
+ rr->rrdata.uri_rec.prio = DFL_URI_PRIO;
+ }
+ if (str_weight) {
+ rr->rrdata.uri_rec.weight = atoi(str_weight);
+ } else {
+ rr->rrdata.uri_rec.weight = DFL_URI_WEIGHT;
+ }
+ memcpy(rr->rrdata.uri_rec.uri, uri, strlen(uri) + 1);
+
+ memcpy(rr->key, key, strlen(key) + 1);
+ rr->type = ns_t_uri;
+ return 0;
+}
+
static int rwrap_create_fake_soa_rr(const char *key,
const char *value,
struct rwrap_fake_rr *rr)
@@ -564,6 +611,46 @@ static ssize_t rwrap_fake_srv(struct rwrap_fake_rr *rr,
return resp_size;
}
+static ssize_t rwrap_fake_uri(struct rwrap_fake_rr *rr,
+ uint8_t *answer,
+ size_t anslen)
+{
+ uint8_t *a = answer;
+ ssize_t resp_size;
+ size_t rdata_size;
+ unsigned char uri_compressed[MAXDNAME];
+ ssize_t compressed_len;
+
+ if (rr == NULL || rr->type != ns_t_uri) {
+ RWRAP_LOG(RWRAP_LOG_ERROR,
+ "Malformed record, no or wrong value!\n");
+ return -1;
+ }
+ RWRAP_LOG(RWRAP_LOG_TRACE, "Adding URI RR");
+ rdata_size = 3 * sizeof(uint16_t);
+
+ /* Prepare the data to write */
+ compressed_len = ns_name_compress(rr->rrdata.uri_rec.uri,
+ uri_compressed, MAXDNAME,
+ NULL, NULL);
+ if (compressed_len < 0) {
+ return -1;
+ }
+ rdata_size += compressed_len;
+
+ resp_size = rwrap_fake_rdata_common(ns_t_uri, rdata_size,
+ rr->key, anslen, &a);
+ if (resp_size < 0) {
+ return -1;
+ }
+
+ NS_PUT16(rr->rrdata.uri_rec.prio, a);
+ NS_PUT16(rr->rrdata.uri_rec.weight, a);
+ memcpy(a, uri_compressed, compressed_len);
+
+ return resp_size;
+}
+
static ssize_t rwrap_fake_soa(struct rwrap_fake_rr *rr,
uint8_t *answer,
size_t anslen)
@@ -770,6 +857,10 @@ static int rwrap_get_record(const char *hostfile, unsigned recursion,
rr + 1);
}
break;
+ } else if (TYPE_MATCH(type, ns_t_uri,
+ rec_type, "URI", key, query)) {
+ rc = rwrap_create_fake_uri_rr(key, value, rr);
+ break;
} else if (TYPE_MATCH(type, ns_t_soa,
rec_type, "SOA", key, query)) {
rc = rwrap_create_fake_soa_rr(key, value, rr);
@@ -837,6 +928,7 @@ static inline bool rwrap_known_type(int type)
case ns_t_aaaa:
case ns_t_ns:
case ns_t_srv:
+ case ns_t_uri:
case ns_t_soa:
case ns_t_cname:
return true;
@@ -901,6 +993,9 @@ static ssize_t rwrap_add_rr(struct rwrap_fake_rr *rr,
case ns_t_srv:
resp_data = rwrap_fake_srv(rr, answer, anslen);
break;
+ case ns_t_uri:
+ resp_data = rwrap_fake_uri(rr, answer, anslen);
+ break;
case ns_t_soa:
resp_data = rwrap_fake_soa(rr, answer, anslen);
break;
diff --git a/tests/fake_hosts.in b/tests/fake_hosts.in
index 19f7551..d7bf9a2 100644
--- a/tests/fake_hosts.in
+++ b/tests/fake_hosts.in
@@ -12,3 +12,5 @@ A www.cwrap.org 127.0.0.22
A krb5.cwrap.org 127.0.0.23
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
diff --git a/tests/test_dns_fake.c b/tests/test_dns_fake.c
index 8d1dd0c..0702dc8 100644
--- a/tests/test_dns_fake.c
+++ b/tests/test_dns_fake.c
@@ -49,6 +49,7 @@
#include <resolv.h>
#define ANSIZE 256
+#define ns_t_uri 256
static void test_res_fake_a_query(void **state)
{
@@ -351,6 +352,110 @@ static void test_res_fake_srv_query_minimal(void **state)
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)
{
int rv;
@@ -572,6 +677,8 @@ int main(void)
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),