surge_ping/icmp/
icmpv6.rs

1use std::convert::TryInto;
2use std::net::Ipv6Addr;
3
4use pnet_packet::icmpv6::{self, Icmpv6Code, Icmpv6Type};
5use pnet_packet::Packet;
6use pnet_packet::PacketSize;
7
8use crate::error::{MalformedPacketError, Result, SurgeError};
9
10use super::{PingIdentifier, PingSequence};
11
12#[allow(dead_code)]
13pub fn make_icmpv6_echo_packet(
14    ident: PingIdentifier,
15    seq_cnt: PingSequence,
16    payload: &[u8],
17) -> Result<Vec<u8>> {
18    let mut buf = vec![0; 8 + payload.len()]; // 8 bytes of header, then payload
19    let mut packet = icmpv6::echo_request::MutableEchoRequestPacket::new(&mut buf[..])
20        .ok_or(SurgeError::IncorrectBufferSize)?;
21    packet.set_icmpv6_type(icmpv6::Icmpv6Types::EchoRequest);
22    packet.set_identifier(ident.into_u16());
23    packet.set_sequence_number(seq_cnt.into_u16());
24    packet.set_payload(payload);
25
26    // Per https://tools.ietf.org/html/rfc3542#section-3.1 the checksum is
27    // omitted, the kernel will insert it.
28
29    Ok(packet.packet().to_vec())
30}
31
32/// Packet structure returned by ICMPv6.
33#[derive(Debug)]
34pub struct Icmpv6Packet {
35    source: Ipv6Addr,
36    destination: Ipv6Addr,
37    max_hop_limit: u8,
38    icmpv6_type: Icmpv6Type,
39    icmpv6_code: Icmpv6Code,
40    size: usize,
41    real_dest: Ipv6Addr,
42    identifier: PingIdentifier,
43    sequence: PingSequence,
44}
45
46impl Default for Icmpv6Packet {
47    fn default() -> Self {
48        Icmpv6Packet {
49            source: Ipv6Addr::LOCALHOST,
50            destination: Ipv6Addr::LOCALHOST,
51            max_hop_limit: 0,
52            icmpv6_type: Icmpv6Type::new(0),
53            icmpv6_code: Icmpv6Code::new(0),
54            size: 0,
55            real_dest: Ipv6Addr::LOCALHOST,
56            identifier: PingIdentifier(0),
57            sequence: PingSequence(0),
58        }
59    }
60}
61
62impl Icmpv6Packet {
63    fn source(&mut self, source: Ipv6Addr) -> &mut Self {
64        self.source = source;
65        self
66    }
67
68    /// Get the source IPv6 address.
69    pub fn get_source(&self) -> Ipv6Addr {
70        self.source
71    }
72
73    fn destination(&mut self, destination: Ipv6Addr) -> &mut Self {
74        self.destination = destination;
75        self
76    }
77
78    /// Get the destination IPv6 address.
79    pub fn get_destination(&self) -> Ipv6Addr {
80        self.destination
81    }
82
83    fn max_hop_limit(&mut self, max_hop_limit: u8) -> &mut Self {
84        self.max_hop_limit = max_hop_limit;
85        self
86    }
87
88    /// Get the hop_limit field.
89    pub fn get_max_hop_limit(&self) -> u8 {
90        self.max_hop_limit
91    }
92
93    fn icmpv6_type(&mut self, icmpv6_type: Icmpv6Type) -> &mut Self {
94        self.icmpv6_type = icmpv6_type;
95        self
96    }
97
98    /// Get the icmpv6_type of the icmpv6 packet.
99    pub fn get_icmpv6_type(&self) -> Icmpv6Type {
100        self.icmpv6_type
101    }
102
103    fn icmpv6_code(&mut self, icmpv6_code: Icmpv6Code) -> &mut Self {
104        self.icmpv6_code = icmpv6_code;
105        self
106    }
107
108    /// Get the icmpv6_code of the icmpv6 packet.
109    pub fn get_icmpv6_code(&self) -> Icmpv6Code {
110        self.icmpv6_code
111    }
112
113    fn size(&mut self, size: usize) -> &mut Self {
114        self.size = size;
115        self
116    }
117
118    /// Get the size of the icmp_v6 packet.
119    pub fn get_size(&self) -> usize {
120        self.size
121    }
122
123    fn real_dest(&mut self, addr: Ipv6Addr) -> &mut Self {
124        self.real_dest = addr;
125        self
126    }
127
128    /// If it is an `echo_reply` packet, it is the source address in the IPv6 packet.
129    /// If it is other packets, it is the destination address in the IPv6 packet in ICMPv6's payload.
130    pub fn get_real_dest(&self) -> Ipv6Addr {
131        self.real_dest
132    }
133
134    fn identifier(&mut self, identifier: PingIdentifier) -> &mut Self {
135        self.identifier = identifier;
136        self
137    }
138
139    /// Get the identifier of the icmp_v6 packet.
140    pub fn get_identifier(&self) -> PingIdentifier {
141        self.identifier
142    }
143
144    fn sequence(&mut self, sequence: PingSequence) -> &mut Self {
145        self.sequence = sequence;
146        self
147    }
148
149    /// Get the sequence of the icmp_v6 packet.
150    pub fn get_sequence(&self) -> PingSequence {
151        self.sequence
152    }
153
154    /// Decode into icmpv6 packet from the socket message.
155    pub fn decode(buf: &[u8], destination: Ipv6Addr) -> Result<Self> {
156        // The IPv6 header is automatically cropped off when recvfrom() is used.
157        let icmpv6_packet = icmpv6::Icmpv6Packet::new(buf)
158            .ok_or_else(|| SurgeError::from(MalformedPacketError::NotIcmpv6Packet))?;
159        let icmpv6_payload = icmpv6_packet.payload();
160        match icmpv6_packet.get_icmpv6_type() {
161            icmpv6::Icmpv6Types::EchoRequest => Err(SurgeError::EchoRequestPacket),
162            icmpv6::Icmpv6Types::EchoReply => {
163                if icmpv6_payload.len() < 4 {
164                    return Err(SurgeError::from(MalformedPacketError::PayloadTooShort {
165                        got: icmpv6_payload.len(),
166                        want: 4,
167                    }));
168                }
169                let identifier = u16::from_be_bytes(icmpv6_payload[0..2].try_into().unwrap());
170                let sequence = u16::from_be_bytes(icmpv6_payload[2..4].try_into().unwrap());
171                let mut packet = Icmpv6Packet::default();
172                packet
173                    .source(destination)
174                    .destination(Ipv6Addr::LOCALHOST)
175                    .max_hop_limit(0)
176                    .icmpv6_type(icmpv6_packet.get_icmpv6_type())
177                    .icmpv6_code(icmpv6_packet.get_icmpv6_code())
178                    .size(icmpv6_packet.packet().len())
179                    .real_dest(destination)
180                    .identifier(identifier.into())
181                    .sequence(sequence.into());
182                Ok(packet)
183            }
184            _ => {
185                // ipv6 header(40) + icmpv6 echo header(4)
186                if icmpv6_payload.len() < 48 {
187                    return Err(SurgeError::from(MalformedPacketError::PayloadTooShort {
188                        got: icmpv6_payload.len(),
189                        want: 48,
190                    }));
191                }
192                let identifier = u16::from_be_bytes(icmpv6_payload[44..46].try_into().unwrap());
193                let sequence = u16::from_be_bytes(icmpv6_payload[46..48].try_into().unwrap());
194                let mut packet = Icmpv6Packet::default();
195                packet
196                    .source(destination)
197                    .destination(destination)
198                    .max_hop_limit(0)
199                    .icmpv6_type(icmpv6_packet.get_icmpv6_type())
200                    .icmpv6_code(icmpv6_packet.get_icmpv6_code())
201                    .size(icmpv6_packet.packet_size())
202                    .identifier(identifier.into())
203                    .sequence(sequence.into());
204                Ok(packet)
205            }
206        }
207    }
208}