RFC 2308 says a lot about negative answer caching. Here is patch, that discloses TTL of negative answer (if possible) to the library user.
-- WBRBW, Leonid Evdokimov xmpp:l...@darkk.net.ru && http://darkk.net.ru tel:+79816800702 && tel:+79050965222
From c903d9db417d2d8478eb7371e46dbc5ef60f650b Mon Sep 17 00:00:00 2001 From: Leonid Evdokimov <da...@yandex-team.ru> Date: Wed, 31 Aug 2011 00:56:45 +0400 Subject: [PATCH 7/7] DNS: add ttl for negative answers using RFC 2308 idea. --- evdns.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 files changed, 36 insertions(+), 6 deletions(-) diff --git a/evdns.c b/evdns.c index d7a3093..5f11772 100644 --- a/evdns.c +++ b/evdns.c @@ -135,6 +135,7 @@ #define TYPE_A EVDNS_TYPE_A #define TYPE_CNAME 5 #define TYPE_PTR EVDNS_TYPE_PTR +#define TYPE_SOA EVDNS_TYPE_SOA #define TYPE_AAAA EVDNS_TYPE_AAAA #define CLASS_INET EVDNS_CLASS_INET @@ -762,7 +763,7 @@ reply_run_callback(struct deferred_cb *d, void *user_pointer) cb->reply.data.a.addresses, user_pointer); else - cb->user_callback(cb->err, 0, 0, 0, NULL, user_pointer); + cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer); break; case TYPE_PTR: if (cb->have_reply) { @@ -770,7 +771,7 @@ reply_run_callback(struct deferred_cb *d, void *user_pointer) cb->user_callback(DNS_ERR_NONE, DNS_PTR, 1, cb->ttl, &name, user_pointer); } else { - cb->user_callback(cb->err, 0, 0, 0, NULL, user_pointer); + cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer); } break; case TYPE_AAAA: @@ -780,7 +781,7 @@ reply_run_callback(struct deferred_cb *d, void *user_pointer) cb->reply.data.aaaa.addresses, user_pointer); else - cb->user_callback(cb->err, 0, 0, 0, NULL, user_pointer); + cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer); break; default: EVUTIL_ASSERT(0); @@ -901,7 +902,7 @@ reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) } /* all else failed. Pass the failure up */ - reply_schedule_callback(req, 0, error, NULL); + reply_schedule_callback(req, ttl, error, NULL); request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1); } else { /* all ok, tell the user */ @@ -1004,8 +1005,8 @@ reply_parse(struct evdns_base *base, u8 *packet, int length) { /* If it's not an answer, it doesn't correspond to any request. */ if (!(flags & 0x8000)) return -1; /* must be an answer */ - if (flags & 0x020f) { - /* there was an error */ + if ((flags & 0x020f) && (flags & 0x020f) != DNS_ERR_NOTEXIST) { + /* there was an error and it's not NXDOMAIN */ goto err; } /* if (!answers) return; */ /* must have an answer of some form */ @@ -1127,6 +1128,35 @@ reply_parse(struct evdns_base *base, u8 *packet, int length) { } } + if (!reply.have_answer) { + for (i = 0; i < authority; ++i) { + u16 type, class; + SKIP_NAME; + GET16(type); + GET16(class); + GET32(ttl); + GET16(datalength); + if (type == TYPE_SOA && class == CLASS_INET) { + u32 serial, refresh, retry, expire, minimum; + SKIP_NAME; + SKIP_NAME; + GET32(serial); + GET32(refresh); + GET32(retry); + GET32(expire); + GET32(minimum); + ttl_r = MIN(ttl_r, ttl); + ttl_r = MIN(ttl_r, minimum); + } else { + /* skip over any other type of resource */ + j += datalength; + } + } + } + + if (ttl_r == 0xffffffff) + ttl_r = 0; + reply_handle(req, flags, ttl_r, &reply); return 0; err: -- 1.7.4.1