1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use super::{Protocol, ParseError};

mod ethernet;
mod arp;
mod icmp;
mod ip;
mod tcp;
mod udp;
// de-glob the modules, doing this rather than having "pub mod x;" allows for shorter use paths
pub use ethernet::*;
pub use arp::*;
pub use icmp::*;
pub use ip::*;
pub use tcp::*;
pub use udp::*;

pub type PacketData = Vec<u8>;

pub trait Header {
    /// 'cook' the header, returning it as a `Vec<u8>`.
    /// this function will calculate checksums, even though they will be over-written by the OS if the packet is sent 'down the wire', likewise with a lot of `length` fields and such.
    /// 
    /// The reason i decided to still calculate checksums is incase someone uses the packet for some other purpose, or if they are building/using an experimntal OS which doesn calculate checksums (or they havent built that in yet).
    fn make(self) -> PacketData;

    /// parse() should never be run from a box<Header>, is hould only ever br un as <Header>::parse().
    /// this is just here to complete the implementation of Header onto boxed structs that implement header
    fn parse(raw_data: &[u8]) -> Result<Box<Self>, ParseError>;

    fn get_proto(&self) -> Protocol;

    /// get the current length of the header in bytes. this usually just returns a fixed value as most headers dont have variable length,
    /// only really IP does and even then its rare for it to be > 20 bytes
    fn get_length(&self) -> u8; // these are done as functions rather than constants in order to enforce all modules to have them if they want to implement this trait

    /// get the minimum length (in bytes) that this type of header can be
    fn get_min_length() -> u8; // these are done as functions rather than constants in order to enforce all modules to have them if they want to implement this trait

    /// attempts to coerce the header (a type which implements the Header trait) into a &mut dyn TransportHeader.
    /// Only returns `Option::Some` when the underlying concrete type is a `UdpHeader` or a `TcpHeader`
    fn into_transport_header(&mut self) -> Option<&mut dyn TransportHeader> {
        None
    }
}

pub trait TransportHeader {
    /// Sets the values of an internal value which represents the pseudo header that is used when calculating the checksum.
    /// This method must be called before the `make` method, which is called when the header is added to the `Packet` with the `add_header` method.
    /// If the IP header is already present in the `Packet` when this one is added, then this method will be called in the `add_header` method, using the data from the IP header.
    /// 
    /// TL;DR: you can ignore this method if you add this header to the `Packet` using the `add_header` method after you have added an IP header to the `Packet` with `add_header`
    fn set_pseudo_header(&mut self, src_ip: [u8; 4], dst_ip: [u8; 4], data_len: u16);
}

struct PseudoHeader {
    src_ip: [u8; 4],
    dst_ip: [u8; 4],
    protocol: u8,
    data_len: u16,
}

impl<T: Header> Header for Box<T> {
    fn make(self) -> PacketData {
        (*self).make()
    }

    fn parse(raw_data: &[u8]) -> Result<Box<Self>, ParseError>{
        match T::parse(raw_data) {
            Ok(boxed_header) => Ok(Box::new(boxed_header)),
            Err(e) => Err(e)
        }
    }

    fn get_proto(&self) -> Protocol{
        (**self).get_proto()
    }

    fn get_length(&self) -> u8{
        (**self).get_length()
    }

    fn get_min_length() -> u8{
        T::get_min_length()
    }

    fn into_transport_header(&mut self) -> Option<&mut dyn TransportHeader> {
        (**self).into_transport_header()
    }
}