mirror of
https://github.com/TechnitiumSoftware/DnsServer.git
synced 2026-03-02 14:59:01 +00:00
615 lines
30 KiB
C#
615 lines
30 KiB
C#
/*
|
|
Technitium DNS Server
|
|
Copyright (C) 2025 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
using DnsServerCore.Auth;
|
|
using DnsServerCore.Cluster;
|
|
using Microsoft.AspNetCore.Http;
|
|
using System;
|
|
using System.Buffers.Text;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Net.NetworkInformation;
|
|
using System.Net.Sockets;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.Text.Json;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace DnsServerCore
|
|
{
|
|
public partial class DnsWebService
|
|
{
|
|
sealed class WebServiceClusterApi
|
|
{
|
|
#region variables
|
|
|
|
readonly DnsWebService _dnsWebService;
|
|
|
|
#endregion
|
|
|
|
#region constructor
|
|
|
|
public WebServiceClusterApi(DnsWebService dnsWebService)
|
|
{
|
|
_dnsWebService = dnsWebService;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region private
|
|
|
|
private void WriteClusterState(Utf8JsonWriter jsonWriter, bool includeServerIpAddresses = false)
|
|
{
|
|
jsonWriter.WriteString("version", _dnsWebService.GetServerVersion());
|
|
jsonWriter.WriteString("dnsServerDomain", _dnsWebService._dnsServer.ServerDomain);
|
|
jsonWriter.WriteBoolean("clusterInitialized", _dnsWebService._clusterManager.ClusterInitialized);
|
|
|
|
if (_dnsWebService._clusterManager.ClusterInitialized)
|
|
{
|
|
jsonWriter.WriteString("clusterDomain", _dnsWebService._clusterManager.ClusterDomain);
|
|
|
|
jsonWriter.WriteNumber("heartbeatRefreshIntervalSeconds", _dnsWebService._clusterManager.HeartbeatRefreshIntervalSeconds);
|
|
jsonWriter.WriteNumber("heartbeatRetryIntervalSeconds", _dnsWebService._clusterManager.HeartBeatRetryIntervalSeconds);
|
|
jsonWriter.WriteNumber("configRefreshIntervalSeconds", _dnsWebService._clusterManager.ConfigRefreshIntervalSeconds);
|
|
jsonWriter.WriteNumber("configRetryIntervalSeconds", _dnsWebService._clusterManager.ConfigRetryIntervalSeconds);
|
|
|
|
WriteClusterNodes(jsonWriter);
|
|
}
|
|
|
|
if (includeServerIpAddresses)
|
|
{
|
|
jsonWriter.WriteStartArray("serverIpAddresses");
|
|
|
|
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces())
|
|
{
|
|
if (networkInterface.OperationalStatus != OperationalStatus.Up)
|
|
continue;
|
|
|
|
foreach (UnicastIPAddressInformation ip in networkInterface.GetIPProperties().UnicastAddresses)
|
|
{
|
|
if (IPAddress.IsLoopback(ip.Address))
|
|
continue;
|
|
|
|
switch (ip.Address.AddressFamily)
|
|
{
|
|
case AddressFamily.InterNetwork:
|
|
jsonWriter.WriteStringValue(ip.Address.ToString());
|
|
break;
|
|
|
|
case AddressFamily.InterNetworkV6:
|
|
if (ip.Address.IsIPv6LinkLocal || ip.Address.IsIPv6Teredo)
|
|
continue;
|
|
|
|
jsonWriter.WriteStringValue(ip.Address.ToString());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
jsonWriter.WriteEndArray();
|
|
}
|
|
}
|
|
|
|
internal void WriteClusterNodes(Utf8JsonWriter jsonWriter)
|
|
{
|
|
List<ClusterNode> sortedClusterNodes = [.. _dnsWebService._clusterManager.ClusterNodes.Values];
|
|
sortedClusterNodes.Sort();
|
|
|
|
jsonWriter.WriteStartArray("clusterNodes");
|
|
|
|
foreach (ClusterNode clusterNode in sortedClusterNodes)
|
|
{
|
|
jsonWriter.WriteStartObject();
|
|
|
|
jsonWriter.WriteNumber("id", clusterNode.Id);
|
|
jsonWriter.WriteString("name", clusterNode.Name);
|
|
jsonWriter.WriteString("url", clusterNode.Url.OriginalString);
|
|
|
|
jsonWriter.WriteStartArray("ipAddresses");
|
|
|
|
foreach (IPAddress ipAddress in clusterNode.IPAddresses)
|
|
jsonWriter.WriteStringValue(ipAddress.ToString());
|
|
|
|
jsonWriter.WriteEndArray();
|
|
|
|
jsonWriter.WriteString("type", clusterNode.Type.ToString());
|
|
jsonWriter.WriteString("state", clusterNode.State.ToString());
|
|
|
|
if (clusterNode.State == ClusterNodeState.Self)
|
|
{
|
|
jsonWriter.WriteString("upSince", clusterNode.UpSince);
|
|
|
|
if (clusterNode.Type == ClusterNodeType.Secondary)
|
|
{
|
|
if (_dnsWebService._clusterManager.ConfigLastSynced != default)
|
|
jsonWriter.WriteString("configLastSynced", _dnsWebService._clusterManager.ConfigLastSynced);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (clusterNode.UpSince != default)
|
|
jsonWriter.WriteString("upSince", clusterNode.UpSince);
|
|
|
|
if (clusterNode.LastSeen != default)
|
|
jsonWriter.WriteString("lastSeen", clusterNode.LastSeen);
|
|
}
|
|
|
|
jsonWriter.WriteEndObject();
|
|
}
|
|
|
|
jsonWriter.WriteEndArray();
|
|
}
|
|
|
|
private void EnableWebServiceTlsWithSelfSignedCertificate()
|
|
{
|
|
_dnsWebService._webServiceEnableTls = true;
|
|
_dnsWebService._webServiceUseSelfSignedTlsCertificate = true;
|
|
_dnsWebService._webServiceTlsCertificatePath = null;
|
|
_dnsWebService._webServiceTlsCertificatePassword = null;
|
|
|
|
_dnsWebService.CheckAndLoadSelfSignedCertificate(false, true);
|
|
|
|
_dnsWebService.SaveConfigFile();
|
|
}
|
|
|
|
private void RestartWebService()
|
|
{
|
|
ThreadPool.QueueUserWorkItem(async delegate (object state)
|
|
{
|
|
try
|
|
{
|
|
await Task.Delay(2000); //wait for the current HTTP response to be delivered before restarting web server
|
|
|
|
_dnsWebService._log.Write("Attempting to restart web service.");
|
|
|
|
await _dnsWebService.StopWebServiceAsync();
|
|
await _dnsWebService.StartWebServiceAsync(false);
|
|
|
|
_dnsWebService._log.Write("Web service was restarted successfully.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_dnsWebService._log.Write("Failed to restart web service.\r\n" + ex.ToString());
|
|
_dnsWebService._log.Write("Attempting to restart web service in HTTP only mode.");
|
|
|
|
try
|
|
{
|
|
await _dnsWebService.StopWebServiceAsync();
|
|
await _dnsWebService.StartWebServiceAsync(true);
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
_dnsWebService._log.Write("Failed to restart web service in HTTP only mode.\r\n" + ex2.ToString());
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region public
|
|
|
|
public void GetClusterState(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.View))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
bool includeServerIpAddresses = request.GetQueryOrForm("includeServerIpAddresses", bool.Parse, false);
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter, includeServerIpAddresses);
|
|
}
|
|
|
|
public void InitializeCluster(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Delete))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
string clusterDomain = request.GetQueryOrForm("clusterDomain").TrimEnd('.');
|
|
|
|
if (!request.TryGetQueryOrFormArray("primaryNodeIpAddresses", IPAddress.Parse, out IPAddress[] primaryNodeIpAddresses))
|
|
throw new DnsWebServiceException("Parameter 'primaryNodeIpAddresses' missing.");
|
|
|
|
bool restartWebService = false;
|
|
|
|
//enable TLS web service if not already enabled
|
|
if (!_dnsWebService.IsWebServiceTlsEnabled)
|
|
{
|
|
EnableWebServiceTlsWithSelfSignedCertificate();
|
|
restartWebService = true;
|
|
}
|
|
|
|
try
|
|
{
|
|
_dnsWebService._clusterManager.InitializeCluster(clusterDomain, primaryNodeIpAddresses, context.GetCurrentSession());
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Cluster (" + _dnsWebService._clusterManager.ClusterDomain + ") was initialized successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
finally
|
|
{
|
|
//restart TLS web service to apply HTTPS changes
|
|
if (restartWebService)
|
|
RestartWebService();
|
|
}
|
|
}
|
|
|
|
public void DeleteCluster(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Delete))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
bool forceDelete = request.GetQueryOrForm("forceDelete", bool.Parse, false);
|
|
|
|
string clusterDomain = _dnsWebService._clusterManager.ClusterDomain;
|
|
_dnsWebService._clusterManager.DeleteCluster(forceDelete);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Cluster (" + clusterDomain + ") was deleted successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
|
|
public void JoinCluster(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Delete))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
int secondaryNodeId = request.GetQueryOrForm("secondaryNodeId", int.Parse);
|
|
Uri secondaryNodeUrl = new Uri(request.GetQueryOrForm("secondaryNodeUrl"));
|
|
|
|
if (!request.TryGetQueryOrFormArray("secondaryNodeIpAddresses", IPAddress.Parse, out IPAddress[] secondaryNodeIpAddresses))
|
|
throw new DnsWebServiceException("Parameter 'secondaryNodeIpAddresses' missing.");
|
|
|
|
X509Certificate2 secondaryNodeCertificate = X509CertificateLoader.LoadCertificate(Base64Url.DecodeFromChars(request.GetQueryOrForm("secondaryNodeCertificate")));
|
|
|
|
ClusterNode secondaryNode = _dnsWebService._clusterManager.JoinCluster(secondaryNodeId, secondaryNodeUrl, secondaryNodeIpAddresses, secondaryNodeCertificate);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Secondary node '" + secondaryNode.ToString() + "' joined the Cluster (" + _dnsWebService._clusterManager.ClusterDomain + ") successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
|
|
public async Task RemoveSecondaryNodeAsync(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Delete))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
int secondaryNodeId = request.GetQueryOrForm("secondaryNodeId", int.Parse);
|
|
|
|
ClusterNode secondaryNode = await _dnsWebService._clusterManager.AskSecondaryNodeToLeaveClusterAsync(secondaryNodeId);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Secondary node '" + secondaryNode.ToString() + "' was asked to leave the Cluster (" + _dnsWebService._clusterManager.ClusterDomain + ") successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
|
|
public void DeleteSecondaryNode(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Delete))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
int secondaryNodeId = request.GetQueryOrForm("secondaryNodeId", int.Parse);
|
|
|
|
ClusterNode secondaryNode = _dnsWebService._clusterManager.DeleteSecondaryNode(secondaryNodeId);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Secondary node '" + secondaryNode.ToString() + "' was deleted from the Cluster (" + _dnsWebService._clusterManager.ClusterDomain + ") successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
|
|
public void UpdateSecondaryNode(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Delete))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
int secondaryNodeId = request.GetQueryOrForm("secondaryNodeId", int.Parse);
|
|
Uri secondaryNodeUrl = new Uri(request.GetQueryOrForm("secondaryNodeUrl"));
|
|
|
|
if (!request.TryGetQueryOrFormArray("secondaryNodeIpAddresses", IPAddress.Parse, out IPAddress[] secondaryNodeIpAddresses))
|
|
throw new DnsWebServiceException("Parameter 'secondaryNodeIpAddresses' missing.");
|
|
|
|
X509Certificate2 secondaryNodeCertificate = X509CertificateLoader.LoadCertificate(Base64Url.DecodeFromChars(request.GetQueryOrForm("secondaryNodeCertificate")));
|
|
|
|
ClusterNode secondaryNode = _dnsWebService._clusterManager.UpdateSecondaryNode(secondaryNodeId, secondaryNodeUrl, secondaryNodeIpAddresses, secondaryNodeCertificate);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Secondary node '" + secondaryNode.ToString() + "' details were updated successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
|
|
public async Task TransferConfigAsync(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Delete))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
string ifModifiedSinceValue = request.Headers.IfModifiedSince;
|
|
string includeZonesValue = request.QueryOrForm("includeZones");
|
|
|
|
DateTime ifModifiedSince = string.IsNullOrEmpty(ifModifiedSinceValue) ? DateTime.UnixEpoch : DateTime.ParseExact(ifModifiedSinceValue, "R", CultureInfo.InvariantCulture);
|
|
string[] includeZones = string.IsNullOrEmpty(includeZonesValue) ? null : includeZonesValue.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
|
|
|
string tmpFile = Path.GetTempFileName();
|
|
try
|
|
{
|
|
await using (FileStream configZipStream = new FileStream(tmpFile, FileMode.Create, FileAccess.ReadWrite))
|
|
{
|
|
//create config zip file
|
|
await _dnsWebService._clusterManager.TransferConfigAsync(configZipStream, ifModifiedSince, includeZones);
|
|
|
|
//send config zip file
|
|
configZipStream.Position = 0;
|
|
|
|
HttpResponse response = context.Response;
|
|
|
|
response.ContentType = "application/zip";
|
|
response.ContentLength = configZipStream.Length;
|
|
response.Headers.LastModified = DateTime.UtcNow.ToString("R");
|
|
response.Headers.Append("Content-Disposition", "attachment; filename=\"config.zip\"");
|
|
|
|
await using (Stream output = response.Body)
|
|
{
|
|
await configZipStream.CopyToAsync(output);
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
try
|
|
{
|
|
File.Delete(tmpFile);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_dnsWebService._log.Write(ex);
|
|
}
|
|
}
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Server configuration was transferred successfully.");
|
|
}
|
|
|
|
public void SetClusterOptions(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Modify))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
ushort heartbeatRefreshIntervalSeconds = request.GetQueryOrForm("heartbeatRefreshIntervalSeconds", ushort.Parse, _dnsWebService._clusterManager.HeartbeatRefreshIntervalSeconds);
|
|
ushort heartbeatRetryIntervalSeconds = request.GetQueryOrForm("heartbeatRetryIntervalSeconds", ushort.Parse, _dnsWebService._clusterManager.HeartBeatRetryIntervalSeconds);
|
|
ushort configRefreshIntervalSeconds = request.GetQueryOrForm("configRefreshIntervalSeconds", ushort.Parse, _dnsWebService._clusterManager.ConfigRefreshIntervalSeconds);
|
|
ushort configRetryIntervalSeconds = request.GetQueryOrForm("configRetryIntervalSeconds", ushort.Parse, _dnsWebService._clusterManager.ConfigRetryIntervalSeconds);
|
|
|
|
_dnsWebService._clusterManager.UpdateClusterOptions(heartbeatRefreshIntervalSeconds, heartbeatRetryIntervalSeconds, configRefreshIntervalSeconds, configRetryIntervalSeconds);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Cluster (" + _dnsWebService._clusterManager.ClusterDomain + ") options were updated successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
|
|
public async Task InitializeAndJoinClusterAsync(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Delete))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
if (!request.TryGetQueryOrFormArray("secondaryNodeIpAddresses", IPAddress.Parse, out IPAddress[] secondaryNodeIpAddresses))
|
|
throw new DnsWebServiceException("Parameter 'secondaryNodeIpAddresses' missing.");
|
|
|
|
Uri primaryNodeUrl = new Uri(request.GetQueryOrForm("primaryNodeUrl"));
|
|
IPAddress primaryNodeIpAddress = request.GetQueryOrForm("primaryNodeIpAddress", IPAddress.Parse, null);
|
|
string primaryNodeUsername = request.GetQueryOrForm("primaryNodeUsername");
|
|
string primaryNodePassword = request.GetQueryOrForm("primaryNodePassword");
|
|
string primaryNodeTotp = request.GetQueryOrForm("primaryNodeTotp", null);
|
|
bool ignoreCertificateErrors = request.GetQueryOrForm("ignoreCertificateErrors", bool.Parse, false);
|
|
|
|
bool restartWebService = false;
|
|
|
|
//enable TLS web service if not already enabled
|
|
if (!_dnsWebService.IsWebServiceTlsEnabled)
|
|
{
|
|
EnableWebServiceTlsWithSelfSignedCertificate();
|
|
restartWebService = true;
|
|
}
|
|
|
|
try
|
|
{
|
|
await _dnsWebService._clusterManager.InitializeAndJoinClusterAsync(secondaryNodeIpAddresses, primaryNodeUrl, primaryNodeUsername, primaryNodePassword, primaryNodeTotp, primaryNodeIpAddress is null ? null : [primaryNodeIpAddress], ignoreCertificateErrors);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Joined the Cluster (" + _dnsWebService._clusterManager.ClusterDomain + ") as a Secondary node successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
finally
|
|
{
|
|
//restart TLS web service to apply HTTPS changes
|
|
if (restartWebService)
|
|
RestartWebService();
|
|
}
|
|
}
|
|
|
|
public async Task LeaveClusterAsync(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Delete))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
bool forceLeave = request.GetQueryOrForm("forceLeave", bool.Parse, false);
|
|
|
|
string clusterDomain = _dnsWebService._clusterManager.ClusterDomain;
|
|
await _dnsWebService._clusterManager.LeaveClusterAsync(forceLeave);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Left the Cluster (" + clusterDomain + ") successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
|
|
public async Task ConfigUpdateNotificationAsync(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Delete))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
int primaryNodeId = request.GetQueryOrForm("primaryNodeId", int.Parse);
|
|
Uri primaryNodeUrl = new Uri(request.GetQueryOrForm("primaryNodeUrl"));
|
|
|
|
if (!request.TryGetQueryOrFormArray("primaryNodeIpAddresses", IPAddress.Parse, out IPAddress[] primaryNodeIpAddresses))
|
|
throw new DnsWebServiceException("Parameter 'primaryNodeIpAddresses' missing.");
|
|
|
|
//update primary node
|
|
ClusterNode primaryNode = await _dnsWebService._clusterManager.UpdatePrimaryNodeAsync(primaryNodeUrl, primaryNodeIpAddresses, primaryNodeId);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Notification for configuration update was received. Primary node '" + primaryNode.ToString() + "' details were updated successfully.");
|
|
}
|
|
|
|
public void ResyncCluster(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Modify))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
_dnsWebService._clusterManager.TriggerResyncForConfig();
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Resync for configuration and Cluster Secondary zones was triggered successfully.");
|
|
}
|
|
|
|
public async Task UpdatePrimaryNodeAsync(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Modify))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
Uri primaryNodeUrl = new Uri(request.GetQueryOrForm("primaryNodeUrl"));
|
|
|
|
if (!request.TryGetQueryOrFormArray("primaryNodeIpAddresses", IPAddress.Parse, out IPAddress[] primaryNodeIpAddresses))
|
|
primaryNodeIpAddresses = null;
|
|
|
|
//update primary node
|
|
ClusterNode primaryNode = await _dnsWebService._clusterManager.UpdatePrimaryNodeAsync(primaryNodeUrl, primaryNodeIpAddresses);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] Primary node '" + primaryNode.ToString() + "' details were updated successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
|
|
public async Task PromoteToPrimaryNodeAsync(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Delete))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
bool forceDeletePrimary = request.GetQueryOrForm("forceDeletePrimary", bool.Parse, false);
|
|
|
|
//promote to primary node
|
|
await _dnsWebService._clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] This Secondary node was promoted to be a Primary node for the Cluster successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
|
|
public void UpdateSelfNodeIPAddress(HttpContext context)
|
|
{
|
|
User sessionUser = _dnsWebService.GetSessionUser(context);
|
|
|
|
if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, sessionUser, PermissionFlag.Modify))
|
|
throw new DnsWebServiceException("Access was denied.");
|
|
|
|
HttpRequest request = context.Request;
|
|
|
|
if (!request.TryGetQueryOrFormArray("ipAddresses", IPAddress.Parse, out IPAddress[] ipAddresses))
|
|
throw new DnsWebServiceException("Parameter 'ipAddresses' missing.");
|
|
|
|
//update self node IP address
|
|
ClusterNode selfNode = _dnsWebService._clusterManager.UpdateSelfNodeIPAddresses(ipAddresses);
|
|
|
|
_dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + sessionUser.Username + "] " + selfNode.Type.ToString() + " node '" + selfNode.ToString() + "' IP address was updated successfully.");
|
|
|
|
Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
|
|
WriteClusterState(jsonWriter);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
}
|