@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.
- package/changelog.md +17 -0
- package/dist_rust/smartnftables_linux_amd64_musl +0 -0
- package/dist_rust/smartnftables_linux_amd64_musl.tsrust-build.json +5 -5
- package/dist_rust/smartnftables_linux_arm64_musl +0 -0
- package/dist_rust/smartnftables_linux_arm64_musl.tsrust-build.json +5 -5
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/managed.egress.types.d.ts +25 -4
- package/package.json +4 -4
- package/readme.md +89 -2
- package/rust/src/egress.compile.rs +105 -38
- package/rust/src/egress.hostgrant.rs +74 -34
- package/rust/src/egress.keys.rs +383 -52
- package/rust/src/egress.leased.rs +71 -42
- package/rust/src/egress.poolguard.rs +72 -0
- 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 +65 -1
- package/rust/src/egress.workloadgrant.rs +30 -28
- package/rust/src/egress_hostgrant_tests.rs +12 -0
- package/rust/src/egress_keys_tests.rs +150 -0
- package/rust/src/egress_poolguardpublished_tests.rs +418 -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
- package/ts/managed.egress.types.ts +26 -4
|
@@ -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,5 +1,14 @@
|
|
|
1
|
+
use super::keys::{
|
|
2
|
+
self, Field, Key, Loads, CT_ORIGINAL_DPORT, CT_REPLY_SADDR, CT_REPLY_SPORT, L4PROTO,
|
|
3
|
+
};
|
|
1
4
|
use super::*;
|
|
2
5
|
|
|
6
|
+
/// Publications translated into a pool: the protocol, the address and port the
|
|
7
|
+
/// flow was translated to, and its originally tracked destination port. Port fields are inclusive intervals, so one element holds
|
|
8
|
+
/// one port or a whole range.
|
|
9
|
+
const PUBLISHED: &str = "pool_published";
|
|
10
|
+
const PUBLISHED_KEY: [Field; 4] = [L4PROTO, CT_REPLY_SADDR, CT_REPLY_SPORT, CT_ORIGINAL_DPORT];
|
|
11
|
+
|
|
3
12
|
pub(super) fn compile(program: &mut Program<'_>, scope: &AllocationPoolGuardScope) -> Result<()> {
|
|
4
13
|
for (name, hook) in [("input", 1), ("forward", 2), ("output", 3)] {
|
|
5
14
|
program.chain(name, Some((hook, 0, "filter")))?;
|
|
@@ -18,6 +27,9 @@ pub(super) fn compile(program: &mut Program<'_>, scope: &AllocationPoolGuardScop
|
|
|
18
27
|
hostgrant::tuple_set(program, &scope.host_grants, |_| Ok(None))?;
|
|
19
28
|
hostgrant::admissions(program, ["output", "input"], false, |_| vec![])?;
|
|
20
29
|
}
|
|
30
|
+
if !scope.published_ports.is_empty() {
|
|
31
|
+
published_set(program, scope)?;
|
|
32
|
+
}
|
|
21
33
|
for name in ["input", "forward", "output"] {
|
|
22
34
|
program.jump(name, ipv4(), "pool_guard")?;
|
|
23
35
|
}
|
|
@@ -25,6 +37,11 @@ pub(super) fn compile(program: &mut Program<'_>, scope: &AllocationPoolGuardScop
|
|
|
25
37
|
for prefix in &scope.prefixes {
|
|
26
38
|
program.end("pool_guard", original_address(prefix, false)?, 0)?;
|
|
27
39
|
}
|
|
40
|
+
// Publications follow that denial, so only a flow translated from outside
|
|
41
|
+
// every pool can match one, and precede every current-address denial.
|
|
42
|
+
if !scope.published_ports.is_empty() {
|
|
43
|
+
published(program, scope)?;
|
|
44
|
+
}
|
|
28
45
|
// GOTO, not JUMP: RETURN from pool_reply must return to the base chain,
|
|
29
46
|
// skipping current-destination denial for legitimate reverse-SNAT replies.
|
|
30
47
|
let mut reply = ct(1, None, vec![1]);
|
|
@@ -40,6 +57,61 @@ pub(super) fn compile(program: &mut Program<'_>, scope: &AllocationPoolGuardScop
|
|
|
40
57
|
program.end("pool_reply", vec![], -5)
|
|
41
58
|
}
|
|
42
59
|
|
|
60
|
+
/// The publications of the scope as one interval set.
|
|
61
|
+
fn published_set(program: &mut Program<'_>, scope: &AllocationPoolGuardScope) -> Result<()> {
|
|
62
|
+
let mut elements = Vec::new();
|
|
63
|
+
for port in &scope.published_ports {
|
|
64
|
+
elements.push(
|
|
65
|
+
Key::default()
|
|
66
|
+
.protocol(&port.protocol)
|
|
67
|
+
.address(&port.target_address)?
|
|
68
|
+
.span(port.target_port, port.target_last())
|
|
69
|
+
.span(port.host_port, port.host_last())
|
|
70
|
+
.element(None),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
keys::interval(program, PUBLISHED, 2, &PUBLISHED_KEY, None, elements).map(|_| ())
|
|
74
|
+
}
|
|
75
|
+
/// The admissions of every publication, whatever their number: behind the
|
|
76
|
+
/// default conntrack zone, an ESTABLISHED packet of either direction, and a NEW
|
|
77
|
+
/// opening per protocol (TCP only with SYN and FIN/RST/ACK clear). Each looks its
|
|
78
|
+
/// flow up once by the reply tuple's source, which is the address and port the
|
|
79
|
+
/// flow was translated to in both directions, and the originally tracked
|
|
80
|
+
/// destination port. They run in the guard chain after the original-destination
|
|
81
|
+
/// denial, so a flow whose original destination lies in a pool never reaches
|
|
82
|
+
/// them. A publication is the exception of every hook it crosses: on a host that
|
|
83
|
+
/// forwards it, that is FORWARD alone.
|
|
84
|
+
fn published(program: &mut Program<'_>, scope: &AllocationPoolGuardScope) -> Result<()> {
|
|
85
|
+
let lookup = || {
|
|
86
|
+
let mut loads = Loads::new();
|
|
87
|
+
loads.protocol().translated().original_port(false);
|
|
88
|
+
loads.lookup(PUBLISHED, &PUBLISHED_KEY)
|
|
89
|
+
};
|
|
90
|
+
let envelope = |connection_state: u32| {
|
|
91
|
+
let mut result = ct(17, None, 0_u16.to_ne_bytes().to_vec());
|
|
92
|
+
result.extend(state(connection_state));
|
|
93
|
+
result
|
|
94
|
+
};
|
|
95
|
+
let mut established = envelope(2);
|
|
96
|
+
established.extend(lookup()?);
|
|
97
|
+
program.end("pool_guard", established, 1)?;
|
|
98
|
+
let transports: std::collections::BTreeSet<&str> = scope
|
|
99
|
+
.published_ports
|
|
100
|
+
.iter()
|
|
101
|
+
.map(|port| port.protocol.as_str())
|
|
102
|
+
.collect();
|
|
103
|
+
for transport in transports {
|
|
104
|
+
let mut opening = envelope(8);
|
|
105
|
+
opening.extend(meta(16, vec![protocol(transport)]));
|
|
106
|
+
if transport == "tcp" {
|
|
107
|
+
opening.extend(opening_tcp());
|
|
108
|
+
}
|
|
109
|
+
opening.extend(lookup()?);
|
|
110
|
+
program.end("pool_guard", opening, 1)?;
|
|
111
|
+
}
|
|
112
|
+
Ok(())
|
|
113
|
+
}
|
|
114
|
+
|
|
43
115
|
/// The exact loopback TCP destination: IPv4, TCP, address and port.
|
|
44
116
|
fn local_tcp_port(owner: &LocalTcpPortOwner) -> Result<Vec<Attr>> {
|
|
45
117
|
let mut result = ipv4();
|
|
@@ -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
|
}
|