use async_trait::async_trait;
use lazydns::Result;
use lazydns::dns::wire::{parse_message, serialize_message};
use lazydns::dns::{Message, Question, RData, RecordClass, RecordType, ResourceRecord};
use lazydns::server::{RequestHandler, ServerConfig, UdpServer};
use std::net::{Ipv4Addr, SocketAddr};
use std::sync::Arc;
use std::time::Duration;
use tokio::net::UdpSocket;
use tokio::time::{sleep, timeout};
struct TestHandler;
#[async_trait]
impl RequestHandler for TestHandler {
async fn handle(&self, ctx: lazydns::server::RequestContext) -> Result<Message> {
let mut request = ctx.into_message();
request.set_response(true);
request.set_recursion_available(true);
if !request.questions().is_empty() {
let question = &request.questions()[0];
if question.qtype() == RecordType::A {
request.add_answer(ResourceRecord::new(
question.qname().trim_end_matches('.'),
RecordType::A,
RecordClass::IN,
300,
RData::A(Ipv4Addr::new(93, 184, 216, 34)),
));
}
}
Ok(request)
}
}
#[tokio::test]
async fn test_udp_server_query_response() {
let server_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
let config = ServerConfig::default().with_udp_addr(server_addr);
let handler = Arc::new(TestHandler);
let server = UdpServer::new(config, handler)
.await
.expect("Failed to create server");
let actual_addr = server.local_addr().expect("Failed to get server address");
let server_handle = tokio::spawn(async move {
let _ = server.run().await;
});
sleep(Duration::from_millis(100)).await;
let mut query = Message::new();
query.set_id(12345);
query.set_query(true);
query.set_recursion_desired(true);
query.add_question(Question::new(
"test.example.com",
RecordType::A,
RecordClass::IN,
));
let query_bytes = serialize_message(&query).expect("Failed to serialize query");
let client_socket = UdpSocket::bind("127.0.0.1:0")
.await
.expect("Failed to bind client socket");
client_socket
.send_to(&query_bytes, actual_addr)
.await
.expect("Failed to send query");
let mut buf = vec![0u8; 512];
let (len, _) = timeout(Duration::from_secs(5), client_socket.recv_from(&mut buf))
.await
.expect("Timeout waiting for response")
.expect("Failed to receive response");
let response = parse_message(&buf[..len]).expect("Failed to parse response");
assert_eq!(response.id(), query.id());
assert!(response.is_response());
assert!(response.recursion_available());
assert_eq!(response.question_count(), 1);
assert_eq!(response.answer_count(), 1);
let answer = &response.answers()[0];
assert_eq!(answer.rtype(), RecordType::A);
match answer.rdata() {
RData::A(ip) => assert_eq!(*ip, Ipv4Addr::new(93, 184, 216, 34)),
_ => panic!("Expected A record"),
}
server_handle.abort();
}
#[tokio::test]
async fn test_multiple_sequential_queries() {
let server_addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
let config = ServerConfig::default().with_udp_addr(server_addr);
let handler = Arc::new(TestHandler);
let server = UdpServer::new(config, handler)
.await
.expect("Failed to create server");
let actual_addr = server.local_addr().expect("Failed to get server address");
let server_handle = tokio::spawn(async move {
let _ = server.run().await;
});
sleep(Duration::from_millis(100)).await;
let client_socket = UdpSocket::bind("127.0.0.1:0")
.await
.expect("Failed to bind client socket");
for i in 0..5 {
let mut query = Message::new();
query.set_id(1000 + i);
query.set_query(true);
query.set_recursion_desired(true);
query.add_question(Question::new(
format!("test{}.example.com", i),
RecordType::A,
RecordClass::IN,
));
let query_bytes = serialize_message(&query).expect("Failed to serialize query");
client_socket
.send_to(&query_bytes, actual_addr)
.await
.expect("Failed to send query");
let mut buf = vec![0u8; 512];
let (len, _) = timeout(Duration::from_secs(5), client_socket.recv_from(&mut buf))
.await
.expect("Timeout waiting for response")
.expect("Failed to receive response");
let response = parse_message(&buf[..len]).expect("Failed to parse response");
assert_eq!(response.id(), 1000 + i);
assert!(response.is_response());
assert_eq!(response.answer_count(), 1);
}
server_handle.abort();
}