1 use crate::{ 2 err::{ValueTooBigError, ValueType}, 3 *, 4 }; 5 6 /// A slice containing an tcp header of a network package. 7 #[derive(Clone, Debug, Eq, PartialEq)] 8 pub struct TcpHeaderSlice<'a> { 9 pub(crate) slice: &'a [u8], 10 } 11 12 impl<'a> TcpHeaderSlice<'a> { 13 /// Creates a slice containing an tcp header. from_slice(slice: &'a [u8]) -> Result<TcpHeaderSlice<'a>, err::tcp::HeaderSliceError>14 pub fn from_slice(slice: &'a [u8]) -> Result<TcpHeaderSlice<'a>, err::tcp::HeaderSliceError> { 15 use err::tcp::{HeaderError::*, HeaderSliceError::*}; 16 17 //check length 18 if slice.len() < TcpHeader::MIN_LEN { 19 return Err(Len(err::LenError { 20 required_len: TcpHeader::MIN_LEN, 21 len: slice.len(), 22 len_source: LenSource::Slice, 23 layer: err::Layer::TcpHeader, 24 layer_start_offset: 0, 25 })); 26 } 27 28 // SAFETY: 29 // Safe as it is checked at the start of the function that the 30 // length of the slice is at least TcpHeader::MIN_LEN (20). 31 let header_len = unsafe { 32 // The length of the TCP header can be determined via 33 // the data offset field of the TCP header. "data offset" 34 // stores the offset in 4 byte steps from the start of the 35 // header to the payload of the header. 36 // 37 // "data offset" is stored in the upper 4 bits 38 // (aka 0b1111_0000) of byte 12. To get to total length 39 // in bytes of the header data offset has to be multiplied 40 // by 4. So the naive version to get the length of 41 // the header would be: 42 // 43 // ``` 44 // let data_offset = (*slice.get_unchecked(12) & 0xf0) >> 4; 45 // let len = data_offset * 4; 46 // ``` 47 // 48 // But a multiplication by 4 can be replaced by 2 49 // left shift: 50 // 51 // ``` 52 // let data_offset = (*slice.get_unchecked(12) & 0xf0) >> 4; 53 // let len = data_offset << 2; 54 // ``` 55 // 56 // And finally the shifts can be combined to one: 57 // 58 // ``` 59 // let len = (*slice.get_unchecked(12) & 0xf0) >> 2; 60 // ``` 61 usize::from((*slice.get_unchecked(12) & 0xf0) >> 2) 62 }; 63 64 if header_len < TcpHeader::MIN_LEN { 65 Err(Content(DataOffsetTooSmall { 66 data_offset: (header_len >> 2) as u8, 67 })) 68 } else if slice.len() < header_len { 69 Err(Len(err::LenError { 70 required_len: header_len, 71 len: slice.len(), 72 len_source: LenSource::Slice, 73 layer: err::Layer::TcpHeader, 74 layer_start_offset: 0, 75 })) 76 } else { 77 //done 78 Ok(TcpHeaderSlice::<'a> { 79 // SAFETY: 80 // Safe as there is a check above that the slice length 81 // is at least len. 82 slice: unsafe { core::slice::from_raw_parts(slice.as_ptr(), header_len) }, 83 }) 84 } 85 } 86 87 /// Returns the slice containing the tcp header 88 #[inline] slice(&self) -> &'a [u8]89 pub fn slice(&self) -> &'a [u8] { 90 self.slice 91 } 92 93 /// Read the source port number. 94 #[inline] source_port(&self) -> u1695 pub fn source_port(&self) -> u16 { 96 // SAFETY: 97 // Constructor checks that the slice has at least the length 98 // of 20. 99 unsafe { get_unchecked_be_u16(self.slice.as_ptr()) } 100 } 101 102 /// Read the destination port number. 103 #[inline] destination_port(&self) -> u16104 pub fn destination_port(&self) -> u16 { 105 // SAFETY: 106 // Constructor checks that the slice has at least the length 107 // of 20. 108 unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(2)) } 109 } 110 111 /// Read the sequence number of the first data octet in this segment (except when SYN is present). 112 /// 113 /// If SYN is present the sequence number is the initial sequence number (ISN) 114 /// and the first data octet is ISN+1. 115 /// \[copied from RFC 793, page 16\] 116 #[inline] sequence_number(&self) -> u32117 pub fn sequence_number(&self) -> u32 { 118 // SAFETY: 119 // Constructor checks that the slice has at least the length 120 // of 20. 121 unsafe { get_unchecked_be_u32(self.slice.as_ptr().add(4)) } 122 } 123 124 /// Reads the acknowledgment number. 125 /// 126 /// If the ACK control bit is set this field contains the value of the 127 /// next sequence number the sender of the segment is expecting to 128 /// receive. 129 /// 130 /// Once a connection is established this is always sent. 131 #[inline] acknowledgment_number(&self) -> u32132 pub fn acknowledgment_number(&self) -> u32 { 133 // SAFETY: 134 // Constructor checks that the slice has at least the length 135 // of 20. 136 unsafe { get_unchecked_be_u32(self.slice.as_ptr().add(8)) } 137 } 138 139 /// Read the number of 32 bit words in the TCP Header. 140 /// 141 /// This indicates where the data begins. The TCP header (even one including options) is an 142 /// integral number of 32 bits long. 143 #[inline] data_offset(&self) -> u8144 pub fn data_offset(&self) -> u8 { 145 // SAFETY: 146 // Constructor checks that the slice has at least the length 147 // of 20. 148 unsafe { (*self.slice.get_unchecked(12) & 0b1111_0000) >> 4 } 149 } 150 151 /// ECN-nonce - concealment protection (experimental: see RFC 3540) 152 #[inline] ns(&self) -> bool153 pub fn ns(&self) -> bool { 154 // SAFETY: 155 // Constructor checks that the slice has at least the length 156 // of 20. 157 unsafe { 0 != (*self.slice.get_unchecked(12) & 0b0000_0001) } 158 } 159 160 /// Read the fin flag (no more data from sender). 161 #[inline] fin(&self) -> bool162 pub fn fin(&self) -> bool { 163 // SAFETY: 164 // Constructor checks that the slice has at least the length 165 // of 20. 166 unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_0001) } 167 } 168 169 /// Reads the syn flag (synchronize sequence numbers). 170 #[inline] syn(&self) -> bool171 pub fn syn(&self) -> bool { 172 // SAFETY: 173 // Constructor checks that the slice has at least the length 174 // of 20. 175 unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_0010) } 176 } 177 178 /// Reads the rst flag (reset the connection). 179 #[inline] rst(&self) -> bool180 pub fn rst(&self) -> bool { 181 // SAFETY: 182 // Constructor checks that the slice has at least the length 183 // of 20. 184 unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_0100) } 185 } 186 187 /// Reads the psh flag (push function). 188 #[inline] psh(&self) -> bool189 pub fn psh(&self) -> bool { 190 // SAFETY: 191 // Constructor checks that the slice has at least the length 192 // of 20. 193 unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0000_1000) } 194 } 195 196 /// Reads the ack flag (acknowledgment field significant). 197 #[inline] ack(&self) -> bool198 pub fn ack(&self) -> bool { 199 // SAFETY: 200 // Constructor checks that the slice has at least the length 201 // of 20. 202 unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0001_0000) } 203 } 204 205 /// Reads the urg flag (Urgent Pointer field significant). 206 #[inline] urg(&self) -> bool207 pub fn urg(&self) -> bool { 208 // SAFETY: 209 // Constructor checks that the slice has at least the length 210 // of 20. 211 unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0010_0000) } 212 } 213 214 /// Read the ECN-Echo flag (RFC 3168). 215 #[inline] ece(&self) -> bool216 pub fn ece(&self) -> bool { 217 // SAFETY: 218 // Constructor checks that the slice has at least the length 219 // of 20. 220 unsafe { 0 != (*self.slice.get_unchecked(13) & 0b0100_0000) } 221 } 222 223 /// Reads the cwr flag (Congestion Window Reduced). 224 /// 225 /// This flag is set by the sending host to indicate that it received a TCP 226 /// segment with the ECE flag set and had responded in congestion control 227 /// mechanism (added to header by RFC 3168). 228 #[inline] cwr(&self) -> bool229 pub fn cwr(&self) -> bool { 230 // SAFETY: 231 // Constructor checks that the slice has at least the length 232 // of 20. 233 unsafe { 0 != (*self.slice.get_unchecked(13) & 0b1000_0000) } 234 } 235 236 /// The number of data octets beginning with the one indicated in the 237 /// acknowledgment field which the sender of this segment is willing to 238 /// accept. 239 #[inline] window_size(&self) -> u16240 pub fn window_size(&self) -> u16 { 241 u16::from_be_bytes( 242 // SAFETY: 243 // Constructor checks that the slice has at least the length 244 // of 20. 245 unsafe { [*self.slice.get_unchecked(14), *self.slice.get_unchecked(15)] }, 246 ) 247 } 248 249 /// Checksum (16 bit one's complement) of the pseudo ip header, this tcp header and the payload. 250 #[inline] checksum(&self) -> u16251 pub fn checksum(&self) -> u16 { 252 u16::from_be_bytes( 253 // SAFETY: 254 // Constructor checks that the slice has at least the length 255 // of 20. 256 unsafe { [*self.slice.get_unchecked(16), *self.slice.get_unchecked(17)] }, 257 ) 258 } 259 260 /// This field communicates the current value of the urgent pointer as a 261 /// positive offset from the sequence number in this segment. 262 /// 263 /// The urgent pointer points to the sequence number of the octet following 264 /// the urgent data. This field is only be interpreted in segments with 265 /// the URG control bit set. 266 #[inline] urgent_pointer(&self) -> u16267 pub fn urgent_pointer(&self) -> u16 { 268 u16::from_be_bytes( 269 // SAFETY: 270 // Constructor checks that the slice has at least the length 271 // of 20. 272 unsafe { [*self.slice.get_unchecked(18), *self.slice.get_unchecked(19)] }, 273 ) 274 } 275 276 /// Options of the header 277 #[inline] options(&self) -> &[u8]278 pub fn options(&self) -> &[u8] { 279 &self.slice[TcpHeader::MIN_LEN..self.data_offset() as usize * 4] 280 } 281 282 /// Returns an iterator that allows to iterate through all known TCP header options. 283 #[inline] options_iterator(&self) -> TcpOptionsIterator284 pub fn options_iterator(&self) -> TcpOptionsIterator { 285 TcpOptionsIterator::from_slice(self.options()) 286 } 287 288 /// Decode all the fields and copy the results to a TcpHeader struct to_header(&self) -> TcpHeader289 pub fn to_header(&self) -> TcpHeader { 290 TcpHeader { 291 source_port: self.source_port(), 292 destination_port: self.destination_port(), 293 sequence_number: self.sequence_number(), 294 acknowledgment_number: self.acknowledgment_number(), 295 ns: self.ns(), 296 fin: self.fin(), 297 syn: self.syn(), 298 rst: self.rst(), 299 psh: self.psh(), 300 ack: self.ack(), 301 ece: self.ece(), 302 urg: self.urg(), 303 cwr: self.cwr(), 304 window_size: self.window_size(), 305 checksum: self.checksum(), 306 urgent_pointer: self.urgent_pointer(), 307 options: { 308 let options_slice = self.options(); 309 let mut options = TcpOptions { 310 len: options_slice.len() as u8, 311 buf: [0; 40], 312 }; 313 options.buf[..options_slice.len()].clone_from_slice(options_slice); 314 options 315 }, 316 } 317 } 318 319 /// Calculates the TCP header checksum based on a ipv4 header and returns the result. This does NOT set the checksum. calc_checksum_ipv4( &self, ip_header: &Ipv4HeaderSlice, payload: &[u8], ) -> Result<u16, ValueTooBigError<usize>>320 pub fn calc_checksum_ipv4( 321 &self, 322 ip_header: &Ipv4HeaderSlice, 323 payload: &[u8], 324 ) -> Result<u16, ValueTooBigError<usize>> { 325 self.calc_checksum_ipv4_raw(ip_header.source(), ip_header.destination(), payload) 326 } 327 328 /// Calculates the checksum for the current header in ipv4 mode and returns the result. This does NOT set the checksum. calc_checksum_ipv4_raw( &self, source_ip: [u8; 4], destination_ip: [u8; 4], payload: &[u8], ) -> Result<u16, ValueTooBigError<usize>>329 pub fn calc_checksum_ipv4_raw( 330 &self, 331 source_ip: [u8; 4], 332 destination_ip: [u8; 4], 333 payload: &[u8], 334 ) -> Result<u16, ValueTooBigError<usize>> { 335 // check that the total length fits into the field 336 let header_len = self.slice.len() as u16; 337 let max_payload = usize::from(u16::MAX) - usize::from(header_len); 338 if max_payload < payload.len() { 339 return Err(ValueTooBigError { 340 actual: payload.len(), 341 max_allowed: max_payload, 342 value_type: ValueType::TcpPayloadLengthIpv4, 343 }); 344 } 345 346 // calculate the checksum 347 let tcp_len = header_len + (payload.len() as u16); 348 Ok(self.calc_checksum_post_ip( 349 checksum::Sum16BitWords::new() 350 .add_4bytes(source_ip) 351 .add_4bytes(destination_ip) 352 .add_2bytes([0, ip_number::TCP.0]) 353 .add_2bytes((tcp_len).to_be_bytes()), 354 payload, 355 )) 356 } 357 358 /// Calculates the TCP header checksum based on a ipv6 header and returns the result. This does NOT set the checksum.. calc_checksum_ipv6( &self, ip_header: &Ipv6HeaderSlice, payload: &[u8], ) -> Result<u16, ValueTooBigError<usize>>359 pub fn calc_checksum_ipv6( 360 &self, 361 ip_header: &Ipv6HeaderSlice, 362 payload: &[u8], 363 ) -> Result<u16, ValueTooBigError<usize>> { 364 self.calc_checksum_ipv6_raw(ip_header.source(), ip_header.destination(), payload) 365 } 366 367 /// Calculates the checksum for the current header in ipv6 mode and returns the result. This does NOT set the checksum. calc_checksum_ipv6_raw( &self, source: [u8; 16], destination: [u8; 16], payload: &[u8], ) -> Result<u16, ValueTooBigError<usize>>368 pub fn calc_checksum_ipv6_raw( 369 &self, 370 source: [u8; 16], 371 destination: [u8; 16], 372 payload: &[u8], 373 ) -> Result<u16, ValueTooBigError<usize>> { 374 // check that the total length fits into the field 375 let header_len = self.slice.len() as u32; 376 let max_payload = (u32::MAX as usize) - (header_len as usize); 377 if max_payload < payload.len() { 378 return Err(ValueTooBigError { 379 actual: payload.len(), 380 max_allowed: max_payload, 381 value_type: ValueType::TcpPayloadLengthIpv6, 382 }); 383 } 384 385 // calculate the checksum 386 let tcp_len = header_len + (payload.len() as u32); 387 Ok(self.calc_checksum_post_ip( 388 checksum::Sum16BitWords::new() 389 .add_16bytes(source) 390 .add_16bytes(destination) 391 .add_2bytes([0, ip_number::TCP.0]) 392 .add_4bytes((tcp_len).to_be_bytes()), 393 payload, 394 )) 395 } 396 397 /// This method takes the sum of the pseudo ip header and calculates the rest of the checksum. calc_checksum_post_ip( &self, ip_pseudo_header_sum: checksum::Sum16BitWords, payload: &[u8], ) -> u16398 fn calc_checksum_post_ip( 399 &self, 400 ip_pseudo_header_sum: checksum::Sum16BitWords, 401 payload: &[u8], 402 ) -> u16 { 403 ip_pseudo_header_sum 404 .add_slice(&self.slice[..16]) //until checksum 405 .add_slice(&self.slice[18..self.slice.len()]) 406 .add_slice(payload) 407 .ones_complement() 408 .to_be() 409 } 410 } 411 412 #[cfg(test)] 413 mod test { 414 use crate::{ 415 err::{ 416 tcp::{HeaderError::*, HeaderSliceError::*}, 417 ValueTooBigError, ValueType, 418 }, 419 test_gens::*, 420 TcpOptionElement::*, 421 *, 422 }; 423 use alloc::{format, vec::Vec}; 424 use proptest::prelude::*; 425 426 proptest! { 427 #[test] 428 fn debug(header in tcp_any()) { 429 let buffer = header.to_bytes(); 430 let slice = TcpHeaderSlice::from_slice(&buffer).unwrap(); 431 assert_eq!( 432 format!("{:?}", slice), 433 format!("TcpHeaderSlice {{ slice: {:?} }}", slice.slice()) 434 ); 435 } 436 } 437 438 proptest! { 439 #[test] 440 fn clone_eq(header in tcp_any()) { 441 let bytes = header.to_bytes(); 442 let slice = TcpHeaderSlice::from_slice(&bytes).unwrap(); 443 assert_eq!(slice.clone(), slice); 444 } 445 } 446 447 proptest! { 448 #[test] 449 fn from_slice(header in tcp_any()) { 450 // ok case 451 { 452 let bytes = { 453 let mut bytes = header.to_bytes(); 454 bytes.try_extend_from_slice( 455 &([0u8;TcpHeader::MAX_LEN])[..bytes.remaining_capacity()] 456 ).unwrap(); 457 bytes 458 }; 459 460 let slice = TcpHeaderSlice::from_slice(&bytes[..]).unwrap(); 461 assert_eq!(slice.slice(), &bytes[..header.header_len() as usize]); 462 assert_eq!(slice.to_header(), header); 463 } 464 465 // data offset error 466 for data_offset in 0..TcpHeader::MIN_DATA_OFFSET { 467 let bytes = { 468 let mut bytes = header.to_bytes(); 469 bytes[12] = (bytes[12] & 0xf) | ((data_offset << 4) & 0xf0); 470 bytes 471 }; 472 assert_eq!( 473 TcpHeaderSlice::from_slice(&bytes[..]), 474 Err(Content(DataOffsetTooSmall{ data_offset })) 475 ); 476 } 477 478 // length error 479 { 480 let bytes = header.to_bytes(); 481 for len in 0..(header.header_len() as usize) { 482 assert_eq!( 483 TcpHeaderSlice::from_slice(&bytes[..len]) 484 .unwrap_err(), 485 Len(err::LenError { 486 required_len: if len < TcpHeader::MIN_LEN { 487 TcpHeader::MIN_LEN 488 } else { 489 header.header_len() as usize 490 }, 491 len: len, 492 len_source: LenSource::Slice, 493 layer: err::Layer::TcpHeader, 494 layer_start_offset: 0, 495 }) 496 ); 497 } 498 } 499 } 500 } 501 502 proptest! { 503 #[test] 504 fn getters(header in tcp_any()) { 505 let bytes = header.to_bytes(); 506 let slice = TcpHeaderSlice::from_slice(&bytes).unwrap(); 507 508 assert_eq!(header.source_port, slice.source_port()); 509 assert_eq!(header.destination_port, slice.destination_port()); 510 assert_eq!(header.sequence_number, slice.sequence_number()); 511 assert_eq!(header.acknowledgment_number, slice.acknowledgment_number()); 512 assert_eq!(header.data_offset(), slice.data_offset()); 513 assert_eq!(header.ns, slice.ns()); 514 assert_eq!(header.fin, slice.fin()); 515 assert_eq!(header.syn, slice.syn()); 516 assert_eq!(header.rst, slice.rst()); 517 assert_eq!(header.psh, slice.psh()); 518 assert_eq!(header.ack, slice.ack()); 519 assert_eq!(header.urg, slice.urg()); 520 assert_eq!(header.ece, slice.ece()); 521 assert_eq!(header.cwr, slice.cwr()); 522 assert_eq!(header.window_size, slice.window_size()); 523 assert_eq!(header.checksum, slice.checksum()); 524 assert_eq!(header.urgent_pointer, slice.urgent_pointer()); 525 assert_eq!(header.options.as_slice(), slice.options()); 526 } 527 } 528 529 proptest! { 530 #[test] 531 fn options_iterator(header in tcp_any()) { 532 let bytes = header.to_bytes(); 533 let slice = TcpHeaderSlice::from_slice(&bytes).unwrap(); 534 assert_eq!( 535 TcpOptionsIterator::from_slice(header.options.as_slice()), 536 slice.options_iterator() 537 ); 538 } 539 } 540 541 proptest! { 542 #[test] 543 fn to_header(header in tcp_any()) { 544 let bytes = header.to_bytes(); 545 let slice = TcpHeaderSlice::from_slice(&bytes).unwrap(); 546 assert_eq!(header, slice.to_header()); 547 } 548 } 549 550 #[test] calc_checksum_ipv4()551 fn calc_checksum_ipv4() { 552 // checksum == 0xf (no carries) (aka sum == 0xffff) 553 { 554 let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8]; 555 556 // setup headers 557 let tcp = TcpHeader::new(0, 0, 40905, 0); 558 let ip_header = Ipv4Header::new( 559 //payload length 560 tcp.header_len_u16() + (tcp_payload.len() as u16), 561 //time to live 562 0, 563 ip_number::TCP, 564 //source ip address 565 [0; 4], 566 //destination ip address 567 [0; 4], 568 ) 569 .unwrap(); 570 571 // setup slices 572 let ip_bytes = ip_header.to_bytes(); 573 let ip_slice = Ipv4HeaderSlice::from_slice(&ip_bytes).unwrap(); 574 575 let tcp_bytes = tcp.to_bytes(); 576 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_bytes).unwrap(); 577 578 assert_eq!( 579 Ok(0x0), 580 tcp_slice.calc_checksum_ipv4(&ip_slice, &tcp_payload) 581 ); 582 } 583 584 //a header with options 585 { 586 let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8]; 587 588 let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653); 589 tcp.urgent_pointer = 0xE26E; 590 tcp.ns = true; 591 tcp.fin = true; 592 tcp.syn = true; 593 tcp.rst = true; 594 tcp.psh = true; 595 tcp.ack = true; 596 tcp.ece = true; 597 tcp.urg = true; 598 tcp.cwr = true; 599 600 tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)]) 601 .unwrap(); 602 603 let ip_header = Ipv4Header::new( 604 //payload length 605 tcp.header_len_u16() + (tcp_payload.len() as u16), 606 //time to live 607 20, 608 ip_number::TCP, 609 //source ip address 610 [192, 168, 1, 42], 611 //destination ip address 612 [192, 168, 1, 1], 613 ) 614 .unwrap(); 615 616 // setup slices 617 let ip_buffer = ip_header.to_bytes(); 618 let ip_slice = Ipv4HeaderSlice::from_slice(&ip_buffer).unwrap(); 619 620 let tcp_buffer = tcp.to_bytes(); 621 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer).unwrap(); 622 623 assert_eq!( 624 Ok(0xdeeb), 625 tcp_slice.calc_checksum_ipv4(&ip_slice, &tcp_payload) 626 ); 627 } 628 629 //a header with an uneven number of options 630 { 631 let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8, 9]; 632 633 let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653); 634 tcp.urgent_pointer = 0xE26E; 635 tcp.ns = true; 636 tcp.fin = true; 637 tcp.syn = true; 638 tcp.rst = true; 639 tcp.psh = true; 640 tcp.ack = true; 641 tcp.ece = true; 642 tcp.urg = true; 643 tcp.cwr = true; 644 645 tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)]) 646 .unwrap(); 647 648 let ip_header = Ipv4Header::new( 649 //payload length 650 tcp.header_len_u16() + (tcp_payload.len() as u16), 651 //time to live 652 20, 653 ip_number::TCP, 654 //source ip address 655 [192, 168, 1, 42], 656 //destination ip address 657 [192, 168, 1, 1], 658 ) 659 .unwrap(); 660 661 // setup slices 662 let ip_buffer = ip_header.to_bytes(); 663 let ip_slice = Ipv4HeaderSlice::from_slice(&ip_buffer[..]).unwrap(); 664 665 let tcp_buffer = tcp.to_bytes(); 666 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap(); 667 668 assert_eq!( 669 Ok(0xd5ea), 670 tcp_slice.calc_checksum_ipv4(&ip_slice, &tcp_payload) 671 ); 672 } 673 674 // value error 675 { 676 // write the tcp header 677 let tcp: TcpHeader = Default::default(); 678 let len = (core::u16::MAX - tcp.header_len_u16()) as usize + 1; 679 let mut tcp_payload = Vec::with_capacity(len); 680 tcp_payload.resize(len, 0); 681 let ip_header = Ipv4Header::new(0, 0, ip_number::TCP, [0; 4], [0; 4]).unwrap(); 682 683 // setup slices 684 let ip_buffer = ip_header.to_bytes(); 685 let ip_slice = Ipv4HeaderSlice::from_slice(&ip_buffer).unwrap(); 686 687 let tcp_buffer = tcp.to_bytes(); 688 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer).unwrap(); 689 690 assert_eq!( 691 tcp_slice.calc_checksum_ipv4(&ip_slice, &tcp_payload), 692 Err(ValueTooBigError { 693 actual: len, 694 max_allowed: usize::from(core::u16::MAX - tcp.header_len_u16()), 695 value_type: ValueType::TcpPayloadLengthIpv4, 696 }) 697 ); 698 } 699 } 700 701 #[test] calc_checksum_ipv4_raw()702 fn calc_checksum_ipv4_raw() { 703 // checksum == 0xf (no carries) (aka sum == 0xffff) 704 { 705 let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8]; 706 707 // setup headers 708 let tcp = TcpHeader::new(0, 0, 40905, 0); 709 710 // setup slices 711 let tcp_bytes = tcp.to_bytes(); 712 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_bytes).unwrap(); 713 714 assert_eq!( 715 Ok(0x0), 716 tcp_slice.calc_checksum_ipv4_raw([0; 4], [0; 4], &tcp_payload) 717 ); 718 } 719 720 //a header with options 721 { 722 let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8]; 723 724 let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653); 725 tcp.urgent_pointer = 0xE26E; 726 tcp.ns = true; 727 tcp.fin = true; 728 tcp.syn = true; 729 tcp.rst = true; 730 tcp.psh = true; 731 tcp.ack = true; 732 tcp.ece = true; 733 tcp.urg = true; 734 tcp.cwr = true; 735 736 tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)]) 737 .unwrap(); 738 739 // setup slices 740 let tcp_buffer = tcp.to_bytes(); 741 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer).unwrap(); 742 743 assert_eq!( 744 Ok(0xdeeb), 745 tcp_slice.calc_checksum_ipv4_raw([192, 168, 1, 42], [192, 168, 1, 1], &tcp_payload) 746 ); 747 } 748 749 //a header with an uneven number of options 750 { 751 let tcp_payload = [1, 2, 3, 4, 5, 6, 7, 8, 9]; 752 753 let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653); 754 tcp.urgent_pointer = 0xE26E; 755 tcp.ns = true; 756 tcp.fin = true; 757 tcp.syn = true; 758 tcp.rst = true; 759 tcp.psh = true; 760 tcp.ack = true; 761 tcp.ece = true; 762 tcp.urg = true; 763 tcp.cwr = true; 764 765 tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)]) 766 .unwrap(); 767 768 // setup slices 769 let tcp_buffer = tcp.to_bytes(); 770 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap(); 771 772 assert_eq!( 773 Ok(0xd5ea), 774 tcp_slice.calc_checksum_ipv4_raw([192, 168, 1, 42], [192, 168, 1, 1], &tcp_payload) 775 ); 776 } 777 778 // value error 779 { 780 // write the tcp header 781 let tcp: TcpHeader = Default::default(); 782 let len = (core::u16::MAX - tcp.header_len_u16()) as usize + 1; 783 let mut tcp_payload = Vec::with_capacity(len); 784 tcp_payload.resize(len, 0); 785 786 // setup slices 787 let tcp_buffer = tcp.to_bytes(); 788 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer).unwrap(); 789 790 assert_eq!( 791 tcp_slice.calc_checksum_ipv4_raw([0; 4], [0; 4], &tcp_payload), 792 Err(ValueTooBigError { 793 actual: len, 794 max_allowed: usize::from(core::u16::MAX - tcp.header_len_u16()), 795 value_type: ValueType::TcpPayloadLengthIpv4, 796 }) 797 ); 798 } 799 } 800 801 #[test] calc_checksum_ipv6()802 fn calc_checksum_ipv6() { 803 // ok case 804 { 805 let tcp_payload = [51, 52, 53, 54, 55, 56, 57, 58]; 806 807 // setup tcp header 808 let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653); 809 tcp.urgent_pointer = 0xE26E; 810 811 tcp.ns = true; 812 tcp.fin = true; 813 tcp.syn = true; 814 tcp.rst = true; 815 tcp.psh = true; 816 tcp.ack = true; 817 tcp.ece = true; 818 tcp.urg = true; 819 tcp.cwr = true; 820 821 use crate::TcpOptionElement::*; 822 tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)]) 823 .unwrap(); 824 825 // setup ip header 826 let ip_header = Ipv6Header { 827 traffic_class: 1, 828 flow_label: 0x81806.try_into().unwrap(), 829 payload_length: tcp_payload.len() as u16 + tcp.header_len_u16(), 830 next_header: ip_number::TCP, 831 hop_limit: 40, 832 source: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], 833 destination: [ 834 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 835 ], 836 }; 837 838 // setup slices 839 let ip_buffer = ip_header.to_bytes(); 840 let ip_slice = Ipv6HeaderSlice::from_slice(&ip_buffer[..]).unwrap(); 841 842 let tcp_bytes = tcp.to_bytes(); 843 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_bytes).unwrap(); 844 845 // verify checksum 846 assert_eq!( 847 Ok(0x786e), 848 tcp_slice.calc_checksum_ipv6(&ip_slice, &tcp_payload) 849 ); 850 } 851 852 // error 853 #[cfg(target_pointer_width = "64")] 854 { 855 //write the udp header 856 let tcp: TcpHeader = Default::default(); 857 let len = (core::u32::MAX - tcp.header_len() as u32) as usize + 1; 858 859 //lets create a slice of that size that points to zero 860 //(as most systems can not allocate blocks of the size of u32::MAX) 861 let tcp_payload = unsafe { 862 //NOTE: The pointer must be initialized with a non null value 863 // otherwise a key constraint of slices is not fulfilled 864 // which can lead to crashes in release mode. 865 use core::ptr::NonNull; 866 core::slice::from_raw_parts(NonNull::<u8>::dangling().as_ptr(), len) 867 }; 868 let ip_header = Ipv6Header { 869 traffic_class: 1, 870 flow_label: 0x81806.try_into().unwrap(), 871 payload_length: 0, //lets assume jumbograms behavior (set to 0, as bigger then u16) 872 next_header: ip_number::TCP, 873 hop_limit: 40, 874 source: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], 875 destination: [ 876 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 877 ], 878 }; 879 880 // setup slices 881 let mut ip_buffer = Vec::new(); 882 ip_header.write(&mut ip_buffer).unwrap(); 883 let ip_slice = Ipv6HeaderSlice::from_slice(&ip_buffer[..]).unwrap(); 884 885 let mut tcp_buffer = Vec::new(); 886 tcp.write(&mut tcp_buffer).unwrap(); 887 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap(); 888 889 // check for an error during checksum calc 890 assert_eq!( 891 tcp_slice.calc_checksum_ipv6(&ip_slice, &tcp_payload), 892 Err(ValueTooBigError { 893 actual: len, 894 max_allowed: core::u32::MAX as usize - tcp.header_len() as usize, 895 value_type: ValueType::TcpPayloadLengthIpv6, 896 }) 897 ); 898 } 899 } 900 901 #[test] calc_checksum_ipv6_raw()902 fn calc_checksum_ipv6_raw() { 903 // ok case 904 { 905 let tcp_payload = [51, 52, 53, 54, 55, 56, 57, 58]; 906 907 //write the tcp header 908 let mut tcp = TcpHeader::new(69, 42, 0x24900448, 0x3653); 909 tcp.urgent_pointer = 0xE26E; 910 911 tcp.ns = true; 912 tcp.fin = true; 913 tcp.syn = true; 914 tcp.rst = true; 915 tcp.psh = true; 916 tcp.ack = true; 917 tcp.ece = true; 918 tcp.urg = true; 919 tcp.cwr = true; 920 921 use crate::TcpOptionElement::*; 922 tcp.set_options(&[Noop, Noop, Noop, Noop, Timestamp(0x4161008, 0x84161708)]) 923 .unwrap(); 924 925 // setup slice 926 let tcp_buffer = tcp.to_bytes(); 927 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer[..]).unwrap(); 928 929 // verify checksum 930 assert_eq!( 931 Ok(0x786e), 932 tcp_slice.calc_checksum_ipv6_raw( 933 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], 934 [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,], 935 &tcp_payload 936 ) 937 ); 938 } 939 940 // error 941 #[cfg(target_pointer_width = "64")] 942 { 943 //write the udp header 944 let tcp: TcpHeader = Default::default(); 945 let len = (core::u32::MAX - tcp.header_len() as u32) as usize + 1; 946 947 //lets create a slice of that size that points to zero 948 //(as most systems can not allocate blocks of the size of u32::MAX) 949 let tcp_payload = unsafe { 950 //NOTE: The pointer must be initialized with a non null value 951 // otherwise a key constraint of slices is not fulfilled 952 // which can lead to crashes in release mode. 953 use core::ptr::NonNull; 954 core::slice::from_raw_parts(NonNull::<u8>::dangling().as_ptr(), len) 955 }; 956 957 // setup slice 958 let tcp_buffer = tcp.to_bytes(); 959 let tcp_slice = TcpHeaderSlice::from_slice(&tcp_buffer).unwrap(); 960 961 // expect an length error 962 assert_eq!( 963 tcp_slice.calc_checksum_ipv6_raw( 964 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], 965 [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,], 966 &tcp_payload 967 ), 968 Err(ValueTooBigError { 969 actual: len, 970 max_allowed: core::u32::MAX as usize - tcp.header_len() as usize, 971 value_type: ValueType::TcpPayloadLengthIpv6, 972 }) 973 ); 974 } 975 } 976 } 977