extern crate libresolv_sys;
extern crate byteorder;
pub mod error;
use error::{Error, ResolutionError};
mod response;
pub use response::{Response, Section, Flags, RecordItems};
pub mod record;
pub use record::{Record, RecordType, Class};
#[cfg(test)]
mod tests;
use std::ffi::CString;
use std::ops::{Deref, DerefMut};
type Context = libresolv_sys::__res_state;
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ResolverOption {
Init = libresolv_sys::RES_INIT,
Debug = libresolv_sys::RES_DEBUG,
UseVC = libresolv_sys::RES_USEVC,
IgnTc = libresolv_sys::RES_IGNTC,
Recurse = libresolv_sys::RES_RECURSE,
DefNames = libresolv_sys::RES_DEFNAMES,
StayOpen = libresolv_sys::RES_STAYOPEN,
DNSrch = libresolv_sys::RES_DNSRCH,
NoAliases = libresolv_sys::RES_NOALIASES,
Rotate = libresolv_sys::RES_ROTATE,
UseEDNS0 = libresolv_sys::RES_USE_EDNS0,
SngLkup = libresolv_sys::RES_SNGLKUP,
SngLkupReop = libresolv_sys::RES_SNGLKUPREOP,
UseDNSSEC = libresolv_sys::RES_USE_DNSSEC,
NoTLDQuery = libresolv_sys::RES_NOTLDQUERY,
NoReload = libresolv_sys::RES_NORELOAD,
TrustAD = libresolv_sys::RES_TRUSTAD,
Default = libresolv_sys::RES_DEFAULT,
}
pub struct Resolver {
context: Context
}
impl Resolver {
pub fn new() -> Option<Resolver>
{
let mut resolver = Resolver {
context: libresolv_sys::__res_state::default(),
};
if unsafe {
libresolv_sys::__res_ninit(&mut resolver.context)
} != 0 {
return None
}
resolver.option(ResolverOption::Default, true);
Some(resolver)
}
pub fn option(&mut self, option: ResolverOption, value: bool) {
if value {
self.context.options = self.context.options | (option as u64);
} else {
self.context.options = self.context.options & !(option as u64);
}
}
pub fn search(&mut self,
name: &[u8],
class: Class,
typ: RecordType)
-> Result<Response, Error>
{
let name = match CString::new(name) {
Ok(c) => c,
Err(n) => return Err(Error::CString(n)),
};
let buflen: usize = libresolv_sys::NS_PACKETSZ as usize;
let mut buffer: Box<Vec<u8>> = Box::new(Vec::with_capacity(buflen));
let rlen: i32 = unsafe {
libresolv_sys::__res_nsearch(
&mut self.context,
name.as_ptr(),
class as i32,
typ as i32,
buffer.deref_mut().as_mut_ptr(),
buflen as i32)
};
if rlen==-1 {
return Err(From::from(self.get_error()));
}
let mut msg: libresolv_sys::__ns_msg = libresolv_sys::__ns_msg::default();
unsafe {
if libresolv_sys::ns_initparse(buffer.deref().as_ptr(), rlen, &mut msg) < 0 {
return Err(Error::ParseError);
}
}
Ok(Response::new(msg, buffer))
}
pub fn query(&mut self,
dname: &[u8],
class: Class,
typ: RecordType)
-> Result<Response, Error>
{
let name = match CString::new(dname) {
Ok(c) => c,
Err(n) => return Err(Error::CString(n)),
};
let buflen: usize = libresolv_sys::NS_PACKETSZ as usize;
let mut buffer: Box<Vec<u8>> = Box::new(Vec::with_capacity(buflen));
let rlen: i32 = unsafe {
libresolv_sys::__res_nquery(
&mut self.context,
name.as_ptr(),
class as i32,
typ as i32,
buffer.deref_mut().as_mut_ptr(),
buflen as i32)
};
if rlen==-1 {
return Err(From::from(self.get_error()));
}
let mut msg: libresolv_sys::__ns_msg = libresolv_sys::__ns_msg::default();
unsafe {
if libresolv_sys::ns_initparse(buffer.deref().as_ptr(), rlen, &mut msg) < 0 {
return Err(Error::ParseError);
}
}
Ok(Response::new(msg, buffer))
}
fn get_error(&self) -> ResolutionError
{
match self.context.res_h_errno {
0 => ResolutionError::Success,
1 => ResolutionError::HostNotFound,
2 => ResolutionError::TryAgain,
3 => ResolutionError::NoRecovery,
4 => ResolutionError::NoData,
_ => ResolutionError::HostNotFound, }
}
}