/*
Technitium DNS Server
Copyright (C) 2024 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.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using TechnitiumLibrary;
using TechnitiumLibrary.Net.Dns.ResourceRecords;
namespace DnsServerCore.Dns.ResourceRecords
{
static class DnsResourceRecordExtensions
{
public static void SetGlueRecords(this DnsResourceRecord record, string glueAddresses)
{
if (record.RDATA is not DnsNSRecordData nsRecord)
throw new InvalidOperationException();
string domain = nsRecord.NameServer;
IReadOnlyList glueAddressesList = glueAddresses.Split(IPAddress.Parse, ',');
DnsResourceRecord[] glueRecords = new DnsResourceRecord[glueAddressesList.Count];
for (int i = 0; i < glueRecords.Length; i++)
{
switch (glueAddressesList[i].AddressFamily)
{
case AddressFamily.InterNetwork:
glueRecords[i] = new DnsResourceRecord(domain, DnsResourceRecordType.A, DnsClass.IN, record.TTL, new DnsARecordData(glueAddressesList[i]));
break;
case AddressFamily.InterNetworkV6:
glueRecords[i] = new DnsResourceRecord(domain, DnsResourceRecordType.AAAA, DnsClass.IN, record.TTL, new DnsAAAARecordData(glueAddressesList[i]));
break;
}
}
record.GetAuthNSRecordInfo().GlueRecords = glueRecords;
}
public static void SyncGlueRecords(this DnsResourceRecord record, IReadOnlyList allGlueRecords)
{
if (record.RDATA is not DnsNSRecordData nsRecord)
throw new InvalidOperationException();
string domain = nsRecord.NameServer;
List foundGlueRecords = new List(2);
foreach (DnsResourceRecord glueRecord in allGlueRecords)
{
switch (glueRecord.Type)
{
case DnsResourceRecordType.A:
case DnsResourceRecordType.AAAA:
if (glueRecord.Name.Equals(domain, StringComparison.OrdinalIgnoreCase))
foundGlueRecords.Add(glueRecord);
break;
}
}
record.GetAuthNSRecordInfo().GlueRecords = foundGlueRecords;
}
public static void SyncGlueRecords(this DnsResourceRecord record, IReadOnlyCollection deletedGlueRecords, IReadOnlyCollection addedGlueRecords)
{
if (record.RDATA is not DnsNSRecordData nsRecord)
throw new InvalidOperationException();
bool updated = false;
List updatedGlueRecords = new List();
IReadOnlyList existingGlueRecords = record.GetAuthNSRecordInfo().GlueRecords;
if (existingGlueRecords is not null)
{
foreach (DnsResourceRecord existingGlueRecord in existingGlueRecords)
{
if (deletedGlueRecords.Contains(existingGlueRecord))
updated = true; //skipped to delete existing glue record
else
updatedGlueRecords.Add(existingGlueRecord);
}
}
string domain = nsRecord.NameServer;
foreach (DnsResourceRecord addedGlueRecord in addedGlueRecords)
{
switch (addedGlueRecord.Type)
{
case DnsResourceRecordType.A:
case DnsResourceRecordType.AAAA:
if (addedGlueRecord.Name.Equals(domain, StringComparison.OrdinalIgnoreCase))
{
updatedGlueRecords.Add(addedGlueRecord);
updated = true;
}
break;
}
}
if (updated)
record.GetAuthNSRecordInfo().GlueRecords = updatedGlueRecords;
}
public static GenericRecordInfo GetAuthGenericRecordInfo(this DnsResourceRecord record)
{
if (record.Tag is null)
{
GenericRecordInfo rrInfo;
switch (record.Type)
{
case DnsResourceRecordType.NS:
rrInfo = new NSRecordInfo();
break;
case DnsResourceRecordType.SOA:
rrInfo = new SOARecordInfo();
break;
case DnsResourceRecordType.SVCB:
case DnsResourceRecordType.HTTPS:
rrInfo = new SVCBRecordInfo();
break;
default:
rrInfo = new GenericRecordInfo();
break;
}
record.Tag = rrInfo;
return rrInfo;
}
else if (record.Tag is GenericRecordInfo rrInfo)
{
return rrInfo;
}
else
{
throw new InvalidOperationException();
}
}
public static NSRecordInfo GetAuthNSRecordInfo(this DnsResourceRecord record)
{
if (record.Tag is null)
{
NSRecordInfo info = new NSRecordInfo();
record.Tag = info;
return info;
}
else if (record.Tag is NSRecordInfo nsInfo)
{
return nsInfo;
}
else
{
throw new InvalidOperationException();
}
}
public static SOARecordInfo GetAuthSOARecordInfo(this DnsResourceRecord record)
{
if (record.Tag is null)
{
SOARecordInfo info = new SOARecordInfo();
record.Tag = info;
return info;
}
else if (record.Tag is SOARecordInfo soaInfo)
{
return soaInfo;
}
else
{
throw new InvalidOperationException();
}
}
public static SVCBRecordInfo GetAuthSVCBRecordInfo(this DnsResourceRecord record)
{
if (record.Tag is null)
{
SVCBRecordInfo info = new SVCBRecordInfo();
record.Tag = info;
return info;
}
else if (record.Tag is SVCBRecordInfo svcbInfo)
{
return svcbInfo;
}
else
{
throw new InvalidOperationException();
}
}
public static HistoryRecordInfo GetAuthHistoryRecordInfo(this DnsResourceRecord record)
{
if (record.Tag is null)
{
HistoryRecordInfo info = new HistoryRecordInfo();
record.Tag = info;
return info;
}
else if (record.Tag is HistoryRecordInfo info)
{
return info;
}
else
{
throw new InvalidOperationException();
}
}
public static CacheRecordInfo GetCacheRecordInfo(this DnsResourceRecord record)
{
if (record.Tag is not CacheRecordInfo rrInfo)
{
rrInfo = new CacheRecordInfo();
record.Tag = rrInfo;
}
return rrInfo;
}
public static void CopyRecordInfoFrom(this DnsResourceRecord record, DnsResourceRecord otherRecord)
{
record.Tag = otherRecord.Tag;
}
}
}