@push.rocks/smartnftables 4.4.0 → 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.
- package/changelog.md +7 -0
- package/dist_rust/smartnftables_linux_amd64_musl +0 -0
- package/dist_rust/smartnftables_linux_amd64_musl.tsrust-build.json +4 -4
- package/dist_rust/smartnftables_linux_arm64_musl +0 -0
- package/dist_rust/smartnftables_linux_arm64_musl.tsrust-build.json +4 -4
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/package.json +1 -1
- package/readme.md +52 -1
- package/rust/src/egress.compile.rs +105 -38
- package/rust/src/egress.hostgrant.rs +74 -42
- package/rust/src/egress.keys.rs +380 -55
- package/rust/src/egress.leased.rs +71 -42
- package/rust/src/egress.poolguard.rs +8 -13
- package/rust/src/egress.private.rs +32 -37
- package/rust/src/egress.published.rs +74 -47
- package/rust/src/egress.router.rs +1 -1
- package/rust/src/egress.rs +8 -0
- package/rust/src/egress.workloadgrant.rs +30 -28
- package/rust/src/egress_keys_tests.rs +150 -0
- package/rust/src/egress_tests.rs +47 -4
- package/rust/src/owner.rs +96 -28
- package/rust/src/owner_listing_tests.rs +634 -0
- package/rust/src/owner_tests.rs +3 -0
- package/ts/00_commitinfo_data.ts +1 -1
|
@@ -6,13 +6,26 @@
|
|
|
6
6
|
//! rules prove through `private_link`), the protocols, the live and originally
|
|
7
7
|
//! tracked tuple and the generation's conntrack zone. Generation labels live in
|
|
8
8
|
//! two exact sets, so a label alone never authorizes a changed grant.
|
|
9
|
-
use super::keys::{
|
|
9
|
+
use super::keys::{
|
|
10
|
+
self, Field, Key, Loads, CT_LABEL, CT_ORIGINAL_DADDR, CT_ORIGINAL_DPORT, CT_ORIGINAL_SADDR,
|
|
11
|
+
CT_ORIGINAL_SPORT, CT_PROTOCOL, CT_ZONE, IIF, IP_DADDR, IP_SADDR, L4PROTO, TH_DPORT, TH_SPORT,
|
|
12
|
+
};
|
|
10
13
|
use super::private::known;
|
|
11
14
|
use super::*;
|
|
12
15
|
|
|
13
16
|
const LABEL_SET: &str = "leased_label";
|
|
14
17
|
const GENERATION_MAP: &str = "leased_generation";
|
|
15
|
-
const
|
|
18
|
+
const LABEL_KEY: [Field; 2] = [CT_ZONE, CT_LABEL];
|
|
19
|
+
/// The generation map's key is the zone padded to its register, as every
|
|
20
|
+
/// release before typed sets declared it.
|
|
21
|
+
const GENERATION_KEY: [Field; 1] = [CT_ZONE];
|
|
22
|
+
const GENERATION_DATA: [Field; 1] = [CT_LABEL];
|
|
23
|
+
const RETURN: [Field; 5] = [L4PROTO, IP_SADDR, IP_DADDR, TH_SPORT, TH_DPORT];
|
|
24
|
+
/// The zone a classification stores.
|
|
25
|
+
const ZONE_DATA: [Field; 1] = [CT_ZONE];
|
|
26
|
+
/// The source NAT a flow map stores: the transit address and the first and
|
|
27
|
+
/// last port of the leased range.
|
|
28
|
+
const TRANSLATION: [Field; 3] = [IP_SADDR, TH_SPORT, TH_SPORT];
|
|
16
29
|
|
|
17
30
|
/// Platform grants precede the protected barrier and public grants follow it.
|
|
18
31
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
|
@@ -69,24 +82,26 @@ impl Shape {
|
|
|
69
82
|
}
|
|
70
83
|
/// A source port field only where the grants name one, then the
|
|
71
84
|
/// destination port.
|
|
72
|
-
fn ports(self) -> Vec<
|
|
85
|
+
fn ports(self, source: Field, destination: Field) -> Vec<Field> {
|
|
73
86
|
if self.sourced {
|
|
74
|
-
vec![
|
|
87
|
+
vec![source, destination]
|
|
75
88
|
} else {
|
|
76
|
-
vec![
|
|
89
|
+
vec![destination]
|
|
77
90
|
}
|
|
78
91
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
fields
|
|
92
|
+
/// The classification key, as the incoming direction loads it.
|
|
93
|
+
fn classification(self) -> Vec<Field> {
|
|
94
|
+
let mut fields = vec![IIF, L4PROTO, IP_SADDR, IP_DADDR];
|
|
95
|
+
fields.extend(self.ports(TH_SPORT, TH_DPORT));
|
|
82
96
|
fields
|
|
83
97
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
fields
|
|
87
|
-
fields.extend(
|
|
88
|
-
fields.extend(
|
|
89
|
-
fields.
|
|
98
|
+
/// The flow key, as the original direction loads it.
|
|
99
|
+
fn flow(self) -> Vec<Field> {
|
|
100
|
+
let mut fields = vec![IIF, L4PROTO, CT_PROTOCOL, IP_SADDR, IP_DADDR];
|
|
101
|
+
fields.extend(self.ports(TH_SPORT, TH_DPORT));
|
|
102
|
+
fields.extend([CT_ORIGINAL_SADDR, CT_ORIGINAL_DADDR]);
|
|
103
|
+
fields.extend(self.ports(CT_ORIGINAL_SPORT, CT_ORIGINAL_DPORT));
|
|
104
|
+
fields.push(CT_ZONE);
|
|
90
105
|
fields
|
|
91
106
|
}
|
|
92
107
|
fn key_ports(self, key: Key, grant: &Grant) -> Key {
|
|
@@ -151,8 +166,15 @@ pub(super) fn sets(program: &mut Program<'_>, scope: &RouterScope) -> Result<()>
|
|
|
151
166
|
labels.push((key, None));
|
|
152
167
|
generations.push((zone_word(generation.conntrack_zone), Some(label)));
|
|
153
168
|
}
|
|
154
|
-
keys::exact(program, LABEL_SET, 38,
|
|
155
|
-
keys::exact(
|
|
169
|
+
keys::exact(program, LABEL_SET, 38, &LABEL_KEY, None, labels)?;
|
|
170
|
+
keys::exact(
|
|
171
|
+
program,
|
|
172
|
+
GENERATION_MAP,
|
|
173
|
+
39,
|
|
174
|
+
&GENERATION_KEY,
|
|
175
|
+
Some(&GENERATION_DATA),
|
|
176
|
+
generations,
|
|
177
|
+
)?;
|
|
156
178
|
for kind in [Kind::Platform, Kind::Public] {
|
|
157
179
|
let mut returns = Vec::new();
|
|
158
180
|
for shape in Shape::all(kind) {
|
|
@@ -212,7 +234,7 @@ pub(super) fn sets(program: &mut Program<'_>, scope: &RouterScope) -> Result<()>
|
|
|
212
234
|
&shape.name("zone"),
|
|
213
235
|
shape.id(0),
|
|
214
236
|
&shape.classification(),
|
|
215
|
-
Some(
|
|
237
|
+
Some(&ZONE_DATA),
|
|
216
238
|
classification,
|
|
217
239
|
)?;
|
|
218
240
|
keys::interval(
|
|
@@ -220,12 +242,19 @@ pub(super) fn sets(program: &mut Program<'_>, scope: &RouterScope) -> Result<()>
|
|
|
220
242
|
&shape.name("flow"),
|
|
221
243
|
shape.id(1),
|
|
222
244
|
&shape.flow(),
|
|
223
|
-
Some(
|
|
245
|
+
Some(&TRANSLATION),
|
|
224
246
|
flows,
|
|
225
247
|
)?;
|
|
226
248
|
}
|
|
227
249
|
let id = 48 + 8 + u32::from(kind == Kind::Public);
|
|
228
|
-
keys::interval(
|
|
250
|
+
keys::interval(
|
|
251
|
+
program,
|
|
252
|
+
&kind.returns(),
|
|
253
|
+
id,
|
|
254
|
+
&RETURN,
|
|
255
|
+
Some(&ZONE_DATA),
|
|
256
|
+
returns,
|
|
257
|
+
)?;
|
|
229
258
|
}
|
|
230
259
|
Ok(())
|
|
231
260
|
}
|
|
@@ -260,15 +289,15 @@ pub(super) fn classification(
|
|
|
260
289
|
};
|
|
261
290
|
if !present(scope, shape, false).is_empty() {
|
|
262
291
|
let mut expressions = ipv4();
|
|
263
|
-
expressions.extend(known(true));
|
|
264
|
-
expressions.extend(tuple(true).map(&shape.name("zone")));
|
|
292
|
+
expressions.extend(known(true)?);
|
|
293
|
+
expressions.extend(tuple(true).map(&shape.name("zone"), &shape.classification())?);
|
|
265
294
|
expressions.push(zone_from_data());
|
|
266
295
|
program.end("raw_in", expressions, 1)?;
|
|
267
296
|
}
|
|
268
297
|
if !present(scope, shape, true).is_empty() {
|
|
269
298
|
let mut expressions = ipv4();
|
|
270
299
|
expressions.extend(link(&scope.handoff, false));
|
|
271
|
-
expressions.extend(tuple(false).map(&shape.name("zone")));
|
|
300
|
+
expressions.extend(tuple(false).map(&shape.name("zone"), &shape.classification())?);
|
|
272
301
|
expressions.push(zone_from_data());
|
|
273
302
|
program.end("raw_out", expressions, 1)?;
|
|
274
303
|
}
|
|
@@ -283,7 +312,7 @@ pub(super) fn classification(
|
|
|
283
312
|
.address(false)
|
|
284
313
|
.port(true)
|
|
285
314
|
.port(false);
|
|
286
|
-
expressions.extend(loads.map(&kind.returns()));
|
|
315
|
+
expressions.extend(loads.map(&kind.returns(), &RETURN)?);
|
|
287
316
|
expressions.push(zone_from_data());
|
|
288
317
|
program.end("raw_return", expressions, 1)?;
|
|
289
318
|
}
|
|
@@ -305,8 +334,8 @@ fn flow(shape: Shape, reply: bool) -> Loads {
|
|
|
305
334
|
loads.zone();
|
|
306
335
|
loads
|
|
307
336
|
}
|
|
308
|
-
fn labelled() -> Vec<Attr
|
|
309
|
-
Loads::new().zone().label().lookup(LABEL_SET)
|
|
337
|
+
fn labelled() -> Result<Vec<Attr>> {
|
|
338
|
+
Loads::new().zone().label().lookup(LABEL_SET, &LABEL_KEY)
|
|
310
339
|
}
|
|
311
340
|
/// Admissions of one kind in one filter chain. The original direction leaves
|
|
312
341
|
/// through the handoff: ESTABLISHED or NEW with the generation's label, or a
|
|
@@ -340,36 +369,36 @@ pub(super) fn admissions(
|
|
|
340
369
|
};
|
|
341
370
|
if !original.is_empty() {
|
|
342
371
|
let mut established = envelope(false, 2);
|
|
343
|
-
established.extend(known(true));
|
|
344
|
-
established.extend(flow(shape, false).lookup(&name));
|
|
345
|
-
established.extend(labelled());
|
|
372
|
+
established.extend(known(true)?);
|
|
373
|
+
established.extend(flow(shape, false).lookup(&name, &shape.flow())?);
|
|
374
|
+
established.extend(labelled()?);
|
|
346
375
|
program.end(chain, established, 1)?;
|
|
347
376
|
for transport in &original {
|
|
348
|
-
let opening = || {
|
|
377
|
+
let opening = || -> Result<Vec<Attr>> {
|
|
349
378
|
let mut result = envelope(false, 8);
|
|
350
379
|
result.extend(meta(16, vec![protocol(transport)]));
|
|
351
380
|
if *transport == "tcp" {
|
|
352
381
|
result.extend(opening_tcp());
|
|
353
382
|
}
|
|
354
|
-
result.extend(known(true));
|
|
355
|
-
result.extend(flow(shape, false).lookup(&name));
|
|
356
|
-
result
|
|
383
|
+
result.extend(known(true)?);
|
|
384
|
+
result.extend(flow(shape, false).lookup(&name, &shape.flow())?);
|
|
385
|
+
Ok(result)
|
|
357
386
|
};
|
|
358
|
-
let mut labelled_opening = opening()
|
|
359
|
-
labelled_opening.extend(labelled());
|
|
387
|
+
let mut labelled_opening = opening()?;
|
|
388
|
+
labelled_opening.extend(labelled()?);
|
|
360
389
|
program.end(chain, labelled_opening, 1)?;
|
|
361
|
-
let mut fresh = opening()
|
|
390
|
+
let mut fresh = opening()?;
|
|
362
391
|
fresh.extend(ct(13, None, vec![0; 16]));
|
|
363
|
-
fresh.extend(Loads::new().zone().map(GENERATION_MAP));
|
|
392
|
+
fresh.extend(Loads::new().zone().map(GENERATION_MAP, &GENERATION_KEY)?);
|
|
364
393
|
fresh.push(keys::set_ct_from_data(13));
|
|
365
394
|
program.end(chain, fresh, 1)?;
|
|
366
395
|
}
|
|
367
396
|
}
|
|
368
397
|
if reply {
|
|
369
398
|
let mut answer = envelope(true, 2);
|
|
370
|
-
answer.extend(known(false));
|
|
371
|
-
answer.extend(flow(shape, true).lookup(&name));
|
|
372
|
-
answer.extend(labelled());
|
|
399
|
+
answer.extend(known(false)?);
|
|
400
|
+
answer.extend(flow(shape, true).lookup(&name, &shape.flow())?);
|
|
401
|
+
answer.extend(labelled()?);
|
|
373
402
|
program.end(chain, answer, 1)?;
|
|
374
403
|
}
|
|
375
404
|
}
|
|
@@ -389,9 +418,9 @@ pub(super) fn translation(
|
|
|
389
418
|
let mut expressions = ipv4();
|
|
390
419
|
expressions.extend(link(&scope.handoff, false));
|
|
391
420
|
expressions.extend(ct(1, None, vec![0]));
|
|
392
|
-
expressions.extend(labelled());
|
|
393
|
-
expressions.extend(known(true));
|
|
394
|
-
expressions.extend(flow(shape, false).map(&shape.name("flow")));
|
|
421
|
+
expressions.extend(labelled()?);
|
|
422
|
+
expressions.extend(known(true)?);
|
|
423
|
+
expressions.extend(flow(shape, false).map(&shape.name("flow"), &shape.flow())?);
|
|
395
424
|
expressions.push(super::published::nat(0, 2));
|
|
396
425
|
program.rule("post", expressions)?;
|
|
397
426
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
use super::keys::{
|
|
1
|
+
use super::keys::{
|
|
2
|
+
self, Field, Key, Loads, CT_ORIGINAL_DPORT, CT_REPLY_SADDR, CT_REPLY_SPORT, L4PROTO,
|
|
3
|
+
};
|
|
2
4
|
use super::*;
|
|
3
5
|
|
|
4
6
|
/// Publications translated into a pool: the protocol, the address and port the
|
|
5
7
|
/// flow was translated to, and its originally tracked destination port. Port fields are inclusive intervals, so one element holds
|
|
6
8
|
/// one port or a whole range.
|
|
7
9
|
const PUBLISHED: &str = "pool_published";
|
|
10
|
+
const PUBLISHED_KEY: [Field; 4] = [L4PROTO, CT_REPLY_SADDR, CT_REPLY_SPORT, CT_ORIGINAL_DPORT];
|
|
8
11
|
|
|
9
12
|
pub(super) fn compile(program: &mut Program<'_>, scope: &AllocationPoolGuardScope) -> Result<()> {
|
|
10
13
|
for (name, hook) in [("input", 1), ("forward", 2), ("output", 3)] {
|
|
@@ -67,15 +70,7 @@ fn published_set(program: &mut Program<'_>, scope: &AllocationPoolGuardScope) ->
|
|
|
67
70
|
.element(None),
|
|
68
71
|
);
|
|
69
72
|
}
|
|
70
|
-
keys::interval(
|
|
71
|
-
program,
|
|
72
|
-
PUBLISHED,
|
|
73
|
-
2,
|
|
74
|
-
&[PROTOCOL, ADDRESS, PORT, PORT],
|
|
75
|
-
None,
|
|
76
|
-
elements,
|
|
77
|
-
)
|
|
78
|
-
.map(|_| ())
|
|
73
|
+
keys::interval(program, PUBLISHED, 2, &PUBLISHED_KEY, None, elements).map(|_| ())
|
|
79
74
|
}
|
|
80
75
|
/// The admissions of every publication, whatever their number: behind the
|
|
81
76
|
/// default conntrack zone, an ESTABLISHED packet of either direction, and a NEW
|
|
@@ -90,7 +85,7 @@ fn published(program: &mut Program<'_>, scope: &AllocationPoolGuardScope) -> Res
|
|
|
90
85
|
let lookup = || {
|
|
91
86
|
let mut loads = Loads::new();
|
|
92
87
|
loads.protocol().translated().original_port(false);
|
|
93
|
-
loads.lookup(PUBLISHED)
|
|
88
|
+
loads.lookup(PUBLISHED, &PUBLISHED_KEY)
|
|
94
89
|
};
|
|
95
90
|
let envelope = |connection_state: u32| {
|
|
96
91
|
let mut result = ct(17, None, 0_u16.to_ne_bytes().to_vec());
|
|
@@ -98,7 +93,7 @@ fn published(program: &mut Program<'_>, scope: &AllocationPoolGuardScope) -> Res
|
|
|
98
93
|
result
|
|
99
94
|
};
|
|
100
95
|
let mut established = envelope(2);
|
|
101
|
-
established.extend(lookup());
|
|
96
|
+
established.extend(lookup()?);
|
|
102
97
|
program.end("pool_guard", established, 1)?;
|
|
103
98
|
let transports: std::collections::BTreeSet<&str> = scope
|
|
104
99
|
.published_ports
|
|
@@ -111,7 +106,7 @@ fn published(program: &mut Program<'_>, scope: &AllocationPoolGuardScope) -> Res
|
|
|
111
106
|
if transport == "tcp" {
|
|
112
107
|
opening.extend(opening_tcp());
|
|
113
108
|
}
|
|
114
|
-
opening.extend(lookup());
|
|
109
|
+
opening.extend(lookup()?);
|
|
115
110
|
program.end("pool_guard", opening, 1)?;
|
|
116
111
|
}
|
|
117
112
|
Ok(())
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
//! anti-spoof guard, the directed rules and the terminal denials look the packet
|
|
5
5
|
//! up there and in sets keyed on the link index, so a renamed or reused interface
|
|
6
6
|
//! never matches an element of another link.
|
|
7
|
-
use super::keys::{
|
|
7
|
+
use super::keys::{
|
|
8
|
+
self, Field, Key, Loads, IIF, IIFNAME, IP_DADDR, IP_SADDR, L4PROTO, OIF, TH_DPORT, TH_SPORT,
|
|
9
|
+
};
|
|
8
10
|
use super::*;
|
|
9
11
|
|
|
10
12
|
/// Every endpoint link, index and name, and the absent interface (0, "") of
|
|
@@ -21,6 +23,14 @@ const SOURCE: &str = "private_source";
|
|
|
21
23
|
const ANY: &str = "private_any";
|
|
22
24
|
const PORTED: &str = "private_port";
|
|
23
25
|
|
|
26
|
+
/// The keys, as the incoming direction loads them where both directions do.
|
|
27
|
+
const LINK_KEY: [Field; 2] = [IIF, IIFNAME];
|
|
28
|
+
const INDEX_KEY: [Field; 1] = [IIF];
|
|
29
|
+
const NAME_KEY: [Field; 1] = [IIFNAME];
|
|
30
|
+
const SOURCE_KEY: [Field; 2] = [IIF, IP_SADDR];
|
|
31
|
+
const ANY_KEY: [Field; 4] = [IIF, OIF, IP_SADDR, IP_DADDR];
|
|
32
|
+
const PORTED_KEY: [Field; 7] = [IIF, OIF, IP_SADDR, IP_DADDR, L4PROTO, TH_SPORT, TH_DPORT];
|
|
33
|
+
|
|
24
34
|
fn name(value: &str) -> Vec<u8> {
|
|
25
35
|
let mut bytes = value.as_bytes().to_vec();
|
|
26
36
|
bytes.resize(16, 0);
|
|
@@ -64,10 +74,10 @@ pub(super) fn sets(program: &mut Program<'_>, scope: &RouterScope) -> Result<()>
|
|
|
64
74
|
);
|
|
65
75
|
}
|
|
66
76
|
}
|
|
67
|
-
keys::exact(program, LINK, 32,
|
|
68
|
-
keys::exact(program, INDEX_SET, 33,
|
|
69
|
-
keys::exact(program, NAME_SET, 34,
|
|
70
|
-
keys::interval(program, SOURCE, 35, &
|
|
77
|
+
keys::exact(program, LINK, 32, &LINK_KEY, None, links)?;
|
|
78
|
+
keys::exact(program, INDEX_SET, 33, &INDEX_KEY, None, indices)?;
|
|
79
|
+
keys::exact(program, NAME_SET, 34, &NAME_KEY, None, names)?;
|
|
80
|
+
keys::interval(program, SOURCE, 35, &SOURCE_KEY, None, sources)?;
|
|
71
81
|
let (mut any, mut ported) = (Vec::new(), Vec::new());
|
|
72
82
|
for rule in &scope.rules {
|
|
73
83
|
let key = Key::default()
|
|
@@ -86,22 +96,8 @@ pub(super) fn sets(program: &mut Program<'_>, scope: &RouterScope) -> Result<()>
|
|
|
86
96
|
);
|
|
87
97
|
}
|
|
88
98
|
}
|
|
89
|
-
keys::interval(
|
|
90
|
-
|
|
91
|
-
ANY,
|
|
92
|
-
36,
|
|
93
|
-
&[INDEX, INDEX, ADDRESS, ADDRESS],
|
|
94
|
-
None,
|
|
95
|
-
any,
|
|
96
|
-
)?;
|
|
97
|
-
keys::interval(
|
|
98
|
-
program,
|
|
99
|
-
PORTED,
|
|
100
|
-
37,
|
|
101
|
-
&[INDEX, INDEX, ADDRESS, ADDRESS, PROTOCOL, PORT, PORT],
|
|
102
|
-
None,
|
|
103
|
-
ported,
|
|
104
|
-
)?;
|
|
99
|
+
keys::interval(program, ANY, 36, &ANY_KEY, None, any)?;
|
|
100
|
+
keys::interval(program, PORTED, 37, &PORTED_KEY, None, ported)?;
|
|
105
101
|
Ok(())
|
|
106
102
|
}
|
|
107
103
|
/// The directions a filter chain sees an endpoint link in.
|
|
@@ -114,8 +110,8 @@ fn directions(chain: &str) -> Vec<bool> {
|
|
|
114
110
|
}
|
|
115
111
|
/// The interface of one direction is an endpoint link or absent, by index and
|
|
116
112
|
/// name.
|
|
117
|
-
pub(super) fn known(incoming: bool) -> Vec<Attr
|
|
118
|
-
Loads::new().link(incoming).lookup(LINK)
|
|
113
|
+
pub(super) fn known(incoming: bool) -> Result<Vec<Attr>> {
|
|
114
|
+
Loads::new().link(incoming).lookup(LINK, &LINK_KEY)
|
|
119
115
|
}
|
|
120
116
|
/// Anti-spoof guards: a packet arriving from an endpoint link must carry one of
|
|
121
117
|
/// its source prefixes, and one leaving to it one of its prefixes as destination;
|
|
@@ -126,7 +122,7 @@ pub(super) fn guards(program: &mut Program<'_>, scope: &RouterScope, chain: &str
|
|
|
126
122
|
return Ok(());
|
|
127
123
|
}
|
|
128
124
|
for incoming in directions(chain) {
|
|
129
|
-
let mut foreign = known(incoming)
|
|
125
|
+
let mut foreign = known(incoming)?;
|
|
130
126
|
foreign.push(expr("meta", vec![Attr::u32(1, 1), Attr::u32(2, 15)]));
|
|
131
127
|
foreign.push(expr(
|
|
132
128
|
"cmp",
|
|
@@ -138,12 +134,12 @@ pub(super) fn guards(program: &mut Program<'_>, scope: &RouterScope, chain: &str
|
|
|
138
134
|
));
|
|
139
135
|
program.end(chain, foreign, 0)?;
|
|
140
136
|
let mut spoofed = ipv4();
|
|
141
|
-
spoofed.extend(known(incoming));
|
|
137
|
+
spoofed.extend(known(incoming)?);
|
|
142
138
|
spoofed.extend(
|
|
143
139
|
Loads::new()
|
|
144
140
|
.index(incoming)
|
|
145
141
|
.address(incoming)
|
|
146
|
-
.absent(SOURCE)
|
|
142
|
+
.absent(SOURCE, &SOURCE_KEY)?,
|
|
147
143
|
);
|
|
148
144
|
program.end(chain, spoofed, 0)?;
|
|
149
145
|
}
|
|
@@ -154,7 +150,7 @@ pub(super) fn guards(program: &mut Program<'_>, scope: &RouterScope, chain: &str
|
|
|
154
150
|
/// protocol and ports. Input sees no outgoing and output no incoming interface,
|
|
155
151
|
/// so each chain matches exactly the rules that were compiled into it.
|
|
156
152
|
pub(super) fn grants(program: &mut Program<'_>, scope: &RouterScope, chain: &str) -> Result<()> {
|
|
157
|
-
for (set, ported) in [(ANY, false), (PORTED, true)] {
|
|
153
|
+
for (set, key, ported) in [(ANY, &ANY_KEY[..], false), (PORTED, &PORTED_KEY[..], true)] {
|
|
158
154
|
if !scope
|
|
159
155
|
.rules
|
|
160
156
|
.iter()
|
|
@@ -163,14 +159,14 @@ pub(super) fn grants(program: &mut Program<'_>, scope: &RouterScope, chain: &str
|
|
|
163
159
|
continue;
|
|
164
160
|
}
|
|
165
161
|
let mut expressions = ipv4();
|
|
166
|
-
expressions.extend(known(true));
|
|
167
|
-
expressions.extend(known(false));
|
|
162
|
+
expressions.extend(known(true)?);
|
|
163
|
+
expressions.extend(known(false)?);
|
|
168
164
|
let mut loads = Loads::new();
|
|
169
165
|
loads.index(true).index(false).address(true).address(false);
|
|
170
166
|
if ported {
|
|
171
167
|
loads.protocol().port(true).port(false);
|
|
172
168
|
}
|
|
173
|
-
expressions.extend(loads.lookup(set));
|
|
169
|
+
expressions.extend(loads.lookup(set, key)?);
|
|
174
170
|
program.end(chain, expressions, 1)?;
|
|
175
171
|
}
|
|
176
172
|
Ok(())
|
|
@@ -181,15 +177,14 @@ pub(super) fn denials(program: &mut Program<'_>, scope: &RouterScope, chain: &st
|
|
|
181
177
|
return Ok(());
|
|
182
178
|
}
|
|
183
179
|
for incoming in directions(chain) {
|
|
184
|
-
program.end(chain, Loads::new().index(incoming).lookup(INDEX_SET), 0)?;
|
|
185
180
|
program.end(
|
|
186
181
|
chain,
|
|
187
|
-
Loads::new()
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
182
|
+
Loads::new().index(incoming).lookup(INDEX_SET, &INDEX_KEY)?,
|
|
183
|
+
0,
|
|
184
|
+
)?;
|
|
185
|
+
program.end(
|
|
186
|
+
chain,
|
|
187
|
+
Loads::new().name(incoming).lookup(NAME_SET, &NAME_KEY)?,
|
|
193
188
|
0,
|
|
194
189
|
)?;
|
|
195
190
|
}
|
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
//! protocols, the live address and port, and the originally tracked address and
|
|
7
7
|
//! port. A port field is an inclusive interval, so one element holds one port or
|
|
8
8
|
//! a whole range, and every other field is exact.
|
|
9
|
-
use super::hostgrant::
|
|
10
|
-
use super::keys::{
|
|
9
|
+
use super::hostgrant::register;
|
|
10
|
+
use super::keys::{
|
|
11
|
+
self, word, Field, Key, Loads, CT_ORIGINAL_DADDR, CT_ORIGINAL_DPORT, CT_ORIGINAL_SADDR,
|
|
12
|
+
CT_ORIGINAL_SPORT, CT_PROTOCOL, IIF, IIFNAME, IP_DADDR, IP_SADDR, L4PROTO, OIF, OIFNAME,
|
|
13
|
+
TH_DPORT, TH_SPORT,
|
|
14
|
+
};
|
|
11
15
|
use super::*;
|
|
12
16
|
|
|
13
17
|
/// Router handoff arrivals of a publication, classified before conntrack.
|
|
@@ -24,7 +28,39 @@ pub(super) const FORWARD: &str = "published_forward";
|
|
|
24
28
|
/// the data is the source NAT to the outside address and port span.
|
|
25
29
|
pub(super) const SYMMETRIC: &str = "published_symmetric";
|
|
26
30
|
|
|
27
|
-
const
|
|
31
|
+
const ARRIVAL_KEY: [Field; 3] = [L4PROTO, IP_DADDR, TH_DPORT];
|
|
32
|
+
const ENDPOINT_KEY: [Field; 5] = [IIF, IIFNAME, L4PROTO, IP_SADDR, TH_SPORT];
|
|
33
|
+
/// The translation maps' key, and their data: the inside address and port, or
|
|
34
|
+
/// the inside address alone.
|
|
35
|
+
const TRANSLATION_KEY: [Field; 4] = [L4PROTO, CT_PROTOCOL, IP_DADDR, TH_DPORT];
|
|
36
|
+
const PORT_DATA: [Field; 2] = [IP_DADDR, TH_DPORT];
|
|
37
|
+
const ADDRESS_DATA: [Field; 1] = [IP_DADDR];
|
|
38
|
+
/// `[link, protocols, address, port, original address, original port]`, the key
|
|
39
|
+
/// of both admission sets, as their original direction loads it: inbound
|
|
40
|
+
/// toward the inside link and destination, symmetric from them.
|
|
41
|
+
const INBOUND_KEY: [Field; 8] = [
|
|
42
|
+
OIF,
|
|
43
|
+
OIFNAME,
|
|
44
|
+
L4PROTO,
|
|
45
|
+
CT_PROTOCOL,
|
|
46
|
+
IP_DADDR,
|
|
47
|
+
TH_DPORT,
|
|
48
|
+
CT_ORIGINAL_DADDR,
|
|
49
|
+
CT_ORIGINAL_DPORT,
|
|
50
|
+
];
|
|
51
|
+
const SYMMETRIC_KEY: [Field; 8] = [
|
|
52
|
+
IIF,
|
|
53
|
+
IIFNAME,
|
|
54
|
+
L4PROTO,
|
|
55
|
+
CT_PROTOCOL,
|
|
56
|
+
IP_SADDR,
|
|
57
|
+
TH_SPORT,
|
|
58
|
+
CT_ORIGINAL_SADDR,
|
|
59
|
+
CT_ORIGINAL_SPORT,
|
|
60
|
+
];
|
|
61
|
+
/// The source NAT a symmetric flow stores: the outside address and the first
|
|
62
|
+
/// and last port of its span.
|
|
63
|
+
const SYMMETRIC_DATA: [Field; 3] = [IP_SADDR, TH_SPORT, TH_SPORT];
|
|
28
64
|
|
|
29
65
|
/// One publication on one hop. The outside is what clients reach (the uplink
|
|
30
66
|
/// address and port on the host, the transit address and port in the router);
|
|
@@ -44,13 +80,6 @@ pub(super) struct Hop<'a> {
|
|
|
44
80
|
pub(super) fixed: &'a LocalLink,
|
|
45
81
|
}
|
|
46
82
|
|
|
47
|
-
/// `[link, protocols, address, port, original address, original port]`, the key
|
|
48
|
-
/// of both admission sets.
|
|
49
|
-
fn flow_fields() -> Vec<u32> {
|
|
50
|
-
let mut fields = LINK.to_vec();
|
|
51
|
-
fields.extend([PROTOCOL, PROTOCOL, ADDRESS, PORT, ADDRESS, PORT]);
|
|
52
|
-
fields
|
|
53
|
-
}
|
|
54
83
|
fn inbound_key(publication: &Publication<'_>) -> Result<IntervalElement> {
|
|
55
84
|
let (outside, outside_first, outside_last) = publication.outside;
|
|
56
85
|
let (inside, inside_first, inside_last) = publication.inside;
|
|
@@ -108,9 +137,6 @@ fn translation_loads() -> Loads {
|
|
|
108
137
|
loads.protocols().address(false).port(false);
|
|
109
138
|
loads
|
|
110
139
|
}
|
|
111
|
-
fn translation_fields() -> [u32; 4] {
|
|
112
|
-
[PROTOCOL, PROTOCOL, ADDRESS, PORT]
|
|
113
|
-
}
|
|
114
140
|
fn ranged(publication: &Publication<'_>) -> bool {
|
|
115
141
|
publication.outside.1 != publication.outside.2
|
|
116
142
|
}
|
|
@@ -133,14 +159,7 @@ pub(super) fn sets(program: &mut Program<'_>, hop: &Hop<'_>, router: bool) -> Re
|
|
|
133
159
|
.element(None),
|
|
134
160
|
);
|
|
135
161
|
}
|
|
136
|
-
declare(
|
|
137
|
-
program,
|
|
138
|
-
ARRIVAL,
|
|
139
|
-
16,
|
|
140
|
-
&[PROTOCOL, ADDRESS, PORT],
|
|
141
|
-
None,
|
|
142
|
-
arrivals,
|
|
143
|
-
)?;
|
|
162
|
+
declare(program, ARRIVAL, 16, &ARRIVAL_KEY, None, arrivals)?;
|
|
144
163
|
// Several publications may share inside ports that are not symmetric;
|
|
145
164
|
// the classification is their union, as disjoint intervals.
|
|
146
165
|
let mut endpoints = Vec::new();
|
|
@@ -155,9 +174,7 @@ pub(super) fn sets(program: &mut Program<'_>, hop: &Hop<'_>, router: bool) -> Re
|
|
|
155
174
|
.element(None),
|
|
156
175
|
);
|
|
157
176
|
}
|
|
158
|
-
|
|
159
|
-
fields.extend([PROTOCOL, ADDRESS, PORT]);
|
|
160
|
-
declare(program, ENDPOINT, 17, &fields, None, endpoints)?;
|
|
177
|
+
declare(program, ENDPOINT, 17, &ENDPOINT_KEY, None, endpoints)?;
|
|
161
178
|
}
|
|
162
179
|
let (mut ports, mut addresses) = (Vec::new(), Vec::new());
|
|
163
180
|
for publication in &hop.publications {
|
|
@@ -175,13 +192,20 @@ pub(super) fn sets(program: &mut Program<'_>, hop: &Hop<'_>, router: bool) -> Re
|
|
|
175
192
|
ports.push(key.element(Some(data)));
|
|
176
193
|
}
|
|
177
194
|
}
|
|
178
|
-
declare(
|
|
195
|
+
declare(
|
|
196
|
+
program,
|
|
197
|
+
PORT_MAP,
|
|
198
|
+
18,
|
|
199
|
+
&TRANSLATION_KEY,
|
|
200
|
+
Some(&PORT_DATA),
|
|
201
|
+
ports,
|
|
202
|
+
)?;
|
|
179
203
|
declare(
|
|
180
204
|
program,
|
|
181
205
|
ADDRESS_MAP,
|
|
182
206
|
19,
|
|
183
|
-
&
|
|
184
|
-
Some(
|
|
207
|
+
&TRANSLATION_KEY,
|
|
208
|
+
Some(&ADDRESS_DATA),
|
|
185
209
|
addresses,
|
|
186
210
|
)?;
|
|
187
211
|
let inbound = hop
|
|
@@ -189,21 +213,28 @@ pub(super) fn sets(program: &mut Program<'_>, hop: &Hop<'_>, router: bool) -> Re
|
|
|
189
213
|
.iter()
|
|
190
214
|
.map(inbound_key)
|
|
191
215
|
.collect::<Result<Vec<_>>>()?;
|
|
192
|
-
declare(program, FORWARD, 20, &
|
|
216
|
+
declare(program, FORWARD, 20, &INBOUND_KEY, None, inbound)?;
|
|
193
217
|
let symmetric = hop
|
|
194
218
|
.publications
|
|
195
219
|
.iter()
|
|
196
220
|
.filter(|publication| publication.symmetric)
|
|
197
221
|
.map(symmetric_key)
|
|
198
222
|
.collect::<Result<Vec<_>>>()?;
|
|
199
|
-
declare(
|
|
223
|
+
declare(
|
|
224
|
+
program,
|
|
225
|
+
SYMMETRIC,
|
|
226
|
+
21,
|
|
227
|
+
&SYMMETRIC_KEY,
|
|
228
|
+
Some(&SYMMETRIC_DATA),
|
|
229
|
+
symmetric,
|
|
230
|
+
)
|
|
200
231
|
}
|
|
201
232
|
fn declare(
|
|
202
233
|
program: &mut Program<'_>,
|
|
203
234
|
name: &str,
|
|
204
235
|
id: u32,
|
|
205
|
-
fields: &[
|
|
206
|
-
data: Option
|
|
236
|
+
fields: &[Field],
|
|
237
|
+
data: Option<&[Field]>,
|
|
207
238
|
elements: Vec<IntervalElement>,
|
|
208
239
|
) -> Result<()> {
|
|
209
240
|
keys::interval(program, name, id, fields, data, elements).map(|_| ())
|
|
@@ -217,6 +248,7 @@ fn admissions(
|
|
|
217
248
|
program: &mut Program<'_>,
|
|
218
249
|
hop: &Hop<'_>,
|
|
219
250
|
set: &str,
|
|
251
|
+
key: &[Field],
|
|
220
252
|
protocols: &BTreeSet<&str>,
|
|
221
253
|
fixed_incoming: bool,
|
|
222
254
|
loads: fn(bool) -> Loads,
|
|
@@ -233,7 +265,7 @@ fn admissions(
|
|
|
233
265
|
result
|
|
234
266
|
};
|
|
235
267
|
let mut established = envelope(false, 2);
|
|
236
|
-
established.extend(loads(false).lookup(set));
|
|
268
|
+
established.extend(loads(false).lookup(set, key)?);
|
|
237
269
|
program.end("forward", established, 1)?;
|
|
238
270
|
for transport in protocols {
|
|
239
271
|
let mut opening = envelope(false, 8);
|
|
@@ -241,11 +273,11 @@ fn admissions(
|
|
|
241
273
|
if *transport == "tcp" {
|
|
242
274
|
opening.extend(opening_tcp());
|
|
243
275
|
}
|
|
244
|
-
opening.extend(loads(false).lookup(set));
|
|
276
|
+
opening.extend(loads(false).lookup(set, key)?);
|
|
245
277
|
program.end("forward", opening, 1)?;
|
|
246
278
|
}
|
|
247
279
|
let mut reply = envelope(true, 2);
|
|
248
|
-
reply.extend(loads(true).lookup(set));
|
|
280
|
+
reply.extend(loads(true).lookup(set, key)?);
|
|
249
281
|
program.end("forward", reply, 1)
|
|
250
282
|
}
|
|
251
283
|
fn protocols<'a>(hop: &Hop<'a>, symmetric: bool) -> BTreeSet<&'a str> {
|
|
@@ -262,6 +294,7 @@ pub(super) fn inbound(program: &mut Program<'_>, hop: &Hop<'_>) -> Result<()> {
|
|
|
262
294
|
program,
|
|
263
295
|
hop,
|
|
264
296
|
FORWARD,
|
|
297
|
+
&INBOUND_KEY,
|
|
265
298
|
&protocols(hop, false),
|
|
266
299
|
true,
|
|
267
300
|
inbound_loads,
|
|
@@ -275,6 +308,7 @@ pub(super) fn symmetric(program: &mut Program<'_>, hop: &Hop<'_>) -> Result<()>
|
|
|
275
308
|
program,
|
|
276
309
|
hop,
|
|
277
310
|
SYMMETRIC,
|
|
311
|
+
&SYMMETRIC_KEY,
|
|
278
312
|
&protocols(hop, true),
|
|
279
313
|
false,
|
|
280
314
|
symmetric_loads,
|
|
@@ -317,7 +351,7 @@ pub(super) fn translations(program: &mut Program<'_>, hop: &Hop<'_>) -> Result<(
|
|
|
317
351
|
] {
|
|
318
352
|
if present {
|
|
319
353
|
let mut expressions = tracked(hop.fixed, true);
|
|
320
|
-
expressions.extend(translation_loads().map(set));
|
|
354
|
+
expressions.extend(translation_loads().map(set, &TRANSLATION_KEY)?);
|
|
321
355
|
expressions.push(nat(1, ports));
|
|
322
356
|
program.rule("pre", expressions)?;
|
|
323
357
|
}
|
|
@@ -329,7 +363,7 @@ pub(super) fn translations(program: &mut Program<'_>, hop: &Hop<'_>) -> Result<(
|
|
|
329
363
|
pub(super) fn symmetric_translation(program: &mut Program<'_>, hop: &Hop<'_>) -> Result<()> {
|
|
330
364
|
if hop.publications.iter().any(|item| item.symmetric) {
|
|
331
365
|
let mut expressions = tracked(hop.fixed, false);
|
|
332
|
-
expressions.extend(symmetric_loads(false).map(SYMMETRIC));
|
|
366
|
+
expressions.extend(symmetric_loads(false).map(SYMMETRIC, &SYMMETRIC_KEY)?);
|
|
333
367
|
expressions.push(nat(0, 2));
|
|
334
368
|
program.rule("post", expressions)?;
|
|
335
369
|
}
|
|
@@ -343,11 +377,8 @@ pub(super) fn arrival(program: &mut Program<'_>, hop: &Hop<'_>) -> Result<()> {
|
|
|
343
377
|
let mut expressions = ipv4();
|
|
344
378
|
expressions.extend(link(hop.fixed, true));
|
|
345
379
|
let mut loads = Loads::new();
|
|
346
|
-
loads
|
|
347
|
-
|
|
348
|
-
.address(false)
|
|
349
|
-
.port(false);
|
|
350
|
-
expressions.extend(loads.lookup(ARRIVAL));
|
|
380
|
+
loads.protocol().address(false).port(false);
|
|
381
|
+
expressions.extend(loads.lookup(ARRIVAL, &ARRIVAL_KEY)?);
|
|
351
382
|
program.end("raw_return", expressions, 1)?;
|
|
352
383
|
}
|
|
353
384
|
Ok(())
|
|
@@ -358,12 +389,8 @@ pub(super) fn endpoint(program: &mut Program<'_>, hop: &Hop<'_>) -> Result<()> {
|
|
|
358
389
|
if !hop.publications.is_empty() {
|
|
359
390
|
let mut expressions = ipv4();
|
|
360
391
|
let mut loads = Loads::new();
|
|
361
|
-
loads
|
|
362
|
-
|
|
363
|
-
.push(|index| meta_to(16, index), PROTOCOL)
|
|
364
|
-
.address(true)
|
|
365
|
-
.port(true);
|
|
366
|
-
expressions.extend(loads.lookup(ENDPOINT));
|
|
392
|
+
loads.link(true).protocol().address(true).port(true);
|
|
393
|
+
expressions.extend(loads.lookup(ENDPOINT, &ENDPOINT_KEY)?);
|
|
367
394
|
program.end("raw_in", expressions, 1)?;
|
|
368
395
|
}
|
|
369
396
|
Ok(())
|