-
Notifications
You must be signed in to change notification settings - Fork 999
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
Add libp2p-mdns #590
Add libp2p-mdns #590
Conversation
Disabled |
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
// DEALINGS IN THE SOFTWARE. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Module docs?
append_txt_record(&mut out, &peer_id_bytes, ttl, Some(&txt_to_send_bytes[..]))?; | ||
} | ||
|
||
if out.len() > 9000 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is 9000
from the spec or simply an empirically found reasonable upper limit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the specs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then I'd make it a const
. Or a comment.
cmp::min(secs, From::from(u32::max_value())) as u32 | ||
} | ||
|
||
/// Appends a big-endian u32 to `out`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you prefer to not use the byteorder
crate for the append_*
methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The methods of byteorder
return a Result
, which is not great.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about:
fn append_u32(out: &mut Vec<u8>, value: u32) {
let n = out.len();
out.resize(n + 4, 0);
BE::write_u32(&mut out[n ..], value)
}
BE
is an alias for byteorder::BigEndian
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, to me the point of using byteorder
is to make the code more straight-forward to read, and that doesn't.
let builder = net2::UdpBuilder::new_v4()?; | ||
builder.reuse_address(true)?; | ||
platform_specific(&builder)?; | ||
builder.bind(("0.0.0.0", 5353))? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using a const MDNS_PORT
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mDNS is an old and well-established standard, and there's 0 chance that the port changes in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was more of a readability concern – easier to read than just the number imo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RFC 6762 states that "[...] using UDP source port 5353 signals the presence of a fully compliant Multicast DNS querier [...]" which this crate is not. Queriers issuing one-shot queries must not use source port 5353.
let socket = UdpSocket::from_std(socket, &Handle::default())?; | ||
socket.set_multicast_loop_v4(true)?; | ||
socket.set_multicast_ttl_v4(255)?; | ||
// TODO: correct interfaces? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, 224.0.0.251 should be right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not about the IP here but about 0.0.0.0
.
Some mDNS examples enumerate the interfaces available on the machine and create a socket for each one of them. However there is no cross-platform way to do that at the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docs here indicate that it should be fine to use 0.0.0.0
, but maybe not ideal for IPv4:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be fine. Going to remove that TODO.
misc/mdns/src/lib.rs
Outdated
pub enum MdnsPacket<'a> { | ||
/// A query made by a remote. | ||
Query(MdnsQuery<'a>), | ||
/// A response received by a remote to one of our queries. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it A response **sent** by a remote in answer to one of our queries.
?
misc/mdns/src/lib.rs
Outdated
/// | ||
/// Pass the ID of the local peer, and the list o addresses we're listening on. | ||
/// | ||
/// If there are more than 2^16-1 addresses, ignores the other. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/other/others/
misc/mdns/src/dns.rs
Outdated
|
||
/// Decodes a `<character-string>` (as defined by RFC1035) into a `Vec` of ASCII characters. | ||
// TODO: better error type? | ||
pub fn decode_character_string(mut from: &[u8]) -> Result<Vec<u8>, ()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why allocating a vector? As currently implemented, this could just return the sub-slice. The current use site parses the result as a str
and turns it into a Multiaddr
which will allocate another vector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not implemented, but we need to turn \\
into \
and \"
into "
.
Since it's quite unlikely to happen in practice, I'm going to use a Cow
though.
cmp::min(secs, From::from(u32::max_value())) as u32 | ||
} | ||
|
||
/// Appends a big-endian u32 to `out`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about:
fn append_u32(out: &mut Vec<u8>, value: u32) {
let n = out.len();
out.resize(n + 4, 0);
BE::write_u32(&mut out[n ..], value)
}
BE
is an alias for byteorder::BigEndian
.
let builder = net2::UdpBuilder::new_v4()?; | ||
builder.reuse_address(true)?; | ||
platform_specific(&builder)?; | ||
builder.bind(("0.0.0.0", 5353))? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RFC 6762 states that "[...] using UDP source port 5353 signals the presence of a fully compliant Multicast DNS querier [...]" which this crate is not. Queriers issuing one-shot queries must not use source port 5353.
misc/mdns/src/dns.rs
Outdated
|
||
append_u16(&mut out, id); | ||
// Flags ; 0x80 for an answer. | ||
append_u16(&mut out, 0x8000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should AA
not be set to 1?
misc/mdns/src/dns.rs
Outdated
|
||
// Flags. | ||
out.push(0x00); | ||
out.push(0x0c); // PTR record. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since type is 16bit, why not append_u16(&mut out, 0xc)
as you did elsewhere?
misc/mdns/src/dns.rs
Outdated
out.push(0x00); | ||
out.push(0x0c); // PTR record. | ||
out.push(0x80); | ||
out.push(0x01); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What class value is this?
|
||
/// Polls the service for packets. | ||
pub fn poll(&mut self) -> Async<MdnsPacket> { | ||
// Send a query every time `query_interval` fires. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to RFC 6762, exponential delays should be used for continuous querying and queries should include known answers to not cause unnecessary re-transmissions and elevated network traffic.
peer_id: PeerId, | ||
addresses: TAddresses, | ||
ttl: Duration, | ||
) -> Result<(), MdnsResponseError> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should responders not probe and announce on startup (cf. RFC 6762, section 8)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be really great to avoid having to figure out the IP address of our network interfaces, as there's no easy cross-platform way to do that.
If the specs allow avoiding that, it would be great.
return Async::NotReady; | ||
} | ||
} else { | ||
return Async::Ready(MdnsPacket::Response(MdnsResponse { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC, it is trivial for an adversary to inject itself into to the set of listen addresses of another peer just by answering queries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, by design it's not secure.
misc/mdns/src/lib.rs
Outdated
socket.set_multicast_loop_v4(true)?; | ||
socket.set_multicast_ttl_v4(255)?; | ||
// TODO: correct interfaces? | ||
socket.join_multicast_v4(&From::from([224, 0, 0, 251]), &From::from([0, 0, 0, 0]))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use std::net::Ipv4Addr::UNSPECIFIED
here.
misc/mdns/src/dns.rs
Outdated
|
||
// Flags. | ||
append_u16(&mut out, 0x000c); | ||
append_u16(&mut out, 0x8001); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC this sets the flush-cache bit saying that this record is the sole truth. I guess this implies that this responder owns the name and no other responder is expected to answer that query.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I set this to 0x8000
, then the dnsparser
crate is incapable of parsing the response w generate. Not sure why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without the flush-cache-bit you would use 1 (internet class).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, ok!
Implements libp2p/specs#80
Allows automatically discovering other nodes on the same local network.