Add DNS Rebind Protection as an DNSApp.

This commit is contained in:
Yip Rui Fung
2023-12-09 13:02:47 +08:00
parent 8444108310
commit fe00b00e6d
5 changed files with 180 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.Json;
using System.Threading.Tasks;
using DnsServerCore.ApplicationCommon;
using TechnitiumLibrary.Net;
using TechnitiumLibrary.Net.Dns;
using TechnitiumLibrary.Net.Dns.ResourceRecords;
namespace DnsRebindBlocking
{
public class App: IDnsApplication, IDnsPostProcessor
{
private AppConfig Config = null!;
private HashSet<NetworkAddress> PrivateNetworks = new();
private IDnsServer DnsServer = null!;
public void Dispose()
{
// Nothing to dispose of.
}
public Task InitializeAsync(IDnsServer dnsServer, string config)
{
DnsServer = dnsServer;
Config = JsonSerializer.Deserialize<AppConfig>(config, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
})!;
DnsServer.WriteLog($"Initializing. Enabled: {Config.Enabled}");
PrivateNetworks.Clear();
foreach (var privateNetwork in Config.PrivateNetworks)
{
var success = NetworkAddress.TryParse(privateNetwork, out NetworkAddress networkAddress);
PrivateNetworks.Add(networkAddress);
}
// Add the ServerDomain to the PrivateDomains list so it doesn't block it's own.
Config.PrivateDomains.Add(DnsServer.ServerDomain);
return Task.CompletedTask;
}
public string Description => "Block DNS responses with protected IP ranges to prevent DNS rebinding attacks.";
public Task<DnsDatagram> PostProcessAsync(DnsDatagram request, IPEndPoint remoteEP, DnsTransportProtocol protocol, DnsDatagram response)
{
if (!Config.Enabled)
return Task.FromResult(response);
var answers = response.Answer.Where(res => !IsFilteredRebind(res)).ToList();
var additional = response.Additional.Where(res => !IsFilteredRebind(res)).ToList();
return Task.FromResult(response.Clone(answers, response.Authority, additional));
}
private bool IsFilteredRebind(DnsResourceRecord record)
{
if (record.Type != DnsResourceRecordType.A && record.Type != DnsResourceRecordType.AAAA)
return false;
IPAddress address;
switch (record.Type)
{
case DnsResourceRecordType.A:
address = ((DnsARecordData)record.RDATA).Address;
break;
case DnsResourceRecordType.AAAA:
address = ((DnsAAAARecordData)record.RDATA).Address;
break;
default:
return false;
}
var isPrivateNetwork = PrivateNetworks.Any(net => net.Contains(address));
var isPrivateDomain = IsZoneFound(Config.PrivateDomains, record.Name, out _);
return isPrivateNetwork && !isPrivateDomain;
}
private static string? GetParentZone(string domain)
{
var i = domain.IndexOf('.');
//dont return root zone
return i > -1 ? domain[(i + 1)..] : null;
}
private static bool IsZoneFound(IReadOnlySet<string> domains, string domain, out string? foundZone)
{
var currentDomain = domain.ToLower();
do
{
if (domains.Contains(currentDomain))
{
foundZone = currentDomain;
return true;
}
currentDomain = GetParentZone(currentDomain);
}
while (currentDomain is not null);
foundZone = null;
return false;
}
}
}

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace DnsRebindBlocking;
public class AppConfig
{
public required bool Enabled { get; set; }
public required List<string> PrivateNetworks { get; init; } = new();
public required HashSet<string> PrivateDomains { get; init; } = new();
}

View File

@@ -0,0 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<Version>1.0.0</Version>
<Company>Technitium</Company>
<Product>Technitium DNS Server</Product>
<Authors>Shreyas Zare, Rui Fung Yip</Authors>
<RootNamespace>DnsRebindBlocking</RootNamespace>
<PackageProjectUrl>https://technitium.com/dns/</PackageProjectUrl>
<RepositoryUrl>https://github.com/TechnitiumSoftware/DnsServer</RepositoryUrl>
<Description>Blocks DNS rebinding attacks using configured private domains and networks.</Description>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<OutputType>Library</OutputType>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\DnsServerCore.ApplicationCommon\DnsServerCore.ApplicationCommon.csproj">
<Private>false</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Reference Include="TechnitiumLibrary">
<HintPath>..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.dll</HintPath>
<Private>false</Private>
</Reference>
<Reference Include="TechnitiumLibrary.Net">
<HintPath>..\..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<None Update="dnsApp.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,14 @@
{
"enabled": false,
"privateNetworks": [
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"169.254.0.0/16",
"fc00::/7",
"fe80::/10"
],
"privateDomains": [
"home.arpa"
]
}

View File

@@ -55,6 +55,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZoneAliasApp", "Apps\ZoneAl
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DefaultRecordsApp", "Apps\DefaultRecordsApp\DefaultRecordsApp.csproj", "{BCF0373F-540D-4E9E-A8AD-70CEE9B385A6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DnsRebindBlockingApp", "Apps\DnsRebindBlockingApp\DnsRebindBlockingApp.csproj", "{6F3E5B6B-7EA7-483D-8736-41ED92404B88}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -161,6 +163,10 @@ Global
{BCF0373F-540D-4E9E-A8AD-70CEE9B385A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BCF0373F-540D-4E9E-A8AD-70CEE9B385A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BCF0373F-540D-4E9E-A8AD-70CEE9B385A6}.Release|Any CPU.Build.0 = Release|Any CPU
{6F3E5B6B-7EA7-483D-8736-41ED92404B88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6F3E5B6B-7EA7-483D-8736-41ED92404B88}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F3E5B6B-7EA7-483D-8736-41ED92404B88}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6F3E5B6B-7EA7-483D-8736-41ED92404B88}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -186,6 +192,7 @@ Global
{29688452-F88A-49F5-9C98-BE7B2812C522} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2}
{6FF8C5F7-C98E-41C1-8FCD-25AEA0057673} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2}
{BCF0373F-540D-4E9E-A8AD-70CEE9B385A6} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2}
{6F3E5B6B-7EA7-483D-8736-41ED92404B88} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6747BB6D-2826-4356-A213-805FBCCF9201}