mirror of
https://github.com/DNSCrypt/doh-server.git
synced 2025-04-01 20:27:34 +03:00
edns0 padding
TODO: check that a padding pseudorecord is not already present
This commit is contained in:
parent
31953b2605
commit
bf42e95368
3 changed files with 60 additions and 9 deletions
59
src/dns.rs
59
src/dns.rs
|
@ -3,10 +3,12 @@ use byteorder::{BigEndian, ByteOrder};
|
|||
|
||||
const DNS_HEADER_SIZE: usize = 12;
|
||||
const DNS_MAX_HOSTNAME_SIZE: usize = 256;
|
||||
const DNS_MAX_PACKET_SIZE: usize = 65_535;
|
||||
const DNS_MAX_PACKET_SIZE: usize = 4096;
|
||||
const DNS_OFFSET_QUESTION: usize = DNS_HEADER_SIZE;
|
||||
const DNS_TYPE_OPT: u16 = 41;
|
||||
|
||||
const DNS_PTYPE_PADDING: u16 = 12;
|
||||
|
||||
const DNS_RCODE_SERVFAIL: u8 = 2;
|
||||
const DNS_RCODE_REFUSED: u8 = 5;
|
||||
|
||||
|
@ -201,3 +203,58 @@ pub fn set_edns_max_payload_size(packet: &mut Vec<u8>, max_payload_size: u16) ->
|
|||
add_edns_section(packet, max_payload_size)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_edns_padding(packet: &mut Vec<u8>, block_size: usize) -> Result<(), Error> {
|
||||
ensure!(qdcount(packet) == 1, "Unsupported number of questions");
|
||||
let mut packet_len = packet.len();
|
||||
ensure!(packet_len > DNS_OFFSET_QUESTION, "Short packet");
|
||||
ensure!(packet_len <= DNS_MAX_PACKET_SIZE, "Large packet");
|
||||
|
||||
let mut offset = skip_name(packet, DNS_OFFSET_QUESTION)?;
|
||||
assert!(offset > DNS_OFFSET_QUESTION);
|
||||
ensure!(packet_len - offset >= 4, "Short packet");
|
||||
offset += 4;
|
||||
let (ancount, nscount, arcount) = (ancount(packet), nscount(packet), arcount(packet));
|
||||
offset = traverse_rrs(packet, offset, ancount + nscount, |_offset| Ok(()))?;
|
||||
let mut edns_offset = None;
|
||||
traverse_rrs_mut(packet, offset, arcount, |packet, offset| {
|
||||
let qtype = BigEndian::read_u16(&packet[offset..]);
|
||||
if qtype == DNS_TYPE_OPT {
|
||||
ensure!(edns_offset.is_none(), "Duplicate OPT RR found");
|
||||
edns_offset = Some(offset)
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
let edns_offset = match edns_offset {
|
||||
Some(edns_offset) => edns_offset,
|
||||
None => {
|
||||
let edns_offset = packet.len() + 1;
|
||||
add_edns_section(packet, DNS_MAX_PACKET_SIZE as _)?;
|
||||
packet_len = packet.len();
|
||||
edns_offset
|
||||
}
|
||||
};
|
||||
ensure!(packet_len < DNS_MAX_PACKET_SIZE, "Large packet");
|
||||
let pad_len = (block_size - 1) - ((packet_len + (block_size - 1)) & (block_size - 1));
|
||||
let mut edns_padding_prr = vec![0u8; 2 + pad_len];
|
||||
edns_padding_prr[0] = (DNS_PTYPE_PADDING >> 8) as u8;
|
||||
edns_padding_prr[1] = DNS_PTYPE_PADDING as u8;
|
||||
let edns_padding_prr_len = edns_padding_prr.len();
|
||||
let edns_rdlen_offset: usize = edns_offset + 8;
|
||||
ensure!(packet_len - edns_rdlen_offset >= 2, "Short packet");
|
||||
let edns_rdlen = BigEndian::read_u16(&packet[edns_rdlen_offset..]);
|
||||
ensure!(
|
||||
0xffff - edns_rdlen as usize >= edns_padding_prr_len,
|
||||
"EDNS section too large for padding"
|
||||
);
|
||||
BigEndian::write_u16(
|
||||
&mut packet[edns_rdlen_offset..],
|
||||
edns_rdlen + edns_padding_prr_len as u16,
|
||||
);
|
||||
ensure!(
|
||||
DNS_MAX_PACKET_SIZE - packet_len >= edns_padding_prr_len,
|
||||
"Large packet"
|
||||
);
|
||||
packet.extend(&edns_padding_prr);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -159,7 +159,7 @@ impl DoH {
|
|||
if query.len() < MIN_DNS_PACKET_LEN {
|
||||
return Err(DoHError::Incomplete);
|
||||
}
|
||||
let _ = dns::set_edns_max_payload_size(&mut query, MAX_DNS_RESPONSE_LEN as u16);
|
||||
let _ = dns::set_edns_max_payload_size(&mut query, MAX_DNS_RESPONSE_LEN as _);
|
||||
let globals = &self.globals;
|
||||
let mut socket = UdpSocket::bind(&globals.local_bind_address)
|
||||
.await
|
||||
|
@ -185,11 +185,11 @@ impl DoH {
|
|||
Ok(ttl) => ttl,
|
||||
}
|
||||
};
|
||||
dns::add_edns_padding(&mut packet, BLOCK_SIZE).map_err(|_| DoHError::TooLarge)?;
|
||||
let packet_len = packet.len();
|
||||
let response = Response::builder()
|
||||
.header(hyper::header::CONTENT_LENGTH, packet_len)
|
||||
.header(hyper::header::CONTENT_TYPE, "application/dns-message")
|
||||
.header("X-Padding", utils::padding_string(packet_len, BLOCK_SIZE))
|
||||
.header(
|
||||
hyper::header::CACHE_CONTROL,
|
||||
format!("max-age={}", ttl).as_str(),
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
|
||||
pub(crate) fn padding_string(input_size: usize, block_size: usize) -> String {
|
||||
let block_size_ = block_size - 1;
|
||||
let padding_len = block_size_ - ((input_size + block_size_) & block_size_);
|
||||
String::from_utf8(vec![b'X'; padding_len]).unwrap()
|
||||
}
|
||||
|
||||
// functions to verify the startup arguments as correct
|
||||
pub(crate) fn verify_sock_addr(arg_val: String) -> Result<(), String> {
|
||||
match arg_val.parse::<SocketAddr>() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue