From: Marek VavruĊĦa Date: Tue, 14 Jul 2015 17:31:18 +0000 (+0200) Subject: layer/iterate: do DNS 0x20 only for outbound queries X-Git-Tag: v1.0.0-beta1~77^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=34375fa84d59f50aa2d1181a3535d6f17107ee6f;p=thirdparty%2Fknot-resolver.git layer/iterate: do DNS 0x20 only for outbound queries no need to scramble queries satisfied from cache --- diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index da1b5a46f..fb4e38c6a 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -14,7 +14,6 @@ along with this program. If not, see . */ -#include #include #include @@ -57,39 +56,11 @@ static const knot_dname_t *minimized_qname(struct kr_query *query, uint16_t *qty return qname; } -/* Randomize QNAME letter case. - * This adds 32 bits of randomness at maximum, but that's more than an average domain name length. - * https://tools.ietf.org/html/draft-vixie-dnsext-dns0x20-00 - */ -static void randomized_qname_case(knot_dname_t *qname, unsigned secret) -{ - unsigned k = 0; - while (*qname != '\0') { - for (unsigned i = *qname; i--;) { - int chr = qname[i + 1]; - if (isalpha(chr)) { - if (secret & (1 << k)) { - qname[i + 1] ^= 0x20; - } - k = (k + 1) % (sizeof(secret) * CHAR_BIT); - } - } - qname = (uint8_t *)knot_wire_next_label(qname, NULL); - } -} - /** Answer is paired to query. */ static bool is_paired_to_query(const knot_pkt_t *answer, struct kr_query *query) { uint16_t qtype = query->stype; - const knot_dname_t *qname_min = minimized_qname(query, &qtype); - - /* Construct expected randomized QNAME */ - uint8_t qname[KNOT_DNAME_MAXLEN]; - knot_dname_to_wire(qname, qname_min, sizeof(qname)); - if (!(query->flags & (QUERY_CACHED|QUERY_SAFEMODE))) { - randomized_qname_case(qname, query->secret); - } + const knot_dname_t *qname = minimized_qname(query, &qtype); return query->id == knot_wire_get_id(answer->wire) && (query->sclass == KNOT_CLASS_ANY || query->sclass == knot_pkt_qclass(answer)) && @@ -397,11 +368,6 @@ int kr_make_query(struct kr_query *query, knot_pkt_t *pkt) return ret; } - /* Randomize query case (if not in safemode) */ - query->secret = (query->flags & QUERY_SAFEMODE) ? 0 : kr_rand_uint(UINT32_MAX); - knot_dname_t *qname_raw = (knot_dname_t *)knot_pkt_qname(pkt); - randomized_qname_case(qname_raw, query->secret); - /* Query built, expect answer. */ query->id = kr_rand_uint(UINT16_MAX); knot_wire_set_id(pkt->wire, query->id); @@ -480,10 +446,6 @@ static int resolve(knot_layer_t *ctx, knot_pkt_t *pkt) return KNOT_STATE_DONE; } - /* Packet cleared, normalize QNAME. */ - knot_dname_t *qname_raw = (knot_dname_t *)knot_pkt_qname(pkt); - knot_dname_to_lower(qname_raw); - /* Check response code. */ #ifndef NDEBUG lookup_table_t *rcode = lookup_by_id(knot_rcode_names, knot_wire_get_rcode(pkt->wire)); diff --git a/lib/resolve.c b/lib/resolve.c index 1e67c2282..c81afd9f1 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -14,6 +14,7 @@ along with this program. If not, see . */ +#include #include #include #include @@ -27,6 +28,27 @@ #define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(rplan), "resl", fmt) +/* Randomize QNAME letter case. + * This adds 32 bits of randomness at maximum, but that's more than an average domain name length. + * https://tools.ietf.org/html/draft-vixie-dnsext-dns0x20-00 + */ +static void randomized_qname_case(knot_dname_t *qname, unsigned secret) +{ + unsigned k = 0; + while (*qname != '\0') { + for (unsigned i = *qname; i--;) { + int chr = qname[i + 1]; + if (isalpha(chr)) { + if (secret & (1 << k)) { + qname[i + 1] ^= 0x20; + } + k = (k + 1) % (sizeof(secret) * CHAR_BIT); + } + } + qname = (uint8_t *)knot_wire_next_label(qname, NULL); + } +} + /** @internal Subtract time (best effort) */ float time_diff(struct timeval *begin, struct timeval *end) { @@ -245,8 +267,13 @@ static int answer_finalize(knot_pkt_t *answer) static int query_finalize(struct kr_request *request, knot_pkt_t *pkt) { - int ret = 0; + /* Randomize query case (if not in safemode) */ struct kr_query *qry = kr_rplan_current(&request->rplan); + qry->secret = (qry->flags & QUERY_SAFEMODE) ? 0 : kr_rand_uint(UINT32_MAX); + knot_dname_t *qname_raw = (knot_dname_t *)knot_pkt_qname(pkt); + randomized_qname_case(qname_raw, qry->secret); + + int ret = 0; knot_pkt_begin(pkt, KNOT_ADDITIONAL); if (!(qry->flags & QUERY_SAFEMODE)) { ret = edns_create(pkt, request->answer); @@ -379,6 +406,11 @@ int kr_resolve_consume(struct kr_request *request, knot_pkt_t *packet) return KNOT_STATE_CONSUME; /* Try again */ } } else { + /* Packet cleared, derandomize QNAME. */ + knot_dname_t *qname_raw = (knot_dname_t *)knot_pkt_qname(packet); + if (qname_raw && qry->secret != 0) { + randomized_qname_case(qname_raw, qry->secret); + } state = knot_overlay_consume(&request->overlay, packet); } @@ -428,6 +460,7 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t int state = knot_overlay_produce(&request->overlay, packet); if (state != KNOT_STATE_FAIL && knot_wire_get_qr(packet->wire)) { /* Produced an answer, consume it. */ + qry->secret = 0; request->overlay.state = KNOT_STATE_CONSUME; state = knot_overlay_consume(&request->overlay, packet); } @@ -488,6 +521,12 @@ ns_election: return KNOT_STATE_PRODUCE; } + /* Prepare additional query */ + int ret = query_finalize(request, packet); + if (ret != 0) { + return KNOT_STATE_FAIL; + } + #ifndef NDEBUG char qname_str[KNOT_DNAME_MAXLEN], zonecut_str[KNOT_DNAME_MAXLEN], ns_str[SOCKADDR_STRLEN]; knot_dname_to_str(qname_str, knot_pkt_qname(packet), sizeof(qname_str)); @@ -497,11 +536,6 @@ ns_election: DEBUG_MSG("=> querying: '%s' score: %u zone cut: '%s' m12n: '%s'\n", ns_str, qry->ns.score, zonecut_str, qname_str); #endif - /* Prepare additional query */ - int ret = query_finalize(request, packet); - if (ret != 0) { - return KNOT_STATE_FAIL; - } gettimeofday(&qry->timestamp, NULL); *dst = &qry->ns.addr.ip; *type = (qry->flags & QUERY_TCP) ? SOCK_STREAM : SOCK_DGRAM;