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