GeoDistanceApp: updated implementation to support EDNS Client Subnet.

This commit is contained in:
Shreyas Zare
2022-11-12 17:14:24 +05:30
parent a6efbb5c52
commit 8d8f91d4c0
2 changed files with 77 additions and 9 deletions

View File

@@ -28,6 +28,7 @@ using System.Net.Sockets;
using System.Threading.Tasks; using System.Threading.Tasks;
using TechnitiumLibrary; using TechnitiumLibrary;
using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns;
using TechnitiumLibrary.Net.Dns.EDnsOptions;
using TechnitiumLibrary.Net.Dns.ResourceRecords; using TechnitiumLibrary.Net.Dns.ResourceRecords;
namespace GeoDistance namespace GeoDistance
@@ -36,6 +37,7 @@ namespace GeoDistance
{ {
#region variables #region variables
IDnsServer _dnsServer;
MaxMind _maxMind; MaxMind _maxMind;
#endregion #endregion
@@ -84,6 +86,7 @@ namespace GeoDistance
public Task InitializeAsync(IDnsServer dnsServer, string config) public Task InitializeAsync(IDnsServer dnsServer, string config)
{ {
_dnsServer = dnsServer;
_maxMind = MaxMind.Create(dnsServer); _maxMind = MaxMind.Create(dnsServer);
return Task.CompletedTask; return Task.CompletedTask;
@@ -98,13 +101,34 @@ namespace GeoDistance
case DnsResourceRecordType.AAAA: case DnsResourceRecordType.AAAA:
Location location = null; Location location = null;
if (_maxMind.DatabaseReader.TryCity(remoteEP.Address, out CityResponse response)) EDnsClientSubnetOptionData clientSubnet = null;
if (request.EDNS is not null)
{
foreach (EDnsOption option in request.EDNS.Options)
{
if (option.Code == EDnsOptionCode.EDNS_CLIENT_SUBNET)
{
EDnsClientSubnetOptionData cs = option.Data as EDnsClientSubnetOptionData;
if (_maxMind.DatabaseReader.TryCity(cs.Address, out CityResponse csResponse) && csResponse.Location.HasCoordinates)
{
location = csResponse.Location;
clientSubnet = cs;
}
break;
}
}
}
if ((location is null) && _maxMind.DatabaseReader.TryCity(remoteEP.Address, out CityResponse response) && response.Location.HasCoordinates)
location = response.Location; location = response.Location;
dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData);
dynamic jsonClosestServer = null; dynamic jsonClosestServer = null;
if ((location == null) || !location.HasCoordinates) if (location is null)
{ {
jsonClosestServer = jsonAppRecordData[0]; jsonClosestServer = jsonAppRecordData[0];
} }
@@ -127,7 +151,7 @@ namespace GeoDistance
} }
} }
if (jsonClosestServer == null) if (jsonClosestServer is null)
return Task.FromResult<DnsDatagram>(null); return Task.FromResult<DnsDatagram>(null);
List<DnsResourceRecord> answers = new List<DnsResourceRecord>(); List<DnsResourceRecord> answers = new List<DnsResourceRecord>();
@@ -161,7 +185,17 @@ namespace GeoDistance
if (answers.Count > 1) if (answers.Count > 1)
answers.Shuffle(); answers.Shuffle();
return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)); EDnsOption[] options = null;
if (clientSubnet is not null)
{
options = new EDnsOption[]
{
new EDnsOption(EDnsOptionCode.EDNS_CLIENT_SUBNET, new EDnsClientSubnetOptionData(clientSubnet.SourcePrefixLength, clientSubnet.SourcePrefixLength, clientSubnet.Address))
};
}
return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options));
default: default:
return Task.FromResult<DnsDatagram>(null); return Task.FromResult<DnsDatagram>(null);

View File

@@ -26,6 +26,7 @@ using System.Collections.Generic;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using TechnitiumLibrary.Net.Dns; using TechnitiumLibrary.Net.Dns;
using TechnitiumLibrary.Net.Dns.EDnsOptions;
using TechnitiumLibrary.Net.Dns.ResourceRecords; using TechnitiumLibrary.Net.Dns.ResourceRecords;
namespace GeoDistance namespace GeoDistance
@@ -34,6 +35,7 @@ namespace GeoDistance
{ {
#region variables #region variables
IDnsServer _dnsServer;
MaxMind _maxMind; MaxMind _maxMind;
#endregion #endregion
@@ -82,6 +84,7 @@ namespace GeoDistance
public Task InitializeAsync(IDnsServer dnsServer, string config) public Task InitializeAsync(IDnsServer dnsServer, string config)
{ {
_dnsServer = dnsServer;
_maxMind = MaxMind.Create(dnsServer); _maxMind = MaxMind.Create(dnsServer);
return Task.CompletedTask; return Task.CompletedTask;
@@ -91,13 +94,34 @@ namespace GeoDistance
{ {
Location location = null; Location location = null;
if (_maxMind.DatabaseReader.TryCity(remoteEP.Address, out CityResponse response)) EDnsClientSubnetOptionData clientSubnet = null;
if (request.EDNS is not null)
{
foreach (EDnsOption option in request.EDNS.Options)
{
if (option.Code == EDnsOptionCode.EDNS_CLIENT_SUBNET)
{
EDnsClientSubnetOptionData cs = option.Data as EDnsClientSubnetOptionData;
if (_maxMind.DatabaseReader.TryCity(cs.Address, out CityResponse csResponse) && csResponse.Location.HasCoordinates)
{
location = csResponse.Location;
clientSubnet = cs;
}
break;
}
}
}
if ((location is null) && _maxMind.DatabaseReader.TryCity(remoteEP.Address, out CityResponse response) && response.Location.HasCoordinates)
location = response.Location; location = response.Location;
dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData); dynamic jsonAppRecordData = JsonConvert.DeserializeObject(appRecordData);
dynamic jsonClosestServer = null; dynamic jsonClosestServer = null;
if ((location == null) || !location.HasCoordinates) if (location is null)
{ {
jsonClosestServer = jsonAppRecordData[0]; jsonClosestServer = jsonAppRecordData[0];
} }
@@ -120,11 +144,11 @@ namespace GeoDistance
} }
} }
if (jsonClosestServer == null) if (jsonClosestServer is null)
return Task.FromResult<DnsDatagram>(null); return Task.FromResult<DnsDatagram>(null);
dynamic jsonCname = jsonClosestServer.cname; dynamic jsonCname = jsonClosestServer.cname;
if (jsonCname == null) if (jsonCname is null)
return Task.FromResult<DnsDatagram>(null); return Task.FromResult<DnsDatagram>(null);
string cname = jsonCname.Value; string cname = jsonCname.Value;
@@ -138,7 +162,17 @@ namespace GeoDistance
else else
answers = new DnsResourceRecord[] { new DnsResourceRecord(request.Question[0].Name, DnsResourceRecordType.CNAME, DnsClass.IN, appRecordTtl, new DnsCNAMERecordData(cname)) }; answers = new DnsResourceRecord[] { new DnsResourceRecord(request.Question[0].Name, DnsResourceRecordType.CNAME, DnsClass.IN, appRecordTtl, new DnsCNAMERecordData(cname)) };
return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers)); EDnsOption[] options = null;
if (clientSubnet is not null)
{
options = new EDnsOption[]
{
new EDnsOption(EDnsOptionCode.EDNS_CLIENT_SUBNET, new EDnsClientSubnetOptionData(clientSubnet.SourcePrefixLength, clientSubnet.SourcePrefixLength, clientSubnet.Address))
};
}
return Task.FromResult(new DnsDatagram(request.Identifier, true, request.OPCODE, true, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NoError, request.Question, answers, null, null, _dnsServer.UdpPayloadSize, EDnsHeaderFlags.None, options));
} }
#endregion #endregion