• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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