assert(s);
assert(q);
- r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL, NULL);
+ r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL);
if (r < 0)
return r;
}
static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
+ _cleanup_free_ char *pretty = NULL;
DnsZoneItem *z;
- Iterator i;
assert(t);
assert(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 larger IP address and thus lost in the conflict.");
+ return;
+ }
+
+ log_debug("We have the lexicographically larger IP address and thus lost in the conflict.");
t->block_gc++;
- SET_FOREACH(z, t->zone_items, i)
+ while ((z = set_first(t->zone_items))) {
+ /* First, make sure the zone item drops the reference
+ * to us */
+ dns_zone_item_probe_stop(z);
+
+ /* Secondly, report this as conflict, so that we might
+ * look for a different hostname */
dns_zone_item_conflict(z);
+ }
t->block_gc--;
dns_transaction_gc(t);
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
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--;
}
/* 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);
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));
}
}
+ 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 */
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);
}