Skip to main content

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