@push.rocks/smartnftables 4.3.1 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,10 @@
4
4
  //! variable interface (index and name), the packet and conntrack protocols, the
5
5
  //! live tuple and the originally tracked tuple. An element is one grant with its
6
6
  //! live tuple equal to its original tuple, so translated flows never match.
7
+ use super::keys::{
8
+ Field, Loads, CT_ORIGINAL_DADDR, CT_ORIGINAL_DPORT, CT_ORIGINAL_SADDR, CT_PROTOCOL, IP_DADDR,
9
+ IP_SADDR, L4PROTO, OIF, OIFNAME, TH_DPORT,
10
+ };
7
11
  use super::*;
8
12
 
9
13
  /// Every exact host-origin flow of the scope, keyed on its full tuple.
@@ -11,6 +15,42 @@ pub(super) const TUPLE_SET: &str = "host_grant";
11
15
  /// Router raw ingress runs before conntrack: exact arriving tuples only.
12
16
  pub(super) const ARRIVAL_SET: &str = "host_grant_arrival";
13
17
 
18
+ /// The tuple key of a link-independent scope: both protocols, the live tuple
19
+ /// and the originally tracked tuple, as the original direction loads them.
20
+ pub(super) const TUPLE: [Field; 8] = [
21
+ L4PROTO,
22
+ CT_PROTOCOL,
23
+ IP_SADDR,
24
+ IP_DADDR,
25
+ TH_DPORT,
26
+ CT_ORIGINAL_SADDR,
27
+ CT_ORIGINAL_DADDR,
28
+ CT_ORIGINAL_DPORT,
29
+ ];
30
+ /// The tuple key behind the variable interface: its index and name first.
31
+ const LINKED_TUPLE: [Field; 10] = [
32
+ OIF,
33
+ OIFNAME,
34
+ L4PROTO,
35
+ CT_PROTOCOL,
36
+ IP_SADDR,
37
+ IP_DADDR,
38
+ TH_DPORT,
39
+ CT_ORIGINAL_SADDR,
40
+ CT_ORIGINAL_DADDR,
41
+ CT_ORIGINAL_DPORT,
42
+ ];
43
+ /// The exact arriving tuple: protocol, addresses and port.
44
+ const ARRIVAL: [Field; 4] = [L4PROTO, IP_SADDR, IP_DADDR, TH_DPORT];
45
+
46
+ fn tuple(linked: bool) -> &'static [Field] {
47
+ if linked {
48
+ &LINKED_TUPLE
49
+ } else {
50
+ &TUPLE
51
+ }
52
+ }
53
+
14
54
  /// Register numbers as Linux dumps them: 16-byte aligned registers use the
15
55
  /// legacy NFT_REG_1..4 names, every other 4-byte register NFT_REG32_xx.
16
56
  pub(super) fn register(index: u32) -> u32 {
@@ -38,10 +78,11 @@ pub(super) fn payload_to(base: u32, offset: u32, length: u32, index: u32) -> Att
38
78
  index,
39
79
  )
40
80
  }
41
- pub(super) fn ct_to(key: u32, original: bool, index: u32) -> Attr {
81
+ /// A conntrack key of the original (0) or reply (1) tuple, or of neither.
82
+ pub(super) fn ct_to(key: u32, direction: Option<u8>, index: u32) -> Attr {
42
83
  let mut data = vec![Attr::u32(2, key)];
43
- if original {
44
- data.push(Attr::bytes(3, vec![0]));
84
+ if let Some(direction) = direction {
85
+ data.push(Attr::bytes(3, vec![direction]));
45
86
  }
46
87
  store("ct", data, index)
47
88
  }
@@ -64,26 +105,22 @@ fn word(bytes: &[u8]) -> Vec<u8> {
64
105
  /// Key loads for one direction, then the lookup in `set`. `linked` adds the
65
106
  /// variable interface: the outgoing interface of the original direction, the
66
107
  /// incoming interface of the reply.
67
- pub(super) fn tuple_lookup(set: &str, linked: bool, reply: bool) -> Vec<Attr> {
68
- let mut result = Vec::new();
69
- let mut index = 4;
108
+ pub(super) fn tuple_lookup(set: &str, linked: bool, reply: bool) -> Result<Vec<Attr>> {
109
+ let mut loads = Loads::new();
70
110
  if linked {
71
- result.push(meta_to(if reply { 4 } else { 5 }, index));
72
- result.push(meta_to(if reply { 6 } else { 7 }, index + 1));
73
- index += 5;
111
+ loads.link(reply);
74
112
  }
75
- result.push(meta_to(16, index));
76
- result.push(ct_to(10, false, index + 1));
77
113
  // The grant's source and destination are the packet's own addresses in the
78
114
  // original direction and swapped on the reply; the port is the workload's.
79
- result.push(payload_to(1, if reply { 16 } else { 12 }, 4, index + 2));
80
- result.push(payload_to(1, if reply { 12 } else { 16 }, 4, index + 3));
81
- result.push(payload_to(2, if reply { 0 } else { 2 }, 2, index + 4));
82
- result.push(ct_to(19, true, index + 5));
83
- result.push(ct_to(20, true, index + 6));
84
- result.push(ct_to(12, true, index + 7));
85
- result.push(lookup(set));
86
- result
115
+ loads
116
+ .protocols()
117
+ .address(!reply)
118
+ .address(reply)
119
+ .port(reply)
120
+ .original_address(true)
121
+ .original_address(false)
122
+ .original_port(false);
123
+ loads.lookup(set, tuple(linked))
87
124
  }
88
125
  pub(super) fn tuple_key(grant: &HostGrant, link: Option<&LocalLink>) -> Result<Vec<u8>> {
89
126
  let protocol = word(&[protocol(&grant.protocol)]);
@@ -120,11 +157,15 @@ pub(super) fn tuple_set<'s>(
120
157
  link: impl Fn(&HostGrant) -> Result<Option<&'s LocalLink>>,
121
158
  ) -> Result<()> {
122
159
  let mut keys = Vec::new();
160
+ let mut linked = false;
123
161
  for grant in grants {
124
- keys.push(tuple_key(grant, link(grant)?)?);
162
+ let link = link(grant)?;
163
+ linked = link.is_some();
164
+ keys.push(tuple_key(grant, link)?);
125
165
  }
126
- let length = keys.first().map(Vec::len).ok_or(crate::Error::Invalid)?;
127
- program.set(TUPLE_SET, 1, length)?;
166
+ // Every element has the declared key's length, so a scope never mixes them.
167
+ require(!keys.is_empty())?;
168
+ program.exact_set(TUPLE_SET, 1, tuple(linked), None)?;
128
169
  program.elements(TUPLE_SET, keys)
129
170
  }
130
171
  pub(super) fn arrival_set(program: &mut Program<'_>, grants: &[HostGrant]) -> Result<()> {
@@ -136,18 +177,17 @@ pub(super) fn arrival_set(program: &mut Program<'_>, grants: &[HostGrant]) -> Re
136
177
  key.extend(word(&grant.destination_port.to_be_bytes()));
137
178
  keys.push(key);
138
179
  }
139
- program.set(ARRIVAL_SET, 2, 16)?;
180
+ program.exact_set(ARRIVAL_SET, 2, &ARRIVAL, None)?;
140
181
  program.elements(ARRIVAL_SET, keys)
141
182
  }
142
183
  /// Exact arriving tuple, before conntrack: protocol, addresses and port.
143
- pub(super) fn arrival_lookup() -> Vec<Attr> {
144
- vec![
145
- meta_to(16, 4),
146
- payload_to(1, 12, 4, 5),
147
- payload_to(1, 16, 4, 6),
148
- payload_to(2, 2, 2, 7),
149
- lookup(ARRIVAL_SET),
150
- ]
184
+ pub(super) fn arrival_lookup() -> Result<Vec<Attr>> {
185
+ Loads::new()
186
+ .protocol()
187
+ .address(true)
188
+ .address(false)
189
+ .port(false)
190
+ .lookup(ARRIVAL_SET, &ARRIVAL)
151
191
  }
152
192
 
153
193
  /// Four admissions whatever the number of grants: the ESTABLISHED original
@@ -170,7 +210,7 @@ pub(super) fn admissions(
170
210
  result
171
211
  };
172
212
  let mut established = envelope(false, 2);
173
- established.extend(tuple_lookup(TUPLE_SET, linked, false));
213
+ established.extend(tuple_lookup(TUPLE_SET, linked, false)?);
174
214
  program.end(chains[0], established, 1)?;
175
215
  for transport in ["udp", "tcp"] {
176
216
  let mut opening = envelope(false, 8);
@@ -178,10 +218,10 @@ pub(super) fn admissions(
178
218
  if transport == "tcp" {
179
219
  opening.extend(opening_tcp());
180
220
  }
181
- opening.extend(tuple_lookup(TUPLE_SET, linked, false));
221
+ opening.extend(tuple_lookup(TUPLE_SET, linked, false)?);
182
222
  program.end(chains[0], opening, 1)?;
183
223
  }
184
224
  let mut reply = envelope(true, 2);
185
- reply.extend(tuple_lookup(TUPLE_SET, linked, true));
225
+ reply.extend(tuple_lookup(TUPLE_SET, linked, true)?);
186
226
  program.end(chains[1], reply, 1)
187
227
  }