ippacket/
lib.rs

1#![forbid(unsafe_code)]
2
3#[macro_use]
4mod bytes;
5mod icmp;
6mod ip;
7mod tcp;
8mod udp;
9mod window;
10
11use std::fmt;
12use std::io;
13use std::net::SocketAddr;
14
15use crate::ip::IpHeaderBuilder;
16use crate::udp::UdpHeaderBuilder;
17use crate::window::Window;
18
19pub use self::bytes::Bytes;
20pub use self::icmp::{IcmpHeader, IcmpType4, IcmpType6};
21pub use self::ip::{ExtHeader, IpHeader, IpProto};
22pub use self::tcp::TcpHeader;
23pub use self::udp::UdpHeader;
24
25#[derive(Debug)]
26pub enum Payload {
27    Udp(UdpHeader),
28    Tcp(TcpHeader),
29    Icmp(IcmpHeader),
30    Unknown(IpProto),
31}
32
33impl Payload {
34    pub fn src(&self) -> Option<u16> {
35        match self {
36            Payload::Udp(ref u) => Some(u.src()),
37            Payload::Tcp(ref t) => Some(t.src()),
38            _ => None,
39        }
40    }
41
42    pub fn dest(&self) -> Option<u16> {
43        match self {
44            Payload::Udp(ref u) => Some(u.dest()),
45            Payload::Tcp(ref t) => Some(t.dest()),
46            _ => None,
47        }
48    }
49
50    pub fn is_udp(&self) -> bool {
51        if let Payload::Udp(..) = self {
52            true
53        } else {
54            false
55        }
56    }
57}
58
59pub struct IpPacket {
60    pub fixed: IpHeader,
61    pub exts: Vec<ExtHeader>,
62    pub payload: Payload,
63    data: Bytes,
64    bytes: Bytes,
65}
66
67impl fmt::Debug for IpPacket {
68    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
69        fmt.debug_struct("IpPacket")
70            .field("fixed", &self.fixed)
71            .field("exts", &self.exts)
72            .field("payload", &self.payload)
73            .field("data", &self.data.len())
74            .field("bytes", &self.bytes.len())
75            .field("checksum_valid", &self.checksum_valid())
76            .finish()
77    }
78}
79
80impl IpPacket {
81    pub fn new(bytes: Box<[u8]>) -> io::Result<IpPacket> {
82        IpPacket::with_bytes(Bytes::new(bytes))
83    }
84
85    fn with_bytes(bytes: Bytes) -> io::Result<IpPacket> {
86        let (ip_hdr, mut remaining) = IpHeader::with_bytes(bytes.clone())?;
87        let mut exts = Vec::new();
88        let mut next = ip_hdr.next();
89        loop {
90            match next {
91                IpProto::Udp => {
92                    return match UdpHeader::with_bytes(remaining) {
93                        Ok((udp_hdr, data)) => Ok(IpPacket {
94                            fixed: ip_hdr,
95                            exts,
96                            payload: Payload::Udp(udp_hdr),
97                            data,
98                            bytes,
99                        }),
100                        Err(e) => Err(e),
101                    };
102                }
103                IpProto::Tcp => {
104                    return match TcpHeader::with_bytes(remaining) {
105                        Ok((tcp_hdr, data)) => Ok(IpPacket {
106                            fixed: ip_hdr,
107                            exts,
108                            payload: Payload::Tcp(tcp_hdr),
109                            data,
110                            bytes,
111                        }),
112                        Err(e) => Err(e),
113                    };
114                }
115                IpProto::Icmp => {
116                    return match IcmpHeader::with_bytes(remaining) {
117                        Ok((icmp_hdr, data)) => Ok(IpPacket {
118                            fixed: ip_hdr,
119                            exts,
120                            payload: Payload::Icmp(icmp_hdr),
121                            data,
122                            bytes,
123                        }),
124                        Err(e) => Err(e),
125                    };
126                }
127                p => match ExtHeader::with_bytes(remaining.clone(), p) {
128                    Ok((ext_hdr, extra)) => {
129                        next = ext_hdr.next();
130                        remaining = extra;
131                        exts.push(ext_hdr);
132                    }
133                    Err(ref e) if e.kind() == io::ErrorKind::InvalidData => {
134                        return Ok(IpPacket {
135                            fixed: ip_hdr,
136                            exts,
137                            payload: Payload::Unknown(p),
138                            data: remaining,
139                            bytes,
140                        })
141                    }
142                    Err(e) => return Err(e),
143                },
144            }
145        }
146    }
147
148    pub fn src(&self) -> Option<SocketAddr> {
149        self.payload
150            .src()
151            .map(|p| SocketAddr::new(self.fixed.src(), p))
152    }
153
154    pub fn dest(&self) -> Option<SocketAddr> {
155        self.payload
156            .dest()
157            .map(|p| SocketAddr::new(self.fixed.dest(), p))
158    }
159
160    pub fn checksum_valid(&self) -> bool {
161        if let IpHeader::V4(ref h) = &self.fixed {
162            if !h.checksum_valid() {
163                return false;
164            }
165        }
166
167        let data = self.data.pair_iter();
168        match self.payload {
169            Payload::Udp(ref u) => u.checksum_valid(&self.fixed, data),
170            Payload::Tcp(ref t) => t.checksum_valid(&self.fixed, data),
171            Payload::Icmp(ref i) => i.checksum_valid(data),
172            Payload::Unknown(_p) => true,
173        }
174    }
175
176    pub fn calculate_checksum(&mut self) {
177        if let IpHeader::V4(ref mut h) = &mut self.fixed {
178            h.calculate_checksum()
179        }
180
181        let data = self.data.pair_iter();
182        match self.payload {
183            Payload::Udp(ref mut u) => u.calculate_checksum(&self.fixed, data),
184            // Payload::Tcp(ref mut t) => t.calculate_checksum(&self.fixed, data),
185            Payload::Icmp(ref mut i) => i.calculate_checksum(data),
186            _ => (),
187        }
188    }
189
190    pub fn into_inner(self) -> Box<[u8]> {
191        self.into_data().into_inner()
192    }
193
194    pub fn into_data(self) -> Window<Box<[u8]>> {
195        drop(self.fixed);
196        drop(self.payload);
197        drop(self.exts);
198        drop(self.bytes);
199        Bytes::try_unwrap(self.data).unwrap()
200    }
201}
202
203#[derive(Default, Debug, Clone)]
204pub struct UdpPacketBuilder<'a> {
205    ip: IpHeaderBuilder,
206    udp: UdpHeaderBuilder,
207    data: Option<&'a [u8]>,
208}
209
210#[allow(clippy::len_without_is_empty)]
211impl<'a> UdpPacketBuilder<'a> {
212    pub fn new() -> UdpPacketBuilder<'a> {
213        let mut builder = UdpPacketBuilder::default();
214        builder.ip = builder.ip.proto(IpProto::Udp);
215        builder
216    }
217
218    pub fn src(mut self, src: SocketAddr) -> UdpPacketBuilder<'a> {
219        self.ip = self.ip.src(src.ip());
220        self.udp = self.udp.src(src.port());
221        self
222    }
223
224    pub fn dest(mut self, dest: SocketAddr) -> UdpPacketBuilder<'a> {
225        self.ip = self.ip.dest(dest.ip());
226        self.udp = self.udp.dest(dest.port());
227        self
228    }
229
230    pub fn data(mut self, data: &'a [u8]) -> UdpPacketBuilder<'a> {
231        self.data = Some(data);
232        self
233    }
234
235    pub fn len(&self) -> Option<usize> {
236        let ip_len = match self.ip.len() {
237            Some(l) => l,
238            None => return None,
239        };
240
241        let data_len = match self.data.map(|d| d.len()) {
242            Some(l) => l,
243            None => return None,
244        };
245
246        Some(ip_len + UdpHeaderBuilder::len() + data_len)
247    }
248
249    pub fn build(self) -> IpPacket {
250        let data = self.data.unwrap_or_else(|| unimplemented!());
251        let len = self.len().unwrap_or_else(|| unimplemented!());
252
253        let bytes = Bytes::new(vec![0; len].into_boxed_slice());
254
255        let (mut fixed, remaining) = self.ip.build(bytes.clone());
256        fixed.set_total_len(len);
257
258        let (mut udp, mut remaining) = self.udp.build(remaining);
259        udp.set_data_len(data.len());
260
261        remaining.as_mut().clone_from_slice(data);
262
263        let mut packet = IpPacket {
264            fixed,
265            exts: Vec::new(),
266            payload: Payload::Udp(udp),
267            data: remaining,
268            bytes,
269        };
270
271        packet.calculate_checksum();
272        packet
273    }
274}