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
80
81
82
83
84
85
86
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

#![warn(rust_2018_idioms, missing_debug_implementations)]

use dominion::{DnsPacket, Name, QType, ServerService};
use serde::Deserialize;
use std::{collections::BTreeMap, net::SocketAddr};

mod a;
mod txt;

#[derive(Debug)]
pub struct Chat<'a> {
    domain: Name<'a>,
    xor: Option<Xor>,
    files: Option<txt::TxtHandler>,
}

impl<'a> Chat<'a> {
    pub fn new(name: Name<'a>, xor: Option<Xor>, files: Option<BTreeMap<String, String>>) -> Self {
        let files = files.map(|f| txt::TxtHandler::new(f.into_iter()));
        Chat {
            domain: name,
            files,
            xor,
        }
    }
}

impl ServerService for Chat<'_> {
    fn run<'a>(&self, client: SocketAddr, question: &'a DnsPacket<'a>) -> Option<DnsPacket<'a>> {
        if question.header.questions > 0 {
            match question.questions[0].qtype {
                QType::A => Some(a::response(client, question, &self.domain, &self.xor)),
                QType::Txt => {
                    self.files.as_ref().map(|files| files.response(question, &self.domain, &self.xor))
                }
                _ => Some(refused(question.header.id)),
            }
        } else {
            Some(refused(question.header.id))
        }
    }
}

#[derive(Debug, Deserialize)]
/// Configuration from file
pub struct Xor {
    key: u8,
    signal: String,
}

fn refused(id: u16) -> DnsPacket<'static> {
    use dominion::*;

    let flags = Flags {
        qr: QueryResponse::Response,
        opcode: OpCode::Query,
        aa: AuthoritativeAnswer::Authoritative,
        tc: TrunCation::NotTruncated,
        rd: RecursionDesired::NotDesired,
        ra: RecursionAvailable::NotAvailable,
        z: Zero::Zero,
        ad: AuthenticData::NotAuthentic,
        cd: CheckingDisabled::Disabled,
        rcode: ResponseCode::Refused,
    };

    let header = DnsHeader {
        id,
        flags,
        questions: 0,
        answers: 0,
        authority: 0,
        additional: 0,
    };
    DnsPacket {
        header,
        questions: vec![],
        answers: vec![],
        authority: vec![],
        additional: vec![],
    }
}