using System.Net;
using DodoSSH.Api.Features.Relay;
using DodoSSH.Api.Setup;
namespace DodoSSH.Api.Tests;
///
/// ADR 0004 ยง3, address by address.
///
///
/// The refused list is tested against the most permissive configuration this server accepts โ every
/// network allowed, private ranges on โ because "no configuration escape" is a claim about exactly that
/// case. A test that ran it only under the defaults would pass for a policy an operator could open up.
///
public sealed class RelayAddressPolicyTests
{
[Theory]
[InlineData("127.0.0.1")]
[InlineData("127.255.255.254")]
[InlineData("0.0.0.0")]
[InlineData("0.1.2.3")]
[InlineData("169.254.169.254")]
[InlineData("169.254.0.1")]
[InlineData("224.0.0.251")]
[InlineData("255.255.255.255")]
[InlineData("100.100.100.200")]
[InlineData("::")]
[InlineData("::1")]
[InlineData("fe80::1")]
[InlineData("ff02::1")]
[InlineData("fd00:ec2::254")]
// The same addresses, spelled as IPv6 โ the bypass ADR 0004 names, and its NAT64 cousin.
[InlineData("::ffff:127.0.0.1")]
[InlineData("::ffff:169.254.169.254")]
[InlineData("64:ff9b::a9fe:a9fe")]
[InlineData("64:ff9b::7f00:1")]
[InlineData("::127.0.0.1")]
public void TheRefusedList_HasNoConfigurationEscape(string address)
{
var wideOpen = new RelayOptions { AllowPrivateNetworks = true };
wideOpen.AllowedNetworks.Add("0.0.0.0/0");
wideOpen.AllowedNetworks.Add("::/0");
new RelayAddressPolicy(wideOpen).Permits(IPAddress.Parse(address)).ShouldBeFalse();
new RelayAddressPolicy(new RelayOptions()).Permits(IPAddress.Parse(address)).ShouldBeFalse();
}
[Fact]
public void ALinkLocalAddressWithAScope_IsStillLinkLocal()
{
var scoped = IPAddress.Parse("fe80::1%7");
new RelayAddressPolicy(new RelayOptions()).Permits(scoped).ShouldBeFalse();
}
[Theory]
[InlineData("10.0.0.5")]
[InlineData("172.16.4.4")]
[InlineData("192.168.1.10")]
[InlineData("100.101.102.103")] // A Tailnet address: carrier-grade NAT, beside the refused metadata one.
[InlineData("fd12:3456::1")]
[InlineData("::ffff:10.0.0.5")]
public void PrivateNetworks_ArePermittedByDefault_AndRefusedWhenSwitchedOff(string address)
{
new RelayAddressPolicy(new RelayOptions()).Permits(IPAddress.Parse(address)).ShouldBeTrue();
new RelayAddressPolicy(new RelayOptions { AllowPrivateNetworks = false })
.Permits(IPAddress.Parse(address))
.ShouldBeFalse();
}
[Theory]
[InlineData("203.0.113.10")]
[InlineData("2001:db8::10")]
public void PublicAddresses_ArePermitted(string address) =>
new RelayAddressPolicy(new RelayOptions { AllowPrivateNetworks = false })
.Permits(IPAddress.Parse(address))
.ShouldBeTrue();
[Fact]
public void AnAllowList_IsTheWholeAnswer_EvenWithPrivateNetworksOff()
{
var options = new RelayOptions { AllowPrivateNetworks = false };
options.AllowedNetworks.Add("10.20.0.0/16");
var policy = new RelayAddressPolicy(options);
policy.Permits(IPAddress.Parse("10.20.3.4")).ShouldBeTrue();
policy.Permits(IPAddress.Parse("10.21.3.4")).ShouldBeFalse();
policy.Permits(IPAddress.Parse("203.0.113.10")).ShouldBeFalse();
}
[Fact]
public void ADenial_IsAHoleInAnAllowance()
{
var options = new RelayOptions();
options.AllowedNetworks.Add("10.20.0.0/16");
options.DeniedNetworks.Add("10.20.5.0/24");
var policy = new RelayAddressPolicy(options);
policy.Permits(IPAddress.Parse("10.20.4.1")).ShouldBeTrue();
policy.Permits(IPAddress.Parse("10.20.5.1")).ShouldBeFalse();
}
[Theory]
[InlineData(25, false)]
[InlineData(465, false)]
[InlineData(587, false)]
[InlineData(0, false)]
[InlineData(65536, false)]
[InlineData(22, true)]
[InlineData(5432, true)]
public void Ports_RefuseSmtpAndNothingElse(int port, bool permitted) =>
RelayAddressPolicy.PermitsPort(port).ShouldBe(permitted);
[Theory]
[InlineData("10.0.0.0/8", true)]
[InlineData("fd00::/8", true)]
[InlineData("10.0.0.1/8", false)]
[InlineData("10.0.0.0", false)]
[InlineData("ten dot oh", false)]
public void NetworksAreReadStrictly(string entry, bool readable) =>
RelayAddressPolicy.AreNetworks([entry]).ShouldBe(readable);
}