mirror of
https://github.com/NLnetLabs/domain.git
synced 2026-09-22 17:54:59 +02:00
This PR refactors the existing support for OPT options. It does the
following things:
o Changes all option data types to ensure their wire format is at most
65,535 octets long. This requires changing the signatures of some
creator functions. Their naming scheme and signatures are also changed
to follow the pattern established with record data.
o Renamed `UnknownOptData::from_octets` to `new` and return a result.
o Completely redesigns DNS cookie options, adding support for standard
server cookies introduced in RFC 9018.
o Change the type of `ExtendedError`’s text to `Str<Octs>` and change the
return type of `set_text` to `()`.
o Changed the type `TcpKeepalive`’s content to a newtype `IdleTimeout` to
make it easier to convert to and from durations.
o Changes Padding to just contain the padding octets and drop
`PaddingMode`. Instead, the methods on OptBuilder` should be used to
add padding.
This is a breaking change.
103 lines
2.7 KiB
Rust
103 lines
2.7 KiB
Rust
use std::net::UdpSocket;
|
|
use std::str::FromStr;
|
|
|
|
use domain::base::opt::AllOptData;
|
|
use domain::base::{
|
|
Dname, Message, MessageBuilder, Rtype, StaticCompressor, StreamTarget,
|
|
};
|
|
use domain::rdata::AllRecordData;
|
|
|
|
fn create_message() -> StreamTarget<Vec<u8>> {
|
|
// Create a message builder wrapping a compressor wrapping a stream
|
|
// target.
|
|
let mut msg = MessageBuilder::from_target(StaticCompressor::new(
|
|
StreamTarget::new_vec(),
|
|
))
|
|
.unwrap();
|
|
|
|
// Set the RD bit and a random ID in the header and proceed to
|
|
// the question section.
|
|
msg.header_mut().set_rd(true);
|
|
msg.header_mut().set_random_id();
|
|
let mut msg = msg.question();
|
|
|
|
// Add a hard-coded question and proceed to the answer section.
|
|
msg.push((
|
|
Dname::<Vec<u8>>::from_str("example.com.").unwrap(),
|
|
Rtype::A,
|
|
))
|
|
.unwrap();
|
|
|
|
// Skip to the additional section
|
|
let mut msg = msg.additional();
|
|
|
|
// Add an OPT record.
|
|
msg.opt(|opt| {
|
|
opt.set_udp_payload_size(4096);
|
|
Ok(())
|
|
})
|
|
.unwrap();
|
|
|
|
// Convert the builder into the actual message.
|
|
msg.finish().into_target()
|
|
}
|
|
|
|
fn main() {
|
|
// Bind a UDP socket to a kernel-provided port
|
|
let socket =
|
|
UdpSocket::bind("0.0.0.0:0").expect("couldn't bind to address");
|
|
|
|
let message = create_message();
|
|
|
|
let server: String = "127.0.0.1".to_string();
|
|
let port: u16 = 53;
|
|
|
|
// Send message off to the server using our socket
|
|
socket
|
|
.send_to(message.as_dgram_slice(), (server, port))
|
|
.unwrap();
|
|
|
|
// Create recv buffer
|
|
let mut buffer = vec![0; 1232];
|
|
|
|
// Recv in buffer
|
|
socket.recv_from(&mut buffer).unwrap();
|
|
|
|
// Parse and print the response
|
|
let response = match Message::from_octets(buffer) {
|
|
Ok(response) => Some(response),
|
|
Err(_) => None,
|
|
}
|
|
.unwrap();
|
|
|
|
for question in response.question() {
|
|
println!("{}", question.unwrap());
|
|
}
|
|
|
|
// Unpack and parse with all known record types
|
|
for record in response.answer().unwrap().limit_to::<AllRecordData<_, _>>()
|
|
{
|
|
println!("{}", record.unwrap());
|
|
}
|
|
|
|
for record in response
|
|
.authority()
|
|
.unwrap()
|
|
.limit_to::<AllRecordData<_, _>>()
|
|
{
|
|
println!("{}", record.unwrap());
|
|
}
|
|
|
|
// Display is only implemented for some OPTs at the time of writing
|
|
for option in response.opt().unwrap().opt().iter::<AllOptData<_, _>>() {
|
|
let opt = option.unwrap();
|
|
match opt {
|
|
AllOptData::Nsid(nsid) => println!("{}", nsid),
|
|
AllOptData::ExtendedError(extendederror) => {
|
|
println!("{}", extendederror)
|
|
}
|
|
_ => println!("NO OPT!"),
|
|
}
|
|
}
|
|
}
|