upstream_entry_t up;
};
+enum rdns_request_state {
+ RDNS_REQUEST_NEW = 0,
+ RDNS_REQUEST_REGISTERED = 1,
+ RDNS_REQUEST_WAIT_SEND,
+ RDNS_REQUEST_WAIT_REPLY,
+ RDNS_REQUEST_REPLIED,
+ RDNS_REQUEST_FAKE,
+};
+
struct rdns_request {
struct rdns_resolver *resolver;
struct rdns_async_context *async;
int id;
struct rdns_request_name *requested_names;
unsigned int qcount;
-
- enum {
- RDNS_REQUEST_NEW = 0,
- RDNS_REQUEST_REGISTERED = 1,
- RDNS_REQUEST_WAIT_SEND,
- RDNS_REQUEST_WAIT_REPLY,
- RDNS_REQUEST_REPLIED
- } state;
+ enum rdns_request_state state;
uint8_t *packet;
off_t pos;
ref_entry_t ref;
};
+struct rdns_fake_reply {
+ char *request;
+ enum dns_rcode rcode;
+ struct rdns_reply_entry *result;
+ UT_hash_handle hh;
+};
+
struct rdns_resolver {
struct rdns_server *servers;
void *periodic; /** periodic event for resolver */
struct rdns_upstream_context *ups;
struct rdns_plugin *curve_plugin;
+ struct rdns_fake_reply *fake_elts;
rdns_log_function logger;
void *log_data;
req->async_event);
req->async_event = NULL;
+ if (req->state == RDNS_REQUEST_FAKE) {
+ /* Reply is ready */
+ req->func (req->reply, req->arg);
+ REF_RELEASE (req);
+
+ return;
+ }
+
r = rdns_send_request (req, fd, false);
if (r == 0) {
size_t olen;
const char *cur_name, *last_name = NULL;
struct rdns_compression_entry *comp = NULL;
+ struct rdns_fake_reply *fake_rep = NULL;
if (resolver == NULL || !resolver->initialized) {
return NULL;
for (i = 0; i < queries * 2; i += 2) {
cur = i / 2;
cur_name = va_arg (args, const char *);
+
+ if (last_name == NULL) {
+ HASH_FIND_STR (resolver->fake_elts, cur_name, fake_rep);
+
+ if (fake_rep) {
+ /* We actually treat it as a short-circuit */
+ req->reply = rdns_make_reply (req, fake_rep->rcode);
+ req->reply->entries = fake_rep->result;
+ req->state = RDNS_REQUEST_FAKE;
+ }
+ }
+
if (cur_name != NULL) {
last_name = cur_name;
clen = strlen (cur_name);
return NULL;
}
- if (!rdns_format_dns_name (resolver, last_name, clen,
+ if (req->state != RDNS_REQUEST_FAKE &&
+ !rdns_format_dns_name (resolver, last_name, clen,
&req->requested_names[cur].name, &olen)) {
rdns_request_free (req);
return NULL;
}
va_end (args);
- rdns_allocate_packet (req, tlen);
- rdns_make_dns_header (req, queries);
-
- for (i = 0; i < queries; i ++) {
- cur_name = req->requested_names[i].name;
- clen = req->requested_names[i].len;
- type = req->requested_names[i].type;
- if (queries > 1) {
- if (!rdns_add_rr (req, cur_name, clen, type, &comp)) {
- REF_RELEASE (req);
- rnds_compression_free (comp);
- return NULL;
- }
- }
- else {
- if (!rdns_add_rr (req, cur_name, clen, type, NULL)) {
- REF_RELEASE (req);
- rnds_compression_free (comp);
- return NULL;
+ if (req->state != RDNS_REQUEST_FAKE) {
+ rdns_allocate_packet (req, tlen);
+ rdns_make_dns_header (req, queries);
+
+ for (i = 0; i < queries; i++) {
+ cur_name = req->requested_names[i].name;
+ clen = req->requested_names[i].len;
+ type = req->requested_names[i].type;
+ if (queries > 1) {
+ if (!rdns_add_rr (req, cur_name, clen, type, &comp)) {
+ REF_RELEASE (req);
+ rnds_compression_free (comp);
+ return NULL;
+ }
+ } else {
+ if (!rdns_add_rr (req, cur_name, clen, type, NULL)) {
+ REF_RELEASE (req);
+ rnds_compression_free (comp);
+ return NULL;
+ }
}
}
- }
- rnds_compression_free (comp);
+ rnds_compression_free (comp);
- /* Add EDNS RR */
- rdns_add_edns0 (req);
+ /* Add EDNS RR */
+ rdns_add_edns0 (req);
+
+ req->retransmits = repeats;
+ req->timeout = timeout;
+ req->state = RDNS_REQUEST_NEW;
+ }
- req->retransmits = repeats;
- req->timeout = timeout;
- req->state = RDNS_REQUEST_NEW;
req->async = resolver->async;
if (resolver->ups) {
/* Select random IO channel */
req->io = serv->io_channels[ottery_rand_uint32 () % serv->io_cnt];
- req->io->uses ++;
- /* Now send request to server */
- r = rdns_send_request (req, req->io->sock, true);
+ if (req->state == RDNS_REQUEST_FAKE) {
+ req->async_event = resolver->async->add_write (resolver->async->data,
+ req->io->sock, req);
+ }
+ else {
+ req->io->uses++;
- if (r == -1) {
- REF_RELEASE (req);
- return NULL;
+ /* Now send request to server */
+ r = rdns_send_request (req, req->io->sock, true);
+
+ if (r == -1) {
+ REF_RELEASE (req);
+ return NULL;
+ }
}
REF_RETAIN (req->io);
resolver->enable_dnssec = enabled;
}
}
+
+
+void rdns_resolver_set_fake_reply (struct rdns_resolver *resolver,
+ const char *name,
+ enum dns_rcode rcode,
+ struct rdns_reply_entry *reply)
+{
+ struct rdns_fake_reply *fake_rep;
+
+ HASH_FIND_STR (resolver->fake_elts, name, fake_rep);
+
+ if (fake_rep) {
+ /* Append reply to the existing list */
+ fake_rep->rcode = rcode;
+ DL_APPEND (fake_rep->result, reply);
+ }
+ else {
+ fake_rep = calloc (1, sizeof (*fake_rep));
+
+ if (fake_rep == NULL) {
+ abort ();
+ }
+
+ fake_rep->request = strdup (name);
+
+ if (fake_rep->request == NULL) {
+ abort ();
+ }
+
+ fake_rep->rcode = rcode;
+ DL_APPEND (fake_rep->result, reply);
+
+ HASH_ADD_KEYPTR (hh, resolver->fake_elts, fake_rep->request,
+ strlen (fake_rep->request), fake_rep);
+ }
+}
\ No newline at end of file
{
struct rdns_reply_entry *entry, *tmp;
- LL_FOREACH_SAFE (rep->entries, entry, tmp) {
- switch (entry->type) {
- case RDNS_REQUEST_PTR:
- free (entry->content.ptr.name);
- break;
- case RDNS_REQUEST_NS:
- free (entry->content.ns.name);
- break;
- case RDNS_REQUEST_MX:
- free (entry->content.mx.name);
- break;
- case RDNS_REQUEST_TXT:
- case RDNS_REQUEST_SPF:
- free (entry->content.txt.data);
- break;
- case RDNS_REQUEST_SRV:
- free (entry->content.srv.target);
- break;
- case RDNS_REQUEST_TLSA:
- free (entry->content.tlsa.data);
- break;
- case RDNS_REQUEST_SOA:
- free (entry->content.soa.mname);
- free (entry->content.soa.admin);
- break;
+ /* We don't need to free data for faked replies */
+ if (!rep->request || rep->request->state != RDNS_REQUEST_FAKE) {
+ LL_FOREACH_SAFE (rep->entries, entry, tmp) {
+ switch (entry->type) {
+ case RDNS_REQUEST_PTR:
+ free (entry->content.ptr.name);
+ break;
+ case RDNS_REQUEST_NS:
+ free (entry->content.ns.name);
+ break;
+ case RDNS_REQUEST_MX:
+ free (entry->content.mx.name);
+ break;
+ case RDNS_REQUEST_TXT:
+ case RDNS_REQUEST_SPF:
+ free (entry->content.txt.data);
+ break;
+ case RDNS_REQUEST_SRV:
+ free (entry->content.srv.target);
+ break;
+ case RDNS_REQUEST_TLSA:
+ free (entry->content.tlsa.data);
+ break;
+ case RDNS_REQUEST_SOA:
+ free (entry->content.soa.mname);
+ free (entry->content.soa.admin);
+ break;
+ }
+ free (entry);
}
- free (entry);
}
+
free (rep);
}
HASH_DEL (req->io->requests, req);
req->async_event = NULL;
}
-
+ else if (req->state == RDNS_REQUEST_FAKE) {
+ req->async->del_write (req->async->data,
+ req->async_event);
+ req->async_event = NULL;
+ }
}
#ifdef TWEETNACL
if (req->curve_plugin_data != NULL) {