systemd-resolved-rs 0.1.1

A compatibility-oriented reimplementation of systemd-resolved
#[cfg(test)]
mod test_05_lookup_name_tries_search_domains_in_order {
    use super::*;

    fn append_test_answer(packet: &mut Vec<u8>, owner: &[u8], rr_type: u16, rdata: &[u8]) {
        packet.extend_from_slice(owner);
        packet.extend_from_slice(&rr_type.to_be_bytes());
        packet.extend_from_slice(&wire::CLASS_IN.to_be_bytes());
        packet.extend_from_slice(&60u32.to_be_bytes());
        packet.extend_from_slice(
            &u16::try_from(rdata.len())
                .expect("test RDATA length")
                .to_be_bytes(),
        );
        packet.extend_from_slice(rdata);
    }

    #[test]
    fn lookup_name_tries_search_domains_in_order() {
        use crate::wire::question_end;
        use std::thread;

        let socket = UdpSocket::bind("127.0.0.1:0").expect("bind test DNS server");
        socket
            .set_read_timeout(Some(Duration::from_secs(2)))
            .expect("set test timeout");
        let server = socket.local_addr().expect("test DNS server address");
        let worker = thread::spawn(move || {
            let mut buffer = [0; 4096];
            for (index, expected_name) in ["host.example.test", "host.lab.test"]
                .into_iter()
                .enumerate()
            {
                let (length, peer) = socket.recv_from(&mut buffer).expect("receive query");
                let query = &buffer[..length];
                let question = first_question(query).expect("question");
                assert_eq!(question.name.text(), expected_name);
                let end = question_end(query).expect("question end");
                let mut response = query[..end].to_vec();
                let flags = if index == 0 { 0x8183u16 } else { 0x8180u16 };
                response[2..4].copy_from_slice(&flags.to_be_bytes());
                response[6..12].fill(0);
                if index == 1 {
                    response[6..8].copy_from_slice(&1u16.to_be_bytes());
                    append_test_answer(&mut response, &[0xc0, 0x0c], TYPE_A, &[192, 0, 2, 77]);
                }
                socket.send_to(&response, peer).expect("send DNS response");
            }
        });

        let config = Config {
            upstreams: vec![server],
            fallback_upstreams: Vec::new(),
            domains: vec![
                Domain {
                    name: "route.test".to_owned(),
                    route_only: true,
                },
                Domain {
                    name: "example.test".to_owned(),
                    route_only: false,
                },
                Domain {
                    name: "lab.test".to_owned(),
                    route_only: false,
                },
            ],
            query_timeout: Duration::from_secs(1),
            attempts: 1,
            cache: false,
            read_etc_hosts: false,
            resolve_unicast_single_label: false,
            ..Config::default()
        };
        let lookup = Resolver::new(config)
            .lookup_name("host", 2)
            .expect("search-domain lookup");
        worker.join().expect("test DNS worker");
        assert_eq!(
            lookup.addresses,
            vec![IpAddr::V4(Ipv4Addr::new(192, 0, 2, 77))]
        );
        assert_eq!(lookup.canonical_name, "host.lab.test");
    }

}