rpkt/udp/
packet.rs

1use bytes::Buf;
2
3use crate::checksum_utils;
4use crate::ipv4::{Ipv4Addr, Ipv4PseudoHeader};
5use crate::{Cursor, CursorMut};
6use crate::{PktBuf, PktMut};
7
8use super::header::{UdpHeader, UDP_HEADER_LEN};
9
10packet_base! {
11    pub struct UdpPacket: UdpHeader {
12        header_len: UDP_HEADER_LEN,
13        get_methods: [
14            (source_port, u16),
15            (dest_port, u16),
16            (packet_len, u16),
17            (checksum, u16),
18        ],
19        set_methods: [
20            (set_source_port, val: u16),
21            (set_dest_port, val: u16),
22            (set_checksum, val: u16),
23        ],
24        unchecked_set_methods:[
25            (set_packet_len_unchecked, set_packet_len, value: u16)
26        ]
27    }
28}
29
30impl<T: Buf> UdpPacket<T> {
31    #[inline]
32    pub fn parse(buf: T) -> Result<UdpPacket<T>, T> {
33        if buf.chunk().len() < UDP_HEADER_LEN {
34            return Err(buf);
35        }
36
37        let packet = UdpPacket::parse_unchecked(buf);
38
39        if usize::from(packet.packet_len()) >= UDP_HEADER_LEN
40            && usize::from(packet.packet_len()) <= packet.buf.remaining()
41        {
42            Ok(packet)
43        } else {
44            Err(packet.release())
45        }
46    }
47}
48
49impl<T: PktBuf> UdpPacket<T> {
50    pub fn calc_checksum(&mut self) -> u16 {
51        let total_len = self.packet_len();
52
53        let result = checksum_utils::from_buf(&mut self.buf, total_len.into());
54        self.buf.move_back(total_len.into());
55        result
56    }
57
58    #[inline]
59    pub fn verify_ipv4_checksum(&mut self, src_addr: Ipv4Addr, dst_addr: Ipv4Addr) -> bool {
60        if self.checksum() == 0 {
61            return true;
62        }
63
64        let phdr = Ipv4PseudoHeader::from_udp_pkt(src_addr, dst_addr, self);
65
66        let cksum = checksum_utils::combine(&[phdr.calc_checksum(), self.calc_checksum()]);
67
68        cksum == !0
69    }
70
71    #[inline]
72    pub fn payload(self) -> T {
73        assert!(usize::from(self.packet_len()) <= self.buf.remaining());
74        let trim_size = self.buf.remaining() - usize::from(self.packet_len());
75
76        let mut buf = self.release();
77        if trim_size > 0 {
78            buf.trim_off(trim_size);
79        }
80
81        buf.advance(UDP_HEADER_LEN);
82
83        buf
84    }
85}
86
87impl<T: PktMut> UdpPacket<T> {
88    #[inline]
89    pub fn adjust_ipv4_checksum(&mut self, src_addr: Ipv4Addr, dst_addr: Ipv4Addr) {
90        self.set_checksum(0);
91
92        let phdr = Ipv4PseudoHeader::from_udp_pkt(src_addr, dst_addr, self);
93
94        let cksum = !checksum_utils::combine(&[phdr.calc_checksum(), self.calc_checksum()]);
95
96        // UDP checksum value of 0 means no checksum; if the checksum really is zero,
97        // use all-ones, which indicates that the remote end must verify the checksum.
98        // Arithmetically, RFC 1071 checksums of all-zeroes and all-ones behave identically,
99        // so no action is necessary on the remote end.
100        self.set_checksum(if cksum == 0 { 0xffff } else { cksum })
101    }
102
103    #[inline]
104    pub fn prepend_header<TH: AsRef<[u8]>>(mut buf: T, header: &UdpHeader<TH>) -> UdpPacket<T> {
105        assert!(buf.chunk_headroom() >= UDP_HEADER_LEN);
106        buf.move_back(UDP_HEADER_LEN);
107
108        let data = &mut buf.chunk_mut()[0..UDP_HEADER_LEN];
109        data.copy_from_slice(header.as_bytes());
110
111        let mut udppkt = UdpPacket::parse_unchecked(buf);
112        udppkt.set_packet_len_unchecked(u16::try_from(udppkt.buf().remaining()).unwrap());
113        udppkt
114    }
115}
116
117impl<'a> UdpPacket<Cursor<'a>> {
118    #[inline]
119    pub fn cursor_header(&self) -> UdpHeader<&'a [u8]> {
120        let data = &self.buf.chunk_shared_lifetime()[..UDP_HEADER_LEN];
121        UdpHeader::new_unchecked(data)
122    }
123
124    #[inline]
125    pub fn cursor_payload(&self) -> Cursor<'a> {
126        Cursor::new(
127            &self.buf.chunk_shared_lifetime()[UDP_HEADER_LEN..usize::from(self.packet_len())],
128        )
129    }
130}
131
132impl<'a> UdpPacket<CursorMut<'a>> {
133    #[inline]
134    pub fn split(self) -> (UdpHeader<&'a mut [u8]>, CursorMut<'a>) {
135        let packet_len = self.packet_len();
136
137        let (buf_mut, _) = self
138            .buf
139            .chunk_mut_shared_lifetime()
140            .split_at_mut(usize::from(packet_len));
141        let (hdr, payload) = buf_mut.split_at_mut(UDP_HEADER_LEN);
142
143        (UdpHeader::new_unchecked(hdr), CursorMut::new(payload))
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150    use crate::ether::*;
151    use crate::ipv4::*;
152    use crate::udp::UDP_HEADER_TEMPLATE;
153    use crate::{Cursor, CursorMut};
154
155    static FRAME_BYTES: [u8; 110] = [
156        0x00, 0x0b, 0x86, 0x64, 0x8b, 0xa0, 0x00, 0x50, 0x56, 0xae, 0x76, 0xf5, 0x08, 0x00, 0x45,
157        0x00, 0x00, 0x5e, 0x5c, 0x65, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0xc0, 0xa8, 0x1d, 0x3a,
158        0xc0, 0xa8, 0x1d, 0xa0, 0xeb, 0xd8, 0x00, 0xa1, 0x00, 0x4a, 0xbc, 0x86, 0x30, 0x40, 0x02,
159        0x01, 0x03, 0x30, 0x0f, 0x02, 0x03, 0x00, 0x91, 0xc8, 0x02, 0x02, 0x05, 0xdc, 0x04, 0x01,
160        0x04, 0x02, 0x01, 0x03, 0x04, 0x15, 0x30, 0x13, 0x04, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01,
161        0x00, 0x04, 0x05, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x04, 0x00, 0x04, 0x00, 0x30, 0x13, 0x04,
162        0x00, 0x04, 0x00, 0xa0, 0x0d, 0x02, 0x03, 0x00, 0x91, 0xc8, 0x02, 0x01, 0x00, 0x02, 0x01,
163        0x00, 0x30, 0x00, 0x00, 0x00,
164    ];
165
166    #[test]
167    fn packet_parse() {
168        let buf = Cursor::new(&FRAME_BYTES[..]);
169
170        let ethpkt = EtherPacket::parse(buf).unwrap();
171        assert_eq!(ethpkt.ethertype(), EtherType::IPV4);
172
173        let ippkt = Ipv4Packet::parse(ethpkt.payload()).unwrap();
174        assert_eq!(ippkt.protocol(), IpProtocol::UDP);
175        assert_eq!(ippkt.source_ip(), Ipv4Addr([192, 168, 29, 58]));
176        assert_eq!(ippkt.dest_ip(), Ipv4Addr([192, 168, 29, 160]));
177
178        let udppkt = UdpPacket::parse(ippkt.payload()).unwrap();
179        assert_eq!(udppkt.source_port(), 60376);
180        assert_eq!(udppkt.dest_port(), 161);
181        assert_eq!(udppkt.packet_len(), 74);
182        assert_eq!(udppkt.checksum(), 0xbc86);
183
184        let payload = udppkt.payload();
185        assert_eq!(
186            payload.chunk(),
187            &FRAME_BYTES[ETHER_HEADER_LEN + IPV4_HEADER_LEN + UDP_HEADER_LEN..108]
188        );
189    }
190
191    #[test]
192    fn packet_build() {
193        let mut bytes = [0xff; 108];
194        (&mut bytes[ETHER_HEADER_LEN + IPV4_HEADER_LEN + UDP_HEADER_LEN..108]).copy_from_slice(
195            &FRAME_BYTES[ETHER_HEADER_LEN + IPV4_HEADER_LEN + UDP_HEADER_LEN..108],
196        );
197
198        let mut pktbuf = CursorMut::new(&mut bytes[..]);
199        pktbuf.advance(ETHER_HEADER_LEN + IPV4_HEADER_LEN + UDP_HEADER_LEN);
200
201        let mut udppkt = UdpPacket::prepend_header(pktbuf, &UDP_HEADER_TEMPLATE);
202        udppkt.set_source_port(60376);
203        udppkt.set_dest_port(161);
204        udppkt.set_checksum(0xbc86);
205
206        let mut ippkt = Ipv4Packet::prepend_header(udppkt.release(), &IPV4_HEADER_TEMPLATE);
207        ippkt.adjust_version();
208        ippkt.set_dscp(0);
209        ippkt.set_ecn(0);
210        ippkt.set_ident(0x5c65);
211        ippkt.clear_flags();
212        ippkt.set_dont_frag(false);
213        ippkt.set_more_frags(false);
214        ippkt.set_frag_offset(0);
215        ippkt.set_time_to_live(128);
216        ippkt.set_protocol(IpProtocol::UDP);
217        ippkt.set_checksum(0x0000);
218        ippkt.set_source_ip(Ipv4Addr([192, 168, 29, 58]));
219        ippkt.set_dest_ip(Ipv4Addr([192, 168, 29, 160]));
220
221        let mut ethpkt = EtherPacket::prepend_header(ippkt.release(), &ETHER_HEADER_TEMPLATE);
222        ethpkt.set_dest_mac(MacAddr([0x00, 0x0b, 0x86, 0x64, 0x8b, 0xa0]));
223        ethpkt.set_source_mac(MacAddr([0x00, 0x50, 0x56, 0xae, 0x76, 0xf5]));
224        ethpkt.set_ethertype(EtherType::IPV4);
225
226        let v = ethpkt.release();
227        assert_eq!(v.chunk(), &FRAME_BYTES[..108]);
228    }
229
230    #[test]
231    fn cursor_parse1() {
232        let buf = Cursor::new(&FRAME_BYTES[..]);
233
234        let ethpkt = EtherPacket::parse(buf).unwrap();
235        let ipv4_pkt = Ipv4Packet::parse(ethpkt.cursor_payload()).unwrap();
236        let udp_pkt = UdpPacket::parse(ipv4_pkt.cursor_payload()).unwrap();
237
238        assert_eq!(ethpkt.ethertype(), EtherType::IPV4);
239        assert_eq!(ipv4_pkt.protocol(), IpProtocol::UDP);
240        assert_eq!(udp_pkt.checksum(), 0xbc86);
241    }
242
243    #[test]
244    fn cursor_parse2() {
245        let buf = Cursor::new(&FRAME_BYTES[..]);
246
247        let ethpkt = EtherPacket::parse(buf).unwrap();
248        let eth_hdr = ethpkt.cursor_header();
249
250        let ipv4_pkt = Ipv4Packet::parse(ethpkt.payload()).unwrap();
251        let ipv4_hdr = ipv4_pkt.cursor_header();
252
253        let udp_pkt = UdpPacket::parse(ipv4_pkt.payload()).unwrap();
254        let udp_hdr = udp_pkt.cursor_header();
255
256        assert_eq!(eth_hdr.ethertype(), EtherType::IPV4);
257        assert_eq!(ipv4_hdr.protocol(), IpProtocol::UDP);
258        assert_eq!(udp_hdr.checksum(), 0xbc86);
259    }
260
261    #[test]
262    fn fake_nat() {
263        let mut buf = [0; 110];
264        buf.copy_from_slice(&FRAME_BYTES[..]);
265
266        let pkt = CursorMut::new(&mut buf[..]);
267
268        let ethpkt = EtherPacket::parse(pkt).unwrap();
269        let (eth_hdr, payload) = ethpkt.split();
270
271        let ippkt = Ipv4Packet::parse(payload).unwrap();
272        let ip_hdr_cursor = ippkt.buf().cursor() + eth_hdr.as_bytes().len();
273
274        let (mut ip_hdr, _, payload) = ippkt.split();
275        let udp_hdr_cursor = ip_hdr_cursor + usize::from(ip_hdr.header_len());
276
277        let udppkt = UdpPacket::parse(payload).unwrap();
278        let (mut udp_hdr, _) = udppkt.split();
279
280        ip_hdr.set_source_ip(Ipv4Addr([127, 0, 0, 1]));
281        udp_hdr.set_source_port(1024);
282        assert_eq!(ip_hdr_cursor, 14);
283        assert_eq!(udp_hdr_cursor, 34);
284
285        let pkt = Cursor::new(&buf[..]);
286        let ethpkt = EtherPacket::parse(pkt).unwrap();
287
288        let ippkt = Ipv4Packet::parse(ethpkt.payload()).unwrap();
289        assert_eq!(ippkt.source_ip(), Ipv4Addr([127, 0, 0, 1]));
290
291        let udppkt = UdpPacket::parse(ippkt.payload()).unwrap();
292        assert_eq!(udppkt.source_port(), 1024);
293    }
294}