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