u16 trans_id; /* the transaction id */
unsigned request_appended :1; /* true if the request pointer is data which follows this struct */
unsigned transmit_me :1; /* needs to be transmitted */
+ unsigned need_cname :1; /* make a separate callback for CNAME */
/* XXXX This is a horrible hack. */
char **put_cname_in_ptr; /* store the cname here if we get one. */
char *ptr_name;
void *raw;
} data;
+ char *cname;
};
enum tcp_state {
switch (cb->request_type) {
case TYPE_A:
- if (cb->have_reply)
+ if (cb->have_reply) {
cb->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
cb->reply.rr_count, cb->ttl,
cb->reply.data.a,
user_pointer);
- else
+ if (cb->reply.cname)
+ cb->user_callback(DNS_ERR_NONE, DNS_CNAME, 1,
+ cb->ttl, cb->reply.cname, user_pointer);
+ } else
cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
break;
case TYPE_PTR:
}
break;
case TYPE_AAAA:
- if (cb->have_reply)
+ if (cb->have_reply) {
cb->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
cb->reply.rr_count, cb->ttl,
cb->reply.data.aaaa,
user_pointer);
- else
+ if (cb->reply.cname)
+ cb->user_callback(DNS_ERR_NONE, DNS_CNAME, 1,
+ cb->ttl, cb->reply.cname, user_pointer);
+ } else
cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
break;
default:
mm_free(cb->reply.data.raw);
}
+ if (cb->reply.cname) {
+ mm_free(cb->reply.cname);
+ }
+
mm_free(cb);
}
break;
} else if (type == TYPE_CNAME) {
char cname[HOST_NAME_MAX];
- if (!req->put_cname_in_ptr || *req->put_cname_in_ptr) {
- j += datalength; continue;
- }
if (name_parse(packet, length, &j, cname,
sizeof(cname))<0)
goto err;
- *req->put_cname_in_ptr = mm_strdup(cname);
+ if (req->need_cname)
+ reply.cname = mm_strdup(cname);
+ if (req->put_cname_in_ptr && !*req->put_cname_in_ptr)
+ *req->put_cname_in_ptr = mm_strdup(cname);
} else if (type == TYPE_AAAA && class == CLASS_INET) {
int addrcount;
if (req->request_type != TYPE_AAAA) {
handle->base = base;
}
+ if (flags & DNS_CNAME_CALLBACK)
+ req->need_cname = 1;
+
return req;
err1:
mm_free(req);
#define DNS_IPv4_A 1
#define DNS_PTR 2
#define DNS_IPv6_AAAA 3
+#define DNS_CNAME 4
/** Disable searching for the query. */
#define DNS_QUERY_NO_SEARCH 0x01
#define DNS_QUERY_USEVC 0x02
/** Ignore trancation flag in responses (don't fallback to TCP connections). */
#define DNS_QUERY_IGNTC 0x04
+/** Make a separate callback for CNAME in answer */
+#define DNS_CNAME_CALLBACK 0x80
/* Allow searching */
#define DNS_OPTION_SEARCH 1
len = count * 4;
else if (type == DNS_IPv6_AAAA)
len = count * 16;
- else if (type == DNS_PTR)
+ else if (type == DNS_PTR || type == DNS_CNAME)
len = strlen(addresses)+1;
else {
res->addrs_len = len = 0;
{ "hostn.a.example.com", "errsoa", "0", 0, 0 },
{ "hostn.b.example.com", "errsoa", "3", 0, 0 },
{ "hostn.c.example.com", "err", "0", 0, 0 },
+ { "hostc.c.example.com", "CNAME", "cname.c.example.com", 0, 0 },
{ "host", "err", "3", 0, 0 },
{ "host2", "err", "3", 0, 0 },
{ "*", "err", "3", 0, 0 },
ev_uint16_t portnum = 0;
char buf[64];
- struct generic_dns_callback_result r[8];
+ struct generic_dns_callback_result r[9];
size_t i;
for (i = 0; i < ARRAY_SIZE(table); ++i) {
evdns_base_search_add(dns, "b.example.com");
evdns_base_search_add(dns, "c.example.com");
- n_replies_left = ARRAY_SIZE(r);
+ n_replies_left = ARRAY_SIZE(r)+1; /* CNAME gives us 2 callbacks for 1 request */
exit_base = base;
evdns_base_resolve_ipv4(dns, "host", 0, generic_dns_callback, &r[0]);
evdns_base_resolve_ipv4(dns, "hostn.a.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[5]);
evdns_base_resolve_ipv4(dns, "hostn.b.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[6]);
evdns_base_resolve_ipv4(dns, "hostn.c.example.com", DNS_NO_SEARCH, generic_dns_callback, &r[7]);
+ evdns_base_resolve_ipv4(dns, "hostc.c.example.com", DNS_NO_SEARCH | DNS_CNAME_CALLBACK,
+ generic_dns_callback, &r[8]);
event_base_dispatch(base);
tt_int_op(r[6].ttl, ==, 42);
tt_int_op(r[7].result, ==, DNS_ERR_NODATA);
tt_int_op(r[7].ttl, ==, 0);
+ tt_int_op(r[8].type, ==, DNS_CNAME);
+ tt_int_op(r[8].count, ==, 1);
+ tt_str_op(r[8].addrs, ==, "cname.c.example.com");
end:
if (dns)
}
evdns_server_request_add_aaaa_reply(req,
question, 1, &in6.s6_addr, 100);
+ } else if (!strcmp(tab->anstype, "CNAME")) {
+ struct in_addr in;
+ evutil_inet_pton(AF_INET, "11.22.33.44", &in);
+ evdns_server_request_add_a_reply(req, question, 1, &in, 100);
+ evdns_server_request_add_cname_reply(req, question, tab->ans, 100);
} else {
TT_DIE(("Weird table entry with type '%s'", tab->anstype));
}