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        let total_len = packet.header_len() as u16 + self.payload_len as u16;
594        packet.set_total_len(total_len);
595        packet.set_ident(0);
596        packet.clear_flags();
597        packet.set_more_frags(false);
598        packet.set_dont_frag(true);
599        packet.set_frag_offset(0);
600        packet.set_hop_limit(self.hop_limit);
601        packet.set_next_header(self.next_header);
602        packet.set_src_addr(self.src_addr);
603        packet.set_dst_addr(self.dst_addr);
604
605        if checksum_caps.ipv4.tx() {
606            packet.fill_checksum();
607        } else {
608            // make sure we get a consistently zeroed checksum,
609            // since implementations might rely on it
610            packet.set_checksum(0);
611        }
612    }
613}
614
615impl<T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&T> {
616    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
617        match Repr::parse(self, &ChecksumCapabilities::ignored()) {
618            Ok(repr) => write!(f, "{repr}"),
619            Err(err) => {
620                write!(f, "IPv4 ({err})")?;
621                write!(
622                    f,
623                    " src={} dst={} proto={} hop_limit={}",
624                    self.src_addr(),
625                    self.dst_addr(),
626                    self.next_header(),
627                    self.hop_limit()
628                )?;
629                if self.version() != 4 {
630                    write!(f, " ver={}", self.version())?;
631                }
632                if self.header_len() != 20 {
633                    write!(f, " hlen={}", self.header_len())?;
634                }
635                if self.dscp() != 0 {
636                    write!(f, " dscp={}", self.dscp())?;
637                }
638                if self.ecn() != 0 {
639                    write!(f, " ecn={}", self.ecn())?;
640                }
641                write!(f, " tlen={}", self.total_len())?;
642                if self.dont_frag() {
643                    write!(f, " df")?;
644                }
645                if self.more_frags() {
646                    write!(f, " mf")?;
647                }
648                if self.frag_offset() != 0 {
649                    write!(f, " off={}", self.frag_offset())?;
650                }
651                if self.more_frags() || self.frag_offset() != 0 {
652                    write!(f, " id={}", self.ident())?;
653                }
654                Ok(())
655            }
656        }
657    }
658}
659
660impl fmt::Display for Repr {
661    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
662        write!(
663            f,
664            "IPv4 src={} dst={} proto={}",
665            self.src_addr, self.dst_addr, self.next_header
666        )
667    }
668}
669
670use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
671
672impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
673    fn pretty_print(
674        buffer: &dyn AsRef<[u8]>,
675        f: &mut fmt::Formatter,
676        indent: &mut PrettyIndent,
677    ) -> fmt::Result {
678        use crate::wire::ip::checksum::format_checksum;
679
680        let checksum_caps = ChecksumCapabilities::ignored();
681
682        let (ip_repr, payload) = match Packet::new_checked(buffer) {
683            Err(err) => return write!(f, "{indent}({err})"),
684            Ok(ip_packet) => match Repr::parse(&ip_packet, &checksum_caps) {
685                Err(_) => return Ok(()),
686                Ok(ip_repr) => {
687                    if ip_packet.more_frags() || ip_packet.frag_offset() != 0 {
688                        write!(
689                            f,
690                            "{}IPv4 Fragment more_frags={} offset={}",
691                            indent,
692                            ip_packet.more_frags(),
693                            ip_packet.frag_offset()
694                        )?;
695                        return Ok(());
696                    } else {
697                        write!(f, "{indent}{ip_repr}")?;
698                        format_checksum(f, ip_packet.verify_checksum(), false)?;
699                        (ip_repr, ip_packet.payload())
700                    }
701                }
702            },
703        };
704
705        pretty_print_ip_payload(f, indent, ip_repr, payload)
706    }
707}
708
709#[cfg(test)]
710pub(crate) mod test {
711    use super::*;
712
713    #[allow(unused)]
714    pub(crate) const MOCK_IP_ADDR_1: Address = Address::new(192, 168, 1, 1);
715    #[allow(unused)]
716    pub(crate) const MOCK_IP_ADDR_2: Address = Address::new(192, 168, 1, 2);
717    #[allow(unused)]
718    pub(crate) const MOCK_IP_ADDR_3: Address = Address::new(192, 168, 1, 3);
719    #[allow(unused)]
720    pub(crate) const MOCK_IP_ADDR_4: Address = Address::new(192, 168, 1, 4);
721    #[allow(unused)]
722    pub(crate) const MOCK_UNSPECIFIED: Address = Address::UNSPECIFIED;
723
724    static PACKET_BYTES: [u8; 30] = [
725        0x45, 0x00, 0x00, 0x1e, 0x01, 0x02, 0x62, 0x03, 0x1a, 0x01, 0xd5, 0x6e, 0x11, 0x12, 0x13,
726        0x14, 0x21, 0x22, 0x23, 0x24, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
727    ];
728
729    static PAYLOAD_BYTES: [u8; 10] = [0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff];
730
731    #[test]
732    fn test_deconstruct() {
733        let packet = Packet::new_unchecked(&PACKET_BYTES[..]);
734        assert_eq!(packet.version(), 4);
735        assert_eq!(packet.header_len(), 20);
736        assert_eq!(packet.dscp(), 0);
737        assert_eq!(packet.ecn(), 0);
738        assert_eq!(packet.total_len(), 30);
739        assert_eq!(packet.ident(), 0x102);
740        assert!(packet.more_frags());
741        assert!(packet.dont_frag());
742        assert_eq!(packet.frag_offset(), 0x203 * 8);
743        assert_eq!(packet.hop_limit(), 0x1a);
744        assert_eq!(packet.next_header(), Protocol::Icmp);
745        assert_eq!(packet.checksum(), 0xd56e);
746        assert_eq!(packet.src_addr(), Address::new(0x11, 0x12, 0x13, 0x14));
747        assert_eq!(packet.dst_addr(), Address::new(0x21, 0x22, 0x23, 0x24));
748        assert!(packet.verify_checksum());
749        assert_eq!(packet.payload(), &PAYLOAD_BYTES[..]);
750    }
751
752    #[test]
753    fn test_construct() {
754        let mut bytes = vec![0xa5; 30];
755        let mut packet = Packet::new_unchecked(&mut bytes);
756        packet.set_version(4);
757        packet.set_header_len(20);
758        packet.clear_flags();
759        packet.set_dscp(0);
760        packet.set_ecn(0);
761        packet.set_total_len(30);
762        packet.set_ident(0x102);
763        packet.set_more_frags(true);
764        packet.set_dont_frag(true);
765        packet.set_frag_offset(0x203 * 8);
766        packet.set_hop_limit(0x1a);
767        packet.set_next_header(Protocol::Icmp);
768        packet.set_src_addr(Address::new(0x11, 0x12, 0x13, 0x14));
769        packet.set_dst_addr(Address::new(0x21, 0x22, 0x23, 0x24));
770        packet.fill_checksum();
771        packet.payload_mut().copy_from_slice(&PAYLOAD_BYTES[..]);
772        assert_eq!(&*packet.into_inner(), &PACKET_BYTES[..]);
773    }
774
775    #[test]
776    fn test_overlong() {
777        let mut bytes = vec![];
778        bytes.extend(&PACKET_BYTES[..]);
779        bytes.push(0);
780
781        assert_eq!(
782            Packet::new_unchecked(&bytes).payload().len(),
783            PAYLOAD_BYTES.len()
784        );
785        assert_eq!(
786            Packet::new_unchecked(&mut bytes).payload_mut().len(),
787            PAYLOAD_BYTES.len()
788        );
789    }
790
791    #[test]
792    fn test_total_len_overflow() {
793        let mut bytes = vec![];
794        bytes.extend(&PACKET_BYTES[..]);
795        Packet::new_unchecked(&mut bytes).set_total_len(128);
796
797        assert_eq!(Packet::new_checked(&bytes).unwrap_err(), Error);
798    }
799
800    static REPR_PACKET_BYTES: [u8; 24] = [
801        0x45, 0x00, 0x00, 0x18, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0xd2, 0x79, 0x11, 0x12, 0x13,
802        0x14, 0x21, 0x22, 0x23, 0x24, 0xaa, 0x00, 0x00, 0xff,
803    ];
804
805    static REPR_PAYLOAD_BYTES: [u8; 4] = [0xaa, 0x00, 0x00, 0xff];
806
807    const fn packet_repr() -> Repr {
808        Repr {
809            src_addr: Address::new(0x11, 0x12, 0x13, 0x14),
810            dst_addr: Address::new(0x21, 0x22, 0x23, 0x24),
811            next_header: Protocol::Icmp,
812            payload_len: 4,
813            hop_limit: 64,
814        }
815    }
816
817    #[test]
818    fn test_parse() {
819        let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]);
820        let repr = Repr::parse(&packet, &ChecksumCapabilities::default()).unwrap();
821        assert_eq!(repr, packet_repr());
822    }
823
824    #[test]
825    fn test_parse_bad_version() {
826        let mut bytes = vec![0; 24];
827        bytes.copy_from_slice(&REPR_PACKET_BYTES[..]);
828        let mut packet = Packet::new_unchecked(&mut bytes);
829        packet.set_version(6);
830        packet.fill_checksum();
831        let packet = Packet::new_unchecked(&*packet.into_inner());
832        assert_eq!(
833            Repr::parse(&packet, &ChecksumCapabilities::default()),
834            Err(Error)
835        );
836    }
837
838    #[test]
839    fn test_parse_total_len_less_than_header_len() {
840        let mut bytes = vec![0; 40];
841        bytes[0] = 0x09;
842        assert_eq!(Packet::new_checked(&mut bytes), Err(Error));
843    }
844
845    #[test]
846    fn test_parse_small_ihl() {
847        let mut bytes = vec![0; 24];
848        bytes.copy_from_slice(&REPR_PACKET_BYTES[..]);
849        let mut packet = Packet::new_unchecked(&mut bytes);
850        packet.set_header_len(16);
851
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_octets(*a)) {
919            assert!(cidr.contains_addr(&addr));
920        }
921
922        for addr in outside_subnet.iter().map(|a| Address::from_octets(*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}