mirror of
https://github.com/fergalmoran/DnsServer.git
synced 2025-12-26 11:28:36 +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
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DefaultRecordsApp", "Apps\DefaultRecordsApp\DefaultRecordsApp.csproj", "{BCF0373F-540D-4E9E-A8AD-70CEE9B385A6}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DefaultRecordsApp", "Apps\DefaultRecordsApp\DefaultRecordsApp.csproj", "{BCF0373F-540D-4E9E-A8AD-70CEE9B385A6}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DnsRebindBlockingApp", "Apps\DnsRebindBlockingApp\DnsRebindBlockingApp.csproj", "{6F3E5B6B-7EA7-483D-8736-41ED92404B88}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{BCF0373F-540D-4E9E-A8AD-70CEE9B385A6}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -186,6 +192,7 @@ Global
|
|||||||
{29688452-F88A-49F5-9C98-BE7B2812C522} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2}
|
{29688452-F88A-49F5-9C98-BE7B2812C522} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2}
|
||||||
{6FF8C5F7-C98E-41C1-8FCD-25AEA0057673} = {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}
|
{BCF0373F-540D-4E9E-A8AD-70CEE9B385A6} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2}
|
||||||
|
{6F3E5B6B-7EA7-483D-8736-41ED92404B88} = {938BF8EF-74B9-4FE0-B46F-11EBB7A4B3D2}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {6747BB6D-2826-4356-A213-805FBCCF9201}
|
SolutionGuid = {6747BB6D-2826-4356-A213-805FBCCF9201}
|
||||||
|
|||||||
Reference in New Issue
Block a user