smoltcp/wire/
ipv4.rs

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