diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs
index d1cbb684..da67b2b7 100644
--- a/DnsServerCore/DnsWebService.cs
+++ b/DnsServerCore/DnsWebService.cs
@@ -17,9 +17,11 @@ along with this program. If not, see .
*/
+using DnsApplicationCommon;
using DnsServerCore.Dhcp;
using DnsServerCore.Dhcp.Options;
using DnsServerCore.Dns;
+using DnsServerCore.Dns.Applications;
using DnsServerCore.Dns.ResourceRecords;
using DnsServerCore.Dns.Zones;
using Newtonsoft.Json;
@@ -483,16 +485,24 @@ namespace DnsServerCore
UpdateRecord(request);
break;
- case "/api/apps/installPackage":
+ case "/api/apps/list":
+ ListApps(jsonWriter);
break;
- case "/api/apps/uninstallPackage":
+ case "/api/apps/install":
+ await InstallAppAsync(request);
+ break;
+
+ case "/api/apps/uninstall":
+ UninstallApp(request);
break;
case "/api/apps/getConfig":
+ await GetAppConfigAsync(request, jsonWriter);
break;
case "/api/apps/setConfig":
+ await SetAppConfigAsync(request);
break;
case "/api/resolveQuery":
@@ -1736,6 +1746,7 @@ namespace DnsServerCore
bool blockLists = false;
bool logs = false;
bool scopes = false;
+ bool apps = false;
bool stats = false;
bool zones = false;
bool allowedZones = false;
@@ -1755,6 +1766,10 @@ namespace DnsServerCore
if (!string.IsNullOrEmpty(strScopes))
scopes = bool.Parse(strScopes);
+ string strApps = request.QueryString["apps"];
+ if (!string.IsNullOrEmpty(strApps))
+ apps = bool.Parse(strApps);
+
string strStats = request.QueryString["stats"];
if (!string.IsNullOrEmpty(strStats))
stats = bool.Parse(strStats);
@@ -1825,11 +1840,27 @@ namespace DnsServerCore
if (scopes)
{
- string[] scopFiles = Directory.GetFiles(Path.Combine(_configFolder, "scopes"), "*.scope", SearchOption.TopDirectoryOnly);
- foreach (string scopFile in scopFiles)
+ string[] scopeFiles = Directory.GetFiles(Path.Combine(_configFolder, "scopes"), "*.scope", SearchOption.TopDirectoryOnly);
+ foreach (string scopeFile in scopeFiles)
{
- string entryName = "scopes/" + Path.GetFileName(scopFile);
- backupZip.CreateEntryFromFile(scopFile, entryName);
+ string entryName = "scopes/" + Path.GetFileName(scopeFile);
+ backupZip.CreateEntryFromFile(scopeFile, entryName);
+ }
+ }
+
+ if (apps)
+ {
+ string[] appFiles = Directory.GetFiles(Path.Combine(_configFolder, "apps"), "*", SearchOption.AllDirectories);
+ foreach (string appFile in appFiles)
+ {
+ string entryName = appFile.Substring(_configFolder.Length);
+
+ if (Path.DirectorySeparatorChar != '/')
+ entryName = entryName.Replace(Path.DirectorySeparatorChar, '/');
+
+ entryName = entryName.TrimStart('/');
+
+ backupZip.CreateEntryFromFile(appFile, entryName);
}
}
@@ -1926,6 +1957,7 @@ namespace DnsServerCore
bool blockLists = false;
bool logs = false;
bool scopes = false;
+ bool apps = false;
bool stats = false;
bool zones = false;
bool allowedZones = false;
@@ -1947,6 +1979,10 @@ namespace DnsServerCore
if (!string.IsNullOrEmpty(strScopes))
scopes = bool.Parse(strScopes);
+ string strApps = request.QueryString["apps"];
+ if (!string.IsNullOrEmpty(strApps))
+ apps = bool.Parse(strApps);
+
string strStats = request.QueryString["stats"];
if (!string.IsNullOrEmpty(strStats))
stats = bool.Parse(strStats);
@@ -2111,6 +2147,41 @@ namespace DnsServerCore
}
}
+ if (apps)
+ {
+ //unload apps
+ _dnsServer.DnsApplicationManager.UnloadAllApplications();
+
+ if (deleteExistingFiles)
+ {
+ //delete existing apps
+ string appFolder = Path.Combine(_configFolder, "apps");
+ if (Directory.Exists(appFolder))
+ Directory.Delete(appFolder, true);
+ }
+
+ //extract apps files from backup
+ foreach (ZipArchiveEntry entry in backupZip.Entries)
+ {
+ if (entry.FullName.StartsWith("apps/"))
+ {
+ string entryPath = entry.FullName;
+
+ if (Path.DirectorySeparatorChar != '/')
+ entryPath = entryPath.Replace('/', '\\');
+
+ string filePath = Path.Combine(_configFolder, entryPath);
+
+ Directory.CreateDirectory(Path.GetDirectoryName(filePath));
+
+ entry.ExtractToFile(filePath, true);
+ }
+ }
+
+ //reload apps
+ _dnsServer.DnsApplicationManager.LoadAllApplications();
+ }
+
if (stats)
{
if (deleteExistingFiles)
@@ -2166,8 +2237,16 @@ namespace DnsServerCore
if (allowedZones)
{
ZipArchiveEntry entry = backupZip.GetEntry("allowed.config");
- if (entry != null)
+ if (entry == null)
+ {
+ string fileName = Path.Combine(_configFolder, "allowed.config");
+ if (File.Exists(fileName))
+ File.Delete(fileName);
+ }
+ else
+ {
entry.ExtractToFile(Path.Combine(_configFolder, entry.Name), true);
+ }
//reload
_dnsServer.AllowedZoneManager.LoadAllowedZoneFile();
@@ -2176,8 +2255,16 @@ namespace DnsServerCore
if (blockedZones)
{
ZipArchiveEntry entry = backupZip.GetEntry("blocked.config");
- if (entry != null)
+ if (entry == null)
+ {
+ string fileName = Path.Combine(_configFolder, "allowed.config");
+ if (File.Exists(fileName))
+ File.Delete(fileName);
+ }
+ else
+ {
entry.ExtractToFile(Path.Combine(_configFolder, entry.Name), true);
+ }
//reload
_dnsServer.BlockedZoneManager.LoadBlockedZoneFile();
@@ -3301,6 +3388,28 @@ namespace DnsServerCore
}
break;
+ case AuthZoneType.Application:
+ {
+ string strAppName = request.QueryString["appName"];
+ if (string.IsNullOrEmpty(strAppName))
+ throw new DnsWebServiceException("Parameter 'appName' missing.");
+
+ string strClassPath = request.QueryString["classPath"];
+ if (string.IsNullOrEmpty(strClassPath))
+ throw new DnsWebServiceException("Parameter 'classPath' missing.");
+
+ string strRecordData = request.QueryString["recordData"];
+ if (string.IsNullOrEmpty(strRecordData))
+ strRecordData = "";
+
+ if (_dnsServer.AuthZoneManager.CreateApplicationZone(domain, _dnsServer.ServerDomain, strAppName, strClassPath, strRecordData) == null)
+ throw new DnsWebServiceException("Zone already exists: " + domain);
+
+ _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Application zone was created: " + domain);
+ _dnsServer.AuthZoneManager.SaveZoneFile(domain);
+ }
+ break;
+
default:
throw new NotSupportedException("Zone type not supported.");
}
@@ -3551,6 +3660,20 @@ namespace DnsServerCore
}
break;
+ case DnsResourceRecordType.APP:
+ {
+ string classPath = request.QueryString["classPath"];
+ if (string.IsNullOrEmpty(classPath))
+ throw new DnsWebServiceException("Parameter 'classPath' missing.");
+
+ string recordData = request.QueryString["recordData"];
+ if (string.IsNullOrEmpty(recordData))
+ recordData = "";
+
+ _dnsServer.AuthZoneManager.SetRecords(domain, type, ttl, new DnsResourceRecordData[] { new DnsApplicationRecord(value, classPath, recordData) });
+ }
+ break;
+
default:
throw new DnsWebServiceException("Type not supported for AddRecords().");
}
@@ -3863,6 +3986,23 @@ namespace DnsServerCore
}
break;
+ case DnsResourceRecordType.APP:
+ {
+ DnsApplicationRecord rdata = record.RDATA as DnsApplicationRecord;
+ if (rdata != null)
+ {
+ jsonWriter.WritePropertyName("value");
+ jsonWriter.WriteValue(rdata.AppName);
+
+ jsonWriter.WritePropertyName("classPath");
+ jsonWriter.WriteValue(rdata.ClassPath);
+
+ jsonWriter.WritePropertyName("data");
+ jsonWriter.WriteValue(rdata.Data);
+ }
+ }
+ break;
+
default:
{
jsonWriter.WritePropertyName("value");
@@ -3962,6 +4102,7 @@ namespace DnsServerCore
case DnsResourceRecordType.CNAME:
case DnsResourceRecordType.PTR:
case DnsResourceRecordType.ANAME:
+ case DnsResourceRecordType.APP:
_dnsServer.AuthZoneManager.DeleteRecords(domain, type);
break;
@@ -4327,6 +4468,26 @@ namespace DnsServerCore
}
break;
+ case DnsResourceRecordType.APP:
+ {
+ string classPath = request.QueryString["classPath"];
+ if (string.IsNullOrEmpty(classPath))
+ throw new DnsWebServiceException("Parameter 'classPath' missing.");
+
+ string recordData = request.QueryString["recordData"];
+ if (string.IsNullOrEmpty(recordData))
+ recordData = "";
+
+ DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsApplicationRecord(value, classPath, recordData));
+ DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsApplicationRecord(newValue, classPath, recordData));
+
+ if (disable)
+ newRecord.Disable();
+
+ _dnsServer.AuthZoneManager.UpdateRecord(oldRecord, newRecord);
+ }
+ break;
+
default:
throw new DnsWebServiceException("Type not supported for UpdateRecords().");
}
@@ -4340,7 +4501,167 @@ namespace DnsServerCore
#region dns apps api
+ private void ListApps(JsonTextWriter jsonWriter)
+ {
+ List apps = new List(_dnsServer.DnsApplicationManager.Applications.Keys);
+ apps.Sort();
+
+ jsonWriter.WritePropertyName("apps");
+ jsonWriter.WriteStartArray();
+
+ foreach (string app in apps)
+ {
+ if (_dnsServer.DnsApplicationManager.Applications.TryGetValue(app, out DnsApplication application))
+ {
+ jsonWriter.WriteStartObject();
+
+ jsonWriter.WritePropertyName("name");
+ jsonWriter.WriteValue(application.AppName);
+
+ jsonWriter.WritePropertyName("details");
+ jsonWriter.WriteStartArray();
+
+ foreach (KeyValuePair handler in application.DnsRequestHandlers)
+ {
+ jsonWriter.WriteStartObject();
+
+ jsonWriter.WritePropertyName("classPath");
+ jsonWriter.WriteValue(handler.Key);
+
+ jsonWriter.WritePropertyName("description");
+ jsonWriter.WriteValue(handler.Value.Description);
+
+ jsonWriter.WritePropertyName("dataTemplate");
+ jsonWriter.WriteValue(handler.Value.ApplicationRecordDataTemplate);
+
+ jsonWriter.WriteEndObject();
+ }
+
+ jsonWriter.WriteEndArray();
+
+ jsonWriter.WriteEndObject();
+ }
+ }
+
+ jsonWriter.WriteEndArray();
+ }
+
+ private async Task InstallAppAsync(HttpListenerRequest request)
+ {
+ string name = request.QueryString["name"];
+ if (string.IsNullOrEmpty(name))
+ throw new DnsWebServiceException("Parameter 'name' missing.");
+
+ #region skip to content
+
+ int crlfCount = 0;
+ int byteRead;
+
+ while (crlfCount != 4)
+ {
+ byteRead = request.InputStream.ReadByte();
+ switch (byteRead)
+ {
+ case -1:
+ throw new EndOfStreamException();
+
+ case 13: //CR
+ case 10: //LF
+ crlfCount++;
+ break;
+
+ default:
+ crlfCount = 0;
+ break;
+ }
+ }
+
+ #endregion
+
+ //write to temp file
+ string tmpFile = Path.GetTempFileName();
+ try
+ {
+ using (FileStream fS = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite))
+ {
+ await request.InputStream.CopyToAsync(fS);
+
+ fS.Position = 0;
+ await _dnsServer.DnsApplicationManager.InstallApplicationAsync(name, fS);
+
+ _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DNS application was installed successfully: " + name);
+ }
+ }
+ finally
+ {
+ try
+ {
+ File.Delete(tmpFile);
+ }
+ catch (Exception ex)
+ {
+ _log.Write(ex);
+ }
+ }
+ }
+
+ private void UninstallApp(HttpListenerRequest request)
+ {
+ string name = request.QueryString["name"];
+ if (string.IsNullOrEmpty(name))
+ throw new DnsWebServiceException("Parameter 'name' missing.");
+
+ _dnsServer.DnsApplicationManager.UninstallApplication(name);
+ _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DNS application was uninstalled successfully: " + name);
+ }
+
+ private async Task GetAppConfigAsync(HttpListenerRequest request, JsonTextWriter jsonWriter)
+ {
+ string name = request.QueryString["name"];
+ if (string.IsNullOrEmpty(name))
+ throw new DnsWebServiceException("Parameter 'name' missing.");
+
+ if (!_dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application))
+ throw new DnsWebServiceException("DNS application was not found: " + name);
+
+ string config = await application.GetConfigAsync();
+
+ jsonWriter.WritePropertyName("config");
+ jsonWriter.WriteValue(config);
+ }
+
+ private async Task SetAppConfigAsync(HttpListenerRequest request)
+ {
+ string name = request.QueryString["name"];
+ if (string.IsNullOrEmpty(name))
+ throw new DnsWebServiceException("Parameter 'name' missing.");
+
+ if (!_dnsServer.DnsApplicationManager.Applications.TryGetValue(name, out DnsApplication application))
+ throw new DnsWebServiceException("DNS application was not found: " + name);
+
+ 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("config="))
+ {
+ string config = formPart.Substring(7);
+
+ if (config.Length == 0)
+ config = null;
+
+ await application.SetConfigAsync(config);
+ break;
+ }
+ }
+ }
#endregion
@@ -6016,8 +6337,8 @@ namespace DnsServerCore
//load config
LoadConfigFile();
- //load dns application packages
- _dnsServer.DnsApplicationManager.LoadAllPackages();
+ //load all dns applications
+ _dnsServer.DnsApplicationManager.LoadAllApplications();
//load all zones files
_dnsServer.AuthZoneManager.LoadAllZoneFiles();