Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/dns/parser.rs
Line
Count
Source
1
/* Copyright (C) 2017 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
//! Nom parsers for DNS.
19
20
use crate::dns::dns::*;
21
use nom7::combinator::{complete, rest};
22
use nom7::error::ErrorKind;
23
use nom7::multi::{count, length_data, many_m_n};
24
use nom7::number::streaming::{be_u16, be_u32, be_u8};
25
use nom7::{error_position, Err, IResult};
26
27
// Parse a DNS header.
28
3.10M
pub fn dns_parse_header(i: &[u8]) -> IResult<&[u8], DNSHeader> {
29
3.10M
    let (i, tx_id) = be_u16(i)?;
30
3.09M
    let (i, flags) = be_u16(i)?;
31
3.07M
    let (i, questions) = be_u16(i)?;
32
3.06M
    let (i, answer_rr) = be_u16(i)?;
33
3.06M
    let (i, authority_rr) = be_u16(i)?;
34
3.06M
    let (i, additional_rr) = be_u16(i)?;
35
3.05M
    Ok((
36
3.05M
        i,
37
3.05M
        DNSHeader {
38
3.05M
            tx_id,
39
3.05M
            flags,
40
3.05M
            questions,
41
3.05M
            answer_rr,
42
3.05M
            authority_rr,
43
3.05M
            additional_rr,
44
3.05M
        },
45
3.05M
    ))
46
3.10M
}
47
48
// Set a maximum assembled hostname length of 1025, this value was
49
// chosen as its what DNSMasq uses, a popular DNS server, even if most
50
// tooling limits names to 256 chars without special options.
51
static MAX_NAME_LEN: usize = 1025;
52
53
/// Parse a DNS name.
54
///
55
/// Names are parsed with the following restrictions:
56
///
57
/// - Only 255 segments will be processed, if more the parser may
58
///   error out. This is also our safeguard against an infinite loop. If
59
///   a pointer had been followed a truncated name will be
60
///   returned. However if pointer has been processed we error out as we
61
///   don't know where the next data point starts without more
62
///   iterations.
63
///
64
/// - The maximum name parsed in representation format is MAX_NAME_LEN
65
///   characters. Once larger, the truncated name will be returned with
66
///   a flag specifying the name was truncated. Note that parsing
67
///   continues if no pointer has been used as we still need to find the
68
///   start of the next protocol unit.
69
///
70
/// As some error in parsing the name are recoverable, a DNSName
71
/// object is returned with flags signifying a recoverable
72
/// error. These errors include:
73
///
74
/// - infinite loop: as we know the end of the name in the input
75
///   stream, we can return what we've parsed with the remain data.
76
///
77
/// - maximum number of segments/labels parsed
78
///
79
/// - truncation of name when too long
80
///
81
/// Parameters:
82
///   start: the start of the name
83
///   message: the complete message that start is a part of with the DNS header
84
2.69M
pub fn dns_parse_name<'b>(start: &'b [u8], message: &'b [u8], parse_flags: &mut DNSNameFlags) -> IResult<&'b [u8], DNSName> {
85
2.69M
    let mut pos = start;
86
2.69M
    let mut pivot = start;
87
2.69M
    let mut name: Vec<u8> = Vec::with_capacity(32);
88
2.69M
    let mut count = 0;
89
2.69M
    let mut flags = DNSNameFlags::default();
90
91
    loop {
92
24.9M
        if pos.is_empty() {
93
7.89k
            break;
94
24.9M
        }
95
96
24.9M
        let len = pos[0];
97
98
24.9M
        if len == 0x00 {
99
2.39M
            pos = &pos[1..];
100
2.39M
            break;
101
22.5M
        } else if len & 0b1100_0000 == 0 {
102
6.54M
            let (rem, label) = length_data(be_u8)(pos)?;
103
6.54M
            if !flags.contains(DNSNameFlags::TRUNCATED) {
104
6.48M
                if !name.is_empty() {
105
6.04M
                    name.push(b'.');
106
6.04M
                }
107
6.48M
                name.extend(label);
108
57.6k
            }
109
6.54M
            pos = rem;
110
16.0M
        } else if len & 0b1100_0000 == 0b1100_0000 {
111
16.0M
            let (rem, leader) = be_u16(pos)?;
112
16.0M
            let offset = usize::from(leader) & 0x3fff;
113
16.0M
            if offset > message.len() {
114
5.74k
                return Err(Err::Error(error_position!(pos, ErrorKind::OctDigit)));
115
16.0M
            }
116
117
16.0M
            if &message[offset..] == pos {
118
                // Self reference, immedate infinite loop.
119
135k
                flags.insert(DNSNameFlags::INFINITE_LOOP);
120
121
                // If we have followed a pointer, we can just break as
122
                // we've already found the end of the input. But if we
123
                // have not followed a pointer yet return a parse
124
                // error.
125
135k
                if pivot != start {
126
134k
                    break;
127
254
                }
128
254
                return Err(Err::Error(error_position!(pos, ErrorKind::OctDigit)));
129
15.8M
            }
130
131
15.8M
            pos = &message[offset..];
132
15.8M
            if pivot == start {
133
447k
                pivot = rem;
134
15.4M
            }
135
        } else {
136
13.3k
            return Err(Err::Error(error_position!(pos, ErrorKind::OctDigit)));
137
        }
138
139
        // Return error if we've looped a certain number of times.
140
22.4M
        count += 1;
141
142
22.4M
        if count > 255 {
143
70.7k
            flags.insert(DNSNameFlags::LABEL_LIMIT);
144
145
            // Our segment limit has been reached, if we have hit a
146
            // pointer we can just return the truncated name. If we
147
            // have not hit a pointer, we need to bail with an error.
148
70.7k
            if pivot != start {
149
70.4k
                flags.insert(DNSNameFlags::TRUNCATED);
150
70.4k
                break;
151
280
            }
152
280
            return Err(Err::Error(error_position!(pos, ErrorKind::OctDigit)));
153
22.3M
        }
154
155
22.3M
        if name.len() > MAX_NAME_LEN {
156
59.9k
            name.truncate(MAX_NAME_LEN);
157
59.9k
            flags.insert(DNSNameFlags::TRUNCATED);
158
159
            // If we have pivoted due to a pointer we know where the
160
            // end of the data is, so we can break early. Otherwise
161
            // we'll keep parsing in hopes to find the end of the name
162
            // so parsing can continue.
163
59.9k
            if pivot != start {
164
59.0k
                break;
165
827
            }
166
22.2M
        }
167
    }
168
169
2.66M
    parse_flags.insert(flags);
170
171
    // If we followed a pointer we return the position after the first
172
    // pointer followed. Is there a better way to see if these slices
173
    // diverged from each other?  A straight up comparison would
174
    // actually check the contents.
175
2.66M
    if pivot != start {
176
446k
        Ok((pivot, DNSName { value: name, flags }))
177
    } else {
178
2.22M
        Ok((pos, DNSName { value: name, flags }))
179
    }
180
2.69M
}
181
182
/// Parse answer entries.
183
///
184
/// In keeping with the C implementation, answer values that can
185
/// contain multiple answers get expanded into their own answer
186
/// records. An example of this is a TXT record with multiple strings
187
/// in it - each string will be expanded to its own answer record.
188
///
189
/// This function could be a made a whole lot simpler if we logged a
190
/// multi-string TXT entry as a single quote string, similar to the
191
/// output of dig. Something to consider for a future version.
192
3.13M
fn dns_parse_answer<'a>(
193
3.13M
    slice: &'a [u8], message: &'a [u8], count: usize, flags: &mut DNSNameFlags,
194
3.13M
) -> IResult<&'a [u8], Vec<DNSAnswerEntry>> {
195
3.13M
    let mut answers = Vec::new();
196
3.13M
    let mut input = slice;
197
198
    struct Answer<'a> {
199
        name: DNSName,
200
        rrtype: u16,
201
        rrclass: u16,
202
        ttl: u32,
203
        data: &'a [u8],
204
    }
205
206
185k
    fn subparser<'a>(
207
185k
        i: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
208
185k
    ) -> IResult<&'a [u8], Answer<'a>> {
209
185k
        let (i, name) = dns_parse_name(i, message, flags)?;
210
181k
        let (i, rrtype) = be_u16(i)?;
211
179k
        let (i, rrclass) = be_u16(i)?;
212
178k
        let (i, ttl) = be_u32(i)?;
213
176k
        let (i, data) = length_data(be_u16)(i)?;
214
168k
        let answer = Answer {
215
168k
            name,
216
168k
            rrtype,
217
168k
            rrclass,
218
168k
            ttl,
219
168k
            data,
220
168k
        };
221
168k
        Ok((i, answer))
222
185k
    }
223
224
3.13M
    for _ in 0..count {
225
185k
        match subparser(input, message, flags) {
226
168k
            Ok((rem, val)) => {
227
168k
                let n = match val.rrtype {
228
                    DNS_RECORD_TYPE_TXT => {
229
                        // For TXT records we need to run the parser
230
                        // multiple times. Set n high, to the maximum
231
                        // value based on a max txt side of 65535, but
232
                        // taking into considering that strings need
233
                        // to be quoted, so half that.
234
4.11k
                        32767
235
                    }
236
                    _ => {
237
                        // For all other types we only want to run the
238
                        // parser once, so set n to 1.
239
164k
                        1
240
                    }
241
                };
242
168k
                let result: IResult<&'a [u8], Vec<DNSRData>> = if val.data.is_empty() {
243
                    // many_m_n returns ErrorKind:ManyMN on empty data as it does not consume
244
46.1k
                    Ok((val.data, Vec::new()))
245
                } else {
246
1.26M
                    many_m_n(1, n, complete(|b| dns_parse_rdata(b, message, val.rrtype, flags)))(val.data)
247
                };
248
168k
                match result {
249
155k
                    Ok((_, rdatas)) => {
250
1.40M
                        for rdata in rdatas {
251
1.24M
                            answers.push(DNSAnswerEntry {
252
1.24M
                                name: val.name.clone(),
253
1.24M
                                rrtype: val.rrtype,
254
1.24M
                                rrclass: val.rrclass,
255
1.24M
                                ttl: val.ttl,
256
1.24M
                                data: rdata,
257
1.24M
                            });
258
1.24M
                        }
259
                    }
260
13.1k
                    Err(e) => {
261
13.1k
                        return Err(e);
262
                    }
263
                }
264
155k
                input = rem;
265
            }
266
17.2k
            Err(e) => {
267
17.2k
                return Err(e);
268
            }
269
        }
270
    }
271
272
3.10M
    return Ok((input, answers));
273
3.13M
}
274
275
1.58M
pub fn dns_parse_response_body<'a>(
276
1.58M
    i: &'a [u8], message: &'a [u8], header: DNSHeader,
277
1.58M
) -> IResult<&'a [u8], (DNSResponse, DNSNameFlags)> {
278
1.58M
    let mut flags = DNSNameFlags::default();
279
1.58M
    let (i, queries) = count(|b| dns_parse_query(b, message, &mut flags), header.questions as usize)(i)?;
280
1.58M
    let (i, answers) = dns_parse_answer(i, message, header.answer_rr as usize, &mut flags)?;
281
1.55M
    let (i, authorities) = dns_parse_answer(i, message, header.authority_rr as usize, &mut flags)?;
282
1.55M
    Ok((
283
1.55M
        i,
284
1.55M
        (DNSResponse {
285
1.55M
            header,
286
1.55M
            queries,
287
1.55M
            answers,
288
1.55M
            authorities,
289
1.55M
        }, flags),
290
1.55M
    ))
291
1.58M
}
292
293
/// Parse a single DNS query.
294
///
295
/// Arguments are suitable for using with call!:
296
///
297
///    call!(complete_dns_message_buffer)
298
2.41M
pub fn dns_parse_query<'a>(input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags) -> IResult<&'a [u8], DNSQueryEntry> {
299
2.41M
    let i = input;
300
2.41M
    let (i, name) = dns_parse_name(i, message, flags)?;
301
2.39M
    let (i, rrtype) = be_u16(i)?;
302
2.39M
    let (i, rrclass) = be_u16(i)?;
303
2.38M
    Ok((
304
2.38M
        i,
305
2.38M
        DNSQueryEntry {
306
2.38M
            name,
307
2.38M
            rrtype,
308
2.38M
            rrclass,
309
2.38M
        },
310
2.38M
    ))
311
2.41M
}
312
313
15.6k
fn dns_parse_rdata_a(input: &[u8]) -> IResult<&[u8], DNSRData> {
314
15.6k
    rest(input).map(|(input, data)| (input, DNSRData::A(data.to_vec())))
315
15.6k
}
316
317
7.99k
fn dns_parse_rdata_aaaa(input: &[u8]) -> IResult<&[u8], DNSRData> {
318
7.99k
    rest(input).map(|(input, data)| (input, DNSRData::AAAA(data.to_vec())))
319
7.99k
}
320
321
5.80k
fn dns_parse_rdata_cname<'a>(
322
5.80k
    input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
323
5.80k
) -> IResult<&'a [u8], DNSRData> {
324
5.80k
    dns_parse_name(input, message, flags).map(|(input, name)| (input, DNSRData::CNAME(name)))
325
5.80k
}
326
327
54.3k
fn dns_parse_rdata_ns<'a>(
328
54.3k
    input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
329
54.3k
) -> IResult<&'a [u8], DNSRData> {
330
54.3k
    dns_parse_name(input, message, flags).map(|(input, name)| (input, DNSRData::NS(name)))
331
54.3k
}
332
333
3.58k
fn dns_parse_rdata_ptr<'a>(
334
3.58k
    input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
335
3.58k
) -> IResult<&'a [u8], DNSRData> {
336
3.58k
    dns_parse_name(input, message, flags).map(|(input, name)| (input, DNSRData::PTR(name)))
337
3.58k
}
338
339
14.7k
fn dns_parse_rdata_soa<'a>(
340
14.7k
    input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
341
14.7k
) -> IResult<&'a [u8], DNSRData> {
342
14.7k
    let i = input;
343
14.7k
    let (i, mname) = dns_parse_name(i, message, flags)?;
344
14.2k
    let (i, rname) = dns_parse_name(i, message, flags)?;
345
13.2k
    let (i, serial) = be_u32(i)?;
346
12.3k
    let (i, refresh) = be_u32(i)?;
347
10.2k
    let (i, retry) = be_u32(i)?;
348
9.29k
    let (i, expire) = be_u32(i)?;
349
8.25k
    let (i, minimum) = be_u32(i)?;
350
6.34k
    Ok((
351
6.34k
        i,
352
6.34k
        DNSRData::SOA(DNSRDataSOA {
353
6.34k
            mname,
354
6.34k
            rname,
355
6.34k
            serial,
356
6.34k
            refresh,
357
6.34k
            retry,
358
6.34k
            expire,
359
6.34k
            minimum,
360
6.34k
        }),
361
6.34k
    ))
362
14.7k
}
363
364
1.05k
fn dns_parse_rdata_mx<'a>(
365
1.05k
    input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
366
1.05k
) -> IResult<&'a [u8], DNSRData> {
367
    // For MX we skip over the preference field before
368
    // parsing out the name.
369
1.05k
    let (i, _) = be_u16(input)?;
370
623
    let (i, name) = dns_parse_name(i, message, flags)?;
371
395
    Ok((i, DNSRData::MX(name)))
372
1.05k
}
373
374
2.69k
fn dns_parse_rdata_srv<'a>(
375
2.69k
    input: &'a [u8], message: &'a [u8], flags: &mut DNSNameFlags,
376
2.69k
) -> IResult<&'a [u8], DNSRData> {
377
2.69k
    let i = input;
378
2.69k
    let (i, priority) = be_u16(i)?;
379
2.46k
    let (i, weight) = be_u16(i)?;
380
1.95k
    let (i, port) = be_u16(i)?;
381
1.67k
    let (i, target) = dns_parse_name(i, message, flags)?;
382
1.18k
    Ok((
383
1.18k
        i,
384
1.18k
        DNSRData::SRV(DNSRDataSRV {
385
1.18k
            priority,
386
1.18k
            weight,
387
1.18k
            port,
388
1.18k
            target,
389
1.18k
        }),
390
1.18k
    ))
391
2.69k
}
392
393
1.14M
fn dns_parse_rdata_txt(input: &[u8]) -> IResult<&[u8], DNSRData> {
394
1.14M
    let (i, txt) = length_data(be_u8)(input)?;
395
1.14M
    Ok((i, DNSRData::TXT(txt.to_vec())))
396
1.14M
}
397
398
525
fn dns_parse_rdata_null(input: &[u8]) -> IResult<&[u8], DNSRData> {
399
525
    rest(input).map(|(input, data)| (input, DNSRData::NULL(data.to_vec())))
400
525
}
401
402
2.63k
fn dns_parse_rdata_sshfp(input: &[u8]) -> IResult<&[u8], DNSRData> {
403
2.63k
    let i = input;
404
2.63k
    let (i, algo) = be_u8(i)?;
405
2.63k
    let (i, fp_type) = be_u8(i)?;
406
2.16k
    let fingerprint = i;
407
2.16k
    Ok((
408
2.16k
        &[],
409
2.16k
        DNSRData::SSHFP(DNSRDataSSHFP {
410
2.16k
            algo,
411
2.16k
            fp_type,
412
2.16k
            fingerprint: fingerprint.to_vec(),
413
2.16k
        }),
414
2.16k
    ))
415
2.63k
}
416
417
8.86k
fn dns_parse_rdata_unknown(input: &[u8]) -> IResult<&[u8], DNSRData> {
418
8.86k
    rest(input).map(|(input, data)| (input, DNSRData::Unknown(data.to_vec())))
419
8.86k
}
420
421
1.26M
pub fn dns_parse_rdata<'a>(
422
1.26M
    input: &'a [u8], message: &'a [u8], rrtype: u16, flags: &mut DNSNameFlags
423
1.26M
) -> IResult<&'a [u8], DNSRData> {
424
1.26M
    match rrtype {
425
15.6k
        DNS_RECORD_TYPE_A => dns_parse_rdata_a(input),
426
7.99k
        DNS_RECORD_TYPE_AAAA => dns_parse_rdata_aaaa(input),
427
5.80k
        DNS_RECORD_TYPE_CNAME => dns_parse_rdata_cname(input, message, flags),
428
3.58k
        DNS_RECORD_TYPE_PTR => dns_parse_rdata_ptr(input, message, flags),
429
14.7k
        DNS_RECORD_TYPE_SOA => dns_parse_rdata_soa(input, message, flags),
430
1.05k
        DNS_RECORD_TYPE_MX => dns_parse_rdata_mx(input, message, flags),
431
54.3k
        DNS_RECORD_TYPE_NS => dns_parse_rdata_ns(input, message, flags),
432
1.14M
        DNS_RECORD_TYPE_TXT => dns_parse_rdata_txt(input),
433
525
        DNS_RECORD_TYPE_NULL => dns_parse_rdata_null(input),
434
2.63k
        DNS_RECORD_TYPE_SSHFP => dns_parse_rdata_sshfp(input),
435
2.69k
        DNS_RECORD_TYPE_SRV => dns_parse_rdata_srv(input, message, flags),
436
8.86k
        _ => dns_parse_rdata_unknown(input),
437
    }
438
1.26M
}
439
440
/// Parse a DNS request.
441
23.5k
pub fn dns_parse_request(input: &[u8]) -> IResult<&[u8], (DNSRequest, DNSNameFlags)> {
442
23.5k
    let i = input;
443
23.5k
    let (i, header) = dns_parse_header(i)?;
444
22.8k
    dns_parse_request_body(i, input, header)
445
23.5k
}
446
447
1.39M
pub fn dns_parse_request_body<'a>(
448
1.39M
    input: &'a [u8], message: &'a [u8], header: DNSHeader,
449
1.39M
) -> IResult<&'a [u8], (DNSRequest, DNSNameFlags)> {
450
1.39M
    let mut flags = DNSNameFlags::default();
451
1.39M
    let i = input;
452
1.43M
    let (i, queries) = count(|b| dns_parse_query(b, message, &mut flags), header.questions as usize)(i)?;
453
1.37M
    Ok((i, (DNSRequest { header, queries }, flags)))
454
1.39M
}
455
456
#[cfg(test)]
457
mod tests {
458
459
    use crate::dns::dns::{DNSAnswerEntry, DNSHeader};
460
    use crate::dns::parser::*;
461
462
    /// Parse a simple name with no pointers.
463
    #[test]
464
    fn test_dns_parse_name() {
465
        let buf: &[u8] = &[
466
            0x09, 0x63, /* .......c */
467
            0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2d, 0x63, 0x66, /* lient-cf */
468
            0x07, 0x64, 0x72, 0x6f, 0x70, 0x62, 0x6f, 0x78, /* .dropbox */
469
            0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, /* .com.... */
470
        ];
471
        let expected_remainder: &[u8] = &[0x00, 0x01, 0x00];
472
        let mut flags = DNSNameFlags::default();
473
        let (remainder, name) = dns_parse_name(buf, buf, &mut flags).unwrap();
474
        assert_eq!("client-cf.dropbox.com".as_bytes(), &name.value[..]);
475
        assert_eq!(remainder, expected_remainder);
476
    }
477
478
    /// Test parsing a name with pointers.
479
    #[test]
480
    fn test_dns_parse_name_with_pointer() {
481
        let buf: &[u8] = &[
482
            0xd8, 0xcb, 0x8a, 0xed, 0xa1, 0x46, 0x00, 0x15, /* 0   - .....F.. */
483
            0x17, 0x0d, 0x06, 0xf7, 0x08, 0x00, 0x45, 0x00, /* 8   - ......E. */
484
            0x00, 0x7b, 0x71, 0x6e, 0x00, 0x00, 0x39, 0x11, /* 16  - .{qn..9. */
485
            0xf4, 0xd9, 0x08, 0x08, 0x08, 0x08, 0x0a, 0x10, /* 24  - ........ */
486
            0x01, 0x0b, 0x00, 0x35, 0xe1, 0x8e, 0x00, 0x67, /* 32  - ...5...g */
487
            0x60, 0x00, 0xef, 0x08, 0x81, 0x80, 0x00, 0x01, /* 40  - `....... */
488
            0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x03, 0x77, /* 48  - .......w */
489
            0x77, 0x77, 0x0c, 0x73, 0x75, 0x72, 0x69, 0x63, /* 56  - ww.suric */
490
            0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, 0x73, 0x03, /* 64  - ata-ids. */
491
            0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01, /* 72  - org..... */
492
            0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, /* 80  - ........ */
493
            0x0e, 0x0f, 0x00, 0x02, 0xc0, 0x10, 0xc0, 0x10, /* 88  - ........ */
494
            0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2b, /* 96  - .......+ */
495
            0x00, 0x04, 0xc0, 0x00, 0x4e, 0x19, 0xc0, 0x10, /* 104 - ....N... */
496
            0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2b, /* 112 - .......+ */
497
            0x00, 0x04, 0xc0, 0x00, 0x4e, 0x18, 0x00, 0x00, /* 120 - ....N... */
498
            0x29, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 - )....... */
499
            0x00, /* 136 - . */
500
        ];
501
502
        // The DNS payload starts at offset 42.
503
        let message = &buf[42..];
504
505
        // The name at offset 54 is the complete name.
506
        let start1 = &buf[54..];
507
        let mut flags = DNSNameFlags::default();
508
        let res1 = dns_parse_name(start1, message, &mut flags);
509
        assert_eq!(
510
            res1,
511
            Ok((
512
                &start1[22..],
513
                DNSName {
514
                    value: "www.suricata-ids.org".as_bytes().to_vec(),
515
                    flags: DNSNameFlags::default(),
516
                }
517
            ))
518
        );
519
520
        // The second name starts at offset 80, but is just a pointer
521
        // to the first.
522
        let start2 = &buf[80..];
523
        let mut flags = DNSNameFlags::default();
524
        let res2 = dns_parse_name(start2, message, &mut flags);
525
        assert_eq!(
526
            res2,
527
            Ok((
528
                &start2[2..],
529
                DNSName {
530
                    value: "www.suricata-ids.org".as_bytes().to_vec(),
531
                    flags: DNSNameFlags::default()
532
                }
533
            ))
534
        );
535
536
        // The third name starts at offset 94, but is a pointer to a
537
        // portion of the first.
538
        let start3 = &buf[94..];
539
        let mut flags = DNSNameFlags::default();
540
        let res3 = dns_parse_name(start3, message, &mut flags);
541
        assert_eq!(
542
            res3,
543
            Ok((
544
                &start3[2..],
545
                DNSName {
546
                    value: "suricata-ids.org".as_bytes().to_vec(),
547
                    flags: DNSNameFlags::default()
548
                }
549
            ))
550
        );
551
552
        // The fourth name starts at offset 110, but is a pointer to a
553
        // portion of the first.
554
        let start4 = &buf[110..];
555
        let mut flags = DNSNameFlags::default();
556
        let res4 = dns_parse_name(start4, message, &mut flags);
557
        assert_eq!(
558
            res4,
559
            Ok((
560
                &start4[2..],
561
                DNSName {
562
                    value: "suricata-ids.org".as_bytes().to_vec(),
563
                    flags: DNSNameFlags::default()
564
                }
565
            ))
566
        );
567
    }
568
569
    #[test]
570
    fn test_dns_parse_name_double_pointer() {
571
        let buf: &[u8] = &[
572
            0xd8, 0xcb, 0x8a, 0xed, 0xa1, 0x46, 0x00, 0x15, /* 0:   .....F.. */
573
            0x17, 0x0d, 0x06, 0xf7, 0x08, 0x00, 0x45, 0x00, /* 8:   ......E. */
574
            0x00, 0x66, 0x5e, 0x20, 0x40, 0x00, 0x40, 0x11, /* 16:  .f^ @.@. */
575
            0xc6, 0x3b, 0x0a, 0x10, 0x01, 0x01, 0x0a, 0x10, /* 24:  .;...... */
576
            0x01, 0x0b, 0x00, 0x35, 0xc2, 0x21, 0x00, 0x52, /* 32:  ...5.!.R */
577
            0x35, 0xc5, 0x0d, 0x4f, 0x81, 0x80, 0x00, 0x01, /* 40:  5..O.... */
578
            0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x05, 0x62, /* 48:  .......b */
579
            0x6c, 0x6f, 0x63, 0x6b, 0x07, 0x64, 0x72, 0x6f, /* 56:  lock.dro */
580
            0x70, 0x62, 0x6f, 0x78, 0x03, 0x63, 0x6f, 0x6d, /* 64:  pbox.com */
581
            0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, /* 72:  ........ */
582
            0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, /* 80:  ........ */
583
            0x0b, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x02, /* 88:  ..block. */
584
            0x67, 0x31, 0xc0, 0x12, 0xc0, 0x2f, 0x00, 0x01, /* 96:  g1.../.. */
585
            0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, /* 104: ........ */
586
            0x2d, 0x3a, 0x46, 0x21, /* 112: -:F!     */
587
        ];
588
589
        // The start of the DNS message in the above packet.
590
        let message: &[u8] = &buf[42..];
591
592
        // The start of the name we want to parse, 0xc0 0x2f, a
593
        // pointer to offset 47 in the message (or 89 in the full
594
        // packet).
595
        let start: &[u8] = &buf[100..];
596
597
        let mut flags = DNSNameFlags::default();
598
        let res = dns_parse_name(start, message, &mut flags);
599
        assert_eq!(
600
            res,
601
            Ok((
602
                &start[2..],
603
                DNSName {
604
                    value: "block.g1.dropbox.com".as_bytes().to_vec(),
605
                    flags: DNSNameFlags::default()
606
                }
607
            ))
608
        );
609
    }
610
611
    #[test]
612
    fn test_dns_parse_request() {
613
        // DNS request from dig-a-www.suricata-ids.org.pcap.
614
        let pkt: &[u8] = &[
615
            0x8d, 0x32, 0x01, 0x20, 0x00, 0x01, /* ...2. .. */
616
            0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x77, /* .......w */
617
            0x77, 0x77, 0x0c, 0x73, 0x75, 0x72, 0x69, 0x63, /* ww.suric */
618
            0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, 0x73, 0x03, /* ata-ids. */
619
            0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01, /* org..... */
620
            0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00, /* ..)..... */
621
            0x00, 0x00, 0x00, /* ... */
622
        ];
623
624
        let (rem, (request, _flags)) = dns_parse_request(pkt).unwrap();
625
        // For now we have some remainder data as there is an
626
        // additional record type we don't parse yet.
627
        assert!(!rem.is_empty());
628
629
        assert_eq!(
630
            request.header,
631
            DNSHeader {
632
                tx_id: 0x8d32,
633
                flags: 0x0120,
634
                questions: 1,
635
                answer_rr: 0,
636
                authority_rr: 0,
637
                additional_rr: 1,
638
            }
639
        );
640
641
        assert_eq!(request.queries.len(), 1);
642
        let query = &request.queries[0];
643
        assert_eq!(query.name.value, "www.suricata-ids.org".as_bytes().to_vec());
644
        assert_eq!(query.rrtype, 1);
645
        assert_eq!(query.rrclass, 1);
646
    }
647
648
    /// Parse a DNS response.
649
    fn dns_parse_response(message: &[u8]) -> IResult<&[u8], (DNSResponse, DNSNameFlags)> {
650
        let i = message;
651
        let (i, header) = dns_parse_header(i)?;
652
        dns_parse_response_body(i, message, header)
653
    }
654
655
    #[test]
656
    fn test_dns_parse_response() {
657
        // DNS response from dig-a-www.suricata-ids.org.pcap.
658
        let pkt: &[u8] = &[
659
            0x8d, 0x32, 0x81, 0xa0, 0x00, 0x01, /* ...2.... */
660
            0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, /* .......w */
661
            0x77, 0x77, 0x0c, 0x73, 0x75, 0x72, 0x69, 0x63, /* ww.suric */
662
            0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, 0x73, 0x03, /* ata-ids. */
663
            0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00, 0x01, /* org..... */
664
            0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, /* ........ */
665
            0x0d, 0xd8, 0x00, 0x12, 0x0c, 0x73, 0x75, 0x72, /* .....sur */
666
            0x69, 0x63, 0x61, 0x74, 0x61, 0x2d, 0x69, 0x64, /* icata-id */
667
            0x73, 0x03, 0x6f, 0x72, 0x67, 0x00, 0xc0, 0x32, /* s.org..2 */
668
            0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf4, /* ........ */
669
            0x00, 0x04, 0xc0, 0x00, 0x4e, 0x18, 0xc0, 0x32, /* ....N..2 */
670
            0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf4, /* ........ */
671
            0x00, 0x04, 0xc0, 0x00, 0x4e, 0x19, /* ....N. */
672
        ];
673
674
        let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
675
        // The response should be full parsed.
676
        assert_eq!(rem.len(), 0);
677
678
        assert_eq!(
679
            response.header,
680
            DNSHeader {
681
                tx_id: 0x8d32,
682
                flags: 0x81a0,
683
                questions: 1,
684
                answer_rr: 3,
685
                authority_rr: 0,
686
                additional_rr: 0,
687
            }
688
        );
689
690
        assert_eq!(response.answers.len(), 3);
691
692
        let answer1 = &response.answers[0];
693
        assert_eq!(answer1.name.value, "www.suricata-ids.org".as_bytes().to_vec());
694
        assert_eq!(answer1.rrtype, 5);
695
        assert_eq!(answer1.rrclass, 1);
696
        assert_eq!(answer1.ttl, 3544);
697
        assert_eq!(
698
            answer1.data,
699
            DNSRData::CNAME(DNSName {
700
                value: "suricata-ids.org".as_bytes().to_vec(),
701
                flags: Default::default(),
702
            })
703
        );
704
705
        let answer2 = &response.answers[1];
706
        assert_eq!(
707
            answer2,
708
            &DNSAnswerEntry {
709
                name: DNSName {
710
                    value: "suricata-ids.org".as_bytes().to_vec(),
711
                    flags: Default::default(),
712
                },
713
                rrtype: 1,
714
                rrclass: 1,
715
                ttl: 244,
716
                data: DNSRData::A([192, 0, 78, 24].to_vec()),
717
            }
718
        );
719
720
        let answer3 = &response.answers[2];
721
        assert_eq!(
722
            answer3,
723
            &DNSAnswerEntry {
724
                name: DNSName {
725
                    value: "suricata-ids.org".as_bytes().to_vec(),
726
                    flags: Default::default(),
727
                },
728
                rrtype: 1,
729
                rrclass: 1,
730
                ttl: 244,
731
                data: DNSRData::A([192, 0, 78, 25].to_vec()),
732
            }
733
        )
734
    }
735
736
    #[test]
737
    fn test_dns_parse_response_nxdomain_soa() {
738
        // DNS response with an SOA authority record from
739
        // dns-udp-nxdomain-soa.pcap.
740
        let pkt: &[u8] = &[
741
            0x82, 0x95, 0x81, 0x83, 0x00, 0x01, /* j....... */
742
            0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x03, 0x64, /* .......d */
743
            0x6e, 0x65, 0x04, 0x6f, 0x69, 0x73, 0x66, 0x03, /* ne.oisf. */
744
            0x6e, 0x65, 0x74, 0x00, 0x00, 0x01, 0x00, 0x01, /* net..... */
745
            0xc0, 0x10, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, /* ........ */
746
            0x03, 0x83, 0x00, 0x45, 0x06, 0x6e, 0x73, 0x2d, /* ...E.ns- */
747
            0x31, 0x31, 0x30, 0x09, 0x61, 0x77, 0x73, 0x64, /* 110.awsd */
748
            0x6e, 0x73, 0x2d, 0x31, 0x33, 0x03, 0x63, 0x6f, /* ns-13.co */
749
            0x6d, 0x00, 0x11, 0x61, 0x77, 0x73, 0x64, 0x6e, /* m..awsdn */
750
            0x73, 0x2d, 0x68, 0x6f, 0x73, 0x74, 0x6d, 0x61, /* s-hostma */
751
            0x73, 0x74, 0x65, 0x72, 0x06, 0x61, 0x6d, 0x61, /* ster.ama */
752
            0x7a, 0x6f, 0x6e, 0xc0, 0x3b, 0x00, 0x00, 0x00, /* zon.;... */
753
            0x01, 0x00, 0x00, 0x1c, 0x20, 0x00, 0x00, 0x03, /* .... ... */
754
            0x84, 0x00, 0x12, 0x75, 0x00, 0x00, 0x01, 0x51, /* ...u...Q */
755
            0x80, 0x00, 0x00, 0x29, 0x02, 0x00, 0x00, 0x00, /* ...).... */
756
            0x00, 0x00, 0x00, 0x00, /* .... */
757
        ];
758
759
        let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
760
        // For now we have some remainder data as there is an
761
        // additional record type we don't parse yet.
762
        assert!(!rem.is_empty());
763
764
        assert_eq!(
765
            response.header,
766
            DNSHeader {
767
                tx_id: 0x8295,
768
                flags: 0x8183,
769
                questions: 1,
770
                answer_rr: 0,
771
                authority_rr: 1,
772
                additional_rr: 1,
773
            }
774
        );
775
776
        assert_eq!(response.authorities.len(), 1);
777
778
        let authority = &response.authorities[0];
779
        assert_eq!(authority.name.value, "oisf.net".as_bytes().to_vec());
780
        assert_eq!(authority.rrtype, 6);
781
        assert_eq!(authority.rrclass, 1);
782
        assert_eq!(authority.ttl, 899);
783
        assert_eq!(
784
            authority.data,
785
            DNSRData::SOA(DNSRDataSOA {
786
                mname: DNSName {
787
                    value: "ns-110.awsdns-13.com".as_bytes().to_vec(),
788
                    flags: DNSNameFlags::default()
789
                },
790
                rname: DNSName {
791
                    value: "awsdns-hostmaster.amazon.com".as_bytes().to_vec(),
792
                    flags: DNSNameFlags::default()
793
                },
794
                serial: 1,
795
                refresh: 7200,
796
                retry: 900,
797
                expire: 1209600,
798
                minimum: 86400,
799
            })
800
        );
801
    }
802
803
    #[test]
804
    fn test_dns_parse_response_null() {
805
        // DNS response with a NULL record from
806
        // https://redmine.openinfosecfoundation.org/attachments/2062
807
808
        let pkt: &[u8] = &[
809
            0x12, 0xb0, 0x84, 0x00, 0x00, 0x01, 0x00, 0x01, /* ........ */
810
            0x00, 0x00, 0x00, 0x00, 0x0b, 0x76, 0x61, 0x61, /* .....vaa */
811
            0x61, 0x61, 0x6b, 0x61, 0x72, 0x64, 0x6c, 0x69, /* aakardli */
812
            0x06, 0x70, 0x69, 0x72, 0x61, 0x74, 0x65, 0x03, /* .pirate. */
813
            0x73, 0x65, 0x61, 0x00, 0x00, 0x0a, 0x00, 0x01, /* sea..... */
814
            0xc0, 0x0c, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, /* ........ */
815
            0x00, 0x00, 0x00, 0x09, 0x56, 0x41, 0x43, 0x4b, /* ....VACK */
816
            0x44, 0x03, 0xc5, 0xe9, 0x01, /* D.... */
817
        ];
818
819
        let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
820
        // The response should be fully parsed.
821
        assert_eq!(rem.len(), 0);
822
823
        assert_eq!(
824
            response.header,
825
            DNSHeader {
826
                tx_id: 0x12b0,
827
                flags: 0x8400,
828
                questions: 1,
829
                answer_rr: 1,
830
                authority_rr: 0,
831
                additional_rr: 0,
832
            }
833
        );
834
835
        assert_eq!(response.queries.len(), 1);
836
        let query = &response.queries[0];
837
        assert_eq!(query.name.value, "vaaaakardli.pirate.sea".as_bytes().to_vec());
838
        assert_eq!(query.rrtype, DNS_RECORD_TYPE_NULL);
839
        assert_eq!(query.rrclass, 1);
840
841
        assert_eq!(response.answers.len(), 1);
842
843
        let answer = &response.answers[0];
844
        assert_eq!(answer.name.value, "vaaaakardli.pirate.sea".as_bytes().to_vec());
845
        assert_eq!(answer.rrtype, DNS_RECORD_TYPE_NULL);
846
        assert_eq!(answer.rrclass, 1);
847
        assert_eq!(answer.ttl, 0);
848
        assert_eq!(
849
            answer.data,
850
            DNSRData::NULL(vec![
851
                0x56, 0x41, 0x43, 0x4b, /* VACK */
852
                0x44, 0x03, 0xc5, 0xe9, 0x01, /* D.... */
853
            ])
854
        );
855
    }
856
857
    #[test]
858
    fn test_dns_parse_rdata_sshfp() {
859
        // Dummy data since we don't have a pcap sample.
860
        let data: &[u8] = &[
861
            // algo: DSS
862
            0x02, // fp_type: SHA-1
863
            0x01, // fingerprint: 123456789abcdef67890123456789abcdef67890
864
            0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf6, 0x78, 0x90, 0x12, 0x34, 0x56, 0x78,
865
            0x9a, 0xbc, 0xde, 0xf6, 0x78, 0x90,
866
        ];
867
868
        let (rem, rdata) = dns_parse_rdata_sshfp(data).unwrap();
869
        // The data should be fully parsed.
870
        assert_eq!(rem.len(), 0);
871
872
        match rdata {
873
            DNSRData::SSHFP(sshfp) => {
874
                assert_eq!(sshfp.algo, 2);
875
                assert_eq!(sshfp.fp_type, 1);
876
                assert_eq!(sshfp.fingerprint, &data[2..]);
877
            }
878
            _ => {
879
                panic!("Expected DNSRData::SSHFP");
880
            }
881
        }
882
    }
883
884
    #[test]
885
    fn test_dns_parse_rdata_srv() {
886
        /*  ; <<>> DiG 9.11.5-P4-5.1+deb10u2-Debian <<>> _sip._udp.sip.voice.google.com SRV
887
        ;; global options: +cmd
888
        ;; Got answer:
889
        ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1524
890
        ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 3
891
892
        [...]
893
894
        ;; ANSWER SECTION:
895
        _sip._udp.sip.voice.google.com. 300 IN  SRV 10 1 5060 sip-anycast-1.voice.google.com.
896
        _sip._udp.sip.voice.google.com. 300 IN  SRV 20 1 5060 sip-anycast-2.voice.google.com.
897
898
        [...]
899
900
        ;; Query time: 72 msec
901
        ;; MSG SIZE  rcvd: 191   */
902
903
        let pkt: &[u8] = &[
904
            0xeb, 0x56, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x04, 0x5f,
905
            0x73, 0x69, 0x70, 0x04, 0x5f, 0x75, 0x64, 0x70, 0x03, 0x73, 0x69, 0x70, 0x05, 0x76,
906
            0x6f, 0x69, 0x63, 0x65, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
907
            0x6d, 0x00, 0x00, 0x21, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00,
908
            0x01, 0x13, 0x00, 0x26, 0x00, 0x14, 0x00, 0x01, 0x13, 0xc4, 0x0d, 0x73, 0x69, 0x70,
909
            0x2d, 0x61, 0x6e, 0x79, 0x63, 0x61, 0x73, 0x74, 0x2d, 0x32, 0x05, 0x76, 0x6f, 0x69,
910
            0x63, 0x65, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
911
            0xc0, 0x0c, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x01, 0x13, 0x00, 0x26, 0x00, 0x0a,
912
            0x00, 0x01, 0x13, 0xc4, 0x0d, 0x73, 0x69, 0x70, 0x2d, 0x61, 0x6e, 0x79, 0x63, 0x61,
913
            0x73, 0x74, 0x2d, 0x31, 0x05, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x06, 0x67, 0x6f, 0x6f,
914
            0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
915
        ];
916
917
        let (rem, (response, _flags)) = dns_parse_response(pkt).unwrap();
918
        // The data should be fully parsed.
919
        assert_eq!(rem.len(), 0);
920
921
        assert_eq!(response.answers.len(), 2);
922
923
        let answer1 = &response.answers[0];
924
        match &answer1.data {
925
            DNSRData::SRV(srv) => {
926
                assert_eq!(srv.priority, 20);
927
                assert_eq!(srv.weight, 1);
928
                assert_eq!(srv.port, 5060);
929
                assert_eq!(
930
                    srv.target.value,
931
                    "sip-anycast-2.voice.google.com".as_bytes().to_vec()
932
                );
933
            }
934
            _ => {
935
                panic!("Expected DNSRData::SRV");
936
            }
937
        }
938
        let answer2 = &response.answers[1];
939
        match &answer2.data {
940
            DNSRData::SRV(srv) => {
941
                assert_eq!(srv.priority, 10);
942
                assert_eq!(srv.weight, 1);
943
                assert_eq!(srv.port, 5060);
944
                assert_eq!(
945
                    srv.target.value,
946
                    "sip-anycast-1.voice.google.com".as_bytes().to_vec()
947
                );
948
            }
949
            _ => {
950
                panic!("Expected DNSRData::SRV");
951
            }
952
        }
953
    }
954
955
    #[test]
956
    fn test_dns_parse_name_truncated() {
957
        // Generate a non-compressed hostname over our maximum of 1024.
958
        let mut buf: Vec<u8> = vec![];
959
960
        for i in 1..18 {
961
            buf.push(0b0011_1111);
962
            buf.resize(i * 64, b'a');
963
        }
964
965
        let mut flags = DNSNameFlags::default();
966
        let (rem, name) = dns_parse_name(&buf, &buf, &mut flags).unwrap();
967
        assert_eq!(name.value.len(), MAX_NAME_LEN);
968
        assert!(name.flags.contains(DNSNameFlags::TRUNCATED));
969
        assert!(rem.is_empty());
970
    }
971
972
    #[test]
973
    fn test_dns_parse_name_truncated_max_segments_no_pointer() {
974
        let mut buf: Vec<u8> = vec![];
975
        for _ in 0..256 {
976
            buf.push(0b0000_0001);
977
            buf.push(b'a');
978
        }
979
980
        // This should fail as we've hit the segment limit without a
981
        // pointer, we'd need to keep parsing more segments to figure
982
        // out where the next data point lies.
983
        let mut flags = DNSNameFlags::default();
984
        assert!(dns_parse_name(&buf, &buf, &mut flags).is_err());
985
    }
986
987
    #[test]
988
    fn test_dns_parse_name_truncated_max_segments_with_pointer() {
989
        #[rustfmt::skip]
990
        let buf: Vec<u8> = vec![
991
            // "a" at the beginning of the buffer.
992
            0b0000_0001,
993
            b'a',
994
995
            // Followed by a pointer back to the beginning.
996
            0b1100_0000,
997
            0b0000_0000,
998
999
            // The start of the name, which is pointer to the beginning of
1000
            // the buffer.
1001
            0b1100_0000,
1002
            0b000_0000
1003
        ];
1004
1005
        let mut flags = DNSNameFlags::default();
1006
        let (_rem, name) = dns_parse_name(&buf[4..], &buf, &mut flags).unwrap();
1007
        assert_eq!(name.value.len(), 255);
1008
        assert!(name.flags.contains(DNSNameFlags::TRUNCATED));
1009
    }
1010
1011
    #[test]
1012
    fn test_dns_parse_name_self_reference() {
1013
        let buf = vec![0b1100_0000, 0b0000_0000];
1014
        let mut flags = DNSNameFlags::default();
1015
        assert!(dns_parse_name(&buf, &buf, &mut flags).is_err());
1016
    }
1017
}