@@ -10,6 +10,7 @@ use crate::wire::NdiscRepr;
10
10
#[ cfg( feature = "proto-rpl" ) ]
11
11
use crate :: wire:: RplRepr ;
12
12
use crate :: wire:: { IpAddress , IpProtocol , Ipv6Packet , Ipv6Repr } ;
13
+ use crate :: wire:: { IPV6_HEADER_LEN , IPV6_MIN_MTU } ;
13
14
14
15
enum_with_unknown ! {
15
16
/// Internet protocol control message type.
@@ -617,7 +618,20 @@ impl<'a> Repr<'a> {
617
618
where
618
619
T : AsRef < [ u8 ] > + ?Sized ,
619
620
{
620
- let ip_packet = Ipv6Packet :: new_checked ( packet. payload ( ) ) ?;
621
+ // The packet must be truncated to fit the min MTU. In case the packet is potentially
622
+ // truncated, only perform a basic sanity check to ensure the original header is
623
+ // still intact.
624
+ let ip_packet = if packet. buffer . as_ref ( ) . len ( ) >= super :: IPV6_MIN_MTU {
625
+ let ip_packet = Ipv6Packet :: new_unchecked ( packet. payload ( ) ) ;
626
+
627
+ if packet. payload ( ) . len ( ) < ip_packet. header_len ( ) {
628
+ return Err ( Error ) ;
629
+ }
630
+
631
+ ip_packet
632
+ } else {
633
+ Ipv6Packet :: new_checked ( packet. payload ( ) ) ?
634
+ } ;
621
635
622
636
let payload = & packet. payload ( ) [ ip_packet. header_len ( ) ..] ;
623
637
if payload. len ( ) < 8 {
@@ -627,7 +641,7 @@ impl<'a> Repr<'a> {
627
641
src_addr : ip_packet. src_addr ( ) ,
628
642
dst_addr : ip_packet. dst_addr ( ) ,
629
643
next_header : ip_packet. next_header ( ) ,
630
- payload_len : payload . len ( ) ,
644
+ payload_len : ip_packet . payload_len ( ) . into ( ) ,
631
645
hop_limit : ip_packet. hop_limit ( ) ,
632
646
} ;
633
647
Ok ( ( payload, repr) )
@@ -697,7 +711,15 @@ impl<'a> Repr<'a> {
697
711
| & Repr :: PktTooBig { header, data, .. }
698
712
| & Repr :: TimeExceeded { header, data, .. }
699
713
| & Repr :: ParamProblem { header, data, .. } => {
700
- field:: UNUSED . end + header. buffer_len ( ) + data. len ( )
714
+ /* (c) Every ICMPv6 error message (type < 128) MUST include as much of
715
+ * the IPv6 offending (invoking) packet (the packet that caused the
716
+ * error) as possible without making the error message packet exceed
717
+ * the minimum IPv6 MTU [IPv6].
718
+ */
719
+ cmp:: min (
720
+ field:: UNUSED . end + header. buffer_len ( ) + data. len ( ) ,
721
+ IPV6_MIN_MTU - IPV6_HEADER_LEN ,
722
+ )
701
723
}
702
724
& Repr :: EchoRequest { data, .. } | & Repr :: EchoReply { data, .. } => {
703
725
field:: ECHO_SEQNO . end + data. len ( )
@@ -725,7 +747,8 @@ impl<'a> Repr<'a> {
725
747
let mut ip_packet = Ipv6Packet :: new_unchecked ( buffer) ;
726
748
header. emit ( & mut ip_packet) ;
727
749
let payload = & mut ip_packet. into_inner ( ) [ header. buffer_len ( ) ..] ;
728
- payload. copy_from_slice ( data) ;
750
+ let data_len = cmp:: min ( payload. len ( ) , data. len ( ) ) ;
751
+ payload[ ..data_len] . copy_from_slice ( & data[ ..data_len] ) ;
729
752
}
730
753
731
754
match * self {
@@ -981,4 +1004,60 @@ mod test {
981
1004
) ;
982
1005
assert_eq ! ( & * packet. into_inner( ) , & PKT_TOO_BIG_BYTES [ ..] ) ;
983
1006
}
1007
+
1008
+ #[ test]
1009
+ fn test_buffer_length_is_truncated_to_mtu ( ) {
1010
+ let repr = Repr :: PktTooBig {
1011
+ mtu : 1280 ,
1012
+ header : Ipv6Repr {
1013
+ src_addr : Default :: default ( ) ,
1014
+ dst_addr : Default :: default ( ) ,
1015
+ next_header : IpProtocol :: Tcp ,
1016
+ hop_limit : 64 ,
1017
+ payload_len : 1280 ,
1018
+ } ,
1019
+ data : & vec ! [ 0 ; 9999 ] ,
1020
+ } ;
1021
+ assert_eq ! ( repr. buffer_len( ) , 1280 - IPV6_HEADER_LEN ) ;
1022
+ }
1023
+
1024
+ #[ test]
1025
+ fn test_mtu_truncated_payload_roundtrip ( ) {
1026
+ let ip_packet_repr = Ipv6Repr {
1027
+ src_addr : Default :: default ( ) ,
1028
+ dst_addr : Default :: default ( ) ,
1029
+ next_header : IpProtocol :: Tcp ,
1030
+ hop_limit : 64 ,
1031
+ payload_len : 1280 ,
1032
+ } ;
1033
+ let mut ip_packet = Ipv6Packet :: new_unchecked ( vec ! [ 0 ; 1280 + IPV6_HEADER_LEN ] ) ;
1034
+ ip_packet_repr. emit ( & mut ip_packet) ;
1035
+
1036
+ let repr1 = Repr :: PktTooBig {
1037
+ mtu : 1280 ,
1038
+ header : ip_packet_repr,
1039
+ // this is needed to make sure roundtrip gives the same value
1040
+ // it is not needed for ensuring the correct bytes get emitted
1041
+ data : & ip_packet. as_ref ( ) [ ..1280 - field:: HEADER_END - IPV6_HEADER_LEN ] ,
1042
+ } ;
1043
+ let mut data = vec ! [ 0 ; 1280 ] ;
1044
+ let mut packet = Packet :: new_unchecked ( & mut data) ;
1045
+ repr1. emit (
1046
+ & MOCK_IP_ADDR_1 ,
1047
+ & MOCK_IP_ADDR_2 ,
1048
+ & mut packet,
1049
+ & ChecksumCapabilities :: default ( ) ,
1050
+ ) ;
1051
+
1052
+ let packet = Packet :: new_unchecked ( & data) ;
1053
+ let repr2 = Repr :: parse (
1054
+ & MOCK_IP_ADDR_1 ,
1055
+ & MOCK_IP_ADDR_2 ,
1056
+ & packet,
1057
+ & ChecksumCapabilities :: default ( ) ,
1058
+ )
1059
+ . unwrap ( ) ;
1060
+
1061
+ assert_eq ! ( repr1, repr2) ;
1062
+ }
984
1063
}
0 commit comments