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::{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    pub fn new(buf: &'a [u8]) -> Option<Self> {
30        if buf.len() < GRE_MIN_LEN { return None; }
31        Some(Self { buf })
32    }
33
34    #[inline]
35    pub fn flags(&self) -> u16 {
36        read_u16be(&self.buf[..2])
37    }
38
39    #[inline] pub fn checksum_present(&self) -> bool { self.flags() & FLAG_CHECKSUM != 0 }
40    #[inline] pub fn routing_present(&self) -> bool { self.flags() & FLAG_ROUTING != 0 }
41    #[inline] pub fn key_present(&self) -> bool { self.flags() & FLAG_KEY != 0 }
42    #[inline] pub fn sequence_present(&self) -> bool { self.flags() & FLAG_SEQUENCE != 0 }
43    #[inline] pub fn strict_source_route(&self) -> bool { self.flags() & FLAG_STRICT_ROUTE != 0 }
44    #[inline] pub fn recursion_control(&self) -> u8 {
45        ((self.flags() & FLAG_RECURSION_MASK) >> FLAG_RECURSION_SHIFT) as u8
46    }
47    #[inline] pub fn version(&self) -> u8 {
48        (self.flags() & FLAG_VERSION_MASK) as u8
49    }
50
51    #[inline]
52    pub fn protocol_type(&self) -> EtherType {
53        EtherType::from(read_u16be(&self.buf[2..4]))
54    }
55
56    fn option_offset(&self) -> usize {
57        let mut off = GRE_MIN_LEN;
58        if self.checksum_present() { off += 4; }
59        if self.key_present() { off += 4; }
60        if self.sequence_present() { off += 4; }
61        if self.routing_present()
62            && off + 2 <= self.buf.len() {
63                let routing_len = read_u16be(&self.buf[off..off+2]) as usize;
64                off += routing_len;
65        }
66        off
67    }
68
69    pub fn checksum(&self) -> Option<u16> {
70        if self.checksum_present() && self.buf.len() >= 8 {
71            Some(read_u16be(&self.buf[4..6]))
72        } else { None }
73    }
74
75    pub fn key(&self) -> Option<u32> {
76        if !self.key_present() { return None; }
77        let mut off = GRE_MIN_LEN;
78        if self.checksum_present() { off += 4; }
79        if off + 4 <= self.buf.len() { Some(read_u32be(&self.buf[off..off+4])) } else { None }
80    }
81
82    pub fn sequence(&self) -> Option<u32> {
83        if !self.sequence_present() { return None; }
84        let mut off = GRE_MIN_LEN;
85        if self.checksum_present() { off += 4; }
86        if self.key_present() { off += 4; }
87        if off + 4 <= self.buf.len() { Some(read_u32be(&self.buf[off..off+4])) } else { None }
88    }
89
90    pub fn routing(&self) -> Option<&[u8]> {
91        if !self.routing_present() { return None; }
92        let mut off = GRE_MIN_LEN;
93        if self.checksum_present() { off += 4; }
94        if self.key_present() { off += 4; }
95        if self.sequence_present() { off += 4; }
96        if off + 2 <= self.buf.len() {
97            let len = read_u16be(&self.buf[off..off+2]) as usize;
98            let end = (off + len).min(self.buf.len());
99            Some(&self.buf[off..end])
100        } else { None }
101    }
102
103    #[inline]
104    pub fn header_length(&self) -> usize { self.option_offset() }
105
106    #[inline]
107    pub fn payload(&self) -> &'a [u8] { &self.buf[self.option_offset()..] }
108}
109
110// ---------------------------------------------------------------------------
111// Builder
112// ---------------------------------------------------------------------------
113
114pub struct GrePacketBuilder {
115    buf: Vec<u8>,
116    has_checksum: bool,
117    has_key: bool,
118    has_seq: bool,
119    key_val: u32,
120    seq_val: u32,
121    payload: Option<Vec<u8>>,
122}
123
124impl GrePacketBuilder {
125    pub fn new(protocol_type: EtherType) -> Self {
126        let mut buf = vec![0u8; GRE_MIN_LEN];
127        let pt: u16 = protocol_type.into();
128        write_u16be(&mut buf[2..4], pt);
129        Self {
130            buf, has_checksum: false, has_key: false, has_seq: false,
131            key_val: 0, seq_val: 0, payload: None,
132        }
133    }
134
135    pub fn key(mut self, key: u32) -> Self {
136        self.has_key = true; self.key_val = key; self
137    }
138
139    pub fn sequence(mut self, seq: u32) -> Self {
140        self.has_seq = true; self.seq_val = seq; self
141    }
142
143    pub fn checksum(mut self) -> Self {
144        self.has_checksum = true; self
145    }
146
147    pub fn recursion_control(mut self, v: u8) -> Self {
148        let flags = read_u16be(&self.buf[..2]);
149        let updated = (flags & !FLAG_RECURSION_MASK) | (((v as u16) << FLAG_RECURSION_SHIFT) & FLAG_RECURSION_MASK);
150        write_u16be(&mut self.buf[..2], updated);
151        self
152    }
153
154    pub fn version(mut self, v: u8) -> Self {
155        let flags = read_u16be(&self.buf[..2]);
156        write_u16be(&mut self.buf[..2], (flags & !FLAG_VERSION_MASK) | (v as u16 & FLAG_VERSION_MASK));
157        self
158    }
159
160    pub fn payload(mut self, data: &[u8]) -> Self {
161        self.payload = Some(data.to_vec());
162        self
163    }
164
165    pub fn build(mut self) -> Vec<u8> {
166        let mut flags = read_u16be(&self.buf[..2]);
167        if self.has_checksum { flags |= FLAG_CHECKSUM; }
168        if self.has_key { flags |= FLAG_KEY; }
169        if self.has_seq {
170            flags |= FLAG_SEQUENCE;
171            if !self.has_key { self.has_key = true; self.key_val = 0; flags |= FLAG_KEY; }
172        }
173        write_u16be(&mut self.buf[..2], flags);
174
175        let mut extras = Vec::new();
176        // Checksum slot (0 for now)
177        let csum_pos = if self.has_checksum { let p = extras.len() + GRE_MIN_LEN; extras.extend_from_slice(&[0u8; 4]); Some(p) } else { None };
178        // Key
179        if self.has_key { extras.extend_from_slice(&self.key_val.to_be_bytes()); }
180        // Sequence
181        if self.has_seq { extras.extend_from_slice(&self.seq_val.to_be_bytes()); }
182
183        let mut pkt = self.buf;
184        pkt.extend_from_slice(&extras);
185        if let Some(ref p) = self.payload { pkt.extend_from_slice(p); }
186
187        // Compute GRE checksum (RFC 2784: over GRE header + payload)
188        if let Some(pos) = csum_pos {
189            let csum = internet_checksum(&pkt);
190            write_u16be(&mut pkt[pos..pos+2], csum);
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}