1use std::net::Ipv4Addr;
2
3use super::{
4 ETH_HEADER_LEN,
5 checksum::{ipv4_header_checksum, tcp_checksum},
6};
7
8#[derive(Debug, Clone, Copy)]
10pub struct TcpFrameParams {
11 pub src_ip: Ipv4Addr,
12 pub dst_ip: Ipv4Addr,
13 pub src_port: u16,
14 pub dst_port: u16,
15 pub seq: u32,
16 pub ack: u32,
17 pub window: u16,
18 pub src_mac: [u8; 6],
19 pub dst_mac: [u8; 6],
20}
21
22#[must_use]
27pub fn build_tcp_ack_frame(p: &TcpFrameParams) -> Vec<u8> {
28 let TcpFrameParams {
29 src_ip,
30 dst_ip,
31 src_port,
32 dst_port,
33 seq,
34 ack,
35 window,
36 src_mac,
37 dst_mac,
38 } = *p;
39 let tcp_hdr_len = 20;
41 let ip_total_len = 20 + tcp_hdr_len;
42 let frame_len = ETH_HEADER_LEN + ip_total_len;
43 let mut frame = vec![0u8; frame_len];
44
45 frame[0..6].copy_from_slice(&dst_mac);
47 frame[6..12].copy_from_slice(&src_mac);
48 frame[12..14].copy_from_slice(&0x0800u16.to_be_bytes());
49
50 let ip = ETH_HEADER_LEN;
52 frame[ip] = 0x45; frame[ip + 2..ip + 4].copy_from_slice(&(ip_total_len as u16).to_be_bytes());
54 frame[ip + 6..ip + 8].copy_from_slice(&0x4000u16.to_be_bytes()); frame[ip + 8] = 64; frame[ip + 9] = 6; frame[ip + 12..ip + 16].copy_from_slice(&src_ip.octets());
58 frame[ip + 16..ip + 20].copy_from_slice(&dst_ip.octets());
59 let ip_cksum = ipv4_header_checksum(&frame[ip..ip + 20]);
60 frame[ip + 10..ip + 12].copy_from_slice(&ip_cksum.to_be_bytes());
61
62 let tcp = ip + 20;
64 frame[tcp..tcp + 2].copy_from_slice(&src_port.to_be_bytes());
65 frame[tcp + 2..tcp + 4].copy_from_slice(&dst_port.to_be_bytes());
66 frame[tcp + 4..tcp + 8].copy_from_slice(&seq.to_be_bytes());
67 frame[tcp + 8..tcp + 12].copy_from_slice(&ack.to_be_bytes());
68 frame[tcp + 12] = 0x50; frame[tcp + 13] = 0x10; frame[tcp + 14..tcp + 16].copy_from_slice(&window.to_be_bytes());
71 let tcp_cksum = tcp_checksum(src_ip, dst_ip, &frame[tcp..]);
72 frame[tcp + 16..tcp + 18].copy_from_slice(&tcp_cksum.to_be_bytes());
73
74 frame
75}
76
77#[must_use]
82pub fn build_tcp_data_frame(p: &TcpFrameParams, payload: &[u8]) -> Vec<u8> {
83 let TcpFrameParams {
84 src_ip,
85 dst_ip,
86 src_port,
87 dst_port,
88 seq,
89 ack,
90 window,
91 src_mac,
92 dst_mac,
93 } = *p;
94
95 let tcp_hdr_len = 20;
96 let tcp_total_len = tcp_hdr_len + payload.len();
97 let ip_total_len = 20 + tcp_total_len;
98 assert!(
102 u16::try_from(ip_total_len).is_ok(),
103 "build_tcp_data_frame: ip_total_len={ip_total_len} overflows u16"
104 );
105 let frame_len = ETH_HEADER_LEN + ip_total_len;
106 let mut frame = vec![0u8; frame_len];
107
108 frame[0..6].copy_from_slice(&dst_mac);
110 frame[6..12].copy_from_slice(&src_mac);
111 frame[12..14].copy_from_slice(&0x0800u16.to_be_bytes());
112
113 let ip = ETH_HEADER_LEN;
115 frame[ip] = 0x45;
116 frame[ip + 2..ip + 4].copy_from_slice(&(ip_total_len as u16).to_be_bytes());
117 frame[ip + 6..ip + 8].copy_from_slice(&0x4000u16.to_be_bytes()); frame[ip + 8] = 64; frame[ip + 9] = 6; frame[ip + 12..ip + 16].copy_from_slice(&src_ip.octets());
121 frame[ip + 16..ip + 20].copy_from_slice(&dst_ip.octets());
122 let ip_cksum = ipv4_header_checksum(&frame[ip..ip + 20]);
123 frame[ip + 10..ip + 12].copy_from_slice(&ip_cksum.to_be_bytes());
124
125 let tcp = ip + 20;
127 frame[tcp..tcp + 2].copy_from_slice(&src_port.to_be_bytes());
128 frame[tcp + 2..tcp + 4].copy_from_slice(&dst_port.to_be_bytes());
129 frame[tcp + 4..tcp + 8].copy_from_slice(&seq.to_be_bytes());
130 frame[tcp + 8..tcp + 12].copy_from_slice(&ack.to_be_bytes());
131 frame[tcp + 12] = 0x50; frame[tcp + 13] = 0x18; frame[tcp + 14..tcp + 16].copy_from_slice(&window.to_be_bytes());
134
135 frame[tcp + 20..].copy_from_slice(payload);
137
138 let tcp_cksum = tcp_checksum(src_ip, dst_ip, &frame[tcp..]);
140 frame[tcp + 16..tcp + 18].copy_from_slice(&tcp_cksum.to_be_bytes());
141
142 frame
143}
144
145#[must_use]
151pub fn build_tcp_data_frame_partial_csum(p: &TcpFrameParams, payload: &[u8]) -> Vec<u8> {
152 let TcpFrameParams {
153 src_ip,
154 dst_ip,
155 src_port,
156 dst_port,
157 seq,
158 ack,
159 window,
160 src_mac,
161 dst_mac,
162 } = *p;
163
164 let tcp_hdr_len = 20;
165 let tcp_total_len = tcp_hdr_len + payload.len();
166 let ip_total_len = 20 + tcp_total_len;
167 assert!(
171 u16::try_from(ip_total_len).is_ok(),
172 "build_tcp_data_frame_partial_csum: ip_total_len={ip_total_len} overflows u16"
173 );
174 let frame_len = ETH_HEADER_LEN + ip_total_len;
175 let mut frame = vec![0u8; frame_len];
176
177 frame[0..6].copy_from_slice(&dst_mac);
179 frame[6..12].copy_from_slice(&src_mac);
180 frame[12..14].copy_from_slice(&0x0800u16.to_be_bytes());
181
182 let ip = ETH_HEADER_LEN;
184 frame[ip] = 0x45;
185 frame[ip + 2..ip + 4].copy_from_slice(&(ip_total_len as u16).to_be_bytes());
186 frame[ip + 6..ip + 8].copy_from_slice(&0x4000u16.to_be_bytes()); frame[ip + 8] = 64; frame[ip + 9] = 6; frame[ip + 12..ip + 16].copy_from_slice(&src_ip.octets());
190 frame[ip + 16..ip + 20].copy_from_slice(&dst_ip.octets());
191 let ip_cksum = ipv4_header_checksum(&frame[ip..ip + 20]);
192 frame[ip + 10..ip + 12].copy_from_slice(&ip_cksum.to_be_bytes());
193
194 let tcp = ip + 20;
196 frame[tcp..tcp + 2].copy_from_slice(&src_port.to_be_bytes());
197 frame[tcp + 2..tcp + 4].copy_from_slice(&dst_port.to_be_bytes());
198 frame[tcp + 4..tcp + 8].copy_from_slice(&seq.to_be_bytes());
199 frame[tcp + 8..tcp + 12].copy_from_slice(&ack.to_be_bytes());
200 frame[tcp + 12] = 0x50; frame[tcp + 13] = 0x18; frame[tcp + 14..tcp + 16].copy_from_slice(&window.to_be_bytes());
203
204 frame[tcp + 20..].copy_from_slice(payload);
206
207 let pseudo_cksum = tcp_pseudo_header_checksum(src_ip, dst_ip, tcp_total_len);
210 frame[tcp + 16..tcp + 18].copy_from_slice(&pseudo_cksum.to_be_bytes());
211
212 frame
213}
214
215#[must_use]
219pub fn tcp_pseudo_header_checksum(src_ip: Ipv4Addr, dst_ip: Ipv4Addr, tcp_len: usize) -> u16 {
220 let mut sum: u32 = 0;
221 let src = src_ip.octets();
222 let dst = dst_ip.octets();
223 sum += u32::from(u16::from_be_bytes([src[0], src[1]]));
224 sum += u32::from(u16::from_be_bytes([src[2], src[3]]));
225 sum += u32::from(u16::from_be_bytes([dst[0], dst[1]]));
226 sum += u32::from(u16::from_be_bytes([dst[2], dst[3]]));
227 sum += 6u32; sum += tcp_len as u32;
229 while sum > 0xFFFF {
230 sum = (sum & 0xFFFF) + (sum >> 16);
231 }
232 !sum as u16
233}
234
235#[must_use]
237pub fn build_tcp_fin_frame(p: &TcpFrameParams) -> Vec<u8> {
238 let mut ack_params = *p;
239 ack_params.window = 65535;
240 let mut frame = build_tcp_ack_frame(&ack_params);
241 let tcp = ETH_HEADER_LEN + 20;
243 frame[tcp + 13] = 0x11; frame[tcp + 16..tcp + 18].copy_from_slice(&[0, 0]);
246 let tcp_cksum = tcp_checksum(p.src_ip, p.dst_ip, &frame[tcp..]);
247 frame[tcp + 16..tcp + 18].copy_from_slice(&tcp_cksum.to_be_bytes());
248 frame
249}
250
251#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
256pub struct TcpSynOptions {
257 pub mss: Option<u16>,
261 pub wscale: Option<u8>,
263 pub sack_permitted: bool,
265 pub timestamps: bool,
269}
270
271#[must_use]
279pub fn parse_tcp_syn_options(tcp_segment: &[u8]) -> TcpSynOptions {
280 let mut opts = TcpSynOptions::default();
281 if tcp_segment.len() < 20 {
282 return opts;
283 }
284 let data_offset = usize::from(tcp_segment[12] >> 4) * 4;
285 if data_offset < 20 || data_offset > tcp_segment.len() {
286 return opts;
287 }
288 let options = &tcp_segment[20..data_offset];
289 let mut i = 0;
290 while i < options.len() {
291 let kind = options[i];
292 match kind {
293 0 => break, 1 => {
295 i += 1;
296 } 2 => {
298 if i + 4 > options.len() || options[i + 1] != 4 {
300 break;
301 }
302 opts.mss = Some(u16::from_be_bytes([options[i + 2], options[i + 3]]));
303 i += 4;
304 }
305 3 => {
306 if i + 3 > options.len() || options[i + 1] != 3 {
308 break;
309 }
310 opts.wscale = Some(options[i + 2]);
311 i += 3;
312 }
313 4 => {
314 if i + 2 > options.len() || options[i + 1] != 2 {
316 break;
317 }
318 opts.sack_permitted = true;
319 i += 2;
320 }
321 8 => {
322 if i + 10 > options.len() || options[i + 1] != 10 {
324 break;
325 }
326 opts.timestamps = true;
327 i += 10;
328 }
329 _ => {
330 if i + 1 >= options.len() {
332 break;
333 }
334 let len = usize::from(options[i + 1]);
335 if len < 2 || i + len > options.len() {
336 break;
337 }
338 i += len;
339 }
340 }
341 }
342 opts
343}
344
345#[derive(Debug, Clone, Copy)]
352pub struct SynAckParams {
353 pub src_ip: Ipv4Addr,
354 pub dst_ip: Ipv4Addr,
355 pub src_port: u16,
356 pub dst_port: u16,
357 pub seq: u32,
359 pub ack: u32,
361 pub src_mac: [u8; 6],
362 pub dst_mac: [u8; 6],
363 pub mss: u16,
365 pub wscale: Option<u8>,
368 pub sack_permitted: bool,
370}
371
372#[must_use]
378pub fn build_tcp_syn_ack_frame(p: &SynAckParams) -> Vec<u8> {
379 let mut options: Vec<u8> = Vec::with_capacity(16);
381
382 options.push(2);
384 options.push(4);
385 options.extend_from_slice(&p.mss.to_be_bytes());
386
387 if p.sack_permitted {
390 options.push(4);
391 options.push(2);
392 }
393
394 if let Some(shift) = p.wscale {
396 options.push(3);
397 options.push(3);
398 options.push(shift);
399 }
400
401 while !options.len().is_multiple_of(4) {
402 options.push(1); }
404
405 let tcp_hdr_len = 20 + options.len();
406 let ip_total_len = 20 + tcp_hdr_len;
407 let frame_len = ETH_HEADER_LEN + ip_total_len;
408 let mut frame = vec![0u8; frame_len];
409
410 frame[0..6].copy_from_slice(&p.dst_mac);
412 frame[6..12].copy_from_slice(&p.src_mac);
413 frame[12..14].copy_from_slice(&0x0800u16.to_be_bytes());
414
415 let ip = ETH_HEADER_LEN;
417 frame[ip] = 0x45;
418 frame[ip + 2..ip + 4].copy_from_slice(&(ip_total_len as u16).to_be_bytes());
419 frame[ip + 6..ip + 8].copy_from_slice(&0x4000u16.to_be_bytes()); frame[ip + 8] = 64;
421 frame[ip + 9] = 6; frame[ip + 12..ip + 16].copy_from_slice(&p.src_ip.octets());
423 frame[ip + 16..ip + 20].copy_from_slice(&p.dst_ip.octets());
424 let ip_cksum = ipv4_header_checksum(&frame[ip..ip + 20]);
425 frame[ip + 10..ip + 12].copy_from_slice(&ip_cksum.to_be_bytes());
426
427 let tcp = ip + 20;
429 frame[tcp..tcp + 2].copy_from_slice(&p.src_port.to_be_bytes());
430 frame[tcp + 2..tcp + 4].copy_from_slice(&p.dst_port.to_be_bytes());
431 frame[tcp + 4..tcp + 8].copy_from_slice(&p.seq.to_be_bytes());
432 frame[tcp + 8..tcp + 12].copy_from_slice(&p.ack.to_be_bytes());
433 frame[tcp + 12] = ((tcp_hdr_len / 4) as u8) << 4;
434 frame[tcp + 13] = 0x12; frame[tcp + 14..tcp + 16].copy_from_slice(&65535u16.to_be_bytes());
436 frame[tcp + 20..tcp + 20 + options.len()].copy_from_slice(&options);
437
438 let tcp_cksum = tcp_checksum(p.src_ip, p.dst_ip, &frame[tcp..]);
439 frame[tcp + 16..tcp + 18].copy_from_slice(&tcp_cksum.to_be_bytes());
440
441 frame
442}
443
444#[derive(Debug, Clone, Copy)]
450pub struct SynParams {
451 pub src_ip: Ipv4Addr,
452 pub dst_ip: Ipv4Addr,
453 pub src_port: u16,
454 pub dst_port: u16,
455 pub seq: u32,
456 pub src_mac: [u8; 6],
457 pub dst_mac: [u8; 6],
458 pub mss: u16,
459 pub wscale: Option<u8>,
460}
461
462#[must_use]
464pub fn build_tcp_syn_frame(p: &SynParams) -> Vec<u8> {
465 let mut options: Vec<u8> = Vec::with_capacity(12);
466
467 options.push(2);
469 options.push(4);
470 options.extend_from_slice(&p.mss.to_be_bytes());
471
472 options.push(4);
474 options.push(2);
475
476 if let Some(shift) = p.wscale {
477 options.push(3);
478 options.push(3);
479 options.push(shift);
480 }
481
482 while !options.len().is_multiple_of(4) {
483 options.push(1);
484 }
485
486 let tcp_hdr_len = 20 + options.len();
487 let ip_total_len = 20 + tcp_hdr_len;
488 let frame_len = ETH_HEADER_LEN + ip_total_len;
489 let mut frame = vec![0u8; frame_len];
490
491 frame[0..6].copy_from_slice(&p.dst_mac);
492 frame[6..12].copy_from_slice(&p.src_mac);
493 frame[12..14].copy_from_slice(&0x0800u16.to_be_bytes());
494
495 let ip = ETH_HEADER_LEN;
496 frame[ip] = 0x45;
497 frame[ip + 2..ip + 4].copy_from_slice(&(ip_total_len as u16).to_be_bytes());
498 frame[ip + 6..ip + 8].copy_from_slice(&0x4000u16.to_be_bytes());
499 frame[ip + 8] = 64;
500 frame[ip + 9] = 6;
501 frame[ip + 12..ip + 16].copy_from_slice(&p.src_ip.octets());
502 frame[ip + 16..ip + 20].copy_from_slice(&p.dst_ip.octets());
503 let ip_cksum = ipv4_header_checksum(&frame[ip..ip + 20]);
504 frame[ip + 10..ip + 12].copy_from_slice(&ip_cksum.to_be_bytes());
505
506 let tcp = ip + 20;
507 frame[tcp..tcp + 2].copy_from_slice(&p.src_port.to_be_bytes());
508 frame[tcp + 2..tcp + 4].copy_from_slice(&p.dst_port.to_be_bytes());
509 frame[tcp + 4..tcp + 8].copy_from_slice(&p.seq.to_be_bytes());
510 frame[tcp + 12] = ((tcp_hdr_len / 4) as u8) << 4;
512 frame[tcp + 13] = 0x02; frame[tcp + 14..tcp + 16].copy_from_slice(&65535u16.to_be_bytes());
514 frame[tcp + 20..tcp + 20 + options.len()].copy_from_slice(&options);
515
516 let tcp_cksum = tcp_checksum(p.src_ip, p.dst_ip, &frame[tcp..]);
517 frame[tcp + 16..tcp + 18].copy_from_slice(&tcp_cksum.to_be_bytes());
518
519 frame
520}
521
522#[must_use]
524pub fn build_tcp_rst_frame(p: &TcpFrameParams) -> Vec<u8> {
525 let mut rst_params = *p;
526 rst_params.window = 0;
527 let mut frame = build_tcp_ack_frame(&rst_params);
528 let tcp = ETH_HEADER_LEN + 20;
530 frame[tcp + 13] = 0x14; frame[tcp + 16..tcp + 18].copy_from_slice(&[0, 0]);
532 let tcp_cksum = tcp_checksum(p.src_ip, p.dst_ip, &frame[tcp..]);
533 frame[tcp + 16..tcp + 18].copy_from_slice(&tcp_cksum.to_be_bytes());
534 frame
535}