mirror of
https://github.com/fergalmoran/DnsServer.git
synced 2025-12-22 09:29:50 +00:00
Add DNS Rebind Protection as an DNSApp.
This commit is contained in:
106
Apps/DnsRebindBlockingApp/App.cs
Normal file
106
Apps/DnsRebindBlockingApp/App.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
Apps/DnsRebindBlockingApp/AppConfig.cs
Normal file
10
Apps/DnsRebindBlockingApp/AppConfig.cs
Normal 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();
|
||||
}
|
||||
43
Apps/DnsRebindBlockingApp/DnsRebindBlockingApp.csproj
Normal file
43
Apps/DnsRebindBlockingApp/DnsRebindBlockingApp.csproj
Normal 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>
|
||||
14
Apps/DnsRebindBlockingApp/dnsApp.config
Normal file
14
Apps/DnsRebindBlockingApp/dnsApp.config
Normal 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"
|
||||
]
|
||||
}
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user