diff --git a/DnsServerCore/Dns/DnsResourceRecordInfo.cs b/DnsServerCore/Dns/DnsResourceRecordInfo.cs
new file mode 100644
index 00000000..19800275
--- /dev/null
+++ b/DnsServerCore/Dns/DnsResourceRecordInfo.cs
@@ -0,0 +1,75 @@
+/*
+Technitium DNS Server
+Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+using System;
+using System.IO;
+
+namespace DnsServerCore.Dns
+{
+ public class DnsResourceRecordInfo
+ {
+ #region variables
+
+ readonly bool _disabled;
+
+ #endregion
+
+ #region constructor
+
+ public DnsResourceRecordInfo()
+ { }
+
+ public DnsResourceRecordInfo(bool disabled)
+ {
+ _disabled = disabled;
+ }
+
+ public DnsResourceRecordInfo(BinaryReader bR)
+ {
+ switch (bR.ReadByte()) //version
+ {
+ case 1:
+ _disabled = bR.ReadBoolean();
+ break;
+
+ default:
+ throw new NotSupportedException("DnsResourceRecordInfo format version not supported.");
+ }
+ }
+
+ #endregion
+
+ #region public
+
+ public void WriteTo(BinaryWriter bW)
+ {
+ bW.Write((byte)1); //version
+ bW.Write(_disabled);
+ }
+
+ #endregion
+
+ #region properties
+
+ public bool Disabled
+ { get { return _disabled; } }
+
+ #endregion
+ }
+}
diff --git a/DnsServerCore/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs
similarity index 96%
rename from DnsServerCore/DnsServer.cs
rename to DnsServerCore/Dns/DnsServer.cs
index 0b49d790..165c1259 100644
--- a/DnsServerCore/DnsServer.cs
+++ b/DnsServerCore/Dns/DnsServer.cs
@@ -32,9 +32,10 @@ using System.Threading;
using TechnitiumLibrary.IO;
using TechnitiumLibrary.Net;
using TechnitiumLibrary.Net.Dns;
+using TechnitiumLibrary.Net.Dns.ResourceRecords;
using TechnitiumLibrary.Net.Proxy;
-namespace DnsServerCore
+namespace DnsServerCore.Dns
{
public class DnsServer : IDisposable
{
@@ -75,9 +76,6 @@ namespace DnsServerCore
readonly Zone _allowedZoneRoot = new Zone(true);
Zone _blockedZoneRoot = new Zone(true);
- const uint NEGATIVE_RECORD_TTL = 300u;
- const uint MINIMUM_RECORD_TTL = 10u;
- const uint SERVE_STALE_TTL = 7 * 24 * 60 * 60; //7 days serve stale ttl as per draft-ietf-dnsop-serve-stale-04
readonly DnsCache _dnsCache;
bool _allowRecursion = false;
@@ -161,19 +159,8 @@ namespace DnsServerCore
return;
if (disposing)
- {
Stop();
- if (_log != null)
- _log.Dispose();
-
- if (_queryLog != null)
- _queryLog.Dispose();
-
- if (_stats != null)
- _stats.Dispose();
- }
-
_disposed = true;
}
@@ -202,11 +189,6 @@ namespace DnsServerCore
{
while (true)
{
- if (udpListener.AddressFamily == AddressFamily.InterNetwork)
- remoteEP = new IPEndPoint(IPAddress.Any, 0);
- else
- remoteEP = new IPEndPoint(IPAddress.IPv6Any, 0);
-
try
{
bytesRecv = udpListener.ReceiveFrom(recvBuffer, ref remoteEP);
@@ -2104,102 +2086,5 @@ namespace DnsServerCore
}
#endregion
-
- class ResolverDnsCache : DnsCache
- {
- #region variables
-
- readonly protected Zone _cacheZoneRoot;
-
- #endregion
-
- #region constructor
-
- public ResolverDnsCache(Zone cacheZoneRoot)
- : base(NEGATIVE_RECORD_TTL, MINIMUM_RECORD_TTL, SERVE_STALE_TTL)
- {
- _cacheZoneRoot = cacheZoneRoot;
- }
-
- #endregion
-
- #region public
-
- public override DnsDatagram Query(DnsDatagram request)
- {
- return _cacheZoneRoot.Query(request);
- }
-
- protected override void CacheRecords(ICollection resourceRecords)
- {
- _cacheZoneRoot.SetRecords(resourceRecords);
- }
-
- #endregion
- }
-
- class ResolverPrefetchDnsCache : ResolverDnsCache
- {
- #region variables
-
- readonly DnsQuestionRecord _prefetchQuery;
-
- #endregion
-
- #region constructor
-
- public ResolverPrefetchDnsCache(Zone cacheZoneRoot, DnsQuestionRecord prefetchQuery)
- : base(cacheZoneRoot)
- {
- _prefetchQuery = prefetchQuery;
- }
-
- #endregion
-
- #region public
-
- public override DnsDatagram Query(DnsDatagram request)
- {
- if (_prefetchQuery.Equals(request.Question[0]))
- return _cacheZoneRoot.QueryCacheGetClosestNameServers(request); //return closest name servers so that the recursive resolver queries them to refreshes cache instead of returning response from cache
-
- return _cacheZoneRoot.Query(request);
- }
-
- #endregion
- }
-
- class RecursiveQueryLock
- {
- #region variables
-
- bool _complete;
- DnsDatagram _response;
-
- #endregion
-
- #region public
-
- public void SetComplete(DnsDatagram response)
- {
- if (!_complete)
- {
- _complete = true;
- _response = response;
- }
- }
-
- #endregion
-
- #region properties
-
- public bool Complete
- { get { return _complete; } }
-
- public DnsDatagram Response
- { get { return _response; } }
-
- #endregion
- }
}
}
diff --git a/DnsServerCore/DnsServerException.cs b/DnsServerCore/Dns/DnsServerException.cs
similarity index 93%
rename from DnsServerCore/DnsServerException.cs
rename to DnsServerCore/Dns/DnsServerException.cs
index 4f375ac7..71d0e1ca 100644
--- a/DnsServerCore/DnsServerException.cs
+++ b/DnsServerCore/Dns/DnsServerException.cs
@@ -1,6 +1,6 @@
/*
Technitium DNS Server
-Copyright (C) 2017 Shreyas Zare (shreyas@technitium.com)
+Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ along with this program. If not, see .
using System;
-namespace DnsServerCore
+namespace DnsServerCore.Dns
{
public class DnsServerException : Exception
{
diff --git a/DnsServerCore/Dns/RecursiveQueryLock.cs b/DnsServerCore/Dns/RecursiveQueryLock.cs
new file mode 100644
index 00000000..35b41ca0
--- /dev/null
+++ b/DnsServerCore/Dns/RecursiveQueryLock.cs
@@ -0,0 +1,56 @@
+/*
+Technitium DNS Server
+Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+using TechnitiumLibrary.Net.Dns;
+
+namespace DnsServerCore.Dns
+{
+ class RecursiveQueryLock
+ {
+ #region variables
+
+ bool _complete;
+ DnsDatagram _response;
+
+ #endregion
+
+ #region public
+
+ public void SetComplete(DnsDatagram response)
+ {
+ if (!_complete)
+ {
+ _complete = true;
+ _response = response;
+ }
+ }
+
+ #endregion
+
+ #region properties
+
+ public bool Complete
+ { get { return _complete; } }
+
+ public DnsDatagram Response
+ { get { return _response; } }
+
+ #endregion
+ }
+}
diff --git a/DnsServerCore/Dns/ResolverDnsCache.cs b/DnsServerCore/Dns/ResolverDnsCache.cs
new file mode 100644
index 00000000..2550d8e9
--- /dev/null
+++ b/DnsServerCore/Dns/ResolverDnsCache.cs
@@ -0,0 +1,61 @@
+/*
+Technitium DNS Server
+Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+using System.Collections.Generic;
+using TechnitiumLibrary.Net.Dns;
+
+namespace DnsServerCore.Dns
+{
+ class ResolverDnsCache : DnsCache
+ {
+ #region variables
+
+ const uint NEGATIVE_RECORD_TTL = 300u;
+ const uint MINIMUM_RECORD_TTL = 10u;
+ const uint SERVE_STALE_TTL = 7 * 24 * 60 * 60; //7 days serve stale ttl as per draft-ietf-dnsop-serve-stale-04
+
+ readonly protected Zone _cacheZoneRoot;
+
+ #endregion
+
+ #region constructor
+
+ public ResolverDnsCache(Zone cacheZoneRoot)
+ : base(NEGATIVE_RECORD_TTL, MINIMUM_RECORD_TTL, SERVE_STALE_TTL)
+ {
+ _cacheZoneRoot = cacheZoneRoot;
+ }
+
+ #endregion
+
+ #region public
+
+ public override DnsDatagram Query(DnsDatagram request)
+ {
+ return _cacheZoneRoot.Query(request);
+ }
+
+ protected override void CacheRecords(ICollection resourceRecords)
+ {
+ _cacheZoneRoot.SetRecords(resourceRecords);
+ }
+
+ #endregion
+ }
+}
diff --git a/DnsServerCore/Dns/ResolverPrefetchDnsCache.cs b/DnsServerCore/Dns/ResolverPrefetchDnsCache.cs
new file mode 100644
index 00000000..71cf4b94
--- /dev/null
+++ b/DnsServerCore/Dns/ResolverPrefetchDnsCache.cs
@@ -0,0 +1,54 @@
+/*
+Technitium DNS Server
+Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+using TechnitiumLibrary.Net.Dns;
+
+namespace DnsServerCore.Dns
+{
+ class ResolverPrefetchDnsCache : ResolverDnsCache
+ {
+ #region variables
+
+ readonly DnsQuestionRecord _prefetchQuery;
+
+ #endregion
+
+ #region constructor
+
+ public ResolverPrefetchDnsCache(Zone cacheZoneRoot, DnsQuestionRecord prefetchQuery)
+ : base(cacheZoneRoot)
+ {
+ _prefetchQuery = prefetchQuery;
+ }
+
+ #endregion
+
+ #region public
+
+ public override DnsDatagram Query(DnsDatagram request)
+ {
+ if (_prefetchQuery.Equals(request.Question[0]))
+ return _cacheZoneRoot.QueryCacheGetClosestNameServers(request); //return closest name servers so that the recursive resolver queries them to refreshes cache instead of returning response from cache
+
+ return _cacheZoneRoot.Query(request);
+ }
+
+ #endregion
+ }
+}
diff --git a/DnsServerCore/StatsManager.cs b/DnsServerCore/Dns/StatsManager.cs
similarity index 99%
rename from DnsServerCore/StatsManager.cs
rename to DnsServerCore/Dns/StatsManager.cs
index ea1fbc50..4fca9c86 100644
--- a/DnsServerCore/StatsManager.cs
+++ b/DnsServerCore/Dns/StatsManager.cs
@@ -28,7 +28,7 @@ using TechnitiumLibrary.IO;
using TechnitiumLibrary.Net;
using TechnitiumLibrary.Net.Dns;
-namespace DnsServerCore
+namespace DnsServerCore.Dns
{
public enum StatsResponseType
{
diff --git a/DnsServerCore/Zone.cs b/DnsServerCore/Dns/Zone.cs
similarity index 95%
rename from DnsServerCore/Zone.cs
rename to DnsServerCore/Dns/Zone.cs
index d31170ec..fe9d2181 100644
--- a/DnsServerCore/Zone.cs
+++ b/DnsServerCore/Dns/Zone.cs
@@ -20,10 +20,10 @@ along with this program. If not, see .
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.IO;
using TechnitiumLibrary.Net.Dns;
+using TechnitiumLibrary.Net.Dns.ResourceRecords;
-namespace DnsServerCore
+namespace DnsServerCore.Dns
{
public class Zone
{
@@ -1028,7 +1028,7 @@ namespace DnsServerCore
List zoneNames = new List();
foreach (Zone zone in zones)
- zoneNames.Add(new ZoneInfo(zone));
+ zoneNames.Add(new ZoneInfo(zone._zoneName, zone._disabled));
return zoneNames;
}
@@ -1096,101 +1096,5 @@ namespace DnsServerCore
}
#endregion
-
- public class ZoneInfo : IComparable
- {
- #region variables
-
- readonly string _zoneName;
- readonly bool _disabled;
-
- #endregion
-
- #region constructor
-
- public ZoneInfo(string zoneName, bool disabled)
- {
- _zoneName = zoneName;
- _disabled = disabled;
- }
-
- public ZoneInfo(Zone zone)
- {
- _zoneName = zone._zoneName;
- _disabled = zone._disabled;
- }
-
- #endregion
-
- #region public
-
- public int CompareTo(ZoneInfo other)
- {
- return this._zoneName.CompareTo(other._zoneName);
- }
-
- #endregion
-
- #region properties
-
- public string ZoneName
- { get { return _zoneName; } }
-
- public bool Disabled
- { get { return _disabled; } }
-
- #endregion
- }
-
- public class DnsResourceRecordInfo
- {
- #region variables
-
- readonly bool _disabled;
-
- #endregion
-
- #region constructor
-
- public DnsResourceRecordInfo()
- { }
-
- public DnsResourceRecordInfo(bool disabled)
- {
- _disabled = disabled;
- }
-
- public DnsResourceRecordInfo(BinaryReader bR)
- {
- switch (bR.ReadByte()) //version
- {
- case 1:
- _disabled = bR.ReadBoolean();
- break;
-
- default:
- throw new NotSupportedException("Zone.DnsResourceRecordInfo format version not supported.");
- }
- }
-
- #endregion
-
- #region public
-
- public void WriteTo(BinaryWriter bW)
- {
- bW.Write((byte)1); //version
- bW.Write(_disabled);
- }
-
- #endregion
-
- #region properties
-
- public bool Disabled
- { get { return _disabled; } }
-
- #endregion
- }
}
}
diff --git a/DnsServerCore/Dns/ZoneInfo.cs b/DnsServerCore/Dns/ZoneInfo.cs
new file mode 100644
index 00000000..4ee07ff8
--- /dev/null
+++ b/DnsServerCore/Dns/ZoneInfo.cs
@@ -0,0 +1,62 @@
+/*
+Technitium DNS Server
+Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+using System;
+
+namespace DnsServerCore.Dns
+{
+ public class ZoneInfo : IComparable
+ {
+ #region variables
+
+ readonly string _zoneName;
+ readonly bool _disabled;
+
+ #endregion
+
+ #region constructor
+
+ public ZoneInfo(string zoneName, bool disabled)
+ {
+ _zoneName = zoneName;
+ _disabled = disabled;
+ }
+
+ #endregion
+
+ #region public
+
+ public int CompareTo(ZoneInfo other)
+ {
+ return this._zoneName.CompareTo(other._zoneName);
+ }
+
+ #endregion
+
+ #region properties
+
+ public string ZoneName
+ { get { return _zoneName; } }
+
+ public bool Disabled
+ { get { return _disabled; } }
+
+ #endregion
+ }
+}
diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs
deleted file mode 100644
index f459186d..00000000
--- a/DnsServerCore/DnsWebService.cs
+++ /dev/null
@@ -1,4150 +0,0 @@
-/*
-Technitium DNS Server
-Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
-using Newtonsoft.Json;
-using Newtonsoft.Json.Converters;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Reflection;
-using System.Security.Cryptography;
-using System.Security.Cryptography.X509Certificates;
-using System.Text;
-using System.Threading;
-using TechnitiumLibrary.IO;
-using TechnitiumLibrary.Net;
-using TechnitiumLibrary.Net.Dns;
-using TechnitiumLibrary.Net.Proxy;
-
-namespace DnsServerCore
-{
- public class DnsWebService : IDisposable
- {
- #region enum
-
- enum ServiceState
- {
- Stopped = 0,
- Starting = 1,
- Running = 2,
- Stopping = 3
- }
-
- #endregion
-
- #region variables
-
- readonly string _currentVersion;
- readonly string _appFolder;
- readonly string _configFolder;
- readonly Uri _updateCheckUri;
-
- readonly LogManager _log;
- StatsManager _stats;
-
- DnsServer _dnsServer;
-
- int _webServicePort;
- HttpListener _webService;
- Thread _webServiceThread;
- string _webServiceHostname;
-
- string _tlsCertificatePath;
- string _tlsCertificatePassword;
- Timer _tlsCertificateUpdateTimer;
- DateTime _tlsCertificateLastModifiedOn;
- const int TLS_CERTIFICATE_UPDATE_TIMER_INITIAL_INTERVAL = 60000;
- const int TLS_CERTIFICATE_UPDATE_TIMER_INTERVAL = 60000;
-
- const int MAX_LOGIN_ATTEMPTS = 5;
- const int BLOCK_ADDRESS_INTERVAL = 5 * 60 * 1000;
- readonly ConcurrentDictionary _failedLoginAttempts = new ConcurrentDictionary();
- readonly ConcurrentDictionary _blockedAddresses = new ConcurrentDictionary();
- readonly ConcurrentDictionary _credentials = new ConcurrentDictionary();
- readonly ConcurrentDictionary _sessions = new ConcurrentDictionary();
-
- volatile ServiceState _state = ServiceState.Stopped;
-
- readonly Zone _customBlockedZoneRoot = new Zone(true);
-
- Timer _blockListUpdateTimer;
- readonly List _blockListUrls = new List();
- DateTime _blockListLastUpdatedOn;
- const int BLOCK_LIST_UPDATE_AFTER_HOURS = 24;
- const int BLOCK_LIST_UPDATE_TIMER_INITIAL_INTERVAL = 5000;
- const int BLOCK_LIST_UPDATE_TIMER_INTERVAL = 900000;
- const int BLOCK_LIST_UPDATE_RETRIES = 3;
-
- int _totalZonesAllowed;
- int _totalZonesBlocked;
-
- List _configDisabledZones;
-
- #endregion
-
- #region constructor
-
- public DnsWebService(string configFolder = null, Uri updateCheckUri = null)
- {
- Assembly assembly = Assembly.GetEntryAssembly();
- AssemblyName assemblyName = assembly.GetName();
-
- _currentVersion = assemblyName.Version.ToString();
- _appFolder = Path.GetDirectoryName(assembly.Location);
-
- if (configFolder == null)
- _configFolder = Path.Combine(_appFolder, "config");
- else
- _configFolder = configFolder;
-
- if (!Directory.Exists(_configFolder))
- Directory.CreateDirectory(_configFolder);
-
- _updateCheckUri = updateCheckUri;
-
- string logFolder = Path.Combine(_configFolder, "logs");
-
- if (!Directory.Exists(logFolder))
- Directory.CreateDirectory(logFolder);
-
- _log = new LogManager(logFolder);
-
- string blockListsFolder = Path.Combine(_configFolder, "blocklists");
-
- if (!Directory.Exists(blockListsFolder))
- Directory.CreateDirectory(blockListsFolder);
- }
-
- #endregion
-
- #region IDisposable
-
- private bool _disposed = false;
-
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed)
- return;
-
- if (disposing)
- {
- Stop();
-
- if (_dnsServer != null)
- _dnsServer.Dispose();
-
- if (_log != null)
- _log.Dispose();
-
- if (_stats != null)
- _stats.Dispose();
- }
-
- _disposed = true;
- }
-
- public void Dispose()
- {
- Dispose(true);
- }
-
- #endregion
-
- #region private
-
- private void AcceptWebRequestAsync(object state)
- {
- try
- {
- while (true)
- {
- HttpListenerContext context = _webService.GetContext();
- ThreadPool.QueueUserWorkItem(ProcessRequestAsync, new object[] { context.Request, context.Response });
- }
- }
- catch (Exception ex)
- {
- if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped))
- return; //web service stopping
-
- _log.Write(ex);
-
- throw;
- }
- }
-
- private void ProcessRequestAsync(object state)
- {
- object[] parameters = state as object[];
- HttpListenerRequest request = parameters[0] as HttpListenerRequest;
- HttpListenerResponse response = parameters[1] as HttpListenerResponse;
-
- response.AddHeader("Server", "");
- response.AddHeader("X-Robots-Tag", "noindex, nofollow");
-
- try
- {
- Uri url = request.Url;
- string path = url.AbsolutePath;
-
- if (!path.StartsWith("/"))
- {
- SendError(response, 404);
- return;
- }
-
- if (path.StartsWith("/api/"))
- {
- using (MemoryStream mS = new MemoryStream())
- {
- try
- {
- JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS));
- jsonWriter.WriteStartObject();
-
- switch (path)
- {
- case "/api/login":
- Login(request, jsonWriter);
- break;
-
- case "/api/logout":
- Logout(request);
- break;
-
- default:
- if (!IsSessionValid(request))
- throw new InvalidTokenDnsWebServiceException("Invalid token or session expired.");
-
- jsonWriter.WritePropertyName("response");
- jsonWriter.WriteStartObject();
-
- try
- {
- switch (path)
- {
- case "/api/changePassword":
- ChangePassword(request);
- break;
-
- case "/api/checkForUpdate":
- CheckForUpdate(request, jsonWriter);
- break;
-
- case "/api/getDnsSettings":
- GetDnsSettings(jsonWriter);
- break;
-
- case "/api/setDnsSettings":
- SetDnsSettings(request, jsonWriter);
- break;
-
- case "/api/getStats":
- GetStats(request, jsonWriter);
- break;
-
- case "/api/flushDnsCache":
- FlushCache(request);
- break;
-
- case "/api/listCachedZones":
- ListCachedZones(request, jsonWriter);
- break;
-
- case "/api/deleteCachedZone":
- DeleteCachedZone(request);
- break;
-
- case "/api/listAllowedZones":
- ListAllowedZones(request, jsonWriter);
- break;
-
- case "/api/importAllowedZones":
- ImportAllowedZones(request);
- break;
-
- case "/api/exportAllowedZones":
- ExportAllowedZones(response);
- return;
-
- case "/api/flushAllowedZone":
- FlushAllowedZone(request);
- break;
-
- case "/api/deleteAllowedZone":
- DeleteAllowedZone(request);
- break;
-
- case "/api/allowZone":
- AllowZone(request);
- break;
-
- case "/api/listBlockedZones":
- ListBlockedZones(request, jsonWriter);
- break;
-
- case "/api/importCustomBlockedZones":
- ImportCustomBlockedZones(request);
- break;
-
- case "/api/exportCustomBlockedZones":
- ExportCustomBlockedZones(response);
- return;
-
- case "/api/flushCustomBlockedZone":
- FlushCustomBlockedZone(request);
- break;
-
- case "/api/deleteCustomBlockedZone":
- DeleteCustomBlockedZone(request);
- break;
-
- case "/api/customBlockZone":
- CustomBlockZone(request);
- break;
-
- case "/api/listZones":
- ListZones(jsonWriter);
- break;
-
- case "/api/createZone":
- CreateZone(request, jsonWriter);
- break;
-
- case "/api/deleteZone":
- DeleteZone(request);
- break;
-
- case "/api/enableZone":
- EnableZone(request);
- break;
-
- case "/api/disableZone":
- DisableZone(request);
- break;
-
- case "/api/addRecord":
- AddRecord(request);
- break;
-
- case "/api/getRecords":
- GetRecords(request, jsonWriter);
- break;
-
- case "/api/deleteRecord":
- DeleteRecord(request);
- break;
-
- case "/api/updateRecord":
- UpdateRecord(request);
- break;
-
- case "/api/resolveQuery":
- ResolveQuery(request, jsonWriter);
- break;
-
- case "/api/listLogs":
- ListLogs(jsonWriter);
- break;
-
- case "/api/deleteLog":
- DeleteLog(request);
- break;
-
- default:
- throw new DnsWebServiceException("Invalid command: " + path);
- }
- }
- finally
- {
- jsonWriter.WriteEndObject();
- }
- break;
- }
-
- jsonWriter.WritePropertyName("status");
- jsonWriter.WriteValue("ok");
-
- jsonWriter.WriteEndObject();
- jsonWriter.Flush();
- }
- catch (InvalidTokenDnsWebServiceException ex)
- {
- mS.SetLength(0);
- JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS));
- jsonWriter.WriteStartObject();
-
- jsonWriter.WritePropertyName("status");
- jsonWriter.WriteValue("invalid-token");
-
- jsonWriter.WritePropertyName("errorMessage");
- jsonWriter.WriteValue(ex.Message);
-
- jsonWriter.WriteEndObject();
- jsonWriter.Flush();
- }
- catch (Exception ex)
- {
- mS.SetLength(0);
- JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS));
- jsonWriter.WriteStartObject();
-
- _log.Write(GetRequestRemoteEndPoint(request), ex);
-
- jsonWriter.WritePropertyName("status");
- jsonWriter.WriteValue("error");
-
- jsonWriter.WritePropertyName("errorMessage");
- jsonWriter.WriteValue(ex.Message);
-
- jsonWriter.WritePropertyName("stackTrace");
- jsonWriter.WriteValue(ex.StackTrace);
-
- jsonWriter.WriteEndObject();
- jsonWriter.Flush();
- }
-
- response.ContentType = "application/json; charset=utf-8";
- response.ContentEncoding = Encoding.UTF8;
- response.ContentLength64 = mS.Length;
-
- using (Stream stream = response.OutputStream)
- {
- mS.WriteTo(response.OutputStream);
- }
- }
- }
- else if (path.StartsWith("/log/"))
- {
- if (!IsSessionValid(request))
- {
- SendError(response, 403, "Invalid token or session expired.");
- return;
- }
-
- string[] pathParts = path.Split('/');
-
- string logFileName = pathParts[2];
- string logFile = Path.Combine(_log.LogFolder, logFileName + ".log");
-
- int limit = 0;
- string strLimit = request.QueryString["limit"];
- if (!string.IsNullOrEmpty(strLimit))
- limit = int.Parse(strLimit);
-
- LogManager.DownloadLog(response, logFile, limit * 1024 * 1024);
- }
- else
- {
- if (path.Contains("/../"))
- {
- SendError(response, 404);
- return;
- }
-
- if (path == "/blocklist.txt")
- {
- if (!IPAddress.IsLoopback(GetRequestRemoteEndPoint(request).Address))
- SendError(response, 403);
- }
-
- if (path == "/")
- path = "/index.html";
-
- path = Path.Combine(_appFolder, "www" + path.Replace('/', Path.DirectorySeparatorChar));
-
- if (!File.Exists(path))
- {
- SendError(response, 404);
- return;
- }
-
- SendFile(response, path);
- }
- }
- catch (Exception ex)
- {
- if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped))
- return; //web service stopping
-
- _log.Write(GetRequestRemoteEndPoint(request), ex);
-
- SendError(response, ex);
- }
- }
-
- private IPEndPoint GetRequestRemoteEndPoint(HttpListenerRequest request)
- {
- //this is due to mono NullReferenceException issue
- try
- {
- if (NetUtilities.IsPrivateIP(request.RemoteEndPoint.Address))
- {
- //reverse proxy X-Real-IP header supported only when remote IP address is private
-
- string xRealIp = request.Headers["X-Real-IP"];
- if (!string.IsNullOrEmpty(xRealIp))
- {
- //get the real IP address of the requesting client from X-Real-IP header set in nginx proxy_pass block
- return new IPEndPoint(IPAddress.Parse(xRealIp), 0);
- }
- }
-
- return request.RemoteEndPoint;
- }
- catch
- {
- return new IPEndPoint(IPAddress.Any, 0);
- }
- }
-
- private static void SendError(HttpListenerResponse response, Exception ex)
- {
- SendError(response, 500, ex.ToString());
- }
-
- private static void SendError(HttpListenerResponse response, int statusCode, string message = null)
- {
- try
- {
- string statusString = statusCode + " " + DnsServer.GetStatusString((HttpStatusCode)statusCode);
- byte[] buffer = Encoding.UTF8.GetBytes("" + statusString + "" + statusString + "
" + (message == null ? "" : "" + message + "
") + "");
-
- response.StatusCode = statusCode;
- response.ContentType = "text/html";
- response.ContentLength64 = buffer.Length;
-
- using (Stream stream = response.OutputStream)
- {
- stream.Write(buffer, 0, buffer.Length);
- }
- }
- catch
- { }
- }
-
- private static void SendFile(HttpListenerResponse response, string path)
- {
- using (FileStream fS = new FileStream(path, FileMode.Open, FileAccess.Read))
- {
- response.ContentType = WebUtilities.GetContentType(path).MediaType;
- response.ContentLength64 = fS.Length;
- response.AddHeader("Cache-Control", "private, max-age=300");
-
- using (Stream stream = response.OutputStream)
- {
- try
- {
- fS.CopyTo(stream);
- }
- catch (HttpListenerException)
- {
- //ignore this error
- }
- }
- }
- }
-
- private string CreateSession(string username)
- {
- string token = BinaryNumber.GenerateRandomNumber256().ToString();
-
- if (!_sessions.TryAdd(token, new UserSession(username)))
- throw new DnsWebServiceException("Error while creating session. Please try again.");
-
- return token;
- }
-
- private UserSession GetSession(string token)
- {
- if (_sessions.TryGetValue(token, out UserSession session))
- return session;
-
- return null;
- }
-
- private UserSession GetSession(HttpListenerRequest request)
- {
- string strToken = request.QueryString["token"];
- if (string.IsNullOrEmpty(strToken))
- throw new DnsWebServiceException("Parameter 'token' missing.");
-
- return GetSession(strToken);
- }
-
- private UserSession DeleteSession(string token)
- {
- if (_sessions.TryRemove(token, out UserSession session))
- return session;
-
- return null;
- }
-
- private UserSession DeleteSession(HttpListenerRequest request)
- {
- string strToken = request.QueryString["token"];
- if (string.IsNullOrEmpty(strToken))
- throw new DnsWebServiceException("Parameter 'token' missing.");
-
- return DeleteSession(strToken);
- }
-
- private void FailedLoginAttempt(IPAddress address)
- {
- _failedLoginAttempts.AddOrUpdate(address, 1, delegate (IPAddress key, int attempts)
- {
- return attempts + 1;
- });
- }
-
- private bool LoginAttemptsExceedLimit(IPAddress address, int limit)
- {
- if (!_failedLoginAttempts.TryGetValue(address, out int attempts))
- return false;
-
- return attempts >= limit;
- }
-
- private void ResetFailedLoginAttempt(IPAddress address)
- {
- _failedLoginAttempts.TryRemove(address, out _);
- }
-
- private void BlockAddress(IPAddress address, int interval)
- {
- _blockedAddresses.TryAdd(address, DateTime.UtcNow.AddMilliseconds(interval));
- }
-
- private bool IsAddressBlocked(IPAddress address)
- {
- if (!_blockedAddresses.TryGetValue(address, out DateTime expiry))
- return false;
-
- if (expiry > DateTime.UtcNow)
- {
- return true;
- }
- else
- {
- UnblockAddress(address);
- ResetFailedLoginAttempt(address);
-
- return false;
- }
- }
-
- private void UnblockAddress(IPAddress address)
- {
- _blockedAddresses.TryRemove(address, out _);
- }
-
- private void Login(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string strUsername = request.QueryString["user"];
- if (string.IsNullOrEmpty(strUsername))
- throw new DnsWebServiceException("Parameter 'user' missing.");
-
- string strPassword = request.QueryString["pass"];
- if (string.IsNullOrEmpty(strPassword))
- throw new DnsWebServiceException("Parameter 'pass' missing.");
-
- IPEndPoint remoteEP = GetRequestRemoteEndPoint(request);
-
- if (IsAddressBlocked(remoteEP.Address))
- throw new DnsWebServiceException("Max limit of " + MAX_LOGIN_ATTEMPTS + " attempts exceeded. Access blocked for " + (BLOCK_ADDRESS_INTERVAL / 1000) + " seconds.");
-
- strUsername = strUsername.ToLower();
- string strPasswordHash = GetPasswordHash(strUsername, strPassword);
-
- if (!_credentials.TryGetValue(strUsername, out string passwordHash) || (passwordHash != strPasswordHash))
- {
- if (strPassword != "admin") //exception for default password
- {
- FailedLoginAttempt(remoteEP.Address);
-
- if (LoginAttemptsExceedLimit(remoteEP.Address, MAX_LOGIN_ATTEMPTS))
- BlockAddress(remoteEP.Address, BLOCK_ADDRESS_INTERVAL);
-
- Thread.Sleep(1000);
- }
-
- throw new DnsWebServiceException("Invalid username or password: " + strUsername);
- }
-
- ResetFailedLoginAttempt(remoteEP.Address);
-
- _log.Write(remoteEP, "[" + strUsername + "] User logged in.");
-
- string token = CreateSession(strUsername);
-
- jsonWriter.WritePropertyName("token");
- jsonWriter.WriteValue(token);
- }
-
- private bool IsSessionValid(HttpListenerRequest request)
- {
- UserSession session = GetSession(request);
- if (session == null)
- return false;
-
- if (session.HasExpired())
- {
- DeleteSession(request);
- return false;
- }
-
- session.UpdateLastSeen();
- return true;
- }
-
- private void ChangePassword(HttpListenerRequest request)
- {
- string strToken = request.QueryString["token"];
- if (string.IsNullOrEmpty(strToken))
- throw new DnsWebServiceException("Parameter 'token' missing.");
-
- string strPassword = request.QueryString["pass"];
- if (string.IsNullOrEmpty(strPassword))
- throw new DnsWebServiceException("Parameter 'pass' missing.");
-
- UserSession session = GetSession(strToken);
- if (session == null)
- throw new DnsWebServiceException("User session does not exists.");
-
- SetCredentials(session.Username, strPassword);
- SaveConfigFile();
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + session.Username + "] Password was changed for user.");
- }
-
- private void Logout(HttpListenerRequest request)
- {
- string strToken = request.QueryString["token"];
- if (string.IsNullOrEmpty(strToken))
- throw new DnsWebServiceException("Parameter 'token' missing.");
-
- UserSession session = DeleteSession(strToken);
-
- if (session != null)
- _log.Write(GetRequestRemoteEndPoint(request), "[" + session.Username + "] User logged out.");
- }
-
- public static void CreateUpdateInfo(Stream s, string version, string displayText, string downloadLink)
- {
- BinaryWriter bW = new BinaryWriter(s);
-
- bW.Write(Encoding.ASCII.GetBytes("DU")); //format
- bW.Write((byte)2); //version
-
- bW.WriteShortString(version);
- bW.WriteShortString(displayText);
- bW.WriteShortString(downloadLink);
- }
-
- public static void CreateUpdateInfov1(Stream s, string version, string displayText, string downloadLink)
- {
- BincodingEncoder encoder = new BincodingEncoder(s, "DU", 1);
-
- encoder.EncodeKeyValue("version", version);
- encoder.EncodeKeyValue("displayText", displayText);
- encoder.EncodeKeyValue("downloadLink", downloadLink);
- }
-
- private void CheckForUpdate(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string updateVersion = null;
- string displayText = null;
- string downloadLink = null;
-
- bool updateAvailable = false;
-
- if (_updateCheckUri != null)
- {
- try
- {
- using (WebClientEx wc = new WebClientEx())
- {
- wc.Proxy = _dnsServer.Proxy;
-
- byte[] response = wc.DownloadData(_updateCheckUri);
-
- using (MemoryStream mS = new MemoryStream(response, false))
- {
- BinaryReader bR = new BinaryReader(mS);
-
- if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "DU") //format
- throw new InvalidDataException("DNS Server update info format is invalid.");
-
- switch (bR.ReadByte()) //version
- {
- case 1:
- #region old version
-
- mS.Position = 0;
- BincodingDecoder decoder = new BincodingDecoder(mS, "DU");
-
- switch (decoder.Version)
- {
- case 1:
- while (true)
- {
- Bincoding entry = decoder.DecodeNext();
- if (entry == null)
- break;
-
- KeyValuePair value = entry.GetKeyValuePair();
-
- switch (value.Key)
- {
- case "version":
- updateVersion = value.Value.GetStringValue();
- break;
-
- case "displayText":
- displayText = value.Value.GetStringValue();
- break;
-
- case "downloadLink":
- downloadLink = value.Value.GetStringValue();
- break;
- }
- }
- break;
-
- default:
- throw new IOException("File version not supported: " + decoder.Version);
- }
-
- #endregion
- break;
-
- case 2:
- updateVersion = bR.ReadShortString();
- displayText = bR.ReadShortString();
- downloadLink = bR.ReadShortString();
- break;
-
- default:
- throw new InvalidDataException("DNS Server update info version not supported.");
- }
-
- updateAvailable = IsUpdateAvailable(_currentVersion, updateVersion);
- }
- }
-
- _log.Write(GetRequestRemoteEndPoint(request), "Check for update was done {updateAvailable: " + updateAvailable + "; updateVersion: " + updateVersion + "; displayText: " + displayText + "; downloadLink: " + downloadLink + ";}");
- }
- catch (Exception ex)
- {
- _log.Write(GetRequestRemoteEndPoint(request), "Check for update was done {updateAvailable: False;}\r\n" + ex.ToString());
- }
- }
-
- jsonWriter.WritePropertyName("updateAvailable");
- jsonWriter.WriteValue(updateAvailable);
-
- if (updateAvailable)
- {
- if (!string.IsNullOrEmpty(displayText))
- {
- jsonWriter.WritePropertyName("displayText");
- jsonWriter.WriteValue(displayText);
- }
-
- jsonWriter.WritePropertyName("downloadLink");
- jsonWriter.WriteValue(downloadLink);
- }
- }
-
- private static bool IsUpdateAvailable(string currentVersion, string updateVersion)
- {
- if (updateVersion == null)
- return false;
-
- string[] uVer = updateVersion.Split(new char[] { '.' });
- string[] cVer = currentVersion.Split(new char[] { '.' });
-
- int x = uVer.Length;
- if (x > cVer.Length)
- x = cVer.Length;
-
- for (int i = 0; i < x; i++)
- {
- if (Convert.ToInt32(uVer[i]) > Convert.ToInt32(cVer[i]))
- return true;
- else if (Convert.ToInt32(uVer[i]) < Convert.ToInt32(cVer[i]))
- return false;
- }
-
- if (uVer.Length > cVer.Length)
- {
- for (int i = x; i < uVer.Length; i++)
- {
- if (Convert.ToInt32(uVer[i]) > 0)
- return true;
- }
- }
-
- return false;
- }
-
- private static string GetCleanVersion(string version)
- {
- while (version.EndsWith(".0"))
- {
- version = version.Substring(0, version.Length - 2);
- }
-
- return version;
- }
-
- private void GetDnsSettings(JsonTextWriter jsonWriter)
- {
- jsonWriter.WritePropertyName("version");
- jsonWriter.WriteValue(GetCleanVersion(_currentVersion));
-
- jsonWriter.WritePropertyName("serverDomain");
- jsonWriter.WriteValue(_dnsServer.ServerDomain);
-
- jsonWriter.WritePropertyName("webServicePort");
- jsonWriter.WriteValue(_webServicePort);
-
- jsonWriter.WritePropertyName("dnsServerLocalAddresses");
- jsonWriter.WriteStartArray();
-
- foreach (IPAddress localAddress in _dnsServer.LocalAddresses)
- jsonWriter.WriteValue(localAddress.ToString());
-
- jsonWriter.WriteEndArray();
-
- jsonWriter.WritePropertyName("enableDnsOverHttp");
- jsonWriter.WriteValue(_dnsServer.EnableDnsOverHttp);
-
- jsonWriter.WritePropertyName("enableDnsOverTls");
- jsonWriter.WriteValue(_dnsServer.EnableDnsOverTls);
-
- jsonWriter.WritePropertyName("enableDnsOverHttps");
- jsonWriter.WriteValue(_dnsServer.EnableDnsOverHttps);
-
- jsonWriter.WritePropertyName("tlsCertificatePath");
- jsonWriter.WriteValue(_tlsCertificatePath);
-
- jsonWriter.WritePropertyName("tlsCertificatePassword");
- jsonWriter.WriteValue("************");
-
- jsonWriter.WritePropertyName("preferIPv6");
- jsonWriter.WriteValue(_dnsServer.PreferIPv6);
-
- jsonWriter.WritePropertyName("logQueries");
- jsonWriter.WriteValue(_dnsServer.QueryLogManager != null);
-
- jsonWriter.WritePropertyName("allowRecursion");
- jsonWriter.WriteValue(_dnsServer.AllowRecursion);
-
- jsonWriter.WritePropertyName("allowRecursionOnlyForPrivateNetworks");
- jsonWriter.WriteValue(_dnsServer.AllowRecursionOnlyForPrivateNetworks);
-
- jsonWriter.WritePropertyName("cachePrefetchEligibility");
- jsonWriter.WriteValue(_dnsServer.CachePrefetchEligibility);
-
- jsonWriter.WritePropertyName("cachePrefetchTrigger");
- jsonWriter.WriteValue(_dnsServer.CachePrefetchTrigger);
-
- jsonWriter.WritePropertyName("cachePrefetchSampleIntervalInMinutes");
- jsonWriter.WriteValue(_dnsServer.CachePrefetchSampleIntervalInMinutes);
-
- jsonWriter.WritePropertyName("cachePrefetchSampleEligibilityHitsPerHour");
- jsonWriter.WriteValue(_dnsServer.CachePrefetchSampleEligibilityHitsPerHour);
-
- jsonWriter.WritePropertyName("proxy");
- if (_dnsServer.Proxy == null)
- {
- jsonWriter.WriteNull();
- }
- else
- {
- jsonWriter.WriteStartObject();
-
- NetProxy proxy = _dnsServer.Proxy;
-
- jsonWriter.WritePropertyName("type");
- jsonWriter.WriteValue(proxy.Type.ToString());
-
- jsonWriter.WritePropertyName("address");
- jsonWriter.WriteValue(proxy.Address);
-
- jsonWriter.WritePropertyName("port");
- jsonWriter.WriteValue(proxy.Port);
-
- NetworkCredential credential = proxy.Credential;
-
- if (credential != null)
- {
- jsonWriter.WritePropertyName("username");
- jsonWriter.WriteValue(credential.UserName);
-
- jsonWriter.WritePropertyName("password");
- jsonWriter.WriteValue(credential.Password);
- }
-
- jsonWriter.WriteEndObject();
- }
-
- jsonWriter.WritePropertyName("forwarders");
-
- if (_dnsServer.Forwarders == null)
- {
- jsonWriter.WriteNull();
- }
- else
- {
- jsonWriter.WriteStartArray();
-
- foreach (NameServerAddress forwarder in _dnsServer.Forwarders)
- jsonWriter.WriteValue(forwarder.OriginalString);
-
- jsonWriter.WriteEndArray();
- }
-
- jsonWriter.WritePropertyName("forwarderProtocol");
- jsonWriter.WriteValue(_dnsServer.ForwarderProtocol.ToString());
-
-
- jsonWriter.WritePropertyName("blockListUrls");
-
- if (_blockListUrls.Count == 0)
- {
- jsonWriter.WriteNull();
- }
- else
- {
- jsonWriter.WriteStartArray();
-
- foreach (Uri blockListUrl in _blockListUrls)
- jsonWriter.WriteValue(blockListUrl.AbsoluteUri);
-
- jsonWriter.WriteEndArray();
- }
- }
-
- private void SetDnsSettings(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string strServerDomain = request.QueryString["serverDomain"];
- if (!string.IsNullOrEmpty(strServerDomain))
- {
- strServerDomain = strServerDomain.ToLower();
-
- if (_dnsServer.ServerDomain != strServerDomain)
- {
- string oldServerDomain = _dnsServer.ServerDomain;
- _dnsServer.ServerDomain = strServerDomain;
-
- ThreadPool.QueueUserWorkItem(delegate (object state)
- {
- try
- {
- //authoritative zone
- {
- ICollection zones = _dnsServer.AuthoritativeZoneRoot.ListAuthoritativeZones();
-
- foreach (Zone.ZoneInfo zone in zones)
- {
- DnsResourceRecord[] soaResourceRecords = _dnsServer.AuthoritativeZoneRoot.GetAllRecords(zone.ZoneName, DnsResourceRecordType.SOA, false, true);
- if (soaResourceRecords.Length > 0)
- {
- DnsResourceRecord soaRecord = soaResourceRecords[0];
- DnsSOARecord soaRecordData = soaRecord.RDATA as DnsSOARecord;
-
- if (soaRecordData.MasterNameServer.Equals(oldServerDomain, StringComparison.OrdinalIgnoreCase))
- {
- string responsiblePerson = soaRecordData.ResponsiblePerson;
- if (responsiblePerson.EndsWith(oldServerDomain))
- responsiblePerson = responsiblePerson.Replace(oldServerDomain, strServerDomain);
-
- _dnsServer.AuthoritativeZoneRoot.SetRecords(soaRecord.Name, soaRecord.Type, soaRecord.TtlValue, new DnsResourceRecordData[] { new DnsSOARecord(strServerDomain, responsiblePerson, soaRecordData.Serial, soaRecordData.Refresh, soaRecordData.Retry, soaRecordData.Expire, soaRecordData.Minimum) });
-
- //update NS records
- DnsResourceRecord[] nsResourceRecords = _dnsServer.AuthoritativeZoneRoot.GetAllRecords(zone.ZoneName, DnsResourceRecordType.NS, false, true);
-
- foreach (DnsResourceRecord nsResourceRecord in nsResourceRecords)
- {
- if ((nsResourceRecord.RDATA as DnsNSRecord).NSDomainName.Equals(oldServerDomain, StringComparison.OrdinalIgnoreCase))
- _dnsServer.AuthoritativeZoneRoot.UpdateRecord(nsResourceRecord, new DnsResourceRecord(nsResourceRecord.Name, nsResourceRecord.Type, nsResourceRecord.Class, nsResourceRecord.TtlValue, new DnsNSRecord(strServerDomain)));
- }
-
- try
- {
- SaveZoneFile(zone.ZoneName);
- }
- catch (Exception ex)
- {
- _log.Write(ex);
- }
- }
- }
- }
- }
-
- //allowed zone
- {
- ICollection zones = _dnsServer.AllowedZoneRoot.ListAuthoritativeZones();
-
- foreach (Zone.ZoneInfo zone in zones)
- {
- DnsResourceRecord[] soaResourceRecords = _dnsServer.AllowedZoneRoot.GetAllRecords(zone.ZoneName, DnsResourceRecordType.SOA, false, true);
- if (soaResourceRecords.Length > 0)
- {
- DnsResourceRecord soaRecord = soaResourceRecords[0];
- DnsSOARecord soaRecordData = soaRecord.RDATA as DnsSOARecord;
-
- _dnsServer.AllowedZoneRoot.SetRecords(soaRecord.Name, soaRecord.Type, soaRecord.TtlValue, new DnsResourceRecordData[] { new DnsSOARecord(strServerDomain, "hostmaster." + strServerDomain, soaRecordData.Serial, soaRecordData.Refresh, soaRecordData.Retry, soaRecordData.Expire, soaRecordData.Minimum) });
- }
- }
- }
-
- //custom blocked zone
- {
- ICollection zones = _customBlockedZoneRoot.ListAuthoritativeZones();
-
- foreach (Zone.ZoneInfo zone in zones)
- {
- DnsResourceRecord[] soaResourceRecords = _customBlockedZoneRoot.GetAllRecords(zone.ZoneName, DnsResourceRecordType.SOA, false, true);
- if (soaResourceRecords.Length > 0)
- {
- DnsResourceRecord soaRecord = soaResourceRecords[0];
- DnsSOARecord soaRecordData = soaRecord.RDATA as DnsSOARecord;
-
- _customBlockedZoneRoot.SetRecords(soaRecord.Name, soaRecord.Type, soaRecord.TtlValue, new DnsResourceRecordData[] { new DnsSOARecord(strServerDomain, "hostmaster." + strServerDomain, soaRecordData.Serial, soaRecordData.Refresh, soaRecordData.Retry, soaRecordData.Expire, soaRecordData.Minimum) });
- }
- }
- }
-
- //blocked zone
- {
- ICollection zones = _dnsServer.BlockedZoneRoot.ListAuthoritativeZones();
-
- foreach (Zone.ZoneInfo zone in zones)
- {
- DnsResourceRecord[] soaResourceRecords = _dnsServer.BlockedZoneRoot.GetAllRecords(zone.ZoneName, DnsResourceRecordType.SOA, false, true);
- if (soaResourceRecords.Length > 0)
- {
- DnsResourceRecord soaRecord = soaResourceRecords[0];
- DnsSOARecord soaRecordData = soaRecord.RDATA as DnsSOARecord;
-
- _dnsServer.BlockedZoneRoot.SetRecords(soaRecord.Name, soaRecord.Type, soaRecord.TtlValue, new DnsResourceRecordData[] { new DnsSOARecord(strServerDomain, "hostmaster." + strServerDomain, soaRecordData.Serial, soaRecordData.Refresh, soaRecordData.Retry, soaRecordData.Expire, soaRecordData.Minimum) });
- }
- }
- }
- }
- catch (Exception ex)
- {
- _log.Write(ex);
- }
- });
- }
- }
-
- string strDnsServerLocalAddresses = request.QueryString["dnsServerLocalAddresses"];
- if (strDnsServerLocalAddresses != null)
- {
- if (string.IsNullOrEmpty(strDnsServerLocalAddresses))
- strDnsServerLocalAddresses = "0.0.0.0,::";
-
- string[] strLocalAddresses = strDnsServerLocalAddresses.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- IPAddress[] localAddresses = new IPAddress[strLocalAddresses.Length];
-
- for (int i = 0; i < strLocalAddresses.Length; i++)
- localAddresses[i] = IPAddress.Parse(strLocalAddresses[i]);
-
- _dnsServer.LocalAddresses = localAddresses;
- }
-
- int oldWebServicePort = _webServicePort;
-
- string strWebServicePort = request.QueryString["webServicePort"];
- if (!string.IsNullOrEmpty(strWebServicePort))
- _webServicePort = int.Parse(strWebServicePort);
-
- string enableDnsOverHttp = request.QueryString["enableDnsOverHttp"];
- if (!string.IsNullOrEmpty(enableDnsOverHttp))
- _dnsServer.EnableDnsOverHttp = bool.Parse(enableDnsOverHttp);
-
- string strEnableDnsOverTls = request.QueryString["enableDnsOverTls"];
- if (!string.IsNullOrEmpty(strEnableDnsOverTls))
- _dnsServer.EnableDnsOverTls = bool.Parse(strEnableDnsOverTls);
-
- string strEnableDnsOverHttps = request.QueryString["enableDnsOverHttps"];
- if (!string.IsNullOrEmpty(strEnableDnsOverHttps))
- _dnsServer.EnableDnsOverHttps = bool.Parse(strEnableDnsOverHttps);
-
- string strTlsCertificatePath = request.QueryString["tlsCertificatePath"];
- string strTlsCertificatePassword = request.QueryString["tlsCertificatePassword"];
- if (string.IsNullOrEmpty(strTlsCertificatePath))
- {
- StopTlsCertificateUpdateTimer();
- _tlsCertificatePath = null;
- _tlsCertificatePassword = "";
- }
- else
- {
- if (strTlsCertificatePassword == "************")
- strTlsCertificatePassword = _tlsCertificatePassword;
-
- if ((strTlsCertificatePath != _tlsCertificatePath) || (strTlsCertificatePassword != _tlsCertificatePassword))
- {
- LoadTlsCertificate(strTlsCertificatePath, strTlsCertificatePassword);
-
- _tlsCertificatePath = strTlsCertificatePath;
- _tlsCertificatePassword = strTlsCertificatePassword;
-
- StartTlsCertificateUpdateTimer();
- }
- }
-
- string strPreferIPv6 = request.QueryString["preferIPv6"];
- if (!string.IsNullOrEmpty(strPreferIPv6))
- _dnsServer.PreferIPv6 = bool.Parse(strPreferIPv6);
-
- string strLogQueries = request.QueryString["logQueries"];
- if (!string.IsNullOrEmpty(strLogQueries))
- {
- if (bool.Parse(strLogQueries))
- _dnsServer.QueryLogManager = _log;
- else
- _dnsServer.QueryLogManager = null;
- }
-
- string strAllowRecursion = request.QueryString["allowRecursion"];
- if (!string.IsNullOrEmpty(strAllowRecursion))
- _dnsServer.AllowRecursion = bool.Parse(strAllowRecursion);
-
- string strAllowRecursionOnlyForPrivateNetworks = request.QueryString["allowRecursionOnlyForPrivateNetworks"];
- if (!string.IsNullOrEmpty(strAllowRecursionOnlyForPrivateNetworks))
- _dnsServer.AllowRecursionOnlyForPrivateNetworks = bool.Parse(strAllowRecursionOnlyForPrivateNetworks);
-
- string strCachePrefetchEligibility = request.QueryString["cachePrefetchEligibility"];
- if (!string.IsNullOrEmpty(strCachePrefetchEligibility))
- _dnsServer.CachePrefetchEligibility = int.Parse(strCachePrefetchEligibility);
-
- string strCachePrefetchTrigger = request.QueryString["cachePrefetchTrigger"];
- if (!string.IsNullOrEmpty(strCachePrefetchTrigger))
- _dnsServer.CachePrefetchTrigger = int.Parse(strCachePrefetchTrigger);
-
- string strCachePrefetchSampleIntervalInMinutes = request.QueryString["cachePrefetchSampleIntervalInMinutes"];
- if (!string.IsNullOrEmpty(strCachePrefetchSampleIntervalInMinutes))
- _dnsServer.CachePrefetchSampleIntervalInMinutes = int.Parse(strCachePrefetchSampleIntervalInMinutes);
-
- string strCachePrefetchSampleEligibilityHitsPerHour = request.QueryString["cachePrefetchSampleEligibilityHitsPerHour"];
- if (!string.IsNullOrEmpty(strCachePrefetchSampleEligibilityHitsPerHour))
- _dnsServer.CachePrefetchSampleEligibilityHitsPerHour = int.Parse(strCachePrefetchSampleEligibilityHitsPerHour);
-
- string strProxyType = request.QueryString["proxyType"];
- if (!string.IsNullOrEmpty(strProxyType))
- {
- NetProxyType proxyType = (NetProxyType)Enum.Parse(typeof(NetProxyType), strProxyType, true);
- if (proxyType == NetProxyType.None)
- {
- _dnsServer.Proxy = null;
- }
- else
- {
- NetworkCredential credential = null;
-
- string strUsername = request.QueryString["proxyUsername"];
- if (!string.IsNullOrEmpty(strUsername))
- credential = new NetworkCredential(strUsername, request.QueryString["proxyPassword"]);
-
- _dnsServer.Proxy = new NetProxy(proxyType, request.QueryString["proxyAddress"], int.Parse(request.QueryString["proxyPort"]), credential);
- }
- }
-
- string strForwarders = request.QueryString["forwarders"];
- if (!string.IsNullOrEmpty(strForwarders))
- {
- if (strForwarders == "false")
- {
- _dnsServer.Forwarders = null;
- }
- else
- {
- string[] strForwardersList = strForwarders.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- NameServerAddress[] forwarders = new NameServerAddress[strForwardersList.Length];
-
- for (int i = 0; i < strForwardersList.Length; i++)
- forwarders[i] = new NameServerAddress(strForwardersList[i]);
-
- _dnsServer.Forwarders = forwarders;
- }
- }
-
- string strForwarderProtocol = request.QueryString["forwarderProtocol"];
- if (!string.IsNullOrEmpty(strForwarderProtocol))
- _dnsServer.ForwarderProtocol = (DnsTransportProtocol)Enum.Parse(typeof(DnsTransportProtocol), strForwarderProtocol, true);
-
- string strBlockListUrls = request.QueryString["blockListUrls"];
- if (!string.IsNullOrEmpty(strBlockListUrls))
- {
- if (strBlockListUrls == "false")
- {
- StopBlockListUpdateTimer();
- FlushBlockedZone(request);
-
- _blockListUrls.Clear();
- }
- else
- {
- bool updated = false;
-
- string[] strBlockListUrlList = strBlockListUrls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
-
- if (oldWebServicePort != _webServicePort)
- {
- for (int i = 0; i < strBlockListUrlList.Length; i++)
- {
- if (strBlockListUrlList[i].Contains("http://localhost:" + oldWebServicePort + "/blocklist.txt"))
- {
- strBlockListUrlList[i] = "http://localhost:" + _webServicePort + "/blocklist.txt";
- updated = true;
- break;
- }
- }
- }
-
- if (!updated)
- {
- if (strBlockListUrlList.Length != _blockListUrls.Count)
- {
- updated = true;
- }
- else
- {
- foreach (string strBlockListUrl in strBlockListUrlList)
- {
- if (!_blockListUrls.Contains(new Uri(strBlockListUrl)))
- {
- updated = true;
- break;
- }
- }
- }
- }
-
- if (updated)
- {
- _blockListUrls.Clear();
-
- foreach (string strBlockListUrl in strBlockListUrlList)
- _blockListUrls.Add(new Uri(strBlockListUrl));
-
- _blockListLastUpdatedOn = new DateTime();
-
- StopBlockListUpdateTimer();
- StartBlockListUpdateTimer();
- }
- }
- }
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DNS Settings were updated {serverDomain: " + _dnsServer.ServerDomain + "; dnsServerLocalAddresses: " + strDnsServerLocalAddresses + "; webServicePort: " + _webServicePort + "; enableDnsOverHttp: " + _dnsServer.EnableDnsOverHttp + "; enableDnsOverTls: " + _dnsServer.EnableDnsOverTls + "; enableDnsOverHttps: " + _dnsServer.EnableDnsOverHttps + "; tlsCertificatePath: " + _tlsCertificatePath + "; preferIPv6: " + _dnsServer.PreferIPv6 + "; logQueries: " + (_dnsServer.QueryLogManager != null) + "; allowRecursion: " + _dnsServer.AllowRecursion + "; allowRecursionOnlyForPrivateNetworks: " + _dnsServer.AllowRecursionOnlyForPrivateNetworks + "; proxyType: " + strProxyType + "; forwarders: " + strForwarders + "; forwarderProtocol: " + strForwarderProtocol + "; blockListUrl: " + strBlockListUrls + ";}");
-
- SaveConfigFile();
-
- GetDnsSettings(jsonWriter);
- }
-
- private void GetStats(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string strType = request.QueryString["type"];
- if (string.IsNullOrEmpty(strType))
- strType = "lastHour";
-
- Dictionary>> data;
-
- switch (strType)
- {
- case "lastHour":
- data = _stats.GetLastHourStats();
- break;
-
- case "lastDay":
- data = _stats.GetLastDayStats();
- break;
-
- case "lastWeek":
- data = _stats.GetLastWeekStats();
- break;
-
- case "lastMonth":
- data = _stats.GetLastMonthStats();
- break;
-
- case "lastYear":
- data = _stats.GetLastYearStats();
- break;
-
- default:
- throw new DnsWebServiceException("Unknown stats type requested: " + strType);
- }
-
- //stats
- {
- List> stats = data["stats"];
-
- jsonWriter.WritePropertyName("stats");
- jsonWriter.WriteStartObject();
-
- foreach (KeyValuePair item in stats)
- {
- jsonWriter.WritePropertyName(item.Key);
- jsonWriter.WriteValue(item.Value);
- }
-
- jsonWriter.WritePropertyName("allowedZones");
- jsonWriter.WriteValue(_totalZonesAllowed);
-
- jsonWriter.WritePropertyName("blockedZones");
- jsonWriter.WriteValue(_totalZonesBlocked);
-
- jsonWriter.WriteEndObject();
- }
-
- //main chart
- {
- jsonWriter.WritePropertyName("mainChartData");
- jsonWriter.WriteStartObject();
-
- //label
- {
- List> statsPerInterval = data["totalQueriesPerInterval"];
-
- jsonWriter.WritePropertyName("labels");
- jsonWriter.WriteStartArray();
-
- foreach (KeyValuePair item in statsPerInterval)
- jsonWriter.WriteValue(item.Key);
-
- jsonWriter.WriteEndArray();
- }
-
- //datasets
- {
- jsonWriter.WritePropertyName("datasets");
- jsonWriter.WriteStartArray();
-
- WriteChartDataSet(jsonWriter, "Total Queries", "rgba(102, 153, 255, 0.1)", "rgb(102, 153, 255)", data["totalQueriesPerInterval"]);
- WriteChartDataSet(jsonWriter, "Cache Hit", "rgba(111, 84, 153, 0.1)", "rgb(111, 84, 153)", data["totalCacheHitPerInterval"]);
- WriteChartDataSet(jsonWriter, "No Error", "rgba(92, 184, 92, 0.1)", "rgb(92, 184, 92)", data["totalNoErrorPerInterval"]);
- WriteChartDataSet(jsonWriter, "Server Failure", "rgba(217, 83, 79, 0.1)", "rgb(217, 83, 79)", data["totalServerFailurePerInterval"]);
- WriteChartDataSet(jsonWriter, "Name Error", "rgba(7, 7, 7, 0.1)", "rgb(7, 7, 7)", data["totalNameErrorPerInterval"]);
- WriteChartDataSet(jsonWriter, "Refused", "rgba(91, 192, 222, 0.1)", "rgb(91, 192, 222)", data["totalRefusedPerInterval"]);
- WriteChartDataSet(jsonWriter, "Blocked", "rgba(255, 165, 0, 0.1)", "rgb(255, 165, 0)", data["totalBlockedPerInterval"]);
- WriteChartDataSet(jsonWriter, "Clients", "rgba(51, 122, 183, 0.1)", "rgb(51, 122, 183)", data["totalClientsPerInterval"]);
-
- jsonWriter.WriteEndArray();
- }
-
- jsonWriter.WriteEndObject();
- }
-
- //query type chart
- {
- jsonWriter.WritePropertyName("queryTypeChartData");
- jsonWriter.WriteStartObject();
-
- List> queryTypes = data["queryTypes"];
-
- //labels
- {
- jsonWriter.WritePropertyName("labels");
- jsonWriter.WriteStartArray();
-
- foreach (KeyValuePair item in queryTypes)
- jsonWriter.WriteValue(item.Key);
-
- jsonWriter.WriteEndArray();
- }
-
- //datasets
- {
- jsonWriter.WritePropertyName("datasets");
- jsonWriter.WriteStartArray();
-
- jsonWriter.WriteStartObject();
-
- jsonWriter.WritePropertyName("data");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair item in queryTypes)
- jsonWriter.WriteValue(item.Value);
- jsonWriter.WriteEndArray();
-
- jsonWriter.WritePropertyName("backgroundColor");
- jsonWriter.WriteStartArray();
- jsonWriter.WriteValue("rgba(102, 153, 255, 0.5)");
- jsonWriter.WriteValue("rgba(92, 184, 92, 0.5)");
- jsonWriter.WriteValue("rgba(91, 192, 222, 0.5)");
- jsonWriter.WriteValue("rgba(255, 165, 0, 0.5)");
- jsonWriter.WriteValue("rgba(51, 122, 183, 0.5)");
- jsonWriter.WriteEndArray();
-
- jsonWriter.WriteEndObject();
-
- jsonWriter.WriteEndArray();
- }
-
- jsonWriter.WriteEndObject();
- }
-
- //top clients
- {
- List> topClients = data["topClients"];
-
- jsonWriter.WritePropertyName("topClients");
- jsonWriter.WriteStartArray();
-
- foreach (KeyValuePair item in topClients)
- {
- jsonWriter.WriteStartObject();
-
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(item.Key);
-
- jsonWriter.WritePropertyName("hits");
- jsonWriter.WriteValue(item.Value);
-
- jsonWriter.WriteEndObject();
- }
-
- jsonWriter.WriteEndArray();
- }
-
- //top domains
- {
- List> topDomains = data["topDomains"];
-
- jsonWriter.WritePropertyName("topDomains");
- jsonWriter.WriteStartArray();
-
- foreach (KeyValuePair item in topDomains)
- {
- jsonWriter.WriteStartObject();
-
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(item.Key);
-
- jsonWriter.WritePropertyName("hits");
- jsonWriter.WriteValue(item.Value);
-
- jsonWriter.WriteEndObject();
- }
-
- jsonWriter.WriteEndArray();
- }
-
- //top blocked domains
- {
- List> topBlockedDomains = data["topBlockedDomains"];
-
- jsonWriter.WritePropertyName("topBlockedDomains");
- jsonWriter.WriteStartArray();
-
- foreach (KeyValuePair item in topBlockedDomains)
- {
- jsonWriter.WriteStartObject();
-
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(item.Key);
-
- jsonWriter.WritePropertyName("hits");
- jsonWriter.WriteValue(item.Value);
-
- jsonWriter.WriteEndObject();
- }
-
- jsonWriter.WriteEndArray();
- }
- }
-
- private void WriteChartDataSet(JsonTextWriter jsonWriter, string label, string backgroundColor, string borderColor, List> statsPerInterval)
- {
- jsonWriter.WriteStartObject();
-
- jsonWriter.WritePropertyName("label");
- jsonWriter.WriteValue(label);
-
- jsonWriter.WritePropertyName("backgroundColor");
- jsonWriter.WriteValue(backgroundColor);
-
- jsonWriter.WritePropertyName("borderColor");
- jsonWriter.WriteValue(borderColor);
-
- jsonWriter.WritePropertyName("borderWidth");
- jsonWriter.WriteValue(2);
-
- jsonWriter.WritePropertyName("fill");
- jsonWriter.WriteValue(true);
-
- jsonWriter.WritePropertyName("data");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair item in statsPerInterval)
- jsonWriter.WriteValue(item.Value);
- jsonWriter.WriteEndArray();
-
- jsonWriter.WriteEndObject();
- }
-
- private void FlushCache(HttpListenerRequest request)
- {
- _dnsServer.CacheZoneRoot.Flush();
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Cache was flushed.");
- }
-
- private void ListCachedZones(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string domain = request.QueryString["domain"];
- if (domain == null)
- domain = "";
-
- string direction = request.QueryString["direction"];
-
- string[] subZones;
- DnsResourceRecord[] records;
-
- while (true)
- {
- subZones = _dnsServer.CacheZoneRoot.ListSubZones(domain);
- records = _dnsServer.CacheZoneRoot.GetAllRecords(domain, DnsResourceRecordType.ANY, false);
-
- if (records.Length > 0)
- break;
-
- if (subZones.Length != 1)
- break;
-
- if (direction == "up")
- {
- if (domain == "")
- break;
-
- int i = domain.IndexOf('.');
- if (i < 0)
- domain = "";
- else
- domain = domain.Substring(i + 1);
- }
- else if (domain == "")
- {
- domain = subZones[0];
- }
- else
- {
- domain = subZones[0] + "." + domain;
- }
- }
-
- Array.Sort(subZones);
-
- jsonWriter.WritePropertyName("domain");
- jsonWriter.WriteValue(domain);
-
- jsonWriter.WritePropertyName("zones");
- jsonWriter.WriteStartArray();
-
- if (domain != "")
- domain = "." + domain;
-
- foreach (string subZone in subZones)
- jsonWriter.WriteValue(subZone + domain);
-
- jsonWriter.WriteEndArray();
-
- WriteRecordsAsJson(records, jsonWriter, false);
- }
-
- private void DeleteCachedZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- _dnsServer.CacheZoneRoot.DeleteZone(domain, true);
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Cached zone was deleted: " + domain);
- }
-
- private void ListAllowedZones(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string domain = request.QueryString["domain"];
- if (domain == null)
- domain = "";
-
- string direction = request.QueryString["direction"];
-
- string[] subZones;
- DnsResourceRecord[] records;
-
- while (true)
- {
- subZones = _dnsServer.AllowedZoneRoot.ListSubZones(domain);
- records = _dnsServer.AllowedZoneRoot.GetAllRecords(domain, DnsResourceRecordType.ANY, false);
-
- if (records.Length > 0)
- break;
-
- if (subZones.Length != 1)
- break;
-
- if (direction == "up")
- {
- if (domain == "")
- break;
-
- int i = domain.IndexOf('.');
- if (i < 0)
- domain = "";
- else
- domain = domain.Substring(i + 1);
- }
- else if (domain == "")
- {
- domain = subZones[0];
- }
- else
- {
- domain = subZones[0] + "." + domain;
- }
- }
-
- Array.Sort(subZones);
-
- jsonWriter.WritePropertyName("domain");
- jsonWriter.WriteValue(domain);
-
- jsonWriter.WritePropertyName("zones");
- jsonWriter.WriteStartArray();
-
- if (domain != "")
- domain = "." + domain;
-
- foreach (string subZone in subZones)
- jsonWriter.WriteValue(subZone + domain);
-
- jsonWriter.WriteEndArray();
-
- WriteRecordsAsJson(records, jsonWriter, false);
- }
-
- private void ImportAllowedZones(HttpListenerRequest request)
- {
- if (!request.ContentType.StartsWith("application/x-www-form-urlencoded"))
- throw new DnsWebServiceException("Invalid content type. Expected application/x-www-form-urlencoded.");
-
- string formRequest;
- using (StreamReader sR = new StreamReader(request.InputStream, request.ContentEncoding))
- {
- formRequest = sR.ReadToEnd();
- }
-
- string[] formParts = formRequest.Split('&');
-
- foreach (string formPart in formParts)
- {
- if (formPart.StartsWith("allowedZones="))
- {
- string[] allowedZones = formPart.Substring(13).Split(',');
-
- foreach (string allowedZone in allowedZones)
- AllowZone(allowedZone);
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Total " + allowedZones.Length + " zones were imported into allowed zone successfully.");
- SaveAllowedZoneFile();
- return;
- }
- }
-
- throw new DnsWebServiceException("Parameter 'allowedZones' missing.");
- }
-
- private void ExportAllowedZones(HttpListenerResponse response)
- {
- ICollection zoneInfoList = _dnsServer.AllowedZoneRoot.ListAuthoritativeZones();
-
- response.ContentType = "text/plain";
- response.AddHeader("Content-Disposition", "attachment;filename=AllowedZones.txt");
-
- using (StreamWriter sW = new StreamWriter(new BufferedStream(response.OutputStream)))
- {
- foreach (Zone.ZoneInfo zoneInfo in zoneInfoList)
- sW.WriteLine(zoneInfo.ZoneName);
- }
- }
-
- private void FlushAllowedZone(HttpListenerRequest request)
- {
- _dnsServer.AllowedZoneRoot.Flush();
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Allowed zone was flushed.");
-
- SaveAllowedZoneFile();
- }
-
- private void DeleteAllowedZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- _dnsServer.AllowedZoneRoot.DeleteZone(domain, false);
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Allowed zone was deleted: " + domain);
-
- SaveAllowedZoneFile();
- }
-
- private void AllowZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- if (IPAddress.TryParse(domain, out IPAddress ipAddress))
- domain = (new DnsQuestionRecord(ipAddress, DnsClass.IN)).Name;
-
- AllowZone(domain);
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Zone was allowed: " + domain);
- SaveAllowedZoneFile();
- }
-
- private void AllowZone(string domain)
- {
- _dnsServer.AllowedZoneRoot.SetRecords(domain, DnsResourceRecordType.SOA, 60, new DnsResourceRecordData[] { new DnsSOARecord(_dnsServer.ServerDomain, "hostmaster." + _dnsServer.ServerDomain, 1, 28800, 7200, 604800, 600) });
- }
-
- private void ListBlockedZones(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string domain = request.QueryString["domain"];
- if (domain == null)
- domain = "";
-
- string direction = request.QueryString["direction"];
-
- string[] subZones;
- DnsResourceRecord[] records;
-
- while (true)
- {
- subZones = _dnsServer.BlockedZoneRoot.ListSubZones(domain);
- records = _dnsServer.BlockedZoneRoot.GetAllRecords(domain, DnsResourceRecordType.ANY, false);
-
- if (records.Length > 0)
- break;
-
- if (subZones.Length != 1)
- break;
-
- if (direction == "up")
- {
- if (domain == "")
- break;
-
- int i = domain.IndexOf('.');
- if (i < 0)
- domain = "";
- else
- domain = domain.Substring(i + 1);
- }
- else if (domain == "")
- {
- domain = subZones[0];
- }
- else
- {
- domain = subZones[0] + "." + domain;
- }
- }
-
- Array.Sort(subZones);
-
- jsonWriter.WritePropertyName("domain");
- jsonWriter.WriteValue(domain);
-
- jsonWriter.WritePropertyName("zones");
- jsonWriter.WriteStartArray();
-
- if (domain != "")
- domain = "." + domain;
-
- foreach (string subZone in subZones)
- jsonWriter.WriteValue(subZone + domain);
-
- jsonWriter.WriteEndArray();
-
- WriteRecordsAsJson(records, jsonWriter, false);
- }
-
- private void ImportCustomBlockedZones(HttpListenerRequest request)
- {
- if (!request.ContentType.StartsWith("application/x-www-form-urlencoded"))
- throw new DnsWebServiceException("Invalid content type. Expected application/x-www-form-urlencoded.");
-
- string formRequest;
- using (StreamReader sR = new StreamReader(request.InputStream, request.ContentEncoding))
- {
- formRequest = sR.ReadToEnd();
- }
-
- string[] formParts = formRequest.Split('&');
-
- foreach (string formPart in formParts)
- {
- if (formPart.StartsWith("blockedZones="))
- {
- string[] blockedZones = formPart.Substring(13).Split(',');
-
- foreach (string blockedZone in blockedZones)
- {
- BlockZone(blockedZone, _customBlockedZoneRoot, "custom");
- BlockZone(blockedZone, _dnsServer.BlockedZoneRoot, "custom");
- }
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Total " + blockedZones.Length + " zones were imported into custom blocked zone successfully.");
- SaveCustomBlockedZoneFile();
- return;
- }
- }
-
- throw new DnsWebServiceException("Parameter 'blockedZones' missing.");
- }
-
- private void ExportCustomBlockedZones(HttpListenerResponse response)
- {
- ICollection zoneInfoList = _customBlockedZoneRoot.ListAuthoritativeZones();
-
- response.ContentType = "text/plain";
- response.AddHeader("Content-Disposition", "attachment;filename=CustomBlockedZones.txt");
-
- using (StreamWriter sW = new StreamWriter(new BufferedStream(response.OutputStream)))
- {
- foreach (Zone.ZoneInfo zoneInfo in zoneInfoList)
- sW.WriteLine(zoneInfo.ZoneName);
- }
- }
-
- private void FlushCustomBlockedZone(HttpListenerRequest request)
- {
- //delete custom blocked zones from dns blocked zone
- foreach (Zone.ZoneInfo zone in _customBlockedZoneRoot.ListAuthoritativeZones())
- _dnsServer.BlockedZoneRoot.DeleteZone(zone.ZoneName, false);
-
- _customBlockedZoneRoot.Flush();
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Custom blocked zone was flushed.");
-
- SaveCustomBlockedZoneFile();
- _totalZonesBlocked = _dnsServer.BlockedZoneRoot.ListAuthoritativeZones().Count;
- }
-
- private void FlushBlockedZone(HttpListenerRequest request)
- {
- _dnsServer.BlockedZoneRoot.Flush();
-
- //load custom blocked zone into dns block zone
- foreach (Zone.ZoneInfo zone in _customBlockedZoneRoot.ListAuthoritativeZones())
- BlockZone(zone.ZoneName, _dnsServer.BlockedZoneRoot, "custom");
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Blocked zone was flushed.");
- _totalZonesBlocked = _dnsServer.BlockedZoneRoot.ListAuthoritativeZones().Count;
- }
-
- private void DeleteCustomBlockedZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- bool customZoneDeleted = _customBlockedZoneRoot.DeleteZone(domain, false);
- if (!customZoneDeleted)
- throw new DnsWebServiceException("Domain '" + domain + "' was not found in custom blocked zone. Try adding the domain into allowed zone instead to unblock it.");
-
- _dnsServer.BlockedZoneRoot.DeleteZone(domain, false);
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Custom blocked zone was deleted: " + domain);
-
- SaveCustomBlockedZoneFile();
- _totalZonesBlocked--;
- }
-
- private void CustomBlockZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- if (IPAddress.TryParse(domain, out IPAddress ipAddress))
- domain = (new DnsQuestionRecord(ipAddress, DnsClass.IN)).Name;
-
- BlockZone(domain, _customBlockedZoneRoot, "custom");
- BlockZone(domain, _dnsServer.BlockedZoneRoot, "custom");
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Domain was added to custom block zone: " + domain);
-
- SaveCustomBlockedZoneFile();
- _totalZonesBlocked++;
- }
-
- private void BlockZone(string domain, Zone blockedZoneRoot, string blockListUrl)
- {
- blockedZoneRoot.SetRecords(new DnsResourceRecord[]
- {
- new DnsResourceRecord(domain, DnsResourceRecordType.SOA, DnsClass.IN, 60, new DnsSOARecord(_dnsServer.ServerDomain, "hostmaster." + _dnsServer.ServerDomain, 1, 28800, 7200, 604800, 600)),
- new DnsResourceRecord(domain, DnsResourceRecordType.A, DnsClass.IN, 60, new DnsARecord(IPAddress.Any)),
- new DnsResourceRecord(domain, DnsResourceRecordType.AAAA, DnsClass.IN, 60, new DnsAAAARecord(IPAddress.IPv6Any))
- });
-
- blockedZoneRoot.AddRecord(domain, DnsResourceRecordType.TXT, 60, new DnsTXTRecord("blockList=" + blockListUrl));
- }
-
- private void ListZones(JsonTextWriter jsonWriter)
- {
- ICollection zoneList = _dnsServer.AuthoritativeZoneRoot.ListAuthoritativeZones();
-
- Zone.ZoneInfo[] zones = new Zone.ZoneInfo[zoneList.Count];
- zoneList.CopyTo(zones, 0);
-
- Array.Sort(zones);
-
- jsonWriter.WritePropertyName("zones");
- jsonWriter.WriteStartArray();
-
- foreach (Zone.ZoneInfo zone in zones)
- {
- jsonWriter.WriteStartObject();
-
- jsonWriter.WritePropertyName("zoneName");
- jsonWriter.WriteValue(zone.ZoneName);
-
- jsonWriter.WritePropertyName("disabled");
- jsonWriter.WriteValue(zone.Disabled);
-
- jsonWriter.WriteEndObject();
- }
-
- jsonWriter.WriteEndArray();
- }
-
- private void CreateZone(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- if (domain.Contains("*"))
- throw new DnsWebServiceException("Domain name for a zone cannot contain wildcard character.");
-
- if (IPAddress.TryParse(domain, out IPAddress ipAddress))
- domain = (new DnsQuestionRecord(ipAddress, DnsClass.IN)).Name.ToLower();
- else if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
-
- if (Zone.DomainEquals(domain, "resolver-associated-doh.arpa") || Zone.DomainEquals(domain, "resolver-addresses.arpa"))
- throw new DnsWebServiceException("Access was denied to manage special DNS Server zones.");
-
- CreateZone(domain);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Authoritative zone was created: " + domain);
-
- SaveZoneFile(domain);
-
- jsonWriter.WritePropertyName("domain");
- jsonWriter.WriteValue(domain);
- }
-
- private void CreateZone(string domain)
- {
- _dnsServer.AuthoritativeZoneRoot.SetRecords(domain, DnsResourceRecordType.SOA, 14400, new DnsResourceRecordData[] { new DnsSOARecord(_dnsServer.ServerDomain, "hostmaster." + _dnsServer.ServerDomain, uint.Parse(DateTime.UtcNow.ToString("yyyyMMddHH")), 28800, 7200, 604800, 600) });
- _dnsServer.AuthoritativeZoneRoot.SetRecords(domain, DnsResourceRecordType.NS, 14400, new DnsResourceRecordData[] { new DnsNSRecord(_dnsServer.ServerDomain) });
- }
-
- private void DeleteZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
-
- if (Zone.DomainEquals(domain, "resolver-associated-doh.arpa") || Zone.DomainEquals(domain, "resolver-addresses.arpa"))
- throw new DnsWebServiceException("Access was denied to manage special DNS Server zones.");
-
- if (!_dnsServer.AuthoritativeZoneRoot.DeleteZone(domain, false))
- throw new DnsWebServiceException("Zone '" + domain + "' was not found.");
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Authoritative zone was deleted: " + domain);
-
- DeleteZoneFile(domain);
- }
-
- private void EnableZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
-
- if (Zone.DomainEquals(domain, "resolver-associated-doh.arpa") || Zone.DomainEquals(domain, "resolver-addresses.arpa"))
- throw new DnsWebServiceException("Access was denied to manage special DNS Server zones.");
-
- _dnsServer.AuthoritativeZoneRoot.EnableZone(domain);
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Authoritative zone was enabled: " + domain);
-
- SaveZoneFile(domain);
- }
-
- private void DisableZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
-
- if (Zone.DomainEquals(domain, "resolver-associated-doh.arpa") || Zone.DomainEquals(domain, "resolver-addresses.arpa"))
- throw new DnsWebServiceException("Access was denied to manage special DNS Server zones.");
-
- _dnsServer.AuthoritativeZoneRoot.DisableZone(domain);
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Authoritative zone was disabled: " + domain);
-
- SaveZoneFile(domain);
- }
-
- private void AddRecord(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
-
- if (Zone.DomainEquals(domain, "resolver-associated-doh.arpa") || Zone.DomainEquals(domain, "resolver-addresses.arpa"))
- throw new DnsWebServiceException("Access was denied to manage special DNS Server zones.");
-
- string strType = request.QueryString["type"];
- if (string.IsNullOrEmpty(strType))
- throw new DnsWebServiceException("Parameter 'type' missing.");
-
- DnsResourceRecordType type = (DnsResourceRecordType)Enum.Parse(typeof(DnsResourceRecordType), strType);
-
- string value = request.QueryString["value"];
- if (string.IsNullOrEmpty(value))
- throw new DnsWebServiceException("Parameter 'value' missing.");
-
- uint ttl;
- string strTtl = request.QueryString["ttl"];
- if (string.IsNullOrEmpty(strTtl))
- ttl = 3600;
- else
- ttl = uint.Parse(strTtl);
-
- switch (type)
- {
- case DnsResourceRecordType.A:
- _dnsServer.AuthoritativeZoneRoot.AddRecord(domain, type, ttl, new DnsARecord(IPAddress.Parse(value)));
- break;
-
- case DnsResourceRecordType.AAAA:
- _dnsServer.AuthoritativeZoneRoot.AddRecord(domain, type, ttl, new DnsAAAARecord(IPAddress.Parse(value)));
- break;
-
- case DnsResourceRecordType.MX:
- {
- string preference = request.QueryString["preference"];
- if (string.IsNullOrEmpty(preference))
- throw new DnsWebServiceException("Parameter 'preference' missing.");
-
- _dnsServer.AuthoritativeZoneRoot.AddRecord(domain, type, ttl, new DnsMXRecord(ushort.Parse(preference), value));
- }
- break;
-
- case DnsResourceRecordType.TXT:
- _dnsServer.AuthoritativeZoneRoot.AddRecord(domain, type, ttl, new DnsTXTRecord(value));
- break;
-
- case DnsResourceRecordType.NS:
- _dnsServer.AuthoritativeZoneRoot.AddRecord(domain, type, ttl, new DnsNSRecord(value));
- break;
-
- case DnsResourceRecordType.PTR:
- _dnsServer.AuthoritativeZoneRoot.SetRecords(domain, type, ttl, new DnsResourceRecordData[] { new DnsPTRRecord(value) });
- break;
-
- case DnsResourceRecordType.CNAME:
- _dnsServer.AuthoritativeZoneRoot.SetRecords(domain, type, ttl, new DnsResourceRecordData[] { new DnsCNAMERecord(value) });
- break;
-
- case DnsResourceRecordType.SRV:
- {
- string priority = request.QueryString["priority"];
- if (string.IsNullOrEmpty(priority))
- throw new DnsWebServiceException("Parameter 'priority' missing.");
-
- string weight = request.QueryString["weight"];
- if (string.IsNullOrEmpty(weight))
- throw new DnsWebServiceException("Parameter 'weight' missing.");
-
- string port = request.QueryString["port"];
- if (string.IsNullOrEmpty(port))
- throw new DnsWebServiceException("Parameter 'port' missing.");
-
- _dnsServer.AuthoritativeZoneRoot.AddRecord(domain, type, ttl, new DnsSRVRecord(ushort.Parse(priority), ushort.Parse(weight), ushort.Parse(port), value));
- }
- break;
-
- default:
- throw new DnsWebServiceException("Type not supported for AddRecords().");
- }
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] New record was added to authoritative zone {domain: " + domain + "; type: " + type + "; value: " + value + "; ttl: " + ttl + ";}");
-
- SaveZoneFile(domain);
- }
-
- private void GetRecords(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
-
- DnsResourceRecord[] records = _dnsServer.AuthoritativeZoneRoot.GetAllRecords(domain);
- if (records.Length == 0)
- throw new DnsWebServiceException("Zone '" + domain + "' was not found.");
-
- WriteRecordsAsJson(records, jsonWriter, true);
- }
-
- private void WriteRecordsAsJson(DnsResourceRecord[] records, JsonTextWriter jsonWriter, bool authoritativeZoneRecords)
- {
- if (records == null)
- {
- jsonWriter.WritePropertyName("records");
- jsonWriter.WriteStartArray();
- jsonWriter.WriteEndArray();
-
- return;
- }
-
- Array.Sort(records);
-
- Dictionary>> groupedByDomainRecords = DnsResourceRecord.GroupRecords(records);
-
- jsonWriter.WritePropertyName("records");
- jsonWriter.WriteStartArray();
-
- foreach (KeyValuePair>> groupedByTypeRecords in groupedByDomainRecords)
- {
- foreach (KeyValuePair> groupedRecords in groupedByTypeRecords.Value)
- {
- foreach (DnsResourceRecord resourceRecord in groupedRecords.Value)
- {
- jsonWriter.WriteStartObject();
-
- if (authoritativeZoneRecords)
- {
- Zone.DnsResourceRecordInfo rrInfo = resourceRecord.Tag as Zone.DnsResourceRecordInfo;
- jsonWriter.WritePropertyName("disabled");
- jsonWriter.WriteValue((rrInfo != null) && rrInfo.Disabled);
- }
-
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(resourceRecord.Name);
-
- jsonWriter.WritePropertyName("type");
- jsonWriter.WriteValue(resourceRecord.Type.ToString());
-
- jsonWriter.WritePropertyName("ttl");
- if (authoritativeZoneRecords)
- jsonWriter.WriteValue(resourceRecord.TtlValue);
- else
- jsonWriter.WriteValue(resourceRecord.TTL);
-
- jsonWriter.WritePropertyName("rData");
- jsonWriter.WriteStartObject();
-
- switch (resourceRecord.Type)
- {
- case DnsResourceRecordType.A:
- {
- DnsARecord rdata = (resourceRecord.RDATA as DnsARecord);
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.IPAddress);
- }
- }
- break;
-
- case DnsResourceRecordType.AAAA:
- {
- DnsAAAARecord rdata = (resourceRecord.RDATA as DnsAAAARecord);
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.IPAddress);
- }
- }
- break;
-
- case DnsResourceRecordType.SOA:
- {
- DnsSOARecord rdata = resourceRecord.RDATA as DnsSOARecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("masterNameServer");
- jsonWriter.WriteValue(rdata.MasterNameServer);
-
- jsonWriter.WritePropertyName("responsiblePerson");
- jsonWriter.WriteValue(rdata.ResponsiblePerson);
-
- jsonWriter.WritePropertyName("serial");
- jsonWriter.WriteValue(rdata.Serial);
-
- jsonWriter.WritePropertyName("refresh");
- jsonWriter.WriteValue(rdata.Refresh);
-
- jsonWriter.WritePropertyName("retry");
- jsonWriter.WriteValue(rdata.Retry);
-
- jsonWriter.WritePropertyName("expire");
- jsonWriter.WriteValue(rdata.Expire);
-
- jsonWriter.WritePropertyName("minimum");
- jsonWriter.WriteValue(rdata.Minimum);
- }
- }
- break;
-
- case DnsResourceRecordType.PTR:
- {
- DnsPTRRecord rdata = resourceRecord.RDATA as DnsPTRRecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.PTRDomainName);
- }
- }
- break;
-
- case DnsResourceRecordType.MX:
- {
- DnsMXRecord rdata = resourceRecord.RDATA as DnsMXRecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("preference");
- jsonWriter.WriteValue(rdata.Preference);
-
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.Exchange);
- }
- }
- break;
-
- case DnsResourceRecordType.TXT:
- {
- DnsTXTRecord rdata = resourceRecord.RDATA as DnsTXTRecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.TXTData);
- }
- }
- break;
-
- case DnsResourceRecordType.NS:
- {
- DnsNSRecord rdata = resourceRecord.RDATA as DnsNSRecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.NSDomainName);
- }
- }
- break;
-
- case DnsResourceRecordType.CNAME:
- {
- DnsCNAMERecord rdata = resourceRecord.RDATA as DnsCNAMERecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.CNAMEDomainName);
- }
- }
- break;
-
- case DnsResourceRecordType.SRV:
- {
- DnsSRVRecord rdata = resourceRecord.RDATA as DnsSRVRecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("priority");
- jsonWriter.WriteValue(rdata.Priority);
-
- jsonWriter.WritePropertyName("weight");
- jsonWriter.WriteValue(rdata.Weight);
-
- jsonWriter.WritePropertyName("port");
- jsonWriter.WriteValue(rdata.Port);
-
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.Target);
- }
- }
- break;
-
- default:
- {
- jsonWriter.WritePropertyName("value");
-
- using (MemoryStream mS = new MemoryStream())
- {
- resourceRecord.RDATA.WriteTo(mS, new List());
-
- jsonWriter.WriteValue(Convert.ToBase64String(mS.ToArray()));
- }
- }
- break;
- }
-
- jsonWriter.WriteEndObject();
-
- jsonWriter.WriteEndObject();
- }
- }
- }
-
- jsonWriter.WriteEndArray();
- }
-
- private void DeleteRecord(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
-
- if (Zone.DomainEquals(domain, "resolver-associated-doh.arpa") || Zone.DomainEquals(domain, "resolver-addresses.arpa"))
- throw new DnsWebServiceException("Access was denied to manage special DNS Server zones.");
-
- string strType = request.QueryString["type"];
- if (string.IsNullOrEmpty(strType))
- throw new DnsWebServiceException("Parameter 'type' missing.");
-
- DnsResourceRecordType type = (DnsResourceRecordType)Enum.Parse(typeof(DnsResourceRecordType), strType);
-
- string value = request.QueryString["value"];
- if (string.IsNullOrEmpty(value))
- throw new DnsWebServiceException("Parameter 'value' missing.");
-
- if (!_dnsServer.AuthoritativeZoneRoot.ZoneExists(domain))
- throw new DnsWebServiceException("Zone '" + domain + "' was not found.");
-
- switch (type)
- {
- case DnsResourceRecordType.A:
- _dnsServer.AuthoritativeZoneRoot.DeleteRecord(domain, type, new DnsARecord(IPAddress.Parse(value)));
- break;
-
- case DnsResourceRecordType.AAAA:
- _dnsServer.AuthoritativeZoneRoot.DeleteRecord(domain, type, new DnsAAAARecord(IPAddress.Parse(value)));
- break;
-
- case DnsResourceRecordType.MX:
- _dnsServer.AuthoritativeZoneRoot.DeleteRecord(domain, type, new DnsMXRecord(0, value));
- break;
-
- case DnsResourceRecordType.TXT:
- _dnsServer.AuthoritativeZoneRoot.DeleteRecord(domain, type, new DnsTXTRecord(value));
- break;
-
- case DnsResourceRecordType.NS:
- _dnsServer.AuthoritativeZoneRoot.DeleteRecord(domain, type, new DnsNSRecord(value));
- break;
-
- case DnsResourceRecordType.CNAME:
- case DnsResourceRecordType.PTR:
- _dnsServer.AuthoritativeZoneRoot.DeleteRecords(domain, type);
- break;
-
- case DnsResourceRecordType.SRV:
- {
- string port = request.QueryString["port"];
- if (string.IsNullOrEmpty(port))
- throw new DnsWebServiceException("Parameter 'port' missing.");
-
- _dnsServer.AuthoritativeZoneRoot.DeleteRecord(domain, type, new DnsSRVRecord(0, 0, ushort.Parse(port), value));
- }
- break;
-
- default:
- throw new DnsWebServiceException("Type not supported for DeleteRecord().");
- }
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Record was deleted from authoritative zone {domain: " + domain + "; type: " + type + "; value: " + value + ";}");
-
- SaveZoneFile(domain);
- }
-
- private void UpdateRecord(HttpListenerRequest request)
- {
- string strType = request.QueryString["type"];
- if (string.IsNullOrEmpty(strType))
- throw new DnsWebServiceException("Parameter 'type' missing.");
-
- DnsResourceRecordType type = (DnsResourceRecordType)Enum.Parse(typeof(DnsResourceRecordType), strType);
-
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
-
- if (Zone.DomainEquals(domain, "resolver-associated-doh.arpa") || Zone.DomainEquals(domain, "resolver-addresses.arpa"))
- throw new DnsWebServiceException("Access was denied to manage special DNS Server zones.");
-
- string oldDomain = request.QueryString["oldDomain"];
- if (string.IsNullOrEmpty(oldDomain))
- oldDomain = domain;
-
- if (oldDomain.EndsWith("."))
- oldDomain = oldDomain.Substring(0, oldDomain.Length - 1);
-
- string value = request.QueryString["value"];
- string oldValue = request.QueryString["oldValue"];
-
- uint ttl;
- string strTtl = request.QueryString["ttl"];
- if (string.IsNullOrEmpty(strTtl))
- ttl = 3600;
- else
- ttl = uint.Parse(strTtl);
-
- bool disable = false;
- string strDisable = request.QueryString["disable"];
- if (!string.IsNullOrEmpty(strDisable))
- disable = bool.Parse(strDisable);
-
- switch (type)
- {
- case DnsResourceRecordType.A:
- _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsARecord(IPAddress.Parse(oldValue))), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsARecord(IPAddress.Parse(value))) { Tag = new Zone.DnsResourceRecordInfo(disable) });
- break;
-
- case DnsResourceRecordType.AAAA:
- _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsAAAARecord(IPAddress.Parse(oldValue))), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsAAAARecord(IPAddress.Parse(value))) { Tag = new Zone.DnsResourceRecordInfo(disable) });
- break;
-
- case DnsResourceRecordType.MX:
- string preference = request.QueryString["preference"];
- if (string.IsNullOrEmpty(preference))
- throw new DnsWebServiceException("Parameter 'preference' missing.");
-
- _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsMXRecord(0, oldValue)), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsMXRecord(ushort.Parse(preference), value)) { Tag = new Zone.DnsResourceRecordInfo(disable) });
- break;
-
- case DnsResourceRecordType.TXT:
- _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsTXTRecord(oldValue)), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsTXTRecord(value)) { Tag = new Zone.DnsResourceRecordInfo(disable) });
- break;
-
- case DnsResourceRecordType.NS:
- _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsNSRecord(oldValue)), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsNSRecord(value)) { Tag = new Zone.DnsResourceRecordInfo(disable) });
- break;
-
- case DnsResourceRecordType.SOA:
- {
- string masterNameServer = request.QueryString["masterNameServer"];
- if (string.IsNullOrEmpty(masterNameServer))
- throw new DnsWebServiceException("Parameter 'masterNameServer' missing.");
-
- string responsiblePerson = request.QueryString["responsiblePerson"];
- if (string.IsNullOrEmpty(responsiblePerson))
- throw new DnsWebServiceException("Parameter 'responsiblePerson' missing.");
-
- string serial = request.QueryString["serial"];
- if (string.IsNullOrEmpty(serial))
- throw new DnsWebServiceException("Parameter 'serial' missing.");
-
- string refresh = request.QueryString["refresh"];
- if (string.IsNullOrEmpty(refresh))
- throw new DnsWebServiceException("Parameter 'refresh' missing.");
-
- string retry = request.QueryString["retry"];
- if (string.IsNullOrEmpty(retry))
- throw new DnsWebServiceException("Parameter 'retry' missing.");
-
- string expire = request.QueryString["expire"];
- if (string.IsNullOrEmpty(expire))
- throw new DnsWebServiceException("Parameter 'expire' missing.");
-
- string minimum = request.QueryString["minimum"];
- if (string.IsNullOrEmpty(minimum))
- throw new DnsWebServiceException("Parameter 'minimum' missing.");
-
- _dnsServer.AuthoritativeZoneRoot.SetRecords(domain, type, ttl, new DnsResourceRecordData[] { new DnsSOARecord(masterNameServer, responsiblePerson, uint.Parse(serial), uint.Parse(refresh), uint.Parse(retry), uint.Parse(expire), uint.Parse(minimum)) });
- }
- break;
-
- case DnsResourceRecordType.PTR:
- _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsPTRRecord(oldValue)), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsPTRRecord(value)) { Tag = new Zone.DnsResourceRecordInfo(disable) });
- break;
-
- case DnsResourceRecordType.CNAME:
- _dnsServer.AuthoritativeZoneRoot.UpdateRecord(new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsCNAMERecord(oldValue)), new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsCNAMERecord(value)) { Tag = new Zone.DnsResourceRecordInfo(disable) });
- break;
-
- case DnsResourceRecordType.SRV:
- {
- string oldPort = request.QueryString["oldPort"];
- if (string.IsNullOrEmpty(oldPort))
- throw new DnsWebServiceException("Parameter 'oldPort' missing.");
-
- string priority = request.QueryString["priority"];
- if (string.IsNullOrEmpty(priority))
- throw new DnsWebServiceException("Parameter 'priority' missing.");
-
- string weight = request.QueryString["weight"];
- if (string.IsNullOrEmpty(weight))
- throw new DnsWebServiceException("Parameter 'weight' missing.");
-
- string port = request.QueryString["port"];
- if (string.IsNullOrEmpty(port))
- throw new DnsWebServiceException("Parameter 'port' missing.");
-
- DnsResourceRecord oldRecord = new DnsResourceRecord(oldDomain, type, DnsClass.IN, 0, new DnsSRVRecord(0, 0, ushort.Parse(oldPort), oldValue));
- DnsResourceRecord newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSRVRecord(ushort.Parse(priority), ushort.Parse(weight), ushort.Parse(port), value)) { Tag = new Zone.DnsResourceRecordInfo(disable) };
-
- _dnsServer.AuthoritativeZoneRoot.UpdateRecord(oldRecord, newRecord);
- }
- break;
-
- default:
- throw new DnsWebServiceException("Type not supported for UpdateRecords().");
- }
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Record was updated for authoritative zone {oldDomain: " + oldDomain + "; domain: " + domain + "; type: " + type + "; oldValue: " + oldValue + "; value: " + value + "; ttl: " + ttl + "; disabled: " + disable + ";}");
-
- SaveZoneFile(domain);
- }
-
- private void ResolveQuery(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string server = request.QueryString["server"];
- if (string.IsNullOrEmpty(server))
- throw new DnsWebServiceException("Parameter 'server' missing.");
-
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new DnsWebServiceException("Parameter 'domain' missing.");
-
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
-
- string strType = request.QueryString["type"];
- if (string.IsNullOrEmpty(strType))
- throw new DnsWebServiceException("Parameter 'type' missing.");
-
- DnsResourceRecordType type = (DnsResourceRecordType)Enum.Parse(typeof(DnsResourceRecordType), strType);
-
- string strProtocol = request.QueryString["protocol"];
- if (string.IsNullOrEmpty(strProtocol))
- strProtocol = "Udp";
-
- bool importRecords = false;
- string strImport = request.QueryString["import"];
- if (!string.IsNullOrEmpty(strImport))
- importRecords = bool.Parse(strImport);
-
- NetProxy proxy = _dnsServer.Proxy;
- bool preferIPv6 = _dnsServer.PreferIPv6;
- DnsTransportProtocol protocol = (DnsTransportProtocol)Enum.Parse(typeof(DnsTransportProtocol), strProtocol, true);
- const int RETRIES = 1;
- const int TIMEOUT = 10000;
-
- DnsDatagram dnsResponse;
-
- if (server == "recursive-resolver")
- {
- DnsQuestionRecord question;
-
- if (type == DnsResourceRecordType.PTR)
- question = new DnsQuestionRecord(IPAddress.Parse(domain), DnsClass.IN);
- else
- question = new DnsQuestionRecord(domain, type, DnsClass.IN);
-
- dnsResponse = DnsClient.RecursiveResolve(question, null, null, proxy, preferIPv6, RETRIES, TIMEOUT);
- }
- else
- {
- NameServerAddress nameServer;
-
- if (server == "this-server")
- {
- nameServer = new NameServerAddress(_dnsServer.ServerDomain, IPAddress.Parse("127.0.0.1"));
- proxy = null; //no proxy required for this server
- }
- else
- {
- nameServer = new NameServerAddress(server);
-
- if (nameServer.IPEndPoint == null)
- {
- if (proxy == null)
- {
- if (_dnsServer.AllowRecursion)
- nameServer.ResolveIPAddress(new NameServerAddress[] { new NameServerAddress(IPAddress.Loopback) }, proxy, preferIPv6, RETRIES, TIMEOUT);
- else
- nameServer.RecursiveResolveIPAddress(_dnsServer.Cache, proxy, preferIPv6, RETRIES, TIMEOUT);
- }
- }
- else if (protocol != DnsTransportProtocol.Tls)
- {
- try
- {
- if (_dnsServer.AllowRecursion)
- nameServer.ResolveDomainName(new NameServerAddress[] { new NameServerAddress(IPAddress.Loopback) }, proxy, preferIPv6, RETRIES, TIMEOUT);
- else
- nameServer.RecursiveResolveDomainName(_dnsServer.Cache, proxy, preferIPv6, RETRIES, TIMEOUT);
- }
- catch
- { }
- }
- }
-
- dnsResponse = (new DnsClient(nameServer) { Proxy = proxy, PreferIPv6 = preferIPv6, Protocol = protocol, Retries = RETRIES, Timeout = TIMEOUT }).Resolve(domain, type);
- }
-
- if (importRecords)
- {
- List recordsToSet = new List();
- bool containsSOARecord = false;
-
- foreach (DnsResourceRecord record in dnsResponse.Answer)
- {
- if (record.Name.Equals(domain, StringComparison.OrdinalIgnoreCase))
- {
- recordsToSet.Add(record);
-
- if (record.Type == DnsResourceRecordType.SOA)
- containsSOARecord = true;
- }
- }
-
- if (!containsSOARecord)
- {
- bool SOARecordExists = false;
-
- foreach (Zone.ZoneInfo zone in _dnsServer.AuthoritativeZoneRoot.ListAuthoritativeZones())
- {
- if (domain.EndsWith(zone.ZoneName, StringComparison.OrdinalIgnoreCase))
- {
- SOARecordExists = true;
- break;
- }
- }
-
- if (!SOARecordExists)
- _dnsServer.AuthoritativeZoneRoot.SetRecords(domain, DnsResourceRecordType.SOA, 14400, new DnsResourceRecordData[] { new DnsSOARecord(_dnsServer.ServerDomain, "hostmaster." + _dnsServer.ServerDomain, uint.Parse(DateTime.UtcNow.ToString("yyyyMMddHH")), 28800, 7200, 604800, 600) });
- }
-
- _dnsServer.AuthoritativeZoneRoot.SetRecords(recordsToSet);
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DNS Client imported record(s) for authoritative zone {server: " + server + "; domain: " + domain + "; type: " + type + ";}");
-
- SaveZoneFile(domain);
- }
-
- jsonWriter.WritePropertyName("result");
- jsonWriter.WriteRawValue(JsonConvert.SerializeObject(dnsResponse, new StringEnumConverter()));
- }
-
- private void ListLogs(JsonTextWriter jsonWriter)
- {
- string[] logFiles = Directory.GetFiles(_log.LogFolder, "*.log");
-
- Array.Sort(logFiles);
- Array.Reverse(logFiles);
-
- jsonWriter.WritePropertyName("logFiles");
- jsonWriter.WriteStartArray();
-
- foreach (string logFile in logFiles)
- {
- jsonWriter.WriteStartObject();
-
- jsonWriter.WritePropertyName("fileName");
- jsonWriter.WriteValue(Path.GetFileNameWithoutExtension(logFile));
-
- jsonWriter.WritePropertyName("size");
- jsonWriter.WriteValue(WebUtilities.GetFormattedSize(new FileInfo(logFile).Length));
-
- jsonWriter.WriteEndObject();
- }
-
- jsonWriter.WriteEndArray();
- }
-
- private void DeleteLog(HttpListenerRequest request)
- {
- string log = request.QueryString["log"];
- if (string.IsNullOrEmpty(log))
- throw new DnsWebServiceException("Parameter 'log' missing.");
-
- string logFile = Path.Combine(_log.LogFolder, log + ".log");
-
- if (_log.CurrentLogFile.Equals(logFile, StringComparison.OrdinalIgnoreCase))
- _log.DeleteCurrentLogFile();
- else
- File.Delete(logFile);
-
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Log file was deleted: " + log);
- }
-
- private void SetCredentials(string username, string password)
- {
- username = username.ToLower();
- string passwordHash = GetPasswordHash(username, password);
-
- _credentials.AddOrUpdate(username, passwordHash, delegate (string key, string oldValue)
- {
- return passwordHash;
- });
- }
-
- private void LoadCredentials(string username, string passwordHash)
- {
- username = username.ToLower();
-
- _credentials.AddOrUpdate(username, passwordHash, delegate (string key, string oldValue)
- {
- return passwordHash;
- });
- }
-
- private static string GetPasswordHash(string username, string password)
- {
- using (HMAC hmac = new HMACSHA256(Encoding.UTF8.GetBytes(password)))
- {
- return BitConverter.ToString(hmac.ComputeHash(Encoding.UTF8.GetBytes(username))).Replace("-", "").ToLower();
- }
- }
-
- private void LoadZoneFiles()
- {
- string[] zoneFiles = Directory.GetFiles(_configFolder, "*.zone");
-
- if (zoneFiles.Length == 0)
- {
- {
- CreateZone("localhost");
- _dnsServer.AuthoritativeZoneRoot.SetRecords("localhost", DnsResourceRecordType.A, 3600, new DnsResourceRecordData[] { new DnsARecord(IPAddress.Loopback) });
- _dnsServer.AuthoritativeZoneRoot.SetRecords("localhost", DnsResourceRecordType.AAAA, 3600, new DnsResourceRecordData[] { new DnsAAAARecord(IPAddress.IPv6Loopback) });
-
- SaveZoneFile("localhost");
- }
-
- {
- string prtDomain = new DnsQuestionRecord(IPAddress.Loopback, DnsClass.IN).Name;
-
- CreateZone(prtDomain);
- _dnsServer.AuthoritativeZoneRoot.SetRecords(prtDomain, DnsResourceRecordType.PTR, 3600, new DnsResourceRecordData[] { new DnsPTRRecord("localhost") });
-
- SaveZoneFile(prtDomain);
- }
-
- {
- string prtDomain = new DnsQuestionRecord(IPAddress.IPv6Loopback, DnsClass.IN).Name;
-
- CreateZone(prtDomain);
- _dnsServer.AuthoritativeZoneRoot.SetRecords(prtDomain, DnsResourceRecordType.PTR, 3600, new DnsResourceRecordData[] { new DnsPTRRecord("localhost") });
-
- SaveZoneFile(prtDomain);
- }
- }
- else
- {
- foreach (string zoneFile in zoneFiles)
- {
- try
- {
- LoadZoneFile(zoneFile);
- }
- catch (Exception ex)
- {
- _log.Write("Failed to loaded zone file: " + zoneFile + "\r\n" + ex.ToString());
- }
- }
- }
- }
-
- private void LoadZoneFile(string zoneFile)
- {
- using (FileStream fS = new FileStream(zoneFile, FileMode.Open, FileAccess.Read))
- {
- BinaryReader bR = new BinaryReader(fS);
-
- if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "DZ")
- throw new InvalidDataException("DnsServer zone file format is invalid.");
-
- switch (bR.ReadByte())
- {
- case 1:
- fS.Position = 0;
- LoadZoneFileV1(fS);
- break;
-
- case 2:
- {
- int count = bR.ReadInt32();
- DnsResourceRecord[] records = new DnsResourceRecord[count];
-
- for (int i = 0; i < count; i++)
- records[i] = new DnsResourceRecord(fS);
-
- _dnsServer.AuthoritativeZoneRoot.SetRecords(records);
- }
- break;
-
- case 3:
- {
- bool zoneDisabled = bR.ReadBoolean();
- int count = bR.ReadInt32();
-
- if (count > 0)
- {
- DnsResourceRecord[] records = new DnsResourceRecord[count];
-
- for (int i = 0; i < count; i++)
- {
- records[i] = new DnsResourceRecord(fS);
- records[i].Tag = new Zone.DnsResourceRecordInfo(new BinaryReader(fS));
- }
-
- _dnsServer.AuthoritativeZoneRoot.SetRecords(records);
-
- if (zoneDisabled)
- _dnsServer.AuthoritativeZoneRoot.DisableZone(records[0].Name);
- }
- }
- break;
-
- default:
- throw new InvalidDataException("DNS Zone file version not supported.");
- }
- }
-
- _log.Write("Loaded zone file: " + zoneFile);
- }
-
- private void LoadZoneFileV1(Stream s)
- {
- BincodingDecoder decoder = new BincodingDecoder(s, "DZ");
-
- switch (decoder.Version)
- {
- case 1:
- ICollection entries = decoder.DecodeNext().GetList();
- DnsResourceRecord[] records = new DnsResourceRecord[entries.Count];
-
- int i = 0;
- foreach (Bincoding entry in entries)
- records[i++] = new DnsResourceRecord(entry.GetValueStream());
-
- _dnsServer.AuthoritativeZoneRoot.SetRecords(records);
- break;
-
- default:
- throw new IOException("DNS Zone file version not supported: " + decoder.Version);
- }
- }
-
- private void SaveZoneFile(string domain)
- {
- domain = domain.ToLower();
- DnsResourceRecord[] records = _dnsServer.AuthoritativeZoneRoot.GetAllRecords(domain, DnsResourceRecordType.ANY, true, true);
- if (records.Length == 0)
- throw new DnsWebServiceException("Zone '" + domain + "' was not found.");
-
- string authZone = records[0].Name.ToLower();
-
- if (Zone.DomainEquals(authZone, "resolver-associated-doh.arpa") || Zone.DomainEquals(authZone, "resolver-addresses.arpa"))
- return;
-
- using (MemoryStream mS = new MemoryStream())
- {
- //serialize zone
- BinaryWriter bW = new BinaryWriter(mS);
-
- bW.Write(Encoding.ASCII.GetBytes("DZ")); //format
- bW.Write((byte)3); //version
-
- bW.Write(_dnsServer.AuthoritativeZoneRoot.IsZoneDisabled(domain));
- bW.Write(records.Length);
-
- foreach (DnsResourceRecord record in records)
- {
- record.WriteTo(mS);
-
- Zone.DnsResourceRecordInfo rrInfo = record.Tag as Zone.DnsResourceRecordInfo;
- if (rrInfo == null)
- rrInfo = new Zone.DnsResourceRecordInfo(); //default info
-
- rrInfo.WriteTo(bW);
- }
-
- //write to zone file
- mS.Position = 0;
-
- using (FileStream fS = new FileStream(Path.Combine(_configFolder, authZone + ".zone"), FileMode.Create, FileAccess.Write))
- {
- mS.CopyTo(fS);
- }
- }
-
- _log.Write("Saved zone file for domain: " + domain);
- }
-
- private void DeleteZoneFile(string domain)
- {
- domain = domain.ToLower();
-
- File.Delete(Path.Combine(_configFolder, domain + ".zone"));
-
- _log.Write("Deleted zone file for domain: " + domain);
- }
-
- private void LoadAllowedZoneFile()
- {
- string allowedZoneFile = Path.Combine(_configFolder, "allowed.config");
-
- try
- {
- _log.Write("DNS Server is loading allowed zone file: " + allowedZoneFile);
-
- using (FileStream fS = new FileStream(allowedZoneFile, FileMode.Open, FileAccess.Read))
- {
- BinaryReader bR = new BinaryReader(fS);
-
- if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "AZ") //format
- throw new InvalidDataException("DnsServer allowed zone file format is invalid.");
-
- byte version = bR.ReadByte();
- switch (version)
- {
- case 1:
- int length = bR.ReadInt32();
-
- for (int i = 0; i < length; i++)
- AllowZone(bR.ReadShortString());
-
- _totalZonesAllowed = length;
- break;
-
- default:
- throw new InvalidDataException("DnsServer allowed zone version not supported.");
- }
- }
-
- _log.Write("DNS Server allowed zone file was loaded: " + allowedZoneFile);
- }
- catch (FileNotFoundException)
- { }
- catch (Exception ex)
- {
- _log.Write("DNS Server encountered an error while loading allowed zone file: " + allowedZoneFile + "\r\n" + ex.ToString());
- }
- }
-
- private void SaveAllowedZoneFile()
- {
- ICollection allowedZones = _dnsServer.AllowedZoneRoot.ListAuthoritativeZones();
-
- _totalZonesAllowed = allowedZones.Count;
-
- string allowedZoneFile = Path.Combine(_configFolder, "allowed.config");
-
- using (FileStream fS = new FileStream(allowedZoneFile, FileMode.Create, FileAccess.Write))
- {
- BinaryWriter bW = new BinaryWriter(fS);
-
- bW.Write(Encoding.ASCII.GetBytes("AZ")); //format
- bW.Write((byte)1); //version
-
- bW.Write(allowedZones.Count);
-
- foreach (Zone.ZoneInfo zone in allowedZones)
- bW.WriteShortString(zone.ZoneName);
- }
-
- _log.Write("DNS Server allowed zone file was saved: " + allowedZoneFile);
- }
-
- private void LoadCustomBlockedZoneFile()
- {
- string customBlockedZoneFile = Path.Combine(_configFolder, "custom-blocked.config");
-
- try
- {
- _log.Write("DNS Server is loading custom blocked zone file: " + customBlockedZoneFile);
-
- using (FileStream fS = new FileStream(customBlockedZoneFile, FileMode.Open, FileAccess.Read))
- {
- BinaryReader bR = new BinaryReader(fS);
-
- if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "BZ") //format
- throw new InvalidDataException("DnsServer blocked zone file format is invalid.");
-
- byte version = bR.ReadByte();
- switch (version)
- {
- case 1:
- int length = bR.ReadInt32();
-
- for (int i = 0; i < length; i++)
- {
- string zoneName = bR.ReadShortString();
-
- BlockZone(zoneName, _customBlockedZoneRoot, "custom");
- BlockZone(zoneName, _dnsServer.BlockedZoneRoot, "custom");
- }
-
- _totalZonesBlocked = length;
- break;
-
- default:
- throw new InvalidDataException("DnsServer blocked zone file version not supported.");
- }
- }
-
- _log.Write("DNS Server custom blocked zone file was loaded: " + customBlockedZoneFile);
- }
- catch (FileNotFoundException)
- { }
- catch (Exception ex)
- {
- _log.Write("DNS Server encountered an error while loading custom blocked zone file: " + customBlockedZoneFile + "\r\n" + ex.ToString());
- }
- }
-
- private void SaveCustomBlockedZoneFile()
- {
- ICollection customBlockedZones = _customBlockedZoneRoot.ListAuthoritativeZones();
-
- string customBlockedZoneFile = Path.Combine(_configFolder, "custom-blocked.config");
-
- using (FileStream fS = new FileStream(customBlockedZoneFile, FileMode.Create, FileAccess.Write))
- {
- BinaryWriter bW = new BinaryWriter(fS);
-
- bW.Write(Encoding.ASCII.GetBytes("BZ")); //format
- bW.Write((byte)1); //version
-
- bW.Write(customBlockedZones.Count);
-
- foreach (Zone.ZoneInfo zone in customBlockedZones)
- bW.WriteShortString(zone.ZoneName);
- }
-
- _log.Write("DNS Server custom blocked zone file was saved: " + customBlockedZoneFile);
- }
-
- private void LoadBlockLists()
- {
- Zone blockedZoneRoot = new Zone(true);
-
- using (CountdownEvent countdown = new CountdownEvent(_blockListUrls.Count))
- {
- foreach (Uri blockListUrl in _blockListUrls)
- {
- ThreadPool.QueueUserWorkItem(delegate (object state)
- {
- try
- {
- LoadBlockListFile(blockedZoneRoot, state as Uri);
- }
- catch (Exception ex)
- {
- _log.Write(ex);
- }
-
- countdown.Signal();
-
- }, blockListUrl);
- }
-
- //load custom blocked zone into new block zone
- foreach (Zone.ZoneInfo zone in _customBlockedZoneRoot.ListAuthoritativeZones())
- BlockZone(zone.ZoneName, blockedZoneRoot, "custom");
-
- countdown.Wait();
- }
-
- //set new blocked zone
- _dnsServer.BlockedZoneRoot = blockedZoneRoot;
- _totalZonesBlocked = blockedZoneRoot.ListAuthoritativeZones().Count;
-
- _log.Write("DNS Server blocked zone loading finished successfully.");
- }
-
- private string GetBlockListFilePath(Uri blockListUrl)
- {
- using (HashAlgorithm hash = SHA256.Create())
- {
- return Path.Combine(_configFolder, "blocklists", BitConverter.ToString(hash.ComputeHash(Encoding.UTF8.GetBytes(blockListUrl.AbsoluteUri))).Replace("-", "").ToLower());
- }
- }
-
- private void LoadBlockListFile(Zone blockedZoneRoot, Uri blockListUrl)
- {
- string blockListAbsoluteUrl = blockListUrl.AbsoluteUri;
-
- try
- {
- string blockListFilePath = GetBlockListFilePath(blockListUrl);
- int count = 0;
-
- _log.Write("DNS Server is loading blocked zone from: " + blockListAbsoluteUrl);
-
- using (FileStream fS = new FileStream(blockListFilePath, FileMode.Open, FileAccess.Read))
- {
- //parse hosts file and populate block zone
- StreamReader sR = new StreamReader(fS, true);
-
- while (true)
- {
- string line = sR.ReadLine();
- if (line == null)
- break; //eof
-
- line = line.TrimStart(' ', '\t');
-
- if (line == "")
- continue; //skip empty line
-
- if (line.StartsWith("#"))
- continue; //skip comment line
-
- string firstWord = PopWord(ref line);
- string secondWord = PopWord(ref line);
-
- string strIpAddress = null;
- string hostname;
-
- if (secondWord == "")
- {
- hostname = firstWord;
- }
- else
- {
- strIpAddress = firstWord;
- hostname = secondWord;
- }
-
- if (!DnsClient.IsDomainNameValid(hostname, false))
- continue;
-
- switch (hostname.ToLower())
- {
- case "":
- case "localhost":
- case "localhost.localdomain":
- case "local":
- case "broadcasthost":
- case "ip6-localhost":
- case "ip6-loopback":
- case "ip6-localnet":
- case "ip6-mcastprefix":
- case "ip6-allnodes":
- case "ip6-allrouters":
- case "ip6-allhosts":
- continue; //skip these hostnames
- }
-
- if (IPAddress.TryParse(hostname, out IPAddress host))
- continue; //skip line when hostname is IP address
-
- IPAddress ipAddress;
-
- if (string.IsNullOrEmpty(strIpAddress) || !IPAddress.TryParse(strIpAddress, out ipAddress))
- ipAddress = IPAddress.Any;
-
- if (ipAddress.Equals(IPAddress.Any) || ipAddress.Equals(IPAddress.Loopback) || ipAddress.Equals(IPAddress.IPv6Any) || ipAddress.Equals(IPAddress.IPv6Loopback))
- {
- BlockZone(hostname, blockedZoneRoot, blockListAbsoluteUrl);
- count++;
- }
- }
- }
-
- _log.Write("DNS Server blocked zone was loaded (" + count + " domains) from: " + blockListAbsoluteUrl);
- }
- catch (Exception ex)
- {
- _log.Write("DNS Server failed to load block list from: " + blockListAbsoluteUrl + "\r\n" + ex.ToString());
- }
- }
-
- private void UpdateBlockLists()
- {
- bool success = false;
-
- foreach (Uri blockListUrl in _blockListUrls)
- {
- string blockListFilePath = GetBlockListFilePath(blockListUrl);
- string blockListDownloadFilePath = blockListFilePath + ".downloading";
-
- try
- {
- int retries = 1;
-
- while (true)
- {
- if (File.Exists(blockListDownloadFilePath))
- File.Delete(blockListDownloadFilePath);
-
- using (WebClientEx wC = new WebClientEx())
- {
- wC.Proxy = _dnsServer.Proxy;
- wC.Timeout = 60000;
-
- try
- {
- wC.DownloadFile(blockListUrl, blockListDownloadFilePath);
- }
- catch (WebException)
- {
- if (retries < BLOCK_LIST_UPDATE_RETRIES)
- {
- retries++;
- continue;
- }
-
- throw;
- }
- }
-
- if (File.Exists(blockListFilePath))
- File.Delete(blockListFilePath);
-
- File.Move(blockListDownloadFilePath, blockListFilePath);
-
- success = true;
- _log.Write("DNS Server successfully downloaded block list (" + WebUtilities.GetFormattedSize(new FileInfo(blockListFilePath).Length) + "): " + blockListUrl.AbsoluteUri);
- break;
- }
- }
- catch (Exception ex)
- {
- _log.Write("DNS Server failed to download block list and will use previously downloaded file (if available): " + blockListUrl.AbsoluteUri + "\r\n" + ex.ToString());
- }
- }
-
- if (success)
- {
- //save last updated on time
- _blockListLastUpdatedOn = DateTime.UtcNow;
- SaveConfigFile();
-
- LoadBlockLists();
- }
- }
-
- private static string PopWord(ref string line)
- {
- if (line == "")
- return line;
-
- line = line.TrimStart(' ', '\t');
-
- int i = line.IndexOf(' ');
-
- if (i < 0)
- i = line.IndexOf('\t');
-
- string word;
-
- if (i < 0)
- {
- word = line;
- line = "";
- }
- else
- {
- word = line.Substring(0, i);
- line = line.Substring(i + 1);
- }
-
- return word;
- }
-
- private void StartBlockListUpdateTimer()
- {
- if (_blockListUpdateTimer == null)
- {
- _blockListUpdateTimer = new Timer(delegate (object state)
- {
- try
- {
- if (DateTime.UtcNow > _blockListLastUpdatedOn.AddHours(BLOCK_LIST_UPDATE_AFTER_HOURS))
- UpdateBlockLists();
- }
- catch (Exception ex)
- {
- _log.Write("DNS Server encountered an error while updating block list.\r\n" + ex.ToString());
- }
-
- }, null, BLOCK_LIST_UPDATE_TIMER_INITIAL_INTERVAL, BLOCK_LIST_UPDATE_TIMER_INTERVAL);
- }
- }
-
- private void StopBlockListUpdateTimer()
- {
- if (_blockListUpdateTimer != null)
- {
- _blockListUpdateTimer.Dispose();
- _blockListUpdateTimer = null;
- }
- }
-
- private void StartTlsCertificateUpdateTimer()
- {
- if (_tlsCertificateUpdateTimer == null)
- {
- _tlsCertificateUpdateTimer = new Timer(delegate (object state)
- {
- try
- {
- FileInfo fileInfo = new FileInfo(_tlsCertificatePath);
-
- if (fileInfo.Exists && (fileInfo.LastWriteTimeUtc != _tlsCertificateLastModifiedOn))
- LoadTlsCertificate(_tlsCertificatePath, _tlsCertificatePassword);
- }
- catch (Exception ex)
- {
- _log.Write("DNS Server encountered an error while updating TLS Certificate: " + _tlsCertificatePath + "\r\n" + ex.ToString());
- }
-
- }, null, TLS_CERTIFICATE_UPDATE_TIMER_INITIAL_INTERVAL, TLS_CERTIFICATE_UPDATE_TIMER_INTERVAL);
- }
- }
-
- private void StopTlsCertificateUpdateTimer()
- {
- if (_tlsCertificateUpdateTimer != null)
- {
- _tlsCertificateUpdateTimer.Dispose();
- _tlsCertificateUpdateTimer = null;
- }
- }
-
- private void LoadTlsCertificate(string tlsCertificatePath, string tlsCertificatePassword)
- {
- FileInfo fileInfo = new FileInfo(tlsCertificatePath);
-
- if (!fileInfo.Exists)
- throw new ArgumentException("Tls certificate file does not exists: " + tlsCertificatePath);
-
- if (Path.GetExtension(tlsCertificatePath) != ".pfx")
- throw new ArgumentException("Tls certificate file must be PKCS #12 formatted with .pfx extension: " + tlsCertificatePath);
-
- X509Certificate2 certificate = new X509Certificate2(tlsCertificatePath, tlsCertificatePassword);
-
- if (!certificate.Verify())
- throw new ArgumentException("Tls certificate is invalid.");
-
- _dnsServer.Certificate = certificate;
- _tlsCertificateLastModifiedOn = fileInfo.LastWriteTimeUtc;
-
- _log.Write("DNS Server TLS certificate was loaded: " + tlsCertificatePath);
- }
-
- private void LoadConfigFile()
- {
- string configFile = Path.Combine(_configFolder, "dns.config");
-
- try
- {
- bool passwordResetOption = false;
-
- if (!File.Exists(configFile))
- {
- string passwordResetConfigFile = Path.Combine(_configFolder, "reset.config");
-
- if (File.Exists(passwordResetConfigFile))
- {
- passwordResetOption = true;
- configFile = passwordResetConfigFile;
- }
- }
-
- byte version;
-
- using (FileStream fS = new FileStream(configFile, FileMode.Open, FileAccess.Read))
- {
- BinaryReader bR = new BinaryReader(fS);
-
- if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "DS") //format
- throw new InvalidDataException("DnsServer config file format is invalid.");
-
- version = bR.ReadByte();
- switch (version)
- {
- case 1:
- fS.Position = 0;
- LoadConfigFileV1(fS);
- break;
-
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- _dnsServer.ServerDomain = bR.ReadShortString();
- _webServicePort = bR.ReadInt32();
-
- _dnsServer.PreferIPv6 = bR.ReadBoolean();
-
- if (bR.ReadBoolean()) //logQueries
- _dnsServer.QueryLogManager = _log;
-
- _dnsServer.AllowRecursion = bR.ReadBoolean();
-
- if (version >= 4)
- _dnsServer.AllowRecursionOnlyForPrivateNetworks = bR.ReadBoolean();
- else
- _dnsServer.AllowRecursionOnlyForPrivateNetworks = true; //default true for security reasons
-
- if (version >= 9)
- {
- _dnsServer.CachePrefetchEligibility = bR.ReadInt32();
- _dnsServer.CachePrefetchTrigger = bR.ReadInt32();
- _dnsServer.CachePrefetchSampleIntervalInMinutes = bR.ReadInt32();
- _dnsServer.CachePrefetchSampleEligibilityHitsPerHour = bR.ReadInt32();
- }
-
- NetProxyType proxyType = (NetProxyType)bR.ReadByte();
- if (proxyType != NetProxyType.None)
- {
- string address = bR.ReadShortString();
- int port = bR.ReadInt32();
- NetworkCredential credential = null;
-
- if (bR.ReadBoolean()) //credential set
- credential = new NetworkCredential(bR.ReadShortString(), bR.ReadShortString());
-
- _dnsServer.Proxy = new NetProxy(proxyType, address, port, credential);
- }
- else
- {
- _dnsServer.Proxy = null;
- }
-
- {
- int count = bR.ReadByte();
- if (count > 0)
- {
- NameServerAddress[] forwarders = new NameServerAddress[count];
-
- for (int i = 0; i < count; i++)
- forwarders[i] = new NameServerAddress(bR);
-
- _dnsServer.Forwarders = forwarders;
- }
- }
-
- _dnsServer.ForwarderProtocol = (DnsTransportProtocol)bR.ReadByte();
-
- {
- int count = bR.ReadByte();
- if (count > 0)
- {
- if (version > 2)
- {
- for (int i = 0; i < count; i++)
- LoadCredentials(bR.ReadShortString(), bR.ReadShortString());
- }
- else
- {
- for (int i = 0; i < count; i++)
- SetCredentials(bR.ReadShortString(), bR.ReadShortString());
- }
- }
- }
-
- if (version <= 6)
- {
- int count = bR.ReadInt32();
- _configDisabledZones = new List(count);
-
- for (int i = 0; i < count; i++)
- {
- string domain = bR.ReadShortString();
- _configDisabledZones.Add(domain);
- }
- }
-
- if (version > 4)
- {
- //block list
- int count = bR.ReadByte();
-
- for (int i = 0; i < count; i++)
- _blockListUrls.Add(new Uri(bR.ReadShortString()));
-
- _blockListLastUpdatedOn = bR.ReadDate();
-
- if (count > 0)
- StartBlockListUpdateTimer();
- }
-
- if (version >= 6)
- {
- int count = bR.ReadByte();
- _dnsServer.LocalAddresses = new IPAddress[count];
-
- for (int i = 0; i < count; i++)
- _dnsServer.LocalAddresses[i] = IPAddressExtension.Parse(bR);
- }
- else
- {
- _dnsServer.LocalAddresses = new IPAddress[] { IPAddress.Any, IPAddress.IPv6Any };
- }
-
- if (version >= 8)
- {
- _dnsServer.EnableDnsOverHttp = bR.ReadBoolean();
- _dnsServer.EnableDnsOverTls = bR.ReadBoolean();
- _dnsServer.EnableDnsOverHttps = bR.ReadBoolean();
- _tlsCertificatePath = bR.ReadShortString();
- _tlsCertificatePassword = bR.ReadShortString();
-
- if (_tlsCertificatePath == "")
- _tlsCertificatePath = null;
-
- if (_tlsCertificatePath != null)
- {
- try
- {
- LoadTlsCertificate(_tlsCertificatePath, _tlsCertificatePassword);
- }
- catch (Exception ex)
- {
- _log.Write("DNS Server encountered an error while loading TLS certificate: " + _tlsCertificatePath + "\r\n" + ex.ToString());
- }
-
- StartTlsCertificateUpdateTimer();
- }
- }
-
- break;
-
- default:
- throw new InvalidDataException("DnsServer config version not supported.");
- }
- }
-
- _log.Write("DNS Server config file was loaded: " + configFile);
-
- if (passwordResetOption)
- {
- SetCredentials("admin", "admin");
-
- _log.Write("DNS Server reset password for user: admin");
- SaveConfigFile();
-
- try
- {
- File.Delete(configFile);
- }
- catch
- { }
- }
-
- if (version <= 6)
- SaveConfigFile(); //save as new config version to avoid loading old version next time
- }
- catch (FileNotFoundException)
- {
- _log.Write("DNS Server config file was not found: " + configFile);
- _log.Write("DNS Server is restoring default config file.");
-
- _dnsServer.ServerDomain = Environment.MachineName.ToLower();
- _webServicePort = 5380;
- _dnsServer.LocalAddresses = new IPAddress[] { IPAddress.Any, IPAddress.IPv6Any };
-
- SetCredentials("admin", "admin");
-
- _dnsServer.AllowRecursion = true;
- _dnsServer.AllowRecursionOnlyForPrivateNetworks = true; //default true for security reasons
-
- SaveConfigFile();
- }
- catch (Exception ex)
- {
- _log.Write("DNS Server encountered an error while loading config file: " + configFile + "\r\n" + ex.ToString());
- _log.Write("Note: You may try deleting the config file to fix this issue. However, you will lose DNS settings but, zone data wont be affected.");
- }
- }
-
- private void LoadConfigFileV1(Stream s)
- {
- BincodingDecoder decoder = new BincodingDecoder(s, "DS");
-
- switch (decoder.Version)
- {
- case 1:
- while (true)
- {
- Bincoding item = decoder.DecodeNext();
- if (item.Type == BincodingType.NULL)
- break;
-
- if (item.Type == BincodingType.KEY_VALUE_PAIR)
- {
- KeyValuePair pair = item.GetKeyValuePair();
-
- switch (pair.Key)
- {
- case "serverDomain":
- _dnsServer.ServerDomain = pair.Value.GetStringValue();
- break;
-
- case "webServicePort":
- _webServicePort = pair.Value.GetIntegerValue();
- break;
-
- case "dnsPreferIPv6":
- _dnsServer.PreferIPv6 = pair.Value.GetBooleanValue();
- break;
-
- case "logQueries":
- if (pair.Value.GetBooleanValue())
- _dnsServer.QueryLogManager = _log;
-
- break;
-
- case "dnsAllowRecursion":
- _dnsServer.AllowRecursion = pair.Value.GetBooleanValue();
- break;
-
- case "dnsForwarders":
- ICollection entries = pair.Value.GetList();
- NameServerAddress[] forwarders = new NameServerAddress[entries.Count];
-
- int i = 0;
- foreach (Bincoding entry in entries)
- forwarders[i++] = new NameServerAddress(IPAddress.Parse(entry.GetStringValue()));
-
- _dnsServer.Forwarders = forwarders;
- break;
-
- case "credentials":
- foreach (KeyValuePair credential in pair.Value.GetDictionary())
- SetCredentials(credential.Key, credential.Value.GetStringValue());
-
- break;
-
- case "disabledZones":
- foreach (Bincoding disabledZone in pair.Value.GetList())
- _dnsServer.AuthoritativeZoneRoot.DisableZone(disabledZone.GetStringValue());
-
- break;
- }
- }
- }
- break;
-
- default:
- throw new IOException("DNS Config file version not supported: " + decoder.Version);
- }
- }
-
- private void SaveConfigFile()
- {
- string configFile = Path.Combine(_configFolder, "dns.config");
-
- using (MemoryStream mS = new MemoryStream())
- {
- //serialize config
- BinaryWriter bW = new BinaryWriter(mS);
-
- bW.Write(Encoding.ASCII.GetBytes("DS")); //format
- bW.Write((byte)9); //version
-
- bW.WriteShortString(_dnsServer.ServerDomain);
- bW.Write(_webServicePort);
-
- bW.Write(_dnsServer.PreferIPv6);
- bW.Write((_dnsServer.QueryLogManager != null)); //logQueries
- bW.Write(_dnsServer.AllowRecursion);
- bW.Write(_dnsServer.AllowRecursionOnlyForPrivateNetworks);
-
- bW.Write(_dnsServer.CachePrefetchEligibility);
- bW.Write(_dnsServer.CachePrefetchTrigger);
- bW.Write(_dnsServer.CachePrefetchSampleIntervalInMinutes);
- bW.Write(_dnsServer.CachePrefetchSampleEligibilityHitsPerHour);
-
- if (_dnsServer.Proxy == null)
- {
- bW.Write((byte)NetProxyType.None);
- }
- else
- {
- bW.Write((byte)_dnsServer.Proxy.Type);
- bW.WriteShortString(_dnsServer.Proxy.Address);
- bW.Write(_dnsServer.Proxy.Port);
-
- NetworkCredential credential = _dnsServer.Proxy.Credential;
-
- if (credential == null)
- {
- bW.Write(false);
- }
- else
- {
- bW.Write(true);
- bW.WriteShortString(credential.UserName);
- bW.WriteShortString(credential.Password);
- }
- }
-
- if (_dnsServer.Forwarders == null)
- {
- bW.Write((byte)0);
- }
- else
- {
- bW.Write(Convert.ToByte(_dnsServer.Forwarders.Length));
-
- foreach (NameServerAddress forwarder in _dnsServer.Forwarders)
- forwarder.WriteTo(bW);
- }
-
- bW.Write((byte)_dnsServer.ForwarderProtocol);
-
- {
- bW.Write(Convert.ToByte(_credentials.Count));
-
- foreach (KeyValuePair credential in _credentials)
- {
- bW.WriteShortString(credential.Key);
- bW.WriteShortString(credential.Value);
- }
- }
-
- //block list
- {
- bW.Write((byte)_blockListUrls.Count);
-
- foreach (Uri blockListUrl in _blockListUrls)
- bW.WriteShortString(blockListUrl.AbsoluteUri);
-
- bW.Write(_blockListLastUpdatedOn);
- }
-
- if (_dnsServer.LocalAddresses == null)
- {
- bW.Write((byte)0);
- }
- else
- {
- bW.Write(Convert.ToByte(_dnsServer.LocalAddresses.Length));
-
- foreach (IPAddress localAddress in _dnsServer.LocalAddresses)
- localAddress.WriteTo(bW);
- }
-
- bW.Write(_dnsServer.EnableDnsOverHttp);
- bW.Write(_dnsServer.EnableDnsOverTls);
- bW.Write(_dnsServer.EnableDnsOverHttps);
-
- if (_tlsCertificatePath == null)
- bW.WriteShortString(string.Empty);
- else
- bW.WriteShortString(_tlsCertificatePath);
-
- if (_tlsCertificatePassword == null)
- bW.WriteShortString(string.Empty);
- else
- bW.WriteShortString(_tlsCertificatePassword);
-
- //write config
- mS.Position = 0;
-
- using (FileStream fS = new FileStream(configFile, FileMode.Create, FileAccess.Write))
- {
- mS.CopyTo(fS);
- }
- }
-
- _log.Write("DNS Server config file was saved: " + configFile);
- }
-
- #endregion
-
- #region public
-
- public void Start()
- {
- if (_disposed)
- throw new ObjectDisposedException("DnsWebService");
-
- if (_state != ServiceState.Stopped)
- throw new InvalidOperationException("DNS Web Service is already running.");
-
- _state = ServiceState.Starting;
-
- try
- {
- if (_stats == null)
- {
- string statsFolder = Path.Combine(_configFolder, "stats");
-
- if (!Directory.Exists(statsFolder))
- Directory.CreateDirectory(statsFolder);
-
- _stats = new StatsManager(statsFolder, _log);
- }
-
- _dnsServer = new DnsServer();
- _dnsServer.LogManager = _log;
- _dnsServer.StatsManager = _stats;
-
- LoadConfigFile();
- LoadZoneFiles();
-
- if (_configDisabledZones != null)
- {
- foreach (string domain in _configDisabledZones)
- {
- _dnsServer.AuthoritativeZoneRoot.DisableZone(domain);
- SaveZoneFile(domain);
- }
- }
-
- ThreadPool.QueueUserWorkItem(delegate (object state)
- {
- try
- {
- LoadAllowedZoneFile();
- LoadCustomBlockedZoneFile();
- LoadBlockLists();
- }
- catch (Exception ex)
- {
- _log.Write(ex);
- }
- });
-
- _dnsServer.Start();
-
- try
- {
- _webService = new HttpListener();
- _webService.Prefixes.Add("http://+:" + _webServicePort + "/");
- _webService.Start();
-
- _webServiceHostname = Environment.MachineName.ToLower();
- }
- catch (Exception ex)
- {
- _log.Write("DNS Web Service failed to bind using default hostname. Attempting to bind again using 'localhost' hostname.\r\n" + ex.ToString());
-
- _webService = new HttpListener();
- _webService.Prefixes.Add("http://localhost:" + _webServicePort + "/");
- _webService.Start();
-
- _webServiceHostname = "localhost";
- }
-
- _webService.IgnoreWriteExceptions = true;
-
- _webServiceThread = new Thread(AcceptWebRequestAsync);
- _webServiceThread.IsBackground = true;
- _webServiceThread.Start();
-
- _state = ServiceState.Running;
-
- _log.Write(new IPEndPoint(IPAddress.Any, _webServicePort), "DNS Web Service (v" + _currentVersion + ") was started successfully.");
- }
- catch (Exception ex)
- {
- _log.Write("Failed to start DNS Web Service (v" + _currentVersion + ")\r\n" + ex.ToString());
- throw;
- }
- }
-
- public void Stop()
- {
- if (_state != ServiceState.Running)
- return;
-
- _state = ServiceState.Stopping;
-
- try
- {
- _webService.Stop();
- _dnsServer.Stop();
-
- StopBlockListUpdateTimer();
- StopTlsCertificateUpdateTimer();
-
- _state = ServiceState.Stopped;
-
- _log.Write(new IPEndPoint(IPAddress.Loopback, _webServicePort), "DNS Web Service (v" + _currentVersion + ") was stopped successfully.");
- }
- catch (Exception ex)
- {
- _log.Write("Failed to stop DNS Web Service (v" + _currentVersion + ")\r\n" + ex.ToString());
- throw;
- }
- }
-
- #endregion
-
- #region properties
-
- public string ConfigFolder
- { get { return _configFolder; } }
-
- public string ServerDomain
- { get { return _dnsServer.ServerDomain; } }
-
- public int WebServicePort
- { get { return _webServicePort; } }
-
- public string WebServiceHostname
- { get { return _webServiceHostname; } }
-
- #endregion
- }
-
- public class UserSession
- {
- #region variables
-
- const int SESSION_TIMEOUT = 30 * 60 * 1000; //30 mins
-
- readonly string _username;
- DateTime _lastSeen;
-
- #endregion
-
- #region constructor
-
- public UserSession(string username)
- {
- _username = username;
- _lastSeen = DateTime.UtcNow;
- }
-
- #endregion
-
- #region public
-
- public void UpdateLastSeen()
- {
- _lastSeen = DateTime.UtcNow;
- }
-
- public bool HasExpired()
- {
- return _lastSeen.AddMilliseconds(SESSION_TIMEOUT) < DateTime.UtcNow;
- }
-
- #endregion
-
- #region properties
-
- public string Username
- { get { return _username; } }
-
- #endregion
- }
-
- public class DnsWebServiceException : Exception
- {
- #region constructors
-
- public DnsWebServiceException()
- : base()
- { }
-
- public DnsWebServiceException(string message)
- : base(message)
- { }
-
- public DnsWebServiceException(string message, Exception innerException)
- : base(message, innerException)
- { }
-
- protected DnsWebServiceException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
- : base(info, context)
- { }
-
- #endregion
- }
-
- public class InvalidTokenDnsWebServiceException : DnsWebServiceException
- {
- #region constructors
-
- public InvalidTokenDnsWebServiceException()
- : base()
- { }
-
- public InvalidTokenDnsWebServiceException(string message)
- : base(message)
- { }
-
- public InvalidTokenDnsWebServiceException(string message, Exception innerException)
- : base(message, innerException)
- { }
-
- protected InvalidTokenDnsWebServiceException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
- : base(info, context)
- { }
-
- #endregion
- }
-}