mx.rs 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. use log::*;
  2. use crate::strings::{Labels, ReadLabels};
  3. use crate::wire::*;
  4. /// An **MX** _(mail exchange)_ record, which contains the hostnames for mail
  5. /// servers that handle mail sent to the domain.
  6. ///
  7. /// # References
  8. ///
  9. /// - [RFC 1035 §3.3.9](https://tools.ietf.org/html/rfc1035) — Domain Names,
  10. /// Implementation and Specification (November 1987)
  11. #[derive(PartialEq, Debug)]
  12. pub struct MX {
  13. /// The preference that clients should give to this MX record amongst all
  14. /// that get returned.
  15. pub preference: u16,
  16. /// The domain name of the mail exchange server.
  17. pub exchange: Labels,
  18. }
  19. impl Wire for MX {
  20. const NAME: &'static str = "MX";
  21. const RR_TYPE: u16 = 15;
  22. #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
  23. fn read(stated_length: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
  24. let preference = c.read_u16::<BigEndian>()?;
  25. trace!("Parsed preference -> {:?}", preference);
  26. let (exchange, exchange_length) = c.read_labels()?;
  27. trace!("Parsed exchange -> {:?}", exchange);
  28. let length_after_labels = 2 + exchange_length;
  29. if stated_length == length_after_labels {
  30. trace!("Length is correct");
  31. Ok(Self { preference, exchange })
  32. }
  33. else {
  34. warn!("Length is incorrect (stated length {:?}, preference plus exchange length {:?}", stated_length, length_after_labels);
  35. Err(WireError::WrongLabelLength { stated_length, length_after_labels })
  36. }
  37. }
  38. }
  39. #[cfg(test)]
  40. mod test {
  41. use super::*;
  42. use pretty_assertions::assert_eq;
  43. #[test]
  44. fn parses() {
  45. let buf = &[
  46. 0x00, 0x0A, // preference
  47. 0x05, 0x62, 0x73, 0x61, 0x67, 0x6f, 0x02, 0x6d, 0x65, // exchange
  48. 0x00, // exchange terminator
  49. ];
  50. assert_eq!(MX::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(),
  51. MX {
  52. preference: 10,
  53. exchange: Labels::encode("bsago.me").unwrap(),
  54. });
  55. }
  56. #[test]
  57. fn incorrect_record_length() {
  58. let buf = &[
  59. 0x00, 0x0A, // preference
  60. 0x03, 0x65, 0x66, 0x67, // domain
  61. 0x00, // domain terminator
  62. ];
  63. assert_eq!(MX::read(6, &mut Cursor::new(buf)),
  64. Err(WireError::WrongLabelLength { stated_length: 6, length_after_labels: 7 }));
  65. }
  66. #[test]
  67. fn record_empty() {
  68. assert_eq!(MX::read(0, &mut Cursor::new(&[])),
  69. Err(WireError::IO));
  70. }
  71. #[test]
  72. fn buffer_ends_abruptly() {
  73. let buf = &[
  74. 0x00, 0x0A, // half a preference
  75. ];
  76. assert_eq!(MX::read(23, &mut Cursor::new(buf)),
  77. Err(WireError::IO));
  78. }
  79. }