s2n_quic_core/xdp/
decoder.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use super::{bpf::Decoder, path};
5use crate::inet::{
6    datagram,
7    ethernet::{self, EtherType},
8    ip, ipv4, ipv6, udp,
9};
10use s2n_codec::DecoderError;
11
12pub type Result<D = ()> = core::result::Result<Option<D>, DecoderError>;
13
14pub trait EventHandler: Sized {
15    #[inline(always)]
16    fn decode_packet<'a, D: Decoder<'a>>(&mut self, buffer: D) -> Result<D> {
17        decode_packet_with_event(buffer, self)
18    }
19
20    #[inline(always)]
21    fn on_ethernet_header(&mut self, header: &ethernet::Header) -> Result {
22        let _ = header;
23        Ok(Some(()))
24    }
25
26    #[inline(always)]
27    fn on_ipv4_header(&mut self, header: &ipv4::Header) -> Result {
28        let _ = header;
29        Ok(Some(()))
30    }
31
32    #[inline(always)]
33    fn on_ipv6_header(&mut self, header: &ipv6::Header) -> Result {
34        let _ = header;
35        Ok(Some(()))
36    }
37
38    #[inline(always)]
39    fn on_udp_header(&mut self, header: &udp::Header) -> Result {
40        let _ = header;
41        Ok(Some(()))
42    }
43}
44
45impl EventHandler for () {}
46
47impl EventHandler for path::Tuple {
48    #[inline(always)]
49    fn on_ethernet_header(&mut self, header: &ethernet::Header) -> Result {
50        self.remote_address.mac = header.source;
51        self.local_address.mac = header.destination;
52        Ok(Some(()))
53    }
54
55    #[inline(always)]
56    fn on_ipv4_header(&mut self, header: &ipv4::Header) -> Result {
57        self.remote_address.ip = header.source.into();
58        self.local_address.ip = header.destination.into();
59        Ok(Some(()))
60    }
61
62    #[inline(always)]
63    fn on_ipv6_header(&mut self, header: &ipv6::Header) -> Result {
64        self.remote_address.ip = header.source.into();
65        self.local_address.ip = header.destination.into();
66        Ok(Some(()))
67    }
68
69    #[inline(always)]
70    fn on_udp_header(&mut self, header: &udp::Header) -> Result {
71        self.remote_address.port = header.source.get();
72        self.local_address.port = header.destination.get();
73        Ok(Some(()))
74    }
75}
76
77impl<P: EventHandler> EventHandler for datagram::Header<P> {
78    #[inline(always)]
79    fn on_ethernet_header(&mut self, header: &ethernet::Header) -> Result {
80        self.path.on_ethernet_header(header)
81    }
82
83    #[inline(always)]
84    fn on_ipv4_header(&mut self, header: &ipv4::Header) -> Result {
85        self.path.on_ipv4_header(header)?;
86        self.ecn = header.tos().ecn();
87        Ok(Some(()))
88    }
89
90    #[inline(always)]
91    fn on_ipv6_header(&mut self, header: &ipv6::Header) -> Result {
92        self.path.on_ipv6_header(header)?;
93        self.ecn = header.vtcfl().ecn();
94        Ok(Some(()))
95    }
96
97    #[inline(always)]
98    fn on_udp_header(&mut self, header: &udp::Header) -> Result {
99        self.path.on_udp_header(header)
100    }
101}
102
103/// Decodes a path tuple and payload from a raw packet
104#[inline(always)]
105pub fn decode_packet<'a, D: Decoder<'a>>(
106    buffer: D,
107) -> core::result::Result<Option<(datagram::Header<path::Tuple>, D)>, DecoderError> {
108    let mut header = datagram::Header {
109        path: path::Tuple::UNSPECIFIED,
110        ecn: Default::default(),
111    };
112    match decode_packet_with_event(buffer, &mut header)? {
113        Some(buffer) => Ok(Some((header, buffer))),
114        None => Ok(None),
115    }
116}
117
118/// Decodes a path tuple and payload from a raw packet
119#[inline(always)]
120pub fn decode_packet_with_event<'a, D: Decoder<'a>, E: EventHandler>(
121    buffer: D,
122    events: &mut E,
123) -> Result<D> {
124    let (header, buffer) = buffer.decode::<&ethernet::Header>()?;
125
126    if events.on_ethernet_header(header)?.is_none() {
127        return Ok(None);
128    }
129
130    match *header.ethertype() {
131        EtherType::IPV4 => decode_ipv4(buffer, events),
132        EtherType::IPV6 => decode_ipv6(buffer, events),
133        // pass the packet on to the OS network stack if we don't understand it
134        _ => Ok(None),
135    }
136}
137
138#[inline(always)]
139fn decode_ipv4<'a, D: Decoder<'a>, E: EventHandler>(buffer: D, events: &mut E) -> Result<D> {
140    let (header, buffer) = buffer.decode::<&ipv4::Header>()?;
141
142    if events.on_ipv4_header(header)?.is_none() {
143        return Ok(None);
144    }
145
146    let protocol = header.protocol();
147
148    //= https://www.rfc-editor.org/rfc/rfc791#section-3.1
149    //# IHL:  4 bits
150    //#
151    //# Internet Header Length is the length of the internet header in 32
152    //# bit words, and thus points to the beginning of the data.  Note that
153    //# the minimum value for a correct header is 5.
154
155    // subtract the fixed header size
156    let count_without_header = header
157        .vihl()
158        .header_len()
159        .checked_sub(5)
160        .ok_or(DecoderError::InvariantViolation("invalid IPv4 IHL value"))?;
161
162    // skip the options and go to the actual payload
163    let options_len = count_without_header as usize * (32 / 8);
164    let (_options, buffer) = buffer.decode_slice(options_len)?;
165
166    parse_ip_protocol(protocol, buffer, events)
167}
168
169#[inline(always)]
170fn decode_ipv6<'a, D: Decoder<'a>, E: EventHandler>(buffer: D, events: &mut E) -> Result<D> {
171    let (header, buffer) = buffer.decode::<&ipv6::Header>()?;
172
173    if events.on_ipv6_header(header)?.is_none() {
174        return Ok(None);
175    }
176
177    let protocol = header.next_header();
178
179    // TODO parse Hop-by-hop/Options headers, for now we'll just forward the packet on to the OS
180
181    parse_ip_protocol(protocol, buffer, events)
182}
183
184#[inline]
185fn parse_ip_protocol<'a, D: Decoder<'a>, E: EventHandler>(
186    protocol: &ip::Protocol,
187    buffer: D,
188    events: &mut E,
189) -> Result<D> {
190    match *protocol {
191        ip::Protocol::UDP | ip::Protocol::UDPLITE => parse_udp(buffer, events),
192        // pass the packet on to the OS network stack if we don't understand it
193        _ => Ok(None),
194    }
195}
196
197#[inline(always)]
198fn parse_udp<'a, D: Decoder<'a>, E: EventHandler>(buffer: D, events: &mut E) -> Result<D> {
199    let (header, buffer) = buffer.decode::<&udp::Header>()?;
200
201    if events.on_udp_header(header)?.is_none() {
202        return Ok(None);
203    }
204
205    // NOTE: duvet doesn't know how to parse this RFC since it doesn't follow more modern formatting
206    //# https://www.rfc-editor.org/rfc/rfc768
207    //# Length  is the length  in octets  of this user datagram  including  this
208    //# header  and the data.   (This  means  the minimum value of the length is
209    //# eight.)
210    let total_len = header.len().get();
211    let payload_len = total_len
212        .checked_sub(8)
213        .ok_or(DecoderError::InvariantViolation("invalid UDP length"))?;
214    let (udp_payload, _remaining) = buffer.decode_slice(payload_len as usize)?;
215
216    Ok(Some(udp_payload))
217}
218
219#[cfg(test)]
220mod tests {
221    use super::*;
222    use bolero::check;
223
224    // Tests to ensure memory safety and no panics
225    #[test]
226    #[cfg_attr(kani, kani::proof, kani::unwind(258), kani::solver(cadical))]
227    fn decode_test() {
228        check!().for_each(|bytes| {
229            let buffer = s2n_codec::DecoderBuffer::new(bytes);
230            let _ = decode_packet(buffer);
231        });
232    }
233}