/* Technitium DNS Server Copyright (C) 2023 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 DnsServerCore.Auth; using DnsServerCore.Dns.Zones; using Microsoft.AspNetCore.Http; using System.Collections.Generic; using System.IO; using System.Net; using System.Text.Json; using System.Threading.Tasks; using TechnitiumLibrary.Net; using TechnitiumLibrary.Net.Dns.ResourceRecords; namespace DnsServerCore { class WebServiceOtherZonesApi { #region variables readonly DnsWebService _dnsWebService; #endregion #region constructor public WebServiceOtherZonesApi(DnsWebService dnsWebService) { _dnsWebService = dnsWebService; } #endregion #region public #region cache api public void FlushCache(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Cache, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); _dnsWebService._dnsServer.CacheZoneManager.Flush(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Cache was flushed."); } public void ListCachedZones(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Cache, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; string domain = request.GetQuery("domain", ""); string direction = request.Query["direction"]; if (direction is not null) direction = direction.ToLower(); List subZones = new List(); List records = new List(); while (true) { subZones.Clear(); records.Clear(); _dnsWebService._dnsServer.CacheZoneManager.ListSubDomains(domain, subZones); _dnsWebService._dnsServer.CacheZoneManager.ListAllRecords(domain, records); if (records.Count > 0) break; if (subZones.Count != 1) break; if (direction == "up") { if (domain.Length == 0) break; int i = domain.IndexOf('.'); if (i < 0) domain = ""; else domain = domain.Substring(i + 1); } else if (domain.Length == 0) { domain = subZones[0]; } else { domain = subZones[0] + "." + domain; } } subZones.Sort(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WriteString("domain", domain); jsonWriter.WritePropertyName("zones"); jsonWriter.WriteStartArray(); if (domain.Length != 0) domain = "." + domain; foreach (string subZone in subZones) jsonWriter.WriteStringValue(subZone + domain); jsonWriter.WriteEndArray(); WebServiceZonesApi.WriteRecordsAsJson(records, jsonWriter, false); } public void DeleteCachedZone(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Cache, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string domain = context.Request.GetQuery("domain"); if (_dnsWebService._dnsServer.CacheZoneManager.DeleteZone(domain)) _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Cached zone was deleted: " + domain); } #endregion #region allowed zones api public void ListAllowedZones(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; string domain = request.GetQuery("domain", ""); string direction = request.Query["direction"]; if (direction is not null) direction = direction.ToLower(); List subZones = new List(); List records = new List(); while (true) { subZones.Clear(); records.Clear(); _dnsWebService._dnsServer.AllowedZoneManager.ListSubDomains(domain, subZones); _dnsWebService._dnsServer.AllowedZoneManager.ListAllRecords(domain, records); if (records.Count > 0) break; if (subZones.Count != 1) break; if (direction == "up") { if (domain.Length == 0) break; int i = domain.IndexOf('.'); if (i < 0) domain = ""; else domain = domain.Substring(i + 1); } else if (domain.Length == 0) { domain = subZones[0]; } else { domain = subZones[0] + "." + domain; } } subZones.Sort(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WriteString("domain", domain); jsonWriter.WritePropertyName("zones"); jsonWriter.WriteStartArray(); if (domain.Length != 0) domain = "." + domain; foreach (string subZone in subZones) jsonWriter.WriteStringValue(subZone + domain); jsonWriter.WriteEndArray(); WebServiceZonesApi.WriteRecordsAsJson(new List(records), jsonWriter, false); } public void ImportAllowedZones(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; if (!request.HasFormContentType) throw new DnsWebServiceException("Invalid content type. Expected application/x-www-form-urlencoded."); string allowedZones = request.Form["allowedZones"]; if (string.IsNullOrEmpty(allowedZones)) throw new DnsWebServiceException("Form parameter 'allowedZones' missing."); string[] allowedZonesList = allowedZones.Split(','); bool added = false; foreach (string allowedZone in allowedZonesList) { if (_dnsWebService._dnsServer.AllowedZoneManager.AllowZone(allowedZone)) added = true; } if (added) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Total " + allowedZonesList.Length + " zones were imported into allowed zone successfully."); _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); } } public async Task ExportAllowedZonesAsync(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); IReadOnlyList zoneInfoList = _dnsWebService._dnsServer.AllowedZoneManager.ListZones(); HttpResponse response = context.Response; response.ContentType = "text/plain"; response.Headers.ContentDisposition = "attachment;filename=AllowedZones.txt"; await using (StreamWriter sW = new StreamWriter(response.Body)) { foreach (AuthZoneInfo zoneInfo in zoneInfoList) await sW.WriteLineAsync(zoneInfo.Name); } } public void DeleteAllowedZone(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string domain = context.Request.GetQuery("domain"); if (_dnsWebService._dnsServer.AllowedZoneManager.DeleteZone(domain)) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Allowed zone was deleted: " + domain); _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); } } public void FlushAllowedZone(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); _dnsWebService._dnsServer.AllowedZoneManager.Flush(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Allowed zone was flushed successfully."); _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); } public void AllowZone(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Allowed, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); string domain = context.Request.GetQuery("domain"); if (IPAddress.TryParse(domain, out IPAddress ipAddress)) domain = ipAddress.GetReverseDomain(); if (_dnsWebService._dnsServer.AllowedZoneManager.AllowZone(domain)) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Zone was allowed: " + domain); _dnsWebService._dnsServer.AllowedZoneManager.SaveZoneFile(); } } #endregion #region blocked zones api public void ListBlockedZones(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; string domain = request.GetQuery("domain", ""); string direction = request.Query["direction"]; if (direction is not null) direction = direction.ToLower(); List subZones = new List(); List records = new List(); while (true) { subZones.Clear(); records.Clear(); _dnsWebService._dnsServer.BlockedZoneManager.ListSubDomains(domain, subZones); _dnsWebService._dnsServer.BlockedZoneManager.ListAllRecords(domain, records); if (records.Count > 0) break; if (subZones.Count != 1) break; if (direction == "up") { if (domain.Length == 0) break; int i = domain.IndexOf('.'); if (i < 0) domain = ""; else domain = domain.Substring(i + 1); } else if (domain.Length == 0) { domain = subZones[0]; } else { domain = subZones[0] + "." + domain; } } subZones.Sort(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WriteString("domain", domain); jsonWriter.WritePropertyName("zones"); jsonWriter.WriteStartArray(); if (domain.Length != 0) domain = "." + domain; foreach (string subZone in subZones) jsonWriter.WriteStringValue(subZone + domain); jsonWriter.WriteEndArray(); WebServiceZonesApi.WriteRecordsAsJson(new List(records), jsonWriter, false); } public void ImportBlockedZones(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; if (!request.HasFormContentType) throw new DnsWebServiceException("Invalid content type. Expected application/x-www-form-urlencoded."); string blockedZones = request.Form["blockedZones"]; if (string.IsNullOrEmpty(blockedZones)) throw new DnsWebServiceException("Form parameter 'blockedZones' missing."); string[] blockedZonesList = blockedZones.Split(','); bool added = false; foreach (string blockedZone in blockedZonesList) { if (_dnsWebService._dnsServer.BlockedZoneManager.BlockZone(blockedZone)) added = true; } if (added) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Total " + blockedZonesList.Length + " zones were imported into blocked zone successfully."); _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); } } public async Task ExportBlockedZonesAsync(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); IReadOnlyList zoneInfoList = _dnsWebService._dnsServer.BlockedZoneManager.ListZones(); HttpResponse response = context.Response; response.ContentType = "text/plain"; response.Headers.ContentDisposition = "attachment;filename=BlockedZones.txt"; await using (StreamWriter sW = new StreamWriter(response.Body)) { foreach (AuthZoneInfo zoneInfo in zoneInfoList) await sW.WriteLineAsync(zoneInfo.Name); } } public void DeleteBlockedZone(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string domain = context.Request.GetQuery("domain"); if (_dnsWebService._dnsServer.BlockedZoneManager.DeleteZone(domain)) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Blocked zone was deleted: " + domain); _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); } } public void FlushBlockedZone(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); _dnsWebService._dnsServer.BlockedZoneManager.Flush(); _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Blocked zone was flushed successfully."); _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); } public void BlockZone(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Blocked, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); string domain = context.Request.GetQuery("domain"); if (IPAddress.TryParse(domain, out IPAddress ipAddress)) domain = ipAddress.GetReverseDomain(); if (_dnsWebService._dnsServer.BlockedZoneManager.BlockZone(domain)) { _dnsWebService._log.Write(context.GetRemoteEndPoint(), "[" + session.User.Username + "] Domain was added to blocked zone: " + domain); _dnsWebService._dnsServer.BlockedZoneManager.SaveZoneFile(); } } #endregion #endregion } }