180 lines
5.4 KiB
C#
180 lines
5.4 KiB
C#
namespace LibNftables.Tests;
|
|
|
|
public sealed class NftRulesetRendererTests
|
|
{
|
|
[Fact]
|
|
public void Render_WithTypedRuleAndMap_RendersExpectedCommands()
|
|
{
|
|
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 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_WithRenderHelperReadyRuleset_RendersMapValueVerdicts()
|
|
{
|
|
NftRuleset ruleset = CreateTypedRuleset();
|
|
|
|
string rendered = NftRulesetRenderer.Render(ruleset);
|
|
|
|
Assert.Contains("80 : accept", rendered, StringComparison.Ordinal);
|
|
Assert.Contains("443 : drop", rendered, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void Render_WithIncompatibleTypedMapKey_ThrowsValidationException()
|
|
{
|
|
var ruleset = new NftRuleset();
|
|
var table = new NftTable
|
|
{
|
|
Name = "filter",
|
|
};
|
|
var map = new NftMap
|
|
{
|
|
Name = "bad_map",
|
|
KeyType = NftMapType.InetService,
|
|
ValueType = NftMapType.Verdict,
|
|
};
|
|
map.Add(NftValue.Interface("eth0"), NftValue.Verdict(NftVerdict.Accept));
|
|
table.Maps.Add(map);
|
|
ruleset.Tables.Add(table);
|
|
|
|
Assert.Throws<NftValidationException>(() => NftRulesetRenderer.Render(ruleset));
|
|
}
|
|
|
|
[Fact]
|
|
public void Render_WithNoTables_ThrowsValidationException()
|
|
{
|
|
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()
|
|
{
|
|
var ruleset = new NftRuleset();
|
|
var table = new NftTable
|
|
{
|
|
Name = "filter",
|
|
};
|
|
table.Sets.Add(new NftSet
|
|
{
|
|
Name = "conflict",
|
|
Type = NftSetType.Ipv4Address,
|
|
CustomTypeExpression = "ipv4_addr",
|
|
});
|
|
ruleset.Tables.Add(table);
|
|
|
|
Assert.Throws<NftValidationException>(() => NftRulesetRenderer.Render(ruleset));
|
|
}
|
|
|
|
private static NftRuleset CreateTypedRuleset()
|
|
{
|
|
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(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.Add(NftValue.Port(80), NftValue.Verdict(NftVerdict.Accept));
|
|
map.Add(NftValue.Port(443), 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;
|
|
}
|
|
}
|