4
0

wire_parsing_tests.rs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. use std::net::Ipv4Addr;
  2. use dns::{Response, Query, Answer, Labels, Flags, Opcode, QClass};
  3. use dns::record::{Record, A, CNAME, OPT, SOA, UnknownQtype, RecordType};
  4. use pretty_assertions::assert_eq;
  5. #[test]
  6. fn parse_nothing() {
  7. assert!(Response::from_bytes(&[]).is_err());
  8. }
  9. #[test]
  10. fn parse_response_standard() {
  11. let buf = &[
  12. 0x0d, 0xcd, // transaction ID
  13. 0x81, 0x80, // flags (standard query, response, no error)
  14. 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, // counts (1, 1, 0, 1)
  15. // the query:
  16. 0x03, 0x64, 0x6e, 0x73, 0x06, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x03,
  17. 0x64, 0x6f, 0x67, 0x00, // "dns.lookup.dog."
  18. 0x00, 0x01, // type A
  19. 0x00, 0x01, // class IN
  20. // the answer:
  21. 0xc0, 0x0c, // to find the name, backtrack to position 0x0c (12)
  22. 0x00, 0x01, // type A
  23. 0x00, 0x01, // class IN
  24. 0x00, 0x00, 0x03, 0xa5, // TTL (933 seconds)
  25. 0x00, 0x04, // record data length 4
  26. 0x8a, 0x44, 0x75, 0x5e, // record date (138.68.117.94)
  27. // the additional:
  28. 0x00, // no name
  29. 0x00, 0x29, // type OPT
  30. 0x02, 0x00, // UDP payload size (512)
  31. 0x00, 0x00, // higher bits (all 0)
  32. 0x00, // EDNS version
  33. 0x00, 0x00, // extra bits (DO bit unset)
  34. 0x00, // data length 0
  35. ];
  36. let response = Response {
  37. transaction_id: 0x0dcd,
  38. flags: Flags {
  39. response: true,
  40. opcode: Opcode::Query,
  41. authoritative: false,
  42. truncated: false,
  43. recursion_desired: true,
  44. recursion_available: true,
  45. authentic_data: false,
  46. checking_disabled: false,
  47. error_code: None,
  48. },
  49. queries: vec![
  50. Query {
  51. qname: Labels::encode("dns.lookup.dog").unwrap(),
  52. qclass: QClass::IN,
  53. qtype: RecordType::A,
  54. },
  55. ],
  56. answers: vec![
  57. Answer::Standard {
  58. qname: Labels::encode("dns.lookup.dog").unwrap(),
  59. qclass: QClass::IN,
  60. ttl: 933,
  61. record: Record::A(A {
  62. address: Ipv4Addr::new(138, 68, 117, 94),
  63. }),
  64. }
  65. ],
  66. authorities: vec![],
  67. additionals: vec![
  68. Answer::Pseudo {
  69. qname: Labels::root(),
  70. opt: OPT {
  71. udp_payload_size: 512,
  72. higher_bits: 0,
  73. edns0_version: 0,
  74. flags: 0,
  75. data: vec![],
  76. },
  77. },
  78. ],
  79. };
  80. assert_eq!(Response::from_bytes(buf), Ok(response));
  81. }
  82. #[test]
  83. fn parse_response_with_mixed_string() {
  84. let buf = &[
  85. 0x06, 0x9f, // transaction ID
  86. 0x81, 0x80, // flags (standard query, response, no error)
  87. 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // counts (1, 1, 0, 0)
  88. // the query:
  89. 0x0d, 0x63, 0x6e, 0x61, 0x6d, 0x65, 0x2d, 0x65, 0x78, 0x61, 0x6d, 0x70,
  90. 0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x03, 0x64, 0x6f,
  91. 0x67, 0x00, // "cname-example.lookup.dog"
  92. 0x00, 0x05, // type CNAME
  93. 0x00, 0x01, // class IN
  94. // the answer:
  95. 0xc0, 0x0c, // to find the name, backtrack to position 0x0c (12)
  96. 0x00, 0x05, // type CNAME
  97. 0x00, 0x01, // class IN
  98. 0x00, 0x00, 0x03, 0x69, // TTL (873 seconds)
  99. 0x00, 0x06, // record data length 6
  100. 0x03, 0x64, 0x6e, 0x73, 0xc0, 0x1a,
  101. // "dns.lookup.dog.", which is "dns." + backtrack to position 0x1a (28)
  102. ];
  103. let response = Response {
  104. transaction_id: 0x069f,
  105. flags: Flags {
  106. response: true,
  107. opcode: Opcode::Query,
  108. authoritative: false,
  109. truncated: false,
  110. recursion_desired: true,
  111. recursion_available: true,
  112. authentic_data: false,
  113. checking_disabled: false,
  114. error_code: None,
  115. },
  116. queries: vec![
  117. Query {
  118. qname: Labels::encode("cname-example.lookup.dog").unwrap(),
  119. qclass: QClass::IN,
  120. qtype: RecordType::CNAME,
  121. },
  122. ],
  123. answers: vec![
  124. Answer::Standard {
  125. qname: Labels::encode("cname-example.lookup.dog").unwrap(),
  126. qclass: QClass::IN,
  127. ttl: 873,
  128. record: Record::CNAME(CNAME {
  129. domain: Labels::encode("dns.lookup.dog").unwrap(),
  130. }),
  131. }
  132. ],
  133. authorities: vec![],
  134. additionals: vec![],
  135. };
  136. assert_eq!(Response::from_bytes(buf), Ok(response));
  137. }
  138. #[test]
  139. fn parse_response_with_multiple_additionals() {
  140. // This is an artifical amalgam of DNS, not a real-world response!
  141. let buf = &[
  142. 0xce, 0xac, // transaction ID
  143. 0x81, 0x80, // flags (standard query, response, no error)
  144. 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, // counts (1, 1, 1, 2)
  145. // query:
  146. 0x05, 0x62, 0x73, 0x61, 0x67, 0x6f, 0x02, 0x6d, 0x65, 0x00, // name
  147. 0x00, 0x01, // type A
  148. 0x00, 0x01, // class IN
  149. // answer:
  150. 0xc0, 0x0c, // name (backreference)
  151. 0x00, 0x01, // type A
  152. 0x00, 0x01, // class IN
  153. 0x00, 0x00, 0x03, 0x77, // TTL
  154. 0x00, 0x04, // data length 4
  155. 0x8a, 0x44, 0x75, 0x5e, // IP address
  156. // authoritative:
  157. 0x00, // name
  158. 0x00, 0x06, // type SOA
  159. 0x00, 0x01, // class IN
  160. 0xFF, 0xFF, 0xFF, 0xFF, // TTL (maximum possible!)
  161. 0x00, 0x1B, // data length
  162. 0x01, 0x61, 0x00, // primary name server ("a")
  163. 0x02, 0x6d, 0x78, 0x00, // mailbox ("mx")
  164. 0x78, 0x68, 0x52, 0x2c, // serial number
  165. 0x00, 0x00, 0x07, 0x08, // refresh interval
  166. 0x00, 0x00, 0x03, 0x84, // retry interval
  167. 0x00, 0x09, 0x3a, 0x80, // expire limit
  168. 0x00, 0x01, 0x51, 0x80, // minimum TTL
  169. // additional 1:
  170. 0x00, // name
  171. 0x00, 0x99, // unknown type
  172. 0x00, 0x99, // unknown class
  173. 0x12, 0x34, 0x56, 0x78, // TTL
  174. 0x00, 0x04, // data length 4
  175. 0x12, 0x34, 0x56, 0x78, // data
  176. // additional 2:
  177. 0x00, // name
  178. 0x00, 0x29, // type OPT
  179. 0x02, 0x00, // UDP payload size
  180. 0x00, // higher bits
  181. 0x00, // EDNS(0) version
  182. 0x00, 0x00, // more flags
  183. 0x00, 0x00, // no data
  184. ];
  185. let response = Response {
  186. transaction_id: 0xceac,
  187. flags: Flags::standard_response(),
  188. queries: vec![
  189. Query {
  190. qname: Labels::encode("bsago.me").unwrap(),
  191. qclass: QClass::IN,
  192. qtype: RecordType::A,
  193. },
  194. ],
  195. answers: vec![
  196. Answer::Standard {
  197. qname: Labels::encode("bsago.me").unwrap(),
  198. qclass: QClass::IN,
  199. ttl: 887,
  200. record: Record::A(A {
  201. address: Ipv4Addr::new(138, 68, 117, 94),
  202. }),
  203. }
  204. ],
  205. authorities: vec![
  206. Answer::Standard {
  207. qname: Labels::root(),
  208. qclass: QClass::IN,
  209. ttl: 4294967295,
  210. record: Record::SOA(SOA {
  211. mname: Labels::encode("a").unwrap(),
  212. rname: Labels::encode("mx").unwrap(),
  213. serial: 2020102700,
  214. refresh_interval: 1800,
  215. retry_interval: 900,
  216. expire_limit: 604800,
  217. minimum_ttl: 86400,
  218. }),
  219. }
  220. ],
  221. additionals: vec![
  222. Answer::Standard {
  223. qname: Labels::root(),
  224. qclass: QClass::Other(153),
  225. ttl: 305419896,
  226. record: Record::Other {
  227. type_number: UnknownQtype::UnheardOf(153),
  228. bytes: vec![ 0x12, 0x34, 0x56, 0x78 ],
  229. },
  230. },
  231. Answer::Pseudo {
  232. qname: Labels::root(),
  233. opt: OPT {
  234. udp_payload_size: 512,
  235. higher_bits: 0,
  236. edns0_version: 0,
  237. flags: 0,
  238. data: vec![],
  239. },
  240. },
  241. ],
  242. };
  243. assert_eq!(Response::from_bytes(buf), Ok(response));
  244. }