@push.rocks/smartnftables 2.5.2 → 3.0.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 +31 -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 +69 -3
- package/package.json +6 -6
- package/readme.md +342 -61
- package/rust/src/egress.compile.rs +157 -76
- package/rust/src/egress.host.rs +104 -44
- package/rust/src/egress.hostgrant.rs +14 -14
- package/rust/src/egress.keys.rs +305 -0
- package/rust/src/egress.leased.rs +399 -0
- package/rust/src/egress.poolguard.rs +45 -0
- package/rust/src/egress.private.rs +197 -0
- package/rust/src/egress.published.rs +370 -0
- package/rust/src/egress.router.rs +64 -295
- package/rust/src/egress.rs +248 -17
- package/rust/src/egress.workloadgrant.rs +88 -0
- package/rust/src/egress_hostgrant_tests.rs +196 -47
- package/rust/src/egress_localplatform_tests.rs +204 -0
- package/rust/src/egress_localport_tests.rs +266 -0
- package/rust/src/egress_publishedrange_tests.rs +812 -0
- package/rust/src/egress_routerequivalence_tests.rs +448 -0
- package/rust/src/egress_tests.rs +132 -230
- package/rust/src/egress_workloadgrant_tests.rs +313 -0
- package/rust/src/owner.rs +77 -15
- package/rust/src/owner_host_traffic_tests.rs +4 -0
- package/rust/src/owner_hostgrant_traffic_tests.rs +9 -4
- package/rust/src/owner_identity_tests.rs +228 -80
- package/rust/src/owner_localplatform_tests.rs +274 -0
- package/rust/src/owner_localport_tests.rs +241 -0
- package/rust/src/owner_publishedrange_traffic_tests.rs +306 -0
- package/rust/src/owner_router_traffic_tests.rs +2 -0
- package/rust/src/owner_scale_traffic_tests.rs +383 -0
- package/rust/src/owner_tests.rs +15 -0
- package/rust/src/owner_workloadgrant_tests.rs +278 -0
- package/rust/src/policy.rs +29 -25
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/managed.egress.types.ts +71 -3
|
@@ -1,56 +1,10 @@
|
|
|
1
|
+
use super::leased::Kind;
|
|
1
2
|
use super::*;
|
|
2
3
|
|
|
3
|
-
fn endpoint<'a>(scope: &'a RouterScope, grant: &Grant) -> Option<&'a LocalLink> {
|
|
4
|
-
grant.source_endpoint.as_ref().and_then(|id| {
|
|
5
|
-
let endpoint = scope.endpoints.iter().find(|item| &item.id == id)?;
|
|
6
|
-
scope
|
|
7
|
-
.links
|
|
8
|
-
.iter()
|
|
9
|
-
.find(|item| item.interface_index == endpoint.interface_index)
|
|
10
|
-
})
|
|
11
|
-
}
|
|
12
|
-
fn raw_original(scope: &RouterScope, grant: &Grant) -> Result<Vec<Attr>> {
|
|
13
|
-
let mut result = tuple(grant, &scope.protection, false, false)?;
|
|
14
|
-
result.extend(match endpoint(scope, grant) {
|
|
15
|
-
Some(endpoint) => link(endpoint, true),
|
|
16
|
-
None => link(&scope.handoff, false),
|
|
17
|
-
});
|
|
18
|
-
Ok(result)
|
|
19
|
-
}
|
|
20
|
-
fn filter(scope: &RouterScope, grant: &Grant, reply: bool) -> Result<Vec<Attr>> {
|
|
21
|
-
let mut result = tuple(grant, &scope.protection, reply, true)?;
|
|
22
|
-
result.extend(link(&scope.handoff, reply));
|
|
23
|
-
if let Some(endpoint) = endpoint(scope, grant) {
|
|
24
|
-
result.extend(link(endpoint, !reply));
|
|
25
|
-
}
|
|
26
|
-
Ok(result)
|
|
27
|
-
}
|
|
28
|
-
fn raw_return(scope: &RouterScope, grant: &Grant, generation: &Generation) -> Result<Vec<Attr>> {
|
|
29
|
-
let mut result = ipv4();
|
|
30
|
-
result.extend(link(&scope.handoff, true));
|
|
31
|
-
result.extend(meta(16, vec![protocol(&grant.protocol)]));
|
|
32
|
-
result.extend(current_address(
|
|
33
|
-
&super::super::destination(grant, &scope.protection)?,
|
|
34
|
-
true,
|
|
35
|
-
)?);
|
|
36
|
-
result.extend(current_address(
|
|
37
|
-
&format!("{}/32", generation.transit_source_address),
|
|
38
|
-
false,
|
|
39
|
-
)?);
|
|
40
|
-
if let Some(port) = grant.destination_port {
|
|
41
|
-
result.extend(current_port(port, true));
|
|
42
|
-
}
|
|
43
|
-
result.extend(current_range(
|
|
44
|
-
grant.source_port_range.first,
|
|
45
|
-
grant.source_port_range.last,
|
|
46
|
-
false,
|
|
47
|
-
));
|
|
48
|
-
Ok(result)
|
|
49
|
-
}
|
|
50
4
|
/// The exact veth link of the workload endpoint that holds an endpoint address.
|
|
51
5
|
/// Validation admits only a current endpoint address, and endpoint prefixes are
|
|
52
6
|
/// pairwise disjoint, so one publication or host grant never spans two links.
|
|
53
|
-
fn endpoint_link<'a>(scope: &'a RouterScope, address: &str) -> Result<&'a LocalLink> {
|
|
7
|
+
pub(super) fn endpoint_link<'a>(scope: &'a RouterScope, address: &str) -> Result<&'a LocalLink> {
|
|
54
8
|
let target = format!("{address}/32");
|
|
55
9
|
let endpoint = scope
|
|
56
10
|
.endpoints
|
|
@@ -68,70 +22,30 @@ fn endpoint_link<'a>(scope: &'a RouterScope, address: &str) -> Result<&'a LocalL
|
|
|
68
22
|
.find(|link| link.interface_index == endpoint.interface_index)
|
|
69
23
|
.ok_or(crate::Error::Invalid)
|
|
70
24
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
/// Inbound publication envelope. Both directions check the exact links, the
|
|
75
|
-
/// translated current tuple and the original conntrack destination, so foreign
|
|
76
|
-
/// NAT cannot borrow this admission for another flow.
|
|
77
|
-
fn published_envelope(
|
|
78
|
-
scope: &RouterScope,
|
|
79
|
-
endpoint: &LocalLink,
|
|
80
|
-
port: &RouterPublishedPort,
|
|
81
|
-
reply: bool,
|
|
82
|
-
) -> Result<Vec<Attr>> {
|
|
83
|
-
let mut expressions = ipv4();
|
|
84
|
-
expressions.extend(link(&scope.handoff, !reply));
|
|
85
|
-
expressions.extend(link(endpoint, reply));
|
|
86
|
-
expressions.extend(meta(16, vec![protocol(&port.protocol)]));
|
|
87
|
-
expressions.extend(ct(10, None, vec![protocol(&port.protocol)]));
|
|
88
|
-
expressions.extend(ct(17, None, 0_u16.to_ne_bytes().to_vec()));
|
|
89
|
-
expressions.extend(ct(1, None, vec![u8::from(reply)]));
|
|
90
|
-
let target = format!("{}/32", port.endpoint_address);
|
|
91
|
-
expressions.extend(current_address(&target, reply)?);
|
|
92
|
-
expressions.extend(current_port(port.endpoint_port, reply));
|
|
93
|
-
let published = format!("{}/32", port.transit_source_address);
|
|
94
|
-
expressions.extend(original_address(&published, false)?);
|
|
95
|
-
expressions.extend(original_port(port.transit_port, false));
|
|
96
|
-
Ok(expressions)
|
|
97
|
-
}
|
|
98
|
-
/// Handoff ingress classification for an exact current publication. Raw runs
|
|
99
|
-
/// before conntrack, so it matches the arriving tuple only and never sets a
|
|
100
|
-
/// generation zone: a publication is an ordinary default-zone flow.
|
|
101
|
-
fn published_return(program: &mut Program<'_>, scope: &RouterScope) -> Result<()> {
|
|
102
|
-
for port in &scope.published_ports {
|
|
103
|
-
let mut expressions = ipv4();
|
|
104
|
-
expressions.extend(link(&scope.handoff, true));
|
|
105
|
-
expressions.extend(meta(16, vec![protocol(&port.protocol)]));
|
|
106
|
-
expressions.extend(current_address(
|
|
107
|
-
&format!("{}/32", port.transit_source_address),
|
|
108
|
-
false,
|
|
109
|
-
)?);
|
|
110
|
-
expressions.extend(current_port(port.transit_port, false));
|
|
111
|
-
program.end("raw_return", expressions, 1)?;
|
|
112
|
-
}
|
|
113
|
-
Ok(())
|
|
114
|
-
}
|
|
115
|
-
/// Endpoint ingress classification for an exact current publication. The workload
|
|
116
|
-
/// side of a publication is an ordinary default-zone flow too, so it is matched on
|
|
117
|
-
/// its exact link, address and dedicated published port before the leased
|
|
118
|
-
/// classifiers below can zone it: a client whose source port equals a leased
|
|
119
|
-
/// grant's destination port would otherwise move the workload's published packets
|
|
120
|
-
/// into that generation, where they are not its flow. This only classifies; both
|
|
121
|
-
/// the anti-spoof guards and the publication's admissions still decide admission.
|
|
122
|
-
fn published_endpoint(program: &mut Program<'_>, scope: &RouterScope) -> Result<()> {
|
|
25
|
+
/// The publications of this hop, each behind the veth link of its workload.
|
|
26
|
+
fn hop(scope: &RouterScope) -> Result<published::Hop<'_>> {
|
|
27
|
+
let mut publications = Vec::new();
|
|
123
28
|
for port in &scope.published_ports {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
29
|
+
publications.push(published::Publication {
|
|
30
|
+
protocol: &port.protocol,
|
|
31
|
+
outside: (
|
|
32
|
+
&port.transit_source_address,
|
|
33
|
+
port.transit_port,
|
|
34
|
+
port.transit_last(),
|
|
35
|
+
),
|
|
36
|
+
inside: (
|
|
37
|
+
&port.endpoint_address,
|
|
38
|
+
port.endpoint_port,
|
|
39
|
+
port.endpoint_last(),
|
|
40
|
+
),
|
|
41
|
+
link: endpoint_link(scope, &port.endpoint_address)?,
|
|
42
|
+
symmetric: port.symmetric,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
Ok(published::Hop {
|
|
46
|
+
publications,
|
|
47
|
+
fixed: &scope.handoff,
|
|
48
|
+
})
|
|
135
49
|
}
|
|
136
50
|
/// Handoff ingress classification for an exact host grant. Like a publication it
|
|
137
51
|
/// is the explicit authority for its tuple, so it leads the protected-source
|
|
@@ -166,42 +80,6 @@ fn host_grant_sets(program: &mut Program<'_>, scope: &RouterScope) -> Result<()>
|
|
|
166
80
|
}
|
|
167
81
|
Ok(())
|
|
168
82
|
}
|
|
169
|
-
fn published_translation(program: &mut Program<'_>, scope: &RouterScope) -> Result<()> {
|
|
170
|
-
for port in &scope.published_ports {
|
|
171
|
-
let mut expressions = ipv4();
|
|
172
|
-
expressions.extend(link(&scope.handoff, true));
|
|
173
|
-
expressions.extend(meta(16, vec![protocol(&port.protocol)]));
|
|
174
|
-
expressions.extend(ct(10, None, vec![protocol(&port.protocol)]));
|
|
175
|
-
expressions.extend(ct(17, None, 0_u16.to_ne_bytes().to_vec()));
|
|
176
|
-
expressions.extend(ct(1, None, vec![0]));
|
|
177
|
-
expressions.extend(current_address(
|
|
178
|
-
&format!("{}/32", port.transit_source_address),
|
|
179
|
-
false,
|
|
180
|
-
)?);
|
|
181
|
-
expressions.extend(current_port(port.transit_port, false));
|
|
182
|
-
expressions.extend(dnat(&port.endpoint_address, port.endpoint_port)?);
|
|
183
|
-
program.rule("pre", expressions)?;
|
|
184
|
-
}
|
|
185
|
-
Ok(())
|
|
186
|
-
}
|
|
187
|
-
fn published_admissions(program: &mut Program<'_>, scope: &RouterScope) -> Result<()> {
|
|
188
|
-
for port in &scope.published_ports {
|
|
189
|
-
let endpoint = published_link(scope, port)?;
|
|
190
|
-
let original = published_envelope(scope, endpoint, port, false)?;
|
|
191
|
-
for connection_state in [2, 8] {
|
|
192
|
-
let mut expressions = original.clone();
|
|
193
|
-
expressions.extend(state(connection_state));
|
|
194
|
-
if connection_state == 8 && port.protocol == "tcp" {
|
|
195
|
-
expressions.extend(opening_tcp());
|
|
196
|
-
}
|
|
197
|
-
program.end("forward", expressions, 1)?;
|
|
198
|
-
}
|
|
199
|
-
let mut reply = published_envelope(scope, endpoint, port, true)?;
|
|
200
|
-
reply.extend(state(2));
|
|
201
|
-
program.end("forward", reply, 1)?;
|
|
202
|
-
}
|
|
203
|
-
Ok(())
|
|
204
|
-
}
|
|
205
83
|
fn protected(
|
|
206
84
|
program: &mut Program<'_>,
|
|
207
85
|
chain: &str,
|
|
@@ -221,7 +99,7 @@ fn protected(
|
|
|
221
99
|
}
|
|
222
100
|
program.end(chain, vec![], -5)
|
|
223
101
|
}
|
|
224
|
-
fn raw(program: &mut Program<'_>, scope: &RouterScope) -> Result<()> {
|
|
102
|
+
fn raw(program: &mut Program<'_>, scope: &RouterScope, hop: &published::Hop<'_>) -> Result<()> {
|
|
225
103
|
// Handoff ingress must classify only exact leased return envelopes and exact
|
|
226
104
|
// inbound publications. Unknown ingress never reaches private/default-zone
|
|
227
105
|
// rules, even after a rename.
|
|
@@ -231,120 +109,28 @@ fn raw(program: &mut Program<'_>, scope: &RouterScope) -> Result<()> {
|
|
|
231
109
|
// classified ahead of the protected-source denial below, exactly as a
|
|
232
110
|
// platform return envelope is. The host publishes into this address, so its
|
|
233
111
|
// clients are not confined to unprotected space.
|
|
234
|
-
|
|
112
|
+
published::arrival(program, hop)?;
|
|
235
113
|
host_grant_return(program, scope)?;
|
|
236
114
|
// Both sides of a publication lead the leased classifiers of every generation,
|
|
237
115
|
// so neither direction depends on the client's choice of source port.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
let mut expressions = ipv4();
|
|
248
|
-
expressions.extend(current_address(prefix, true)?);
|
|
249
|
-
program.end("raw_return", expressions, 0)?;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
for generation in &scope.generations {
|
|
253
|
-
for grant in &generation.grants {
|
|
254
|
-
if matches!(grant.destination, Destination::Platform { .. }) != platform {
|
|
255
|
-
continue;
|
|
256
|
-
}
|
|
257
|
-
let mut original = raw_original(scope, grant)?;
|
|
258
|
-
original.extend(set_ct(17, generation.conntrack_zone.to_ne_bytes().to_vec()));
|
|
259
|
-
program.end(
|
|
260
|
-
if grant.source_endpoint.is_some() {
|
|
261
|
-
"raw_in"
|
|
262
|
-
} else {
|
|
263
|
-
"raw_out"
|
|
264
|
-
},
|
|
265
|
-
original,
|
|
266
|
-
1,
|
|
267
|
-
)?;
|
|
268
|
-
let mut reply = raw_return(scope, grant, generation)?;
|
|
269
|
-
reply.extend(set_ct(17, generation.conntrack_zone.to_ne_bytes().to_vec()));
|
|
270
|
-
program.end("raw_return", reply, 1)?;
|
|
271
|
-
}
|
|
116
|
+
published::endpoint(program, hop)?;
|
|
117
|
+
// Platform grants are classified ahead of the protected barrier, public
|
|
118
|
+
// grants behind it, whose protected destinations stay in the default zone.
|
|
119
|
+
leased::classification(program, scope, Kind::Platform)?;
|
|
120
|
+
for prefix in &scope.protection.prefixes {
|
|
121
|
+
for chain in ["raw_in", "raw_out"] {
|
|
122
|
+
let mut expressions = ipv4();
|
|
123
|
+
expressions.extend(current_address(prefix, false)?);
|
|
124
|
+
program.end(chain, expressions, -5)?;
|
|
272
125
|
}
|
|
126
|
+
let mut expressions = ipv4();
|
|
127
|
+
expressions.extend(current_address(prefix, true)?);
|
|
128
|
+
program.end("raw_return", expressions, 0)?;
|
|
273
129
|
}
|
|
130
|
+
leased::classification(program, scope, Kind::Public)?;
|
|
274
131
|
program.end("raw_return", vec![], 0)
|
|
275
132
|
}
|
|
276
|
-
fn
|
|
277
|
-
for (index, allocation) in scope.generations.iter().enumerate() {
|
|
278
|
-
for protocol in ["tcp", "udp"] {
|
|
279
|
-
if !allocation
|
|
280
|
-
.grants
|
|
281
|
-
.iter()
|
|
282
|
-
.any(|grant| grant.protocol == protocol)
|
|
283
|
-
{
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
let chain = format!("original_{index}_{protocol}");
|
|
287
|
-
program.chain(&chain, None)?;
|
|
288
|
-
// Only exact tuple/link/zone/direction classifiers jump here. Share
|
|
289
|
-
// state checks instead of repeating those classifiers three times.
|
|
290
|
-
for connection_state in [2, 8] {
|
|
291
|
-
let mut labelled = ct(13, None, label(allocation));
|
|
292
|
-
labelled.extend(state(connection_state));
|
|
293
|
-
if connection_state == 8 && protocol == "tcp" {
|
|
294
|
-
labelled.extend(opening_tcp());
|
|
295
|
-
}
|
|
296
|
-
program.end(&chain, labelled, 1)?;
|
|
297
|
-
}
|
|
298
|
-
let mut fresh = state(8);
|
|
299
|
-
fresh.extend(ct(13, None, vec![0; 16]));
|
|
300
|
-
if protocol == "tcp" {
|
|
301
|
-
fresh.extend(opening_tcp());
|
|
302
|
-
}
|
|
303
|
-
fresh.extend(set_ct(13, label(allocation)));
|
|
304
|
-
program.end(&chain, fresh, 1)?;
|
|
305
|
-
// A failed state/label match returns to the caller's remaining
|
|
306
|
-
// classifiers and terminal denials, exactly as the inlined rules.
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
Ok(())
|
|
310
|
-
}
|
|
311
|
-
fn grants(
|
|
312
|
-
program: &mut Program<'_>,
|
|
313
|
-
scope: &RouterScope,
|
|
314
|
-
chain: &str,
|
|
315
|
-
platform: bool,
|
|
316
|
-
) -> Result<()> {
|
|
317
|
-
for (index, allocation) in scope.generations.iter().enumerate() {
|
|
318
|
-
for grant in &allocation.grants {
|
|
319
|
-
if matches!(grant.destination, Destination::Platform { .. }) != platform {
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
322
|
-
let local = grant.source_endpoint.is_none();
|
|
323
|
-
if chain == "forward" && local || chain != "forward" && !local {
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
if chain != "input" {
|
|
327
|
-
let mut original = filter(scope, grant, false)?;
|
|
328
|
-
original.extend(generation(allocation, 0, false));
|
|
329
|
-
// Current and original tuples remain checked on every packet;
|
|
330
|
-
// a label alone never authorizes a changed grant or endpoint.
|
|
331
|
-
program.jump(
|
|
332
|
-
chain,
|
|
333
|
-
original,
|
|
334
|
-
&format!("original_{index}_{}", grant.protocol),
|
|
335
|
-
)?;
|
|
336
|
-
}
|
|
337
|
-
if chain != "output" {
|
|
338
|
-
let mut reply = filter(scope, grant, true)?;
|
|
339
|
-
reply.extend(generation(allocation, 1, true));
|
|
340
|
-
reply.extend(state(2));
|
|
341
|
-
program.end(chain, reply, 1)?;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
Ok(())
|
|
346
|
-
}
|
|
347
|
-
pub(super) fn compile(program: &mut Program<'_>, scope: &RouterScope, revision: u64) -> Result<()> {
|
|
133
|
+
pub(super) fn compile(program: &mut Program<'_>, scope: &RouterScope) -> Result<()> {
|
|
348
134
|
for (name, hook, priority, kind) in [
|
|
349
135
|
("raw_in", 0, -300, "filter"),
|
|
350
136
|
("raw_out", 3, -300, "filter"),
|
|
@@ -358,36 +144,24 @@ pub(super) fn compile(program: &mut Program<'_>, scope: &RouterScope, revision:
|
|
|
358
144
|
if !scope.published_ports.is_empty() {
|
|
359
145
|
// Published destination NAT lives in this table's own prerouting chain, so
|
|
360
146
|
// it is created, replaced and deleted with the exact generation. An empty
|
|
361
|
-
// publication list keeps the previous chain set
|
|
147
|
+
// publication list keeps the previous chain set.
|
|
362
148
|
program.chain("pre", Some((0, -100, "nat")))?;
|
|
363
149
|
}
|
|
364
150
|
for name in ["raw_return", "protected_out", "protected_back"] {
|
|
365
151
|
program.chain(name, None)?;
|
|
366
152
|
}
|
|
153
|
+
let hop = hop(scope)?;
|
|
154
|
+
published::sets(program, &hop, true)?;
|
|
367
155
|
host_grant_sets(program, scope)?;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
rules: scope.rules.clone(),
|
|
373
|
-
}
|
|
374
|
-
.prepare()?;
|
|
375
|
-
for (name, rules) in private.guard_chains()? {
|
|
376
|
-
program.chain(&name, None)?;
|
|
377
|
-
for expressions in rules {
|
|
378
|
-
program.rule(&name, expressions)?;
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
original_states(program, scope)?;
|
|
382
|
-
raw(program, scope)?;
|
|
156
|
+
workloadgrant::sets(program, scope)?;
|
|
157
|
+
private::sets(program, scope)?;
|
|
158
|
+
leased::sets(program, scope)?;
|
|
159
|
+
raw(program, scope, &hop)?;
|
|
383
160
|
protected(program, "protected_out", scope, false)?;
|
|
384
161
|
protected(program, "protected_back", scope, true)?;
|
|
385
|
-
|
|
162
|
+
published::translations(program, &hop)?;
|
|
386
163
|
for chain in ["input", "forward", "output"] {
|
|
387
|
-
|
|
388
|
-
for expressions in parts.guards {
|
|
389
|
-
program.rule(chain, expressions)?;
|
|
390
|
-
}
|
|
164
|
+
private::guards(program, scope, chain)?;
|
|
391
165
|
// Published admission keeps the private anti-spoof guards ahead of it and
|
|
392
166
|
// precedes the capture barrier: the barrier denies every protected original
|
|
393
167
|
// destination, which includes this transit address, and an exact inbound
|
|
@@ -395,13 +169,12 @@ pub(super) fn compile(program: &mut Program<'_>, scope: &RouterScope, revision:
|
|
|
395
169
|
// Host grants take the same position for the same reason: the barrier
|
|
396
170
|
// denies the host's protected transit address in both directions.
|
|
397
171
|
if chain == "forward" {
|
|
398
|
-
|
|
172
|
+
published::inbound(program, &hop)?;
|
|
399
173
|
host_grant_admissions(program, scope)?;
|
|
174
|
+
workloadgrant::admissions(program, scope)?;
|
|
400
175
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
grants(program, scope, chain, true)?;
|
|
176
|
+
private::grants(program, scope, chain)?;
|
|
177
|
+
leased::admissions(program, scope, chain, Kind::Platform)?;
|
|
405
178
|
for incoming in [true, false] {
|
|
406
179
|
if chain == "input" && !incoming || chain == "output" && incoming {
|
|
407
180
|
continue;
|
|
@@ -416,10 +189,14 @@ pub(super) fn compile(program: &mut Program<'_>, scope: &RouterScope, revision:
|
|
|
416
189
|
},
|
|
417
190
|
)?;
|
|
418
191
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
192
|
+
// Symmetric flows follow the capture barrier, so protected destinations
|
|
193
|
+
// stay denied; the endpoint classification already keeps them, and
|
|
194
|
+
// their replies, in the default zone.
|
|
195
|
+
if chain == "forward" {
|
|
196
|
+
published::symmetric(program, &hop)?;
|
|
422
197
|
}
|
|
198
|
+
leased::admissions(program, scope, chain, Kind::Public)?;
|
|
199
|
+
private::denials(program, scope, chain)?;
|
|
423
200
|
for incoming in [true, false] {
|
|
424
201
|
if chain == "input" && !incoming || chain == "output" && incoming {
|
|
425
202
|
continue;
|
|
@@ -427,16 +204,8 @@ pub(super) fn compile(program: &mut Program<'_>, scope: &RouterScope, revision:
|
|
|
427
204
|
program.deny_link(chain, &scope.handoff, incoming)?;
|
|
428
205
|
}
|
|
429
206
|
}
|
|
430
|
-
for
|
|
431
|
-
|
|
432
|
-
let mut expressions = filter(scope, grant, false)?;
|
|
433
|
-
expressions.extend(generation(allocation, 0, true));
|
|
434
|
-
expressions.extend(snat(
|
|
435
|
-
&allocation.transit_source_address,
|
|
436
|
-
Some((grant.source_port_range.first, grant.source_port_range.last)),
|
|
437
|
-
)?);
|
|
438
|
-
program.rule("post", expressions)?;
|
|
439
|
-
}
|
|
207
|
+
for kind in [Kind::Platform, Kind::Public] {
|
|
208
|
+
leased::translation(program, scope, kind)?;
|
|
440
209
|
}
|
|
441
|
-
|
|
210
|
+
published::symmetric_translation(program, &hop)
|
|
442
211
|
}
|