flex_dns/rdata/
tsig.rs

1use crate::{Buffer, DnsMessage, DnsMessageError, MutBuffer};
2use crate::characters::Characters;
3use crate::name::DnsName;
4use crate::parse::Parse;
5use crate::rdata::{RData, RDataParse};
6use crate::write::WriteBytes;
7
8/// # Transaction signature record (TSIG)
9/// This record is used to authenticate dynamic updates as coming from an
10/// approved client, and to authenticate responses as coming from an approved
11/// recursive server.
12#[derive(Copy, Clone, Debug, PartialEq)]
13pub struct TSig<'a> {
14    /// The name of the algorithm in domain name syntax.
15    pub algorithm: DnsName<'a>,
16    /// The time that the signature was generated.
17    pub time_signed: u64,
18    /// The Fudge value is an unsigned 8-bit field that specifies the allowed
19    /// time difference in seconds.
20    pub fudge: u8,
21    /// The MAC is a variable length octet string containing the message
22    /// authentication code.
23    pub mac: Characters<'a>,
24    /// The original ID of the message.
25    pub original_id: u16,
26    /// The error field is an unsigned 16-bit field that contains the extended
27    /// RCODE covering TSIG processing.
28    pub error: u16,
29    /// The other field is a variable length octet string that contains
30    /// information that may be used by the server to complete the transaction.
31    pub other: Characters<'a>,
32}
33
34impl<'a> RDataParse<'a> for TSig<'a> {
35    #[inline]
36    fn parse(rdata: &RData<'a>, i: &mut usize) -> Result<Self, DnsMessageError> {
37        let algorithm = DnsName::parse(rdata, i)?;
38        let time_signed = u64::parse(rdata, i)?;
39        let fudge = u8::parse(rdata, i)?;
40        let mac = Characters::parse(rdata, i)?;
41        let original_id = u16::parse(rdata, i)?;
42        let error = u16::parse(rdata, i)?;
43        let other = Characters::parse(rdata, i)?;
44
45        Ok(Self {
46            algorithm,
47            time_signed,
48            fudge,
49            mac,
50            original_id,
51            error,
52            other,
53        })
54    }
55}
56
57impl<'a> WriteBytes for TSig<'a> {
58    #[inline]
59    fn write<
60        const PTR_STORAGE: usize,
61        const DNS_SECTION: usize,
62        B: MutBuffer + Buffer,
63    >(&self, message: &mut DnsMessage<PTR_STORAGE, DNS_SECTION, B>) -> Result<usize, DnsMessageError> {
64        let mut bytes = 0;
65
66        bytes += self.algorithm.write(message)?;
67        bytes += self.time_signed.write(message)?;
68        bytes += self.fudge.write(message)?;
69        bytes += self.mac.write(message)?;
70        bytes += self.original_id.write(message)?;
71        bytes += self.error.write(message)?;
72        bytes += self.other.write(message)?;
73
74        Ok(bytes)
75    }
76}
77
78#[cfg(test)]
79mod test {
80    use crate::rdata::testutils::parse_write_test;
81
82    use super::*;
83
84    parse_write_test!(
85        26,
86        [
87            0x03, b'w', b'w', b'w', 0x00, // algorithm
88            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, // time_signed
89            0x0b, // fudge
90            0x03, 0x77, 0x77, 0x77, // mac
91            0x00, 0x0c, // original_id
92            0x00, 0x0d, // error
93            0x03, 0x77, 0x77, 0x77, // other
94        ],
95        TSig {
96            algorithm: unsafe { DnsName::new_unchecked(b"\x03www\x00") },
97            time_signed: 10,
98            fudge: 11,
99            mac: unsafe { Characters::new_unchecked(b"www") },
100            original_id: 12,
101            error: 13,
102            other: unsafe { Characters::new_unchecked(b"www") },
103        },
104    );
105}