diff options
-rw-r--r-- | doc/libs6dns/s6dns-message.html | 3 | ||||
-rw-r--r-- | src/libs6dns/s6dns_message_parse.c | 4 | ||||
-rw-r--r-- | src/libs6dns/s6dns_resolveq.c | 2 | ||||
-rw-r--r-- | src/libs6dns/s6dns_resolveq_aaaaa.c | 50 |
4 files changed, 37 insertions, 22 deletions
diff --git a/doc/libs6dns/s6dns-message.html b/doc/libs6dns/s6dns-message.html index 1c5a92d..315b375 100644 --- a/doc/libs6dns/s6dns-message.html +++ b/doc/libs6dns/s6dns-message.html @@ -257,7 +257,8 @@ containing <tt>s6dns_message_rr_caa_t</tt> structures. It stores the packet header into *<em>h</em>. Then, for every RR in the answer, authority or additional section of the packet, it calls <em>f</em> with the relevant parameters. <em>data</em> is the extra pointer given to <em>f</em> to -store information. The function returns 1 if the parsing succeeds. Otherwise it +store information. If the parsing succeeds, the function returns 2 if the packet +contains an answer section and 1 if it does not. Otherwise, it returns -1 if there is a local error unrelated to the packet, or 0 if no appropriate answer can be decoded from the packet. errno then contains one of the following values: diff --git a/src/libs6dns/s6dns_message_parse.c b/src/libs6dns/s6dns_message_parse.c index 06b7677..4aaee9a 100644 --- a/src/libs6dns/s6dns_message_parse.c +++ b/src/libs6dns/s6dns_message_parse.c @@ -10,6 +10,7 @@ int s6dns_message_parse (s6dns_message_header_t *h, char const *packet, unsigned s6dns_message_counts_t counts ; unsigned int pos ; unsigned int section ; + int gotans ; if (!s6dns_message_parse_init(h, &counts, packet, packetlen, &pos)) return 0 ; switch (h->rcode) { @@ -21,6 +22,7 @@ int s6dns_message_parse (s6dns_message_header_t *h, char const *packet, unsigned case 5 : return (errno = ECONNREFUSED, 0) ; default: return (errno = EIO, 0) ; } + gotans = !!counts.an ; section = s6dns_message_parse_skipqd(&counts, packet, packetlen, &pos) ; while (section) { @@ -33,5 +35,5 @@ int s6dns_message_parse (s6dns_message_header_t *h, char const *packet, unsigned } section = s6dns_message_parse_next(&counts, &rr, packet, packetlen, &pos) ; } - return 1 ; + return 1 + gotans ; } diff --git a/src/libs6dns/s6dns_resolveq.c b/src/libs6dns/s6dns_resolveq.c index a2933ee..3c1d22c 100644 --- a/src/libs6dns/s6dns_resolveq.c +++ b/src/libs6dns/s6dns_resolveq.c @@ -1,7 +1,9 @@ /* ISC license. */ #include <errno.h> + #include <skalibs/error.h> + #include <s6-dns/s6dns-domain.h> #include <s6-dns/s6dns-message.h> #include <s6-dns/s6dns-engine.h> diff --git a/src/libs6dns/s6dns_resolveq_aaaaa.c b/src/libs6dns/s6dns_resolveq_aaaaa.c index f990a7c..460956e 100644 --- a/src/libs6dns/s6dns_resolveq_aaaaa.c +++ b/src/libs6dns/s6dns_resolveq_aaaaa.c @@ -13,7 +13,19 @@ #include <s6-dns/s6dns-engine.h> #include <s6-dns/s6dns-resolve.h> -#define d_ip46full_from_ip(i, s, h) ((h) ? ip46full_from_ip6(i, s) : ip46full_from_ip4(i, s)) +static int addit (genalloc *ips, char const *s, size_t len, int is6) +{ + size_t base = genalloc_len(ip46full_t, ips) ; + size_t n = len >> (is6 ? 4 : 2) ; + ip46full_t *p ; + if (!genalloc_readyplus(ip46full_t, ips, n)) return 0 ; + p = genalloc_s(ip46full_t, ips) + base ; + for (size_t i = 0 ; i < n ; i++) + if (is6) ip46full_from_ip6(p + i, s + (i << 4)) ; + else ip46full_from_ip4(p + i, s + (i << 2)) ; + genalloc_setlen(ip46full_t, ips, base + n) ; + return 1 ; +} int s6dns_resolveq_aaaaa_r (genalloc *ips, char const *name, size_t len, s6dns_rci_t const *rci, s6dns_debughook_t const *dbh, tain_t const *deadline, tain_t *stamp) { @@ -22,6 +34,8 @@ int s6dns_resolveq_aaaaa_r (genalloc *ips, char const *name, size_t len, s6dns_r unsigned int best = 0 ; unsigned int n ; int e = 0 ; + int ans = 0 ; + int pinned = 0 ; unsigned int i = 0 ; { s6dns_domain_t domains[rci->rulesnum] ; @@ -54,12 +68,19 @@ int s6dns_resolveq_aaaaa_r (genalloc *ips, char const *name, size_t len, s6dns_r { s6dns_message_header_t h ; int r ; + if (pinned && !(best & 1)) goto end ; if (best >= n << 1) goto notfound ; if (error_isagain(dtl[best].status)) break ; if (dtl[best].status) { errno = dtl[best].status ; goto err ; } r = s6dns_message_parse(&h, s6dns_engine_packet(dtl + best), s6dns_engine_packetlen(dtl + best), (best & 1) ? &s6dns_message_parse_answer_a : s6dns_message_parse_answer_aaaa, &data) ; if (r < 0) goto err ; - else if (r) goto found ; + else if (r) + { + if (!addit(ips, data.s, data.len, !(best & 1))) goto err ; + if (r > 1) ans |= 1 + !(best & 1) ; + data.len = 0 ; + pinned = 1 ; + } else switch (errno) { case EBUSY : @@ -74,25 +95,14 @@ int s6dns_resolveq_aaaaa_r (genalloc *ips, char const *name, size_t len, s6dns_r } } - found: - s6dns_engine_freen(dtl, n<<1) ; - { - size_t len = data.len >> ((best & 1) ? 2 : 4) ; - size_t i = 0 ; - size_t base = genalloc_len(ip46full_t, ips) ; - if (!genalloc_readyplus(ip46full_t, ips, len)) return -1 ; - for (; i < len ; i++) - d_ip46full_from_ip(genalloc_s(ip46full_t, ips) + base + i, data.s + (i << ((best & 1) ? 2 : 4)), !(best & 1)) ; - genalloc_setlen(ip46full_t, ips, base + len) ; - } - stralloc_free(&data) ; - return 1 ; - notfound: - s6dns_engine_freen(dtl, n<<1) ; - return (errno = e, 0) ; - + errno = e ; + ans = 0 ; + goto end ; err: + ans = -1 ; + end: + stralloc_free(&data) ; s6dns_engine_freen(dtl, n<<1) ; - return -1 ; + return ans ; } |