keepsimple1 / mdns-sd

Rust library for mDNS based Service Discovery
Apache License 2.0
88 stars 38 forks source link

Add support for traffic reduction techniques from RFC6762, sec. 7 #193

Open oysteintveit-nordicsemi opened 2 months ago

oysteintveit-nordicsemi commented 2 months ago

(I made a small comment about this in #192, but I thought it would be better to create a proper issue)

RFC6762 includes a whole section on techniques to reduce network traffic. The current implementation works fine without these techniques - the daemon will properly answer anyone requesting service details, and it's able to query for service details just fine. However, it is wasteful and it's technically not compliant with the RFC due to the MUST requirements.

I'll include some extracts of the contents in the RFC, and roughly what needs to be done in the points below.

Sec. 7.1 - Known Answer Suppression (MUST)

When a Multicast DNS querier sends a query to which it already knows some answers, it populates the Answer Section of the DNS query message with those answers.

I see there's a method DnsOutgoing::add_additional_answer that seems to be able to write answers to any question packet, so I believe the only missing piece is to fetch any relevant non-expired records from the dns cache, and add it to any outgoing packets.

Sec. 7.2 - Multipacket Known Answer Suppression (MUST)

Sometimes a Multicast DNS querier will already have too many answers to fit in the Known-Answer Section of its query packets. In this case, it should issue a Multicast DNS query containing a question and as many Known-Answer records as will fit. It MUST then set the TC (Truncated) bit in the header before sending the query. It MUST immediately follow the packet with another query packet containing no questions and as many more Known-Answer records as will fit. [...]

A Multicast DNS responder seeing a Multicast DNS query with the TC bit set defers its response for a time period randomly selected in the interval 400-500 ms. [...]

This seems like it will require some more work. Maybe it would be best to rethink the DnsOutgoing and DnsIncoming as an abstraction between the DNS packets (DnsOutPacket and a potential DnsInPacket) and the ServiceDaemon, that can take an arbitrary amount of questions and answers, and de/serialize it from/into one or more DnsOutPacket/DnsInPacket? The ServiceDaemon would then keep track of these unfinished DnsIncoming packets, create or extend them while receiving packets, and then process any finished ones afterwards? (Although, it would be nice if it also could somehow interact with unfinished packets, to comply better with the recommendations in 7.3 and 7.4)

Sec. 7.3 - Duplicate Question Suppression (SHOULD)

If a host is planning to transmit (or retransmit) a query, and it sees another host on the network send a query containing the same "QM" question, and the Known-Answer Section of that query does not contain any records that this host would not also put in its own Known-Answer Section, then this host SHOULD treat its own query as having been sent.

If I'm reading this correctly, it would require the run loop to keep track of any incoming queries and compare them with its own outgoing queries, removing the matching ones. It can drop this table after every iteration of the run loop (with the exception of partial packets)? It should probably still add itself to the retransmission queue, and add a new timer.

Sec. 7.4 - Duplicate Answer Suppression (SHOULD)

If a host is planning to send an answer, and it sees another host on the network send a response message containing the same answer record, and the TTL in that record is not less than the TTL this host would have given, then this host SHOULD treat its own answer as having been sent, and not also send an identical answer itself.

Same as with 7.3, only keeping track of answers instead of queries. No retransmissions required.