async_traceroute/traceroute/utils/
packet_utils.rs

1use 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(); // todo
177    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(); // todo
183    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(); // todo
190    let ips = &first_interface.ips;
191    let ip_addr = ips.get(0).unwrap().ip(); // todo
192    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!(""), // todo
222        IpAddr::V6(ipv6_addr) => ipv6_addr
223    }
224}