netlink_packet_route/tc/actions/
nat.rs

1// SPDX-License-Identifier: MIT
2
3/// Nat action
4///
5/// The nat action maps one IP prefix to another
6use std::net::Ipv4Addr;
7
8use netlink_packet_core::{
9    DecodeError, DefaultNla, Emitable, Nla, NlaBuffer, Parseable,
10};
11
12use super::{
13    nat_flag::TcNatFlags, TcActionGeneric, TcActionGenericBuffer, Tcf,
14    TcfBuffer, TC_TCF_BUF_LEN,
15};
16
17const TCA_NAT_PARMS: u16 = 1;
18const TCA_NAT_TM: u16 = 2;
19
20/// Network address translation action.
21#[derive(Debug, PartialEq, Eq, Clone)]
22#[non_exhaustive]
23pub struct TcActionNat {}
24
25impl TcActionNat {
26    pub(crate) const KIND: &'static str = "nat";
27}
28
29/// Options for the [`TcActionNat`] action.
30#[derive(Debug, PartialEq, Eq, Clone)]
31#[non_exhaustive]
32pub enum TcActionNatOption {
33    /// Rule installation and usage time
34    Tm(Tcf),
35    /// Parameters for the nat action.
36    Parms(TcNat),
37    /// Other attributes unknown at the time of writing.
38    Other(DefaultNla),
39}
40
41impl Nla for TcActionNatOption {
42    fn value_len(&self) -> usize {
43        match self {
44            Self::Tm(_) => TC_TCF_BUF_LEN,
45            Self::Parms(v) => v.buffer_len(),
46            Self::Other(attr) => attr.value_len(),
47        }
48    }
49
50    fn emit_value(&self, buffer: &mut [u8]) {
51        match self {
52            Self::Tm(p) => p.emit(buffer),
53            Self::Parms(p) => p.emit(buffer),
54            Self::Other(attr) => attr.emit_value(buffer),
55        }
56    }
57    fn kind(&self) -> u16 {
58        match self {
59            Self::Tm(_) => TCA_NAT_TM,
60            Self::Parms(_) => TCA_NAT_PARMS,
61            Self::Other(nla) => nla.kind(),
62        }
63    }
64}
65
66impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
67    for TcActionNatOption
68{
69    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
70        let payload = buf.value();
71        Ok(match buf.kind() {
72            TCA_NAT_TM => {
73                Self::Tm(Tcf::parse(&TcfBuffer::new_checked(payload)?)?)
74            }
75            TCA_NAT_PARMS => {
76                Self::Parms(TcNat::parse(&TcNatBuffer::new_checked(payload)?)?)
77            }
78            _ => Self::Other(DefaultNla::parse(buf)?),
79        })
80    }
81}
82
83const TC_NAT_BUF_LEN: usize = TcActionGeneric::BUF_LEN + 16;
84
85/// Network address translation action.
86#[derive(Debug, PartialEq, Eq, Clone)]
87#[non_exhaustive]
88pub struct TcNat {
89    /// Common attributes for all actions.
90    pub generic: TcActionGeneric,
91    /// Original address.
92    pub old_addr: Ipv4Addr,
93    /// New address.
94    pub new_addr: Ipv4Addr,
95    /// Mask of the old address
96    pub mask: Ipv4Addr,
97    /// Flags for the NAT action.
98    pub flags: TcNatFlags,
99}
100
101impl Default for TcNat {
102    fn default() -> Self {
103        Self {
104            generic: TcActionGeneric::default(),
105            old_addr: Ipv4Addr::UNSPECIFIED,
106            new_addr: Ipv4Addr::UNSPECIFIED,
107            mask: Ipv4Addr::UNSPECIFIED,
108            flags: TcNatFlags::empty(),
109        }
110    }
111}
112
113buffer!(TcNatBuffer(TC_NAT_BUF_LEN) {
114    generic: (slice, 0..TcActionGeneric::BUF_LEN),
115    old_addr: (slice, TcActionGeneric::BUF_LEN..(TcActionGeneric::BUF_LEN+4)),
116    new_addr: (slice, (TcActionGeneric::BUF_LEN+4)..(TcActionGeneric::BUF_LEN+8)),
117    mask: (slice, (TcActionGeneric::BUF_LEN+8)..(TcActionGeneric::BUF_LEN+12)),
118    flags: (u32, (TcActionGeneric::BUF_LEN+12)..TC_NAT_BUF_LEN),
119});
120
121impl Emitable for TcNat {
122    fn buffer_len(&self) -> usize {
123        TC_NAT_BUF_LEN
124    }
125
126    fn emit(&self, buffer: &mut [u8]) {
127        let mut packet = TcNatBuffer::new(buffer);
128        self.generic.emit(packet.generic_mut());
129        packet
130            .old_addr_mut()
131            .copy_from_slice(&self.old_addr.octets());
132        packet
133            .new_addr_mut()
134            .copy_from_slice(&self.new_addr.octets());
135        packet.mask_mut().copy_from_slice(&self.mask.octets());
136        packet.set_flags(self.flags.bits());
137    }
138}
139
140impl<T: AsRef<[u8]> + ?Sized> Parseable<TcNatBuffer<&T>> for TcNat {
141    fn parse(buf: &TcNatBuffer<&T>) -> Result<Self, DecodeError> {
142        Ok(Self {
143            generic: TcActionGeneric::parse(&TcActionGenericBuffer::new(
144                buf.generic(),
145            ))?,
146            old_addr: parse_ipv4(buf.old_addr())?,
147            new_addr: parse_ipv4(buf.new_addr())?,
148            mask: parse_ipv4(buf.mask())?,
149            flags: TcNatFlags::from_bits_retain(buf.flags()),
150        })
151    }
152}
153
154fn parse_ipv4(data: &[u8]) -> Result<Ipv4Addr, DecodeError> {
155    if data.len() != 4 {
156        Err(DecodeError::from(format!(
157            "Invalid length of IPv4 Address, expecting 4 bytes, but got \
158             {data:?}"
159        )))
160    } else {
161        Ok(Ipv4Addr::new(data[0], data[1], data[2], data[3]))
162    }
163}