1use std::net::Ipv4Addr;
2use types::*;
3use ip::Protocol;
4
5packet!(Ipv4Packet, MutIpv4Packet, 20);
6
7getters!(Ipv4Packet
8 pub fn version(&self) -> u4 {
9 read_offset!(self.0, 0, u8) >> 4
10 }
11
12 pub fn header_length(&self) -> u4 {
13 read_offset!(self.0, 0, u8) & 0x0f
14 }
15
16 pub fn dscp(&self) -> u6 {
17 read_offset!(self.0, 1, u8) >> 2
18 }
19
20 pub fn ecn(&self) -> u2 {
21 read_offset!(self.0, 1, u8) & 0x03
22 }
23
24 pub fn total_length(&self) -> u16 {
25 read_offset!(self.0, 2, u16, from_be)
26 }
27
28 pub fn identification(&self) -> u16 {
29 read_offset!(self.0, 4, u16, from_be)
30 }
31
32 pub fn flags(&self) -> Flags {
33 Flags::from_bits_truncate(read_offset!(self.0, 6, u8) >> 5)
34 }
35
36 pub fn dont_fragment(&self) -> bool {
37 self.flags().contains(Flags::DF)
38 }
39
40 pub fn more_fragments(&self) -> bool {
41 self.flags().contains(Flags::MF)
42 }
43
44 pub fn fragment_offset(&self) -> u13 {
45 read_offset!(self.0, 6, u16, from_be) & 0x1fff
46 }
47
48 pub fn ttl(&self) -> u8 {
49 read_offset!(self.0, 8, u8)
50 }
51
52 pub fn protocol(&self) -> Protocol {
53 Protocol(read_offset!(self.0, 9, u8))
54 }
55
56 pub fn header_checksum(&self) -> u16 {
57 read_offset!(self.0, 10, u16, from_be)
58 }
59
60 pub fn source(&self) -> Ipv4Addr {
61 Ipv4Addr::from(read_offset!(self.0, 12, [u8; 4]))
62 }
63
64 pub fn destination(&self) -> Ipv4Addr {
65 Ipv4Addr::from(read_offset!(self.0, 16, [u8; 4]))
66 }
67);
68
69setters!(MutIpv4Packet
70 pub fn set_version(&mut self, version: u4) {
71 let new_byte = (version << 4) | (read_offset!(self.0, 0, u8) & 0x0f);
72 write_offset!(self.0, 0, new_byte, u8);
73 }
74
75 pub fn set_header_length(&mut self, header_length: u4) {
76 let new_byte = (read_offset!(self.0, 0, u8) & 0xf0) | (header_length & 0x0f);
77 write_offset!(self.0, 0, new_byte, u8);
78 }
79
80 pub fn set_dscp(&mut self, dscp: u6) {
81 let new_byte = (dscp << 2) | (read_offset!(self.0, 1, u8) & 0x03);
82 write_offset!(self.0, 1, new_byte, u8);
83 }
84
85 pub fn set_ecn(&mut self, ecn: u2) {
86 let new_byte = (read_offset!(self.0, 1, u8) & 0xfc) | (ecn & 0x03);
87 write_offset!(self.0, 1, new_byte, u8);
88 }
89
90 pub fn set_total_length(&mut self, total_length: u16) {
91 write_offset!(self.0, 2, total_length, u16, to_be);
92 }
93
94 pub fn set_identification(&mut self, identification: u16) {
95 write_offset!(self.0, 4, identification, u16, to_be);
96 }
97
98 pub fn set_flags(&mut self, flags: Flags) {
99 let new_byte = (flags.bits() << 5) | (read_offset!(self.0, 6, u8) & 0x1f);
100 write_offset!(self.0, 6, new_byte, u8);
101 }
102
103 pub fn set_fragment_offset(&mut self, fragment_offset: u13) {
104 let new_byte = (read_offset!(self.0, 6, u16, from_be) & 0xe000) |
105 (fragment_offset & 0x1fff);
106 write_offset!(self.0, 6, new_byte, u16, to_be);
107 }
108
109 pub fn set_ttl(&mut self, ttl: u8) {
110 write_offset!(self.0, 8, ttl, u8);
111 }
112
113 pub fn set_protocol(&mut self, protocol: Protocol) {
114 write_offset!(self.0, 9, protocol.value(), u8);
115 }
116
117 pub fn set_header_checksum(&mut self, checksum: u16) {
118 write_offset!(self.0, 10, checksum, u16, to_be);
119 }
120
121 pub fn set_source(&mut self, source: Ipv4Addr) {
122 write_offset!(self.0, 12, source.octets(), [u8; 4]);
123 }
124
125 pub fn set_destination(&mut self, destination: Ipv4Addr) {
126 write_offset!(self.0, 16, destination.octets(), [u8; 4]);
127 }
128);
129
130
131bitflags! {
132 pub struct Flags: u3 {
134 const RESERVED = 0b100;
136 const DF = 0b010;
138 const MF = 0b001;
140 }
141}
142
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn min_length() {
150 assert_eq!(Ipv4Packet::MIN_LEN, 20);
151 }
152
153 #[test]
154 fn too_short_slice() {
155 assert!(Ipv4Packet::new(&[0; 19]).is_none());
156 }
157
158 #[test]
159 fn exactly_20_bytes_slice() {
160 let packet = Ipv4Packet::new(&[1; 20]).expect("Ipv4Packet to accept 20 bytes");
161 assert_eq!(packet.data(), &[1; 20]);
162 assert_eq!(packet.header(), &[1; 20]);
163 assert!(packet.payload().is_empty());
164 }
165
166 #[test]
167 fn correct_payload() {
168 let mut data = vec![2; 19];
169 data.push(3);
170 data.push(4);
171 let packet = Ipv4Packet::new(&data[..]).expect("Ipv4Packet to accept 21 bytes");
172 assert_eq!(packet.data(), &data[..]);
173 assert_eq!(packet.header(), &data[..20]);
174 assert_eq!(packet.payload(), &[4]);
175 }
176
177 macro_rules! ipv4_setget_test {
178 ($name:ident, $set_name:ident, $value:expr, $offset:expr, $expected:expr) => {
179 setget_test!(MutIpv4Packet, $name, $set_name, $value, $offset, $expected);
180 }
181 }
182
183 ipv4_setget_test!(version, set_version, 0xf, 0, [0xf0]);
184 ipv4_setget_test!(header_length, set_header_length, 0xf, 0, [0x0f]);
185 ipv4_setget_test!(dscp, set_dscp, 0x3f, 1, [0xfc]);
186 ipv4_setget_test!(ecn, set_ecn, 0x3, 1, [0x3]);
187 ipv4_setget_test!(total_length, set_total_length, 0xffbf, 2, [0xff, 0xbf]);
188 ipv4_setget_test!(identification, set_identification, 0xffaf, 4, [0xff, 0xaf]);
189 ipv4_setget_test!(flags, set_flags, Flags::all(), 6, [0xe0]);
190 ipv4_setget_test!(
191 fragment_offset,
192 set_fragment_offset,
193 0x1faf,
194 6,
195 [0x1f, 0xaf]
196 );
197 ipv4_setget_test!(ttl, set_ttl, 0xff, 8, [0xff]);
198 ipv4_setget_test!(protocol, set_protocol, Protocol(0xff), 9, [0xff]);
199 ipv4_setget_test!(
200 header_checksum,
201 set_header_checksum,
202 0xfeff,
203 10,
204 [0xfe, 0xff]
205 );
206 ipv4_setget_test!(
207 source,
208 set_source,
209 Ipv4Addr::new(192, 168, 15, 1),
210 12,
211 [192, 168, 15, 1]
212 );
213 ipv4_setget_test!(
214 destination,
215 set_destination,
216 Ipv4Addr::new(168, 254, 99, 88),
217 16,
218 [168, 254, 99, 88]
219 );
220
221 #[test]
222 fn getters_alternating_bits() {
223 let backing_data = [0b1010_1010; 20];
224 let testee = Ipv4Packet::new(&backing_data).unwrap();
225 assert_eq!(0b1010, testee.version());
226 assert_eq!(0b1010, testee.header_length());
227 assert_eq!(0b101010, testee.dscp());
228 assert_eq!(0b10, testee.ecn());
229 assert_eq!(0b1010_1010_1010_1010, testee.total_length());
230 assert_eq!(0b1010_1010_1010_1010, testee.identification());
231 assert_eq!(Flags::RESERVED | Flags::MF, testee.flags());
232 assert!(!testee.dont_fragment());
233 assert!(testee.more_fragments());
234 assert_eq!(0b0_1010_1010_1010, testee.fragment_offset());
235 }
236}