1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
extern crate base64;
extern crate byteorder;

mod dnscrypt;
mod doh;

pub use self::dnscrypt::*;
pub use self::doh::*;
use std::io::{self, Write};

#[derive(Copy, Clone, Debug)]
pub enum Protocol {
    Plain = 0x00,
    DNSCrypt = 0x01,
    DoH = 0x02,
    DoT = 0x03,
}

pub enum InformalProperty {
    DNSSEC,
    NoLogs,
    NoFilters,
}

impl From<InformalProperty> for u64 {
    fn from(informal_property: InformalProperty) -> u64 {
        match informal_property {
            InformalProperty::DNSSEC => 0x01,
            InformalProperty::NoLogs => 0x02,
            InformalProperty::NoFilters => 0x04,
        }
    }
}

pub trait WithInformalProperty {
    fn with_informal_property(self, informal_property: InformalProperty) -> Self;
}

fn lp_encode<W: Write>(writer: &mut W, string: &[u8]) -> io::Result<()> {
    let mut encoded = vec![];
    let len = string.len();
    assert!(len <= 0xff);
    encoded.push(len as u8);
    encoded.extend(&string[..]);
    writer.write_all(&encoded)
}

fn vlp_encode<W: Write>(writer: &mut W, strings: &[Vec<u8>]) -> io::Result<()> {
    if strings.is_empty() {
        return writer.write_all(&[0u8]);
    }
    let mut encoded = vec![];
    let mut it = strings.iter();
    let mut next = it.next();
    while let Some(string) = next {
        next = it.next();
        let len = string.len();
        assert!(len < 0x80);
        match next {
            None => encoded.push(len as u8),
            _ => encoded.push(0x80 | len as u8),
        };
        encoded.extend(&string[..]);
    }
    writer.write_all(&encoded)
}

#[test]
fn test_doh() {
    let b = DoHBuilder::new("example.com".to_owned(), "/dns".to_owned())
        .with_address("127.0.0.1:443".to_string())
        .with_informal_property(InformalProperty::DNSSEC)
        .serialize()
        .unwrap();
    assert_eq!(
        b,
        "sdns://AgEAAAAAAAAADTEyNy4wLjAuMTo0NDMAC2V4YW1wbGUuY29tBC9kbnM",
    )
}