mirror of
https://git.savannah.nongnu.org/git/lwip.git
synced 2025-08-04 21:44:38 +08:00
mDNS: conflict resolution added
If the host observes a response (after probing) containing RR's that he thought were unique to him, there is a conflict. If a host observes such conflict, it resets back to probing and the probing procedures will resolve the conflict. (RFC6762 section 9)
This commit is contained in:
parent
3bd84aba4b
commit
ee1bab3411
@ -1682,13 +1682,18 @@ mdns_probe_conflict(struct netif *netif)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle response MDNS packet
|
* Handle response MDNS packet:
|
||||||
* Only prints debug for now. Will need more code to do conflict resolution.
|
* - Handle responses on probe query
|
||||||
|
* - Perform conflict resolution on every packet (RFC6762 section 9)
|
||||||
|
*
|
||||||
|
* @param pkt incoming packet
|
||||||
|
* @param netif network interface on which packet was received
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
mdns_handle_response(struct mdns_packet *pkt, struct netif *netif)
|
mdns_handle_response(struct mdns_packet *pkt, struct netif *netif)
|
||||||
{
|
{
|
||||||
struct mdns_host* mdns = NETIF_TO_HOST(netif);
|
struct mdns_host* mdns = NETIF_TO_HOST(netif);
|
||||||
|
u16_t total_answers_left;
|
||||||
|
|
||||||
/* Ignore responses with a source port different from 5353
|
/* Ignore responses with a source port different from 5353
|
||||||
* (LWIP_IANA_PORT_MDNS) -> RFC6762 section 6 */
|
* (LWIP_IANA_PORT_MDNS) -> RFC6762 section 6 */
|
||||||
@ -1707,12 +1712,13 @@ mdns_handle_response(struct mdns_packet *pkt, struct netif *netif)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* We need to check all resource record sections: answers, authoritative and additional */
|
||||||
while (pkt->answers_left) {
|
total_answers_left = pkt->answers_left + pkt->authoritative_left + pkt->additional_left;
|
||||||
|
while (total_answers_left) {
|
||||||
struct mdns_answer ans;
|
struct mdns_answer ans;
|
||||||
err_t res;
|
err_t res;
|
||||||
|
|
||||||
res = mdns_read_answer(pkt, &ans, &pkt->answers_left);
|
res = mdns_read_answer(pkt, &ans, &total_answers_left);
|
||||||
if (res != ERR_OK) {
|
if (res != ERR_OK) {
|
||||||
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping response packet\n"));
|
LWIP_DEBUGF(MDNS_DEBUG, ("MDNS: Failed to parse answer, skipping response packet\n"));
|
||||||
return;
|
return;
|
||||||
@ -1722,6 +1728,11 @@ mdns_handle_response(struct mdns_packet *pkt, struct netif *netif)
|
|||||||
mdns_domain_debug_print(&ans.info.domain);
|
mdns_domain_debug_print(&ans.info.domain);
|
||||||
LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass));
|
LWIP_DEBUGF(MDNS_DEBUG, (" type %d class %d\n", ans.info.type, ans.info.klass));
|
||||||
|
|
||||||
|
if (ans.info.type == DNS_RRTYPE_ANY || ans.info.klass != DNS_RRCLASS_IN) {
|
||||||
|
/* Skip answers for ANY type or if class != IN */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* "Conflicting Multicast DNS responses received *before* the first probe
|
/* "Conflicting Multicast DNS responses received *before* the first probe
|
||||||
* packet is sent MUST be silently ignored" so drop answer if we haven't
|
* packet is sent MUST be silently ignored" so drop answer if we haven't
|
||||||
* started probing yet. */
|
* started probing yet. */
|
||||||
@ -1751,9 +1762,123 @@ mdns_handle_response(struct mdns_packet *pkt, struct netif *netif)
|
|||||||
|
|
||||||
if (conflict != 0) {
|
if (conflict != 0) {
|
||||||
mdns_probe_conflict(netif);
|
mdns_probe_conflict(netif);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Perform conflict resolution (RFC6762 section 9):
|
||||||
|
* We assume a conflict if the hostname or service name matches the answers
|
||||||
|
* domain. Only if the rdata matches exactly we reset our assumption to no
|
||||||
|
* conflict. As stated in the RFC:
|
||||||
|
* What may be considered inconsistent is context sensitive, except that
|
||||||
|
* resource records with identical rdata are never considered inconsistent,
|
||||||
|
* even if they originate from different hosts.
|
||||||
|
*/
|
||||||
|
else if ((mdns->state == MDNS_STATE_ANNOUNCING) ||
|
||||||
|
(mdns->state == MDNS_STATE_COMPLETE)) {
|
||||||
|
struct mdns_domain domain;
|
||||||
|
u8_t i;
|
||||||
|
u8_t conflict = 0;
|
||||||
|
|
||||||
|
/* Evaluate unique hostname records -> A and AAAA */
|
||||||
|
res = mdns_build_host_domain(&domain, mdns);
|
||||||
|
if (res == ERR_OK && mdns_domain_eq(&ans.info.domain, &domain)) {
|
||||||
|
LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response matches host domain, assuming conflict\n"));
|
||||||
|
/* This means a conflict has taken place, except when the packet contains
|
||||||
|
* exactly the same rdata. */
|
||||||
|
conflict = 1;
|
||||||
|
/* Evaluate rdata -> to see if it's a copy of our own data */
|
||||||
|
if (ans.info.type == DNS_RRTYPE_A) {
|
||||||
|
#if LWIP_IPV4
|
||||||
|
if (ans.rd_length == sizeof(ip4_addr_t) &&
|
||||||
|
pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip4_addr(netif), ans.rd_length) == 0) {
|
||||||
|
LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own IPv4 address record -> no conflict\n"));
|
||||||
|
conflict = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (ans.info.type == DNS_RRTYPE_AAAA) {
|
||||||
|
#if LWIP_IPV6
|
||||||
|
if (ans.rd_length == sizeof(ip6_addr_p_t)) {
|
||||||
|
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
||||||
|
if (pbuf_memcmp(pkt->pbuf, ans.rd_offset, netif_ip6_addr(netif, i), ans.rd_length) == 0) {
|
||||||
|
LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own iPv6 address record, num = %d -> no conflict\n",i));
|
||||||
|
conflict = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Evaluate unique service name records -> SRV and TXT */
|
||||||
|
for (i = 0; i < MDNS_MAX_SERVICES; i++) {
|
||||||
|
struct mdns_service* service = mdns->services[i];
|
||||||
|
if (!service) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
res = mdns_build_service_domain(&domain, service, 1);
|
||||||
|
if ((res == ERR_OK) && mdns_domain_eq(&ans.info.domain, &domain)) {
|
||||||
|
LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response matches service domain, assuming conflict\n"));
|
||||||
|
/* This means a conflict has taken place, except when the packet contains
|
||||||
|
* exactly the same rdata. */
|
||||||
|
conflict = 1;
|
||||||
|
/* Evaluate rdata -> to see if it's a copy of our own data */
|
||||||
|
if (ans.info.type == DNS_RRTYPE_SRV) {
|
||||||
|
/* Read and compare to with our SRV record */
|
||||||
|
u16_t field16, len, read_pos;
|
||||||
|
struct mdns_domain srv_ans, my_ans;
|
||||||
|
read_pos = ans.rd_offset;
|
||||||
|
do {
|
||||||
|
/* Check priority field */
|
||||||
|
len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
|
||||||
|
if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_PRIORITY) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
read_pos += len;
|
||||||
|
/* Check weight field */
|
||||||
|
len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
|
||||||
|
if (len != sizeof(field16) || lwip_ntohs(field16) != SRV_WEIGHT) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
read_pos += len;
|
||||||
|
/* Check port field */
|
||||||
|
len = pbuf_copy_partial(pkt->pbuf, &field16, sizeof(field16), read_pos);
|
||||||
|
if (len != sizeof(field16) || lwip_ntohs(field16) != service->port) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
read_pos += len;
|
||||||
|
/* Check host field */
|
||||||
|
len = mdns_readname(pkt->pbuf, read_pos, &srv_ans);
|
||||||
|
mdns_build_host_domain(&my_ans, mdns);
|
||||||
|
if (len == MDNS_READNAME_ERROR || !mdns_domain_eq(&srv_ans, &my_ans)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own SRV record -> no conflict\n"));
|
||||||
|
conflict = 0;
|
||||||
|
} while (0);
|
||||||
|
} else if (ans.info.type == DNS_RRTYPE_TXT) {
|
||||||
|
mdns_prepare_txtdata(service);
|
||||||
|
if (service->txtdata.length == ans.rd_length &&
|
||||||
|
pbuf_memcmp(pkt->pbuf, ans.rd_offset, service->txtdata.name, ans.rd_length) == 0) {
|
||||||
|
LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: response equals our own TXT record -> no conflict\n"));
|
||||||
|
conflict = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (conflict != 0) {
|
||||||
|
/* Reset host to probing to reconfirm uniqueness */
|
||||||
|
LWIP_DEBUGF(MDNS_DEBUG, ("mDNS: Conflict resolution -> reset to probing state\n"));
|
||||||
|
mdns->state = MDNS_STATE_PROBE_WAIT;
|
||||||
|
mdns->sent_num = 0;
|
||||||
|
sys_timeout(MDNS_INITIAL_PROBE_DELAY_MS, mdns_probe_and_announce, netif);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Clear all xxx_left variables because we parsed all answers */
|
||||||
|
pkt->answers_left = 0;
|
||||||
|
pkt->authoritative_left = 0;
|
||||||
|
pkt->additional_left = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user