From 8af5b883227ac8dfa796742b9edcc1647a5d4d6c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 9 Dec 2015 17:49:05 +0100 Subject: resolved: split out check whether reply matches our question It's complicated enough, it deserves its own call. (Also contains some unrelated whitespace, comment and assertion changes) --- src/resolve/resolved-dns-packet.c | 24 ++++++++++++++++++++++++ src/resolve/resolved-dns-packet.h | 2 ++ src/resolve/resolved-dns-transaction.c | 21 ++++++++++++++------- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index b9c2dee557..399ba59749 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -2021,6 +2021,30 @@ finish: return r; } +int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) { + int r; + + assert(p); + assert(key); + + /* Checks if the specified packet is a reply for the specified + * key and the specified key is the only one in the question + * section. */ + + if (DNS_PACKET_QR(p) != 1) + return 0; + + /* Let's unpack the packet, if that hasn't happened yet. */ + r = dns_packet_extract(p); + if (r < 0) + return r; + + if (p->question->n_keys != 1) + return 0; + + return dns_resource_key_equal(p->question->keys[0], key); +} + static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = { [DNS_RCODE_SUCCESS] = "SUCCESS", [DNS_RCODE_FORMERR] = "FORMERR", diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index b0b8600232..5b6a71dc01 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -161,6 +161,8 @@ int dns_packet_validate(DnsPacket *p); int dns_packet_validate_reply(DnsPacket *p); int dns_packet_validate_query(DnsPacket *p); +int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key); + int dns_packet_append_blob(DnsPacket *p, const void *d, size_t sz, size_t *start); int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start); int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 90f07e6c4b..b83aef5f35 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -428,12 +428,13 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); switch (t->scope->protocol) { + case DNS_PROTOCOL_DNS: assert(t->server); if (IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_FORMERR, DNS_RCODE_SERVFAIL, DNS_RCODE_NOTIMP)) { - /* request failed, immediately try again with reduced features */ + /* Request failed, immediately try again with reduced features */ log_debug("Server returned error: %s", dns_rcode_to_string(DNS_PACKET_RCODE(p))); dns_server_packet_failed(t->server, t->current_features); @@ -449,13 +450,14 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { dns_server_packet_received(t->server, t->current_features, ts - t->start_usec, p->size); break; + case DNS_PROTOCOL_LLMNR: case DNS_PROTOCOL_MDNS: dns_scope_packet_received(t->scope, ts - t->start_usec); - break; + default: - break; + assert_not_reached("Invalid DNS protocol."); } if (DNS_PACKET_TC(p)) { @@ -474,7 +476,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { return; } if (r < 0) { - /* On LLMNR and mDNS, if we cannot connect to the host, + /* On LLMNR, if we cannot connect to the host, * we immediately give up */ if (t->scope->protocol == DNS_PROTOCOL_LLMNR) { dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); @@ -494,7 +496,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { } } - /* Parse and update the cache */ + /* Parse message, if it isn't parsed yet. */ r = dns_packet_extract(p); if (r < 0) { dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); @@ -503,7 +505,12 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { if (t->scope->protocol == DNS_PROTOCOL_DNS) { /* Only consider responses with equivalent query section to the request */ - if (p->question->n_keys != 1 || dns_resource_key_equal(p->question->keys[0], t->key) <= 0) { + r = dns_packet_is_reply_for(p, t->key); + if (r < 0) { + dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); + return; + } + if (r == 0) { dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); return; } @@ -549,7 +556,7 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use DNS_PACKET_ID(p) == t->id) dns_transaction_process_reply(t, p); else - log_debug("Invalid DNS packet."); + log_debug("Invalid DNS packet, ignoring."); return 0; } -- cgit v1.2.3-54-g00ecf