Client written and working, but now need to implement pointer for names, non-consuming data stream

This commit is contained in:
Benjamin Fry 2015-08-18 17:07:45 -07:00
parent d781deceee
commit a8fe789836
10 changed files with 179 additions and 60 deletions

View File

@ -1,5 +1,5 @@
# trust-dns
A Rust based DNS server
A Rust based DNS client and server
# Goals
@ -21,6 +21,7 @@ All parsers complete.
Todo: Serializers.
Todo: Operations.
- EDNS http://tools.ietf.org/html/rfc2671
- Support DNS Update RFC 2136.
- DNSSEC Resource Records RFC 4034
- DNSSec protocol RFC 4035

View File

@ -1,6 +1,3 @@
pub mod rr;
pub mod op;
#[test]
fn it_works() {
}
pub mod udp;

View File

@ -128,6 +128,19 @@ impl Header {
pub fn name_server_count(&mut self, name_server_count: u16) -> &mut Self { self.name_server_count = name_server_count; self }
pub fn additional_count(&mut self, additional_count: u16) -> &mut Self { self.additional_count = additional_count; self }
pub fn get_id(&self) -> u16 { self.id }
pub fn get_message_type(&self) -> MessageType { self.message_type }
pub fn get_op_code(&self) -> OpCode { self.op_code }
pub fn is_authoritative(&self) -> bool { self.authoritative }
pub fn is_truncated(&self) -> bool { self.truncation }
pub fn is_recursion_desired(&self) -> bool { self.recursion_desired }
pub fn is_recursion_available(&self) -> bool {self.recursion_available }
pub fn get_response_code(&self) -> ResponseCode { self.response_code }
pub fn get_query_count(&self) -> u16 { self.query_count }
pub fn get_answer_count(&self) -> u16 { self.answer_count }
pub fn get_name_server_count(&self) -> u16 { self.name_server_count }
pub fn get_additional_count(&self) -> u16 { self.additional_count }
/// This is a specialized clone which clones all the fields but the counts
/// handy for setting the count fields before sending over the wire.
pub fn clone(&self, query_count: u16, answer_count: u16, name_server_count: u16, additional_count: u16) -> Self {
@ -191,19 +204,6 @@ impl Header {
util::write_u16_to(buf, self.name_server_count);
util::write_u16_to(buf, self.additional_count);
}
pub fn get_id(&self) -> u16 { self.id }
pub fn get_message_type(&self) -> MessageType { self.message_type }
pub fn get_op_code(&self) -> OpCode { self.op_code }
pub fn is_authoritative(&self) -> bool { self.authoritative }
pub fn is_truncated(&self) -> bool { self.truncation }
pub fn is_recursion_desired(&self) -> bool { self.recursion_desired }
pub fn is_recursion_available(&self) -> bool {self.recursion_available }
pub fn get_response_code(&self) -> ResponseCode { self.response_code }
pub fn get_query_count(&self) -> u16 { self.query_count }
pub fn get_answer_count(&self) -> u16 { self.answer_count }
pub fn get_name_server_count(&self) -> u16 { self.name_server_count }
pub fn get_additional_count(&self) -> u16 { self.additional_count }
}
#[test]

View File

@ -65,6 +65,20 @@ impl Message {
pub fn add_name_server(&mut self, record: Record) -> &mut Self { self.name_servers.push(record); self }
pub fn add_additional(&mut self, record: Record) -> &mut Self { self.additionals.push(record); self }
pub fn get_id(&self) -> u16 { self.header.get_id() }
pub fn get_message_type(&self) -> MessageType { self.header.get_message_type() }
pub fn get_op_code(&self) -> OpCode { self.header.get_op_code() }
pub fn is_authoritative(&self) -> bool { self.header.is_authoritative() }
pub fn is_truncated(&self) -> bool { self.header.is_truncated() }
pub fn is_recursion_desired(&self) -> bool { self.header.is_recursion_desired() }
pub fn is_recursion_available(&self) -> bool { self.header.is_recursion_available() }
pub fn get_response_code(&self) -> ResponseCode { self.header.get_response_code() }
pub fn get_queries(&self) -> &Vec<Query> { &self.queries }
pub fn get_answers(&self) -> &Vec<Record> { &self.answers }
pub fn get_name_servers(&self) -> &Vec<Record> { &self.name_servers }
pub fn get_additional(&self) -> &Vec<Record> { &self.additionals }
/// this is necessary to match the counts in the header from the record sections
/// this happens implicitly on write_to, so no need to call before write_to
pub fn update_counts(&mut self) -> &mut Self {

View File

@ -8,7 +8,7 @@ pub enum DNSClass {
CH, // 3 Chaos (CH)
HS, // 4 Hesiod (HS)
NONE, // 254 QCLASS NONE
ANY, // 255 QCLASS * (ANY)
// ANY, // 255 QCLASS * (ANY)
}
impl DNSClass {
@ -42,7 +42,7 @@ impl From<DNSClass> for &'static str {
DNSClass::CH => "CH",
DNSClass::HS => "HS",
DNSClass::NONE => "NONE",
DNSClass::ANY => "ANY",
// DNSClass::ANY => "ANY",
}
}
}
@ -66,8 +66,8 @@ impl<'a> From<&'a str> for DNSClass {
"CH" => DNSClass::CH,
"HS" => DNSClass::HS,
"NONE" => DNSClass::NONE,
"ANY" => DNSClass::ANY,
"*" => DNSClass::ANY,
// "ANY" => DNSClass::ANY,
// "*" => DNSClass::ANY,
_ => unimplemented!(),
}
}
@ -92,7 +92,7 @@ impl From<DNSClass> for u16 {
DNSClass::CH => 3,
DNSClass::HS => 4,
DNSClass::NONE => 254,
DNSClass::ANY => 255,
// DNSClass::ANY => 255,
}
}
}
@ -116,7 +116,7 @@ impl From<u16> for DNSClass {
3 => DNSClass::CH,
4 => DNSClass::HS,
254 => DNSClass::NONE,
255 => DNSClass::ANY,
// 255 => DNSClass::ANY,
_ => unimplemented!(),
}
}

View File

@ -3,7 +3,7 @@ use std::ops::Index;
use super::util;
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub struct Name {
labels: Vec<String>
}

View File

@ -6,42 +6,42 @@ use super::util;
pub enum RecordType {
A, // 1 RFC 1035[1] IPv4 Address record
AAAA, // 28 RFC 3596[2] IPv6 address record
AFSDB, // 18 RFC 1183 AFS database record
APL, // 42 RFC 3123 Address Prefix List
CAA, // 257 RFC 6844 Certification Authority Authorization
CDNSKEY, // 60 RFC 7344 Child DNSKEY
CDS, // 59 RFC 7344 Child DS
CERT, // 37 RFC 4398 Certificate record
// AFSDB, // 18 RFC 1183 AFS database record
// APL, // 42 RFC 3123 Address Prefix List
// CAA, // 257 RFC 6844 Certification Authority Authorization
// CDNSKEY, // 60 RFC 7344 Child DNSKEY
// CDS, // 59 RFC 7344 Child DS
// CERT, // 37 RFC 4398 Certificate record
CNAME, // 5 RFC 1035[1] Canonical name record
DHCID, // 49 RFC 4701 DHCP identifier
DLV, // 32769 RFC 4431 DNSSEC Lookaside Validation record
DNAME, // 39 RFC 2672 Delegation Name
DNSKEY, // 48 RFC 4034 DNS Key record
DS, // 43 RFC 4034 Delegation signer
HIP, // 55 RFC 5205 Host Identity Protocol
IPSECKEY, // 45 RFC 4025 IPsec Key
KEY, // 25 RFC 2535[3] and RFC 2930[4] Key record
KX, // 36 RFC 2230 Key eXchanger record
LOC, // 29 RFC 1876 Location record
// DHCID, // 49 RFC 4701 DHCP identifier
// DLV, // 32769 RFC 4431 DNSSEC Lookaside Validation record
// DNAME, // 39 RFC 2672 Delegation Name
// DNSKEY, // 48 RFC 4034 DNS Key record
// DS, // 43 RFC 4034 Delegation signer
// HIP, // 55 RFC 5205 Host Identity Protocol
// IPSECKEY, // 45 RFC 4025 IPsec Key
// KEY, // 25 RFC 2535[3] and RFC 2930[4] Key record
// KX, // 36 RFC 2230 Key eXchanger record
// LOC, // 29 RFC 1876 Location record
MX, // 15 RFC 1035[1] Mail exchange record
NAPTR, // 35 RFC 3403 Naming Authority Pointer
// NAPTR, // 35 RFC 3403 Naming Authority Pointer
NS, // 2 RFC 1035[1] Name server record
NSEC, // 47 RFC 4034 Next-Secure record
NSEC3, // 50 RFC 5155 NSEC record version 3
NSEC3PARAM, // 51 RFC 5155 NSEC3 parameters
// NSEC, // 47 RFC 4034 Next-Secure record
// NSEC3, // 50 RFC 5155 NSEC record version 3
// NSEC3PARAM, // 51 RFC 5155 NSEC3 parameters
PTR, // 12 RFC 1035[1] Pointer record
RRSIG, // 46 RFC 4034 DNSSEC signature
RP, // 17 RFC 1183 Responsible person
SIG, // 24 RFC 2535 Signature
// RRSIG, // 46 RFC 4034 DNSSEC signature
// RP, // 17 RFC 1183 Responsible person
// SIG, // 24 RFC 2535 Signature
SOA, // 6 RFC 1035[1] and RFC 2308[9] Start of [a zone of] authority record
SRV, // 33 RFC 2782 Service locator
SSHFP, // 44 RFC 4255 SSH Public Key Fingerprint
TA, // 32768 N/A DNSSEC Trust Authorities
TKEY, // 249 RFC 2930 Secret key record
TLSA, // 52 RFC 6698 TLSA certificate association
TSIG, // 250 RFC 2845 Transaction Signature
// SRV, // 33 RFC 2782 Service locator
// SSHFP, // 44 RFC 4255 SSH Public Key Fingerprint
// TA, // 32768 N/A DNSSEC Trust Authorities
// TKEY, // 249 RFC 2930 Secret key record
// TLSA, // 52 RFC 6698 TLSA certificate association
// TSIG, // 250 RFC 2845 Transaction Signature
TXT, // 16 RFC 1035[1] Text record
ANY, // * 255 RFC 1035[1] All cached records, aka ANY
// ANY, // * 255 RFC 1035[1] All cached records, aka ANY
AXFR, // 252 RFC 1035[1] Authoritative Zone Transfer
IXFR, // 251 RFC 1996 Incremental Zone Transfer
OPT, // 41 RFC 6891 Option
@ -81,7 +81,6 @@ impl From<RecordType> for &'static str {
RecordType::CNAME => "CNAME",
RecordType::NS => "NS",
RecordType::SOA => "SOA",
RecordType::ANY => "ANY",
_ => panic!("unsupported RecordType: {:?}", rt),
}
}
@ -107,8 +106,6 @@ impl<'a> From<&'a str> for RecordType {
"CNAME" => RecordType::CNAME,
"NS" => RecordType::NS,
"SOA" => RecordType::SOA,
"ANY" => RecordType::ANY,
"*" => RecordType::ANY,
_ => panic!("unsupported RecordType: {:?}", str),
}
}
@ -134,7 +131,6 @@ impl From<RecordType> for u16 {
RecordType::CNAME => 5,
RecordType::NS => 2,
RecordType::SOA => 6,
RecordType::ANY => 255,
_ => panic!("unsupported RecordType: {:?}", rt),
}
}
@ -160,7 +156,6 @@ impl From<u16> for RecordType {
5 => RecordType::CNAME,
2 => RecordType::NS,
6 => RecordType::SOA,
255 => RecordType::ANY,
_ => panic!("unsupported RecordType: {:?}", value),
}
}

View File

@ -96,6 +96,13 @@ impl Record {
pub fn ttl(&mut self, ttl: i32) -> &mut Self { self.ttl = ttl; self }
pub fn rdata(&mut self, rdata: RData) -> &mut Self { self.rdata = rdata; self }
pub fn get_name(&self) -> &domain::Name { &self.name_labels }
pub fn get_rr_type(&self) -> RecordType { self.rr_type }
pub fn get_dns_class(&self) -> DNSClass { self.dns_class }
pub fn get_ttl(&self) -> i32 { self.ttl }
pub fn get_rdata(&self) -> &RData { &self.rdata }
/// parse a resource record line example:
/// WARNING: the record_bytes is 100% consumed and destroyed in this parsing process
pub fn parse(data: &mut Vec<u8>) -> Record {

104
src/udp/client.rs Normal file
View File

@ -0,0 +1,104 @@
use std::net::*; // we need almost everything in here...
use std::cell::Cell;
use std::io;
use super::super::rr::resource::Record;
use super::super::rr::dns_class::DNSClass;
use super::super::rr::record_type::RecordType;
use super::super::rr::domain;
use super::super::op::message::Message;
use super::super::op::header::{Header, MessageType};
use super::super::op::op_code::OpCode;
use super::super::op::query::Query;
pub struct Client {
socket: UdpSocket,
name_server: SocketAddrV4,
next_id: Cell<u16>,
}
impl Client {
/// name_server to connect to with default port 53
pub fn new(name_server: Ipv4Addr) -> io::Result<Client> {
Self::with_port(name_server, 53)
}
/// name_server to connect to, port is the port number that server is listening on (default 53)
pub fn with_port(name_server: Ipv4Addr, port: u16) -> io::Result<Client> {
// client binds to all addresses...
// TODO when the socket_opts interfaces stabilize, need to add timeouts, ttl, etc.
let socket = try!(UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::new(0,0,0,0),0)));
Ok(Client { socket: socket, name_server: SocketAddrV4::new(name_server, port), next_id: Cell::new(4096) })
}
/// send a DNS query to the name_server specified in Clint.
///
/// ```
/// use std::net::*;
///
/// use trust_dns::rr::dns_class::DNSClass;
/// use trust_dns::rr::record_type::RecordType;
/// use trust_dns::rr::domain;
/// use trust_dns::rr::record_data::RData;
/// use trust_dns::udp::client::Client;
///
/// let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
/// let client = Client::new(("8.8.8.8").parse().unwrap()).unwrap();
/// let response = client.query(name.clone(), DNSClass::IN, RecordType::A).unwrap();
///
/// let record = &response.get_answers()[0];
/// assert_eq!(record.get_name(), &name);
/// assert_eq!(record.get_rr_type(), RecordType::A);
/// assert_eq!(record.get_dns_class(), DNSClass::IN);
///
/// if let &RData::A{ ref address } = record.get_rdata() {
/// assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
/// } else {
/// assert!(false);
/// }
///
/// ```
pub fn query(&self, name: domain::Name, query_class: DNSClass, query_type: RecordType) -> Result<Message, ()> {
// build the message
let mut message: Message = Message::new();
let id = self.next_id();
message.id(id).message_type(MessageType::Query).op_code(OpCode::Query).recursion_desired(true);
// add the query
let mut query: Query = Query::new();
query.name(name).query_class(query_class).query_type(query_type);
message.add_query(query);
// get the message bytes and send the query
let mut buf: Vec<u8> = Vec::new();
message.write_to(&mut buf);
// TODO proper error handling
// TODO when the socket_opts interfaces stabilize, need to add timeouts, ttl, etc.
let bytes_sent = self.socket.send_to(&buf, self.name_server).unwrap();
assert_eq!(bytes_sent, buf.len()); // TODO, proper error...
//----------------------------
// now listen for the response
//----------------------------
// the max buffer size we'll except is 4k
let mut buf = [0u8; 4096];
let (bytes_recv, remote) = self.socket.recv_from(&mut buf).unwrap();
// TODO change parsers to use Read or something else, so that we don't need to copy here.
let mut resp_bytes = buf.to_vec();
resp_bytes.truncate(bytes_recv);
resp_bytes.reverse();
let response = Message::parse(&mut resp_bytes); // TODO, change all parses to return Results...
assert_eq!(response.get_id(), id); // TODO, better error...
Ok(response)
}
fn next_id(&self) -> u16 {
let id = self.next_id.get();
self.next_id.set(id + 1);
id
}
}

1
src/udp/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod client;