soa.rs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. use log::*;
  2. use crate::strings::{Labels, ReadLabels};
  3. use crate::wire::*;
  4. /// A **SOA** _(start of authority)_ record, which contains administrative
  5. /// information about the zone the domain is in. These are returned when a
  6. /// server does not have a record for a domain.
  7. ///
  8. /// # References
  9. ///
  10. /// - [RFC 1035 §3.3.13](https://tools.ietf.org/html/rfc1035) — Domain Names, Implementation and Specification (November 1987)
  11. #[derive(PartialEq, Debug)]
  12. pub struct SOA {
  13. /// The primary master name for this server.
  14. pub mname: Labels,
  15. /// The e-mail address of the administrator responsible for this DNS zone.
  16. pub rname: Labels,
  17. /// A serial number for this DNS zone.
  18. pub serial: u32,
  19. /// Duration, in seconds, after which secondary nameservers should query
  20. /// the master for _its_ SOA record.
  21. pub refresh_interval: u32,
  22. /// Duration, in seconds, after which secondary nameservers should retry
  23. /// requesting the serial number from the master if it does not respond.
  24. /// It should be less than `refresh`.
  25. pub retry_interval: u32,
  26. /// Duration, in seconds, after which secondary nameservers should stop
  27. /// answering requests for this zone if the master does not respond.
  28. /// It should be greater than the sum of `refresh` and `retry`.
  29. pub expire_limit: u32,
  30. /// Duration, in seconds, of the minimum time-to-live.
  31. pub minimum_ttl: u32,
  32. }
  33. impl Wire for SOA {
  34. const NAME: &'static str = "SOA";
  35. const RR_TYPE: u16 = 6;
  36. #[allow(clippy::similar_names)]
  37. #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
  38. fn read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
  39. let (mname, mname_len) = c.read_labels()?;
  40. trace!("Parsed mname -> {:?}", mname);
  41. let (rname, rname_len) = c.read_labels()?;
  42. trace!("Parsed rname -> {:?}", rname);
  43. let serial = c.read_u32::<BigEndian>()?;
  44. trace!("Parsed serial -> {:?}", serial);
  45. let refresh_interval = c.read_u32::<BigEndian>()?;
  46. trace!("Parsed refresh interval -> {:?}", refresh_interval);
  47. let retry_interval = c.read_u32::<BigEndian>()?;
  48. trace!("Parsed retry interval -> {:?}", retry_interval);
  49. let expire_limit = c.read_u32::<BigEndian>()?;
  50. trace!("Parsed expire limit -> {:?}", expire_limit);
  51. let minimum_ttl = c.read_u32::<BigEndian>()?;
  52. trace!("Parsed minimum TTL -> {:?}", minimum_ttl);
  53. let got_len = 4 * 5 + mname_len + rname_len;
  54. if len == got_len {
  55. trace!("Length is correct");
  56. Ok(Self {
  57. mname, rname, serial, refresh_interval,
  58. retry_interval, expire_limit, minimum_ttl,
  59. })
  60. }
  61. else {
  62. warn!("Length is incorrect (record length {:?}, mname plus rname plus fields length {:?})", len, got_len);
  63. Err(WireError::WrongLabelLength { expected: len, got: got_len })
  64. }
  65. }
  66. }
  67. #[cfg(test)]
  68. mod test {
  69. use super::*;
  70. #[test]
  71. fn parses() {
  72. let buf = &[
  73. 0x05, 0x62, 0x73, 0x61, 0x67, 0x6f, 0x02, 0x6d, 0x65, // mname
  74. 0x00, // mname terminator
  75. 0x05, 0x62, 0x73, 0x61, 0x67, 0x6f, 0x02, 0x6d, 0x65, // rname
  76. 0x00, // rname terminator
  77. 0x5d, 0x3c, 0xef, 0x02, // Serial
  78. 0x00, 0x01, 0x51, 0x80, // Refresh interval
  79. 0x00, 0x00, 0x1c, 0x20, // Retry interval
  80. 0x00, 0x09, 0x3a, 0x80, // Expire limit
  81. 0x00, 0x00, 0x01, 0x2c, // Minimum TTL
  82. ];
  83. assert_eq!(SOA::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(),
  84. SOA {
  85. mname: Labels::encode("bsago.me").unwrap(),
  86. rname: Labels::encode("bsago.me").unwrap(),
  87. serial: 1564274434,
  88. refresh_interval: 86400,
  89. retry_interval: 7200,
  90. expire_limit: 604800,
  91. minimum_ttl: 300,
  92. });
  93. }
  94. #[test]
  95. fn record_empty() {
  96. assert_eq!(SOA::read(0, &mut Cursor::new(&[])),
  97. Err(WireError::IO));
  98. }
  99. #[test]
  100. fn buffer_ends_abruptly() {
  101. let buf = &[
  102. 0x05, 0x62, // the start of an mname
  103. ];
  104. assert_eq!(SOA::read(23, &mut Cursor::new(buf)),
  105. Err(WireError::IO));
  106. }
  107. }