1use std::convert::TryFrom;
47
48use std::net::Ipv6Addr;
49
50fn ipv6_sum_words(ip: &Ipv6Addr) -> u32 {
51 ip.segments().iter().map(|x| *x as u32).sum()
52}
53
54fn sum_big_endian_words(bs: &[u8]) -> u32 {
55 if bs.len() == 0 {
56 return 0;
57 }
58
59 let len = bs.len();
60 let mut data = &bs[..];
61 let mut sum = 0u32;
62 while data.len() >= 2 {
64 sum += u16_from_be(&data[0..2]) as u32;
65 data = &data[2..];
67 }
68
69 if (len % 2) != 0 {
70 sum += (data[0] as u32) << 8;
72 }
73 return sum;
74}
75
76#[inline]
77fn u16_from_be(data: &[u8]) -> u16 {
78 u16::from_be_bytes(data.try_into().expect("Invalid slice size for u16"))
79}
80
81#[inline]
82fn u32_from_be(data: &[u8]) -> u32 {
83 u32::from_be_bytes(data.try_into().expect("Invalid slice size for u32"))
84}
85
86pub trait WithEchoRequest {
88 type Packet;
89
90 fn with_echo_request(
91 identifier: u16,
92 sequence: u16,
93 payload: Vec<u8>,
94 ) -> Result<Self::Packet, IcmpPacketBuildError>;
95}
96
97pub trait WithEchoReply {
100 type Packet;
101
102 fn with_echo_reply(
103 identifier: u16,
104 sequence: u16,
105 payload: Vec<u8>,
106 ) -> Result<Self::Packet, IcmpPacketBuildError>;
107}
108
109pub trait WithTimestampRequest {
111 type Packet;
112
113 fn with_timestamp_request(
114 identifier: u16,
115 sequence: u16,
116 originate: u32,
117 receive: u32,
118 transmit: u32,
119 ) -> Result<Self::Packet, IcmpPacketBuildError>;
120}
121
122pub trait WithTimestampReply {
124 type Packet;
125
126 fn with_timestamp_reply(
127 identifier: u16,
128 sequence: u16,
129 originate: u32,
130 receive: u32,
131 transmit: u32,
132 ) -> Result<Self::Packet, IcmpPacketBuildError>;
133}
134
135pub trait WithUnreachable {
137 type Packet;
138
139 fn with_unreachable(code: u8, packet: Vec<u8>) -> Result<Self::Packet, IcmpPacketBuildError>;
140}
141
142pub trait WithParameterProblem {
144 type Packet;
145 type Pointer;
146
147 fn with_parameter_problem(
148 code: u8,
149 pointer: Self::Pointer,
150 packet: Vec<u8>,
151 ) -> Result<Self::Packet, IcmpPacketBuildError>;
152}
153
154pub trait WithTimeExceeded {
156 type Packet;
157
158 fn with_time_exceeded(code: u8, packet: Vec<u8>) -> Result<Self::Packet, IcmpPacketBuildError>;
159}
160
161#[derive(Debug, PartialEq)]
163pub enum Icmpv6Message {
164 Unreachable {
167 _unused: u32,
168 invoking_packet: Vec<u8>,
169 },
170 PacketTooBig {
171 mtu: u32,
172 invoking_packet: Vec<u8>,
173 },
174 TimeExceeded {
175 _unused: u32,
176 invoking_packet: Vec<u8>,
177 },
178 ParameterProblem {
179 pointer: u32,
180 invoking_packet: Vec<u8>,
181 },
182 PrivateExperimental {
183 padding: u32,
184 payload: Vec<u8>,
185 },
186 EchoRequest {
187 identifier: u16,
188 sequence: u16,
189 payload: Vec<u8>,
190 },
191 EchoReply {
192 identifier: u16,
193 sequence: u16,
194 payload: Vec<u8>,
195 },
196}
197
198use Icmpv6Message::{
199 EchoReply, EchoRequest, PacketTooBig, ParameterProblem, PrivateExperimental, TimeExceeded,
200 Unreachable,
201};
202
203impl Icmpv6Message {
204 pub fn get_bytes(&self) -> Vec<u8> {
206 let mut bytes = Vec::new();
207 match self {
208 Unreachable {
209 _unused: field1,
210 invoking_packet: field2,
211 }
212 | PacketTooBig {
213 mtu: field1,
214 invoking_packet: field2,
215 }
216 | TimeExceeded {
217 _unused: field1,
218 invoking_packet: field2,
219 }
220 | ParameterProblem {
221 pointer: field1,
222 invoking_packet: field2,
223 }
224 | PrivateExperimental {
225 padding: field1,
226 payload: field2,
227 } => {
228 bytes.extend_from_slice(&field1.to_be_bytes());
229 bytes.extend_from_slice(field2);
230 }
231 EchoRequest {
232 identifier,
233 sequence,
234 payload,
235 }
236 | EchoReply {
237 identifier,
238 sequence,
239 payload,
240 } => {
241 bytes.extend_from_slice(&identifier.to_be_bytes());
242 bytes.extend_from_slice(&sequence.to_be_bytes());
243 bytes.extend_from_slice(payload);
244 }
245 }
246 bytes
247 }
248}
249
250#[derive(Debug)]
251pub struct Icmpv6Packet {
252 pub typ: u8,
255 pub code: u8,
256 pub checksum: u16,
257 pub message: Icmpv6Message,
258}
259
260#[derive(Debug)]
262pub enum PacketParseError {
263 PacketTooSmall(usize),
265 UnrecognizedICMPType(u8),
267}
268
269impl Icmpv6Packet {
270 pub fn parse<B: AsRef<[u8]>>(bytes: B) -> Result<Self, PacketParseError> {
272 let bytes = bytes.as_ref();
273 if bytes.len() < 8 {
275 return Err(PacketParseError::PacketTooSmall(bytes.len()));
276 }
277 let (typ, code, checksum) = (bytes[0], bytes[1], u16_from_be(&bytes[2..4]));
278
279 let next_field = u32_from_be(&bytes[4..8]);
280 let payload = bytes[8..].to_owned();
281 let message = match typ {
282 1 => Unreachable {
283 _unused: next_field,
284 invoking_packet: payload,
285 },
286 2 => PacketTooBig {
287 mtu: next_field,
288 invoking_packet: payload,
289 },
290 3 => TimeExceeded {
291 _unused: next_field,
292 invoking_packet: payload,
293 },
294 4 => ParameterProblem {
295 pointer: next_field,
296 invoking_packet: payload,
297 },
298 100 | 101 | 200 | 201 => PrivateExperimental {
299 padding: next_field,
300 payload: payload,
301 },
302 128 => EchoRequest {
303 identifier: u16_from_be(&bytes[4..6]),
304 sequence: u16_from_be(&bytes[6..8]),
305 payload: payload,
306 },
307 129 => EchoReply {
308 identifier: u16_from_be(&bytes[4..6]),
309 sequence: u16_from_be(&bytes[6..8]),
310 payload: payload,
311 },
312 t => return Err(PacketParseError::UnrecognizedICMPType(t)),
313 };
314 return Ok(Icmpv6Packet {
315 typ: typ,
316 code: code,
317 checksum: checksum,
318 message: message,
319 });
320 }
321
322 pub fn get_bytes(&self, with_checksum: bool) -> Vec<u8> {
324 let mut bytes = Vec::new();
325 bytes.push(self.typ);
326 bytes.push(self.code);
327 bytes.extend_from_slice(&(if with_checksum { self.checksum } else { 0 }).to_be_bytes());
328 bytes.append(&mut self.message.get_bytes());
329 return bytes;
330 }
331
332 pub fn calculate_checksum(&self, source: &Ipv6Addr, dest: &Ipv6Addr) -> u16 {
335 let mut sum = 0u32;
337 sum += ipv6_sum_words(source);
338 sum += ipv6_sum_words(dest);
339 sum += 58;
342
343 let bytes = self.get_bytes(false);
346 let len = bytes.len();
347 sum += len as u32;
348 sum += sum_big_endian_words(&bytes);
349
350 while sum >> 16 != 0 {
352 sum = (sum >> 16) + (sum & 0xFFFF);
353 }
354 !sum as u16
355 }
356
357 pub fn with_checksum(mut self, source: &Ipv6Addr, dest: &Ipv6Addr) -> Self {
360 self.checksum = self.calculate_checksum(source, dest);
361 self
362 }
363
364 pub fn with_packet_too_big(mtu: u32, packet: Vec<u8>) -> Result<Self, IcmpPacketBuildError> {
366 Ok(Self {
367 typ: 2,
368 code: 0,
369 checksum: 0,
370 message: PacketTooBig {
373 mtu: mtu,
374 invoking_packet: packet,
375 },
376 })
377 }
378}
379
380impl WithEchoRequest for Icmpv6Packet {
381 type Packet = Icmpv6Packet;
382
383 fn with_echo_request(
384 identifier: u16,
385 sequence: u16,
386 payload: Vec<u8>,
387 ) -> Result<Self::Packet, IcmpPacketBuildError> {
388 Ok(Self {
389 typ: 128,
390 code: 0,
391 checksum: 0,
392 message: EchoRequest {
393 identifier: identifier,
394 sequence: sequence,
395 payload: payload,
396 },
397 })
398 }
399}
400
401impl WithEchoReply for Icmpv6Packet {
402 type Packet = Icmpv6Packet;
403
404 fn with_echo_reply(
405 identifier: u16,
406 sequence: u16,
407 payload: Vec<u8>,
408 ) -> Result<Self, IcmpPacketBuildError> {
409 Ok(Self {
410 typ: 129,
411 code: 0,
412 checksum: 0,
413 message: EchoReply {
414 identifier: identifier,
415 sequence: sequence,
416 payload: payload,
417 },
418 })
419 }
420}
421
422impl WithUnreachable for Icmpv6Packet {
423 type Packet = Icmpv6Packet;
424
425 fn with_unreachable(code: u8, packet: Vec<u8>) -> Result<Self, IcmpPacketBuildError> {
426 if code > 6 {
427 return Err(IcmpPacketBuildError::InvalidCode(code));
428 }
429 Ok(Self {
430 typ: 1,
431 code: code,
432 checksum: 0,
433 message: Unreachable {
436 _unused: 0,
437 invoking_packet: packet,
438 },
439 })
440 }
441}
442
443impl WithParameterProblem for Icmpv6Packet {
444 type Packet = Icmpv6Packet;
445 type Pointer = u32;
446
447 fn with_parameter_problem(
448 code: u8,
449 pointer: Self::Pointer,
450 packet: Vec<u8>,
451 ) -> Result<Self, IcmpPacketBuildError> {
452 if code > 1 {
453 return Err(IcmpPacketBuildError::InvalidCode(code));
454 }
455 Ok(Self {
456 typ: 4,
457 code: code,
458 checksum: 0,
459 message: ParameterProblem {
460 pointer: pointer,
461 invoking_packet: packet,
462 },
463 })
464 }
465}
466
467impl WithTimeExceeded for Icmpv6Packet {
468 type Packet = Icmpv6Packet;
469
470 fn with_time_exceeded(code: u8, packet: Vec<u8>) -> Result<Self, IcmpPacketBuildError> {
471 if code > 1 {
472 return Err(IcmpPacketBuildError::InvalidCode(code));
473 }
474 Ok(Self {
475 typ: 3,
476 code: code,
477 checksum: 0,
478 message: TimeExceeded {
481 _unused: 0,
482 invoking_packet: packet,
483 },
484 })
485 }
486}
487
488impl TryFrom<&[u8]> for Icmpv6Packet {
489 type Error = PacketParseError;
490 fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
491 Icmpv6Packet::parse(b)
492 }
493}
494
495#[derive(Debug, PartialEq)]
497pub enum IcmpPacketBuildError {
498 InvalidCode(u8),
500}
501use IcmpPacketBuildError::InvalidCode;
502
503impl std::fmt::Display for IcmpPacketBuildError {
504 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
505 write!(
506 f,
507 "{}",
508 match self {
509 InvalidCode(c) => format!("Invalid Code: {}", c),
510 }
511 )
512 }
513}
514
515impl std::fmt::Display for PacketParseError {
516 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
517 write!(
518 f,
519 "{}",
520 match self {
521 PacketParseError::PacketTooSmall(c) => format!("Packet Too Small size: {}", c),
522 PacketParseError::UnrecognizedICMPType(t) => format!("UnrecognizedIcmpType({})", t),
523 }
524 )
525 }
526}
527
528impl From<IcmpPacketBuildError> for std::io::Error {
529 fn from(err: IcmpPacketBuildError) -> Self {
530 std::io::Error::new(std::io::ErrorKind::Other, format!("{}", err))
531 }
532}
533
534impl From<PacketParseError> for std::io::Error {
535 fn from(err: PacketParseError) -> Self {
536 std::io::Error::new(std::io::ErrorKind::Other, format!("{}", err))
537 }
538}
539
540#[derive(Debug)]
542pub enum Icmpv4Message {
543 Unreachable {
544 padding: u32,
546 header: Vec<u8>,
547 },
548 TimeExceeded {
549 padding: u32,
551 header: Vec<u8>,
552 },
553 ParameterProblem {
554 pointer: u8,
556 padding: (u8, u16),
557 header: Vec<u8>,
558 },
559 Quench {
560 padding: u32,
562 header: Vec<u8>,
563 },
564 Redirect {
565 gateway: u32,
567 header: Vec<u8>,
568 },
569 Echo {
570 identifier: u16,
572 sequence: u16,
573 payload: Vec<u8>,
574 },
575 EchoReply {
576 identifier: u16,
578 sequence: u16,
579 payload: Vec<u8>,
580 },
581 Timestamp {
582 identifier: u16,
584 sequence: u16,
585 originate: u32,
586 receive: u32,
587 transmit: u32,
588 },
589 TimestampReply {
590 identifier: u16,
592 sequence: u16,
593 originate: u32,
594 receive: u32,
595 transmit: u32,
596 },
597 Information {
598 identifier: u16,
600 sequence: u16,
601 },
602 InformationReply {
603 identifier: u16,
605 sequence: u16,
606 },
607}
608
609impl Icmpv4Message {
610 pub fn get_bytes(&self) -> Vec<u8> {
612 let mut bytes = Vec::with_capacity(20);
613 match self {
614 Self::Unreachable {
615 padding,
617 header,
618 }
619 | Self::TimeExceeded {
620 padding,
622 header,
623 }
624 | Self::Quench {
625 padding,
627 header,
628 }
629 | Self::Redirect {
630 gateway: padding,
632 header,
633 } => {
634 bytes.extend_from_slice(&padding.to_be_bytes());
635 bytes.extend_from_slice(header);
636 }
637 Self::Echo {
638 identifier,
640 sequence,
641 payload,
642 }
643 | Self::EchoReply {
644 identifier,
646 sequence,
647 payload,
648 } => {
649 bytes.extend_from_slice(&identifier.to_be_bytes());
650 bytes.extend_from_slice(&sequence.to_be_bytes());
651 bytes.extend_from_slice(payload);
652 }
653 Self::ParameterProblem {
654 pointer,
656 padding,
657 header,
658 } => {
659 bytes.push(*pointer);
660 bytes.push(padding.0);
661 bytes.extend_from_slice(&padding.1.to_be_bytes());
662 bytes.extend_from_slice(header);
663 }
664 Self::Timestamp {
665 identifier,
667 sequence,
668 originate,
669 receive,
670 transmit,
671 }
672 | Self::TimestampReply {
673 identifier,
675 sequence,
676 originate,
677 receive,
678 transmit,
679 } => {
680 bytes.extend_from_slice(&identifier.to_be_bytes());
681 bytes.extend_from_slice(&sequence.to_be_bytes());
682 bytes.extend_from_slice(&originate.to_be_bytes());
683 bytes.extend_from_slice(&receive.to_be_bytes());
684 bytes.extend_from_slice(&transmit.to_be_bytes());
685 }
686 Self::Information {
687 identifier,
689 sequence,
690 }
691 | Self::InformationReply {
692 identifier,
694 sequence,
695 } => {
696 bytes.extend_from_slice(&identifier.to_be_bytes());
697 bytes.extend_from_slice(&sequence.to_be_bytes());
698 }
699 }
700 bytes
701 }
702}
703
704#[derive(Debug)]
706pub struct Icmpv4Packet {
707 pub typ: u8,
708 pub code: u8,
709 pub checksum: u16,
710 pub message: Icmpv4Message,
711}
712
713impl Icmpv4Packet {
714 pub fn parse<B: AsRef<[u8]>>(bytes: B) -> Result<Self, PacketParseError> {
716 let mut bytes = bytes.as_ref();
717 let mut packet_len = bytes.len();
718 if bytes.len() < 28 {
719 return Err(PacketParseError::PacketTooSmall(packet_len));
720 }
721 bytes = &bytes[20..];
723 packet_len = bytes.len();
725 let (typ, code, checksum) = (bytes[0], bytes[1], u16_from_be(&bytes[2..4]));
726 let message = match typ {
727 3 => Icmpv4Message::Unreachable {
728 padding: u32_from_be(&bytes[4..8]),
729 header: bytes[8..].to_owned(),
730 },
731 11 => Icmpv4Message::TimeExceeded {
732 padding: u32_from_be(&bytes[4..8]),
733 header: bytes[8..].to_owned(),
734 },
735 4 => Icmpv4Message::Quench {
736 padding: u32_from_be(&bytes[4..8]),
737 header: bytes[8..].to_owned(),
738 },
739 5 => Icmpv4Message::Redirect {
740 gateway: u32_from_be(&bytes[4..8]),
741 header: bytes[8..].to_owned(),
742 },
743 8 => Icmpv4Message::Echo {
744 identifier: u16_from_be(&bytes[4..6]),
745 sequence: u16_from_be(&bytes[6..8]),
746 payload: bytes[8..].to_owned(),
747 },
748 0 => Icmpv4Message::EchoReply {
749 identifier: u16_from_be(&bytes[4..6]),
750 sequence: u16_from_be(&bytes[6..8]),
751 payload: bytes[8..].to_owned(),
752 },
753 15 => Icmpv4Message::Information {
754 identifier: u16_from_be(&bytes[4..6]),
755 sequence: u16_from_be(&bytes[6..8]),
756 },
757 16 => Icmpv4Message::InformationReply {
758 identifier: u16_from_be(&bytes[4..6]),
759 sequence: u16_from_be(&bytes[6..8]),
760 },
761 13 => {
762 if packet_len < 20 {
763 return Err(PacketParseError::PacketTooSmall(bytes.len()));
764 }
765 Icmpv4Message::Timestamp {
766 identifier: u16_from_be(&bytes[4..6]),
767 sequence: u16_from_be(&bytes[6..8]),
768 originate: u32_from_be(&bytes[8..12]),
769 receive: u32_from_be(&bytes[12..16]),
770 transmit: u32_from_be(&bytes[16..20]),
771 }
772 }
773 14 => {
774 if packet_len < 20 {
775 return Err(PacketParseError::PacketTooSmall(bytes.len()));
776 }
777 Icmpv4Message::TimestampReply {
778 identifier: u16_from_be(&bytes[4..6]),
779 sequence: u16_from_be(&bytes[6..8]),
780 originate: u32_from_be(&bytes[8..12]),
781 receive: u32_from_be(&bytes[12..16]),
782 transmit: u32_from_be(&bytes[16..20]),
783 }
784 }
785 t => {
786 dbg!(bytes);
787 return Err(PacketParseError::UnrecognizedICMPType(t));
788 }
789 };
790 return Ok(Icmpv4Packet {
791 typ: typ,
792 code: code,
793 checksum: checksum,
794 message: message,
795 });
796 }
797
798 pub fn get_bytes(&self, with_checksum: bool) -> Vec<u8> {
800 let mut bytes = Vec::new();
801 bytes.push(self.typ);
802 bytes.push(self.code);
803 bytes.extend_from_slice(&(if with_checksum { self.checksum } else { 0 }).to_be_bytes());
804 bytes.append(&mut self.message.get_bytes());
805 return bytes;
806 }
807
808 pub fn calculate_checksum(&self) -> u16 {
811 let mut sum = 0u32;
813
814 let bytes = self.get_bytes(false);
817 sum += sum_big_endian_words(&bytes);
818
819 while sum >> 16 != 0 {
821 sum = (sum >> 16) + (sum & 0xFFFF);
822 }
823 !sum as u16
824 }
825
826 pub fn with_checksum(mut self) -> Self {
828 self.checksum = self.calculate_checksum();
829 self
830 }
831}
832
833impl WithEchoReply for Icmpv4Packet {
834 type Packet = Icmpv4Packet;
835
836 fn with_echo_reply(
837 identifier: u16,
838 sequence: u16,
839 payload: Vec<u8>,
840 ) -> Result<Self, IcmpPacketBuildError> {
841 Ok(Self {
842 typ: 0,
843 code: 0,
844 checksum: 0,
845 message: Icmpv4Message::EchoReply {
846 identifier: identifier,
847 sequence: sequence,
848 payload: payload,
849 },
850 })
851 }
852}
853
854impl TryFrom<&[u8]> for Icmpv4Packet {
855 type Error = PacketParseError;
856 fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
857 Icmpv4Packet::parse(b)
858 }
859}
860
861impl WithEchoRequest for Icmpv4Packet {
862 type Packet = Icmpv4Packet;
863
864 fn with_echo_request(
865 identifier: u16,
866 sequence: u16,
867 payload: Vec<u8>,
868 ) -> Result<Self::Packet, IcmpPacketBuildError> {
869 Ok(Self {
870 typ: 8,
871 code: 0,
872 checksum: 0,
873 message: Icmpv4Message::Echo {
874 identifier,
875 sequence,
876 payload,
877 },
878 })
879 }
880}
881
882impl WithTimestampRequest for Icmpv4Packet {
883 type Packet = Icmpv4Packet;
884
885 fn with_timestamp_request(
886 identifier: u16,
887 sequence: u16,
888 originate: u32,
889 receive: u32,
890 transmit: u32,
891 ) -> Result<Self::Packet, IcmpPacketBuildError> {
892 Ok(Self {
893 typ: 13,
894 code: 0,
895 checksum: 0,
896 message: Icmpv4Message::Timestamp {
897 identifier,
898 sequence,
899 originate,
900 receive,
901 transmit,
902 },
903 })
904 }
905}
906
907impl WithTimestampReply for Icmpv4Packet {
908 type Packet = Icmpv4Packet;
909
910 fn with_timestamp_reply(
911 identifier: u16,
912 sequence: u16,
913 originate: u32,
914 receive: u32,
915 transmit: u32,
916 ) -> Result<Self::Packet, IcmpPacketBuildError> {
917 Ok(Self {
918 typ: 14,
919 code: 0,
920 checksum: 0,
921 message: Icmpv4Message::TimestampReply {
922 identifier,
923 sequence,
924 originate,
925 receive,
926 transmit,
927 },
928 })
929 }
930}
931
932impl WithUnreachable for Icmpv4Packet {
933 type Packet = Icmpv4Packet;
934
935 fn with_unreachable(code: u8, packet: Vec<u8>) -> Result<Self::Packet, IcmpPacketBuildError> {
936 if code > 5 {
937 return Err(IcmpPacketBuildError::InvalidCode(code));
938 }
939 Ok(Self {
940 typ: 3,
941 code: code,
942 checksum: 0,
943 message: Icmpv4Message::Unreachable {
944 padding: 0,
945 header: packet,
946 },
947 })
948 }
949}
950
951impl WithParameterProblem for Icmpv4Packet {
952 type Packet = Icmpv4Packet;
953 type Pointer = u8;
954
955 fn with_parameter_problem(
956 code: u8,
957 pointer: Self::Pointer,
958 packet: Vec<u8>,
959 ) -> Result<Self::Packet, IcmpPacketBuildError> {
960 if code != 0 {
961 return Err(IcmpPacketBuildError::InvalidCode(code));
962 }
963 Ok(Self {
964 typ: 12,
965 code: code,
966 checksum: 0,
967 message: Icmpv4Message::ParameterProblem {
968 pointer: pointer,
969 padding: (0, 0),
970 header: packet,
971 },
972 })
973 }
974}
975
976impl WithTimeExceeded for Icmpv4Packet {
977 type Packet = Icmpv4Packet;
978
979 fn with_time_exceeded(code: u8, packet: Vec<u8>) -> Result<Self::Packet, IcmpPacketBuildError> {
980 if code > 1 {
981 return Err(IcmpPacketBuildError::InvalidCode(code));
982 }
983 Ok(Self {
984 typ: 11,
985 code: code,
986 checksum: 0,
987 message: Icmpv4Message::TimeExceeded {
988 padding: 0,
989 header: packet,
990 },
991 })
992 }
993}
994
995#[cfg(test)]
996mod tests {
997 use super::*;
998
999 #[test]
1000 fn packet_construction_echo_request_test() {
1001 let pkt = Icmpv6Packet::with_echo_request(42, 1, vec![1, 2, 3, 4]).unwrap();
1002 assert_eq!(pkt.typ, 128);
1003 assert_eq!(pkt.code, 0);
1004 assert_eq!(
1005 pkt.message,
1006 EchoRequest {
1007 identifier: 42,
1008 sequence: 1,
1009 payload: vec![1, 2, 3, 4],
1010 }
1011 );
1012 }
1013
1014 #[test]
1015 fn packet_construction_echo_reply_test() {
1016 let pkt = Icmpv6Packet::with_echo_reply(42, 1, vec![1, 2, 3, 4]).unwrap();
1017 assert_eq!(pkt.typ, 129);
1018 assert_eq!(pkt.code, 0);
1019 assert_eq!(
1020 pkt.message,
1021 EchoReply {
1022 identifier: 42,
1023 sequence: 1,
1024 payload: vec![1, 2, 3, 4],
1025 }
1026 );
1027 }
1028
1029 #[test]
1030 fn packet_construction_too_big_test() {
1031 let pkt = Icmpv6Packet::with_packet_too_big(3, vec![1, 2, 3, 4]).unwrap();
1032 assert_eq!(pkt.typ, 2);
1033 assert_eq!(pkt.code, 0);
1034 assert_eq!(
1035 pkt.message,
1036 PacketTooBig {
1037 mtu: 3,
1038 invoking_packet: vec![1, 2, 3, 4],
1039 }
1040 );
1041 }
1042
1043 #[test]
1044 fn packet_construction_time_exceeded() {
1045 let pkt = Icmpv6Packet::with_time_exceeded(0, vec![1, 2, 3, 4]).unwrap();
1046 assert_eq!(pkt.typ, 3);
1047 assert_eq!(pkt.code, 0);
1048 assert_eq!(
1049 pkt.message,
1050 TimeExceeded {
1051 _unused: 0,
1052 invoking_packet: vec![1, 2, 3, 4],
1053 }
1054 );
1055 }
1056
1057 #[test]
1058 fn packet_construction_time_exceeded_invalid_code() {
1059 let pkt = Icmpv6Packet::with_time_exceeded(2, vec![1, 2, 3, 4]);
1060 assert!(pkt.is_err());
1061 let e = pkt.unwrap_err();
1062 assert_eq!(e, IcmpPacketBuildError::InvalidCode(2));
1063 }
1064
1065 #[test]
1066 fn packet_construction_parameter_problem() {
1067 let pkt = Icmpv6Packet::with_parameter_problem(0, 30, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
1068 .unwrap();
1069 assert_eq!(pkt.typ, 4);
1070 assert_eq!(pkt.code, 0);
1071 assert_eq!(
1072 pkt.message,
1073 ParameterProblem {
1074 pointer: 30,
1075 invoking_packet: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
1076 }
1077 );
1078 }
1079
1080 #[test]
1081 fn packet_construction_parameter_problem_invalid_code() {
1082 let pkt = Icmpv6Packet::with_parameter_problem(3, 30, vec![1, 2, 3, 4]);
1083 assert!(pkt.is_err());
1084 let e = pkt.unwrap_err();
1085 assert_eq!(e, IcmpPacketBuildError::InvalidCode(3));
1086 }
1087
1088 #[test]
1089 fn echo_packet_parse_test() {
1090 let lo = &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
1093 let mut data = vec![
1094 0x80, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, 0x66, 0x6c, 0x65, 0x73, 0x68, 0x20,
1101 0x77, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, 0x20, 0x62, 0x75, 0x74,
1102 0x20, 0x61, 0x20, 0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, 0x20, 0x6b, 0x6e,
1103 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x6e, 0x69, 0x20, 0x20, 0x20,
1104 ];
1105 let mut pkt = Icmpv6Packet::parse(&data).unwrap();
1106 assert_eq!(pkt.typ, 128);
1107 assert_eq!(pkt.code, 0x00);
1108 if let EchoRequest {
1109 identifier,
1110 sequence,
1111 payload,
1112 } = &pkt.message
1113 {
1114 assert_eq!(*identifier, 0);
1115 assert_eq!(*sequence, 1);
1116 assert_eq!(
1117 payload,
1118 &[
1119 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, 0x66, 0x6c, 0x65, 0x73, 0x68,
1120 0x20, 0x77, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, 0x20, 0x62,
1121 0x75, 0x74, 0x20, 0x61, 0x20, 0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20,
1122 0x20, 0x6b, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x6e,
1123 0x69, 0x20, 0x20, 0x20
1124 ]
1125 );
1126 } else {
1127 assert!(
1128 false,
1129 "Packet did not parse as an EchoRequest {:?}",
1130 pkt.message
1131 );
1132 }
1133 assert_eq!(pkt.get_bytes(true), data);
1134 assert_eq!(pkt.calculate_checksum(lo, lo), 0x1d2e);
1135 pkt = pkt.with_checksum(lo, lo);
1136 assert_eq!(pkt.checksum, 0x1d2e);
1137
1138 data[0] = 0x81;
1140 let pkt = Icmpv6Packet::parse(&data).unwrap();
1141 assert_eq!(pkt.typ, 129);
1142 assert_eq!(pkt.code, 0);
1143 if let EchoReply {
1144 identifier,
1145 sequence,
1146 payload,
1147 } = &pkt.message
1148 {
1149 assert_eq!(*identifier, 0);
1150 assert_eq!(*sequence, 1);
1151 assert_eq!(
1152 payload,
1153 &[
1154 0x20, 0x20, 0x75, 0x73, 0x74, 0x20, 0x61, 0x20, 0x66, 0x6c, 0x65, 0x73, 0x68,
1155 0x20, 0x77, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x20, 0x74, 0x69, 0x73, 0x20, 0x62,
1156 0x75, 0x74, 0x20, 0x61, 0x20, 0x73, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20,
1157 0x20, 0x6b, 0x6e, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x6e,
1158 0x69, 0x20, 0x20, 0x20
1159 ]
1160 );
1161 } else {
1162 assert!(
1163 false,
1164 "Packet did not parse as an EchoReply {:?}",
1165 pkt.message
1166 );
1167 }
1168 assert_eq!(pkt.get_bytes(true), data);
1169 assert_eq!(pkt.calculate_checksum(lo, lo), 0x1c2e);
1170 }
1171}