Skip to main content

packet_dissector_gre/
lib.rs

1//! GRE (Generic Routing Encapsulation) dissector.
2//!
3//! ## References
4//! - RFC 2784: <https://www.rfc-editor.org/rfc/rfc2784>
5//! - RFC 2890 (Key and Sequence Number Extensions; updates RFC 2784):
6//!   <https://www.rfc-editor.org/rfc/rfc2890>
7//! - RFC 9601 (ECN propagation requirement for GRE tunnels; updates RFC 2784):
8//!   <https://www.rfc-editor.org/rfc/rfc9601>
9
10#![deny(missing_docs)]
11
12use packet_dissector_core::dissector::{DispatchHint, DissectResult, Dissector};
13use packet_dissector_core::error::PacketError;
14use packet_dissector_core::field::{FieldDescriptor, FieldType, FieldValue};
15use packet_dissector_core::packet::DissectBuffer;
16use packet_dissector_core::util::{read_be_u16, read_be_u32};
17
18/// Minimum GRE header size (no optional fields).
19///
20/// RFC 2784, Section 2 — The base header contains only the flags/version
21/// word (2 octets) and the Protocol Type field (2 octets).
22const MIN_HEADER_SIZE: usize = 4;
23
24/// Mask selecting bits of the first 16-bit header word that RFC 2784 requires
25/// a non-RFC-1701 receiver to discard when non-zero.
26///
27/// RFC 2784, Section 2.3 — "Receivers MUST discard a packet where any of bits
28/// 1-5 are non-zero, unless that receiver implements RFC 1701". RFC 2890
29/// reassigns bits 2 and 3 as the K (Key Present) and S (Sequence Number
30/// Present) flags, so the remaining must-be-zero bits are {1, 4, 5}:
31/// `1 << (15 - 1) | 1 << (15 - 4) | 1 << (15 - 5) == 0x4C00`.
32///
33/// RFC 2784, Section 2.3 — <https://www.rfc-editor.org/rfc/rfc2784#section-2.3>
34const RESERVED_MUST_BE_ZERO_MASK: u16 = 0x4C00;
35
36/// Field descriptor indices for [`GreDissector::field_descriptors`].
37const FD_CHECKSUM_PRESENT: usize = 0;
38const FD_KEY_PRESENT: usize = 1;
39const FD_SEQUENCE_NUMBER_PRESENT: usize = 2;
40const FD_RESERVED0: usize = 3;
41const FD_VERSION: usize = 4;
42const FD_PROTOCOL_TYPE: usize = 5;
43const FD_CHECKSUM: usize = 6;
44const FD_RESERVED1: usize = 7;
45const FD_KEY: usize = 8;
46const FD_SEQUENCE_NUMBER: usize = 9;
47
48static FIELD_DESCRIPTORS: &[FieldDescriptor] = &[
49    FieldDescriptor::new("checksum_present", "Checksum Present", FieldType::U8),
50    FieldDescriptor::new("key_present", "Key Present", FieldType::U8),
51    FieldDescriptor::new(
52        "sequence_number_present",
53        "Sequence Number Present",
54        FieldType::U8,
55    ),
56    FieldDescriptor::new("reserved0", "Reserved0", FieldType::U16),
57    FieldDescriptor::new("version", "Version", FieldType::U8),
58    FieldDescriptor::new("protocol_type", "Protocol Type", FieldType::U16),
59    FieldDescriptor::new("checksum", "Checksum", FieldType::U16).optional(),
60    FieldDescriptor::new("reserved1", "Reserved1", FieldType::U16).optional(),
61    FieldDescriptor::new("key", "Key", FieldType::U32).optional(),
62    FieldDescriptor::new("sequence_number", "Sequence Number", FieldType::U32).optional(),
63];
64
65/// GRE dissector.
66pub struct GreDissector;
67
68impl Dissector for GreDissector {
69    fn name(&self) -> &'static str {
70        "Generic Routing Encapsulation"
71    }
72
73    fn short_name(&self) -> &'static str {
74        "GRE"
75    }
76
77    fn field_descriptors(&self) -> &'static [FieldDescriptor] {
78        FIELD_DESCRIPTORS
79    }
80
81    fn dissect<'pkt>(
82        &self,
83        data: &'pkt [u8],
84        buf: &mut DissectBuffer<'pkt>,
85        offset: usize,
86    ) -> Result<DissectResult, PacketError> {
87        if data.len() < MIN_HEADER_SIZE {
88            return Err(PacketError::Truncated {
89                expected: MIN_HEADER_SIZE,
90                actual: data.len(),
91            });
92        }
93
94        // RFC 2784, Section 2 — Flags/version word (first 2 octets)
95        // https://www.rfc-editor.org/rfc/rfc2784#section-2
96        let flags_ver = read_be_u16(data, 0)?;
97
98        // RFC 2784, Section 2.1 — Bit 0: Checksum Present (C)
99        // https://www.rfc-editor.org/rfc/rfc2784#section-2.1
100        let c_flag = ((flags_ver >> 15) & 1) as u8;
101        // RFC 2890, Section 2 — Bit 2: Key Present (K)
102        // https://www.rfc-editor.org/rfc/rfc2890#section-2
103        let k_flag = ((flags_ver >> 13) & 1) as u8;
104        // RFC 2890, Section 2 — Bit 3: Sequence Number Present (S)
105        // https://www.rfc-editor.org/rfc/rfc2890#section-2
106        let s_flag = ((flags_ver >> 12) & 1) as u8;
107        // RFC 2890, Section 2 — Reserved0 occupies bits 4-12 of the flags
108        // word. RFC 2784, Section 2.3 requires bits 6-12 be ignored on
109        // receipt; bits 4-5 are validated below.
110        // https://www.rfc-editor.org/rfc/rfc2890#section-2
111        let reserved0 = (flags_ver >> 3) & 0x01FF;
112        // RFC 2784, Section 2.3.1 — Bits 13-15: Version Number (MUST be 0)
113        // https://www.rfc-editor.org/rfc/rfc2784#section-2.3.1
114        let version = (flags_ver & 0x0007) as u8;
115
116        // RFC 2784, Section 2.3 — Reject packets that set reserved bits
117        // {1, 4, 5} of the flags word. This implementation does not support
118        // RFC 1701, so non-zero values in these bits are invalid.
119        // https://www.rfc-editor.org/rfc/rfc2784#section-2.3
120        if flags_ver & RESERVED_MUST_BE_ZERO_MASK != 0 {
121            return Err(PacketError::InvalidFieldValue {
122                field: "reserved0",
123                value: (flags_ver & RESERVED_MUST_BE_ZERO_MASK) as u32,
124            });
125        }
126
127        if version != 0 {
128            return Err(PacketError::InvalidFieldValue {
129                field: "version",
130                value: version as u32,
131            });
132        }
133
134        // Compute expected header length based on flags
135        let mut header_len = MIN_HEADER_SIZE;
136        if c_flag != 0 {
137            header_len += 4; // Checksum (2) + Reserved1 (2)
138        }
139        if k_flag != 0 {
140            header_len += 4; // Key (4)
141        }
142        if s_flag != 0 {
143            header_len += 4; // Sequence Number (4)
144        }
145
146        if data.len() < header_len {
147            return Err(PacketError::Truncated {
148                expected: header_len,
149                actual: data.len(),
150            });
151        }
152
153        let protocol_type = read_be_u16(data, 2)?;
154
155        buf.begin_layer(
156            self.short_name(),
157            None,
158            FIELD_DESCRIPTORS,
159            offset..offset + header_len,
160        );
161
162        buf.push_field(
163            &FIELD_DESCRIPTORS[FD_CHECKSUM_PRESENT],
164            FieldValue::U8(c_flag),
165            offset..offset + 1,
166        );
167        buf.push_field(
168            &FIELD_DESCRIPTORS[FD_KEY_PRESENT],
169            FieldValue::U8(k_flag),
170            offset..offset + 1,
171        );
172        buf.push_field(
173            &FIELD_DESCRIPTORS[FD_SEQUENCE_NUMBER_PRESENT],
174            FieldValue::U8(s_flag),
175            offset..offset + 1,
176        );
177        buf.push_field(
178            &FIELD_DESCRIPTORS[FD_RESERVED0],
179            FieldValue::U16(reserved0),
180            offset..offset + 2,
181        );
182        buf.push_field(
183            &FIELD_DESCRIPTORS[FD_VERSION],
184            FieldValue::U8(version),
185            offset..offset + 2,
186        );
187        buf.push_field(
188            &FIELD_DESCRIPTORS[FD_PROTOCOL_TYPE],
189            FieldValue::U16(protocol_type),
190            offset + 2..offset + 4,
191        );
192
193        // Optional fields — order is always: Checksum+Reserved1, Key, Sequence Number
194        let mut pos = MIN_HEADER_SIZE;
195
196        // RFC 2784, Sections 2.5 & 2.6 — Checksum and Reserved1
197        // https://www.rfc-editor.org/rfc/rfc2784#section-2.5
198        // https://www.rfc-editor.org/rfc/rfc2784#section-2.6
199        if c_flag != 0 {
200            let checksum = read_be_u16(data, pos)?;
201            let reserved1 = read_be_u16(data, pos + 2)?;
202            buf.push_field(
203                &FIELD_DESCRIPTORS[FD_CHECKSUM],
204                FieldValue::U16(checksum),
205                offset + pos..offset + pos + 2,
206            );
207            buf.push_field(
208                &FIELD_DESCRIPTORS[FD_RESERVED1],
209                FieldValue::U16(reserved1),
210                offset + pos + 2..offset + pos + 4,
211            );
212            pos += 4;
213        }
214
215        // RFC 2890, Section 2.1 — Key
216        // https://www.rfc-editor.org/rfc/rfc2890#section-2.1
217        if k_flag != 0 {
218            let key = read_be_u32(data, pos)?;
219            buf.push_field(
220                &FIELD_DESCRIPTORS[FD_KEY],
221                FieldValue::U32(key),
222                offset + pos..offset + pos + 4,
223            );
224            pos += 4;
225        }
226
227        // RFC 2890, Section 2.2 — Sequence Number
228        // https://www.rfc-editor.org/rfc/rfc2890#section-2.2
229        if s_flag != 0 {
230            let seq = read_be_u32(data, pos)?;
231            buf.push_field(
232                &FIELD_DESCRIPTORS[FD_SEQUENCE_NUMBER],
233                FieldValue::U32(seq),
234                offset + pos..offset + pos + 4,
235            );
236        }
237
238        buf.end_layer();
239
240        // RFC 2784, Section 2.4 — Protocol Type is an EtherType value.
241        // https://www.rfc-editor.org/rfc/rfc2784#section-2.4
242        Ok(DissectResult::new(
243            header_len,
244            DispatchHint::ByEtherType(protocol_type),
245        ))
246    }
247}
248
249#[cfg(test)]
250mod tests {
251    use super::*;
252
253    // # RFC 2784 / RFC 2890 (GRE) Coverage
254    //
255    // | RFC Section  | Description                          | Test                                  |
256    // |--------------|--------------------------------------|---------------------------------------|
257    // | 2784 §2      | Base header format                   | parse_gre_basic                       |
258    // | 2784 §2.3    | Reserved0 bits 6-12 ignored          | parse_gre_reserved_bits_6_to_12       |
259    // | 2784 §2.3    | Reject non-zero bit 1                | parse_gre_rejects_reserved_bit1       |
260    // | 2784 §2.3    | Reject non-zero bit 4                | parse_gre_rejects_reserved_bit4       |
261    // | 2784 §2.3    | Reject non-zero bit 5                | parse_gre_rejects_reserved_bit5       |
262    // | 2784 §2.3.1  | Version validation                   | parse_gre_invalid_version             |
263    // | 2784 §2.4    | Protocol Type dispatch (IPv6)        | parse_gre_dispatch_ipv6               |
264    // | 2784 §2.5    | Checksum present                     | parse_gre_with_checksum               |
265    // | 2784 §2.6    | Reserved1 present                    | parse_gre_with_checksum               |
266    // | 2890 §2.1    | Key present                          | parse_gre_with_key                    |
267    // | 2890 §2.2    | Sequence Number present              | parse_gre_with_sequence_number        |
268    // | 2784 + 2890  | All optional fields                  | parse_gre_all_options                 |
269    // | 2784 §2      | Truncated base header                | parse_gre_truncated                   |
270    // | 2784 §2      | Truncated optional fields            | parse_gre_truncated_optional_fields   |
271
272    /// Helper: dissect raw bytes at offset 0 and return the result.
273    fn dissect(data: &[u8]) -> Result<(DissectBuffer<'_>, DissectResult), PacketError> {
274        let mut buf = DissectBuffer::new();
275        let result = GreDissector.dissect(data, &mut buf, 0)?;
276        Ok((buf, result))
277    }
278
279    #[test]
280    fn parse_gre_basic() {
281        // Minimal GRE header: C=0, K=0, S=0, Ver=0, Protocol Type=0x0800 (IPv4)
282        let raw: &[u8] = &[
283            0x00, 0x00, // flags=0, version=0
284            0x08, 0x00, // Protocol Type: IPv4
285        ];
286        let (buf, result) = dissect(raw).unwrap();
287        assert_eq!(result.bytes_consumed, 4);
288        assert_eq!(result.next, DispatchHint::ByEtherType(0x0800));
289
290        let layer = buf.layer_by_name("GRE").unwrap();
291        assert_eq!(
292            buf.field_by_name(layer, "checksum_present").unwrap().value,
293            FieldValue::U8(0)
294        );
295        assert_eq!(
296            buf.field_by_name(layer, "key_present").unwrap().value,
297            FieldValue::U8(0)
298        );
299        assert_eq!(
300            buf.field_by_name(layer, "sequence_number_present")
301                .unwrap()
302                .value,
303            FieldValue::U8(0)
304        );
305        assert_eq!(
306            buf.field_by_name(layer, "reserved0").unwrap().value,
307            FieldValue::U16(0)
308        );
309        assert_eq!(
310            buf.field_by_name(layer, "version").unwrap().value,
311            FieldValue::U8(0)
312        );
313        assert_eq!(
314            buf.field_by_name(layer, "protocol_type").unwrap().value,
315            FieldValue::U16(0x0800)
316        );
317        assert!(buf.field_by_name(layer, "checksum").is_none());
318        assert!(buf.field_by_name(layer, "key").is_none());
319        assert!(buf.field_by_name(layer, "sequence_number").is_none());
320    }
321
322    #[test]
323    fn parse_gre_with_checksum() {
324        // C=1 → Checksum + Reserved1 present (8 bytes total)
325        let raw: &[u8] = &[
326            0x80, 0x00, // C=1, rest=0
327            0x08, 0x00, // Protocol Type: IPv4
328            0xAB, 0xCD, // Checksum
329            0x00, 0x00, // Reserved1
330        ];
331        let (buf, result) = dissect(raw).unwrap();
332        assert_eq!(result.bytes_consumed, 8);
333
334        let layer = buf.layer_by_name("GRE").unwrap();
335        assert_eq!(
336            buf.field_by_name(layer, "checksum_present").unwrap().value,
337            FieldValue::U8(1)
338        );
339        assert_eq!(
340            buf.field_by_name(layer, "checksum").unwrap().value,
341            FieldValue::U16(0xABCD)
342        );
343        assert_eq!(
344            buf.field_by_name(layer, "reserved1").unwrap().value,
345            FieldValue::U16(0)
346        );
347    }
348
349    #[test]
350    fn parse_gre_with_key() {
351        // K=1 → Key present (8 bytes total)
352        let raw: &[u8] = &[
353            0x20, 0x00, // K=1 (bit 2 of byte 0 = 0x20)
354            0x08, 0x00, // Protocol Type: IPv4
355            0x00, 0x01, 0x02, 0x03, // Key
356        ];
357        let (buf, result) = dissect(raw).unwrap();
358        assert_eq!(result.bytes_consumed, 8);
359
360        let layer = buf.layer_by_name("GRE").unwrap();
361        assert_eq!(
362            buf.field_by_name(layer, "key_present").unwrap().value,
363            FieldValue::U8(1)
364        );
365        assert_eq!(
366            buf.field_by_name(layer, "key").unwrap().value,
367            FieldValue::U32(0x00010203)
368        );
369        assert!(buf.field_by_name(layer, "checksum").is_none());
370    }
371
372    #[test]
373    fn parse_gre_with_sequence_number() {
374        // S=1 → Sequence Number present (8 bytes total)
375        let raw: &[u8] = &[
376            0x10, 0x00, // S=1 (bit 3 of byte 0 = 0x10)
377            0x86, 0xDD, // Protocol Type: IPv6
378            0x00, 0x00, 0x00, 0x2A, // Sequence Number = 42
379        ];
380        let (buf, result) = dissect(raw).unwrap();
381        assert_eq!(result.bytes_consumed, 8);
382        assert_eq!(result.next, DispatchHint::ByEtherType(0x86DD));
383
384        let layer = buf.layer_by_name("GRE").unwrap();
385        assert_eq!(
386            buf.field_by_name(layer, "sequence_number_present")
387                .unwrap()
388                .value,
389            FieldValue::U8(1)
390        );
391        assert_eq!(
392            buf.field_by_name(layer, "sequence_number").unwrap().value,
393            FieldValue::U32(42)
394        );
395    }
396
397    #[test]
398    fn parse_gre_all_options() {
399        // C=1, K=1, S=1 → 16 bytes total
400        let raw: &[u8] = &[
401            0xB0, 0x00, // C=1, K=1, S=1 (0x80|0x20|0x10 = 0xB0)
402            0x08, 0x00, // Protocol Type: IPv4
403            0x12, 0x34, // Checksum
404            0x00, 0x00, // Reserved1
405            0xDE, 0xAD, 0xBE, 0xEF, // Key
406            0x00, 0x00, 0x00, 0x01, // Sequence Number = 1
407        ];
408        let (buf, result) = dissect(raw).unwrap();
409        assert_eq!(result.bytes_consumed, 16);
410
411        let layer = buf.layer_by_name("GRE").unwrap();
412        assert_eq!(
413            buf.field_by_name(layer, "checksum_present").unwrap().value,
414            FieldValue::U8(1)
415        );
416        assert_eq!(
417            buf.field_by_name(layer, "key_present").unwrap().value,
418            FieldValue::U8(1)
419        );
420        assert_eq!(
421            buf.field_by_name(layer, "sequence_number_present")
422                .unwrap()
423                .value,
424            FieldValue::U8(1)
425        );
426        assert_eq!(
427            buf.field_by_name(layer, "checksum").unwrap().value,
428            FieldValue::U16(0x1234)
429        );
430        assert_eq!(
431            buf.field_by_name(layer, "key").unwrap().value,
432            FieldValue::U32(0xDEADBEEF)
433        );
434        assert_eq!(
435            buf.field_by_name(layer, "sequence_number").unwrap().value,
436            FieldValue::U32(1)
437        );
438    }
439
440    #[test]
441    fn parse_gre_truncated() {
442        let raw: &[u8] = &[0x00, 0x00, 0x08]; // Only 3 bytes
443        let err = GreDissector
444            .dissect(raw, &mut DissectBuffer::new(), 0)
445            .unwrap_err();
446        assert!(matches!(
447            err,
448            PacketError::Truncated {
449                expected: 4,
450                actual: 3
451            }
452        ));
453    }
454
455    #[test]
456    fn parse_gre_invalid_version() {
457        // Version = 1 (bits 13-15 of the flags word)
458        let raw: &[u8] = &[
459            0x00, 0x01, // Version = 1
460            0x08, 0x00, // Protocol Type: IPv4
461        ];
462        let err = GreDissector
463            .dissect(raw, &mut DissectBuffer::new(), 0)
464            .unwrap_err();
465        assert!(matches!(
466            err,
467            PacketError::InvalidFieldValue {
468                field: "version",
469                value: 1,
470            }
471        ));
472    }
473
474    #[test]
475    fn parse_gre_truncated_optional_fields() {
476        // C=1 but only 4 bytes available (need 8)
477        let raw: &[u8] = &[
478            0x80, 0x00, // C=1
479            0x08, 0x00, // Protocol Type: IPv4
480        ];
481        let err = GreDissector
482            .dissect(raw, &mut DissectBuffer::new(), 0)
483            .unwrap_err();
484        assert!(matches!(
485            err,
486            PacketError::Truncated {
487                expected: 8,
488                actual: 4
489            }
490        ));
491    }
492
493    #[test]
494    fn parse_gre_dispatch_ipv6() {
495        let raw: &[u8] = &[
496            0x00, 0x00, // flags=0
497            0x86, 0xDD, // Protocol Type: IPv6
498        ];
499        let (_, result) = dissect(raw).unwrap();
500        assert_eq!(result.next, DispatchHint::ByEtherType(0x86DD));
501    }
502
503    /// RFC 2784, Section 2.3: "Receivers MUST discard a packet where any of
504    /// bits 1-5 are non-zero, unless that receiver implements RFC 1701."
505    /// Bit 1 of the flags word was R (Routing Present) in RFC 1701 and has
506    /// no definition in RFC 2784 or RFC 2890; a non-zero value MUST cause
507    /// rejection.
508    #[test]
509    fn parse_gre_rejects_reserved_bit1() {
510        // 0x40 = bit 1 set (binary 0100 0000 in byte 0).
511        let raw: &[u8] = &[0x40, 0x00, 0x08, 0x00];
512        let err = GreDissector
513            .dissect(raw, &mut DissectBuffer::new(), 0)
514            .unwrap_err();
515        assert!(matches!(
516            err,
517            PacketError::InvalidFieldValue {
518                field: "reserved0",
519                value: 0x4000,
520            }
521        ));
522    }
523
524    /// RFC 2784, Section 2.3: bit 4 of the flags word MUST be zero for
525    /// non-RFC-1701 receivers.
526    #[test]
527    fn parse_gre_rejects_reserved_bit4() {
528        // 0x08 = bit 4 set (binary 0000 1000 in byte 0).
529        let raw: &[u8] = &[0x08, 0x00, 0x08, 0x00];
530        let err = GreDissector
531            .dissect(raw, &mut DissectBuffer::new(), 0)
532            .unwrap_err();
533        assert!(matches!(
534            err,
535            PacketError::InvalidFieldValue {
536                field: "reserved0",
537                value: 0x0800,
538            }
539        ));
540    }
541
542    /// RFC 2784, Section 2.3: bit 5 of the flags word MUST be zero for
543    /// non-RFC-1701 receivers.
544    #[test]
545    fn parse_gre_rejects_reserved_bit5() {
546        // 0x04 = bit 5 set (binary 0000 0100 in byte 0).
547        let raw: &[u8] = &[0x04, 0x00, 0x08, 0x00];
548        let err = GreDissector
549            .dissect(raw, &mut DissectBuffer::new(), 0)
550            .unwrap_err();
551        assert!(matches!(
552            err,
553            PacketError::InvalidFieldValue {
554                field: "reserved0",
555                value: 0x0400,
556            }
557        ));
558    }
559
560    /// RFC 2784, Section 2.3: "Bits 6-12 are reserved for future use. These
561    /// bits MUST be sent as zero and MUST be ignored on receipt." The
562    /// dissector must accept such packets and expose the received bits via
563    /// the `reserved0` field.
564    #[test]
565    fn parse_gre_reserved_bits_6_to_12() {
566        // Set bits 6-12 all to 1. In byte terms:
567        //   byte 0 bits (RFC 6, RFC 7) = 0x03
568        //   byte 1 bits (RFC 8..12)    = 0xF8
569        // flags_ver = 0x03F8. Reserved0 = (flags_ver >> 3) & 0x1FF = 0x7F.
570        let raw: &[u8] = &[0x03, 0xF8, 0x08, 0x00];
571        let (buf, result) = dissect(raw).unwrap();
572        assert_eq!(result.bytes_consumed, 4);
573
574        let layer = buf.layer_by_name("GRE").unwrap();
575        assert_eq!(
576            buf.field_by_name(layer, "reserved0").unwrap().value,
577            FieldValue::U16(0x7F)
578        );
579        assert_eq!(
580            buf.field_by_name(layer, "version").unwrap().value,
581            FieldValue::U8(0)
582        );
583    }
584
585    #[test]
586    fn parse_gre_with_offset() {
587        // Verify byte ranges use the offset parameter correctly
588        let raw: &[u8] = &[
589            0x20, 0x00, // K=1
590            0x08, 0x00, // Protocol Type: IPv4
591            0x00, 0x00, 0x00, 0x01, // Key = 1
592        ];
593        let mut buf = DissectBuffer::new();
594        let result = GreDissector.dissect(raw, &mut buf, 100).unwrap();
595        assert_eq!(result.bytes_consumed, 8);
596
597        let layer = buf.layer_by_name("GRE").unwrap();
598        assert_eq!(layer.range, 100..108);
599        assert_eq!(
600            buf.field_by_name(layer, "protocol_type").unwrap().range,
601            102..104
602        );
603        assert_eq!(buf.field_by_name(layer, "key").unwrap().range, 104..108);
604    }
605
606    #[test]
607    fn field_descriptors_consistent() {
608        let descs = GreDissector.field_descriptors();
609        assert_eq!(descs.len(), 10);
610        assert_eq!(descs[FD_CHECKSUM_PRESENT].name, "checksum_present");
611        assert_eq!(descs[FD_KEY_PRESENT].name, "key_present");
612        assert_eq!(
613            descs[FD_SEQUENCE_NUMBER_PRESENT].name,
614            "sequence_number_present"
615        );
616        assert_eq!(descs[FD_RESERVED0].name, "reserved0");
617        assert_eq!(descs[FD_VERSION].name, "version");
618        assert_eq!(descs[FD_PROTOCOL_TYPE].name, "protocol_type");
619        assert_eq!(descs[FD_CHECKSUM].name, "checksum");
620        assert_eq!(descs[FD_RESERVED1].name, "reserved1");
621        assert_eq!(descs[FD_KEY].name, "key");
622        assert_eq!(descs[FD_SEQUENCE_NUMBER].name, "sequence_number");
623    }
624}