mDNS: respond to probe via multicast added

The host only responded to a probe query via unicast because
according to the RFC, a probe should have the QU bit on.
This is a should and not a must so we need to be careful.
We added multicast probe answering support with the needed timouts.
Avahi for example probes with the QM queries. With this commit the
conflict is resolved.
This commit is contained in:
Jasper Verschueren 2018-11-14 15:38:36 +01:00 committed by Dirk Ziegelmeier
parent 530a4ccdce
commit 861ce296b9
4 changed files with 180 additions and 50 deletions

View File

@ -901,10 +901,11 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
reply.cache_flush = 1;
}
/* Delaying response.
/* Delaying response. (RFC6762 section 6)
* Always delay the response, unicast or multicast, except when:
* - Answering to a single question with a unique answer (RFC6762 section 6)
* - Answering to a probe query via unicast (RFC6762 section 6)
* - Answering to a single question with a unique answer (not a probe).
* - Answering to a probe query via unicast.
* - Answering to a probe query via multicast if not multicasted within 250ms.
*
* unique answer? -> not if it includes service type or name ptr's
*/
@ -912,9 +913,22 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
shared_answer |= (reply.serv_replies[i] &
(REPLY_SERVICE_TYPE_PTR | REPLY_SERVICE_NAME_PTR));
}
if (((pkt->questions == 1) && (!shared_answer)) || reply.probe_query_recv) {
if ( ((pkt->questions == 1) && (!shared_answer) && !reply.probe_query_recv)
|| (reply.probe_query_recv && reply.unicast_reply_requested)) {
delay_response = 0;
}
#if LWIP_IPV6
if (IP_IS_V6_VAL(pkt->source_addr) && reply.probe_query_recv
&& !reply.unicast_reply_requested && !mdns->ipv6.multicast_probe_timeout) {
delay_response = 0;
}
#endif
#if LWIP_IPV4
if (IP_IS_V4_VAL(pkt->source_addr) && reply.probe_query_recv
&& !reply.unicast_reply_requested && !mdns->ipv4.multicast_probe_timeout) {
delay_response = 0;
}
#endif
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: response %s delayed\r\n", (delay_response ? "randomly" : "not")));
/* Unicast / multicast response:
@ -923,7 +937,7 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
* a) Unicast reply requested && recently multicasted 1/4ttl (RFC6762 section 5.4)
* b) Direct unicast query to port 5353 (RFC6762 section 5.5)
* c) Reply to Legacy DNS querier (RFC6762 section 6.7)
* d) A probe message is received (RFC6762 section 6)
* d) A probe message is received requesting unicast (RFC6762 section 6)
*/
#if LWIP_IPV6
@ -939,7 +953,7 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
if ( (reply.unicast_reply_requested && listen_to_QU_bit)
|| pkt->recv_unicast
|| reply.legacy_query
|| reply.probe_query_recv ) {
|| (reply.probe_query_recv && reply.unicast_reply_requested)) {
send_unicast = 1;
}
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: send response via %s\r\n", (send_unicast ? "unicast" : "multicast")));
@ -984,9 +998,14 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
#if LWIP_IPV6
/* Add answers to IPv6 waiting list if:
* - it's a IPv6 incoming packet
* - and the 1 second timeout is passed (RFC6762 section 6)
* - the 1 second timeout is passed (RFC6762 section 6)
* - and it's not a probe packet
* Or if:
* - it's a IPv6 incoming packet
* - and it's a probe packet
*/
if (IP_IS_V6_VAL(pkt->source_addr) && !mdns->ipv6.multicast_timeout) {
if (IP_IS_V6_VAL(pkt->source_addr) && !mdns->ipv6.multicast_timeout
&& !reply.probe_query_recv) {
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to multicast IPv6 waiting list\r\n"));
mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_multicast, &reply);
@ -994,13 +1013,25 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_multicast_msg_delayed_ipv6,
&mdns->ipv6.multicast_msg_waiting);
}
else if (IP_IS_V6_VAL(pkt->source_addr) && reply.probe_query_recv) {
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to probe multicast IPv6 waiting list\r\n"));
mdns_add_msg_to_delayed(&mdns->ipv6.delayed_msg_multicast, &reply);
mdns->ipv6.multicast_msg_waiting = 1;
}
#endif
#if LWIP_IPV4
/* Add answers to IPv4 waiting list if:
* - it's a IPv4 incoming packet
* - and the 1 second timeout is passed (RFC6762 section 6)
* - the 1 second timeout is passed (RFC6762 section 6)
* - and it's not a probe packet
* Or if:
* - it's a IPv4 incoming packet
* - and it's a probe packet
*/
if (IP_IS_V4_VAL(pkt->source_addr) && !mdns->ipv4.multicast_timeout) {
if (IP_IS_V4_VAL(pkt->source_addr) && !mdns->ipv4.multicast_timeout
&& !reply.probe_query_recv) {
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to multicast IPv4 waiting list\r\n"));
mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_multicast, &reply);
@ -1008,6 +1039,13 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
mdns_set_timeout(netif, MDNS_RESPONSE_DELAY, mdns_send_multicast_msg_delayed_ipv4,
&mdns->ipv4.multicast_msg_waiting);
}
else if (IP_IS_V4_VAL(pkt->source_addr) && reply.probe_query_recv) {
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: add answers to probe multicast IPv4 waiting list\r\n"));
mdns_add_msg_to_delayed(&mdns->ipv4.delayed_msg_multicast, &reply);
mdns->ipv4.multicast_msg_waiting = 1;
}
#endif
}
}
@ -1030,7 +1068,7 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
/* Set IP/port to use when responding multicast */
#if LWIP_IPV6
if (IP_IS_V6_VAL(pkt->source_addr)) {
if (mdns->ipv6.multicast_timeout) {
if (mdns->ipv6.multicast_timeout && !reply.probe_query_recv) {
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: we just multicasted, ignore question\r\n"));
return;
}
@ -1039,7 +1077,7 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
#endif
#if LWIP_IPV4
if (IP_IS_V4_VAL(pkt->source_addr)) {
if (mdns->ipv4.multicast_timeout) {
if (mdns->ipv4.multicast_timeout && !reply.probe_query_recv) {
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: we just multicasted, ignore question\r\n"));
return;
}
@ -1056,22 +1094,12 @@ mdns_handle_question(struct mdns_packet *pkt, struct netif *netif)
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Multicast answer send successfully\r\n"));
#if LWIP_IPV6
if (IP_IS_V6_VAL(pkt->source_addr)) {
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv6,
&mdns->ipv6.multicast_timeout);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv6\n"));
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv6,
&mdns->ipv6.multicast_timeout_25TTL);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv6\n"));
mdns_start_multicast_timeouts_ipv6(netif);
}
#endif
#if LWIP_IPV4
if (IP_IS_V4_VAL(pkt->source_addr)) {
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv4,
&mdns->ipv4.multicast_timeout);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv4\n"));
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv4,
&mdns->ipv4.multicast_timeout_25TTL);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv4\n"));
mdns_start_multicast_timeouts_ipv4(netif);
}
#endif
}
@ -1689,22 +1717,12 @@ mdns_resp_announce(struct netif *netif)
/* Announce on IPv6 and IPv4 */
#if LWIP_IPV6
mdns_announce(netif, &v6group);
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv6,
&mdns->ipv6.multicast_timeout);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv6\n"));
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv6,
&mdns->ipv6.multicast_timeout_25TTL);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv6\n"));
mdns_start_multicast_timeouts_ipv6(netif);
#endif
#if LWIP_IPV4
if (!ip4_addr_isany_val(*netif_ip4_addr(netif))) {
mdns_announce(netif, &v4group);
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv4,
&mdns->ipv4.multicast_timeout);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv4\n"));
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv4,
&mdns->ipv4.multicast_timeout_25TTL);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv4\n"));
mdns_start_multicast_timeouts_ipv4(netif);
}
#endif
} /* else: ip address changed while probing was ongoing? @todo reset counter to restart? */

View File

@ -775,6 +775,37 @@ mdns_multicast_timeout_reset_ipv4(void *arg)
mdns->ipv4.multicast_timeout = 0;
}
/**
* Called by timeouts when timer is passed, allows direct multicast IPv4 probe
* response traffic again and sends out probe response if one was pending
*
* @param arg pointer to netif of timeout.
*/
void
mdns_multicast_probe_timeout_reset_ipv4(void *arg)
{
struct netif *netif = (struct netif*)arg;
struct mdns_host *mdns = netif_mdns_data(netif);
err_t res;
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout finished - IPv4\n"));
mdns->ipv4.multicast_probe_timeout = 0;
if (mdns->ipv4.multicast_msg_waiting) {
res = mdns_send_outpacket(&mdns->ipv4.delayed_msg_multicast, netif);
if(res != ERR_OK) {
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send failed - IPv4\n"));
}
else {
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send successful - IPv4\n"));
mdns_clear_outmsg(&mdns->ipv4.delayed_msg_multicast);
mdns->ipv4.multicast_msg_waiting = 0;
mdns_start_multicast_timeouts_ipv4(netif);
}
}
}
/**
* Called by timeouts when timer is passed, allows to send an answer on a QU
* question via multicast.
@ -812,12 +843,7 @@ mdns_send_multicast_msg_delayed_ipv4(void *arg)
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send successful - IPv4\n"));
mdns_clear_outmsg(&mdns->ipv4.delayed_msg_multicast);
mdns->ipv4.multicast_msg_waiting = 0;
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv4,
&mdns->ipv4.multicast_timeout);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv4\n"));
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv4,
&mdns->ipv4.multicast_timeout_25TTL);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv4\n"));
mdns_start_multicast_timeouts_ipv4(netif);
}
}
@ -844,6 +870,29 @@ mdns_send_unicast_msg_delayed_ipv4(void *arg)
}
}
/** Start all multicast timeouts for IPv4
* Timeouts started:
* - do not multicast within one second
* - do not multicast a probe response within 250ms
* - send a multicast answer on a QU question if not send recently.
*
* @param netif network interface to start timeouts on
*/
void
mdns_start_multicast_timeouts_ipv4(struct netif *netif)
{
struct mdns_host *mdns = netif_mdns_data(netif);
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv4,
&mdns->ipv4.multicast_timeout);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv4\n"));
mdns_set_timeout(netif, MDNS_MULTICAST_PROBE_TIMEOUT, mdns_multicast_probe_timeout_reset_ipv4,
&mdns->ipv4.multicast_probe_timeout);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout started - IPv4\n"));
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv4,
&mdns->ipv4.multicast_timeout_25TTL);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv4\n"));
}
#endif
#if LWIP_IPV6
@ -863,6 +912,37 @@ mdns_multicast_timeout_reset_ipv6(void *arg)
mdns->ipv6.multicast_timeout = 0;
}
/**
* Called by timeouts when timer is passed, allows direct multicast IPv6 probe
* response traffic again and sends out probe response if one was pending
*
* @param arg pointer to netif of timeout.
*/
void
mdns_multicast_probe_timeout_reset_ipv6(void *arg)
{
struct netif *netif = (struct netif*)arg;
struct mdns_host *mdns = netif_mdns_data(netif);
err_t res;
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout finished - IPv6\n"));
mdns->ipv6.multicast_probe_timeout = 0;
if (mdns->ipv6.multicast_msg_waiting) {
res = mdns_send_outpacket(&mdns->ipv6.delayed_msg_multicast, netif);
if(res != ERR_OK) {
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send failed - IPv6\n"));
}
else {
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Waiting probe multicast send successful - IPv6\n"));
mdns_clear_outmsg(&mdns->ipv6.delayed_msg_multicast);
mdns->ipv6.multicast_msg_waiting = 0;
mdns_start_multicast_timeouts_ipv6(netif);
}
}
}
/**
* Called by timeouts when timer is passed, allows to send an answer on a QU
* question via multicast.
@ -900,12 +980,7 @@ mdns_send_multicast_msg_delayed_ipv6(void *arg)
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Delayed multicast send successful - IPv6\n"));
mdns_clear_outmsg(&mdns->ipv6.delayed_msg_multicast);
mdns->ipv6.multicast_msg_waiting = 0;
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv6,
&mdns->ipv6.multicast_timeout);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv6\n"));
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv6,
&mdns->ipv6.multicast_timeout_25TTL);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv6\n"));
mdns_start_multicast_timeouts_ipv6(netif);
}
}
@ -932,6 +1007,29 @@ mdns_send_unicast_msg_delayed_ipv6(void *arg)
}
}
/** Start all multicast timeouts for IPv6
* Timeouts started:
* - do not multicast within one second
* - do not multicast a probe response within 250ms
* - send a multicast answer on a QU question if not send recently.
*
* @param netif network interface to start timeouts on
*/
void
mdns_start_multicast_timeouts_ipv6(struct netif *netif)
{
struct mdns_host *mdns = netif_mdns_data(netif);
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT, mdns_multicast_timeout_reset_ipv6,
&mdns->ipv6.multicast_timeout);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout started - IPv6\n"));
mdns_set_timeout(netif, MDNS_MULTICAST_PROBE_TIMEOUT, mdns_multicast_probe_timeout_reset_ipv6,
&mdns->ipv6.multicast_probe_timeout);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast probe timeout started - IPv6\n"));
mdns_set_timeout(netif, MDNS_MULTICAST_TIMEOUT_25TTL, mdns_multicast_timeout_25ttl_reset_ipv6,
&mdns->ipv6.multicast_timeout_25TTL);
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: multicast timeout 1/4 of ttl started - IPv6\n"));
}
#endif
/**

View File

@ -83,6 +83,14 @@ extern "C" {
*/
#define MDNS_MULTICAST_TIMEOUT 1000
/* RFC6762 section 6:
* In this special case only, when responding via multicast to a probe, a
* Multicast DNS responder is only required to delay its transmission as
* necessary to ensure an interval of at least 250 ms since the last time the
* record was multicast on that interface.
*/
#define MDNS_MULTICAST_PROBE_TIMEOUT 250
/* RFC6762 section 5.4:
* When receiving a question with the unicast-response bit set, a responder
* SHOULD usually respond with a unicast packet directed back to the querier.
@ -100,15 +108,19 @@ void mdns_set_timeout(struct netif *netif, u32_t msecs,
sys_timeout_handler handler, u8_t *busy_flag);
#if LWIP_IPV4
void mdns_multicast_timeout_reset_ipv4(void *arg);
void mdns_multicast_probe_timeout_reset_ipv4(void *arg);
void mdns_multicast_timeout_25ttl_reset_ipv4(void *arg);
void mdns_send_multicast_msg_delayed_ipv4(void *arg);
void mdns_send_unicast_msg_delayed_ipv4(void *arg);
void mdns_start_multicast_timeouts_ipv4(struct netif *netif);
#endif
#if LWIP_IPV6
void mdns_multicast_timeout_reset_ipv6(void *arg);
void mdns_multicast_probe_timeout_reset_ipv6(void *arg);
void mdns_multicast_timeout_25ttl_reset_ipv6(void *arg);
void mdns_send_multicast_msg_delayed_ipv6(void *arg);
void mdns_send_unicast_msg_delayed_ipv6(void *arg);
void mdns_start_multicast_timeouts_ipv6(struct netif *netif);
#endif
void mdns_prepare_txtdata(struct mdns_service *service);

View File

@ -145,10 +145,12 @@ struct mdns_outmsg {
/** Delayed msg info */
struct mdns_delayed_msg {
/** Timer state multicast */
/** Signals if a multicast msg needs to be send out */
u8_t multicast_msg_waiting;
/** Multicast timeout on */
/** Multicast timeout for all multicast traffic except probe answers */
u8_t multicast_timeout;
/** Multicast timeout only for probe answers */
u8_t multicast_probe_timeout;
/** Output msg used for delayed multicast responses */
struct mdns_outmsg delayed_msg_multicast;
/** Prefer multicast over unicast timeout -> 25% of TTL = we take 30s as