1#[macro_use]
17mod macros;
18mod common;
19mod icmpv4;
20mod icmpv6;
21pub mod mld;
22pub mod ndp;
23
24#[cfg(test)]
25mod testdata;
26
27pub use self::common::*;
28pub use self::icmpv4::*;
29pub use self::icmpv6::*;
30
31use core::fmt::Debug;
32use core::marker::PhantomData;
33use core::{cmp, mem};
34
35use byteorder::{ByteOrder, NetworkEndian};
36use derivative::Derivative;
37use internet_checksum::Checksum;
38use net_types::ip::{GenericOverIp, Ip, IpAddress, IpVersion, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
39use packet::records::options::{Options, OptionsImpl};
40use packet::{
41 AsFragmentedByteSlice, BufferView, FragmentedByteSlice, FragmentedBytesMut, FromRaw,
42 PacketBuilder, PacketConstraints, ParsablePacket, ParseMetadata, PartialPacketBuilder,
43 SerializeTarget,
44};
45use zerocopy::byteorder::network_endian::U16;
46use zerocopy::{
47 FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, SplitByteSliceMut, Unaligned,
48};
49
50use crate::error::{NotZeroError, ParseError, ParseResult};
51use crate::ip::{IpProtoExt, Ipv4Proto, Ipv6Proto};
52use crate::ipv4::{self, Ipv4PacketRaw};
53use crate::ipv6::Ipv6PacketRaw;
54
55#[derive(Copy, Clone, Default, Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
56#[repr(C)]
57struct HeaderPrefix {
58 msg_type: u8,
59 code: u8,
60 checksum: [u8; 2],
61 }
66
67impl HeaderPrefix {
68 fn set_msg_type<T: Into<u8>>(&mut self, msg_type: T) {
69 self.msg_type = msg_type.into();
70 }
71}
72
73pub fn peek_message_type<MessageType: TryFrom<u8>>(bytes: &[u8]) -> ParseResult<MessageType> {
86 let (hdr_pfx, _) = Ref::<_, HeaderPrefix>::from_prefix(bytes).map_err(Into::into).map_err(
87 |_: zerocopy::SizeError<_, _>| debug_err!(ParseError::Format, "too few bytes for header"),
88 )?;
89 MessageType::try_from(hdr_pfx.msg_type).map_err(|_| {
90 debug_err!(ParseError::NotSupported, "unrecognized message type: {:x}", hdr_pfx.msg_type,)
91 })
92}
93
94pub trait IcmpIpExt: IpProtoExt {
96 type IcmpPacketTypeRaw<B: SplitByteSliceMut>: IcmpPacketTypeRaw<B, Self>
98 + GenericOverIp<Self, Type = Self::IcmpPacketTypeRaw<B>>
99 + GenericOverIp<Ipv4, Type = Icmpv4PacketRaw<B>>
100 + GenericOverIp<Ipv6, Type = Icmpv6PacketRaw<B>>;
101
102 type IcmpMessageType: IcmpMessageType
107 + GenericOverIp<Self, Type = Self::IcmpMessageType>
108 + GenericOverIp<Ipv4, Type = Icmpv4MessageType>
109 + GenericOverIp<Ipv6, Type = Icmpv6MessageType>;
110
111 type ParameterProblemCode: PartialEq + Send + Sync + Debug;
116
117 type ParameterProblemPointer: PartialEq + Send + Sync + Debug;
121
122 type HeaderLen: PartialEq + Send + Sync + Debug;
126
127 const ICMP_IP_PROTO: <Self as IpProtoExt>::Proto;
133
134 fn header_len(bytes: &[u8]) -> usize;
142
143 const ECHO_REPLY: Self::IcmpMessageType;
145 const ECHO_REQUEST: Self::IcmpMessageType;
147}
148
149impl IcmpIpExt for Ipv4 {
150 type IcmpPacketTypeRaw<B: SplitByteSliceMut> = Icmpv4PacketRaw<B>;
151 type IcmpMessageType = Icmpv4MessageType;
152 type ParameterProblemCode = Icmpv4ParameterProblemCode;
153 type ParameterProblemPointer = u8;
154 type HeaderLen = usize;
155
156 const ICMP_IP_PROTO: Ipv4Proto = Ipv4Proto::Icmp;
157
158 fn header_len(bytes: &[u8]) -> usize {
159 if bytes.len() < ipv4::IPV4_MIN_HDR_LEN {
160 return bytes.len();
161 }
162 let (header_prefix, _) = Ref::<_, ipv4::HeaderPrefix>::from_prefix(bytes).unwrap();
163 cmp::min(header_prefix.ihl() as usize * 4, bytes.len())
164 }
165
166 const ECHO_REPLY: Icmpv4MessageType = Icmpv4MessageType::EchoReply;
167 const ECHO_REQUEST: Icmpv4MessageType = Icmpv4MessageType::EchoRequest;
168}
169
170impl IcmpIpExt for Ipv6 {
171 type IcmpPacketTypeRaw<B: SplitByteSliceMut> = Icmpv6PacketRaw<B>;
172 type IcmpMessageType = Icmpv6MessageType;
173 type ParameterProblemCode = Icmpv6ParameterProblemCode;
174 type ParameterProblemPointer = u32;
175 type HeaderLen = ();
176
177 const ICMP_IP_PROTO: Ipv6Proto = Ipv6Proto::Icmpv6;
178
179 fn header_len(_bytes: &[u8]) -> usize {
182 unimplemented!()
187 }
188
189 const ECHO_REPLY: Icmpv6MessageType = Icmpv6MessageType::EchoReply;
190 const ECHO_REQUEST: Icmpv6MessageType = Icmpv6MessageType::EchoRequest;
191}
192
193pub trait IcmpPacketTypeRaw<B: SplitByteSliceMut, I: Ip>:
197 Sized + ParsablePacket<B, (), Error = ParseError>
198{
199 fn update_checksum_pseudo_header_address(&mut self, old: I::Addr, new: I::Addr);
201
202 fn update_checksum_header_field<F: IntoBytes + Immutable>(&mut self, old: F, new: F);
207
208 fn update_checksum_header_field_u16(&mut self, old: u16, new: u16) {
211 self.update_checksum_header_field(U16::new(old), U16::new(new))
212 }
213
214 fn try_write_checksum(&mut self, src_addr: I::Addr, dst_addr: I::Addr) -> bool;
219
220 fn message_body_mut(&mut self) -> &mut B;
222}
223
224impl<B: SplitByteSliceMut> IcmpPacketTypeRaw<B, Ipv4> for Icmpv4PacketRaw<B> {
225 fn update_checksum_pseudo_header_address(&mut self, old: Ipv4Addr, new: Ipv4Addr) {
226 crate::icmpv4_dispatch!(self: raw, p => p.update_checksum_pseudo_header_address(old, new))
227 }
228
229 fn update_checksum_header_field<F: IntoBytes + Immutable>(&mut self, old: F, new: F) {
230 crate::icmpv4_dispatch!(self: raw, p => p.update_checksum_header_field(old, new))
231 }
232
233 fn try_write_checksum(&mut self, src_addr: Ipv4Addr, dst_addr: Ipv4Addr) -> bool {
234 crate::icmpv4_dispatch!(self: raw, p => p.try_write_checksum(src_addr, dst_addr))
235 }
236
237 fn message_body_mut(&mut self) -> &mut B {
238 crate::icmpv4_dispatch!(self: raw, p => p.message_body_mut())
239 }
240}
241
242impl<I: IcmpIpExt, B: SplitByteSliceMut> GenericOverIp<I> for Icmpv4PacketRaw<B> {
243 type Type = I::IcmpPacketTypeRaw<B>;
244}
245
246impl<B: SplitByteSliceMut> IcmpPacketTypeRaw<B, Ipv6> for Icmpv6PacketRaw<B> {
247 fn update_checksum_pseudo_header_address(&mut self, old: Ipv6Addr, new: Ipv6Addr) {
248 crate::icmpv6_dispatch!(self: raw, p => p.update_checksum_pseudo_header_address(old, new))
249 }
250
251 fn update_checksum_header_field<F: IntoBytes + Immutable>(&mut self, old: F, new: F) {
252 crate::icmpv6_dispatch!(self: raw, p => p.update_checksum_header_field(old, new))
253 }
254
255 fn try_write_checksum(&mut self, src_addr: Ipv6Addr, dst_addr: Ipv6Addr) -> bool {
256 crate::icmpv6_dispatch!(self: raw, p => p.try_write_checksum(src_addr, dst_addr))
257 }
258
259 fn message_body_mut(&mut self) -> &mut B {
260 crate::icmpv6_dispatch!(self: raw, p => p.message_body_mut())
261 }
262}
263
264impl<I: IcmpIpExt, B: SplitByteSliceMut, M: IcmpMessage<I>> IcmpPacketTypeRaw<B, I>
265 for IcmpPacketRaw<I, B, M>
266{
267 fn update_checksum_pseudo_header_address(&mut self, old: I::Addr, new: I::Addr) {
268 match I::VERSION {
269 IpVersion::V4 => {
270 }
272 IpVersion::V6 => {
273 let checksum = &mut self.header.prefix.checksum;
274 *checksum = internet_checksum::update(*checksum, old.bytes(), new.bytes());
275 }
276 }
277 }
278
279 fn update_checksum_header_field<F: IntoBytes + Immutable>(&mut self, old: F, new: F) {
280 let checksum = &mut self.header.prefix.checksum;
281 *checksum = internet_checksum::update(*checksum, old.as_bytes(), new.as_bytes());
282 }
283
284 fn try_write_checksum(&mut self, src_addr: I::Addr, dst_addr: I::Addr) -> bool {
285 self.try_write_checksum(src_addr, dst_addr)
286 }
287
288 fn message_body_mut(&mut self) -> &mut B {
289 self.message_body_mut()
290 }
291}
292
293impl<I: IcmpIpExt, B: SplitByteSliceMut> GenericOverIp<I> for Icmpv6PacketRaw<B> {
294 type Type = I::IcmpPacketTypeRaw<B>;
295}
296
297#[derive(Derivative, Debug, Clone, Copy, PartialEq, Eq)]
299#[derivative(Default(bound = ""))]
300pub struct EmptyMessage<B>(core::marker::PhantomData<B>);
301
302pub trait MessageBody: Sized {
309 type B: SplitByteSlice;
311
312 fn parse(bytes: Self::B) -> ParseResult<Self>;
314
315 fn len(&self) -> usize;
317
318 fn is_empty(&self) -> bool {
322 self.len() == 0
323 }
324
325 fn bytes(&self) -> (&[u8], Option<&[u8]>);
338}
339
340impl<B: SplitByteSlice> MessageBody for EmptyMessage<B> {
341 type B = B;
342
343 fn parse(bytes: B) -> ParseResult<Self> {
344 if !bytes.is_empty() {
345 return debug_err!(Err(ParseError::Format), "unexpected message body");
346 }
347
348 Ok(EmptyMessage::default())
349 }
350
351 fn len(&self) -> usize {
352 0
353 }
354
355 fn bytes(&self) -> (&[u8], Option<&[u8]>) {
356 (&[], None)
357 }
358}
359
360#[derive(Debug)]
362pub struct OriginalPacket<B>(B);
363
364impl<B: SplitByteSlice> OriginalPacket<B> {
365 pub fn body<I: IcmpIpExt>(&self) -> &[u8] {
367 let header_len = I::header_len(&self.0);
369 debug_assert!(header_len <= self.0.len());
370 debug_assert!(I::VERSION.is_v6() || self.0.len() - header_len == 8);
371 &self.0[header_len..]
372 }
373}
374
375impl<B: SplitByteSlice> MessageBody for OriginalPacket<B> {
376 type B = B;
377
378 fn parse(bytes: B) -> ParseResult<OriginalPacket<B>> {
379 Ok(OriginalPacket(bytes))
380 }
381
382 fn len(&self) -> usize {
383 self.0.len()
384 }
385
386 fn bytes(&self) -> (&[u8], Option<&[u8]>) {
387 (&self.0, None)
388 }
389}
390
391impl<B: SplitByteSlice, O: OptionsImpl> MessageBody for Options<B, O> {
392 type B = B;
393 fn parse(bytes: B) -> ParseResult<Options<B, O>> {
394 Self::parse(bytes).map_err(|_e| debug_err!(ParseError::Format, "unable to parse options"))
395 }
396
397 fn len(&self) -> usize {
398 self.bytes().len()
399 }
400
401 fn bytes(&self) -> (&[u8], Option<&[u8]>) {
402 (self.bytes(), None)
403 }
404}
405
406pub trait IcmpMessage<I: IcmpIpExt>:
408 Sized + Copy + FromBytes + IntoBytes + KnownLayout + Immutable + Unaligned
409{
410 const EXPECTS_BODY: bool = true;
412
413 type Code: Into<u8> + Copy + Debug;
420
421 type Body<B: SplitByteSlice>: MessageBody<B = B>;
423
424 const TYPE: I::IcmpMessageType;
429
430 fn code_from_u8(code: u8) -> Option<Self::Code>;
436}
437
438pub trait IcmpMessageType: TryFrom<u8> + Into<u8> + Copy + Debug {
443 fn is_err(self) -> bool;
450}
451
452#[derive(Copy, Clone, Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
453#[repr(C)]
454struct Header<M> {
455 prefix: HeaderPrefix,
456 message: M,
457}
458
459#[derive(Debug)]
471pub struct IcmpPacketRaw<I: IcmpIpExt, B: SplitByteSlice, M: IcmpMessage<I>> {
472 header: Ref<B, Header<M>>,
473 message_body: B,
474 _marker: PhantomData<I>,
475}
476
477impl<I: IcmpIpExt, B: SplitByteSlice, M: IcmpMessage<I>> IcmpPacketRaw<I, B, M> {
478 pub fn message(&self) -> &M {
480 &self.header.message
481 }
482
483 pub fn message_body(&self) -> &B {
485 &self.message_body
486 }
487}
488
489impl<I: IcmpIpExt, B: SplitByteSliceMut, M: IcmpMessage<I>> IcmpPacketRaw<I, B, M> {
490 pub fn message_mut(&mut self) -> &mut M {
492 &mut self.header.message
493 }
494
495 pub fn message_body_mut(&mut self) -> &mut B {
497 &mut self.message_body
498 }
499
500 pub(crate) fn try_write_checksum(&mut self, src_ip: I::Addr, dst_ip: I::Addr) -> bool {
505 let original_checksum = self.header.prefix.checksum;
507 self.header.prefix.checksum = [0, 0];
508
509 if let Some(checksum) = IcmpPacket::<I, B, M>::compute_checksum(
510 &self.header,
511 &self.message_body,
512 src_ip,
513 dst_ip,
514 ) {
515 self.header.prefix.checksum = checksum;
516 true
517 } else {
518 self.header.prefix.checksum = original_checksum;
519 false
520 }
521 }
522}
523
524#[derive(Debug)]
529pub struct IcmpPacket<I: IcmpIpExt, B: SplitByteSlice, M: IcmpMessage<I>> {
530 header: Ref<B, Header<M>>,
531 message_body: M::Body<B>,
532 _marker: PhantomData<I>,
533}
534
535pub struct IcmpParseArgs<A: IpAddress> {
537 src_ip: A,
538 dst_ip: A,
539}
540
541impl<A: IpAddress> IcmpParseArgs<A> {
542 pub fn new<S: Into<A>, D: Into<A>>(src_ip: S, dst_ip: D) -> IcmpParseArgs<A> {
544 IcmpParseArgs { src_ip: src_ip.into(), dst_ip: dst_ip.into() }
545 }
546}
547
548impl<B: SplitByteSlice, I: IcmpIpExt, M: IcmpMessage<I>> ParsablePacket<B, ()>
549 for IcmpPacketRaw<I, B, M>
550{
551 type Error = ParseError;
552
553 fn parse_metadata(&self) -> ParseMetadata {
554 ParseMetadata::from_packet(Ref::bytes(&self.header).len(), self.message_body.len(), 0)
555 }
556
557 fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> ParseResult<Self> {
558 let header = buffer.take_obj_front::<Header<M>>().ok_or(ParseError::Format)?;
559 let message_body = buffer.into_rest();
560 if header.prefix.msg_type != M::TYPE.into() {
561 return Err(ParseError::NotExpected);
562 }
563 Ok(IcmpPacketRaw { header, message_body, _marker: PhantomData })
564 }
565}
566
567impl<B: SplitByteSlice, I: IcmpIpExt, M: IcmpMessage<I>>
568 FromRaw<IcmpPacketRaw<I, B, M>, IcmpParseArgs<I::Addr>> for IcmpPacket<I, B, M>
569{
570 type Error = ParseError;
571
572 fn try_from_raw_with(
573 raw: IcmpPacketRaw<I, B, M>,
574 args: IcmpParseArgs<I::Addr>,
575 ) -> ParseResult<Self> {
576 let IcmpPacketRaw { header, message_body, _marker } = raw;
577 if !M::EXPECTS_BODY && !message_body.is_empty() {
578 return Err(ParseError::Format);
579 }
580 let _: M::Code = M::code_from_u8(header.prefix.code).ok_or(ParseError::Format)?;
581 let checksum = Self::compute_checksum(&header, &message_body, args.src_ip, args.dst_ip)
582 .ok_or(ParseError::Format)?;
583 if checksum != [0, 0] {
584 return Err(ParseError::Checksum);
585 }
586 let message_body = M::Body::parse(message_body)?;
587 Ok(IcmpPacket { header, message_body, _marker })
588 }
589}
590
591impl<B: SplitByteSlice, I: IcmpIpExt, M: IcmpMessage<I>> ParsablePacket<B, IcmpParseArgs<I::Addr>>
592 for IcmpPacket<I, B, M>
593{
594 type Error = ParseError;
595
596 fn parse_metadata(&self) -> ParseMetadata {
597 ParseMetadata::from_packet(Ref::bytes(&self.header).len(), self.message_body.len(), 0)
598 }
599
600 fn parse<BV: BufferView<B>>(buffer: BV, args: IcmpParseArgs<I::Addr>) -> ParseResult<Self> {
601 IcmpPacketRaw::parse(buffer, ()).and_then(|p| IcmpPacket::try_from_raw_with(p, args))
602 }
603}
604
605impl<I: IcmpIpExt, B: SplitByteSlice, M: IcmpMessage<I>> IcmpPacket<I, B, M> {
606 pub fn message(&self) -> &M {
608 &self.header.message
609 }
610
611 pub fn body(&self) -> &M::Body<B> {
613 &self.message_body
614 }
615
616 pub fn code(&self) -> M::Code {
621 M::code_from_u8(self.header.prefix.code).unwrap()
623 }
624
625 pub fn builder(&self, src_ip: I::Addr, dst_ip: I::Addr) -> IcmpPacketBuilder<I, M> {
627 IcmpPacketBuilder { src_ip, dst_ip, code: self.code(), msg: *self.message() }
628 }
629}
630
631fn compute_checksum_fragmented<I: IcmpIpExt, BB: packet::Fragment, M: IcmpMessage<I>>(
632 header: &Header<M>,
633 message_body: &FragmentedByteSlice<'_, BB>,
634 src_ip: I::Addr,
635 dst_ip: I::Addr,
636) -> Option<[u8; 2]> {
637 let mut c = Checksum::new();
638 if I::VERSION.is_v6() {
639 c.add_bytes(src_ip.bytes());
640 c.add_bytes(dst_ip.bytes());
641 let icmpv6_len = mem::size_of::<Header<M>>() + message_body.len();
642 let mut len_bytes = [0; 4];
643 NetworkEndian::write_u32(&mut len_bytes, icmpv6_len.try_into().ok()?);
644 c.add_bytes(&len_bytes[..]);
645 c.add_bytes(&[0, 0, 0]);
646 c.add_bytes(&[Ipv6Proto::Icmpv6.into()]);
647 }
648 c.add_bytes(&[header.prefix.msg_type, header.prefix.code]);
649 c.add_bytes(&header.prefix.checksum);
650 c.add_bytes(header.message.as_bytes());
651 for p in message_body.iter_fragments() {
652 c.add_bytes(p);
653 }
654 Some(c.checksum())
655}
656
657impl<I: IcmpIpExt, B: SplitByteSlice, M: IcmpMessage<I>> IcmpPacket<I, B, M> {
658 fn compute_checksum(
663 header: &Header<M>,
664 message_body: &[u8],
665 src_ip: I::Addr,
666 dst_ip: I::Addr,
667 ) -> Option<[u8; 2]> {
668 let mut body = [message_body];
669 compute_checksum_fragmented(header, &body.as_fragmented_byte_slice(), src_ip, dst_ip)
670 }
671}
672
673impl<I: IcmpIpExt, B: SplitByteSlice, M: IcmpMessage<I, Body<B> = OriginalPacket<B>>>
674 IcmpPacket<I, B, M>
675{
676 pub fn original_packet_body(&self) -> &[u8] {
684 self.message_body.body::<I>()
685 }
686
687 pub fn original_packet(&self) -> &OriginalPacket<B> {
695 &self.message_body
696 }
697}
698
699impl<B: SplitByteSlice, M: IcmpMessage<Ipv4, Body<B> = OriginalPacket<B>>> IcmpPacket<Ipv4, B, M> {
700 pub fn with_original_packet<O, F: FnOnce(Result<Ipv4PacketRaw<&[u8]>, &[u8]>) -> O>(
705 &self,
706 f: F,
707 ) -> O {
708 let mut bv = self.message_body.0.deref();
709 f(Ipv4PacketRaw::parse(&mut bv, ()).map_err(|_| self.message_body.0.deref()))
710 }
711}
712
713impl<B: SplitByteSlice, M: IcmpMessage<Ipv6, Body<B> = OriginalPacket<B>>> IcmpPacket<Ipv6, B, M> {
714 pub fn with_original_packet<O, F: FnOnce(Result<Ipv6PacketRaw<&[u8]>, &[u8]>) -> O>(
719 &self,
720 f: F,
721 ) -> O {
722 let mut bv = self.message_body.0.deref();
723 f(Ipv6PacketRaw::parse(&mut bv, ()).map_err(|_| self.message_body.0.deref()))
724 }
725}
726
727impl<I: IcmpIpExt, B: SplitByteSlice, M: IcmpMessage<I, Body<B> = ndp::Options<B>>>
728 IcmpPacket<I, B, M>
729{
730 pub fn ndp_options(&self) -> &ndp::Options<B> {
732 &self.message_body
733 }
734}
735
736#[derive(Debug, PartialEq, Clone)]
738pub struct IcmpPacketBuilder<I: IcmpIpExt, M: IcmpMessage<I>> {
739 src_ip: I::Addr,
740 dst_ip: I::Addr,
741 code: M::Code,
742 msg: M,
743}
744
745impl<I: IcmpIpExt, M: IcmpMessage<I>> IcmpPacketBuilder<I, M> {
746 pub fn new<S: Into<I::Addr>, D: Into<I::Addr>>(
748 src_ip: S,
749 dst_ip: D,
750 code: M::Code,
751 msg: M,
752 ) -> IcmpPacketBuilder<I, M> {
753 IcmpPacketBuilder { src_ip: src_ip.into(), dst_ip: dst_ip.into(), code, msg }
754 }
755
756 pub fn message(&self) -> &M {
758 &self.msg
759 }
760
761 pub fn message_mut(&mut self) -> &mut M {
763 &mut self.msg
764 }
765
766 pub fn set_src_ip(&mut self, addr: I::Addr) {
768 self.src_ip = addr;
769 }
770
771 pub fn set_dst_ip(&mut self, addr: I::Addr) {
773 self.dst_ip = addr;
774 }
775
776 fn serialize_header(
777 &self,
778 mut header: &mut [u8],
779 message_body: Option<FragmentedBytesMut<'_, '_>>,
780 ) {
781 use packet::BufferViewMut;
782
783 let mut prefix = &mut header;
785
786 let mut header =
789 prefix.take_obj_front_zero::<Header<M>>().expect("too few bytes for ICMP message");
790 header.prefix.set_msg_type(M::TYPE);
791 header.prefix.code = self.code.into();
792 header.message = self.msg;
793
794 if let Some(message_body) = message_body {
795 assert!(
796 M::EXPECTS_BODY || message_body.is_empty(),
797 "body provided for message that doesn't take a body"
798 );
799 let checksum =
800 compute_checksum_fragmented(&header, &message_body, self.src_ip, self.dst_ip)
801 .unwrap_or_else(|| {
802 panic!(
803 "total ICMP packet length of {} overflows 32-bit length field of pseudo-header",
804 Ref::bytes(&header).len() + message_body.len(),
805 )
806 });
807 header.prefix.checksum = checksum;
808 }
809 }
810}
811
812impl<I: IcmpIpExt, M: IcmpMessage<I>> PacketBuilder for IcmpPacketBuilder<I, M> {
816 fn constraints(&self) -> PacketConstraints {
817 PacketConstraints::new(mem::size_of::<Header<M>>(), 0, 0, core::u32::MAX as usize)
830 }
831
832 fn serialize(
833 &self,
834 target: &mut SerializeTarget<'_>,
835 message_body: FragmentedBytesMut<'_, '_>,
836 ) {
837 self.serialize_header(target.header, Some(message_body));
838 }
839}
840
841impl<I: IcmpIpExt, M: IcmpMessage<I>> PartialPacketBuilder for IcmpPacketBuilder<I, M> {
842 fn partial_serialize(&self, _body_len: usize, buffer: &mut [u8]) {
843 self.serialize_header(buffer, None);
844 }
845}
846
847#[derive(Copy, Clone, Debug, Eq, PartialEq)]
853pub struct IcmpZeroCode;
854
855impl From<IcmpZeroCode> for u8 {
856 fn from(_: IcmpZeroCode) -> u8 {
857 0
858 }
859}
860
861impl TryFrom<u8> for IcmpZeroCode {
862 type Error = NotZeroError<u8>;
863
864 fn try_from(value: u8) -> Result<Self, NotZeroError<u8>> {
865 if value == 0 {
866 Ok(Self)
867 } else {
868 Err(NotZeroError(value))
869 }
870 }
871}
872
873#[derive(Copy, Clone, Debug, Eq, PartialEq)]
878pub struct IcmpSenderZeroCode;
879
880impl From<IcmpSenderZeroCode> for u8 {
881 fn from(_: IcmpSenderZeroCode) -> u8 {
882 0
883 }
884}
885
886impl From<u8> for IcmpSenderZeroCode {
887 fn from(_: u8) -> Self {
888 Self
889 }
890}
891
892#[doc(hidden)]
897#[derive(
898 Copy, Clone, Debug, Eq, PartialEq, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned,
899)]
900#[repr(C)]
901pub struct IdAndSeq {
902 id: U16,
903 seq: U16,
904}
905
906impl IdAndSeq {
907 fn new(id: u16, seq: u16) -> IdAndSeq {
908 IdAndSeq { id: U16::new(id), seq: U16::new(seq) }
909 }
910}
911
912#[cfg(test)]
913mod tests {
914 use ip_test_macro::ip_test;
915 use packet::{EmptyBuf, ParseBuffer, Serializer, SliceBufViewMut};
916 use test_case::test_case;
917
918 use super::*;
919
920 #[test]
921 fn test_partial_parse() {
922 let reference_header = Header {
925 prefix: HeaderPrefix {
926 msg_type: <IcmpEchoRequest as IcmpMessage<Ipv4>>::TYPE.into(),
927 code: 0,
928 checksum: [0, 0],
929 },
930 message: IcmpEchoRequest::new(1, 1),
931 };
932
933 let mut buf = &reference_header.as_bytes()[..7];
938 assert_eq!(
939 buf.parse::<IcmpPacketRaw<Ipv4, _, IcmpEchoRequest>>().unwrap_err(),
940 ParseError::Format
941 );
942
943 let mut header = reference_header;
945 header.prefix.msg_type = <IcmpEchoReply as IcmpMessage<Ipv4>>::TYPE.into();
946 let mut buf = header.as_bytes();
947 assert_eq!(
948 buf.parse::<IcmpPacketRaw<Ipv4, _, IcmpEchoRequest>>().unwrap_err(),
949 ParseError::NotExpected
950 );
951
952 let mut header = reference_header;
954 header.prefix.code = 0xFF;
955 let mut buf = header.as_bytes();
956 assert!(buf.parse::<IcmpPacketRaw<Ipv4, _, IcmpEchoRequest>>().is_ok());
957
958 let mut buf = reference_header.as_bytes();
962 assert!(buf.parse::<IcmpPacketRaw<Ipv4, _, IcmpEchoRequest>>().is_ok());
963 let mut header = reference_header;
964 header.prefix.checksum = [1, 1];
965 let mut buf = header.as_bytes();
966 assert!(buf.parse::<IcmpPacketRaw<Ipv4, _, IcmpEchoRequest>>().is_ok());
967 }
968
969 #[ip_test(I)]
970 #[test_case([0,0]; "zeroed_checksum")]
971 #[test_case([123, 234]; "garbage_checksum")]
972 fn test_try_write_checksum<I: IcmpIpExt>(corrupt_checksum: [u8; 2]) {
973 let icmp_message_with_checksum = IcmpPacketBuilder::<I, _>::new(
976 *I::LOOPBACK_ADDRESS,
977 *I::LOOPBACK_ADDRESS,
978 IcmpZeroCode,
979 IcmpEchoRequest::new(1, 1),
980 )
981 .wrap_body(EmptyBuf)
982 .serialize_vec_outer()
983 .unwrap()
984 .as_ref()
985 .to_vec();
986
987 let mut icmp_message_without_checksum = icmp_message_with_checksum.clone();
989 {
990 let buf = SliceBufViewMut::new(&mut icmp_message_without_checksum);
991 let mut message = IcmpPacketRaw::<I, _, IcmpEchoRequest>::parse_mut(buf, ())
992 .expect("parse packet raw should succeed");
993 message.header.prefix.checksum = corrupt_checksum;
994 }
995 assert_ne!(&icmp_message_with_checksum[..], &icmp_message_without_checksum[..]);
996
997 let buf = SliceBufViewMut::new(&mut icmp_message_without_checksum);
999 let mut message = IcmpPacketRaw::<I, _, IcmpEchoRequest>::parse_mut(buf, ())
1000 .expect("parse packet raw should succeed");
1001 assert!(message.try_write_checksum(*I::LOOPBACK_ADDRESS, *I::LOOPBACK_ADDRESS));
1002 assert_eq!(&icmp_message_with_checksum[..], &icmp_message_without_checksum[..]);
1003 }
1004}