Expand typed firewall and map API
This commit is contained in:
@@ -3,53 +3,30 @@ namespace LibNftables.Tests;
|
||||
public sealed class NftRulesetRendererTests
|
||||
{
|
||||
[Fact]
|
||||
public void Render_WithTypedSet_RendersExpectedCommands()
|
||||
public void Render_WithTypedRuleAndMap_RendersExpectedCommands()
|
||||
{
|
||||
var ruleset = new NftRuleset();
|
||||
var table = new NftTable
|
||||
{
|
||||
Family = NftFamily.Inet,
|
||||
Name = "filter",
|
||||
};
|
||||
var set = new NftSet
|
||||
{
|
||||
Name = "blocked_ipv4",
|
||||
Type = NftSetType.Ipv4Address,
|
||||
};
|
||||
set.Elements.Add("10.0.0.1");
|
||||
set.Elements.Add("10.0.0.2");
|
||||
table.Sets.Add(set);
|
||||
ruleset.Tables.Add(table);
|
||||
NftRuleset ruleset = CreateTypedRuleset();
|
||||
|
||||
string rendered = NftRulesetRenderer.Render(ruleset);
|
||||
|
||||
Assert.Equal(
|
||||
"add table inet filter" + Environment.NewLine +
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine,
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine +
|
||||
"add map inet filter service_policy { type inet_service : verdict; elements = { 80 : accept, 443 : drop }; }" + Environment.NewLine +
|
||||
"add chain inet filter input { type filter hook input priority 0; policy drop; }" + Environment.NewLine +
|
||||
"add rule inet filter input iifname \"eth0\" ip saddr @blocked_ipv4 tcp dport 22 accept" + Environment.NewLine,
|
||||
rendered);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_WithCustomTypeExpression_UsesCustomKeyword()
|
||||
public void Render_WithRenderHelperReadyRuleset_RendersMapValueVerdicts()
|
||||
{
|
||||
var ruleset = new NftRuleset();
|
||||
var table = new NftTable
|
||||
{
|
||||
Family = NftFamily.Ip,
|
||||
Name = "custom",
|
||||
};
|
||||
var set = new NftSet
|
||||
{
|
||||
Name = "ports",
|
||||
CustomTypeExpression = "inet_service",
|
||||
};
|
||||
set.Elements.Add("80");
|
||||
table.Sets.Add(set);
|
||||
ruleset.Tables.Add(table);
|
||||
NftRuleset ruleset = CreateTypedRuleset();
|
||||
|
||||
string rendered = NftRulesetRenderer.Render(ruleset);
|
||||
|
||||
Assert.Contains("type inet_service;", rendered, StringComparison.Ordinal);
|
||||
Assert.Contains("80 : accept", rendered, StringComparison.Ordinal);
|
||||
Assert.Contains("443 : drop", rendered, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -58,6 +35,58 @@ public sealed class NftRulesetRendererTests
|
||||
Assert.Throws<NftValidationException>(() => NftRulesetRenderer.Render(new NftRuleset()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_WithPortMatchWithoutProtocol_ThrowsValidationException()
|
||||
{
|
||||
var ruleset = new NftRuleset();
|
||||
var table = new NftTable
|
||||
{
|
||||
Name = "filter",
|
||||
};
|
||||
var chain = new NftChain
|
||||
{
|
||||
Name = "input",
|
||||
Type = NftChainType.Filter,
|
||||
Hook = NftHook.Input,
|
||||
Priority = 0,
|
||||
};
|
||||
chain.Rules.Add(new NftRule
|
||||
{
|
||||
DestinationPort = NftValue.Port(22),
|
||||
Verdict = NftVerdict.Accept,
|
||||
});
|
||||
table.Chains.Add(chain);
|
||||
ruleset.Tables.Add(table);
|
||||
|
||||
Assert.Throws<NftValidationException>(() => NftRulesetRenderer.Render(ruleset));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_WithUnknownJumpTarget_ThrowsValidationException()
|
||||
{
|
||||
var ruleset = new NftRuleset();
|
||||
var table = new NftTable
|
||||
{
|
||||
Name = "filter",
|
||||
};
|
||||
var chain = new NftChain
|
||||
{
|
||||
Name = "input",
|
||||
Type = NftChainType.Filter,
|
||||
Hook = NftHook.Input,
|
||||
Priority = 0,
|
||||
};
|
||||
chain.Rules.Add(new NftRule
|
||||
{
|
||||
Verdict = NftVerdict.Jump,
|
||||
JumpTarget = "missing",
|
||||
});
|
||||
table.Chains.Add(chain);
|
||||
ruleset.Tables.Add(table);
|
||||
|
||||
Assert.Throws<NftValidationException>(() => NftRulesetRenderer.Render(ruleset));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_WithConflictingSetTypeSources_ThrowsValidationException()
|
||||
{
|
||||
@@ -77,23 +106,61 @@ public sealed class NftRulesetRendererTests
|
||||
Assert.Throws<NftValidationException>(() => NftRulesetRenderer.Render(ruleset));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_WithInvalidElement_ThrowsValidationException()
|
||||
private static NftRuleset CreateTypedRuleset()
|
||||
{
|
||||
var ruleset = new NftRuleset();
|
||||
var table = new NftTable
|
||||
{
|
||||
Family = NftFamily.Inet,
|
||||
Name = "filter",
|
||||
};
|
||||
|
||||
var set = new NftSet
|
||||
{
|
||||
Name = "bad",
|
||||
Type = NftSetType.Mark,
|
||||
Name = "blocked_ipv4",
|
||||
Type = NftSetType.Ipv4Address,
|
||||
};
|
||||
set.Elements.Add("1; drop");
|
||||
set.Elements.Add(NftValue.Address(System.Net.IPAddress.Parse("10.0.0.1")));
|
||||
set.Elements.Add(NftValue.Address(System.Net.IPAddress.Parse("10.0.0.2")));
|
||||
table.Sets.Add(set);
|
||||
ruleset.Tables.Add(table);
|
||||
|
||||
Assert.Throws<NftValidationException>(() => NftRulesetRenderer.Render(ruleset));
|
||||
var map = new NftMap
|
||||
{
|
||||
Name = "service_policy",
|
||||
KeyType = NftMapType.InetService,
|
||||
ValueType = NftMapType.Verdict,
|
||||
};
|
||||
map.Entries.Add(new NftMapEntry
|
||||
{
|
||||
Key = NftValue.Port(80),
|
||||
Value = NftValue.Verdict(NftVerdict.Accept),
|
||||
});
|
||||
map.Entries.Add(new NftMapEntry
|
||||
{
|
||||
Key = NftValue.Port(443),
|
||||
Value = NftValue.Verdict(NftVerdict.Drop),
|
||||
});
|
||||
table.Maps.Add(map);
|
||||
|
||||
var chain = new NftChain
|
||||
{
|
||||
Name = "input",
|
||||
Type = NftChainType.Filter,
|
||||
Hook = NftHook.Input,
|
||||
Priority = 0,
|
||||
Policy = NftChainPolicy.Drop,
|
||||
};
|
||||
chain.Rules.Add(new NftRule
|
||||
{
|
||||
InputInterface = NftValue.Interface("eth0"),
|
||||
SourceAddressSetName = "blocked_ipv4",
|
||||
TransportProtocol = NftTransportProtocol.Tcp,
|
||||
DestinationPort = NftValue.Port(22),
|
||||
Verdict = NftVerdict.Accept,
|
||||
});
|
||||
table.Chains.Add(chain);
|
||||
|
||||
ruleset.Tables.Add(table);
|
||||
return ruleset;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,9 +91,27 @@ public sealed class NftablesClientIntegrationTests
|
||||
Name = "blocked_ipv4",
|
||||
Type = NftSetType.Ipv4Address,
|
||||
};
|
||||
set.Elements.Add("10.0.0.1");
|
||||
set.Elements.Add("10.0.0.2");
|
||||
set.Elements.Add(NftValue.Address(System.Net.IPAddress.Parse("10.0.0.1")));
|
||||
set.Elements.Add(NftValue.Address(System.Net.IPAddress.Parse("10.0.0.2")));
|
||||
table.Sets.Add(set);
|
||||
|
||||
var chain = new NftChain
|
||||
{
|
||||
Name = "input",
|
||||
Type = NftChainType.Filter,
|
||||
Hook = NftHook.Input,
|
||||
Priority = 0,
|
||||
Policy = NftChainPolicy.Drop,
|
||||
};
|
||||
chain.Rules.Add(new NftRule
|
||||
{
|
||||
SourceAddressSetName = "blocked_ipv4",
|
||||
TransportProtocol = NftTransportProtocol.Tcp,
|
||||
DestinationPort = NftValue.Port(22),
|
||||
Verdict = NftVerdict.Accept,
|
||||
});
|
||||
table.Chains.Add(chain);
|
||||
|
||||
ruleset.Tables.Add(table);
|
||||
|
||||
NftValidationResult result = client.ValidateRuleset(ruleset);
|
||||
|
||||
@@ -80,7 +80,10 @@ public sealed class NftablesClientUnitTests
|
||||
Assert.True(context.DryRun);
|
||||
Assert.Equal(
|
||||
"add table inet filter" + Environment.NewLine +
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine,
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine +
|
||||
"add map inet filter service_policy { type inet_service : verdict; elements = { 80 : accept, 443 : drop }; }" + Environment.NewLine +
|
||||
"add chain inet filter input { type filter hook input priority 0; policy drop; }" + Environment.NewLine +
|
||||
"add rule inet filter input iifname \"eth0\" ip saddr @blocked_ipv4 tcp dport 22 accept" + Environment.NewLine,
|
||||
context.LastCommandText);
|
||||
}
|
||||
|
||||
@@ -95,7 +98,10 @@ public sealed class NftablesClientUnitTests
|
||||
Assert.False(context.DryRun);
|
||||
Assert.Equal(
|
||||
"add table inet filter" + Environment.NewLine +
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine,
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine +
|
||||
"add map inet filter service_policy { type inet_service : verdict; elements = { 80 : accept, 443 : drop }; }" + Environment.NewLine +
|
||||
"add chain inet filter input { type filter hook input priority 0; policy drop; }" + Environment.NewLine +
|
||||
"add rule inet filter input iifname \"eth0\" ip saddr @blocked_ipv4 tcp dport 22 accept" + Environment.NewLine,
|
||||
context.LastCommandText);
|
||||
}
|
||||
|
||||
@@ -109,10 +115,31 @@ public sealed class NftablesClientUnitTests
|
||||
|
||||
Assert.Equal(
|
||||
"add table inet filter" + Environment.NewLine +
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine,
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine +
|
||||
"add map inet filter service_policy { type inet_service : verdict; elements = { 80 : accept, 443 : drop }; }" + Environment.NewLine +
|
||||
"add chain inet filter input { type filter hook input priority 0; policy drop; }" + Environment.NewLine +
|
||||
"add rule inet filter input iifname \"eth0\" ip saddr @blocked_ipv4 tcp dport 22 accept" + Environment.NewLine,
|
||||
context.LastCommandText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RenderRuleset_ReturnsTypedRulesetTextWithoutExecuting()
|
||||
{
|
||||
var context = new FakeContext();
|
||||
var client = CreateClient(() => context);
|
||||
|
||||
string rendered = client.RenderRuleset(CreateTypedRuleset());
|
||||
|
||||
Assert.Equal(
|
||||
"add table inet filter" + Environment.NewLine +
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine +
|
||||
"add map inet filter service_policy { type inet_service : verdict; elements = { 80 : accept, 443 : drop }; }" + Environment.NewLine +
|
||||
"add chain inet filter input { type filter hook input priority 0; policy drop; }" + Environment.NewLine +
|
||||
"add rule inet filter input iifname \"eth0\" ip saddr @blocked_ipv4 tcp dport 22 accept" + Environment.NewLine,
|
||||
rendered);
|
||||
Assert.Null(context.LastCommandText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_WithFileRequest_UsesFileExecutionPath()
|
||||
{
|
||||
@@ -248,14 +275,52 @@ public sealed class NftablesClientUnitTests
|
||||
Family = NftFamily.Inet,
|
||||
Name = "filter",
|
||||
};
|
||||
|
||||
var set = new NftSet
|
||||
{
|
||||
Name = "blocked_ipv4",
|
||||
Type = NftSetType.Ipv4Address,
|
||||
};
|
||||
set.Elements.Add("10.0.0.1");
|
||||
set.Elements.Add("10.0.0.2");
|
||||
set.Elements.Add(NftValue.Address(System.Net.IPAddress.Parse("10.0.0.1")));
|
||||
set.Elements.Add(NftValue.Address(System.Net.IPAddress.Parse("10.0.0.2")));
|
||||
table.Sets.Add(set);
|
||||
|
||||
var map = new NftMap
|
||||
{
|
||||
Name = "service_policy",
|
||||
KeyType = NftMapType.InetService,
|
||||
ValueType = NftMapType.Verdict,
|
||||
};
|
||||
map.Entries.Add(new NftMapEntry
|
||||
{
|
||||
Key = NftValue.Port(80),
|
||||
Value = NftValue.Verdict(NftVerdict.Accept),
|
||||
});
|
||||
map.Entries.Add(new NftMapEntry
|
||||
{
|
||||
Key = NftValue.Port(443),
|
||||
Value = NftValue.Verdict(NftVerdict.Drop),
|
||||
});
|
||||
table.Maps.Add(map);
|
||||
|
||||
var chain = new NftChain
|
||||
{
|
||||
Name = "input",
|
||||
Type = NftChainType.Filter,
|
||||
Hook = NftHook.Input,
|
||||
Priority = 0,
|
||||
Policy = NftChainPolicy.Drop,
|
||||
};
|
||||
chain.Rules.Add(new NftRule
|
||||
{
|
||||
InputInterface = NftValue.Interface("eth0"),
|
||||
SourceAddressSetName = "blocked_ipv4",
|
||||
TransportProtocol = NftTransportProtocol.Tcp,
|
||||
DestinationPort = NftValue.Port(22),
|
||||
Verdict = NftVerdict.Accept,
|
||||
});
|
||||
table.Chains.Add(chain);
|
||||
|
||||
ruleset.Tables.Add(table);
|
||||
return ruleset;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user