4
0

soa.rs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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,
  11. /// Implementation and Specification (November 1987)
  12. #[derive(PartialEq, Debug)]
  13. pub struct SOA {
  14. /// The primary master name for this server.
  15. pub mname: Labels,
  16. /// The e-mail address of the administrator responsible for this DNS zone.
  17. pub rname: Labels,
  18. /// A serial number for this DNS zone.
  19. pub serial: u32,
  20. /// Duration, in seconds, after which secondary nameservers should query
  21. /// the master for _its_ SOA record.
  22. pub refresh_interval: u32,
  23. /// Duration, in seconds, after which secondary nameservers should retry
  24. /// requesting the serial number from the master if it does not respond.
  25. /// It should be less than `refresh`.
  26. pub retry_interval: u32,
  27. /// Duration, in seconds, after which secondary nameservers should stop
  28. /// answering requests for this zone if the master does not respond.
  29. /// It should be greater than the sum of `refresh` and `retry`.
  30. pub expire_limit: u32,
  31. /// Duration, in seconds, of the minimum time-to-live.
  32. pub minimum_ttl: u32,
  33. }
  34. impl Wire for SOA {
  35. const NAME: &'static str = "SOA";
  36. const RR_TYPE: u16 = 6;
  37. #[allow(clippy::similar_names)]
  38. #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
  39. fn read(stated_length: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
  40. let (mname, mname_length) = c.read_labels()?;
  41. trace!("Parsed mname -> {:?}", mname);
  42. let (rname, rname_length) = c.read_labels()?;
  43. trace!("Parsed rname -> {:?}", rname);
  44. let serial = c.read_u32::<BigEndian>()?;
  45. trace!("Parsed serial -> {:?}", serial);
  46. let refresh_interval = c.read_u32::<BigEndian>()?;
  47. trace!("Parsed refresh interval -> {:?}", refresh_interval);
  48. let retry_interval = c.read_u32::<BigEndian>()?;
  49. trace!("Parsed retry interval -> {:?}", retry_interval);
  50. let expire_limit = c.read_u32::<BigEndian>()?;
  51. trace!("Parsed expire limit -> {:?}", expire_limit);
  52. let minimum_ttl = c.read_u32::<BigEndian>()?;
  53. trace!("Parsed minimum TTL -> {:?}", minimum_ttl);
  54. let length_after_labels = 4 * 5 + mname_length + rname_length;
  55. if stated_length == length_after_labels {
  56. trace!("Length is correct");
  57. Ok(Self {
  58. mname, rname, serial, refresh_interval,
  59. retry_interval, expire_limit, minimum_ttl,
  60. })
  61. }
  62. else {
  63. warn!("Length is incorrect (stated length {:?}, mname plus rname plus fields length {:?})", stated_length, length_after_labels);
  64. Err(WireError::WrongLabelLength { stated_length, length_after_labels })
  65. }
  66. }
  67. }
  68. #[cfg(test)]
  69. mod test {
  70. use super::*;
  71. use pretty_assertions::assert_eq;
  72. #[test]
  73. fn parses() {
  74. let buf = &[
  75. 0x05, 0x62, 0x73, 0x61, 0x67, 0x6f, 0x02, 0x6d, 0x65, // mname
  76. 0x00, // mname terminator
  77. 0x05, 0x62, 0x73, 0x61, 0x67, 0x6f, 0x02, 0x6d, 0x65, // rname
  78. 0x00, // rname terminator
  79. 0x5d, 0x3c, 0xef, 0x02, // Serial
  80. 0x00, 0x01, 0x51, 0x80, // Refresh interval
  81. 0x00, 0x00, 0x1c, 0x20, // Retry interval
  82. 0x00, 0x09, 0x3a, 0x80, // Expire limit
  83. 0x00, 0x00, 0x01, 0x2c, // Minimum TTL
  84. ];
  85. assert_eq!(SOA::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(),
  86. SOA {
  87. mname: Labels::encode("bsago.me").unwrap(),
  88. rname: Labels::encode("bsago.me").unwrap(),
  89. serial: 1564274434,
  90. refresh_interval: 86400,
  91. retry_interval: 7200,
  92. expire_limit: 604800,
  93. minimum_ttl: 300,
  94. });
  95. }
  96. #[test]
  97. fn incorrect_record_length() {
  98. let buf = &[
  99. 0x03, 0x65, 0x66, 0x67, // mname
  100. 0x00, // mname terminator
  101. 0x03, 0x65, 0x66, 0x67, // rname
  102. 0x00, // rname terminator
  103. 0x5d, 0x3c, 0xef, 0x02, // Serial
  104. 0x00, 0x01, 0x51, 0x80, // Refresh interval
  105. 0x00, 0x00, 0x1c, 0x20, // Retry interval
  106. 0x00, 0x09, 0x3a, 0x80, // Expire limit
  107. 0x00, 0x00, 0x01, 0x2c, // Minimum TTL
  108. ];
  109. assert_eq!(SOA::read(89, &mut Cursor::new(buf)),
  110. Err(WireError::WrongLabelLength { stated_length: 89, length_after_labels: 30 }));
  111. }
  112. #[test]
  113. fn record_empty() {
  114. assert_eq!(SOA::read(0, &mut Cursor::new(&[])),
  115. Err(WireError::IO));
  116. }
  117. #[test]
  118. fn buffer_ends_abruptly() {
  119. let buf = &[
  120. 0x05, 0x62, // the start of an mname
  121. ];
  122. assert_eq!(SOA::read(23, &mut Cursor::new(buf)),
  123. Err(WireError::IO));
  124. }
  125. }