resolv 0.4.0

DNS resolution via glibc
Documentation
use super::{RecordData, RecordType};
use crate::error::Error;
use byteorder::{BigEndian, ByteOrder};
use libresolv_sys::ns_msg as Message;
use libresolv_sys::ns_rr as Rr;
use libresolv_sys::MAXDNAME;
use std::ffi::CStr;
use std::slice;

#[derive(Debug, Clone)]
pub struct SOA {
    pub mname: String,
    pub rname: String,
    pub serial: u32,
    pub refresh: u32,
    pub retry: u32,
    pub expire: u32,
    pub minimum: u32,
}

impl RecordData for SOA {
    fn get_record_type() -> RecordType {
        RecordType::SOA
    }

    fn extract(msg: &mut Message, rr: &Rr) -> Result<SOA, Error> {
        if rr.type_ != Self::get_record_type() as u16 {
            return Err(Error::WrongRRType);
        }

        let mut soa = SOA {
            mname: "".to_owned(),
            rname: "".to_owned(),
            serial: 0,
            refresh: 0,
            retry: 0,
            expire: 0,
            minimum: 0,
        };

        let mut buffer: [u8; MAXDNAME as usize] = [0; MAXDNAME as usize];

        let mut offset = 0;

        soa.mname = {
            let count = unsafe {
                ::libresolv_sys::ns_name_uncompress(
                    msg._msg,
                    msg._eom,
                    rr.rdata.offset(offset),
                    buffer.as_mut_ptr() as *mut i8,
                    MAXDNAME as usize,
                )
            };
            if count < 0 {
                return Err(Error::UncompressError);
            }
            offset += count as isize;
            unsafe {
                CStr::from_ptr(buffer.as_ptr() as *const i8)
                    .to_string_lossy()
                    .into_owned()
            }
        };

        soa.rname = {
            let count = unsafe {
                ::libresolv_sys::ns_name_uncompress(
                    msg._msg,
                    msg._eom,
                    rr.rdata.offset(offset),
                    buffer.as_mut_ptr() as *mut i8,
                    MAXDNAME as usize,
                )
            };
            if count < 0 {
                return Err(Error::UncompressError);
            }
            offset += count as isize;
            unsafe {
                CStr::from_ptr(buffer.as_ptr() as *const i8)
                    .to_string_lossy()
                    .into_owned()
            }
        };

        soa.serial = unsafe {
            let slice: &[u8] = slice::from_raw_parts(rr.rdata.offset(offset), 4);
            BigEndian::read_u32(slice)
        };
        offset += 4;

        soa.refresh = unsafe {
            let slice: &[u8] = slice::from_raw_parts(rr.rdata.offset(offset), 4);
            BigEndian::read_u32(slice)
        };
        offset += 4;

        soa.retry = unsafe {
            let slice: &[u8] = slice::from_raw_parts(rr.rdata.offset(offset), 4);
            BigEndian::read_u32(slice)
        };
        offset += 4;

        soa.expire = unsafe {
            let slice: &[u8] = slice::from_raw_parts(rr.rdata.offset(offset), 4);
            BigEndian::read_u32(slice)
        };
        offset += 4;

        soa.minimum = unsafe {
            let slice: &[u8] = slice::from_raw_parts(rr.rdata.offset(offset), 4);
            BigEndian::read_u32(slice)
        };

        Ok(soa)
    }
}