1use crate::custom_module::manycastr::{Address, address};
2use crate::net::{IPv4Packet, PacketPayload};
3use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
4use std::io::{Cursor, Write};
5
6#[derive(Debug)]
8pub struct ICMPPacket {
9 pub icmp_type: u8,
10 pub code: u8,
11 pub checksum: u16,
12 pub icmp_identifier: u16,
13 pub sequence_number: u16,
14 pub payload: Vec<u8>,
15}
16
17impl From<&[u8]> for ICMPPacket {
19 fn from(data: &[u8]) -> Self {
20 let mut data = Cursor::new(data);
21 ICMPPacket {
22 icmp_type: data.read_u8().unwrap(),
23 code: data.read_u8().unwrap(),
24 checksum: data.read_u16::<NetworkEndian>().unwrap(),
25 icmp_identifier: data.read_u16::<NetworkEndian>().unwrap(),
26 sequence_number: data.read_u16::<NetworkEndian>().unwrap(),
27 payload: data.into_inner()[8..].to_vec(),
28 }
29 }
30}
31
32impl From<&ICMPPacket> for Vec<u8> {
34 fn from(packet: &ICMPPacket) -> Self {
35 let mut wtr = vec![];
36 wtr.write_u8(packet.icmp_type)
37 .expect("Unable to write to byte buffer for ICMP packet");
38 wtr.write_u8(packet.code)
39 .expect("Unable to write to byte buffer for ICMP packet");
40 wtr.write_u16::<NetworkEndian>(packet.checksum)
41 .expect("Unable to write to byte buffer for ICMP packet");
42 wtr.write_u16::<NetworkEndian>(packet.icmp_identifier)
43 .expect("Unable to write to byte buffer for ICMP packet");
44 wtr.write_u16::<NetworkEndian>(packet.sequence_number)
45 .expect("Unable to write to byte buffer for ICMP packet");
46 wtr.write_all(&packet.payload)
47 .expect("Unable to write to byte buffer for ICMP packet");
48 wtr
49 }
50}
51
52impl ICMPPacket {
53 pub fn echo_request(
63 icmp_identifier: u16,
64 sequence_number: u16,
65 body: Vec<u8>,
66 src: &Address,
67 dst: &Address,
68 ttl: u8,
69 ) -> Vec<u8> {
70 let body_len = body.len() as u16;
71
72 match (src.value, dst.value) {
73 (Some(address::Value::V4(src)), Some(address::Value::V4(dst))) => {
74 let mut packet = ICMPPacket {
75 icmp_type: 8, code: 0,
77 checksum: 0,
78 icmp_identifier,
79 sequence_number,
80 payload: body,
81 };
82
83 let icmp_bytes: Vec<u8> = (&packet).into();
84 packet.checksum = ICMPPacket::calc_checksum(&icmp_bytes);
85
86 let v4_packet = IPv4Packet {
87 length: 20 + 8 + body_len,
88 identifier: 15037,
89 ttl,
90 src,
91 dst,
92 payload: PacketPayload::Icmp { value: packet },
93 };
94 (&v4_packet).into()
95 }
96
97 (Some(address::Value::V6(src)), Some(address::Value::V6(dst))) => {
98 let src_u128 = (src.high as u128) << 64 | (src.low as u128);
99 let dst_u128 = (dst.high as u128) << 64 | (dst.low as u128);
100 let mut packet = ICMPPacket {
101 icmp_type: 128,
102 code: 0,
103 checksum: 0,
104 icmp_identifier,
105 sequence_number,
106 payload: body,
107 };
108 let icmp_bytes: Vec<u8> = (&packet).into();
109
110 let mut pseudo = Vec::new();
112 pseudo.write_u128::<NetworkEndian>(src_u128).unwrap();
113 pseudo.write_u128::<NetworkEndian>(dst_u128).unwrap();
114 pseudo
115 .write_u32::<NetworkEndian>((8 + packet.payload.len()) as u32)
116 .unwrap();
117 pseudo.extend_from_slice(&[0, 0, 0, 58]);
118 pseudo.extend(icmp_bytes);
119
120 packet.checksum = ICMPPacket::calc_checksum(&pseudo);
121
122 (&packet).into()
123 }
124
125 _ => panic!("Source and Destination IP versions must match"),
126 }
127 }
128
129 pub(crate) fn calc_checksum(buffer: &[u8]) -> u16 {
134 let mut sum: u32 = 0;
135 let len = buffer.len();
136
137 let mut i = 0;
139 while i < len - 1 {
140 let word = ((buffer[i] as u32) << 8) | (buffer[i + 1] as u32);
141 sum += word;
142 i += 2;
143 }
144
145 if !len.is_multiple_of(2) {
147 sum += (buffer[len - 1] as u32) << 8;
148 }
149
150 while sum >> 16 > 0 {
152 sum = (sum & 0xffff) + (sum >> 16);
153 }
154
155 !sum as u16
157 }
158}