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