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::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}