@@ -5,22 +5,18 @@ use std::collections::{HashMap, HashSet};
55use std:: net:: { Ipv4Addr , Ipv6Addr } ;
66use std:: str:: FromStr ;
77
8+ use translator:: pnet_packet:: ip:: IpNextHeaderProtocol ;
89use translator:: pnet_packet:: ipv4:: { Ipv4Packet , MutableIpv4Packet } ;
9- use translator:: pnet_packet:: ipv6:: { Ipv6Packet , MutableIpv6Packet } ;
10- use translator:: pnet_packet:: icmp:: { IcmpPacket , MutableIcmpPacket , IcmpType , IcmpTypes } ;
11- use translator:: pnet_packet:: icmpv6:: { Icmpv6Packet , MutableIcmpv6Packet , Icmpv6Type , Icmpv6Types } ;
12- use translator:: pnet_packet:: Packet ;
13- use translator:: pnet_packet:: icmp;
14- use translator:: pnet_packet:: ip;
15- use translator:: pnet_packet:: ipv4;
16- use translator:: pnet_packet:: tcp;
17- use translator:: pnet_packet:: udp;
10+ use translator:: pnet_packet:: ipv6:: { MutableIpv6Packet } ;
11+ use translator:: pnet_packet:: icmp:: { IcmpPacket , MutableIcmpPacket , IcmpTypes , IcmpCode , IcmpType } ;
12+ use translator:: pnet_packet:: icmpv6:: { Icmpv6Packet , MutableIcmpv6Packet , Icmpv6Types , Icmpv6Type , Icmpv6Code } ;
13+ use translator:: pnet_packet:: { Packet , icmp, ip, ipv4, tcp, udp, icmpv6} ;
1814use translator:: pnet_packet:: MutablePacket ;
19- use translator:: pnet_packet:: PacketSize ;
2015
2116#[ derive( Debug ) ]
2217pub enum Xlat6to4Error {
2318 TTLExceeded ,
19+ BufferTooSmall ,
2420 Other ( String ) ,
2521}
2622
@@ -91,28 +87,22 @@ impl HMNat64 {
9187
9288 // Takes an incoming v6 packet and returns the translated v4 packet.
9389 pub fn process_v6 < ' p > ( & mut self , pkt : & mut MutableIpv6Packet , buf : & ' p mut [ u8 ] ) -> Result < Ipv4Packet < ' p > , Xlat6to4Error > {
94- println ! ( "called process_v6" ) ;
95- let mut response: MutableIpv4Packet < ' p > = pnet_packet:: ipv4:: MutableIpv4Packet :: new ( buf) . unwrap ( ) ;
96- let v4src: Ipv4Addr = self . get_v4addr_for_host ( pkt. get_source ( ) ) . map_err ( |e| Xlat6to4Error :: Other ( e) ) ?;
90+ let mut response: MutableIpv4Packet < ' p > = pnet_packet:: ipv4:: MutableIpv4Packet :: new ( buf)
91+ . ok_or ( Xlat6to4Error :: BufferTooSmall ) ?;
92+ let v4src: Ipv4Addr = self . get_v4addr_for_host ( pkt. get_source ( ) )
93+ . map_err ( |e| Xlat6to4Error :: Other ( e) ) ?;
9794 let v4dst: Ipv4Addr = self . v6_to_v4 ( pkt. get_destination ( ) ) ;
98- let total_v4_length = 20 + pkt. get_payload_length ( ) ; // FIXME: use the IHL from the input packet instead of 20.
9995
10096 response. set_version ( 4 ) ;
10197 response. set_header_length ( 5 ) ;
10298 response. set_dscp ( pkt. get_traffic_class ( ) ) ;
103- response. set_total_length ( total_v4_length) ;
10499 response. set_identification ( 0 ) ; // TODO: Check what this should be.
105- // Ipv4 flags: [ZERO, DF, MF]
106- if total_v4_length <= 1260 {
107- response. set_flags ( 0 ) ;
108- } else {
109- response. set_flags ( 2 ) ;
110- }
111100 response. set_fragment_offset ( 0 ) ;
112101
113102 // Decrement and check the TTL.
114103 let ttl = pkt. get_hop_limit ( ) - 1 ;
115104 if ttl == 0 {
105+ // TODO: Should return ICMP Time Exceeded message to the sender.
116106 return Err ( Xlat6to4Error :: TTLExceeded ) ;
117107 }
118108 response. set_ttl ( ttl) ;
@@ -121,8 +111,9 @@ impl HMNat64 {
121111 ip:: IpNextHeaderProtocols :: Icmpv6 => {
122112 let old_payload = Icmpv6Packet :: new ( pkt. payload ( ) ) . unwrap ( ) ;
123113 let new_payload = HMNat64 :: icmp6_to_icmp4 ( & old_payload) ?;
114+ response. set_total_length ( 20 + new_payload. packet ( ) . len ( ) as u16 ) ;
124115 response. set_payload ( & new_payload. packet ( ) ) ;
125- response. set_total_length ( total_v4_length + new_payload . packet ( ) . len ( ) as u16 ) ;
116+ response. set_next_level_protocol ( ip :: IpNextHeaderProtocols :: Icmp )
126117 } ,
127118 ip:: IpNextHeaderProtocols :: Tcp => {
128119 let mut tcp_pkt = tcp:: MutableTcpPacket :: new ( pkt. payload_mut ( ) ) . unwrap ( ) ;
@@ -131,7 +122,9 @@ impl HMNat64 {
131122 & v4src,
132123 & v4dst) ;
133124 tcp_pkt. set_checksum ( sum) ;
125+ response. set_total_length ( 20 + tcp_pkt. packet ( ) . len ( ) as u16 ) ;
134126 response. set_payload ( tcp_pkt. packet ( ) ) ;
127+ response. set_next_level_protocol ( ip:: IpNextHeaderProtocols :: Tcp ) ;
135128 } ,
136129 ip:: IpNextHeaderProtocols :: Udp => {
137130 let mut udp_pkt = udp:: MutableUdpPacket :: new ( pkt. payload_mut ( ) ) . unwrap ( ) ;
@@ -140,20 +133,30 @@ impl HMNat64 {
140133 & v4src,
141134 & v4dst) ;
142135 udp_pkt. set_checksum ( sum) ;
136+ response. set_total_length ( 20 + udp_pkt. packet ( ) . len ( ) as u16 ) ;
143137 response. set_payload ( udp_pkt. packet ( ) ) ;
138+ response. set_next_level_protocol ( ip:: IpNextHeaderProtocols :: Udp )
144139 } ,
145140 _ => {
146- // If the protocol is unknown leave the inner payload alone.
141+ // If the protocol is unknown leave the inner payload alone and forward.
142+ response. set_total_length ( 20 + pkt. payload ( ) . len ( ) as u16 ) ;
147143 response. set_payload ( pkt. payload ( ) ) ;
144+ response. set_next_level_protocol ( pkt. get_next_header ( ) ) ;
148145 } ,
149146 }
150147
148+ // Ipv4 flags: [ZERO, DF, MF]
149+ if response. get_total_length ( ) <= 1260 {
150+ response. set_flags ( 0 ) ;
151+ } else {
152+ response. set_flags ( 2 ) ;
153+ }
154+
151155 response. set_source ( v4src) ;
152156 response. set_destination ( v4dst) ;
153- println ! ( "out: src={:?}, dst={:?}" , v4src, v4dst) ;
157+ println ! ( "out: src={:?}, dst={:?}, in len: {}, out len: {} " , v4src, v4dst, pkt . packet ( ) . len ( ) , response . packet ( ) . len ( ) ) ;
154158 let sum = ipv4:: checksum ( & response. to_immutable ( ) ) ;
155159 response. set_checksum ( sum) ;
156-
157160 Ok ( response. consume_to_immutable ( ) )
158161 }
159162
@@ -362,6 +365,11 @@ mod tests {
362365 n64_prefix : & ' a str ,
363366 }
364367
368+ struct PacketTestCase {
369+ ipv4 : Box < Vec < u8 > > ,
370+ ipv6 : Box < Vec < u8 > > ,
371+ }
372+
365373 #[ test]
366374 fn test_convert_u8_to_u16 ( ) {
367375 assert_eq ! ( 0 , u8_to_u16( 0 , 0 ) ) ;
@@ -470,4 +478,96 @@ mod tests {
470478 assert_eq ! ( test. ipv4, translator. v6_to_v4( test. ipv6) ) ;
471479 }
472480 }
481+
482+ // Create an ICMPv4 packet with given type, code, payload.
483+ fn tmpl_icmp4 ( typ : IcmpType , code : IcmpCode , payload : & [ u8 ] ) -> Box < Vec < u8 > > {
484+ // Size of ICMP v4 packet is 4 bytes + payload.
485+ let buf = vec ! [ 0u8 ; 4 + payload. len( ) ] ;
486+ let mut icmp4Pkt = MutableIcmpPacket :: owned ( buf) . unwrap ( ) ;
487+ icmp4Pkt. set_icmp_type ( typ) ;
488+ icmp4Pkt. set_icmp_code ( code) ;
489+ icmp4Pkt. set_payload ( payload) ;
490+ let checksum: u16 = icmp:: checksum ( & icmp4Pkt. to_immutable ( ) ) ;
491+ icmp4Pkt. set_checksum ( checksum) ;
492+ Box :: new ( icmp4Pkt. packet ( ) . to_vec ( ) )
493+ }
494+
495+ // Create an ICMPv6 packet with given type, code and payload.
496+ fn tmpl_icmpv6 ( ipsrc : Ipv6Addr , ipdst : Ipv6Addr , typ : Icmpv6Type , code : Icmpv6Code , payload : & [ u8 ] ) -> Box < Vec < u8 > > {
497+ let buf = vec ! [ 0u8 ; 4 + payload. len( ) ] ;
498+ let mut icmpv6Pkt = MutableIcmpv6Packet :: owned ( buf) . unwrap ( ) ;
499+ icmpv6Pkt. set_icmpv6_type ( typ) ;
500+ icmpv6Pkt. set_icmpv6_code ( code) ;
501+ icmpv6Pkt. set_payload ( payload) ;
502+ let checksum: u16 = icmpv6:: checksum ( & icmpv6Pkt. to_immutable ( ) , & ipsrc, & ipdst) ;
503+ icmpv6Pkt. set_checksum ( checksum) ;
504+ Box :: new ( icmpv6Pkt. packet ( ) . to_vec ( ) )
505+ }
506+
507+ // Wrap an IP payload with an IP header.
508+ fn wrap_iphdr ( src : Ipv4Addr , dst : Ipv4Addr , ttl : u8 , next : IpNextHeaderProtocol , payload : & [ u8 ] ) -> Box < Vec < u8 > > {
509+ let buf = vec ! [ 0u8 ; 20 + payload. len( ) ] ;
510+ let mut ip4Pkt = MutableIpv4Packet :: owned ( buf) . unwrap ( ) ;
511+ ip4Pkt. set_version ( 4 ) ;
512+ ip4Pkt. set_source ( src) ;
513+ ip4Pkt. set_destination ( dst) ;
514+ ip4Pkt. set_header_length ( 5 ) ;
515+ ip4Pkt. set_total_length ( 20 + payload. len ( ) as u16 ) ;
516+ ip4Pkt. set_ttl ( ttl) ;
517+ ip4Pkt. set_next_level_protocol ( next) ;
518+ ip4Pkt. set_payload ( payload) ;
519+ let checksum: u16 = ipv4:: checksum ( & ip4Pkt. to_immutable ( ) ) ;
520+ ip4Pkt. set_checksum ( checksum) ;
521+ Box :: new ( ip4Pkt. packet ( ) . to_vec ( ) )
522+ }
523+
524+ fn wrap_ip6hdr ( src : Ipv6Addr , dst : Ipv6Addr , hopLim : u8 , next : IpNextHeaderProtocol , payload : & [ u8 ] ) -> Box < Vec < u8 > > {
525+ let buf = vec ! [ 0u8 ; 40 + payload. len( ) ] ;
526+ let mut ip6Pkt = MutableIpv6Packet :: owned ( buf) . unwrap ( ) ;
527+ ip6Pkt. set_source ( src) ;
528+ ip6Pkt. set_destination ( dst) ;
529+ ip6Pkt. set_hop_limit ( hopLim) ;
530+ ip6Pkt. set_next_header ( next) ;
531+ ip6Pkt. set_payload_length ( payload. len ( ) as u16 ) ;
532+ ip6Pkt. set_payload ( payload) ;
533+ Box :: new ( ip6Pkt. packet ( ) . to_vec ( ) )
534+ }
535+
536+ #[ test]
537+ fn test_v6_to_v4 ( ) {
538+ let clientV4 = Ipv4Addr :: new ( 10 , 0 , 0 , 1 ) ;
539+ let tests: Vec < PacketTestCase > = vec ! [
540+ PacketTestCase {
541+ ipv6: wrap_ip6hdr(
542+ Ipv6Addr :: new( 0x2001 , 0xdb8 , 0 , 0 , 0 , 0 , 0 , 0xcafe ) ,
543+ Ipv6Addr :: new( 0x64 , 0xff9b , 0 , 0 , 0 , 0 , 0x808 , 0x808 ) ,
544+ 255 ,
545+ ip:: IpNextHeaderProtocols :: Icmpv6 ,
546+ & * tmpl_icmpv6( Ipv6Addr :: new( 0x2001 , 0xdb8 , 0 , 0 , 0 , 0 , 0 , 0xcafe ) ,
547+ Ipv6Addr :: new( 0x64 , 0xff9b , 0 , 0 , 0 , 0 , 0x808 , 0x808 ) ,
548+ icmpv6:: Icmpv6Types :: EchoRequest ,
549+ icmpv6:: ndp:: Icmpv6Codes :: NoCode ,
550+ & vec![ 0xca , 0xfe , 0xbe , 0xef ] )
551+ ) ,
552+ ipv4: wrap_iphdr(
553+ clientV4,
554+ Ipv4Addr :: new( 0x8 , 0x8 , 0x8 , 0x8 ) ,
555+ 254 ,
556+ ip:: IpNextHeaderProtocols :: Icmp ,
557+ & * tmpl_icmp4( icmp:: IcmpTypes :: EchoRequest ,
558+ icmp:: echo_request:: IcmpCodes :: NoCode ,
559+ & vec![ 0xca , 0xfe , 0xbe , 0xef ] )
560+ )
561+ } ,
562+ ] ;
563+ let client_subnet = "10.0.0.0/24" ;
564+ for mut test in tests {
565+ let mut rbuf = [ 0u8 ; 1500 ] ;
566+ let mut translator = HMNat64 :: new ( "64:ff9b::/96" , client_subnet) . unwrap ( ) ;
567+ let response: Ipv4Packet = translator. process_v6 ( & mut MutableIpv6Packet :: new ( & mut * test. ipv6 ) . unwrap ( ) , & mut rbuf) . unwrap ( ) ;
568+ let lim: usize = response. get_total_length ( ) as usize ;
569+ let pkt = & response. packet ( ) [ ..lim] ;
570+ assert_eq ! ( * test. ipv4, pkt) ;
571+ }
572+ }
473573}
0 commit comments