X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fresolve%2Fresolved-dns-transaction.c;h=cf2987d1925cb4d922fc1e56f7e7e5e92a3ff240;hb=2fb3034cb21c745ed4f9aa4cba57563f7f071466;hp=ad1b277555254a4b92efff9520cda20a4750235d;hpb=13b551acb68695716cb4029531b5dec0759efa53;p=elogind.git diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index ad1b27755..cf2987d19 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -118,6 +118,7 @@ static void dns_transaction_stop(DnsTransaction *t) { } static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { + _cleanup_free_ char *pretty = NULL; DnsZoneItem *z; Iterator i; @@ -127,10 +128,22 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { if (manager_our_packet(t->scope->manager, p) != 0) return; - log_debug("Transaction on scope %s on %s/%s got tentative packet", + in_addr_to_string(p->family, &p->sender, &pretty); + + log_debug("Transaction on scope %s on %s/%s got tentative packet from %s", dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->name : "*", - t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family)); + t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family), + pretty); + + /* RFC 4795, Section 4.1 says that the peer with the + * lexicographically smaller IP address loses */ + if (memcmp(&p->sender, &p->destination, FAMILY_ADDRESS_SIZE(p->family)) < 0) { + log_debug("Peer has lexicographically smaller IP address and thus lost in the conflict."); + return; + } + + log_debug("We have the lexicographically smaller IP address and thus lost in the conflict."); t->block_gc++; SET_FOREACH(z, t->zone_items, i) @@ -147,7 +160,9 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { assert(t); assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)); - assert(IN_SET(t->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)); + + if (!IN_SET(t->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)) + return; /* Note that this call might invalidate the query. Callers * should hence not attempt to access the query or transaction @@ -194,6 +209,14 @@ static int on_stream_complete(DnsStream *s, int error) { return 0; } + if (dns_packet_validate_reply(p) <= 0) { + log_debug("Invalid LLMNR TCP packet."); + dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); + return 0; + } + + dns_scope_check_conflicts(t->scope, p); + t->block_gc++; dns_transaction_process_reply(t, p); t->block_gc--; @@ -368,7 +391,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { } /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */ - dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0); + dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender); if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS) dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); @@ -443,7 +466,7 @@ int dns_transaction_go(DnsTransaction *t) { dns_transaction_stop(t); - log_debug("Beginning transaction on scope %s on %s/%s", + log_debug("Excercising transaction on scope %s on %s/%s", dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->name : "*", t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family)); @@ -490,6 +513,34 @@ int dns_transaction_go(DnsTransaction *t) { } } + if (t->scope->protocol == DNS_PROTOCOL_LLMNR && !t->initial_jitter) { + usec_t jitter; + + /* RFC 4795 Section 2.7 suggests all queries should be + * delayed by a random time from 0 to JITTER_INTERVAL. */ + + t->initial_jitter = true; + + random_bytes(&jitter, sizeof(jitter)); + jitter %= LLMNR_JITTER_INTERVAL_USEC; + + r = sd_event_add_time( + t->scope->manager->event, + &t->timeout_event_source, + clock_boottime_or_monotonic(), + now(clock_boottime_or_monotonic()) + jitter, + LLMNR_JITTER_INTERVAL_USEC, + on_transaction_timeout, t); + if (r < 0) + return r; + + t->n_attempts = 0; + t->state = DNS_TRANSACTION_PENDING; + + log_debug("Delaying LLMNR transaction for " USEC_FMT "us.", jitter); + return 0; + } + log_debug("Cache miss!"); /* Otherwise, we need to ask the network */ @@ -513,7 +564,7 @@ int dns_transaction_go(DnsTransaction *t) { r = dns_transaction_open_tcp(t); } else { /* Try via UDP, and if that fails due to large size try via TCP */ - r = dns_scope_send(t->scope, t->sent); + r = dns_scope_emit(t->scope, t->sent); if (r == -EMSGSIZE) r = dns_transaction_open_tcp(t); }