/// Parameters:
/// start: the start of the name
/// message: the complete message that start is a part of with the DNS header
-fn dns_parse_name<'b>(start: &'b [u8], message: &'b [u8]) -> IResult<&'b [u8], DNSName> {
+fn dns_parse_name<'b>(
+ start: &'b [u8], message: &'b [u8], parse_flags: &mut DNSNameFlags,
+) -> IResult<&'b [u8], DNSName> {
let mut pos = start;
let mut pivot = start;
let mut name: Vec<u8> = Vec::with_capacity(32);
}
}
+ parse_flags.insert(flags);
+
// If we followed a pointer we return the position after the first
// pointer followed. Is there a better way to see if these slices
// diverged from each other? A straight up comparison would
/// multi-string TXT entry as a single quote string, similar to the
/// output of dig. Something to consider for a future version.
fn dns_parse_answer<'a>(
- slice: &'a [u8], message: &'a [u8], count: usize,
+ slice: &'a [u8], message: &'a [u8], count: usize, flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], Vec<DNSAnswerEntry>> {
let mut answers = Vec::new();
let mut input = slice;
data: &'a [u8],
}
- fn subparser<'a>(i: &'a [u8], message: &'a [u8]) -> IResult<&'a [u8], Answer<'a>> {
- let (i, name) = dns_parse_name(i, message)?;
+ fn subparser<'a>(
+ i: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
+ ) -> IResult<&'a [u8], Answer<'a>> {
+ let (i, name) = dns_parse_name(i, message, flags)?;
let (i, rrtype) = be_u16(i)?;
let (i, rrclass) = be_u16(i)?;
let (i, ttl) = be_u32(i)?;
}
for _ in 0..count {
- match subparser(input, message) {
+ match subparser(input, message, flags) {
Ok((rem, val)) => {
let n = match val.rrtype {
DNS_RECORD_TYPE_TXT => {
input = rem;
continue;
}
- let result: IResult<&'a [u8], Vec<DNSRData>> =
- many_m_n(1, n, complete(|b| dns_parse_rdata(b, message, val.rrtype)))(val.data);
+ let result: IResult<&'a [u8], Vec<DNSRData>> = many_m_n(
+ 1,
+ n,
+ complete(|b| dns_parse_rdata(b, message, val.rrtype, flags)),
+ )(val.data);
match result {
Ok((_, rdatas)) => {
for rdata in rdatas {
/// Arguments are suitable for using with call!:
///
/// call!(complete_dns_message_buffer)
-fn dns_parse_query<'a>(input: &'a [u8], message: &'a [u8]) -> IResult<&'a [u8], DNSQueryEntry> {
+fn dns_parse_query<'a>(
+ input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
+) -> IResult<&'a [u8], DNSQueryEntry> {
let i = input;
- let (i, name) = dns_parse_name(i, message)?;
+ let (i, name) = dns_parse_name(i, message, flags)?;
let (i, rrtype) = be_u16(i)?;
let (i, rrclass) = be_u16(i)?;
Ok((
rest(input).map(|(input, data)| (input, DNSRData::AAAA(data.to_vec())))
}
-fn dns_parse_rdata_cname<'a>(input: &'a [u8], message: &'a [u8]) -> IResult<&'a [u8], DNSRData> {
- dns_parse_name(input, message).map(|(input, name)| (input, DNSRData::CNAME(name)))
+fn dns_parse_rdata_cname<'a>(
+ input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
+) -> IResult<&'a [u8], DNSRData> {
+ dns_parse_name(input, message, flags).map(|(input, name)| (input, DNSRData::CNAME(name)))
}
-fn dns_parse_rdata_ns<'a>(input: &'a [u8], message: &'a [u8]) -> IResult<&'a [u8], DNSRData> {
- dns_parse_name(input, message).map(|(input, name)| (input, DNSRData::NS(name)))
+fn dns_parse_rdata_ns<'a>(
+ input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
+) -> IResult<&'a [u8], DNSRData> {
+ dns_parse_name(input, message, flags).map(|(input, name)| (input, DNSRData::NS(name)))
}
-fn dns_parse_rdata_ptr<'a>(input: &'a [u8], message: &'a [u8]) -> IResult<&'a [u8], DNSRData> {
- dns_parse_name(input, message).map(|(input, name)| (input, DNSRData::PTR(name)))
+fn dns_parse_rdata_ptr<'a>(
+ input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
+) -> IResult<&'a [u8], DNSRData> {
+ dns_parse_name(input, message, flags).map(|(input, name)| (input, DNSRData::PTR(name)))
}
-fn dns_parse_rdata_soa<'a>(input: &'a [u8], message: &'a [u8]) -> IResult<&'a [u8], DNSRData> {
+fn dns_parse_rdata_soa<'a>(
+ input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
+) -> IResult<&'a [u8], DNSRData> {
let i = input;
- let (i, mname) = dns_parse_name(i, message)?;
- let (i, rname) = dns_parse_name(i, message)?;
+ let (i, mname) = dns_parse_name(i, message, flags)?;
+ let (i, rname) = dns_parse_name(i, message, flags)?;
let (i, serial) = be_u32(i)?;
let (i, refresh) = be_u32(i)?;
let (i, retry) = be_u32(i)?;
))
}
-fn dns_parse_rdata_mx<'a>(input: &'a [u8], message: &'a [u8]) -> IResult<&'a [u8], DNSRData> {
+fn dns_parse_rdata_mx<'a>(
+ input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
+) -> IResult<&'a [u8], DNSRData> {
// For MX we skip over the preference field before
// parsing out the name.
let (i, _) = be_u16(input)?;
- let (i, name) = dns_parse_name(i, message)?;
+ let (i, name) = dns_parse_name(i, message, flags)?;
Ok((i, DNSRData::MX(name)))
}
-fn dns_parse_rdata_srv<'a>(input: &'a [u8], message: &'a [u8]) -> IResult<&'a [u8], DNSRData> {
+fn dns_parse_rdata_srv<'a>(
+ input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
+) -> IResult<&'a [u8], DNSRData> {
let i = input;
let (i, priority) = be_u16(i)?;
let (i, weight) = be_u16(i)?;
let (i, port) = be_u16(i)?;
- let (i, target) = dns_parse_name(i, message)?;
+ let (i, target) = dns_parse_name(i, message, flags)?;
Ok((
i,
DNSRData::SRV(DNSRDataSRV {
}
fn dns_parse_rdata<'a>(
- input: &'a [u8], message: &'a [u8], rrtype: u16,
+ input: &'a [u8], message: &'a [u8], rrtype: u16, flags: &mut DNSNameFlags,
) -> IResult<&'a [u8], DNSRData> {
match rrtype {
DNS_RECORD_TYPE_A => dns_parse_rdata_a(input),
DNS_RECORD_TYPE_AAAA => dns_parse_rdata_aaaa(input),
- DNS_RECORD_TYPE_CNAME => dns_parse_rdata_cname(input, message),
- DNS_RECORD_TYPE_PTR => dns_parse_rdata_ptr(input, message),
- DNS_RECORD_TYPE_SOA => dns_parse_rdata_soa(input, message),
- DNS_RECORD_TYPE_MX => dns_parse_rdata_mx(input, message),
- DNS_RECORD_TYPE_NS => dns_parse_rdata_ns(input, message),
+ DNS_RECORD_TYPE_CNAME => dns_parse_rdata_cname(input, message, flags),
+ DNS_RECORD_TYPE_PTR => dns_parse_rdata_ptr(input, message, flags),
+ DNS_RECORD_TYPE_SOA => dns_parse_rdata_soa(input, message, flags),
+ DNS_RECORD_TYPE_MX => dns_parse_rdata_mx(input, message, flags),
+ DNS_RECORD_TYPE_NS => dns_parse_rdata_ns(input, message, flags),
DNS_RECORD_TYPE_TXT => dns_parse_rdata_txt(input),
DNS_RECORD_TYPE_NULL => dns_parse_rdata_null(input),
DNS_RECORD_TYPE_SSHFP => dns_parse_rdata_sshfp(input),
- DNS_RECORD_TYPE_SRV => dns_parse_rdata_srv(input, message),
+ DNS_RECORD_TYPE_SRV => dns_parse_rdata_srv(input, message, flags),
DNS_RECORD_TYPE_OPT => dns_parse_rdata_opt(input),
_ => dns_parse_rdata_unknown(input),
}
pub fn dns_parse_body<'a>(
i: &'a [u8], message: &'a [u8], header: DNSHeader,
-) -> IResult<&'a [u8], DNSMessage> {
- let (i, queries) = count(|b| dns_parse_query(b, message), header.questions as usize)(i)?;
- let (i, answers) = dns_parse_answer(i, message, header.answer_rr as usize)?;
- let (i, authorities) = dns_parse_answer(i, message, header.authority_rr as usize)?;
- let (i, additionals) = dns_parse_answer(i, message, header.additional_rr as usize)?;
+) -> IResult<&'a [u8], (DNSMessage, DNSNameFlags)> {
+ let mut flags = DNSNameFlags::default();
+ let (i, queries) = count(
+ |b| dns_parse_query(b, message, &mut flags),
+ header.questions as usize,
+ )(i)?;
+ let (i, answers) = dns_parse_answer(i, message, header.answer_rr as usize, &mut flags)?;
+ let (i, authorities) = dns_parse_answer(i, message, header.authority_rr as usize, &mut flags)?;
+ let (i, additionals) = dns_parse_answer(i, message, header.additional_rr as usize, &mut flags)?;
Ok((
i,
- DNSMessage {
- header,
- queries,
- answers,
- authorities,
- additionals,
- },
+ (
+ DNSMessage {
+ header,
+ queries,
+ answers,
+ authorities,
+ additionals,
+ },
+ flags,
+ ),
))
}
0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, /* .com.... */
];
let expected_remainder: &[u8] = &[0x00, 0x01, 0x00];
- let (remainder, name) = dns_parse_name(buf, buf).unwrap();
+ let mut flags = DNSNameFlags::default();
+ let (remainder, name) = dns_parse_name(buf, buf, &mut flags).unwrap();
assert_eq!("client-cf.dropbox.com".as_bytes(), &name.value[..]);
assert_eq!(remainder, expected_remainder);
}
// The name at offset 54 is the complete name.
let start1 = &buf[54..];
- let res1 = dns_parse_name(start1, message);
+ let mut flags = DNSNameFlags::default();
+ let res1 = dns_parse_name(start1, message, &mut flags);
assert_eq!(
res1,
Ok((
// The second name starts at offset 80, but is just a pointer
// to the first.
let start2 = &buf[80..];
- let res2 = dns_parse_name(start2, message);
+ let mut flags = DNSNameFlags::default();
+ let res2 = dns_parse_name(start2, message, &mut flags);
assert_eq!(
res2,
Ok((
// The third name starts at offset 94, but is a pointer to a
// portion of the first.
let start3 = &buf[94..];
- let res3 = dns_parse_name(start3, message);
+ let mut flags = DNSNameFlags::default();
+ let res3 = dns_parse_name(start3, message, &mut flags);
assert_eq!(
res3,
Ok((
// The fourth name starts at offset 110, but is a pointer to a
// portion of the first.
let start4 = &buf[110..];
- let res4 = dns_parse_name(start4, message);
+ let mut flags = DNSNameFlags::default();
+ let res4 = dns_parse_name(start4, message, &mut flags);
assert_eq!(
res4,
Ok((
// packet).
let start: &[u8] = &buf[100..];
- let res = dns_parse_name(start, message);
+ let mut flags = DNSNameFlags::default();
+ let res = dns_parse_name(start, message, &mut flags);
assert_eq!(
res,
Ok((
let (body, header) = dns_parse_header(pkt).unwrap();
let res = dns_parse_body(body, pkt, header);
- let (rem, request) = res.unwrap();
+ let (rem, (request, _flags)) = res.unwrap();
// The request should be fully parsed.
assert!(rem.is_empty());
let (body, header) = dns_parse_header(pkt).unwrap();
let res = dns_parse_body(body, pkt, header);
- let (rem, request) = res.unwrap();
+ let (rem, (request, _flags)) = res.unwrap();
assert!(rem.is_empty());
assert_eq!(
}
/// Parse a DNS response.
- fn dns_parse_response(message: &[u8]) -> IResult<&[u8], DNSMessage> {
+ fn dns_parse_response(message: &[u8]) -> IResult<&[u8], (DNSMessage, DNSNameFlags)> {
let i = message;
let (i, header) = dns_parse_header(i)?;
dns_parse_body(i, message, header)
0x00, 0x04, 0xc0, 0x00, 0x4e, 0x19, /* ....N. */
];
- let (rem, response) = dns_parse_response(pkt).unwrap();
+ let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
// The response should be full parsed.
assert_eq!(rem.len(), 0);
0x00, 0x00, 0x00, 0x00, /* .... */
];
- let (rem, response) = dns_parse_response(pkt).unwrap();
+ let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
// The response should be fully parsed.
assert!(rem.is_empty());
0x44, 0x03, 0xc5, 0xe9, 0x01, /* D.... */
];
- let (rem, response) = dns_parse_response(pkt).unwrap();
+ let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
// The response should be fully parsed.
assert_eq!(rem.len(), 0);
0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
];
- let (rem, response) = dns_parse_response(pkt).unwrap();
+ let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
// The data should be fully parsed.
assert_eq!(rem.len(), 0);
}
}
- let (rem, name) = dns_parse_name(&buf, &buf).unwrap();
+ let mut flags = DNSNameFlags::default();
+ let (rem, name) = dns_parse_name(&buf, &buf, &mut flags).unwrap();
assert_eq!(name.value.len(), MAX_NAME_LEN);
assert!(name.flags.contains(DNSNameFlags::TRUNCATED));
assert!(rem.is_empty());
// This should fail as we've hit the segment limit without a
// pointer, we'd need to keep parsing more segments to figure
// out where the next data point lies.
- assert!(dns_parse_name(&buf, &buf).is_err());
+ let mut flags = DNSNameFlags::default();
+ assert!(dns_parse_name(&buf, &buf, &mut flags).is_err());
}
#[test]
buf.push(0b1100_0000);
buf.push(0b000_0000);
- let (_rem, name) = dns_parse_name(&buf[4..], &buf).unwrap();
+ let mut flags = DNSNameFlags::default();
+ let (_rem, name) = dns_parse_name(&buf[4..], &buf, &mut flags).unwrap();
assert_eq!(name.value.len(), 255);
assert!(name.flags.contains(DNSNameFlags::TRUNCATED));
}
let mut buf = vec![];
buf.push(0b1100_0000);
buf.push(0b0000_0000);
- assert!(dns_parse_name(&buf, &buf).is_err());
+ let mut flags = DNSNameFlags::default();
+ assert!(dns_parse_name(&buf, &buf, &mut flags).is_err());
}
}