ppp_packet/
lib.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Utilities for parsing and serializing PPP packets.
6//!
7//! Currently supports parsing and serialization of LCP, IPCP, and IPV6CP packets and their
8//! configuration options.
9
10#![deny(missing_docs)]
11
12pub mod ipv4;
13pub mod ipv6;
14pub mod link;
15pub mod records;
16
17use packet::{
18    BufferView, BufferViewMut, FragmentedBytesMut, PacketBuilder, PacketConstraints,
19    ParsablePacket, ParseMetadata, SerializeTarget,
20};
21use thiserror::Error;
22use zerocopy::byteorder::network_endian::{U16, U32};
23use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
24
25/// The type of error that occurred while attempting to parse a packet.
26#[derive(Error, Debug, PartialEq)]
27pub enum ParseError {
28    /// Too few bytes for header.
29    #[error("Too few bytes for header.")]
30    InsufficientHeaderBytes,
31    /// Too few bytes for body (per header).
32    #[error("Too few bytes for body (per header).")]
33    InsufficientBodyBytes,
34    /// Too many bytes for body (per header).
35    #[error("Too many bytes for body (per header).")]
36    ExcessBodyBytes,
37}
38
39#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
40#[repr(C)]
41struct PppHeader {
42    protocol: U16,
43}
44
45impl PppHeader {
46    pub fn protocol(&self) -> u16 {
47        self.protocol.get()
48    }
49}
50
51/// Wrapper around a parsed on-the-wire PPP header and the rest of the packet.
52pub struct PppPacket<B> {
53    header: Ref<B, PppHeader>,
54    body: B,
55}
56
57impl<B: SplitByteSlice> PppPacket<B> {
58    /// Extract the protocol from the wire format.
59    pub fn protocol(&self) -> u16 {
60        self.header.protocol()
61    }
62}
63
64impl<B: SplitByteSlice> ParsablePacket<B, ()> for PppPacket<B> {
65    type Error = ParseError;
66
67    fn parse_metadata(&self) -> ParseMetadata {
68        ParseMetadata::from_packet(Ref::bytes(&self.header).len(), self.body.len(), 0)
69    }
70
71    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> Result<Self, Self::Error> {
72        let header =
73            buffer.take_obj_front::<PppHeader>().ok_or(ParseError::InsufficientHeaderBytes)?;
74        Ok(Self { header, body: buffer.into_rest() })
75    }
76}
77
78/// Builder for a PPP packet.
79pub struct PppPacketBuilder {
80    protocol: u16,
81}
82
83impl PppPacketBuilder {
84    /// Construct with the given protocol.
85    pub fn new(protocol: u16) -> Self {
86        Self { protocol }
87    }
88}
89
90impl PacketBuilder for PppPacketBuilder {
91    fn constraints(&self) -> PacketConstraints {
92        PacketConstraints::new(std::mem::size_of::<PppHeader>(), 0, 0, usize::max_value())
93    }
94
95    fn serialize(&self, target: &mut SerializeTarget<'_>, _body: FragmentedBytesMut<'_, '_>) {
96        let mut header = (&mut target.header).take_obj_front_zero::<PppHeader>().unwrap();
97        header.protocol = U16::new(self.protocol);
98    }
99}
100
101#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
102#[repr(C)]
103struct ControlProtocolHeader {
104    code: u8,
105    identifier: u8,
106    length: U16,
107}
108
109impl ControlProtocolHeader {
110    pub fn code(&self) -> u8 {
111        self.code
112    }
113
114    pub fn identifier(&self) -> u8 {
115        self.identifier
116    }
117
118    pub fn length(&self) -> u16 {
119        self.length.get()
120    }
121}
122
123/// Wrapper around a parsed on-the-wire control protocol header and the rest of the packet.
124pub struct ControlProtocolPacket<B> {
125    header: Ref<B, ControlProtocolHeader>,
126    body: B,
127}
128
129impl<B: SplitByteSlice> ControlProtocolPacket<B> {
130    /// Extract the code from the wire format.
131    pub fn code(&self) -> u8 {
132        self.header.code()
133    }
134
135    /// Extract the identifier from the wire format.
136    pub fn identifier(&self) -> u8 {
137        self.header.identifier()
138    }
139}
140
141impl<B: SplitByteSlice> ParsablePacket<B, ()> for ControlProtocolPacket<B> {
142    type Error = ParseError;
143
144    fn parse_metadata(&self) -> ParseMetadata {
145        ParseMetadata::from_packet(Ref::bytes(&self.header).len(), self.body.len(), 0)
146    }
147
148    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> Result<Self, Self::Error> {
149        let header = buffer
150            .take_obj_front::<ControlProtocolHeader>()
151            .ok_or(ParseError::InsufficientHeaderBytes)?;
152
153        let body_length = (header.length() as usize)
154            .checked_sub(Ref::bytes(&header).len())
155            .ok_or(ParseError::InsufficientBodyBytes)?;
156
157        let padding = buffer.len().checked_sub(body_length).ok_or(ParseError::ExcessBodyBytes)?;
158
159        // We did the necessary bounds check above for this to be safe. `parse`
160        // is required to consume this padding from the suffix to maintain the
161        // body invariant for encapsulated packets.
162        buffer.take_back(padding).unwrap();
163
164        Ok(Self { header, body: buffer.into_rest() })
165    }
166}
167
168/// Builder for a control protocol packet.
169pub struct ControlProtocolPacketBuilder {
170    code: u8,
171    identifier: u8,
172}
173
174impl ControlProtocolPacketBuilder {
175    /// Construct with the given code and identifier.
176    pub fn new(code: u8, identifier: u8) -> Self {
177        Self { code, identifier }
178    }
179}
180
181impl PacketBuilder for ControlProtocolPacketBuilder {
182    fn constraints(&self) -> PacketConstraints {
183        PacketConstraints::new(
184            std::mem::size_of::<ControlProtocolHeader>(),
185            0,
186            0,
187            usize::max_value(),
188        )
189    }
190
191    fn serialize(&self, target: &mut SerializeTarget<'_>, body: FragmentedBytesMut<'_, '_>) {
192        let mut header = &mut target.header;
193        let mut header = header.take_obj_front_zero::<ControlProtocolHeader>().unwrap();
194
195        let length = body
196            .len()
197            .try_into()
198            .ok()
199            .and_then(|c: u16| c.checked_add(self.constraints().header_len() as u16))
200            .unwrap();
201
202        header.code = self.code;
203        header.identifier = self.identifier;
204        header.length = U16::new(length);
205    }
206}
207
208/// Wrapper around a parsed on-the-wire configuration packet header and the rest of the packet.
209pub struct ConfigurationPacket<B> {
210    body: B,
211}
212
213impl<B: SplitByteSlice> ParsablePacket<B, ()> for ConfigurationPacket<B> {
214    type Error = ParseError;
215
216    fn parse_metadata(&self) -> ParseMetadata {
217        ParseMetadata::from_packet(0, self.body.len(), 0)
218    }
219
220    fn parse<BV: BufferView<B>>(buffer: BV, _args: ()) -> Result<Self, Self::Error> {
221        Ok(Self { body: buffer.into_rest() })
222    }
223}
224
225/// Builder for a configuration packet.
226#[derive(Default)]
227pub struct ConfigurationPacketBuilder;
228
229impl ConfigurationPacketBuilder {
230    /// Construct.
231    pub fn new() -> Self {
232        Self {}
233    }
234}
235
236impl PacketBuilder for ConfigurationPacketBuilder {
237    fn constraints(&self) -> PacketConstraints {
238        PacketConstraints::new(0, 0, 0, usize::max_value())
239    }
240
241    fn serialize(&self, _target: &mut SerializeTarget<'_>, _body: FragmentedBytesMut<'_, '_>) {}
242}
243
244/// Wrapper around a parsed on-the-wire termination packet header and the rest of the packet.
245pub struct TerminationPacket<B> {
246    body: B,
247}
248
249impl<B: SplitByteSlice> ParsablePacket<B, ()> for TerminationPacket<B> {
250    type Error = ParseError;
251
252    fn parse_metadata(&self) -> ParseMetadata {
253        ParseMetadata::from_packet(0, self.body.len(), 0)
254    }
255
256    fn parse<BV: BufferView<B>>(buffer: BV, _args: ()) -> Result<Self, Self::Error> {
257        Ok(Self { body: buffer.into_rest() })
258    }
259}
260
261/// Builder for a termination packet.
262#[derive(Default)]
263pub struct TerminationPacketBuilder;
264
265impl TerminationPacketBuilder {
266    /// Construct.
267    pub fn new() -> Self {
268        Self {}
269    }
270}
271
272impl PacketBuilder for TerminationPacketBuilder {
273    fn constraints(&self) -> PacketConstraints {
274        PacketConstraints::new(0, 0, 0, usize::max_value())
275    }
276
277    fn serialize(&self, _target: &mut SerializeTarget<'_>, _body: FragmentedBytesMut<'_, '_>) {}
278}
279
280/// Wrapper around a parsed on-the-wire code reject packet header and the rest of the packet.
281pub struct CodeRejectPacket<B> {
282    body: B,
283}
284
285impl<B: SplitByteSlice> ParsablePacket<B, ()> for CodeRejectPacket<B> {
286    type Error = ParseError;
287
288    fn parse_metadata(&self) -> ParseMetadata {
289        ParseMetadata::from_packet(0, self.body.len(), 0)
290    }
291
292    fn parse<BV: BufferView<B>>(buffer: BV, _args: ()) -> Result<Self, Self::Error> {
293        Ok(Self { body: buffer.into_rest() })
294    }
295}
296
297/// Builder for a code reject packet.
298#[derive(Default)]
299pub struct CodeRejectPacketBuilder;
300
301impl CodeRejectPacketBuilder {
302    /// Construct.
303    pub fn new() -> Self {
304        Self {}
305    }
306}
307
308impl PacketBuilder for CodeRejectPacketBuilder {
309    fn constraints(&self) -> PacketConstraints {
310        PacketConstraints::new(0, 0, 0, usize::max_value())
311    }
312
313    fn serialize(&self, _target: &mut SerializeTarget<'_>, _body: FragmentedBytesMut<'_, '_>) {}
314}
315
316#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
317#[repr(C)]
318struct ProtocolRejectHeader {
319    rejected_protocol: U16,
320}
321
322impl ProtocolRejectHeader {
323    pub fn rejected_protocol(&self) -> u16 {
324        self.rejected_protocol.get()
325    }
326}
327
328/// Wrapper around a parsed on-the-wire protocol reject packet header and the rest of the packet.
329pub struct ProtocolRejectPacket<B> {
330    header: Ref<B, ProtocolRejectHeader>,
331    body: B,
332}
333
334impl<B: SplitByteSlice> ProtocolRejectPacket<B> {
335    /// Extract the rejected protocol from the wire format.
336    pub fn rejected_protocol(&self) -> u16 {
337        self.header.rejected_protocol()
338    }
339}
340
341impl<B: SplitByteSlice> ParsablePacket<B, ()> for ProtocolRejectPacket<B> {
342    type Error = ParseError;
343
344    fn parse_metadata(&self) -> ParseMetadata {
345        ParseMetadata::from_packet(Ref::bytes(&self.header).len(), self.body.len(), 0)
346    }
347
348    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> Result<Self, Self::Error> {
349        let header = buffer
350            .take_obj_front::<ProtocolRejectHeader>()
351            .ok_or(ParseError::InsufficientHeaderBytes)?;
352        Ok(Self { header, body: buffer.into_rest() })
353    }
354}
355
356/// Builder for a protocol reject packet.
357pub struct ProtocolRejectPacketBuilder {
358    rejected_protocol: u16,
359}
360
361impl ProtocolRejectPacketBuilder {
362    /// Construct with a rejected protocol.
363    pub fn new(rejected_protocol: u16) -> Self {
364        Self { rejected_protocol }
365    }
366}
367
368impl PacketBuilder for ProtocolRejectPacketBuilder {
369    fn constraints(&self) -> PacketConstraints {
370        PacketConstraints::new(
371            std::mem::size_of::<ProtocolRejectHeader>(),
372            0,
373            0,
374            usize::max_value(),
375        )
376    }
377
378    fn serialize(&self, target: &mut SerializeTarget<'_>, _body: FragmentedBytesMut<'_, '_>) {
379        let mut header =
380            (&mut target.header).take_obj_front_zero::<ProtocolRejectHeader>().unwrap();
381        header.rejected_protocol = U16::new(self.rejected_protocol);
382    }
383}
384
385#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
386#[repr(C)]
387struct EchoDiscardHeader {
388    magic_number: U32,
389}
390
391impl EchoDiscardHeader {
392    pub fn magic_number(&self) -> u32 {
393        self.magic_number.get()
394    }
395}
396
397/// Wrapper around a parsed on-the-wire echo-discard packet header and the rest of the packet.
398pub struct EchoDiscardPacket<B> {
399    header: Ref<B, EchoDiscardHeader>,
400    body: B,
401}
402
403impl<B: SplitByteSlice> EchoDiscardPacket<B> {
404    /// Extract the magic number from the wire format.
405    pub fn magic_number(&self) -> u32 {
406        self.header.magic_number()
407    }
408}
409
410impl<B: SplitByteSlice> ParsablePacket<B, ()> for EchoDiscardPacket<B> {
411    type Error = ParseError;
412
413    fn parse_metadata(&self) -> ParseMetadata {
414        ParseMetadata::from_packet(Ref::bytes(&self.header).len(), self.body.len(), 0)
415    }
416
417    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> Result<Self, Self::Error> {
418        let header = buffer
419            .take_obj_front::<EchoDiscardHeader>()
420            .ok_or(ParseError::InsufficientHeaderBytes)?;
421        Ok(Self { header, body: buffer.into_rest() })
422    }
423}
424
425/// Builder for an echo-discard packet.
426pub struct EchoDiscardPacketBuilder {
427    magic_number: u32,
428}
429
430impl EchoDiscardPacketBuilder {
431    /// Construct with a magic number.
432    pub fn new(magic_number: u32) -> Self {
433        Self { magic_number }
434    }
435}
436
437impl PacketBuilder for EchoDiscardPacketBuilder {
438    fn constraints(&self) -> PacketConstraints {
439        PacketConstraints::new(std::mem::size_of::<EchoDiscardHeader>(), 0, 0, usize::max_value())
440    }
441
442    fn serialize(&self, target: &mut SerializeTarget<'_>, _body: FragmentedBytesMut<'_, '_>) {
443        let mut header = (&mut target.header).take_obj_front_zero::<EchoDiscardHeader>().unwrap();
444        header.magic_number = U32::new(self.magic_number);
445    }
446}
447
448#[cfg(test)]
449mod tests {
450    use super::*;
451    use crate::records::options::{Options, OptionsSerializer};
452    use packet::{Buf, InnerPacketBuilder, ParseBuffer, Serializer};
453
454    #[fuchsia::test]
455    fn test_link_parse_serialize() {
456        let expected_link_options = [
457            link::ControlOption::MaximumReceiveUnit(0x8888),
458            link::ControlOption::AddressControlFieldCompression,
459            link::ControlOption::QualityProtocol(0xc025, vec![0xab, 0xcd, 0xef]),
460            link::ControlOption::MagicNumber(0x01234567),
461        ];
462
463        const EXPECT_BUFFER: [u8; 25] = [
464            0xc0, 0x21, 3, 0xe6, 0x00, 0x17, 1, 4, 0x05, 0xdc, 8, 2, 4, 7, 0xc0, 0x25, 0xab, 0xcd,
465            0xef, 5, 6, 0x01, 0x23, 0x45, 0x67,
466        ];
467
468        let buf: [u8; 25] = [
469            0xc0, 0x21, 1, 0xe6, 0x00, 0x17, 1, 4, 0x88, 0x88, 8, 2, 4, 7, 0xc0, 0x25, 0xab, 0xcd,
470            0xef, 5, 6, 0x01, 0x23, 0x45, 0x67,
471        ];
472
473        let mut buf = Buf::new(buf, ..);
474
475        let ppp = buf.parse::<PppPacket<_>>().unwrap();
476        let protocol = ppp.protocol();
477        assert_eq!(protocol, 0xc021);
478
479        let lcp = buf.parse::<ControlProtocolPacket<_>>().unwrap();
480        let code = lcp.code();
481        let identifier = lcp.identifier();
482        assert_eq!(code, 1);
483        assert_eq!(identifier, 0xe6);
484
485        let _configuration_packet = buf.parse::<ConfigurationPacket<_>>().unwrap();
486        let mut options: Vec<_> = Options::<_, link::ControlOptionsImpl>::parse(buf.as_ref())
487            .map(|options| options.iter().collect())
488            .unwrap();
489
490        assert_eq!(options, expected_link_options);
491
492        if let link::ControlOption::MaximumReceiveUnit(ref mut mru) = options[0] {
493            *mru = 0x05dc;
494        };
495
496        let buffer = OptionsSerializer::<link::ControlOptionsImpl, link::ControlOption, _>::new(
497            options.iter(),
498        )
499        .into_serializer()
500        .encapsulate(ControlProtocolPacketBuilder::new(3, identifier))
501        .encapsulate(PppPacketBuilder::new(protocol))
502        .serialize_vec_outer()
503        .ok()
504        .unwrap();
505
506        assert_eq!(buffer.as_ref(), EXPECT_BUFFER);
507    }
508
509    #[fuchsia::test]
510    fn test_ipv4_parse_serialize() {
511        let expected_ipv4_options = [
512            ipv4::ControlOption::Unrecognized(0xa, vec![0x01, 0x02, 0x03]),
513            ipv4::ControlOption::IpAddress(0xffee_ddcc),
514            ipv4::ControlOption::IpCompressionProtocol(0x002d, vec![0x89]),
515        ];
516        const EXPECT_BUFFER: [u8; 22] = [
517            0x80, 0x21, 4, 0x03, 0x00, 0x14, 0xa, 5, 0x01, 0x02, 0x03, 0x3, 6, 0xaa, 0xbb, 0xcc,
518            0xdd, 0x2, 5, 0x00, 0x2d, 0x89,
519        ];
520
521        let buf: [u8; 22] = [
522            0x80, 0x21, 1, 0x03, 0x00, 0x14, 0xa, 5, 0x01, 0x02, 0x03, 0x3, 6, 0xff, 0xee, 0xdd,
523            0xcc, 0x2, 5, 0x00, 0x2d, 0x89,
524        ];
525
526        let mut buf = Buf::new(buf, ..);
527
528        let ppp = buf.parse::<PppPacket<_>>().unwrap();
529        let protocol = ppp.protocol();
530        assert_eq!(protocol, 0x8021);
531
532        let lcp = buf.parse::<ControlProtocolPacket<_>>().unwrap();
533        let code = lcp.code();
534        let identifier = lcp.identifier();
535        assert_eq!(code, 1);
536        assert_eq!(identifier, 0x03);
537
538        let _configuration_packet = buf.parse::<ConfigurationPacket<_>>().unwrap();
539        let mut options: Vec<_> = Options::<_, ipv4::ControlOptionsImpl>::parse(buf.as_ref())
540            .map(|options| options.iter().collect())
541            .unwrap();
542
543        assert_eq!(options, expected_ipv4_options);
544
545        if let ipv4::ControlOption::IpAddress(ref mut address) = options[1] {
546            *address = 0xaabbccdd;
547        };
548
549        let buffer = OptionsSerializer::<ipv4::ControlOptionsImpl, ipv4::ControlOption, _>::new(
550            options.iter(),
551        )
552        .into_serializer()
553        .encapsulate(ControlProtocolPacketBuilder::new(4, identifier))
554        .encapsulate(PppPacketBuilder::new(protocol))
555        .serialize_vec_outer()
556        .ok()
557        .unwrap();
558
559        assert_eq!(buffer.as_ref(), EXPECT_BUFFER);
560    }
561
562    #[fuchsia::test]
563    fn test_ipv6_parse_serialize() {
564        let expected_ipv6_options = [
565            ipv6::ControlOption::Unrecognized(0x5, vec![0x99]),
566            ipv6::ControlOption::InterfaceIdentifier(0x0123_4567_890a_bcde),
567        ];
568
569        const EXPECT_BUFFER: [u8; 21] = [
570            0x80, 0x57, 2, 0x09, 0x00, 0x13, 0x5, 5, 0x99, 0x88, 0x77, 0x01, 10, 0x01, 0x23, 0x45,
571            0x67, 0x89, 0x0a, 0xbc, 0xde,
572        ];
573
574        let buf: [u8; 19] = [
575            0x80, 0x57, 1, 0x09, 0x00, 0x11, 0x5, 3, 0x99, 0x01, 10, 0x01, 0x23, 0x45, 0x67, 0x89,
576            0x0a, 0xbc, 0xde,
577        ];
578
579        let mut buf = Buf::new(buf, ..);
580
581        let ppp = buf.parse::<PppPacket<_>>().unwrap();
582        let protocol = ppp.protocol();
583        assert_eq!(protocol, 0x8057);
584
585        let lcp = buf.parse::<ControlProtocolPacket<_>>().unwrap();
586        let code = lcp.code();
587        let identifier = lcp.identifier();
588        assert_eq!(code, 1);
589        assert_eq!(identifier, 0x09);
590
591        let _configuration_packet = buf.parse::<ConfigurationPacket<_>>().unwrap();
592        let mut options: Vec<_> = Options::<_, ipv6::ControlOptionsImpl>::parse(buf.as_ref())
593            .map(|options| options.iter().collect())
594            .unwrap();
595
596        assert_eq!(options, expected_ipv6_options);
597
598        if let ipv6::ControlOption::Unrecognized(ref mut _type, ref mut data) = options[0] {
599            data.push(0x88);
600            data.push(0x77);
601        };
602
603        let buffer = OptionsSerializer::<ipv6::ControlOptionsImpl, ipv6::ControlOption, _>::new(
604            options.iter(),
605        )
606        .into_serializer()
607        .encapsulate(ControlProtocolPacketBuilder::new(2, identifier))
608        .encapsulate(PppPacketBuilder::new(protocol))
609        .serialize_vec_outer()
610        .ok()
611        .unwrap();
612
613        assert_eq!(buffer.as_ref(), EXPECT_BUFFER);
614    }
615}