netlink_packet_route/rtnl/tc/nlas/action/
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::{self, DefaultNla, NlaBuffer},
10    traits::{Emitable, Parseable},
11    DecodeError,
12};
13
14use crate::tc::{constants::*, TC_GEN_BUF_LEN};
15
16pub const KIND: &str = "nat";
17pub const TC_NAT_BUF_LEN: usize = TC_GEN_BUF_LEN + 16;
18
19#[derive(Debug, PartialEq, Eq, Clone)]
20#[non_exhaustive]
21pub enum Nla {
22    Unspec(Vec<u8>),
23    Tm(Vec<u8>),
24    Parms(TcNat),
25    Other(DefaultNla),
26}
27
28impl nla::Nla for Nla {
29    fn value_len(&self) -> usize {
30        use self::Nla::*;
31        match self {
32            Unspec(bytes) | Tm(bytes) => bytes.len(),
33            Parms(_) => TC_NAT_BUF_LEN,
34            Other(attr) => attr.value_len(),
35        }
36    }
37
38    fn emit_value(&self, buffer: &mut [u8]) {
39        use self::Nla::*;
40        match self {
41            Unspec(bytes) | Tm(bytes) => {
42                buffer.copy_from_slice(bytes.as_slice())
43            }
44            Parms(p) => p.emit(buffer),
45            Other(attr) => attr.emit_value(buffer),
46        }
47    }
48    fn kind(&self) -> u16 {
49        use self::Nla::*;
50        match self {
51            Unspec(_) => TCA_NAT_UNSPEC,
52            Tm(_) => TCA_NAT_TM,
53            Parms(_) => TCA_NAT_PARMS,
54            Other(nla) => nla.kind(),
55        }
56    }
57}
58
59impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {
60    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
61        use self::Nla::*;
62        let payload = buf.value();
63        Ok(match buf.kind() {
64            TCA_NAT_UNSPEC => Unspec(payload.to_vec()),
65            TCA_NAT_TM => Tm(payload.to_vec()),
66            TCA_NAT_PARMS => {
67                Parms(TcNat::parse(&TcNatBuffer::new_checked(payload)?)?)
68            }
69            _ => Other(DefaultNla::parse(buf)?),
70        })
71    }
72}
73
74#[derive(Debug, PartialEq, Eq, Clone, Default)]
75#[non_exhaustive]
76pub struct TcNat {
77    pub index: u32,
78    pub capab: u32,
79    pub action: i32,
80    pub refcnt: i32,
81    pub bindcnt: i32,
82
83    pub old_addr: Vec<u8>,
84    pub new_addr: Vec<u8>,
85    pub mask: Vec<u8>,
86    pub flags: u32,
87}
88
89buffer!(TcNatBuffer(TC_NAT_BUF_LEN) {
90    index: (u32, 0..4),
91    capab: (u32, 4..8),
92    action: (i32, 8..12),
93    refcnt: (i32, 12..16),
94    bindcnt: (i32, 16..20),
95
96    old_addr: (slice, TC_GEN_BUF_LEN..(TC_GEN_BUF_LEN+4)),
97    new_addr: (slice, (TC_GEN_BUF_LEN +4)..(TC_GEN_BUF_LEN+8)),
98    mask: (slice, (TC_GEN_BUF_LEN +8)..(TC_GEN_BUF_LEN+12)),
99    flags: (u32, (TC_GEN_BUF_LEN+12)..TC_NAT_BUF_LEN),
100});
101
102impl TcNat {
103    pub fn set_new_addr(mut self, target: Ipv4Addr) -> Self {
104        self.new_addr = target.octets().to_vec();
105        self
106    }
107
108    pub fn set_old_addr(mut self, target: Ipv4Addr) -> Self {
109        self.old_addr = target.octets().to_vec();
110        self
111    }
112
113    pub fn set_prefix(mut self, prefix_len: usize) -> Self {
114        assert!(prefix_len <= 32);
115
116        let prefix: u32 = if prefix_len == 0 {
117            0x0
118        } else {
119            !((1 << (32 - prefix_len)) - 1)
120        };
121        self.mask = prefix.to_be_bytes().to_vec();
122
123        self
124    }
125
126    pub fn egress(mut self) -> Self {
127        self.flags = TCA_NAT_FLAG_EGRESS;
128        self
129    }
130}
131impl Emitable for TcNat {
132    fn buffer_len(&self) -> usize {
133        TC_NAT_BUF_LEN
134    }
135
136    fn emit(&self, buffer: &mut [u8]) {
137        let mut packet = TcNatBuffer::new(buffer);
138        packet.set_index(self.index);
139        packet.set_capab(self.capab);
140        packet.set_action(self.action);
141        packet.set_refcnt(self.refcnt);
142        packet.set_bindcnt(self.bindcnt);
143
144        packet.old_addr_mut().copy_from_slice(&self.old_addr[0..4]);
145        packet.new_addr_mut().copy_from_slice(&self.new_addr[0..4]);
146        packet.mask_mut().copy_from_slice(&self.mask[0..4]);
147        packet.set_flags(self.flags);
148    }
149}
150
151impl<'buf, T: AsRef<[u8]> + ?Sized> Parseable<TcNatBuffer<&'buf T>> for TcNat {
152    fn parse(buf: &TcNatBuffer<&'buf T>) -> Result<Self, DecodeError> {
153        Ok(Self {
154            index: buf.index(),
155            capab: buf.capab(),
156            action: buf.action(),
157            refcnt: buf.refcnt(),
158            bindcnt: buf.bindcnt(),
159            old_addr: buf.old_addr().to_vec(),
160            new_addr: buf.new_addr().to_vec(),
161            mask: buf.mask().to_vec(),
162            flags: buf.flags(),
163        })
164    }
165}