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

Implemented unicast responses to direct unicast, unicast questions and legacy unicast queries. #190

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ if-addrs = { version = "0.10", features = ["link-local"] } # get local IP addres
log = { version = "0.4", optional = true } # logging
polling = "2.1" # select/poll sockets
socket2 = { version = "0.5.5", features = ["all"] } # socket APIs
socket-pktinfo = { version = "0.2.1" } # socket packet info extension

[dev-dependencies]
fastrand = "1.8"
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ This implementation is based on the following RFCs:

This is still beta software. We focus on the common use cases at hand. And we tested with some existing common tools (e.g. `Avahi` on Linux, `dns-sd` on MacOS, and `Bonjour` library on iOS) to verify the basic compatibility.

Currently this library has the following limitations:
- Only support multicast, no unicast send/recv.

## License

Licensed under either of
Expand Down
31 changes: 22 additions & 9 deletions src/dns_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ pub(crate) const TYPE_ANY: u16 = 255;

pub(crate) const CLASS_IN: u16 = 1;
pub(crate) const CLASS_MASK: u16 = 0x7FFF;
pub(crate) const CLASS_UNIQUE: u16 = 0x8000;
pub(crate) const CLASS_CACHE_FLUSH: u16 = 0x8000;
pub(crate) const CLASS_UNICAST_RESPONSE: u16 = 0x8000;

/// Max size of UDP datagram payload: 9000 bytes - IP header 20 bytes - UDP header 8 bytes.
/// Reference: RFC6762: https://datatracker.ietf.org/doc/html/rfc6762#section-17
Expand Down Expand Up @@ -66,7 +67,7 @@ impl DnsEntry {
name,
ty,
class: class & CLASS_MASK,
unique: (class & CLASS_UNIQUE) != 0,
unique: (class & CLASS_CACHE_FLUSH) != 0,
}
}
}
Expand All @@ -77,6 +78,12 @@ pub(crate) struct DnsQuestion {
pub(crate) entry: DnsEntry,
}

impl DnsQuestion {
pub fn is_unicast_response_requested(&self) -> bool {
self.entry.class & CLASS_UNICAST_RESPONSE == CLASS_UNICAST_RESPONSE
}
}

/// A DNS Resource Record - like a DNS entry, but has a TTL.
/// RFC: https://www.rfc-editor.org/rfc/rfc1035#section-3.2.1
/// https://www.rfc-editor.org/rfc/rfc1035#section-4.1.3
Expand Down Expand Up @@ -548,7 +555,7 @@ impl DnsOutPacket {
self.write_short(record.entry.ty);
if record.entry.unique {
// check "multicast"
self.write_short(record.entry.class | CLASS_UNIQUE);
self.write_short(record.entry.class | CLASS_CACHE_FLUSH);
} else {
self.write_short(record.entry.class);
}
Expand Down Expand Up @@ -825,7 +832,7 @@ impl DnsOutgoing {
// https://tools.ietf.org/html/rfc6763#section-12.1.
self.add_additional_answer(Box::new(DnsSrv::new(
service.get_fullname(),
CLASS_IN | CLASS_UNIQUE,
CLASS_IN | CLASS_CACHE_FLUSH,
service.get_host_ttl(),
service.get_priority(),
service.get_weight(),
Expand All @@ -836,7 +843,7 @@ impl DnsOutgoing {
self.add_additional_answer(Box::new(DnsTxt::new(
service.get_fullname(),
TYPE_TXT,
CLASS_IN | CLASS_UNIQUE,
CLASS_IN | CLASS_CACHE_FLUSH,
service.get_host_ttl(),
service.generate_txt(),
)));
Expand All @@ -850,7 +857,7 @@ impl DnsOutgoing {
self.add_additional_answer(Box::new(DnsAddress::new(
service.get_hostname(),
t,
CLASS_IN | CLASS_UNIQUE,
CLASS_IN | CLASS_CACHE_FLUSH,
service.get_host_ttl(),
address,
)));
Expand Down Expand Up @@ -1331,7 +1338,7 @@ mod tests {
use crate::dns_parser::{TYPE_A, TYPE_AAAA};

use super::{
DnsIncoming, DnsNSec, DnsOutgoing, DnsSrv, CLASS_IN, CLASS_UNIQUE, FLAGS_QR_QUERY,
DnsIncoming, DnsNSec, DnsOutgoing, DnsSrv, CLASS_CACHE_FLUSH, CLASS_IN, FLAGS_QR_QUERY,
FLAGS_QR_RESPONSE, TYPE_PTR,
};

Expand Down Expand Up @@ -1379,7 +1386,7 @@ mod tests {
let mut response = DnsOutgoing::new(FLAGS_QR_RESPONSE);
response.add_additional_answer(Box::new(DnsSrv::new(
name,
CLASS_IN | CLASS_UNIQUE,
CLASS_IN | CLASS_CACHE_FLUSH,
1,
1,
1,
Expand Down Expand Up @@ -1407,7 +1414,13 @@ mod tests {
let name = "instance1._nsec_test._udp.local.";
let next_domain = name.to_string();
let type_bitmap = vec![64, 0, 0, 8]; // Two bits set to '1': bit 1 and bit 28.
let nsec = DnsNSec::new(name, CLASS_IN | CLASS_UNIQUE, 1, next_domain, type_bitmap);
let nsec = DnsNSec::new(
name,
CLASS_IN | CLASS_CACHE_FLUSH,
1,
next_domain,
type_bitmap,
);
let absent_types = nsec._types();
assert_eq!(absent_types.len(), 2);
assert_eq!(absent_types[0], TYPE_A);
Expand Down
Loading