opt.rs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. use std::convert::TryFrom;
  2. use std::io;
  3. use log::*;
  4. use crate::wire::*;
  5. /// A **OPT** _(options)_ pseudo-record, which is used to extend the DNS
  6. /// protocol with additional flags such as DNSSEC stuff.
  7. ///
  8. /// # Pseudo-record?
  9. ///
  10. /// Unlike all the other record types, which are used to return data about a
  11. /// domain name, the OPT record type is used to add more options to the
  12. /// request, including data about the client or the server. It can exist, with
  13. /// a payload, as a query or a response, though it’s usually encountered in
  14. /// the Additional section. Its purpose is to add more room to the DNS wire
  15. /// format, as backwards compatibility makes it impossible to simply add more
  16. /// flags to the header.
  17. ///
  18. /// The fact that this isn’t a standard record type is annoying for a DNS
  19. /// implementation. It re-purposes the ‘class’ and ‘TTL’ fields of the
  20. /// `Answer` struct, as they only have meaning when associated with a domain
  21. /// name. This means that the parser has to treat the OPT type specially,
  22. /// switching to `Opt::read` as soon as the rtype is detected. It also means
  23. /// the output has to deal with missing classes and TTLs.
  24. ///
  25. /// # References
  26. ///
  27. /// - [RFC 6891](https://tools.ietf.org/html/rfc6891) — Extension Mechanisms
  28. /// for DNS (April 2013)
  29. #[derive(PartialEq, Debug, Clone)]
  30. pub struct OPT {
  31. /// The maximum size of a UDP packet that the client supports.
  32. pub udp_payload_size: u16,
  33. /// The bits that form an extended rcode when non-zero.
  34. pub higher_bits: u8,
  35. /// The version number of the DNS extension mechanism.
  36. pub edns0_version: u8,
  37. /// Sixteen bits worth of flags.
  38. pub flags: u16,
  39. /// The payload of the OPT record.
  40. pub data: Vec<u8>,
  41. }
  42. impl OPT {
  43. /// The record type number associated with OPT.
  44. pub const RR_TYPE: u16 = 41;
  45. /// Reads from the given cursor to parse an OPT record.
  46. ///
  47. /// The buffer will have slightly more bytes to read for an OPT record
  48. /// than for a typical one: we will not have encountered the ‘class’ or
  49. /// ‘ttl’ fields, which have different meanings for this record type.
  50. /// See §6.1.3 of the RFC, “OPT Record TTL Field Use”.
  51. ///
  52. /// Unlike the `Wire::read` function, this does not require a length.
  53. #[cfg_attr(feature = "with_mutagen", ::mutagen::mutate)]
  54. pub fn read(c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
  55. let udp_payload_size = c.read_u16::<BigEndian>()?; // replaces the class field
  56. trace!("Parsed UDP payload size -> {:?}", udp_payload_size);
  57. let higher_bits = c.read_u8()?; // replaces the ttl field...
  58. trace!("Parsed higher bits -> {:#08b}", higher_bits);
  59. let edns0_version = c.read_u8()?; // ...as does this...
  60. trace!("Parsed EDNS(0) version -> {:?}", edns0_version);
  61. let flags = c.read_u16::<BigEndian>()?; // ...as does this
  62. trace!("Parsed flags -> {:#08b}", flags);
  63. let data_length = c.read_u16::<BigEndian>()?;
  64. trace!("Parsed data length -> {:?}", data_length);
  65. let mut data = vec![0_u8; usize::from(data_length)];
  66. c.read_exact(&mut data)?;
  67. trace!("Parsed data -> {:#x?}", data);
  68. Ok(Self { udp_payload_size, higher_bits, edns0_version, flags, data })
  69. }
  70. /// Serialises this OPT record into a vector of bytes.
  71. ///
  72. /// This is necessary for OPT records to be sent in the Additional section
  73. /// of requests.
  74. pub fn to_bytes(&self) -> io::Result<Vec<u8>> {
  75. let mut bytes = Vec::with_capacity(32);
  76. bytes.write_u16::<BigEndian>(self.udp_payload_size)?;
  77. bytes.write_u8(self.higher_bits)?;
  78. bytes.write_u8(self.edns0_version)?;
  79. bytes.write_u16::<BigEndian>(self.flags)?;
  80. // We should not be sending any data at all in the request, really,
  81. // so sending too much data is downright nonsensical
  82. let data_len = u16::try_from(self.data.len()).expect("Sending too much data");
  83. bytes.write_u16::<BigEndian>(data_len)?;
  84. for b in &self.data {
  85. bytes.write_u8(*b)?;
  86. }
  87. Ok(bytes)
  88. }
  89. }
  90. #[cfg(test)]
  91. mod test {
  92. use super::*;
  93. use pretty_assertions::assert_eq;
  94. #[test]
  95. fn parses_no_data() {
  96. let buf = &[
  97. 0x05, 0xAC, // UDP payload size
  98. 0x00, // higher bits
  99. 0x00, 0x00, // EDNS(0) version
  100. 0x00, 0x00, // flags
  101. 0x00, // data length (followed by no data)
  102. ];
  103. assert_eq!(OPT::read(&mut Cursor::new(buf)).unwrap(),
  104. OPT {
  105. udp_payload_size: 1452,
  106. higher_bits: 0,
  107. edns0_version: 0,
  108. flags: 0,
  109. data: vec![],
  110. });
  111. }
  112. #[test]
  113. fn parses_with_data() {
  114. let buf = &[
  115. 0x05, 0xAC, // UDP payload size
  116. 0x00, // higher bits
  117. 0x00, 0x00, // EDNS(0) version
  118. 0x00, 0x00, // flags
  119. 0x04, // data length
  120. 0x01, 0x02, 0x03, 0x04, // data
  121. ];
  122. assert_eq!(OPT::read(&mut Cursor::new(buf)).unwrap(),
  123. OPT {
  124. udp_payload_size: 1452,
  125. higher_bits: 0,
  126. edns0_version: 0,
  127. flags: 0,
  128. data: vec![1, 2, 3, 4],
  129. });
  130. }
  131. #[test]
  132. fn record_empty() {
  133. assert_eq!(OPT::read(&mut Cursor::new(&[])),
  134. Err(WireError::IO));
  135. }
  136. #[test]
  137. fn buffer_ends_abruptly() {
  138. let buf = &[
  139. 0x05, // half a UDP payload size
  140. ];
  141. assert_eq!(OPT::read(&mut Cursor::new(buf)),
  142. Err(WireError::IO));
  143. }
  144. }