pub mod dns_packet;
pub mod domain_name;
pub const DNS_PORT: u8 = 53;
pub const DNS_HEADER_SIZE: usize = 12;
pub mod opcodes {
pub const DNS_OPCODE_QUERY: u8 = 0;
pub const DNS_OPCODE_IQUERY: u8 = 1;
pub const DNS_OPCODE_STATUS: u8 = 2;
}
pub mod rcodes {
pub const DNS_RCODE_NO_ERROR: u8 = 0;
pub const DNS_RCODE_FORMAT_ERROR: u8 = 1;
pub const DNS_RCODE_SERVER_ERROR: u8 = 2;
pub const DNS_RCODE_NAME_ERROR: u8 = 3;
pub const DNS_RCODE_NOT_IMPLEMENTED: u8 = 4;
pub const DNS_RCODE_REFUSED: u8 = 5;
}
pub mod classes {
pub const DNS_CLASS_IN: u16 = 1;
pub const DNS_CLASS_CS: u16 = 2;
pub const DNS_CLASS_CH: u16 = 3;
pub const DNS_CLASS_HS: u16 = 4;
}
pub mod qclasses {
pub const DNS_QCLASS_ANY: u16 = 255;
}
pub mod types {
pub const DNS_TYPE_A: u16 = 1;
pub const DNS_TYPE_NS: u16 = 2;
pub const DNS_TYPE_MD: u16 = 3;
pub const DNS_TYPE_MF: u16 = 4;
pub const DNS_TYPE_CNAME: u16 = 5;
pub const DNS_TYPE_SOA: u16 = 6;
pub const DNS_TYPE_MB: u16 = 7;
pub const DNS_TYPE_MG: u16 = 8;
pub const DNS_TYPE_MR: u16 = 9;
pub const DNS_TYPE_NULL: u16 = 10;
pub const DNS_TYPE_WKS: u16 = 11;
pub const DNS_TYPE_PTR: u16 = 12;
pub const DNS_TYPE_HINFO: u16 = 13;
pub const DNS_TYPE_MINFO: u16 = 14;
pub const DNS_TYPE_MX: u16 = 15;
pub const DNS_TYPE_TXT: u16 = 16;
pub const DNS_TYPE_AAAA: u16 = 28;
pub const DNS_TYPE_SRV: u16 = 33;
}
pub mod qtypes {
pub const DNS_QTYPE_AXFR: u16 = 252;
pub const DNS_QTYPE_MAILB: u16 = 253;
pub const DNS_QTYPE_MAILA: u16 = 254;
pub const DNS_QTYPE_ANY: u16 = 255;
}
pub mod query_examples {
pub const BASIC_QUERY: &'static [u8] = &[
0x24, 0xB1, 0x01, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x01, 0x00, 0x01, ];
pub const BASIC_QUERY_RESPONSE: &'static [u8] = &[
0x24, 0xB1, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x01, 0x00, 0x01, 0xC0, 0x0C, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x58, 0x00, 0x04, 0xD8, 0x3A, 0xD9, 0x24, ];
pub const NAME_COMPRESSION_QUERY: &'static [u8] = &[
0x24, 0xB1, 0x01, 0x80, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77, 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x01, 0x00, 0x01, 0x07, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x65, 0x72, 0xC0, 0x0C, 0x00, 0x02, 0x00, 0x03, ];
}
pub fn send_dns_query_to(
dns_packet: &dns_packet::DnsPacket,
destination: &String,
) -> Result<dns_packet::DnsPacket, String> {
let client_socket = std::net::UdpSocket::bind("0.0.0.0:0").expect("Client could not bind");
let serialized_dns_packet = dns_packet.serialize()?;
client_socket
.send_to(&serialized_dns_packet, destination)
.expect("Client could not send data");
match client_socket.set_read_timeout(Some(std::time::Duration::from_secs(2))) {
Ok(_) => {}
Err(_) => {
return Err("Could not set query socket timeout".into());
}
}
let mut buf: [u8; 65535] = [0; 65535];
let (amt, _) = client_socket
.recv_from(&mut buf)
.expect("Client could not recieve data from google dns");
let buf = &buf[..amt];
let dns_response = dns_packet::DnsPacket::parse_dns_packet(&buf.into())?;
Ok(dns_response)
}
pub fn resolve_domain_name(domain_name: &String) -> Result<std::net::Ipv4Addr, String> {
let dns_packet = dns_packet::DnsPacket::new(domain_name, types::DNS_TYPE_A)?;
let dns_response = send_dns_query_to(&dns_packet, &String::from("8.8.8.8:53"))?;
match dns_response.header.rcode {
rcodes::DNS_RCODE_NO_ERROR => {}
_ => {
return Err(format!(
"Recursive resolver could not find {}, returned RCODE={}",
domain_name, dns_response.header.rcode
));
}
}
let position = dns_response
.answer
.iter()
.position(|record| record.rrtype == types::DNS_TYPE_A)
.ok_or("DNS response had no A records")?;
match dns_response.answer[position].rdata {
crate::dns_packet::dns_resource_record::DnsResourceRecordData::A(address) => {
return Ok(address);
}
_ => {
return Err("Did not match A resource record".into());
}
}
}