smoltcp/wire/
ipv4.rs

1use byteorder::{ByteOrder, NetworkEndian};
2use core::fmt;
3
4use super::{Error, Result};
5use crate::phy::ChecksumCapabilities;
6use crate::wire::ip::{checksum, pretty_print_ip_payload};
7
8pub use super::IpProtocol as Protocol;
9
10/// Minimum MTU required of all links supporting IPv4. See [RFC 791 § 3.1].
11///
12/// [RFC 791 § 3.1]: https://tools.ietf.org/html/rfc791#section-3.1
13// RFC 791 states the following:
14//
15// > Every internet module must be able to forward a datagram of 68
16// > octets without further fragmentation... Every internet destination
17// > must be able to receive a datagram of 576 octets either in one piece
18// > or in fragments to be reassembled.
19//
20// As a result, we can assume that every host we send packets to can
21// accept a packet of the following size.
22pub const MIN_MTU: usize = 576;
23
24/// Size of IPv4 adderess in octets.
25///
26/// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc791#section-3.2
27pub const ADDR_SIZE: usize = 4;
28
29/// All multicast-capable nodes
30pub const MULTICAST_ALL_SYSTEMS: Address = Address::new(224, 0, 0, 1);
31
32/// All multicast-capable routers
33pub const MULTICAST_ALL_ROUTERS: Address = Address::new(224, 0, 0, 2);
34
35#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
37pub struct Key {
38    id: u16,
39    src_addr: Address,
40    dst_addr: Address,
41    protocol: Protocol,
42}
43
44pub use core::net::Ipv4Addr as Address;
45
46pub(crate) trait AddressExt {
47    /// Construct an IPv4 address from a sequence of octets, in big-endian.
48    ///
49    /// # Panics
50    /// The function panics if `data` is not four octets long.
51    fn from_bytes(data: &[u8]) -> Self;
52
53    /// Query whether the address is an unicast address.
54    ///
55    /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
56    fn x_is_unicast(&self) -> bool;
57
58    /// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
59    /// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
60    fn prefix_len(&self) -> Option<u8>;
61}
62
63impl AddressExt for Address {
64    fn from_bytes(data: &[u8]) -> Address {
65        let mut bytes = [0; ADDR_SIZE];
66        bytes.copy_from_slice(data);
67        Address::from_bits(u32::from_be_bytes(bytes))
68    }
69
70    /// Query whether the address is an unicast address.
71    fn x_is_unicast(&self) -> bool {
72        !(self.is_broadcast() || self.is_multicast() || self.is_unspecified())
73    }
74
75    fn prefix_len(&self) -> Option<u8> {
76        let mut ones = true;
77        let mut prefix_len = 0;
78        for byte in self.octets() {
79            let mut mask = 0x80;
80            for _ in 0..8 {
81                let one = byte & mask != 0;
82                if ones {
83                    // Expect 1s until first 0
84                    if one {
85                        prefix_len += 1;
86                    } else {
87                        ones = false;
88                    }
89                } else if one {
90                    // 1 where 0 was expected
91                    return None;
92                }
93                mask >>= 1;
94            }
95        }
96        Some(prefix_len)
97    }
98}
99
100/// A specification of an IPv4 CIDR block, containing an address and a variable-length
101/// subnet masking prefix length.
102#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
103pub struct Cidr {
104    address: Address,
105    prefix_len: u8,
106}
107
108impl Cidr {
109    /// Create an IPv4 CIDR block from the given address and prefix length.
110    ///
111    /// # Panics
112    /// This function panics if the prefix length is larger than 32.
113    pub const fn new(address: Address, prefix_len: u8) -> Cidr {
114        assert!(prefix_len <= 32);
115        Cidr {
116            address,
117            prefix_len,
118        }
119    }
120
121    /// Create an IPv4 CIDR block from the given address and network mask.
122    pub fn from_netmask(addr: Address, netmask: Address) -> Result<Cidr> {
123        let netmask = netmask.to_bits();
124        if netmask.leading_zeros() == 0 && netmask.trailing_zeros() == netmask.count_zeros() {
125            Ok(Cidr {
126                address: addr,
127                prefix_len: netmask.count_ones() as u8,
128            })
129        } else {
130            Err(Error)
131        }
132    }
133
134    /// Return the address of this IPv4 CIDR block.
135    pub const fn address(&self) -> Address {
136        self.address
137    }
138
139    /// Return the prefix length of this IPv4 CIDR block.
140    pub const fn prefix_len(&self) -> u8 {
141        self.prefix_len
142    }
143
144    /// Return the network mask of this IPv4 CIDR.
145    pub const fn netmask(&self) -> Address {
146        if self.prefix_len == 0 {
147            return Address::new(0, 0, 0, 0);
148        }
149
150        let number = 0xffffffffu32 << (32 - self.prefix_len);
151        Address::from_bits(number)
152    }
153
154    /// Return the broadcast address of this IPv4 CIDR.
155    pub fn broadcast(&self) -> Option<Address> {
156        let network = self.network();
157
158        if network.prefix_len == 31 || network.prefix_len == 32 {
159            return None;
160        }
161
162        let network_number = network.address.to_bits();
163        let number = network_number | 0xffffffffu32 >> network.prefix_len;
164        Some(Address::from_bits(number))
165    }
166
167    /// Return the network block of this IPv4 CIDR.
168    pub const fn network(&self) -> Cidr {
169        Cidr {
170            address: Address::from_bits(self.address.to_bits() & self.netmask().to_bits()),
171            prefix_len: self.prefix_len,
172        }
173    }
174
175    /// Query whether the subnetwork described by this IPv4 CIDR block contains
176    /// the given address.
177    pub fn contains_addr(&self, addr: &Address) -> bool {
178        self.address.to_bits() & self.netmask().to_bits()
179            == addr.to_bits() & self.netmask().to_bits()
180    }
181
182    /// Query whether the subnetwork described by this IPv4 CIDR block contains
183    /// the subnetwork described by the given IPv4 CIDR block.
184    pub fn contains_subnet(&self, subnet: &Cidr) -> bool {
185        self.prefix_len <= subnet.prefix_len && self.contains_addr(&subnet.address)
186    }
187}
188
189impl fmt::Display for Cidr {
190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191        write!(f, "{}/{}", self.address, self.prefix_len)
192    }
193}
194
195#[cfg(feature = "defmt")]
196impl defmt::Format for Cidr {
197    fn format(&self, f: defmt::Formatter) {
198        defmt::write!(f, "{}/{=u8}", self.address, self.prefix_len);
199    }
200}
201
202/// A read/write wrapper around an Internet Protocol version 4 packet buffer.
203#[derive(Debug, PartialEq, Eq, Clone)]
204#[cfg_attr(feature = "defmt", derive(defmt::Format))]
205pub struct Packet<T: AsRef<[u8]>> {
206    buffer: T,
207}
208
209mod field {
210    use crate::wire::field::*;
211
212    pub const VER_IHL: usize = 0;
213    pub const DSCP_ECN: usize = 1;
214    pub const LENGTH: Field = 2..4;
215    pub const IDENT: Field = 4..6;
216    pub const FLG_OFF: Field = 6..8;
217    pub const TTL: usize = 8;
218    pub const PROTOCOL: usize = 9;
219    pub const CHECKSUM: Field = 10..12;
220    pub const SRC_ADDR: Field = 12..16;
221    pub const DST_ADDR: Field = 16..20;
222}
223
224pub const HEADER_LEN: usize = field::DST_ADDR.end;
225
226impl<T: AsRef<[u8]>> Packet<T> {
227    /// Imbue a raw octet buffer with IPv4 packet structure.
228    pub const fn new_unchecked(buffer: T) -> Packet<T> {
229        Packet { buffer }
230    }
231
232    /// Shorthand for a combination of [new_unchecked] and [check_len].
233    ///
234    /// [new_unchecked]: #method.new_unchecked
235    /// [check_len]: #method.check_len
236    pub fn new_checked(buffer: T) -> Result<Packet<T>> {
237        let packet = Self::new_unchecked(buffer);
238        packet.check_len()?;
239        Ok(packet)
240    }
241
242    /// Ensure that no accessor method will panic if called.
243    /// Returns `Err(Error)` if the buffer is too short.
244    /// Returns `Err(Error)` if the header length is greater
245    /// than total length.
246    ///
247    /// The result of this check is invalidated by calling [set_header_len]
248    /// and [set_total_len].
249    ///
250    /// [set_header_len]: #method.set_header_len
251    /// [set_total_len]: #method.set_total_len
252    #[allow(clippy::if_same_then_else)]
253    pub fn check_len(&self) -> Result<()> {
254        let len = self.buffer.as_ref().len();
255        if len < field::DST_ADDR.end {
256            Err(Error)
257        } else if len < self.header_len() as usize {
258            Err(Error)
259        } else if self.header_len() as u16 > self.total_len() {
260            Err(Error)
261        } else if len < self.total_len() as usize {
262            Err(Error)
263        } else {
264            Ok(())
265        }
266    }
267
268    /// Consume the packet, returning the underlying buffer.
269    pub fn into_inner(self) -> T {
270        self.buffer
271    }
272
273    /// Return the version field.
274    #[inline]
275    pub fn version(&self) -> u8 {
276        let data = self.buffer.as_ref();
277        data[field::VER_IHL] >> 4
278    }
279
280    /// Return the header length, in octets.
281    #[inline]
282    pub fn header_len(&self) -> u8 {
283        let data = self.buffer.as_ref();
284        (data[field::VER_IHL] & 0x0f) * 4
285    }
286
287    /// Return the Differential Services Code Point field.
288    pub fn dscp(&self) -> u8 {
289        let data = self.buffer.as_ref();
290        data[field::DSCP_ECN] >> 2
291    }
292
293    /// Return the Explicit Congestion Notification field.
294    pub fn ecn(&self) -> u8 {
295        let data = self.buffer.as_ref();
296        data[field::DSCP_ECN] & 0x03
297    }
298
299    /// Return the total length field.
300    #[inline]
301    pub fn total_len(&self) -> u16 {
302        let data = self.buffer.as_ref();
303        NetworkEndian::read_u16(&data[field::LENGTH])
304    }
305
306    /// Return the fragment identification field.
307    #[inline]
308    pub fn ident(&self) -> u16 {
309        let data = self.buffer.as_ref();
310        NetworkEndian::read_u16(&data[field::IDENT])
311    }
312
313    /// Return the "don't fragment" flag.
314    #[inline]
315    pub fn dont_frag(&self) -> bool {
316        let data = self.buffer.as_ref();
317        NetworkEndian::read_u16(&data[field::FLG_OFF]) & 0x4000 != 0
318    }
319
320    /// Return the "more fragments" flag.
321    #[inline]
322    pub fn more_frags(&self) -> bool {
323        let data = self.buffer.as_ref();
324        NetworkEndian::read_u16(&data[field::FLG_OFF]) & 0x2000 != 0
325    }
326
327    /// Return the fragment offset, in octets.
328    #[inline]
329    pub fn frag_offset(&self) -> u16 {
330        let data = self.buffer.as_ref();
331        NetworkEndian::read_u16(&data[field::FLG_OFF]) << 3
332    }
333
334    /// Return the time to live field.
335    #[inline]
336    pub fn hop_limit(&self) -> u8 {
337        let data = self.buffer.as_ref();
338        data[field::TTL]
339    }
340
341    /// Return the next_header (protocol) field.
342    #[inline]
343    pub fn next_header(&self) -> Protocol {
344        let data = self.buffer.as_ref();
345        Protocol::from(data[field::PROTOCOL])
346    }
347
348    /// Return the header checksum field.
349    #[inline]
350    pub fn checksum(&self) -> u16 {
351        let data = self.buffer.as_ref();
352        NetworkEndian::read_u16(&data[field::CHECKSUM])
353    }
354
355    /// Return the source address field.
356    #[inline]
357    pub fn src_addr(&self) -> Address {
358        let data = self.buffer.as_ref();
359        Address::from_bytes(&data[field::SRC_ADDR])
360    }
361
362    /// Return the destination address field.
363    #[inline]
364    pub fn dst_addr(&self) -> Address {
365        let data = self.buffer.as_ref();
366        Address::from_bytes(&data[field::DST_ADDR])
367    }
368
369    /// Validate the header checksum.
370    ///
371    /// # Fuzzing
372    /// This function always returns `true` when fuzzing.
373    pub fn verify_checksum(&self) -> bool {
374        if cfg!(fuzzing) {
375            return true;
376        }
377
378        let data = self.buffer.as_ref();
379        checksum::data(&data[..self.header_len() as usize]) == !0
380    }
381
382    /// Returns the key for identifying the packet.
383    pub fn get_key(&self) -> Key {
384        Key {
385            id: self.ident(),
386            src_addr: self.src_addr(),
387            dst_addr: self.dst_addr(),
388            protocol: self.next_header(),
389        }
390    }
391}
392
393impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
394    /// Return a pointer to the payload.
395    #[inline]
396    pub fn payload(&self) -> &'a [u8] {
397        let range = self.header_len() as usize..self.total_len() as usize;
398        let data = self.buffer.as_ref();
399        &data[range]
400    }
401}
402
403impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
404    /// Set the version field.
405    #[inline]
406    pub fn set_version(&mut self, value: u8) {
407        let data = self.buffer.as_mut();
408        data[field::VER_IHL] = (data[field::VER_IHL] & !0xf0) | (value << 4);
409    }
410
411    /// Set the header length, in octets.
412    #[inline]
413    pub fn set_header_len(&mut self, value: u8) {
414        let data = self.buffer.as_mut();
415        data[field::VER_IHL] = (data[field::VER_IHL] & !0x0f) | ((value / 4) & 0x0f);
416    }
417
418    /// Set the Differential Services Code Point field.
419    pub fn set_dscp(&mut self, value: u8) {
420        let data = self.buffer.as_mut();
421        data[field::DSCP_ECN] = (data[field::DSCP_ECN] & !0xfc) | (value << 2)
422    }
423
424    /// Set the Explicit Congestion Notification field.
425    pub fn set_ecn(&mut self, value: u8) {
426        let data = self.buffer.as_mut();
427        data[field::DSCP_ECN] = (data[field::DSCP_ECN] & !0x03) | (value & 0x03)
428    }
429
430    /// Set the total length field.
431    #[inline]
432    pub fn set_total_len(&mut self, value: u16) {
433        let data = self.buffer.as_mut();
434        NetworkEndian::write_u16(&mut data[field::LENGTH], value)
435    }
436
437    /// Set the fragment identification field.
438    #[inline]
439    pub fn set_ident(&mut self, value: u16) {
440        let data = self.buffer.as_mut();
441        NetworkEndian::write_u16(&mut data[field::IDENT], value)
442    }
443
444    /// Clear the entire flags field.
445    #[inline]
446    pub fn clear_flags(&mut self) {
447        let data = self.buffer.as_mut();
448        let raw = NetworkEndian::read_u16(&data[field::FLG_OFF]);
449        let raw = raw & !0xe000;
450        NetworkEndian::write_u16(&mut data[field::FLG_OFF], raw);
451    }
452
453    /// Set the "don't fragment" flag.
454    #[inline]
455    pub fn set_dont_frag(&mut self, value: bool) {
456        let data = self.buffer.as_mut();
457        let raw = NetworkEndian::read_u16(&data[field::FLG_OFF]);
458        let raw = if value { raw | 0x4000 } else { raw & !0x4000 };
459        NetworkEndian::write_u16(&mut data[field::FLG_OFF], raw);
460    }
461
462    /// Set the "more fragments" flag.
463    #[inline]
464    pub fn set_more_frags(&mut self, value: bool) {
465        let data = self.buffer.as_mut();
466        let raw = NetworkEndian::read_u16(&data[field::FLG_OFF]);
467        let raw = if value { raw | 0x2000 } else { raw & !0x2000 };
468        NetworkEndian::write_u16(&mut data[field::FLG_OFF], raw);
469    }
470
471    /// Set the fragment offset, in octets.
472    #[inline]
473    pub fn set_frag_offset(&mut self, value: u16) {
474        let data = self.buffer.as_mut();
475        let raw = NetworkEndian::read_u16(&data[field::FLG_OFF]);
476        let raw = (raw & 0xe000) | (value >> 3);
477        NetworkEndian::write_u16(&mut data[field::FLG_OFF], raw);
478    }
479
480    /// Set the time to live field.
481    #[inline]
482    pub fn set_hop_limit(&mut self, value: u8) {
483        let data = self.buffer.as_mut();
484        data[field::TTL] = value
485    }
486
487    /// Set the next header (protocol) field.
488    #[inline]
489    pub fn set_next_header(&mut self, value: Protocol) {
490        let data = self.buffer.as_mut();
491        data[field::PROTOCOL] = value.into()
492    }
493
494    /// Set the header checksum field.
495    #[inline]
496    pub fn set_checksum(&mut self, value: u16) {
497        let data = self.buffer.as_mut();
498        NetworkEndian::write_u16(&mut data[field::CHECKSUM], value)
499    }
500
501    /// Set the source address field.
502    #[inline]
503    pub fn set_src_addr(&mut self, value: Address) {
504        let data = self.buffer.as_mut();
505        data[field::SRC_ADDR].copy_from_slice(&value.octets())
506    }
507
508    /// Set the destination address field.
509    #[inline]
510    pub fn set_dst_addr(&mut self, value: Address) {
511        let data = self.buffer.as_mut();
512        data[field::DST_ADDR].copy_from_slice(&value.octets())
513    }
514
515    /// Compute and fill in the header checksum.
516    pub fn fill_checksum(&mut self) {
517        self.set_checksum(0);
518        let checksum = {
519            let data = self.buffer.as_ref();
520            !checksum::data(&data[..self.header_len() as usize])
521        };
522        self.set_checksum(checksum)
523    }
524
525    /// Return a mutable pointer to the payload.
526    #[inline]
527    pub fn payload_mut(&mut self) -> &mut [u8] {
528        let range = self.header_len() as usize..self.total_len() as usize;
529        let data = self.buffer.as_mut();
530        &mut data[range]
531    }
532}
533
534impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
535    fn as_ref(&self) -> &[u8] {
536        self.buffer.as_ref()
537    }
538}
539
540/// A high-level representation of an Internet Protocol version 4 packet header.
541#[derive(Debug, PartialEq, Eq, Clone, Copy)]
542#[cfg_attr(feature = "defmt", derive(defmt::Format))]
543pub struct Repr {
544    pub src_addr: Address,
545    pub dst_addr: Address,
546    pub next_header: Protocol,
547    pub payload_len: usize,
548    pub hop_limit: u8,
549}
550
551impl Repr {
552    /// Parse an Internet Protocol version 4 packet and return a high-level representation.
553    pub fn parse<T: AsRef<[u8]> + ?Sized>(
554        packet: &Packet<&T>,
555        checksum_caps: &ChecksumCapabilities,
556    ) -> Result<Repr> {
557        packet.check_len()?;
558        // Version 4 is expected.
559        if packet.version() != 4 {
560            return Err(Error);
561        }
562        // Valid checksum is expected.
563        if checksum_caps.ipv4.rx() && !packet.verify_checksum() {
564            return Err(Error);
565        }
566
567        #[cfg(not(feature = "proto-ipv4-fragmentation"))]
568        // We do not support fragmentation.
569        if packet.more_frags() || packet.frag_offset() != 0 {
570            return Err(Error);
571        }
572
573        let payload_len = packet.total_len() as usize - packet.header_len() as usize;
574
575        // All DSCP values are acceptable, since they are of no concern to receiving endpoint.
576        // All ECN values are acceptable, since ECN requires opt-in from both endpoints.
577        // All TTL values are acceptable, since we do not perform routing.
578        Ok(Repr {
579            src_addr: packet.src_addr(),
580            dst_addr: packet.dst_addr(),
581            next_header: packet.next_header(),
582            payload_len,
583            hop_limit: packet.hop_limit(),
584        })
585    }
586
587    /// Return the length of a header that will be emitted from this high-level representation.
588    pub const fn buffer_len(&self) -> usize {
589        // We never emit any options.
590        field::DST_ADDR.end
591    }
592
593    /// Emit a high-level representation into an Internet Protocol version 4 packet.
594    pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(
595        &self,
596        packet: &mut Packet<T>,
597        checksum_caps: &ChecksumCapabilities,
598    ) {
599        packet.set_version(4);
600        packet.set_header_len(field::DST_ADDR.end as u8);
601        packet.set_dscp(0);
602        packet.set_ecn(0);
603        let total_len = packet.header_len() as u16 + self.payload_len as u16;
604        packet.set_total_len(total_len);
605        packet.set_ident(0);
606        packet.clear_flags();
607        packet.set_more_frags(false);
608        packet.set_dont_frag(true);
609        packet.set_frag_offset(0);
610        packet.set_hop_limit(self.hop_limit);
611        packet.set_next_header(self.next_header);
612        packet.set_src_addr(self.src_addr);
613        packet.set_dst_addr(self.dst_addr);
614
615        if checksum_caps.ipv4.tx() {
616            packet.fill_checksum();
617        } else {
618            // make sure we get a consistently zeroed checksum,
619            // since implementations might rely on it
620            packet.set_checksum(0);
621        }
622    }
623}
624
625impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
626    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
627        match Repr::parse(self, &ChecksumCapabilities::ignored()) {
628            Ok(repr) => write!(f, "{repr}"),
629            Err(err) => {
630                write!(f, "IPv4 ({err})")?;
631                write!(
632                    f,
633                    " src={} dst={} proto={} hop_limit={}",
634                    self.src_addr(),
635                    self.dst_addr(),
636                    self.next_header(),
637                    self.hop_limit()
638                )?;
639                if self.version() != 4 {
640                    write!(f, " ver={}", self.version())?;
641                }
642                if self.header_len() != 20 {
643                    write!(f, " hlen={}", self.header_len())?;
644                }
645                if self.dscp() != 0 {
646                    write!(f, " dscp={}", self.dscp())?;
647                }
648                if self.ecn() != 0 {
649                    write!(f, " ecn={}", self.ecn())?;
650                }
651                write!(f, " tlen={}", self.total_len())?;
652                if self.dont_frag() {
653                    write!(f, " df")?;
654                }
655                if self.more_frags() {
656                    write!(f, " mf")?;
657                }
658                if self.frag_offset() != 0 {
659                    write!(f, " off={}", self.frag_offset())?;
660                }
661                if self.more_frags() || self.frag_offset() != 0 {
662                    write!(f, " id={}", self.ident())?;
663                }
664                Ok(())
665            }
666        }
667    }
668}
669
670impl fmt::Display for Repr {
671    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
672        write!(
673            f,
674            "IPv4 src={} dst={} proto={}",
675            self.src_addr, self.dst_addr, self.next_header
676        )
677    }
678}
679
680use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
681
682impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
683    fn pretty_print(
684        buffer: &dyn AsRef<[u8]>,
685        f: &mut fmt::Formatter,
686        indent: &mut PrettyIndent,
687    ) -> fmt::Result {
688        use crate::wire::ip::checksum::format_checksum;
689
690        let checksum_caps = ChecksumCapabilities::ignored();
691
692        let (ip_repr, payload) = match Packet::new_checked(buffer) {
693            Err(err) => return write!(f, "{indent}({err})"),
694            Ok(ip_packet) => match Repr::parse(&ip_packet, &checksum_caps) {
695                Err(_) => return Ok(()),
696                Ok(ip_repr) => {
697                    if ip_packet.more_frags() || ip_packet.frag_offset() != 0 {
698                        write!(
699                            f,
700                            "{}IPv4 Fragment more_frags={} offset={}",
701                            indent,
702                            ip_packet.more_frags(),
703                            ip_packet.frag_offset()
704                        )?;
705                        return Ok(());
706                    } else {
707                        write!(f, "{indent}{ip_repr}")?;
708                        format_checksum(f, ip_packet.verify_checksum())?;
709                        (ip_repr, ip_packet.payload())
710                    }
711                }
712            },
713        };
714
715        pretty_print_ip_payload(f, indent, ip_repr, payload)
716    }
717}
718
719#[cfg(test)]
720pub(crate) mod test {
721    use super::*;
722
723    #[allow(unused)]
724    pub(crate) const MOCK_IP_ADDR_1: Address = Address::new(192, 168, 1, 1);
725    #[allow(unused)]
726    pub(crate) const MOCK_IP_ADDR_2: Address = Address::new(192, 168, 1, 2);
727    #[allow(unused)]
728    pub(crate) const MOCK_IP_ADDR_3: Address = Address::new(192, 168, 1, 3);
729    #[allow(unused)]
730    pub(crate) const MOCK_IP_ADDR_4: Address = Address::new(192, 168, 1, 4);
731    #[allow(unused)]
732    pub(crate) const MOCK_UNSPECIFIED: Address = Address::UNSPECIFIED;
733
734    static PACKET_BYTES: [u8; 30] = [
735        0x45, 0x00, 0x00, 0x1e, 0x01, 0x02, 0x62, 0x03, 0x1a, 0x01, 0xd5, 0x6e, 0x11, 0x12, 0x13,
736        0x14, 0x21, 0x22, 0x23, 0x24, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
737    ];
738
739    static PAYLOAD_BYTES: [u8; 10] = [0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff];
740
741    #[test]
742    fn test_deconstruct() {
743        let packet = Packet::new_unchecked(&PACKET_BYTES[..]);
744        assert_eq!(packet.version(), 4);
745        assert_eq!(packet.header_len(), 20);
746        assert_eq!(packet.dscp(), 0);
747        assert_eq!(packet.ecn(), 0);
748        assert_eq!(packet.total_len(), 30);
749        assert_eq!(packet.ident(), 0x102);
750        assert!(packet.more_frags());
751        assert!(packet.dont_frag());
752        assert_eq!(packet.frag_offset(), 0x203 * 8);
753        assert_eq!(packet.hop_limit(), 0x1a);
754        assert_eq!(packet.next_header(), Protocol::Icmp);
755        assert_eq!(packet.checksum(), 0xd56e);
756        assert_eq!(packet.src_addr(), Address::new(0x11, 0x12, 0x13, 0x14));
757        assert_eq!(packet.dst_addr(), Address::new(0x21, 0x22, 0x23, 0x24));
758        assert!(packet.verify_checksum());
759        assert_eq!(packet.payload(), &PAYLOAD_BYTES[..]);
760    }
761
762    #[test]
763    fn test_construct() {
764        let mut bytes = vec![0xa5; 30];
765        let mut packet = Packet::new_unchecked(&mut bytes);
766        packet.set_version(4);
767        packet.set_header_len(20);
768        packet.clear_flags();
769        packet.set_dscp(0);
770        packet.set_ecn(0);
771        packet.set_total_len(30);
772        packet.set_ident(0x102);
773        packet.set_more_frags(true);
774        packet.set_dont_frag(true);
775        packet.set_frag_offset(0x203 * 8);
776        packet.set_hop_limit(0x1a);
777        packet.set_next_header(Protocol::Icmp);
778        packet.set_src_addr(Address::new(0x11, 0x12, 0x13, 0x14));
779        packet.set_dst_addr(Address::new(0x21, 0x22, 0x23, 0x24));
780        packet.fill_checksum();
781        packet.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
782        assert_eq!(&*packet.into_inner(), &PACKET_BYTES[..]);
783    }
784
785    #[test]
786    fn test_overlong() {
787        let mut bytes = vec![];
788        bytes.extend(&PACKET_BYTES[..]);
789        bytes.push(0);
790
791        assert_eq!(
792            Packet::new_unchecked(&bytes).payload().len(),
793            PAYLOAD_BYTES.len()
794        );
795        assert_eq!(
796            Packet::new_unchecked(&mut bytes).payload_mut().len(),
797            PAYLOAD_BYTES.len()
798        );
799    }
800
801    #[test]
802    fn test_total_len_overflow() {
803        let mut bytes = vec![];
804        bytes.extend(&PACKET_BYTES[..]);
805        Packet::new_unchecked(&mut bytes).set_total_len(128);
806
807        assert_eq!(Packet::new_checked(&bytes).unwrap_err(), Error);
808    }
809
810    static REPR_PACKET_BYTES: [u8; 24] = [
811        0x45, 0x00, 0x00, 0x18, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xd2, 0x79, 0x11, 0x12, 0x13,
812        0x14, 0x21, 0x22, 0x23, 0x24, 0xaa, 0x00, 0x00, 0xff,
813    ];
814
815    static REPR_PAYLOAD_BYTES: [u8; ADDR_SIZE] = [0xaa, 0x00, 0x00, 0xff];
816
817    const fn packet_repr() -> Repr {
818        Repr {
819            src_addr: Address::new(0x11, 0x12, 0x13, 0x14),
820            dst_addr: Address::new(0x21, 0x22, 0x23, 0x24),
821            next_header: Protocol::Icmp,
822            payload_len: 4,
823            hop_limit: 64,
824        }
825    }
826
827    #[test]
828    fn test_parse() {
829        let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]);
830        let repr = Repr::parse(&packet, &ChecksumCapabilities::default()).unwrap();
831        assert_eq!(repr, packet_repr());
832    }
833
834    #[test]
835    fn test_parse_bad_version() {
836        let mut bytes = vec![0; 24];
837        bytes.copy_from_slice(&REPR_PACKET_BYTES[..]);
838        let mut packet = Packet::new_unchecked(&mut bytes);
839        packet.set_version(6);
840        packet.fill_checksum();
841        let packet = Packet::new_unchecked(&*packet.into_inner());
842        assert_eq!(
843            Repr::parse(&packet, &ChecksumCapabilities::default()),
844            Err(Error)
845        );
846    }
847
848    #[test]
849    fn test_parse_total_len_less_than_header_len() {
850        let mut bytes = vec![0; 40];
851        bytes[0] = 0x09;
852        assert_eq!(Packet::new_checked(&mut bytes), Err(Error));
853    }
854
855    #[test]
856    fn test_emit() {
857        let repr = packet_repr();
858        let mut bytes = vec![0xa5; repr.buffer_len() + REPR_PAYLOAD_BYTES.len()];
859        let mut packet = Packet::new_unchecked(&mut bytes);
860        repr.emit(&mut packet, &ChecksumCapabilities::default());
861        packet.payload_mut().copy_from_slice(&REPR_PAYLOAD_BYTES);
862        assert_eq!(&*packet.into_inner(), &REPR_PACKET_BYTES[..]);
863    }
864
865    #[test]
866    fn test_unspecified() {
867        assert!(Address::UNSPECIFIED.is_unspecified());
868        assert!(!Address::UNSPECIFIED.is_broadcast());
869        assert!(!Address::UNSPECIFIED.is_multicast());
870        assert!(!Address::UNSPECIFIED.is_link_local());
871        assert!(!Address::UNSPECIFIED.is_loopback());
872    }
873
874    #[test]
875    fn test_broadcast() {
876        assert!(!Address::BROADCAST.is_unspecified());
877        assert!(Address::BROADCAST.is_broadcast());
878        assert!(!Address::BROADCAST.is_multicast());
879        assert!(!Address::BROADCAST.is_link_local());
880        assert!(!Address::BROADCAST.is_loopback());
881    }
882
883    #[test]
884    fn test_cidr() {
885        let cidr = Cidr::new(Address::new(192, 168, 1, 10), 24);
886
887        let inside_subnet = [
888            [192, 168, 1, 0],
889            [192, 168, 1, 1],
890            [192, 168, 1, 2],
891            [192, 168, 1, 10],
892            [192, 168, 1, 127],
893            [192, 168, 1, 255],
894        ];
895
896        let outside_subnet = [
897            [192, 168, 0, 0],
898            [127, 0, 0, 1],
899            [192, 168, 2, 0],
900            [192, 168, 0, 255],
901            [0, 0, 0, 0],
902            [255, 255, 255, 255],
903        ];
904
905        let subnets = [
906            ([192, 168, 1, 0], 32),
907            ([192, 168, 1, 255], 24),
908            ([192, 168, 1, 10], 30),
909        ];
910
911        let not_subnets = [
912            ([192, 168, 1, 10], 23),
913            ([127, 0, 0, 1], 8),
914            ([192, 168, 1, 0], 0),
915            ([192, 168, 0, 255], 32),
916        ];
917
918        for addr in inside_subnet.iter().map(|a| Address::from_bytes(a)) {
919            assert!(cidr.contains_addr(&addr));
920        }
921
922        for addr in outside_subnet.iter().map(|a| Address::from_bytes(a)) {
923            assert!(!cidr.contains_addr(&addr));
924        }
925
926        for subnet in subnets
927            .iter()
928            .map(|&(a, p)| Cidr::new(Address::new(a[0], a[1], a[2], a[3]), p))
929        {
930            assert!(cidr.contains_subnet(&subnet));
931        }
932
933        for subnet in not_subnets
934            .iter()
935            .map(|&(a, p)| Cidr::new(Address::new(a[0], a[1], a[2], a[3]), p))
936        {
937            assert!(!cidr.contains_subnet(&subnet));
938        }
939
940        let cidr_without_prefix = Cidr::new(cidr.address(), 0);
941        assert!(cidr_without_prefix.contains_addr(&Address::new(127, 0, 0, 1)));
942    }
943
944    #[test]
945    fn test_cidr_from_netmask() {
946        assert!(Cidr::from_netmask(Address::new(0, 0, 0, 0), Address::new(1, 0, 2, 0)).is_err());
947        assert!(Cidr::from_netmask(Address::new(0, 0, 0, 0), Address::new(0, 0, 0, 0)).is_err());
948        assert_eq!(
949            Cidr::from_netmask(Address::new(0, 0, 0, 1), Address::new(255, 255, 255, 0)).unwrap(),
950            Cidr::new(Address::new(0, 0, 0, 1), 24)
951        );
952        assert_eq!(
953            Cidr::from_netmask(Address::new(192, 168, 0, 1), Address::new(255, 255, 0, 0)).unwrap(),
954            Cidr::new(Address::new(192, 168, 0, 1), 16)
955        );
956        assert_eq!(
957            Cidr::from_netmask(Address::new(172, 16, 0, 1), Address::new(255, 240, 0, 0)).unwrap(),
958            Cidr::new(Address::new(172, 16, 0, 1), 12)
959        );
960        assert_eq!(
961            Cidr::from_netmask(
962                Address::new(255, 255, 255, 1),
963                Address::new(255, 255, 255, 0)
964            )
965            .unwrap(),
966            Cidr::new(Address::new(255, 255, 255, 1), 24)
967        );
968        assert_eq!(
969            Cidr::from_netmask(
970                Address::new(255, 255, 255, 255),
971                Address::new(255, 255, 255, 255)
972            )
973            .unwrap(),
974            Cidr::new(Address::new(255, 255, 255, 255), 32)
975        );
976    }
977
978    #[test]
979    fn test_cidr_netmask() {
980        assert_eq!(
981            Cidr::new(Address::new(0, 0, 0, 0), 0).netmask(),
982            Address::new(0, 0, 0, 0)
983        );
984        assert_eq!(
985            Cidr::new(Address::new(0, 0, 0, 1), 24).netmask(),
986            Address::new(255, 255, 255, 0)
987        );
988        assert_eq!(
989            Cidr::new(Address::new(0, 0, 0, 0), 32).netmask(),
990            Address::new(255, 255, 255, 255)
991        );
992        assert_eq!(
993            Cidr::new(Address::new(127, 0, 0, 0), 8).netmask(),
994            Address::new(255, 0, 0, 0)
995        );
996        assert_eq!(
997            Cidr::new(Address::new(192, 168, 0, 0), 16).netmask(),
998            Address::new(255, 255, 0, 0)
999        );
1000        assert_eq!(
1001            Cidr::new(Address::new(192, 168, 1, 1), 16).netmask(),
1002            Address::new(255, 255, 0, 0)
1003        );
1004        assert_eq!(
1005            Cidr::new(Address::new(192, 168, 1, 1), 17).netmask(),
1006            Address::new(255, 255, 128, 0)
1007        );
1008        assert_eq!(
1009            Cidr::new(Address::new(172, 16, 0, 0), 12).netmask(),
1010            Address::new(255, 240, 0, 0)
1011        );
1012        assert_eq!(
1013            Cidr::new(Address::new(255, 255, 255, 1), 24).netmask(),
1014            Address::new(255, 255, 255, 0)
1015        );
1016        assert_eq!(
1017            Cidr::new(Address::new(255, 255, 255, 255), 32).netmask(),
1018            Address::new(255, 255, 255, 255)
1019        );
1020    }
1021
1022    #[test]
1023    fn test_cidr_broadcast() {
1024        assert_eq!(
1025            Cidr::new(Address::new(0, 0, 0, 0), 0).broadcast().unwrap(),
1026            Address::new(255, 255, 255, 255)
1027        );
1028        assert_eq!(
1029            Cidr::new(Address::new(0, 0, 0, 1), 24).broadcast().unwrap(),
1030            Address::new(0, 0, 0, 255)
1031        );
1032        assert_eq!(Cidr::new(Address::new(0, 0, 0, 0), 32).broadcast(), None);
1033        assert_eq!(
1034            Cidr::new(Address::new(127, 0, 0, 0), 8)
1035                .broadcast()
1036                .unwrap(),
1037            Address::new(127, 255, 255, 255)
1038        );
1039        assert_eq!(
1040            Cidr::new(Address::new(192, 168, 0, 0), 16)
1041                .broadcast()
1042                .unwrap(),
1043            Address::new(192, 168, 255, 255)
1044        );
1045        assert_eq!(
1046            Cidr::new(Address::new(192, 168, 1, 1), 16)
1047                .broadcast()
1048                .unwrap(),
1049            Address::new(192, 168, 255, 255)
1050        );
1051        assert_eq!(
1052            Cidr::new(Address::new(192, 168, 1, 1), 17)
1053                .broadcast()
1054                .unwrap(),
1055            Address::new(192, 168, 127, 255)
1056        );
1057        assert_eq!(
1058            Cidr::new(Address::new(172, 16, 0, 1), 12)
1059                .broadcast()
1060                .unwrap(),
1061            Address::new(172, 31, 255, 255)
1062        );
1063        assert_eq!(
1064            Cidr::new(Address::new(255, 255, 255, 1), 24)
1065                .broadcast()
1066                .unwrap(),
1067            Address::new(255, 255, 255, 255)
1068        );
1069        assert_eq!(
1070            Cidr::new(Address::new(255, 255, 255, 254), 31).broadcast(),
1071            None
1072        );
1073        assert_eq!(
1074            Cidr::new(Address::new(255, 255, 255, 255), 32).broadcast(),
1075            None
1076        );
1077    }
1078
1079    #[test]
1080    fn test_cidr_network() {
1081        assert_eq!(
1082            Cidr::new(Address::new(0, 0, 0, 0), 0).network(),
1083            Cidr::new(Address::new(0, 0, 0, 0), 0)
1084        );
1085        assert_eq!(
1086            Cidr::new(Address::new(0, 0, 0, 1), 24).network(),
1087            Cidr::new(Address::new(0, 0, 0, 0), 24)
1088        );
1089        assert_eq!(
1090            Cidr::new(Address::new(0, 0, 0, 0), 32).network(),
1091            Cidr::new(Address::new(0, 0, 0, 0), 32)
1092        );
1093        assert_eq!(
1094            Cidr::new(Address::new(127, 0, 0, 0), 8).network(),
1095            Cidr::new(Address::new(127, 0, 0, 0), 8)
1096        );
1097        assert_eq!(
1098            Cidr::new(Address::new(192, 168, 0, 0), 16).network(),
1099            Cidr::new(Address::new(192, 168, 0, 0), 16)
1100        );
1101        assert_eq!(
1102            Cidr::new(Address::new(192, 168, 1, 1), 16).network(),
1103            Cidr::new(Address::new(192, 168, 0, 0), 16)
1104        );
1105        assert_eq!(
1106            Cidr::new(Address::new(192, 168, 1, 1), 17).network(),
1107            Cidr::new(Address::new(192, 168, 0, 0), 17)
1108        );
1109        assert_eq!(
1110            Cidr::new(Address::new(172, 16, 0, 1), 12).network(),
1111            Cidr::new(Address::new(172, 16, 0, 0), 12)
1112        );
1113        assert_eq!(
1114            Cidr::new(Address::new(255, 255, 255, 1), 24).network(),
1115            Cidr::new(Address::new(255, 255, 255, 0), 24)
1116        );
1117        assert_eq!(
1118            Cidr::new(Address::new(255, 255, 255, 255), 32).network(),
1119            Cidr::new(Address::new(255, 255, 255, 255), 32)
1120        );
1121    }
1122}