1#![warn(rust_2018_idioms, missing_debug_implementations)]
6
7use dominion::{DnsPacket, Name, QType, ServerService};
8use serde::Deserialize;
9use std::{collections::BTreeMap, net::SocketAddr};
10
11mod a;
12mod txt;
13
14#[derive(Debug)]
15pub struct Chat<'a> {
16 domain: Name<'a>,
17 xor: Option<Xor>,
18 files: Option<txt::TxtHandler>,
19}
20
21impl<'a> Chat<'a> {
22 pub fn new(name: Name<'a>, xor: Option<Xor>, files: Option<BTreeMap<String, String>>) -> Self {
23 let files = files.map(|f| txt::TxtHandler::new(f.into_iter()));
24 Chat {
25 domain: name,
26 files,
27 xor,
28 }
29 }
30}
31
32impl ServerService for Chat<'_> {
33 fn run<'a>(&self, client: SocketAddr, question: &'a DnsPacket<'a>) -> Option<DnsPacket<'a>> {
34 if question.header.questions > 0 {
35 match question.questions[0].qtype {
36 QType::A => Some(a::response(client, question, &self.domain, &self.xor)),
37 QType::Txt => {
38 self.files.as_ref().map(|files| files.response(question, &self.domain, &self.xor))
39 }
40 _ => Some(refused(question.header.id)),
41 }
42 } else {
43 Some(refused(question.header.id))
44 }
45 }
46}
47
48#[derive(Debug, Deserialize)]
49pub struct Xor {
51 key: u8,
52 signal: String,
53}
54
55fn refused(id: u16) -> DnsPacket<'static> {
56 use dominion::*;
57
58 let flags = Flags {
59 qr: QueryResponse::Response,
60 opcode: OpCode::Query,
61 aa: AuthoritativeAnswer::Authoritative,
62 tc: TrunCation::NotTruncated,
63 rd: RecursionDesired::NotDesired,
64 ra: RecursionAvailable::NotAvailable,
65 z: Zero::Zero,
66 ad: AuthenticData::NotAuthentic,
67 cd: CheckingDisabled::Disabled,
68 rcode: ResponseCode::Refused,
69 };
70
71 let header = DnsHeader {
72 id,
73 flags,
74 questions: 0,
75 answers: 0,
76 authority: 0,
77 additional: 0,
78 };
79 DnsPacket {
80 header,
81 questions: vec![],
82 answers: vec![],
83 authority: vec![],
84 additional: vec![],
85 }
86}