mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-23 17:34:00 +03:00
resolved: implement mDNS probing and announcement
Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
This commit is contained in:
parent
3b991089c3
commit
53fda2bb93
@ -124,6 +124,8 @@ DnsScope* dns_scope_free(DnsScope *s) {
|
|||||||
ordered_hashmap_free(s->conflict_queue);
|
ordered_hashmap_free(s->conflict_queue);
|
||||||
sd_event_source_unref(s->conflict_event_source);
|
sd_event_source_unref(s->conflict_event_source);
|
||||||
|
|
||||||
|
sd_event_source_unref(s->announce_event_source);
|
||||||
|
|
||||||
dns_cache_flush(&s->cache);
|
dns_cache_flush(&s->cache);
|
||||||
dns_zone_flush(&s->zone);
|
dns_zone_flush(&s->zone);
|
||||||
|
|
||||||
@ -791,8 +793,15 @@ DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key,
|
|||||||
/* Try to find an ongoing transaction that is a equal to the
|
/* Try to find an ongoing transaction that is a equal to the
|
||||||
* specified question */
|
* specified question */
|
||||||
t = hashmap_get(scope->transactions_by_key, key);
|
t = hashmap_get(scope->transactions_by_key, key);
|
||||||
if (!t)
|
if (!t) {
|
||||||
return NULL;
|
DnsResourceKey *key_any;
|
||||||
|
|
||||||
|
key_any = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_ANY, dns_resource_key_name(key));
|
||||||
|
t = hashmap_get(scope->transactions_by_key, key_any);
|
||||||
|
key_any = dns_resource_key_unref(key_any);
|
||||||
|
if (!t)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Refuse reusing transactions that completed based on cached
|
/* Refuse reusing transactions that completed based on cached
|
||||||
* data instead of a real packet, if that's requested. */
|
* data instead of a real packet, if that's requested. */
|
||||||
@ -936,17 +945,19 @@ void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
|
|||||||
assert(scope);
|
assert(scope);
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
||||||
if (p->protocol != DNS_PROTOCOL_LLMNR)
|
if (!IN_SET(p->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (DNS_PACKET_RRCOUNT(p) <= 0)
|
if (DNS_PACKET_RRCOUNT(p) <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (DNS_PACKET_LLMNR_C(p) != 0)
|
if (p->protocol == DNS_PROTOCOL_LLMNR) {
|
||||||
return;
|
if (DNS_PACKET_LLMNR_C(p) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (DNS_PACKET_LLMNR_T(p) != 0)
|
if (DNS_PACKET_LLMNR_T(p) != 0)
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (manager_our_packet(scope->manager, p))
|
if (manager_our_packet(scope->manager, p))
|
||||||
return;
|
return;
|
||||||
@ -1049,3 +1060,76 @@ int dns_scope_ifindex(DnsScope *s) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int on_announcement_timeout(sd_event_source *s, usec_t usec, void *userdata) {
|
||||||
|
DnsScope *scope = userdata;
|
||||||
|
|
||||||
|
assert(s);
|
||||||
|
|
||||||
|
scope->announce_event_source = sd_event_source_unref(scope->announce_event_source);
|
||||||
|
|
||||||
|
dns_scope_announce(scope);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_scope_announce(DnsScope *scope) {
|
||||||
|
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
|
||||||
|
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
|
||||||
|
LinkAddress *a;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!scope)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (scope->protocol != DNS_PROTOCOL_MDNS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
answer = dns_answer_new(4);
|
||||||
|
LIST_FOREACH(addresses, a, scope->link->addresses) {
|
||||||
|
r = dns_answer_add(answer, a->mdns_address_rr, 0);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Failed to add address RR to answer: %m");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r = dns_answer_add(answer, a->mdns_ptr_rr, 0);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Failed to add PTR RR to answer: %m");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dns_answer_isempty(answer))
|
||||||
|
return;
|
||||||
|
|
||||||
|
r = dns_scope_make_reply_packet(scope, 0, DNS_RCODE_SUCCESS, NULL, answer, NULL, false, &p);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Failed to build reply packet: %m");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r = dns_scope_emit_udp(scope, -1, p);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "Failed to send reply packet: %m");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In section 8.3 of RFC6762: "The Multicast DNS responder MUST send at least two unsolicited
|
||||||
|
* responses, one second apart." */
|
||||||
|
if (!scope->announced) {
|
||||||
|
usec_t ts;
|
||||||
|
|
||||||
|
scope->announced = true;
|
||||||
|
|
||||||
|
assert_se(sd_event_now(scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
|
||||||
|
ts += MDNS_ANNOUNCE_DELAY;
|
||||||
|
|
||||||
|
r = sd_event_add_time(
|
||||||
|
scope->manager->event,
|
||||||
|
&scope->announce_event_source,
|
||||||
|
clock_boottime_or_monotonic(),
|
||||||
|
ts,
|
||||||
|
MDNS_JITTER_RANGE_USEC,
|
||||||
|
on_announcement_timeout, scope);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Failed to schedule second announcement: %m");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -56,6 +56,9 @@ struct DnsScope {
|
|||||||
OrderedHashmap *conflict_queue;
|
OrderedHashmap *conflict_queue;
|
||||||
sd_event_source *conflict_event_source;
|
sd_event_source *conflict_event_source;
|
||||||
|
|
||||||
|
bool announced:1;
|
||||||
|
sd_event_source *announce_event_source;
|
||||||
|
|
||||||
RateLimit ratelimit;
|
RateLimit ratelimit;
|
||||||
|
|
||||||
usec_t resend_timeout;
|
usec_t resend_timeout;
|
||||||
@ -113,3 +116,5 @@ bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name);
|
|||||||
bool dns_scope_network_good(DnsScope *s);
|
bool dns_scope_network_good(DnsScope *s);
|
||||||
|
|
||||||
int dns_scope_ifindex(DnsScope *s);
|
int dns_scope_ifindex(DnsScope *s);
|
||||||
|
|
||||||
|
void dns_scope_announce(DnsScope *scope);
|
||||||
|
@ -363,6 +363,9 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
|
|||||||
SET_FOREACH_MOVE(z, t->notify_zone_items_done, t->notify_zone_items)
|
SET_FOREACH_MOVE(z, t->notify_zone_items_done, t->notify_zone_items)
|
||||||
dns_zone_item_notify(z);
|
dns_zone_item_notify(z);
|
||||||
SWAP_TWO(t->notify_zone_items, t->notify_zone_items_done);
|
SWAP_TWO(t->notify_zone_items, t->notify_zone_items_done);
|
||||||
|
if (t->probing) {
|
||||||
|
dns_scope_announce(t->scope);
|
||||||
|
}
|
||||||
|
|
||||||
SET_FOREACH_MOVE(d, t->notify_transactions_done, t->notify_transactions)
|
SET_FOREACH_MOVE(d, t->notify_transactions_done, t->notify_transactions)
|
||||||
dns_transaction_notify(d, t);
|
dns_transaction_notify(d, t);
|
||||||
@ -1209,7 +1212,10 @@ static usec_t transaction_get_resend_timeout(DnsTransaction *t) {
|
|||||||
|
|
||||||
case DNS_PROTOCOL_MDNS:
|
case DNS_PROTOCOL_MDNS:
|
||||||
assert(t->n_attempts > 0);
|
assert(t->n_attempts > 0);
|
||||||
return (1 << (t->n_attempts - 1)) * USEC_PER_SEC;
|
if (t->probing)
|
||||||
|
return MDNS_PROBING_INTERVAL_USEC;
|
||||||
|
else
|
||||||
|
return (1 << (t->n_attempts - 1)) * USEC_PER_SEC;
|
||||||
|
|
||||||
case DNS_PROTOCOL_LLMNR:
|
case DNS_PROTOCOL_LLMNR:
|
||||||
return t->scope->resend_timeout;
|
return t->scope->resend_timeout;
|
||||||
|
@ -78,6 +78,8 @@ struct DnsTransaction {
|
|||||||
|
|
||||||
bool clamp_ttl:1;
|
bool clamp_ttl:1;
|
||||||
|
|
||||||
|
bool probing:1;
|
||||||
|
|
||||||
DnsPacket *sent, *received;
|
DnsPacket *sent, *received;
|
||||||
|
|
||||||
DnsAnswer *answer;
|
DnsAnswer *answer;
|
||||||
@ -172,10 +174,20 @@ DnsTransactionSource dns_transaction_source_from_string(const char *s) _pure_;
|
|||||||
#define MDNS_JITTER_MIN_USEC (20 * USEC_PER_MSEC)
|
#define MDNS_JITTER_MIN_USEC (20 * USEC_PER_MSEC)
|
||||||
#define MDNS_JITTER_RANGE_USEC (100 * USEC_PER_MSEC)
|
#define MDNS_JITTER_RANGE_USEC (100 * USEC_PER_MSEC)
|
||||||
|
|
||||||
|
/* mDNS probing interval, see RFC 6762 Section 8.1 */
|
||||||
|
#define MDNS_PROBING_INTERVAL_USEC (250 * USEC_PER_MSEC)
|
||||||
|
|
||||||
/* Maximum attempts to send DNS requests, across all DNS servers */
|
/* Maximum attempts to send DNS requests, across all DNS servers */
|
||||||
#define DNS_TRANSACTION_ATTEMPTS_MAX 16
|
#define DNS_TRANSACTION_ATTEMPTS_MAX 16
|
||||||
|
|
||||||
/* Maximum attempts to send LLMNR requests, see RFC 4795 Section 2.7 */
|
/* Maximum attempts to send LLMNR requests, see RFC 4795 Section 2.7 */
|
||||||
#define LLMNR_TRANSACTION_ATTEMPTS_MAX 3
|
#define LLMNR_TRANSACTION_ATTEMPTS_MAX 3
|
||||||
|
|
||||||
#define TRANSACTION_ATTEMPTS_MAX(p) ((p) == DNS_PROTOCOL_LLMNR ? LLMNR_TRANSACTION_ATTEMPTS_MAX : DNS_TRANSACTION_ATTEMPTS_MAX)
|
/* Maximum attempts to send MDNS requests, see RFC 6762 Section 8.1 */
|
||||||
|
#define MDNS_TRANSACTION_ATTEMPTS_MAX 3
|
||||||
|
|
||||||
|
#define TRANSACTION_ATTEMPTS_MAX(p) (((p) == DNS_PROTOCOL_LLMNR) ? \
|
||||||
|
LLMNR_TRANSACTION_ATTEMPTS_MAX : \
|
||||||
|
(((p) == DNS_PROTOCOL_MDNS) ? \
|
||||||
|
MDNS_TRANSACTION_ATTEMPTS_MAX : \
|
||||||
|
DNS_TRANSACTION_ATTEMPTS_MAX))
|
||||||
|
@ -196,6 +196,7 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) {
|
|||||||
goto gc;
|
goto gc;
|
||||||
|
|
||||||
i->probe_transaction = t;
|
i->probe_transaction = t;
|
||||||
|
t->probing = true;
|
||||||
|
|
||||||
if (t->state == DNS_TRANSACTION_NULL) {
|
if (t->state == DNS_TRANSACTION_NULL) {
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "resolved-manager.h"
|
#include "resolved-manager.h"
|
||||||
|
|
||||||
#define MDNS_PORT 5353
|
#define MDNS_PORT 5353
|
||||||
|
#define MDNS_ANNOUNCE_DELAY (1 * USEC_PER_SEC)
|
||||||
|
|
||||||
int manager_mdns_ipv4_fd(Manager *m);
|
int manager_mdns_ipv4_fd(Manager *m);
|
||||||
int manager_mdns_ipv6_fd(Manager *m);
|
int manager_mdns_ipv6_fd(Manager *m);
|
||||||
|
Loading…
Reference in New Issue
Block a user