Skip to main content

wireforge_core/
gre.rs

1//! GRE (Generic Routing Encapsulation) tunnel packet parser and builder.
2//! Implements RFC 2784 (base) and RFC 2890 (Key/Sequence extensions).
3
4use alloc::vec;
5use alloc::vec::Vec;
6
7use crate::types::EtherType;
8use crate::util::{seal_internet_checksum, read_u16be, read_u32be, write_u16be};
9
10pub const GRE_MIN_LEN: usize = 4;
11
12// Flag bits in the first 2 bytes
13const FLAG_CHECKSUM: u16 = 0x8000;
14const FLAG_ROUTING: u16 = 0x4000;
15const FLAG_KEY: u16 = 0x2000;
16const FLAG_SEQUENCE: u16 = 0x1000;
17const FLAG_STRICT_ROUTE: u16 = 0x0800;
18const FLAG_RECURSION_MASK: u16 = 0x0700;
19const FLAG_VERSION_MASK: u16 = 0x0007;
20const FLAG_RECURSION_SHIFT: u16 = 8;
21
22/// Zero-copy GRE packet parser.
23#[derive(Debug, Clone)]
24pub struct GrePacket<'a> {
25    buf: &'a [u8],
26}
27
28impl<'a> GrePacket<'a> {
29    crate::parser_new!(GRE_MIN_LEN);
30
31    /// Raw bytes backing this packet.
32    #[inline]
33    pub fn as_bytes(&self) -> &'a [u8] { self.buf }
34
35    #[inline]
36    pub fn flags(&self) -> u16 {
37        read_u16be(&self.buf[..2])
38    }
39
40    #[inline] pub fn checksum_present(&self) -> bool { self.flags() & FLAG_CHECKSUM != 0 }
41    #[inline] pub fn routing_present(&self) -> bool { self.flags() & FLAG_ROUTING != 0 }
42    #[inline] pub fn key_present(&self) -> bool { self.flags() & FLAG_KEY != 0 }
43    #[inline] pub fn sequence_present(&self) -> bool { self.flags() & FLAG_SEQUENCE != 0 }
44    #[inline] pub fn strict_source_route(&self) -> bool { self.flags() & FLAG_STRICT_ROUTE != 0 }
45    #[inline] pub fn recursion_control(&self) -> u8 {
46        ((self.flags() & FLAG_RECURSION_MASK) >> FLAG_RECURSION_SHIFT) as u8
47    }
48    #[inline] pub fn version(&self) -> u8 {
49        (self.flags() & FLAG_VERSION_MASK) as u8
50    }
51
52    #[inline]
53    pub fn protocol_type(&self) -> EtherType {
54        EtherType::from(read_u16be(&self.buf[2..4]))
55    }
56
57    fn option_offset(&self) -> usize {
58        let mut off = GRE_MIN_LEN;
59        if self.checksum_present() { off += 4; }
60        if self.key_present() { off += 4; }
61        if self.sequence_present() { off += 4; }
62        if self.routing_present()
63            && off + 2 <= self.buf.len() {
64                let routing_len = read_u16be(&self.buf[off..off+2]) as usize;
65                off += routing_len;
66        }
67        off
68    }
69
70    pub fn checksum(&self) -> Option<u16> {
71        if self.checksum_present() && self.buf.len() >= 8 {
72            Some(read_u16be(&self.buf[4..6]))
73        } else { None }
74    }
75
76    pub fn key(&self) -> Option<u32> {
77        if !self.key_present() { return None; }
78        let mut off = GRE_MIN_LEN;
79        if self.checksum_present() { off += 4; }
80        if off + 4 <= self.buf.len() { Some(read_u32be(&self.buf[off..off+4])) } else { None }
81    }
82
83    pub fn sequence(&self) -> Option<u32> {
84        if !self.sequence_present() { return None; }
85        let mut off = GRE_MIN_LEN;
86        if self.checksum_present() { off += 4; }
87        if self.key_present() { off += 4; }
88        if off + 4 <= self.buf.len() { Some(read_u32be(&self.buf[off..off+4])) } else { None }
89    }
90
91    pub fn routing(&self) -> Option<&[u8]> {
92        if !self.routing_present() { return None; }
93        let mut off = GRE_MIN_LEN;
94        if self.checksum_present() { off += 4; }
95        if self.key_present() { off += 4; }
96        if self.sequence_present() { off += 4; }
97        if off + 2 <= self.buf.len() {
98            let len = read_u16be(&self.buf[off..off+2]) as usize;
99            let end = (off + len).min(self.buf.len());
100            Some(&self.buf[off..end])
101        } else { None }
102    }
103
104    #[inline]
105    pub fn header_length(&self) -> usize { self.option_offset() }
106
107    #[inline]
108    pub fn payload(&self) -> &'a [u8] { &self.buf[self.option_offset()..] }
109}
110
111// ---------------------------------------------------------------------------
112// Builder
113// ---------------------------------------------------------------------------
114
115pub struct GrePacketBuilder {
116    buf: Vec<u8>,
117    has_checksum: bool,
118    has_key: bool,
119    has_seq: bool,
120    key_val: u32,
121    seq_val: u32,
122    payload: Option<Vec<u8>>,
123}
124
125impl GrePacketBuilder {
126    pub fn new(protocol_type: EtherType) -> Self {
127        let mut buf = vec![0u8; GRE_MIN_LEN];
128        let pt: u16 = protocol_type.into();
129        write_u16be(&mut buf[2..4], pt);
130        Self {
131            buf, has_checksum: false, has_key: false, has_seq: false,
132            key_val: 0, seq_val: 0, payload: None,
133        }
134    }
135
136    pub fn key(mut self, key: u32) -> Self {
137        self.has_key = true; self.key_val = key; self
138    }
139
140    pub fn sequence(mut self, seq: u32) -> Self {
141        self.has_seq = true; self.seq_val = seq; self
142    }
143
144    pub fn checksum(mut self) -> Self {
145        self.has_checksum = true; self
146    }
147
148    pub fn recursion_control(mut self, v: u8) -> Self {
149        let flags = read_u16be(&self.buf[..2]);
150        let updated = (flags & !FLAG_RECURSION_MASK) | (((v as u16) << FLAG_RECURSION_SHIFT) & FLAG_RECURSION_MASK);
151        write_u16be(&mut self.buf[..2], updated);
152        self
153    }
154
155    pub fn version(mut self, v: u8) -> Self {
156        let flags = read_u16be(&self.buf[..2]);
157        write_u16be(&mut self.buf[..2], (flags & !FLAG_VERSION_MASK) | (v as u16 & FLAG_VERSION_MASK));
158        self
159    }
160
161    pub fn payload(mut self, data: &[u8]) -> Self {
162        self.payload = Some(data.to_vec());
163        self
164    }
165
166    pub fn build(mut self) -> Vec<u8> {
167        let mut flags = read_u16be(&self.buf[..2]);
168        if self.has_checksum { flags |= FLAG_CHECKSUM; }
169        if self.has_key { flags |= FLAG_KEY; }
170        if self.has_seq {
171            flags |= FLAG_SEQUENCE;
172            if !self.has_key { self.has_key = true; self.key_val = 0; flags |= FLAG_KEY; }
173        }
174        write_u16be(&mut self.buf[..2], flags);
175
176        let mut extras = Vec::new();
177        // Checksum slot (0 for now)
178        let csum_pos = if self.has_checksum { let p = extras.len() + GRE_MIN_LEN; extras.extend_from_slice(&[0u8; 4]); Some(p) } else { None };
179        // Key
180        if self.has_key { extras.extend_from_slice(&self.key_val.to_be_bytes()); }
181        // Sequence
182        if self.has_seq { extras.extend_from_slice(&self.seq_val.to_be_bytes()); }
183
184        let mut pkt = self.buf;
185        pkt.extend_from_slice(&extras);
186        if let Some(ref p) = self.payload { pkt.extend_from_slice(p); }
187
188        // Compute GRE checksum (RFC 2784: over GRE header + payload)
189        if let Some(pos) = csum_pos {
190            seal_internet_checksum(&mut pkt, pos);
191        }
192
193        pkt
194    }
195}
196
197// ---------------------------------------------------------------------------
198// Tests
199// ---------------------------------------------------------------------------
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204
205    #[test]
206    fn parse_basic_gre() {
207        // GRE with no options, protocol_type=IPv4(0x0800)
208        let data = &[0x00u8, 0x00, 0x08, 0x00, 0xAA, 0xBB];
209        let pkt = GrePacket::new(data).unwrap();
210        assert!(!pkt.checksum_present());
211        assert!(!pkt.key_present());
212        assert!(!pkt.sequence_present());
213        assert_eq!(pkt.version(), 0);
214        assert_eq!(pkt.protocol_type(), EtherType::Ipv4);
215        assert_eq!(pkt.header_length(), 4);
216        assert_eq!(pkt.payload(), &[0xAA, 0xBB]);
217        assert_eq!(pkt.key(), None);
218        assert_eq!(pkt.sequence(), None);
219    }
220
221    #[test]
222    fn parse_gre_with_key() {
223        // K bit set, key=0x12345678
224        let mut data = vec![0x20u8, 0x00, 0x08, 0x00]; // K=1
225        data.extend_from_slice(&0x12345678u32.to_be_bytes());
226        data.extend_from_slice(&[0xCC, 0xDD]);
227        let pkt = GrePacket::new(&data).unwrap();
228        assert!(pkt.key_present());
229        assert_eq!(pkt.key(), Some(0x12345678));
230        assert_eq!(pkt.header_length(), 8);
231        assert_eq!(pkt.payload(), &[0xCC, 0xDD]);
232    }
233
234    #[test]
235    fn parse_gre_with_key_seq() {
236        // K+S, key=1, seq=42
237        let mut data = vec![0x30u8, 0x00, 0x08, 0x00];
238        data.extend_from_slice(&1u32.to_be_bytes());
239        data.extend_from_slice(&42u32.to_be_bytes());
240        data.push(0xEE);
241        let pkt = GrePacket::new(&data).unwrap();
242        assert!(pkt.key_present());
243        assert!(pkt.sequence_present());
244        assert_eq!(pkt.key(), Some(1));
245        assert_eq!(pkt.sequence(), Some(42));
246        assert_eq!(pkt.header_length(), 12);
247        assert_eq!(pkt.payload(), &[0xEE]);
248    }
249
250    #[test]
251    fn build_roundtrip() {
252        let pkt = GrePacketBuilder::new(EtherType::Ipv4)
253            .key(0xABCD)
254            .sequence(100)
255            .payload(&[0x01, 0x02, 0x03])
256            .build();
257
258        let parsed = GrePacket::new(&pkt).unwrap();
259        assert_eq!(parsed.protocol_type(), EtherType::Ipv4);
260        assert_eq!(parsed.key(), Some(0xABCD));
261        assert_eq!(parsed.sequence(), Some(100));
262        assert!(parsed.key_present()); // key always set when seq is set
263        assert_eq!(parsed.payload(), &[0x01, 0x02, 0x03]);
264    }
265
266    #[test]
267    fn build_with_checksum() {
268        let pkt = GrePacketBuilder::new(EtherType::Ipv4)
269            .key(1)
270            .checksum()
271            .payload(&[0xAA])
272            .build();
273
274        let parsed = GrePacket::new(&pkt).unwrap();
275        assert!(parsed.checksum_present());
276        assert!(parsed.checksum().is_some());
277        assert_eq!(parsed.payload(), &[0xAA]);
278    }
279
280    #[test]
281    fn parse_too_short() {
282        assert!(GrePacket::new(&[]).is_none());
283        assert!(GrePacket::new(&[0u8; 3]).is_none());
284        assert!(GrePacket::new(&[0u8; 4]).is_some());
285    }
286
287    #[test]
288    fn header_length_variants() {
289        let basic = GrePacketBuilder::new(EtherType::Ipv4).build();
290        assert_eq!(GrePacket::new(&basic).unwrap().header_length(), 4);
291
292        let with_key = GrePacketBuilder::new(EtherType::Ipv4).key(1).build();
293        assert_eq!(GrePacket::new(&with_key).unwrap().header_length(), 8);
294
295        let with_key_seq = GrePacketBuilder::new(EtherType::Ipv4).key(1).sequence(1).build();
296        assert_eq!(GrePacket::new(&with_key_seq).unwrap().header_length(), 12);
297    }
298}