static void rwrap_log(enum rwrap_dbglvl_e dbglvl, const char *func, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
# define RWRAP_LOG(dbglvl, ...) rwrap_log((dbglvl), __func__, __VA_ARGS__)
+#define NEXT_KEY(buf, key) do { \
+ (key) = (buf) ? strpbrk((buf), " \t") : NULL; \
+ if ((key) != NULL) { \
+ (key)[0] = '\0'; \
+ (key)++; \
+ } \
+ while ((key) != NULL \
+ && (isblank((int)(key)[0]))) { \
+ (key)++; \
+ } \
+} while(0);
+
static void rwrap_log(enum rwrap_dbglvl_e dbglvl,
const char *func,
const char *format, ...)
return 0;
}
+/*
+ * Priority and weight can be omitted from the hosts file, but need to be part
+ * of the output
+ */
+#define DFL_SRV_PRIO 1
+#define DFL_SRV_WEIGHT 100
+
+static int rwrap_fake_srv(const char *key,
+ const char *value,
+ uint8_t *answer,
+ size_t anslen)
+{
+ uint8_t *a = answer;
+ int rv;
+ size_t rdata_size;
+ char *str_prio;
+ char *str_weight;
+ char *str_port;
+ const char *hostname;
+ unsigned char hostname_compressed[MAXDNAME];
+ ssize_t compressed_len;
+
+ /*
+ * Parse the value into priority, weight, port and hostname
+ * and check the validity.
+ */
+ hostname = value;
+ NEXT_KEY(hostname, str_port);
+ NEXT_KEY(str_port, str_prio);
+ NEXT_KEY(str_prio, str_weight);
+ if (str_port == NULL || hostname == NULL) {
+ RWRAP_LOG(RWRAP_LOG_ERROR,
+ "Malformed SRV entry [%s]\n", value);
+ return -1;
+ }
+ rdata_size = 3 * sizeof(uint16_t);
+
+ /* Prepare the data to write */
+ compressed_len = ns_name_compress(hostname,
+ hostname_compressed, MAXDNAME,
+ NULL, NULL);
+ if (compressed_len < 0) {
+ return -1;
+ }
+ rdata_size += compressed_len;
+
+ rv = rwrap_fake_common(ns_t_srv, key, rdata_size, &a, anslen);
+ if (rv < 0) {
+ return -1;
+ }
+
+ if (str_prio) {
+ NS_PUT16(atoi(str_prio), a);
+ } else {
+ NS_PUT16(DFL_SRV_PRIO, a);
+ }
+ if (str_weight) {
+ NS_PUT16(atoi(str_weight), a);
+ } else {
+ NS_PUT16(DFL_SRV_WEIGHT, a);
+ }
+ NS_PUT16(atoi(str_port), a);
+ memcpy(a, hostname_compressed, compressed_len);
+
+ return 0;
+}
+
static int rwrap_fake_empty_query(const char *key,
uint16_t type,
uint8_t *answer,
(line[sizeof(name) - 1] == ' ' || \
line[sizeof(name) - 1] == '\t'))
-#define NEXT_KEY(buf, key) do { \
- (key) = strpbrk(buf, " \t"); \
- if ((key) != NULL) { \
- (key)[0] = '\0'; \
- (key)++; \
- } \
- while ((key) != NULL \
- && (isblank((int)(key)[0]))) { \
- (key)++; \
- } \
-} while(0);
-
#define TYPE_MATCH(type, ns_type, rec_type, str_type, key, query) \
((type) == (ns_type) && \
(strncmp((rec_type), (str_type), sizeof(str_type)) == 0) && \
rec_type, "AAAA", key, query)) {
rc = rwrap_fake_aaaa(key, value, answer, anslen);
break;
+ } else if (TYPE_MATCH(type, ns_t_srv,
+ rec_type, "SRV", key, query)) {
+ rc = rwrap_fake_srv(key, value, answer, anslen);
+ break;
}
}
assert_int_equal(ns_msg_count(handle, ns_s_an), 0);
}
+static void test_res_fake_srv_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;
+ int port;
+ char hostname[MAXDNAME];
+
+ (void) state; /* unused */
+
+ memset(&dnsstate, 0, sizeof(struct __res_state));
+ rv = res_ninit(&dnsstate);
+ assert_int_equal(rv, 0);
+
+ rv = res_nquery(&dnsstate, "_ldap._tcp.cwrap.org", ns_c_in, ns_t_srv,
+ answer, ANSIZE);
+ assert_int_not_equal(rv, -1);
+
+ 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 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_srv);
+
+ rrdata = ns_rr_rdata(rr);
+ NS_GET16(prio, rrdata);
+ NS_GET16(weight, rrdata);
+ NS_GET16(port, rrdata);
+
+ rv = ns_name_uncompress(ns_msg_base(handle),
+ ns_msg_end(handle),
+ rrdata,
+ hostname, MAXDNAME);
+ assert_int_not_equal(rv, -1);
+
+ assert_int_equal(prio, 1);
+ assert_int_equal(weight, 5);
+ assert_int_equal(port, 389);
+ assert_string_equal(hostname, "ldap.cwrap.org");
+}
+
+/*
+ * Test the case of a SRV 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_srv_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;
+ int port;
+ char hostname[MAXDNAME];
+
+ (void) state; /* unused */
+
+ memset(&dnsstate, 0, sizeof(struct __res_state));
+ rv = res_ninit(&dnsstate);
+ assert_int_equal(rv, 0);
+
+ rv = res_nquery(&dnsstate, "_krb5._tcp.cwrap.org", ns_c_in, ns_t_srv,
+ answer, ANSIZE);
+ assert_int_not_equal(rv, -1);
+
+ 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 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_srv);
+
+ rrdata = ns_rr_rdata(rr);
+ NS_GET16(prio, rrdata);
+ NS_GET16(weight, rrdata);
+ NS_GET16(port, rrdata);
+
+ rv = ns_name_uncompress(ns_msg_base(handle),
+ ns_msg_end(handle),
+ rrdata,
+ hostname, MAXDNAME);
+ assert_int_not_equal(rv, -1);
+
+ assert_int_equal(prio, 1);
+ assert_int_equal(weight, 100);
+ assert_int_equal(port, 88);
+ assert_string_equal(hostname, "krb5.cwrap.org");
+}
+
int main(void)
{
int rc;
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),
};
rc = run_tests(tests);