async_traceroute/traceroute/utils/
packet_utils.rs1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2use std::time::UNIX_EPOCH;
3
4use pnet::datalink::{interfaces, NetworkInterface};
5use pnet::packet::FromPacket;
6use pnet::packet::icmp::{Icmp, IcmpCode, IcmpPacket, IcmpType};
7use pnet::packet::icmp::echo_request::{EchoRequest, EchoRequestPacket};
8use pnet::packet::ipv4::{Ipv4, Ipv4Packet};
9use pnet::packet::ipv6::Ipv6;
10use pnet::packet::tcp::{ipv4_checksum, Tcp, TcpOption, TcpPacket};
11use pnet::packet::udp::{Udp, UdpPacket};
12
13use crate::traceroute::utils::bytes::ToBytes;
14
15const TCP_SYN_ACK: u8 = 18;
16
17pub enum IpDatagram {
18 V4(Ipv4), V6(Ipv6)
19}
20
21impl IpDatagram {
22 pub const STANDARD_HEADER_LENGTH: u16 = 20;
23
24 pub fn set_payload(&mut self, data: &[u8]) {
25 let data_to_vec = data.to_vec();
26 match self {
27 IpDatagram::V4(ipv4_datagram) => {
28 ipv4_datagram.payload = data_to_vec;
29 },
30 IpDatagram::V6(ipv6_datagram) => {
31 ipv6_datagram.payload = data_to_vec;
32 }
33 }
34 }
35
36 pub fn set_length(&mut self, length: u16) {
37 match self {
38 IpDatagram::V4(ipv4_datagram) => {
39 ipv4_datagram.total_length = length;
40 },
41 IpDatagram::V6(ipv6_datagram) => {
42 ipv6_datagram.payload_length = length;
43 }
44 }
45 }
46}
47
48pub fn build_ipv4_datagram_from_bytes(data: &[u8]) -> Option<Ipv4> {
49 let ipv4packet = Ipv4Packet::new(&data)?;
50 Some(ipv4packet.from_packet())
51}
52
53pub fn build_icmpv4_packet_from_bytes(data: &[u8]) -> Option<Icmp> {
54 let icmp_packet = IcmpPacket::new(data)?;
55 Some(icmp_packet.from_packet())
56}
57
58pub fn build_tcp_segment_from_bytes(data: &[u8]) -> Option<Tcp> {
59 let tcp_packet = TcpPacket::new(data)?;
60 Some(tcp_packet.from_packet())
61}
62
63pub fn is_tcp_syn_ack_segment(tcp_segment: &Tcp) -> bool {
64 tcp_segment.flags == TCP_SYN_ACK
65}
66
67pub fn is_icmp_ttl_expired(icmp_packet: &Icmp) -> bool {
68 let icmp_type = icmp_packet.icmp_type.0;
69 let icmp_code = icmp_packet.icmp_code.0;
70 icmp_type == 11 && icmp_code == 0
71}
72
73pub fn is_icmp_destination_port_unreachable(icmp_packet: &Icmp) -> bool {
74 let icmp_type = icmp_packet.icmp_type.0;
75 let icmp_code = icmp_packet.icmp_code.0;
76 icmp_type == 3 && icmp_code == 3
77}
78
79pub fn is_icmp_echo_reply(icmp_packet: &Icmp) -> bool {
80 let icmp_type = icmp_packet.icmp_type.0;
81 let icmp_code = icmp_packet.icmp_code.0;
82 icmp_type == 0 && icmp_code == 0
83}
84
85pub fn extract_ipv4_header_from_icmp_error_response(icmp_packet: &Icmp) -> Option<Ipv4> {
86 let payload = &icmp_packet.payload;
87 let payload: Vec<u8> = payload
88 .into_iter()
89 .skip_while(|byte| **byte != 69)
90 .map(|byte| *byte)
91 .collect();
92
93 build_ipv4_datagram_from_bytes(&payload[..20])
94}
95
96pub fn extract_icmp_ping_from_icmp_error_response(icmp_packet: &Icmp) -> Option<EchoRequest> {
97 let payload = &icmp_packet.payload;
98 let payload: Vec<u8> = payload
99 .into_iter()
100 .skip(24)
101 .map(|byte| *byte)
102 .collect();
103
104 let echo_request_packet = EchoRequestPacket::new(&payload)?;
105 Some(echo_request_packet.from_packet())
106}
107
108pub fn extract_udp_header_from_icmp_error_response(icmp_packet: &Icmp) -> Option<Udp> {
109 let payload = &icmp_packet.payload;
110 let payload: Vec<u8> = payload
111 .into_iter()
112 .skip_while(|byte| **byte != 69)
113 .map(|byte| *byte)
114 .collect();
115
116 let udp_packet = UdpPacket::new(&payload[20..28])?;
117 Some(udp_packet.from_packet())
118}
119
120pub fn build_udp_datagram_with_ports(source_port: u16, destination_port: u16) -> Udp {
121 Udp {
122 source: source_port,
123 destination: destination_port,
124 length: 8,
125 checksum: 0,
126 payload: vec![]
127 }
128}
129
130pub fn build_tcp_syn_segment(source_port: u16, destination_port: u16, isn: u32) -> Tcp {
131 Tcp {
132 source: source_port,
133 destination: destination_port,
134 sequence: isn,
135 acknowledgement: 0,
136 data_offset: 10,
137 reserved: 0,
138 flags: 2,
139 window: 5840,
140 checksum: 0,
141 urgent_ptr: 0,
142 options: vec![
143 TcpOption::mss(1460),
144 TcpOption::sack_perm(),
145 TcpOption::timestamp(UNIX_EPOCH.elapsed().unwrap().subsec_millis(), 0),
146 TcpOption::nop(),
147 TcpOption::wscale(2),
148 ],
149 payload: vec![],
150 }
151}
152
153pub fn build_icmpv4_echo_request(id: u16, sqn: u16) -> Icmp {
154 let mut payload = Vec::with_capacity(4);
155 payload.extend_from_slice(id.to_be_bytes().as_ref());
156 payload.extend_from_slice(sqn.to_be_bytes().as_ref());
157 Icmp {
158 icmp_type: IcmpType(8),
159 icmp_code: IcmpCode(0),
160 checksum: 0,
161 payload,
162 }
163}
164
165pub fn internet_checksum(tcp_segment: &Tcp, ip_datagram: &IpDatagram) -> u16 {
166 match ip_datagram {
167 IpDatagram::V4(ipv4_datagram) => {
168 internet_checksum_ipv4(tcp_segment, ipv4_datagram)
169 }
170 IpDatagram::V6(ipv6_datagram) => todo!()
171 }
172}
173
174fn internet_checksum_ipv4(tcp_segment: &Tcp, ipv4_datagram: &Ipv4) -> u16 {
175 let tcp_segment_bytes = tcp_segment.to_bytes();
176 let tcp_packet = TcpPacket::new(&tcp_segment_bytes).unwrap(); ipv4_checksum(&tcp_packet, &ipv4_datagram.source, &ipv4_datagram.destination)
178}
179
180pub fn icmpv4_checksum(icmp: &Icmp) -> u16 {
181 let icmp_bytes = icmp.to_bytes();
182 let icmp_packet = IcmpPacket::new(&icmp_bytes).unwrap(); pnet::packet::icmp::checksum(&icmp_packet)
184}
185
186pub fn get_default_ipv4_addr_interface() -> Ipv4Addr {
187 let interfaces = interfaces();
188
189 let first_interface = interfaces.get(1).unwrap(); let ips = &first_interface.ips;
191 let ip_addr = ips.get(0).unwrap().ip(); match ip_addr {
193 IpAddr::V4(ipv4_addr) => ipv4_addr,
194 IpAddr::V6(_ipv6_addr) => panic!("")
195 }
196}
197
198pub fn default_interface() -> Option<NetworkInterface> {
199 interfaces()
200 .iter()
201 .find(|e| e. is_up() && !e. is_loopback() && !e. ips. is_empty())
202 .cloned()
203}
204
205pub fn get_interface(interface: &str) -> Option<NetworkInterface> {
206 for network_interface in interfaces() {
207 if &network_interface.name == interface {
208 return Some(network_interface);
209 }
210 }
211
212 None
213}
214
215pub fn get_default_ipv6_addr_interface() -> Ipv6Addr {
216 let interfaces = interfaces();
217 let first_interface = interfaces.get(1).unwrap();
218 let ips = &first_interface.ips;
219 let ip_addr = ips.get(0).unwrap().ip();
220 match ip_addr {
221 IpAddr::V4(_ipv4_addr) => panic!(""), IpAddr::V6(ipv6_addr) => ipv6_addr
223 }
224}