cross_socket/packet/
icmpv6.rs

1use pnet::packet::Packet;
2use std::net::Ipv6Addr;
3use crate::packet::ethernet::ETHERNET_HEADER_LEN;
4use crate::packet::ipv6::IPV6_HEADER_LEN;
5
6pub const ICMPV6_HEADER_LEN: usize =
7    pnet::packet::icmpv6::echo_request::MutableEchoRequestPacket::minimum_packet_size();
8/// ICMPv6 Minimum Packet Length
9pub const ICMPV6_PACKET_LEN: usize = ETHERNET_HEADER_LEN + IPV6_HEADER_LEN + ICMPV6_HEADER_LEN;
10/// ICMPv6 IP Packet Length
11pub const ICMPV6_IP_PACKET_LEN: usize = IPV6_HEADER_LEN + ICMPV6_HEADER_LEN;
12
13/// ICMPv6 types
14/// <https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml>
15#[derive(Clone, Debug, PartialEq)]
16pub enum Icmpv6Type {
17    DestinationUnreachable,
18    PacketTooBig,
19    TimeExceeded,
20    ParameterProblem,
21    EchoRequest,
22    EchoReply,
23    MulticastListenerQuery,
24    MulticastListenerReport,
25    MulticastListenerDone,
26    RouterSolicitation,
27    RouterAdvertisement,
28    NeighborSolicitation,
29    NeighborAdvertisement,
30    RedirectMessage,
31    RouterRenumbering,
32    NodeInformationQuery,
33    NodeInformationResponse,
34    InverseNeighborDiscoverySolicitation,
35    InverseNeighborDiscoveryAdvertisement,
36    Version2MulticastListenerReport,
37    HomeAgentAddressDiscoveryRequest,
38    HomeAgentAddressDiscoveryReply,
39    MobilePrefixSolicitation,
40    MobilePrefixAdvertisement,
41    CertificationPathSolicitationMessage,
42    CertificationPathAdvertisementMessage,
43    ExperimentalMobilityProtocols,
44    MulticastRouterAdvertisement,
45    MulticastRouterSolicitation,
46    MulticastRouterTermination,
47    FMIPv6Messages,
48    RPLControlMessage,
49    ILNPv6LocatorUpdateMessage,
50    DuplicateAddressRequest,
51    DuplicateAddressConfirmation,
52    MPLControlMessage,
53    ExtendedEchoRequest,
54    ExtendedEchoReply,
55    Unknown(u8),
56}
57
58impl Icmpv6Type {
59    /// Get the number of the ICMPv6 type
60    pub fn number(&self) -> u8 {
61        match *self {
62            Icmpv6Type::DestinationUnreachable => 1,
63            Icmpv6Type::PacketTooBig => 2,
64            Icmpv6Type::TimeExceeded => 3,
65            Icmpv6Type::ParameterProblem => 4,
66            Icmpv6Type::EchoRequest => 128,
67            Icmpv6Type::EchoReply => 129,
68            Icmpv6Type::MulticastListenerQuery => 130,
69            Icmpv6Type::MulticastListenerReport => 131,
70            Icmpv6Type::MulticastListenerDone => 132,
71            Icmpv6Type::RouterSolicitation => 133,
72            Icmpv6Type::RouterAdvertisement => 134,
73            Icmpv6Type::NeighborSolicitation => 135,
74            Icmpv6Type::NeighborAdvertisement => 136,
75            Icmpv6Type::RedirectMessage => 137,
76            Icmpv6Type::RouterRenumbering => 138,
77            Icmpv6Type::NodeInformationQuery => 139,
78            Icmpv6Type::NodeInformationResponse => 140,
79            Icmpv6Type::InverseNeighborDiscoverySolicitation => 141,
80            Icmpv6Type::InverseNeighborDiscoveryAdvertisement => 142,
81            Icmpv6Type::Version2MulticastListenerReport => 143,
82            Icmpv6Type::HomeAgentAddressDiscoveryRequest => 144,
83            Icmpv6Type::HomeAgentAddressDiscoveryReply => 145,
84            Icmpv6Type::MobilePrefixSolicitation => 146,
85            Icmpv6Type::MobilePrefixAdvertisement => 147,
86            Icmpv6Type::CertificationPathSolicitationMessage => 148,
87            Icmpv6Type::CertificationPathAdvertisementMessage => 149,
88            Icmpv6Type::ExperimentalMobilityProtocols => 150,
89            Icmpv6Type::MulticastRouterAdvertisement => 151,
90            Icmpv6Type::MulticastRouterSolicitation => 152,
91            Icmpv6Type::MulticastRouterTermination => 153,
92            Icmpv6Type::FMIPv6Messages => 154,
93            Icmpv6Type::RPLControlMessage => 155,
94            Icmpv6Type::ILNPv6LocatorUpdateMessage => 156,
95            Icmpv6Type::DuplicateAddressRequest => 157,
96            Icmpv6Type::DuplicateAddressConfirmation => 158,
97            Icmpv6Type::MPLControlMessage => 159,
98            Icmpv6Type::ExtendedEchoRequest => 160,
99            Icmpv6Type::ExtendedEchoReply => 161,
100            Icmpv6Type::Unknown(n) => n,
101        }
102    }
103    /// Get the id of the ICMPv6 type
104    pub fn id(&self) -> String {
105        match *self {
106            Icmpv6Type::DestinationUnreachable => String::from("destination_unreachable"),
107            Icmpv6Type::PacketTooBig => String::from("packet_too_big"),
108            Icmpv6Type::TimeExceeded => String::from("time_exceeded"),
109            Icmpv6Type::ParameterProblem => String::from("parameter_problem"),
110            Icmpv6Type::EchoRequest => String::from("echo_request"),
111            Icmpv6Type::EchoReply => String::from("echo_reply"),
112            Icmpv6Type::MulticastListenerQuery => String::from("multicast_listener_query"),
113            Icmpv6Type::MulticastListenerReport => String::from("multicast_listener_report"),
114            Icmpv6Type::MulticastListenerDone => String::from("multicast_listener_done"),
115            Icmpv6Type::RouterSolicitation => String::from("router_solicitation"),
116            Icmpv6Type::RouterAdvertisement => String::from("router_advertisement"),
117            Icmpv6Type::NeighborSolicitation => String::from("neighbor_solicitation"),
118            Icmpv6Type::NeighborAdvertisement => String::from("neighbor_advertisement"),
119            Icmpv6Type::RedirectMessage => String::from("redirect_message"),
120            Icmpv6Type::RouterRenumbering => String::from("router_renumbering"),
121            Icmpv6Type::NodeInformationQuery => String::from("node_information_query"),
122            Icmpv6Type::NodeInformationResponse => String::from("node_information_response"),
123            Icmpv6Type::InverseNeighborDiscoverySolicitation => {
124                String::from("inverse_neighbor_discovery_solicitation")
125            }
126            Icmpv6Type::InverseNeighborDiscoveryAdvertisement => {
127                String::from("inverse_neighbor_discovery_advertisement")
128            }
129            Icmpv6Type::Version2MulticastListenerReport => {
130                String::from("version_2_multicast_listener_report")
131            }
132            Icmpv6Type::HomeAgentAddressDiscoveryRequest => {
133                String::from("home_agent_address_discovery_request")
134            }
135            Icmpv6Type::HomeAgentAddressDiscoveryReply => {
136                String::from("home_agent_address_discovery_reply")
137            }
138            Icmpv6Type::MobilePrefixSolicitation => String::from("mobile_prefix_solicitation"),
139            Icmpv6Type::MobilePrefixAdvertisement => String::from("mobile_prefix_advertisement"),
140            Icmpv6Type::CertificationPathSolicitationMessage => {
141                String::from("certification_path_solicitation_message")
142            }
143            Icmpv6Type::CertificationPathAdvertisementMessage => {
144                String::from("certification_path_advertisement_message")
145            }
146            Icmpv6Type::ExperimentalMobilityProtocols => {
147                String::from("experimental_mobility_protocols")
148            }
149            Icmpv6Type::MulticastRouterAdvertisement => {
150                String::from("multicast_router_advertisement")
151            }
152            Icmpv6Type::MulticastRouterSolicitation => {
153                String::from("multicast_router_solicitation")
154            }
155            Icmpv6Type::MulticastRouterTermination => String::from("multicast_router_termination"),
156            Icmpv6Type::FMIPv6Messages => String::from("fmipv6_messages"),
157            Icmpv6Type::RPLControlMessage => String::from("rpl_control_message"),
158            Icmpv6Type::ILNPv6LocatorUpdateMessage => String::from("ilnpv6_locator_update_message"),
159            Icmpv6Type::DuplicateAddressRequest => String::from("duplicate_address_request"),
160            Icmpv6Type::DuplicateAddressConfirmation => {
161                String::from("duplicate_address_confirmation")
162            }
163            Icmpv6Type::MPLControlMessage => String::from("mpl_control_message"),
164            Icmpv6Type::ExtendedEchoRequest => String::from("extended_echo_request"),
165            Icmpv6Type::ExtendedEchoReply => String::from("extended_echo_reply"),
166            Icmpv6Type::Unknown(n) => format!("unknown_{}", n),
167        }
168    }
169    /// Get the name of the ICMPv6 type
170    pub fn name(&self) -> String {
171        match *self {
172            Icmpv6Type::DestinationUnreachable => String::from("Destination Unreachable"),
173            Icmpv6Type::PacketTooBig => String::from("Packet Too Big"),
174            Icmpv6Type::TimeExceeded => String::from("Time Exceeded"),
175            Icmpv6Type::ParameterProblem => String::from("Parameter Problem"),
176            Icmpv6Type::EchoRequest => String::from("Echo Request"),
177            Icmpv6Type::EchoReply => String::from("Echo Reply"),
178            Icmpv6Type::MulticastListenerQuery => String::from("Multicast Listener Query"),
179            Icmpv6Type::MulticastListenerReport => String::from("Multicast Listener Report"),
180            Icmpv6Type::MulticastListenerDone => String::from("Multicast Listener Done"),
181            Icmpv6Type::RouterSolicitation => String::from("Router Solicitation"),
182            Icmpv6Type::RouterAdvertisement => String::from("Router Advertisement"),
183            Icmpv6Type::NeighborSolicitation => String::from("Neighbor Solicitation"),
184            Icmpv6Type::NeighborAdvertisement => String::from("Neighbor Advertisement"),
185            Icmpv6Type::RedirectMessage => String::from("Redirect Message"),
186            Icmpv6Type::RouterRenumbering => String::from("Router Renumbering"),
187            Icmpv6Type::NodeInformationQuery => String::from("Node Information Query"),
188            Icmpv6Type::NodeInformationResponse => String::from("Node Information Response"),
189            Icmpv6Type::InverseNeighborDiscoverySolicitation => {
190                String::from("Inverse Neighbor Discovery Solicitation")
191            }
192            Icmpv6Type::InverseNeighborDiscoveryAdvertisement => {
193                String::from("Inverse Neighbor Discovery Advertisement")
194            }
195            Icmpv6Type::Version2MulticastListenerReport => {
196                String::from("Version 2 Multicast Listener Report")
197            }
198            Icmpv6Type::HomeAgentAddressDiscoveryRequest => {
199                String::from("Home Agent Address Discovery Request")
200            }
201            Icmpv6Type::HomeAgentAddressDiscoveryReply => {
202                String::from("Home Agent Address Discovery Reply")
203            }
204            Icmpv6Type::MobilePrefixSolicitation => String::from("Mobile Prefix Solicitation"),
205            Icmpv6Type::MobilePrefixAdvertisement => String::from("Mobile Prefix Advertisement"),
206            Icmpv6Type::CertificationPathSolicitationMessage => {
207                String::from("Certification Path Solicitation Message")
208            }
209            Icmpv6Type::CertificationPathAdvertisementMessage => {
210                String::from("Certification Path Advertisement Message")
211            }
212            Icmpv6Type::ExperimentalMobilityProtocols => {
213                String::from("Experimental Mobility Protocols")
214            }
215            Icmpv6Type::MulticastRouterAdvertisement => {
216                String::from("Multicast Router Advertisement")
217            }
218            Icmpv6Type::MulticastRouterSolicitation => {
219                String::from("Multicast Router Solicitation")
220            }
221            Icmpv6Type::MulticastRouterTermination => String::from("Multicast Router Termination"),
222            Icmpv6Type::FMIPv6Messages => String::from("FMIPv6 Messages"),
223            Icmpv6Type::RPLControlMessage => String::from("RPL Control Message"),
224            Icmpv6Type::ILNPv6LocatorUpdateMessage => String::from("ILNPv6 Locator Update Message"),
225            Icmpv6Type::DuplicateAddressRequest => String::from("Duplicate Address Request"),
226            Icmpv6Type::DuplicateAddressConfirmation => {
227                String::from("Duplicate Address Confirmation")
228            }
229            Icmpv6Type::MPLControlMessage => String::from("MPL Control Message"),
230            Icmpv6Type::ExtendedEchoRequest => String::from("Extended Echo Request"),
231            Icmpv6Type::ExtendedEchoReply => String::from("Extended Echo Reply"),
232            Icmpv6Type::Unknown(n) => format!("Unknown ({})", n),
233        }
234    }
235    pub(crate) fn from_pnet_type(t: pnet::packet::icmpv6::Icmpv6Type) -> Icmpv6Type {
236        match t {
237            pnet::packet::icmpv6::Icmpv6Types::DestinationUnreachable => {
238                Icmpv6Type::DestinationUnreachable
239            }
240            pnet::packet::icmpv6::Icmpv6Types::PacketTooBig => Icmpv6Type::PacketTooBig,
241            pnet::packet::icmpv6::Icmpv6Types::TimeExceeded => Icmpv6Type::TimeExceeded,
242            pnet::packet::icmpv6::Icmpv6Types::ParameterProblem => Icmpv6Type::ParameterProblem,
243            pnet::packet::icmpv6::Icmpv6Types::EchoRequest => Icmpv6Type::EchoRequest,
244            pnet::packet::icmpv6::Icmpv6Types::EchoReply => Icmpv6Type::EchoReply,
245            pnet::packet::icmpv6::Icmpv6Types::NeighborSolicit => Icmpv6Type::NeighborSolicitation,
246            pnet::packet::icmpv6::Icmpv6Types::NeighborAdvert => Icmpv6Type::NeighborAdvertisement,
247            pnet::packet::icmpv6::Icmpv6Types::RouterSolicit => Icmpv6Type::RouterSolicitation,
248            pnet::packet::icmpv6::Icmpv6Types::RouterAdvert => Icmpv6Type::RouterAdvertisement,
249            _ => Icmpv6Type::Unknown(t.0),
250        }
251    }
252}
253
254/// Represents an ICMPv6 packet.
255#[derive(Clone, Debug, PartialEq)]
256pub struct Icmpv6Packet {
257    /// ICMPv6 type
258    pub icmpv6_type: Icmpv6Type,
259    /// ICMPv6 code
260    pub icmpv6_code: u8,
261    /// ICMPv6 checksum
262    pub checksum: u16,
263    /// Payload
264    pub payload: Vec<u8>,
265}
266
267impl Icmpv6Packet {
268    pub(crate) fn from_pnet_packet(packet: &pnet::packet::icmpv6::Icmpv6Packet) -> Icmpv6Packet {
269        Icmpv6Packet {
270            icmpv6_type: Icmpv6Type::from_pnet_type(packet.get_icmpv6_type()),
271            icmpv6_code: packet.get_icmpv6_code().0,
272            checksum: packet.get_checksum(),
273            payload: packet.payload().to_vec(),
274        }
275    }
276    /// Constructs a new Icmpv6Packet from bytes
277    pub fn from_bytes(packet: &[u8]) -> Icmpv6Packet {
278        let icmpv6_packet = pnet::packet::icmpv6::Icmpv6Packet::new(packet).unwrap();
279        Icmpv6Packet::from_pnet_packet(&icmpv6_packet)
280    }
281}
282
283/// Build ICMPv6 packet
284pub(crate) fn build_icmpv6_echo_packet(
285    icmp_packet: &mut pnet::packet::icmpv6::echo_request::MutableEchoRequestPacket,
286    src_ip: Ipv6Addr,
287    dst_ip: Ipv6Addr,
288) {
289    icmp_packet.set_icmpv6_type(pnet::packet::icmpv6::Icmpv6Types::EchoRequest);
290    icmp_packet.set_identifier(rand::random::<u16>());
291    icmp_packet.set_sequence_number(rand::random::<u16>());
292    let icmpv6_packet = pnet::packet::icmpv6::Icmpv6Packet::new(icmp_packet.packet()).unwrap();
293    let icmpv6_checksum = pnet::packet::icmpv6::checksum(&icmpv6_packet, &src_ip, &dst_ip);
294    //let icmp_check_sum = pnet::packet::util::checksum(&icmp_packet.packet(), 1);
295    icmp_packet.set_checksum(icmpv6_checksum);
296}
297
298/// ICMPv6 Packet Builder
299#[derive(Clone, Debug)]
300pub struct Icmpv6PacketBuilder {
301    /// Source IPv6 address
302    pub src_ip: Ipv6Addr,
303    /// Destination IPv6 address
304    pub dst_ip: Ipv6Addr,
305    /// ICMPv6 type
306    pub icmpv6_type: Icmpv6Type,
307    /// ICMPv6 sequence number
308    pub sequence_number: Option<u16>,
309    /// ICMPv6 identifier
310    pub identifier: Option<u16>,
311}
312
313impl Icmpv6PacketBuilder {
314    /// Constructs a new Icmpv6PacketBuilder
315    pub fn new(src_ip: Ipv6Addr, dst_ip: Ipv6Addr) -> Icmpv6PacketBuilder {
316        Icmpv6PacketBuilder {
317            src_ip,
318            dst_ip,
319            icmpv6_type: Icmpv6Type::EchoRequest,
320            sequence_number: None,
321            identifier: None,
322        }
323    }
324    /// Build ICMPv6 packet and return bytes
325    pub fn build(&self) -> Vec<u8> {
326        let buffer: &mut [u8] = &mut [0u8; ICMPV6_HEADER_LEN];
327        let mut icmp_packet =
328            pnet::packet::icmpv6::echo_request::MutableEchoRequestPacket::new(buffer).unwrap();
329        icmp_packet.set_icmpv6_type(pnet::packet::icmpv6::Icmpv6Type(self.icmpv6_type.number()));
330        icmp_packet.set_identifier(self.identifier.unwrap_or(rand::random::<u16>()));
331        icmp_packet.set_sequence_number(self.sequence_number.unwrap_or(rand::random::<u16>()));
332        let icmpv6_packet = pnet::packet::icmpv6::Icmpv6Packet::new(icmp_packet.packet()).unwrap();
333        let icmpv6_checksum =
334            pnet::packet::icmpv6::checksum(&icmpv6_packet, &self.src_ip, &self.dst_ip);
335        icmp_packet.set_checksum(icmpv6_checksum);
336        icmp_packet.packet().to_vec()
337    }
338}