/// Performs the header translation part of NAT64 as described in [RFC
/// 7915].
///
/// `nat64_translate` follows the rules described in RFC 7915 to construct
/// the IPv4 equivalent of this IPv6 packet. If the payload is a TCP segment
/// or a UDP packet, its checksum will be updated. If the payload is an
/// ICMPv6 packet, it will be converted to the equivalent ICMPv4 packet. For
/// all other payloads, the payload will be unchanged, and the IP header will
/// be translated. On success, a [`Serializer`] is returned which describes
/// the new packet to be sent.
///
/// Note that the IPv4 TTL/IPv6 Hop Limit field is not modified. It is the
/// caller's responsibility to decrement and process this field per RFC
/// 7915.
///
/// In some cases, the packet has no IPv4 equivalent, in which case the
/// value [`Nat64TranslationResult::Drop`] will be returned, instructing the
/// caller to silently drop the packet.
///
/// # Errors
///
/// `nat64_translate` will return an error if support has not yet been
/// implemented for translating a particular IP protocol.
///
/// [RFC 7915]: https://datatracker.ietf.org/doc/html/rfc7915
Performs the header translation part of NAT64 as described in [RFC
7915].

`nat64_translate` follows the rules described in RFC 7915 to construct
the IPv4 equivalent of this IPv6 packet. If the payload is a TCP segment
or a UDP packet, its checksum will be updated. If the payload is an
ICMPv6 packet, it will be converted to the equivalent ICMPv4 packet. For
all other payloads, the payload will be unchanged, and the IP header will
be translated. On success, a [`Serializer`] is returned which describes
the new packet to be sent.

Note that the IPv4 TTL/IPv6 Hop Limit field is not modified. It is the
caller's responsibility to decrement and process this field per RFC
7915.

In some cases, the packet has no IPv4 equivalent, in which case the
value [`Nat64TranslationResult::Drop`] will be returned, instructing the
caller to silently drop the packet.
Performs the header translation part of NAT64 as described in [ RFC 7915 ] . ` nat64_translate ` follows the rules described in RFC 7915 to construct the IPv4 equivalent of this IPv6 packet . If the payload is a TCP segment or a UDP packet its checksum will be updated . If the payload is an ICMPv6 packet it will be converted to the equivalent ICMPv4 packet . For all other payloads the payload will be unchanged and the IP header will be translated . On success a [ ` Serializer ` ] is returned which describes the new packet to be sent . Note that the IPv4 TTL / IPv6 Hop Limit field is not modified . It is the caller ' s responsibility to decrement and process this field per RFC 7915 . In some cases the packet has no IPv4 equivalent in which case the value [ ` Nat64TranslationResult :: Drop ` ] will be returned instructing the caller to silently drop the packet .
pub fn nat64_translate(
        &self,
        v4_src_addr: Ipv4Addr,
        v4_dst_addr: Ipv4Addr,
    ) -> Nat64TranslationResult<impl Serializer<Buffer = EmptyBuf> + Debug + '_, Nat64Error> {
        // A single `Serializer` type so that all possible return values from
        // this function have the same type.
        #[derive(Debug)]
        enum Nat64Serializer<T, U, O> {
            Tcp(T),
            Udp(U),
            Other(O),
        }
        impl<T, U, O> Serializer for Nat64Serializer<T, U, O>
        where
            T: Serializer<Buffer = EmptyBuf>,
            U: Serializer<Buffer = EmptyBuf>,
            O: Serializer<Buffer = EmptyBuf>,
        {
            type Buffer = EmptyBuf;
            fn serialize<B, PB, P>(
                self,
                outer: PB,
                provider: P,
            ) -> Result<B, (SerializeError<P::Error>, Self)>
            where
                B: TargetBuffer,
                PB: NestedPacketBuilder,
                P: BufferProvider<Self::Buffer, B>,
            {
                match self {
                    Nat64Serializer::Tcp(serializer) => serializer
                        .serialize(outer, provider)
                        .map_err(|(err, ser)| (err, Nat64Serializer::Tcp(ser))),
                    Nat64Serializer::Udp(serializer) => serializer
                        .serialize(outer, provider)
                        .map_err(|(err, ser)| (err, Nat64Serializer::Udp(ser))),
                    Nat64Serializer::Other(serializer) => serializer
                        .serialize(outer, provider)
                        .map_err(|(err, ser)| (err, Nat64Serializer::Other(ser))),
                }
            }
        }
        // TODO(https://fxbug.dev/92381): Add support for fragmented packets
        // forwarding.
        if self.fragment_header_present() {
            return Nat64TranslationResult::Err(Nat64Error::NotImplemented);
        }
        let v4_builder = |v4_proto| {
            let mut builder =
                Ipv4PacketBuilder::new(v4_src_addr, v4_dst_addr, self.hop_limit(), v4_proto);
            builder.dscp(self.ds());
            builder.ecn(self.ecn());
            // The IPv4 header length is 20 bytes (so IHL field value is 5), as
            // no header options are present in translated IPv4 packet.
            // As per RFC 7915 Section 5.1:
            //  "Internet Header Length:  5 (no IPv4 options)"
            const IPV4_HEADER_LEN_BYTES: usize = HDR_PREFIX_LEN;
            // As per RFC 7915 Section 5.1,
            //    "Flags:  The More Fragments flag is set to zero.  The Don't Fragment
            //        (DF) flag is set as follows: If the size of the translated IPv4
            //        packet is less than or equal to 1260 bytes, it is set to zero;
            //        otherwise, it is set to one."
            builder.df_flag(self.body().len() + IPV4_HEADER_LEN_BYTES > 1260);
            // TODO(https://fxbug.dev/92381): This needs an update once
            // we don't return early for fragment_header_present case.
            builder.fragment_offset(0);
            builder.mf_flag(false);
            builder
        };
        match self.proto() {
            Ipv6Proto::Proto(IpProto::Tcp) => {
                let v4_pkt_builder = v4_builder(Ipv4Proto::Proto(IpProto::Tcp));
                let args = TcpParseArgs::new(self.src_ip(), self.dst_ip());
                // TODO(https://fxbug.dev/92701): We're doing roughly similar work
                // in valid/invalid parsing case. Remove match statement and
                // update the checksum in place without needing to parse the TCP
                // segment once we have ability to update the checksum.
                match TcpSegment::parse(&mut self.body.as_bytes(), args) {
                    Ok(tcp) => {
                        // Creating a new tcp_serializer for IPv6 packet from
                        // the existing one ensures that checksum is
                        // updated due to changed IP addresses.
                        let tcp_serializer =
                            Nat64Serializer::Tcp(tcp.into_serializer(v4_src_addr, v4_dst_addr));
                        Nat64TranslationResult::Forward(tcp_serializer.encapsulate(v4_pkt_builder))
                    }
                    Err(msg) => {
                        debug!("Parsing of TCP segment failed: {:?}", msg);
                        // This means we can't create a TCP segment builder with
                        // updated checksum. Parsing may fail due to a variety of
                        // reasons, including incorrect checksum in incoming packet.
                        // We should still return a packet with IP payload copied
                        // as is from IPv6 to IPv4. This handling is similar to
                        // the handling of the case with unsupported protocol type
                        // as done in `Ipv6Proto::Other(val)` case below. The similar
                        // reasoning from RFC appiles here as well.
                        let common_serializer =
                            Nat64Serializer::Other(self.body().into_serializer());
                        Nat64TranslationResult::Forward(
                            common_serializer.encapsulate(v4_pkt_builder),
                        )
                    }
                }
            }
            // TODO(https://fxbug.dev/92701): We're doing roughly similar work
            // in valid/invalid parsing case. Remove match statement and
            // update the checksum in place without needing to parse the UDP segment
            // once we have ability to update checksum.
            Ipv6Proto::Proto(IpProto::Udp) => {
                let v4_pkt_builder = v4_builder(Ipv4Proto::Proto(IpProto::Udp));
                let args = UdpParseArgs::new(self.src_ip(), self.dst_ip());
                match UdpPacket::parse(&mut self.body.as_bytes(), args) {
                    Ok(udp) => {
                        // Creating a new udp_serializer for IPv6 packet from
                        // the existing one ensures that checksum is
                        // updated due to changed IP addresses.
                        let udp_serializer =
                            Nat64Serializer::Udp(udp.into_serializer(v4_src_addr, v4_dst_addr));
                        Nat64TranslationResult::Forward(udp_serializer.encapsulate(v4_pkt_builder))
                    }
                    Err(msg) => {
                        debug!("Parsing of UDP packet failed: {:?}", msg);
                        // This means we can't create a UDP packet builder with
                        // updated checksum. Parsing may fail due to a variety of
                        // reasons, including incorrect checksum in incoming packet.
                        // We should still return a packet with IP payload copied
                        // as is from IPv6 to IPv4. This handling is similar to
                        // the handling of the case with unsupported protocol type
                        // as done in `Ipv6Proto::Other(val)` case below. The similar
                        // reasoning from RFC appiles here as well.
                        let common_serializer =
                            Nat64Serializer::Other(self.body().into_serializer());
                        Nat64TranslationResult::Forward(
                            common_serializer.encapsulate(v4_pkt_builder),
                        )
                    }
                }
            }
            // TODO(https://fxbug.dev/92383): Implement ICMP packet translation
            // support here.
            Ipv6Proto::Icmpv6 => Nat64TranslationResult::Err(Nat64Error::NotImplemented),
            // For all other protocols, an IPv4 packet must be forwarded even if
            // the transport layer checksum update is not implemented.
            // As per RFC 7915 Section 5.1,
            //     "Protocol:
            //       ...
            //
            //       For the first 'next header' that does not match one of the cases
            //       above, its Next Header value (which contains the transport
            //       protocol number) is copied to the protocol field in the IPv4
            //       header.  This means that all transport protocols are translated.
            //
            //       Note:  Some translated protocols will fail at the receiver for
            //          various reasons: some are known to fail when translated (e.g.,
            //          IPsec Authentication Header (51)), and others will fail
            //          checksum validation if the address translation is not checksum
            //          neutral [RFC6052] and the translator does not update the
            //          transport protocol's checksum (because the translator doesn't
            //          support recalculating the checksum for that transport protocol;
            //          see Section 5.5)."
            Ipv6Proto::Other(val) => {
                let v4_pkt_builder = v4_builder(Ipv4Proto::Other(val));
                let common_serializer = Nat64Serializer::Other(self.body().into_serializer());
                Nat64TranslationResult::Forward(common_serializer.encapsulate(v4_pkt_builder))
            }
            Ipv6Proto::NoNextHeader => {
                let v4_pkt_builder = v4_builder(Ipv4Proto::Other(Ipv6Proto::NoNextHeader.into()));
                let common_serializer = Nat64Serializer::Other(self.body().into_serializer());
                Nat64TranslationResult::Forward(common_serializer.encapsulate(v4_pkt_builder))
            }
        }
    }
pub fn nat64_translate ( & self , v4_src_addr : Ipv4Addr , v4_dst_addr : Ipv4Addr , ) -> Nat64TranslationResult < impl Serializer < Buffer = EmptyBuf > + Debug + ' _ , Nat64Error > { // A single `Serializer` type so that all possible return values from // this function have the same type. # [ derive ( Debug ) ] enum Nat64Serializer < T , U , O > { Tcp ( T ) , Udp ( U ) , Other ( O ) , } impl < T , U , O > Serializer for Nat64Serializer < T , U , O > where T : Serializer < Buffer = EmptyBuf > , U : Serializer < Buffer = EmptyBuf > , O : Serializer < Buffer = EmptyBuf > , { type Buffer = EmptyBuf ; fn serialize < B , PB , P > ( self , outer : PB , provider : P , ) -> Result < B , ( SerializeError < P :: Error > , Self ) > where B : TargetBuffer , PB : NestedPacketBuilder , P : BufferProvider < Self :: Buffer , B > , { match self { Nat64Serializer :: Tcp ( serializer ) => serializer . serialize ( outer , provider ) . map_err ( | ( err , ser ) | ( err , Nat64Serializer :: Tcp ( ser ) ) ) , Nat64Serializer :: Udp ( serializer ) => serializer . serialize ( outer , provider ) . map_err ( | ( err , ser ) | ( err , Nat64Serializer :: Udp ( ser ) ) ) , Nat64Serializer :: Other ( serializer ) => serializer . serialize ( outer , provider ) . map_err ( | ( err , ser ) | ( err , Nat64Serializer :: Other ( ser ) ) ) , } } } // TODO(https://fxbug.dev/92381): Add support for fragmented packets // forwarding. if self . fragment_header_present ( ) { return Nat64TranslationResult :: Err ( Nat64Error :: NotImplemented ) ; } let v4_builder = | v4_proto | { let mut builder = Ipv4PacketBuilder :: new ( v4_src_addr , v4_dst_addr , self . hop_limit ( ) , v4_proto ) ; builder . dscp ( self . ds ( ) ) ; builder . ecn ( self . ecn ( ) ) ; // The IPv4 header length is 20 bytes (so IHL field value is 5), as // no header options are present in translated IPv4 packet. // As per RFC 7915 Section 5.1: //  "Internet Header Length:  5 (no IPv4 options)" const IPV4_HEADER_LEN_BYTES : usize = HDR_PREFIX_LEN ; // As per RFC 7915 Section 5.1, //    "Flags:  The More Fragments flag is set to zero.  The Don't Fragment //        (DF) flag is set as follows: If the size of the translated IPv4 //        packet is less than or equal to 1260 bytes, it is set to zero; //        otherwise, it is set to one." builder . df_flag ( self . body ( ) . len ( ) + IPV4_HEADER_LEN_BYTES > 1260 ) ; // TODO(https://fxbug.dev/92381): This needs an update once // we don't return early for fragment_header_present case. builder . fragment_offset ( 0 ) ; builder . mf_flag ( false ) ; builder } ; match self . proto ( ) { Ipv6Proto :: Proto ( IpProto :: Tcp ) => { let v4_pkt_builder = v4_builder ( Ipv4Proto :: Proto ( IpProto :: Tcp ) ) ; let args = TcpParseArgs :: new ( self . src_ip ( ) , self . dst_ip ( ) ) ; // TODO(https://fxbug.dev/92701): We're doing roughly similar work // in valid/invalid parsing case. Remove match statement and // update the checksum in place without needing to parse the TCP // segment once we have ability to update the checksum. match TcpSegment :: parse ( & mut self . body . as_bytes ( ) , args ) { Ok ( tcp ) => { // Creating a new tcp_serializer for IPv6 packet from // the existing one ensures that checksum is // updated due to changed IP addresses. let tcp_serializer = Nat64Serializer :: Tcp ( tcp . into_serializer ( v4_src_addr , v4_dst_addr ) ) ; Nat64TranslationResult :: Forward ( tcp_serializer . encapsulate ( v4_pkt_builder ) ) } Err ( msg ) => { debug ! ( " " msg ) ; // This means we can't create a TCP segment builder with // updated checksum. Parsing may fail due to a variety of // reasons, including incorrect checksum in incoming packet. // We should still return a packet with IP payload copied // as is from IPv6 to IPv4. This handling is similar to // the handling of the case with unsupported protocol type // as done in `Ipv6Proto::Other(val)` case below. The similar // reasoning from RFC appiles here as well. let common_serializer = Nat64Serializer :: Other ( self . body ( ) . into_serializer ( ) ) ; Nat64TranslationResult :: Forward ( common_serializer . encapsulate ( v4_pkt_builder ) , ) } } } // TODO(https://fxbug.dev/92701): We're doing roughly similar work // in valid/invalid parsing case. Remove match statement and // update the checksum in place without needing to parse the UDP segment // once we have ability to update checksum. Ipv6Proto :: Proto ( IpProto :: Udp ) => { let v4_pkt_builder = v4_builder ( Ipv4Proto :: Proto ( IpProto :: Udp ) ) ; let args = UdpParseArgs :: new ( self . src_ip ( ) , self . dst_ip ( ) ) ; match UdpPacket :: parse ( & mut self . body . as_bytes ( ) , args ) { Ok ( udp ) => { // Creating a new udp_serializer for IPv6 packet from // the existing one ensures that checksum is // updated due to changed IP addresses. let udp_serializer = Nat64Serializer :: Udp ( udp . into_serializer ( v4_src_addr , v4_dst_addr ) ) ; Nat64TranslationResult :: Forward ( udp_serializer . encapsulate ( v4_pkt_builder ) ) } Err ( msg ) => { debug ! ( " " msg ) ; // This means we can't create a UDP packet builder with // updated checksum. Parsing may fail due to a variety of // reasons, including incorrect checksum in incoming packet. // We should still return a packet with IP payload copied // as is from IPv6 to IPv4. This handling is similar to // the handling of the case with unsupported protocol type // as done in `Ipv6Proto::Other(val)` case below. The similar // reasoning from RFC appiles here as well. let common_serializer = Nat64Serializer :: Other ( self . body ( ) . into_serializer ( ) ) ; Nat64TranslationResult :: Forward ( common_serializer . encapsulate ( v4_pkt_builder ) , ) } } } // TODO(https://fxbug.dev/92383): Implement ICMP packet translation // support here. Ipv6Proto :: Icmpv6 => Nat64TranslationResult :: Err ( Nat64Error :: NotImplemented ) , // For all other protocols, an IPv4 packet must be forwarded even if // the transport layer checksum update is not implemented. // As per RFC 7915 Section 5.1, //     "Protocol: //       ... // //       For the first 'next header' that does not match one of the cases //       above, its Next Header value (which contains the transport //       protocol number) is copied to the protocol field in the IPv4 //       header.  This means that all transport protocols are translated. // //       Note:  Some translated protocols will fail at the receiver for //          various reasons: some are known to fail when translated (e.g., //          IPsec Authentication Header (51)), and others will fail //          checksum validation if the address translation is not checksum //          neutral [RFC6052] and the translator does not update the //          transport protocol's checksum (because the translator doesn't //          support recalculating the checksum for that transport protocol; //          see Section 5.5)." Ipv6Proto :: Other ( val ) => { let v4_pkt_builder = v4_builder ( Ipv4Proto :: Other ( val ) ) ; let common_serializer = Nat64Serializer :: Other ( self . body ( ) . into_serializer ( ) ) ; Nat64TranslationResult :: Forward ( common_serializer . encapsulate ( v4_pkt_builder ) ) } Ipv6Proto :: NoNextHeader => { let v4_pkt_builder = v4_builder ( Ipv4Proto :: Other ( Ipv6Proto :: NoNextHeader . into ( ) ) ) ; let common_serializer = Nat64Serializer :: Other ( self . body ( ) . into_serializer ( ) ) ; Nat64TranslationResult :: Forward ( common_serializer . encapsulate ( v4_pkt_builder ) ) } } }
Performs the header translation part of NAT64 as described in [RFC
7915].
Performs the header translation part of NAT64 as described in [ RFC 7915 ] .
&self
v4_src_addr
Ipv4Addr
v4_dst_addr
Ipv4Addr
errors
`nat64_translate` will return an error if support has not yet been
implemented for translating a particular IP protocol.


` nat64_translate ` will return an error if support has not yet been implemented for translating a particular IP protocol .