123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- use log::*;
- use crate::strings::ReadLabels;
- use crate::wire::*;
- /// A **SOA** _(start of authority)_ record, which contains administrative
- /// information about the zone the domain is in. These are returned when a
- /// server does not have a record for a domain.
- ///
- /// # References
- ///
- /// - [RFC 1035 §3.3.13](https://tools.ietf.org/html/rfc1035) — Domain Names, Implementation and Specification (November 1987)
- #[derive(PartialEq, Debug, Clone)]
- pub struct SOA {
- /// The primary master name for this server.
- pub mname: String,
- /// The e-mail address of the administrator responsible for this DNS zone.
- pub rname: String,
- /// A serial number for this DNS zone.
- pub serial: u32,
- /// Duration, in seconds, after which secondary nameservers should query
- /// the master for _its_ SOA record.
- pub refresh_interval: u32,
- /// Duration, in seconds, after which secondary nameservers should retry
- /// requesting the serial number from the master if it does not respond.
- /// It should be less than `refresh`.
- pub retry_interval: u32,
- /// Duration, in seconds, after which secondary nameservers should stop
- /// answering requests for this zone if the master does not respond.
- /// It should be greater than the sum of `refresh` and `retry`.
- pub expire_limit: u32,
- /// Duration, in seconds, of the minimum time-to-live.
- pub minimum_ttl: u32,
- }
- impl Wire for SOA {
- const NAME: &'static str = "SOA";
- const RR_TYPE: u16 = 6;
- #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
- fn read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
- let (mname, mname_len) = c.read_labels()?;
- trace!("Parsed mname -> {:?}", mname);
- let (rname, rname_len) = c.read_labels()?;
- trace!("Parsed rname -> {:?}", rname);
- let serial = c.read_u32::<BigEndian>()?;
- trace!("Parsed serial -> {:?}", serial);
- let refresh_interval = c.read_u32::<BigEndian>()?;
- trace!("Parsed refresh interval -> {:?}", refresh_interval);
- let retry_interval = c.read_u32::<BigEndian>()?;
- trace!("Parsed retry interval -> {:?}", retry_interval);
- let expire_limit = c.read_u32::<BigEndian>()?;
- trace!("Parsed expire limit -> {:?}", expire_limit);
- let minimum_ttl = c.read_u32::<BigEndian>()?;
- trace!("Parsed minimum TTL -> {:?}", minimum_ttl);
- let got_len = 4 * 5 + mname_len + rname_len;
- if len == got_len {
- trace!("Length is correct");
- Ok(Self {
- mname, rname, serial, refresh_interval,
- retry_interval, expire_limit, minimum_ttl,
- })
- }
- else {
- warn!("Length is incorrect (record length {:?}, mname plus rname plus fields length {:?})", len, got_len);
- Err(WireError::WrongLabelLength { expected: len, got: got_len })
- }
- }
- }
- #[cfg(test)]
- mod test {
- use super::*;
- #[test]
- fn parses() {
- let buf = &[
- 0x05, 0x62, 0x73, 0x61, 0x67, 0x6f, 0x02, 0x6d, 0x65, // mname
- 0x00, // mname terminator
- 0x05, 0x62, 0x73, 0x61, 0x67, 0x6f, 0x02, 0x6d, 0x65, // rname
- 0x00, // rname terminator
- 0x5d, 0x3c, 0xef, 0x02, // Serial
- 0x00, 0x01, 0x51, 0x80, // Refresh interval
- 0x00, 0x00, 0x1c, 0x20, // Retry interval
- 0x00, 0x09, 0x3a, 0x80, // Expire limit
- 0x00, 0x00, 0x01, 0x2c, // Minimum TTL
- ];
- assert_eq!(SOA::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(),
- SOA {
- mname: String::from("bsago.me."),
- rname: String::from("bsago.me."),
- serial: 1564274434,
- refresh_interval: 86400,
- retry_interval: 7200,
- expire_limit: 604800,
- minimum_ttl: 300,
- });
- }
- #[test]
- fn record_empty() {
- assert_eq!(SOA::read(0, &mut Cursor::new(&[])),
- Err(WireError::IO));
- }
- #[test]
- fn buffer_ends_abruptly() {
- let buf = &[
- 0x05, 0x62, // the start of an mname
- ];
- assert_eq!(SOA::read(23, &mut Cursor::new(buf)),
- Err(WireError::IO));
- }
- }
|