Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(mdns): Parse messages using trust-dns-proto instead of dns-parse #3102

Merged
merged 7 commits into from
Nov 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions protocols/mdns/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

- Update to `libp2p-swarm` `v0.41.0`.

- Use `trust-dns-proto` to parse DNS messages. See [PR 3102].

[PR 3102]: https://github.com/libp2p/rust-libp2p/pull/3102

# 0.41.0

- Remove default features. If you previously depended on `async-io` you need to enable this explicitly now. See [PR 2918].
Expand Down
7 changes: 3 additions & 4 deletions protocols/mdns/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ keywords = ["peer-to-peer", "libp2p", "networking"]
categories = ["network-programming", "asynchronous"]

[dependencies]
async-io = { version = "1.3.1", optional = true }
data-encoding = "2.3.2"
dns-parser = "0.8.0"
futures = "0.3.13"
if-watch = "2.0.0"
libp2p-core = { version = "0.38.0", path = "../../core" }
Expand All @@ -21,10 +21,9 @@ log = "0.4.14"
rand = "0.8.3"
smallvec = "1.6.1"
socket2 = { version = "0.4.0", features = ["all"] }
void = "1.0.2"

async-io = { version = "1.3.1", optional = true }
tokio = { version = "1.19", default-features = false, features = ["net", "time"], optional = true}
trust-dns-proto = { version = "0.22.0", default-features = false, features = ["mdns"] }
void = "1.0.2"

[features]
tokio = ["dep:tokio"]
Expand Down
8 changes: 4 additions & 4 deletions protocols/mdns/src/behaviour/iface/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,14 +395,14 @@ impl error::Error for MdnsResponseError {}
#[cfg(test)]
mod tests {
use super::*;
use dns_parser::Packet;
use libp2p_core::identity;
use std::time::Duration;
use trust_dns_proto::op::Message;

#[test]
fn build_query_correct() {
let query = build_query();
assert!(Packet::parse(&query).is_ok());
assert!(Message::from_vec(&query).is_ok());
}

#[test]
Expand All @@ -417,14 +417,14 @@ mod tests {
Duration::from_secs(60),
);
for packet in packets {
assert!(Packet::parse(&packet).is_ok());
assert!(Message::from_vec(&packet).is_ok());
}
}

#[test]
fn build_service_discovery_response_correct() {
let query = build_service_discovery_response(0x1234, Duration::from_secs(120));
assert!(Packet::parse(&query).is_ok());
assert!(Message::from_vec(&query).is_ok());
}

#[test]
Expand Down
57 changes: 30 additions & 27 deletions protocols/mdns/src/behaviour/iface/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@
// DEALINGS IN THE SOFTWARE.

use super::dns;
use crate::{META_QUERY_SERVICE, SERVICE_NAME};
use dns_parser::{Packet, RData};
use crate::{META_QUERY_SERVICE_FQDN, SERVICE_NAME_FQDN};
use libp2p_core::{
address_translation,
multiaddr::{Multiaddr, Protocol},
PeerId,
};
use std::time::Instant;
use std::{convert::TryFrom, fmt, net::SocketAddr, str, time::Duration};
use trust_dns_proto::{
op::Message,
rr::{Name, RData},
};

/// A valid mDNS packet received by the service.
#[derive(Debug)]
Expand All @@ -44,33 +47,33 @@ impl MdnsPacket {
pub fn new_from_bytes(
buf: &[u8],
from: SocketAddr,
) -> Result<Option<MdnsPacket>, dns_parser::Error> {
let packet = Packet::parse(buf)?;
) -> Result<Option<MdnsPacket>, trust_dns_proto::error::ProtoError> {
let packet = Message::from_vec(buf)?;

if !packet.header.query {
return Ok(Some(MdnsPacket::Response(MdnsResponse::new(packet, from))));
if packet.query().is_none() {
return Ok(Some(MdnsPacket::Response(MdnsResponse::new(&packet, from))));
}

if packet
.questions
.queries()
.iter()
.any(|q| q.qname.to_string().as_bytes() == SERVICE_NAME)
.any(|q| q.name().to_utf8() == SERVICE_NAME_FQDN)
{
return Ok(Some(MdnsPacket::Query(MdnsQuery {
from,
query_id: packet.header.id,
query_id: packet.header().id(),
})));
}

if packet
.questions
.queries()
.iter()
.any(|q| q.qname.to_string().as_bytes() == META_QUERY_SERVICE)
.any(|q| q.name().to_utf8() == META_QUERY_SERVICE_FQDN)
{
// TODO: what if multiple questions, one with SERVICE_NAME and one with META_QUERY_SERVICE?
return Ok(Some(MdnsPacket::ServiceDiscovery(MdnsServiceDiscovery {
from,
query_id: packet.header.id,
query_id: packet.header().id(),
})));
}

Expand Down Expand Up @@ -144,21 +147,21 @@ pub struct MdnsResponse {

impl MdnsResponse {
/// Creates a new `MdnsResponse` based on the provided `Packet`.
pub fn new(packet: Packet<'_>, from: SocketAddr) -> MdnsResponse {
pub fn new(packet: &Message, from: SocketAddr) -> MdnsResponse {
let peers = packet
.answers
.answers()
.iter()
.filter_map(|record| {
if record.name.to_string().as_bytes() != SERVICE_NAME {
if record.name().to_string() != SERVICE_NAME_FQDN {
return None;
}

let record_value = match record.data {
RData::PTR(record) => record.0.to_string(),
let record_value = match record.data() {
Some(RData::PTR(record)) => record,
_ => return None,
};

MdnsPeer::new(&packet, record_value, record.ttl)
MdnsPeer::new(packet, record_value, record.ttl())
})
.collect();

Expand Down Expand Up @@ -225,17 +228,17 @@ pub struct MdnsPeer {

impl MdnsPeer {
/// Creates a new `MdnsPeer` based on the provided `Packet`.
pub fn new(packet: &Packet<'_>, record_value: String, ttl: u32) -> Option<MdnsPeer> {
pub fn new(packet: &Message, record_value: &Name, ttl: u32) -> Option<MdnsPeer> {
let mut my_peer_id: Option<PeerId> = None;
let addrs = packet
.additional
.additionals()
.iter()
.filter_map(|add_record| {
if add_record.name.to_string() != record_value {
if add_record.name() != record_value {
return None;
}

if let RData::TXT(ref txt) = add_record.data {
if let Some(RData::TXT(ref txt)) = add_record.data() {
Some(txt)
} else {
None
Expand Down Expand Up @@ -337,16 +340,16 @@ mod tests {
);

for bytes in packets {
let packet = Packet::parse(&bytes).expect("unable to parse packet");
let packet = Message::from_vec(&bytes).expect("unable to parse packet");
let record_value = packet
.answers
.answers()
.iter()
.filter_map(|record| {
if record.name.to_string().as_bytes() != SERVICE_NAME {
if record.name().to_utf8() != SERVICE_NAME_FQDN {
return None;
}
let record_value = match record.data {
RData::PTR(record) => record.0.to_string(),
let record_value = match record.data() {
Some(RData::PTR(record)) => record,
_ => return None,
};
Some(record_value)
Expand Down
4 changes: 4 additions & 0 deletions protocols/mdns/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,12 @@ pub use crate::behaviour::TokioMdns;

/// The DNS service name for all libp2p peers used to query for addresses.
const SERVICE_NAME: &[u8] = b"_p2p._udp.local";
/// `SERVICE_NAME` as a Fully Qualified Domain Name.
const SERVICE_NAME_FQDN: &str = "_p2p._udp.local.";
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved
/// The meta query for looking up the `SERVICE_NAME`.
const META_QUERY_SERVICE: &[u8] = b"_services._dns-sd._udp.local";
/// `META_QUERY_SERVICE` as a Fully Qualified Domain Name.
const META_QUERY_SERVICE_FQDN: &str = "_services._dns-sd._udp.local.";

pub const IPV4_MDNS_MULTICAST_ADDRESS: Ipv4Addr = Ipv4Addr::new(224, 0, 0, 251);
pub const IPV6_MDNS_MULTICAST_ADDRESS: Ipv6Addr = Ipv6Addr::new(0xFF02, 0, 0, 0, 0, 0, 0, 0xFB);
Expand Down