DnsServer.cs 108 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586
  1. /*
  2. Technitium DNS Server
  3. Copyright (C) 2020 Shreyas Zare (shreyas@technitium.com)
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. using DnsServerCore.Dns.ZoneManagers;
  16. using DnsServerCore.Dns.Zones;
  17. using Newtonsoft.Json;
  18. using System;
  19. using System.Collections.Generic;
  20. using System.IO;
  21. using System.Net;
  22. using System.Net.Security;
  23. using System.Net.Sockets;
  24. using System.Security.Cryptography.X509Certificates;
  25. using System.Text;
  26. using System.Threading;
  27. using System.Threading.Tasks;
  28. using TechnitiumLibrary.IO;
  29. using TechnitiumLibrary.Net;
  30. using TechnitiumLibrary.Net.Dns;
  31. using TechnitiumLibrary.Net.Dns.ResourceRecords;
  32. using TechnitiumLibrary.Net.Http;
  33. using TechnitiumLibrary.Net.Proxy;
  34. namespace DnsServerCore.Dns
  35. {
  36. public sealed class DnsServer : IDisposable
  37. {
  38. #region enum
  39. enum ServiceState
  40. {
  41. Stopped = 0,
  42. Starting = 1,
  43. Running = 2,
  44. Stopping = 3
  45. }
  46. #endregion
  47. #region variables
  48. const int MAX_CNAME_HOPS = 16;
  49. const int SERVE_STALE_WAIT_TIME = 1800;
  50. string _serverDomain;
  51. readonly string _configFolder;
  52. readonly string _dohwwwFolder;
  53. IReadOnlyList<IPEndPoint> _localEndPoints;
  54. LogManager _log;
  55. NameServerAddress _thisServer;
  56. readonly List<Socket> _udpListeners = new List<Socket>();
  57. readonly List<Socket> _tcpListeners = new List<Socket>();
  58. readonly List<Socket> _httpListeners = new List<Socket>();
  59. readonly List<Socket> _tlsListeners = new List<Socket>();
  60. readonly List<Socket> _httpsListeners = new List<Socket>();
  61. bool _enableDnsOverHttp;
  62. bool _enableDnsOverTls;
  63. bool _enableDnsOverHttps;
  64. bool _isDnsOverHttpsEnabled;
  65. X509Certificate2 _certificate;
  66. readonly AuthZoneManager _authZoneManager;
  67. readonly AllowedZoneManager _allowedZoneManager;
  68. readonly BlockedZoneManager _blockedZoneManager;
  69. readonly BlockListZoneManager _blockListZoneManager;
  70. readonly CacheZoneManager _cacheZoneManager = new CacheZoneManager();
  71. readonly ResolverDnsCache _dnsCache;
  72. readonly DnsARecord _aRecord = new DnsARecord(IPAddress.Any);
  73. readonly DnsAAAARecord _aaaaRecord = new DnsAAAARecord(IPAddress.IPv6Any);
  74. bool _allowRecursion;
  75. bool _allowRecursionOnlyForPrivateNetworks;
  76. NetProxy _proxy;
  77. IReadOnlyList<NameServerAddress> _forwarders;
  78. bool _preferIPv6;
  79. int _forwarderRetries = 3;
  80. int _resolverRetries = 5;
  81. int _forwarderTimeout = 4000;
  82. int _resolverTimeout = 4000;
  83. int _clientTimeout = 4000;
  84. int _forwarderConcurrency = 2;
  85. int _resolverMaxStackCount = 10;
  86. int _cachePrefetchEligibility = 2;
  87. int _cachePrefetchTrigger = 9;
  88. int _cachePrefetchSampleIntervalInMinutes = 5;
  89. int _cachePrefetchSampleEligibilityHitsPerHour = 30;
  90. LogManager _queryLog;
  91. readonly StatsManager _stats;
  92. int _tcpSendTimeout = 10000;
  93. int _tcpReceiveTimeout = 10000;
  94. Timer _cachePrefetchSamplingTimer;
  95. readonly object _cachePrefetchSamplingTimerLock = new object();
  96. Timer _cachePrefetchRefreshTimer;
  97. readonly object _cachePrefetchRefreshTimerLock = new object();
  98. const int CACHE_PREFETCH_REFRESH_TIMER_INITIAL_INTEVAL = 60000;
  99. DateTime _cachePrefetchSamplingTimerTriggersOn;
  100. IList<DnsQuestionRecord> _cachePrefetchSampleList;
  101. Timer _cacheMaintenanceTimer;
  102. const int CACHE_MAINTENANCE_TIMER_INITIAL_INTEVAL = 60 * 60 * 1000;
  103. const int CACHE_MAINTENANCE_TIMER_PERIODIC_INTERVAL = 60 * 60 * 1000;
  104. readonly IndependentTaskScheduler _resolverTaskScheduler = new IndependentTaskScheduler(ThreadPriority.AboveNormal);
  105. readonly DomainTree<Task<DnsDatagram>> _resolverTasks = new DomainTree<Task<DnsDatagram>>();
  106. volatile ServiceState _state = ServiceState.Stopped;
  107. #endregion
  108. #region constructor
  109. static DnsServer()
  110. {
  111. //set min threads since the default value is too small
  112. {
  113. ThreadPool.GetMinThreads(out int minWorker, out int minIOC);
  114. int minThreads = Environment.ProcessorCount * 256;
  115. if (minWorker < minThreads)
  116. minWorker = minThreads;
  117. if (minIOC < minThreads)
  118. minIOC = minThreads;
  119. ThreadPool.SetMinThreads(minWorker, minIOC);
  120. }
  121. if (ServicePointManager.DefaultConnectionLimit < 10)
  122. ServicePointManager.DefaultConnectionLimit = 10; //concurrent http request limit required when using DNS-over-HTTPS forwarders
  123. }
  124. public DnsServer(string configFolder, string dohwwwFolder, LogManager log = null)
  125. : this(Environment.MachineName.ToLower(), configFolder, dohwwwFolder, log)
  126. { }
  127. public DnsServer(string serverDomain, string configFolder, string dohwwwFolder, LogManager log = null)
  128. : this(serverDomain, configFolder, dohwwwFolder, new IPEndPoint[] { new IPEndPoint(IPAddress.Any, 53), new IPEndPoint(IPAddress.IPv6Any, 53) }, log)
  129. { }
  130. public DnsServer(string serverDomain, string configFolder, string dohwwwFolder, IPEndPoint localEndPoint, LogManager log = null)
  131. : this(serverDomain, configFolder, dohwwwFolder, new IPEndPoint[] { localEndPoint }, log)
  132. { }
  133. public DnsServer(string serverDomain, string configFolder, string dohwwwFolder, IReadOnlyList<IPEndPoint> localEndPoints, LogManager log = null)
  134. {
  135. _serverDomain = serverDomain;
  136. _configFolder = configFolder;
  137. _dohwwwFolder = dohwwwFolder;
  138. _localEndPoints = localEndPoints;
  139. _log = log;
  140. _authZoneManager = new AuthZoneManager(this);
  141. _allowedZoneManager = new AllowedZoneManager(this);
  142. _blockedZoneManager = new BlockedZoneManager(this);
  143. _blockListZoneManager = new BlockListZoneManager(this);
  144. _dnsCache = new ResolverDnsCache(_authZoneManager, _cacheZoneManager);
  145. //init stats
  146. string statsFolder = Path.Combine(_configFolder, "stats");
  147. if (!Directory.Exists(statsFolder))
  148. Directory.CreateDirectory(statsFolder);
  149. _stats = new StatsManager(statsFolder, _log);
  150. }
  151. #endregion
  152. #region IDisposable
  153. bool _disposed;
  154. private void Dispose(bool disposing)
  155. {
  156. if (_disposed)
  157. return;
  158. if (disposing)
  159. {
  160. Stop();
  161. if (_authZoneManager != null)
  162. _authZoneManager.Dispose();
  163. if (_stats != null)
  164. _stats.Dispose();
  165. }
  166. _disposed = true;
  167. }
  168. public void Dispose()
  169. {
  170. Dispose(true);
  171. }
  172. #endregion
  173. #region private
  174. private void ReadUdpRequestAsync(object parameter)
  175. {
  176. Socket udpListener = parameter as Socket;
  177. EndPoint remoteEP;
  178. byte[] recvBuffer = new byte[512];
  179. int bytesRecv;
  180. if (udpListener.AddressFamily == AddressFamily.InterNetwork)
  181. remoteEP = new IPEndPoint(IPAddress.Any, 0);
  182. else
  183. remoteEP = new IPEndPoint(IPAddress.IPv6Any, 0);
  184. try
  185. {
  186. while (true)
  187. {
  188. try
  189. {
  190. bytesRecv = udpListener.ReceiveFrom(recvBuffer, ref remoteEP);
  191. }
  192. catch (SocketException ex)
  193. {
  194. switch (ex.SocketErrorCode)
  195. {
  196. case SocketError.ConnectionReset:
  197. case SocketError.HostUnreachable:
  198. case SocketError.MessageSize:
  199. case SocketError.NetworkReset:
  200. bytesRecv = 0;
  201. break;
  202. default:
  203. throw;
  204. }
  205. }
  206. if (bytesRecv > 0)
  207. {
  208. try
  209. {
  210. DnsDatagram request = DnsDatagram.ReadFromUdp(new MemoryStream(recvBuffer, 0, bytesRecv, false));
  211. _ = ProcessUdpRequestAsync(udpListener, remoteEP as IPEndPoint, request);
  212. }
  213. catch (Exception ex)
  214. {
  215. LogManager log = _log;
  216. if (log != null)
  217. log.Write(remoteEP as IPEndPoint, DnsTransportProtocol.Udp, ex);
  218. }
  219. }
  220. }
  221. }
  222. catch (Exception ex)
  223. {
  224. if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped))
  225. return; //server stopping
  226. LogManager log = _log;
  227. if (log != null)
  228. log.Write(remoteEP as IPEndPoint, DnsTransportProtocol.Udp, ex);
  229. throw;
  230. }
  231. }
  232. private async Task ProcessUdpRequestAsync(Socket udpListener, IPEndPoint remoteEP, DnsDatagram request)
  233. {
  234. try
  235. {
  236. DnsDatagram response;
  237. if (request.ParsingException == null)
  238. {
  239. response = await ProcessQueryAsync(request, remoteEP, IsRecursionAllowed(remoteEP), DnsTransportProtocol.Udp);
  240. }
  241. else
  242. {
  243. //format error
  244. LogManager log = _log;
  245. if (log != null)
  246. log.Write(remoteEP, DnsTransportProtocol.Udp, request.ParsingException);
  247. //format error response
  248. response = new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, IsRecursionAllowed(remoteEP), false, false, DnsResponseCode.FormatError, request.Question);
  249. }
  250. //send response
  251. if (response != null)
  252. {
  253. byte[] sendBuffer = new byte[512];
  254. MemoryStream sendBufferStream = new MemoryStream(sendBuffer);
  255. try
  256. {
  257. response.WriteToUdp(sendBufferStream);
  258. }
  259. catch (NotSupportedException)
  260. {
  261. response = new DnsDatagram(response.Identifier, true, response.OPCODE, response.AuthoritativeAnswer, true, response.RecursionDesired, response.RecursionAvailable, response.AuthenticData, response.CheckingDisabled, response.RCODE, response.Question);
  262. sendBufferStream.Position = 0;
  263. response.WriteToUdp(sendBufferStream);
  264. }
  265. //send dns datagram async
  266. await udpListener.SendToAsync(sendBuffer, 0, (int)sendBufferStream.Position, remoteEP);
  267. LogManager queryLog = _queryLog;
  268. if (queryLog != null)
  269. queryLog.Write(remoteEP, DnsTransportProtocol.Udp, request, response);
  270. StatsManager stats = _stats;
  271. if (stats != null)
  272. stats.Update(response, remoteEP.Address);
  273. }
  274. }
  275. catch (Exception ex)
  276. {
  277. if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped))
  278. return; //server stopping
  279. LogManager queryLog = _queryLog;
  280. if (queryLog != null)
  281. queryLog.Write(remoteEP, DnsTransportProtocol.Udp, request, null);
  282. LogManager log = _log;
  283. if (log != null)
  284. log.Write(remoteEP, DnsTransportProtocol.Udp, ex);
  285. }
  286. }
  287. private void AcceptConnectionAsync(object parameter)
  288. {
  289. object[] parameters = parameter as object[];
  290. Socket tcpListener = parameters[0] as Socket;
  291. DnsTransportProtocol protocol = (DnsTransportProtocol)parameters[1];
  292. bool usingHttps = true;
  293. if (parameters.Length > 2)
  294. usingHttps = (bool)parameters[2];
  295. IPEndPoint localEP = tcpListener.LocalEndPoint as IPEndPoint;
  296. try
  297. {
  298. tcpListener.SendTimeout = _tcpSendTimeout;
  299. tcpListener.ReceiveTimeout = _tcpReceiveTimeout;
  300. tcpListener.SendBufferSize = 2048;
  301. tcpListener.ReceiveBufferSize = 512;
  302. tcpListener.NoDelay = true;
  303. while (true)
  304. {
  305. Socket socket = tcpListener.Accept();
  306. _ = ProcessConnectionAsync(socket, protocol, usingHttps);
  307. }
  308. }
  309. catch (Exception ex)
  310. {
  311. if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped))
  312. return; //server stopping
  313. LogManager log = _log;
  314. if (log != null)
  315. log.Write(localEP, protocol, ex);
  316. throw;
  317. }
  318. }
  319. private async Task ProcessConnectionAsync(Socket socket, DnsTransportProtocol protocol, bool usingHttps)
  320. {
  321. IPEndPoint remoteEP = null;
  322. try
  323. {
  324. remoteEP = socket.RemoteEndPoint as IPEndPoint;
  325. switch (protocol)
  326. {
  327. case DnsTransportProtocol.Tcp:
  328. await ReadStreamRequestAsync(new NetworkStream(socket), _tcpReceiveTimeout, remoteEP, protocol);
  329. break;
  330. case DnsTransportProtocol.Tls:
  331. SslStream tlsStream = new SslStream(new NetworkStream(socket));
  332. await tlsStream.AuthenticateAsServerAsync(_certificate);
  333. await ReadStreamRequestAsync(tlsStream, _tcpReceiveTimeout, remoteEP, protocol);
  334. break;
  335. case DnsTransportProtocol.Https:
  336. Stream stream = new NetworkStream(socket);
  337. if (usingHttps)
  338. {
  339. SslStream httpsStream = new SslStream(stream);
  340. await httpsStream.AuthenticateAsServerAsync(_certificate);
  341. stream = httpsStream;
  342. }
  343. await ProcessDoHRequestAsync(stream, _tcpReceiveTimeout, remoteEP, usingHttps);
  344. break;
  345. }
  346. }
  347. catch (IOException)
  348. {
  349. //ignore IO exceptions
  350. }
  351. catch (Exception ex)
  352. {
  353. LogManager log = _log;
  354. if (log != null)
  355. log.Write(remoteEP, protocol, ex);
  356. }
  357. finally
  358. {
  359. if (socket != null)
  360. socket.Dispose();
  361. }
  362. }
  363. private async Task ReadStreamRequestAsync(Stream stream, int receiveTimeout, IPEndPoint remoteEP, DnsTransportProtocol protocol)
  364. {
  365. try
  366. {
  367. MemoryStream readBuffer = new MemoryStream(64);
  368. MemoryStream writeBuffer = new MemoryStream(64);
  369. SemaphoreSlim writeSemaphore = new SemaphoreSlim(1, 1);
  370. while (true)
  371. {
  372. DnsDatagram request;
  373. //read dns datagram with timeout
  374. using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource())
  375. {
  376. Task<DnsDatagram> task = DnsDatagram.ReadFromTcpAsync(stream, readBuffer, cancellationTokenSource.Token);
  377. if (await Task.WhenAny(task, Task.Delay(receiveTimeout, cancellationTokenSource.Token)) != task)
  378. {
  379. //read timed out
  380. stream.Dispose();
  381. return;
  382. }
  383. cancellationTokenSource.Cancel(); //cancel delay task
  384. request = await task;
  385. }
  386. //process request async
  387. _ = ProcessStreamRequestAsync(stream, writeBuffer, writeSemaphore, remoteEP, request, protocol);
  388. }
  389. }
  390. catch (ObjectDisposedException)
  391. {
  392. //ignore
  393. }
  394. catch (IOException)
  395. {
  396. //ignore IO exceptions
  397. }
  398. catch (Exception ex)
  399. {
  400. LogManager log = _log;
  401. if (log != null)
  402. log.Write(remoteEP, protocol, ex);
  403. }
  404. }
  405. private async Task ProcessStreamRequestAsync(Stream stream, MemoryStream writeBuffer, SemaphoreSlim writeSemaphore, IPEndPoint remoteEP, DnsDatagram request, DnsTransportProtocol protocol)
  406. {
  407. try
  408. {
  409. DnsDatagram response;
  410. if (request.ParsingException == null)
  411. {
  412. response = await ProcessQueryAsync(request, remoteEP, IsRecursionAllowed(remoteEP), protocol);
  413. }
  414. else
  415. {
  416. //format error
  417. response = new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, IsRecursionAllowed(remoteEP), false, false, DnsResponseCode.FormatError, request.Question);
  418. LogManager queryLog = _queryLog;
  419. if (queryLog != null)
  420. queryLog.Write(remoteEP, protocol, request, response);
  421. LogManager log = _log;
  422. if (log != null)
  423. log.Write(remoteEP, protocol, request.ParsingException);
  424. }
  425. //send response
  426. if (response != null)
  427. {
  428. await writeSemaphore.WaitAsync();
  429. try
  430. {
  431. //send dns datagram
  432. await response.WriteToTcpAsync(stream, writeBuffer);
  433. await stream.FlushAsync();
  434. }
  435. finally
  436. {
  437. writeSemaphore.Release();
  438. }
  439. LogManager queryLog = _queryLog;
  440. if (queryLog != null)
  441. queryLog.Write(remoteEP, protocol, request, response);
  442. StatsManager stats = _stats;
  443. if (stats != null)
  444. stats.Update(response, remoteEP.Address);
  445. }
  446. }
  447. catch (IOException)
  448. {
  449. //ignore IO exceptions
  450. }
  451. catch (Exception ex)
  452. {
  453. LogManager queryLog = _queryLog;
  454. if ((queryLog != null) && (request != null))
  455. queryLog.Write(remoteEP, protocol, request, null);
  456. LogManager log = _log;
  457. if (log != null)
  458. log.Write(remoteEP, protocol, ex);
  459. }
  460. }
  461. private async Task ProcessDoHRequestAsync(Stream stream, int receiveTimeout, IPEndPoint remoteEP, bool usingHttps)
  462. {
  463. DnsDatagram dnsRequest = null;
  464. DnsTransportProtocol dnsProtocol = DnsTransportProtocol.Https;
  465. try
  466. {
  467. while (true)
  468. {
  469. HttpRequest httpRequest = await HttpRequest.ReadRequestAsync(stream).WithTimeout(receiveTimeout);
  470. if (httpRequest == null)
  471. return; //connection closed gracefully by client
  472. IPEndPoint socketRemoteEP = remoteEP;
  473. if (!usingHttps && NetUtilities.IsPrivateIP(socketRemoteEP.Address))
  474. {
  475. string xRealIp = httpRequest.Headers["X-Real-IP"];
  476. if (IPAddress.TryParse(xRealIp, out IPAddress address))
  477. {
  478. //get the real IP address of the requesting client from X-Real-IP header set in nginx proxy_pass block
  479. remoteEP = new IPEndPoint(address, 0);
  480. }
  481. }
  482. string requestConnection = httpRequest.Headers[HttpRequestHeader.Connection];
  483. if (string.IsNullOrEmpty(requestConnection))
  484. requestConnection = "close";
  485. switch (httpRequest.RequestPath)
  486. {
  487. case "/dns-query":
  488. if (!usingHttps && !NetUtilities.IsPrivateIP(socketRemoteEP.Address))
  489. {
  490. //intentionally blocking public IP addresses from using DNS-over-HTTP (without TLS)
  491. //this feature is intended to be used with an SSL terminated reverse proxy like nginx on private network
  492. await SendErrorAsync(stream, 403, "DNS-over-HTTPS (DoH) queries are supported only on HTTPS.");
  493. return;
  494. }
  495. DnsTransportProtocol protocol = DnsTransportProtocol.Udp;
  496. string strRequestAcceptTypes = httpRequest.Headers[HttpRequestHeader.Accept];
  497. if (!string.IsNullOrEmpty(strRequestAcceptTypes))
  498. {
  499. foreach (string acceptType in strRequestAcceptTypes.Split(','))
  500. {
  501. if (acceptType == "application/dns-message")
  502. {
  503. protocol = DnsTransportProtocol.Https;
  504. break;
  505. }
  506. else if (acceptType == "application/dns-json")
  507. {
  508. protocol = DnsTransportProtocol.HttpsJson;
  509. dnsProtocol = DnsTransportProtocol.HttpsJson;
  510. break;
  511. }
  512. }
  513. }
  514. switch (protocol)
  515. {
  516. case DnsTransportProtocol.Https:
  517. #region https wire format
  518. {
  519. switch (httpRequest.HttpMethod)
  520. {
  521. case "GET":
  522. string strRequest = httpRequest.QueryString["dns"];
  523. if (string.IsNullOrEmpty(strRequest))
  524. throw new ArgumentNullException("dns");
  525. //convert from base64url to base64
  526. strRequest = strRequest.Replace('-', '+');
  527. strRequest = strRequest.Replace('_', '/');
  528. //add padding
  529. int x = strRequest.Length % 4;
  530. if (x > 0)
  531. strRequest = strRequest.PadRight(strRequest.Length - x + 4, '=');
  532. dnsRequest = DnsDatagram.ReadFromUdp(new MemoryStream(Convert.FromBase64String(strRequest)));
  533. break;
  534. case "POST":
  535. string strContentType = httpRequest.Headers[HttpRequestHeader.ContentType];
  536. if (string.IsNullOrEmpty(strContentType))
  537. throw new DnsServerException("Missing Content-Type header.");
  538. if (strContentType != "application/dns-message")
  539. throw new NotSupportedException("DNS request type not supported: " + strContentType);
  540. using (MemoryStream mS = new MemoryStream())
  541. {
  542. await httpRequest.InputStream.CopyToAsync(mS, 512);
  543. mS.Position = 0;
  544. dnsRequest = DnsDatagram.ReadFromUdp(mS);
  545. }
  546. break;
  547. default:
  548. throw new NotSupportedException("DoH request type not supported.");
  549. }
  550. DnsDatagram dnsResponse;
  551. if (dnsRequest.ParsingException == null)
  552. {
  553. dnsResponse = await ProcessQueryAsync(dnsRequest, remoteEP, IsRecursionAllowed(remoteEP), protocol);
  554. }
  555. else
  556. {
  557. //format error
  558. LogManager log = _log;
  559. if (log != null)
  560. log.Write(remoteEP, protocol, dnsRequest.ParsingException);
  561. //format error response
  562. dnsResponse = new DnsDatagram(dnsRequest.Identifier, true, dnsRequest.OPCODE, false, false, dnsRequest.RecursionDesired, IsRecursionAllowed(remoteEP), false, false, DnsResponseCode.FormatError, dnsRequest.Question);
  563. }
  564. if (dnsResponse != null)
  565. {
  566. using (MemoryStream mS = new MemoryStream())
  567. {
  568. dnsResponse.WriteToUdp(mS);
  569. byte[] buffer = mS.ToArray();
  570. await SendContentAsync(stream, "application/dns-message", buffer);
  571. }
  572. LogManager queryLog = _queryLog;
  573. if (queryLog != null)
  574. queryLog.Write(remoteEP, protocol, dnsRequest, dnsResponse);
  575. StatsManager stats = _stats;
  576. if (stats != null)
  577. stats.Update(dnsResponse, remoteEP.Address);
  578. }
  579. }
  580. #endregion
  581. break;
  582. case DnsTransportProtocol.HttpsJson:
  583. #region https json format
  584. {
  585. string strName = httpRequest.QueryString["name"];
  586. if (string.IsNullOrEmpty(strName))
  587. throw new ArgumentNullException("name");
  588. string strType = httpRequest.QueryString["type"];
  589. if (string.IsNullOrEmpty(strType))
  590. strType = "1";
  591. dnsRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord(strName, (DnsResourceRecordType)int.Parse(strType), DnsClass.IN) });
  592. DnsDatagram dnsResponse = await ProcessQueryAsync(dnsRequest, remoteEP, IsRecursionAllowed(remoteEP), protocol);
  593. if (dnsResponse != null)
  594. {
  595. using (MemoryStream mS = new MemoryStream())
  596. {
  597. JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS));
  598. dnsResponse.WriteToJson(jsonWriter);
  599. jsonWriter.Flush();
  600. byte[] buffer = mS.ToArray();
  601. await SendContentAsync(stream, "application/dns-json; charset=utf-8", buffer);
  602. }
  603. LogManager queryLog = _queryLog;
  604. if (queryLog != null)
  605. queryLog.Write(remoteEP, protocol, dnsRequest, dnsResponse);
  606. StatsManager stats = _stats;
  607. if (stats != null)
  608. stats.Update(dnsResponse, remoteEP.Address);
  609. }
  610. }
  611. #endregion
  612. break;
  613. default:
  614. await SendErrorAsync(stream, 406, "Only application/dns-message and application/dns-json types are accepted.");
  615. break;
  616. }
  617. if (requestConnection.Equals("close", StringComparison.OrdinalIgnoreCase))
  618. return;
  619. break;
  620. default:
  621. string path = httpRequest.RequestPath;
  622. if (!path.StartsWith("/") || path.Contains("/../") || path.Contains("/.../"))
  623. {
  624. await SendErrorAsync(stream, 404);
  625. break;
  626. }
  627. if (path == "/")
  628. path = "/index.html";
  629. path = Path.GetFullPath(_dohwwwFolder + path.Replace('/', Path.DirectorySeparatorChar));
  630. if (!path.StartsWith(_dohwwwFolder) || !File.Exists(path))
  631. {
  632. await SendErrorAsync(stream, 404);
  633. break;
  634. }
  635. await SendFileAsync(stream, path);
  636. break;
  637. }
  638. }
  639. }
  640. catch (TimeoutException)
  641. {
  642. //ignore timeout exception
  643. }
  644. catch (IOException)
  645. {
  646. //ignore IO exceptions
  647. }
  648. catch (Exception ex)
  649. {
  650. LogManager queryLog = _queryLog;
  651. if ((queryLog != null) && (dnsRequest != null))
  652. queryLog.Write(remoteEP, dnsProtocol, dnsRequest, null);
  653. LogManager log = _log;
  654. if (log != null)
  655. log.Write(remoteEP, dnsProtocol, ex);
  656. await SendErrorAsync(stream, ex);
  657. }
  658. }
  659. private static async Task SendContentAsync(Stream outputStream, string contentType, byte[] bufferContent)
  660. {
  661. byte[] bufferHeader = Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\nDate: " + DateTime.UtcNow.ToString("r") + "\r\nContent-Type: " + contentType + "\r\nContent-Length: " + bufferContent.Length + "\r\nX-Robots-Tag: noindex, nofollow\r\n\r\n");
  662. await outputStream.WriteAsync(bufferHeader, 0, bufferHeader.Length);
  663. await outputStream.WriteAsync(bufferContent, 0, bufferContent.Length);
  664. await outputStream.FlushAsync();
  665. }
  666. private static Task SendErrorAsync(Stream outputStream, Exception ex)
  667. {
  668. return SendErrorAsync(outputStream, 500, ex.ToString());
  669. }
  670. private static async Task SendErrorAsync(Stream outputStream, int statusCode, string message = null)
  671. {
  672. try
  673. {
  674. string statusString = statusCode + " " + GetHttpStatusString((HttpStatusCode)statusCode);
  675. byte[] bufferContent = Encoding.UTF8.GetBytes("<html><head><title>" + statusString + "</title></head><body><h1>" + statusString + "</h1>" + (message == null ? "" : "<p>" + message + "</p>") + "</body></html>");
  676. byte[] bufferHeader = Encoding.UTF8.GetBytes("HTTP/1.1 " + statusString + "\r\nDate: " + DateTime.UtcNow.ToString("r") + "\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: " + bufferContent.Length + "\r\nX-Robots-Tag: noindex, nofollow\r\n\r\n");
  677. await outputStream.WriteAsync(bufferHeader, 0, bufferHeader.Length);
  678. await outputStream.WriteAsync(bufferContent, 0, bufferContent.Length);
  679. await outputStream.FlushAsync();
  680. }
  681. catch
  682. { }
  683. }
  684. private static async Task SendFileAsync(Stream outputStream, string filePath)
  685. {
  686. using (FileStream fS = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
  687. {
  688. byte[] bufferHeader = Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\nDate: " + DateTime.UtcNow.ToString("r") + "\r\nContent-Type: " + WebUtilities.GetContentType(filePath).MediaType + "\r\nContent-Length: " + fS.Length + "\r\nCache-Control: private, max-age=300\r\nX-Robots-Tag: noindex, nofollow\r\n\r\n");
  689. await outputStream.WriteAsync(bufferHeader, 0, bufferHeader.Length);
  690. await fS.CopyToAsync(outputStream);
  691. await outputStream.FlushAsync();
  692. }
  693. }
  694. internal static string GetHttpStatusString(HttpStatusCode statusCode)
  695. {
  696. StringBuilder sb = new StringBuilder();
  697. foreach (char c in statusCode.ToString().ToCharArray())
  698. {
  699. if (char.IsUpper(c) && sb.Length > 0)
  700. sb.Append(' ');
  701. sb.Append(c);
  702. }
  703. return sb.ToString();
  704. }
  705. private bool IsRecursionAllowed(IPEndPoint remoteEP)
  706. {
  707. if (!_allowRecursion)
  708. return false;
  709. if (_allowRecursionOnlyForPrivateNetworks)
  710. {
  711. switch (remoteEP.AddressFamily)
  712. {
  713. case AddressFamily.InterNetwork:
  714. case AddressFamily.InterNetworkV6:
  715. return NetUtilities.IsPrivateIP(remoteEP.Address);
  716. default:
  717. return false;
  718. }
  719. }
  720. return true;
  721. }
  722. private async Task<DnsDatagram> ProcessQueryAsync(DnsDatagram request, IPEndPoint remoteEP, bool isRecursionAllowed, DnsTransportProtocol protocol)
  723. {
  724. if (request.IsResponse)
  725. return null;
  726. switch (request.OPCODE)
  727. {
  728. case DnsOpcode.StandardQuery:
  729. if ((request.Question.Count != 1) || (request.Question[0].Class != DnsClass.IN))
  730. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.Refused, request.Question);
  731. try
  732. {
  733. switch (request.Question[0].Type)
  734. {
  735. case DnsResourceRecordType.AXFR:
  736. if (protocol == DnsTransportProtocol.Udp)
  737. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.FormatError, request.Question);
  738. return await ProcessZoneTransferQueryAsync(request, remoteEP);
  739. case DnsResourceRecordType.IXFR:
  740. return await ProcessZoneTransferQueryAsync(request, remoteEP);
  741. case DnsResourceRecordType.MAILB:
  742. case DnsResourceRecordType.MAILA:
  743. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NotImplemented, request.Question);
  744. default:
  745. DnsDatagram response;
  746. //check in allowed zone
  747. bool inAllowedZone = _allowedZoneManager.Query(request).RCODE != DnsResponseCode.Refused;
  748. if (!inAllowedZone)
  749. {
  750. //check in blocked zone and block list zone
  751. response = ProcessBlockedQuery(request);
  752. if (response != null)
  753. return response;
  754. }
  755. //query authoritative zone
  756. response = await ProcessAuthoritativeQueryAsync(request, inAllowedZone, isRecursionAllowed);
  757. if ((response.RCODE != DnsResponseCode.Refused) || !request.RecursionDesired || !isRecursionAllowed)
  758. return response;
  759. //do recursive query
  760. return await ProcessRecursiveQueryAsync(request, null, null, !inAllowedZone, false);
  761. }
  762. }
  763. catch (Exception ex)
  764. {
  765. LogManager log = _log;
  766. if (log != null)
  767. log.Write(remoteEP, protocol, ex);
  768. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.ServerFailure, request.Question);
  769. }
  770. case DnsOpcode.Notify:
  771. return await ProcessNotifyQueryAsync(request, remoteEP);
  772. default:
  773. return new DnsDatagram(request.Identifier, true, request.OPCODE, false, false, request.RecursionDesired, isRecursionAllowed, false, false, DnsResponseCode.NotImplemented, request.Question);
  774. }
  775. }
  776. private async Task<DnsDatagram> ProcessNotifyQueryAsync(DnsDatagram request, IPEndPoint remoteEP)
  777. {
  778. AuthZoneInfo authZoneInfo = _authZoneManager.GetAuthZoneInfo(request.Question[0].Name);
  779. if ((authZoneInfo == null) || (authZoneInfo.Type != AuthZoneType.Secondary))
  780. return new DnsDatagram(request.Identifier, true, DnsOpcode.Notify, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = StatsResponseType.Authoritative };
  781. IPAddress remoteAddress = remoteEP.Address;
  782. bool remoteVerified = false;
  783. IReadOnlyList<NameServerAddress> primaryNameServers = await authZoneInfo.GetPrimaryNameServerAddressesAsync(this);
  784. foreach (NameServerAddress primaryNameServer in primaryNameServers)
  785. {
  786. if (primaryNameServer.IPEndPoint.Address.Equals(remoteAddress))
  787. {
  788. remoteVerified = true;
  789. break;
  790. }
  791. }
  792. if (!remoteVerified)
  793. return new DnsDatagram(request.Identifier, true, DnsOpcode.Notify, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = StatsResponseType.Authoritative };
  794. LogManager log = _log;
  795. if (log != null)
  796. log.Write(remoteEP, "DNS Server received NOTIFY for zone: " + authZoneInfo.Name);
  797. if ((request.Answer.Count > 0) && (request.Answer[0].Type == DnsResourceRecordType.SOA))
  798. {
  799. IReadOnlyList<DnsResourceRecord> localSoaRecords = authZoneInfo.GetRecords(DnsResourceRecordType.SOA);
  800. if (!DnsSOARecord.IsZoneUpdateAvailable((localSoaRecords[0].RDATA as DnsSOARecord).Serial, (request.Answer[0].RDATA as DnsSOARecord).Serial))
  801. {
  802. //no update was available
  803. return new DnsDatagram(request.Identifier, true, DnsOpcode.Notify, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question) { Tag = StatsResponseType.Authoritative };
  804. }
  805. }
  806. authZoneInfo.RefreshZone();
  807. return new DnsDatagram(request.Identifier, true, DnsOpcode.Notify, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question) { Tag = StatsResponseType.Authoritative };
  808. }
  809. private async Task<DnsDatagram> ProcessZoneTransferQueryAsync(DnsDatagram request, IPEndPoint remoteEP)
  810. {
  811. AuthZoneInfo authZoneInfo = _authZoneManager.GetAuthZoneInfo(request.Question[0].Name);
  812. if ((authZoneInfo == null) || (authZoneInfo.Type != AuthZoneType.Primary))
  813. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = StatsResponseType.Authoritative };
  814. IPAddress remoteAddress = remoteEP.Address;
  815. bool isAxfrAllowed = IPAddress.IsLoopback(remoteAddress);
  816. if (!isAxfrAllowed)
  817. {
  818. IReadOnlyList<NameServerAddress> secondaryNameServers = await authZoneInfo.GetSecondaryNameServerAddressesAsync(this);
  819. foreach (NameServerAddress secondaryNameServer in secondaryNameServers)
  820. {
  821. if (secondaryNameServer.IPEndPoint.Address.Equals(remoteAddress))
  822. {
  823. isAxfrAllowed = true;
  824. break;
  825. }
  826. }
  827. }
  828. if (!isAxfrAllowed)
  829. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.Refused, request.Question) { Tag = StatsResponseType.Authoritative };
  830. LogManager log = _log;
  831. if (log != null)
  832. log.Write(remoteEP, "DNS Server received zone transfer request for zone: " + authZoneInfo.Name);
  833. IReadOnlyList<DnsResourceRecord> axfrRecords = _authZoneManager.QueryZoneTransferRecords(request.Question[0].Name);
  834. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, request.Question, axfrRecords) { Tag = StatsResponseType.Authoritative };
  835. }
  836. private Task<DnsDatagram> ProcessAuthoritativeQueryAsync(DnsDatagram request, bool inAllowedZone, bool isRecursionAllowed)
  837. {
  838. DnsDatagram response = _authZoneManager.Query(request);
  839. response.Tag = StatsResponseType.Authoritative;
  840. if (response.RCODE == DnsResponseCode.NoError)
  841. {
  842. if (response.Answer.Count > 0)
  843. {
  844. DnsResourceRecordType questionType = request.Question[0].Type;
  845. DnsResourceRecord lastRR = response.Answer[response.Answer.Count - 1];
  846. if ((lastRR.Type != questionType) && (questionType != DnsResourceRecordType.ANY))
  847. {
  848. switch (lastRR.Type)
  849. {
  850. case DnsResourceRecordType.CNAME:
  851. return ProcessCNAMEAsync(request, response, isRecursionAllowed, false);
  852. case DnsResourceRecordType.ANAME:
  853. return ProcessANAMEAsync(request, response, isRecursionAllowed);
  854. }
  855. }
  856. }
  857. else if (response.Authority.Count > 0)
  858. {
  859. switch (response.Authority[0].Type)
  860. {
  861. case DnsResourceRecordType.NS:
  862. if (request.RecursionDesired && isRecursionAllowed)
  863. {
  864. //do recursive resolution using response authority name servers
  865. List<NameServerAddress> nameServers = NameServerAddress.GetNameServersFromResponse(response, _preferIPv6, false);
  866. return ProcessRecursiveQueryAsync(request, nameServers, null, !inAllowedZone, false);
  867. }
  868. break;
  869. case DnsResourceRecordType.FWD:
  870. if ((response.Authority.Count == 1) && (response.Authority[0].Type == DnsResourceRecordType.FWD) && (response.Authority[0].RDATA as DnsForwarderRecord).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase))
  871. {
  872. //do conditional forwarding via "this-server"
  873. return ProcessRecursiveQueryAsync(request, null, null, !inAllowedZone, false);
  874. }
  875. else
  876. {
  877. //do conditional forwarding
  878. List<NameServerAddress> forwarders = new List<NameServerAddress>(response.Authority.Count);
  879. foreach (DnsResourceRecord rr in response.Authority)
  880. {
  881. if (rr.Type == DnsResourceRecordType.FWD)
  882. {
  883. DnsForwarderRecord fwd = rr.RDATA as DnsForwarderRecord;
  884. if (!fwd.Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase))
  885. forwarders.Add(fwd.NameServer);
  886. }
  887. }
  888. return ProcessRecursiveQueryAsync(request, null, forwarders, !inAllowedZone, false);
  889. }
  890. }
  891. }
  892. }
  893. return Task.FromResult(response);
  894. }
  895. private async Task<DnsDatagram> ProcessCNAMEAsync(DnsDatagram request, DnsDatagram response, bool isRecursionAllowed, bool cacheRefreshOperation)
  896. {
  897. List<DnsResourceRecord> responseAnswer = new List<DnsResourceRecord>();
  898. responseAnswer.AddRange(response.Answer);
  899. DnsDatagram lastResponse;
  900. bool isAuthoritativeAnswer = response.AuthoritativeAnswer;
  901. string lastDomain = (response.Answer[response.Answer.Count - 1].RDATA as DnsCNAMERecord).Domain;
  902. int queryCount = 0;
  903. do
  904. {
  905. DnsDatagram newRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord(lastDomain, request.Question[0].Type, request.Question[0].Class) });
  906. //query authoritative zone first
  907. lastResponse = _authZoneManager.Query(newRequest);
  908. if (lastResponse.RCODE == DnsResponseCode.Refused)
  909. {
  910. //not found in auth zone
  911. if (newRequest.RecursionDesired && isRecursionAllowed)
  912. {
  913. //do recursion
  914. lastResponse = await RecursiveResolveAsync(newRequest, null, null, false, cacheRefreshOperation);
  915. isAuthoritativeAnswer = false;
  916. }
  917. else
  918. {
  919. //break since no recursion allowed/desired
  920. break;
  921. }
  922. }
  923. else if ((lastResponse.Answer.Count > 0) && (lastResponse.Answer[0].Type == DnsResourceRecordType.ANAME))
  924. {
  925. lastResponse = await ProcessANAMEAsync(request, lastResponse, isRecursionAllowed);
  926. }
  927. else if ((lastResponse.Answer.Count == 0) && (lastResponse.Authority.Count > 0))
  928. {
  929. //found delegated/forwarded zone
  930. switch (lastResponse.Authority[0].Type)
  931. {
  932. case DnsResourceRecordType.NS:
  933. if (newRequest.RecursionDesired && isRecursionAllowed)
  934. {
  935. //do recursive resolution using last response authority name servers
  936. List<NameServerAddress> nameServers = NameServerAddress.GetNameServersFromResponse(lastResponse, _preferIPv6, false);
  937. lastResponse = await RecursiveResolveAsync(newRequest, nameServers, null, false, false);
  938. isAuthoritativeAnswer = false;
  939. }
  940. break;
  941. case DnsResourceRecordType.FWD:
  942. if ((lastResponse.Authority.Count == 1) && (lastResponse.Authority[0].RDATA as DnsForwarderRecord).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase))
  943. {
  944. //do conditional forwarding via "this-server"
  945. lastResponse = await RecursiveResolveAsync(newRequest, null, null, false, false);
  946. isAuthoritativeAnswer = false;
  947. }
  948. else
  949. {
  950. //do conditional forwarding
  951. List<NameServerAddress> forwarders = new List<NameServerAddress>(lastResponse.Authority.Count);
  952. foreach (DnsResourceRecord rr in lastResponse.Authority)
  953. {
  954. if (rr.Type == DnsResourceRecordType.FWD)
  955. {
  956. DnsForwarderRecord fwd = rr.RDATA as DnsForwarderRecord;
  957. if (!fwd.Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase))
  958. forwarders.Add(fwd.NameServer);
  959. }
  960. }
  961. lastResponse = await RecursiveResolveAsync(newRequest, null, forwarders, false, false);
  962. isAuthoritativeAnswer = false;
  963. }
  964. break;
  965. }
  966. }
  967. //check last response
  968. if (lastResponse.Answer.Count == 0)
  969. break; //cannot proceed to resolve further
  970. responseAnswer.AddRange(lastResponse.Answer);
  971. DnsResourceRecord lastRR = lastResponse.Answer[lastResponse.Answer.Count - 1];
  972. if (lastRR.Type != DnsResourceRecordType.CNAME)
  973. break; //cname was resolved
  974. lastDomain = (lastRR.RDATA as DnsCNAMERecord).Domain;
  975. }
  976. while (++queryCount < MAX_CNAME_HOPS);
  977. DnsResponseCode rcode;
  978. IReadOnlyList<DnsResourceRecord> authority = null;
  979. IReadOnlyList<DnsResourceRecord> additional = null;
  980. if ((lastResponse.RCODE == DnsResponseCode.Refused) && !(request.RecursionDesired && isRecursionAllowed))
  981. {
  982. rcode = DnsResponseCode.NoError;
  983. }
  984. else
  985. {
  986. rcode = lastResponse.RCODE;
  987. if (isAuthoritativeAnswer)
  988. {
  989. authority = response.Authority;
  990. additional = response.Additional;
  991. }
  992. else
  993. {
  994. if ((lastResponse.Authority.Count > 0) && (lastResponse.Authority[0].Type == DnsResourceRecordType.SOA))
  995. authority = lastResponse.Authority;
  996. }
  997. }
  998. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, isAuthoritativeAnswer, false, request.RecursionDesired, isRecursionAllowed, false, false, rcode, request.Question, responseAnswer, authority, additional) { Tag = response.Tag };
  999. }
  1000. private async Task<DnsDatagram> ProcessANAMEAsync(DnsDatagram request, DnsDatagram response, bool isRecursionAllowed)
  1001. {
  1002. List<DnsResourceRecord> responseAnswer = new List<DnsResourceRecord>();
  1003. for (int i = 0; i < response.Answer.Count - 1; i++)
  1004. responseAnswer.Add(response.Answer[i]);
  1005. DnsDatagram lastResponse;
  1006. DnsResourceRecord anameRR = response.Answer[response.Answer.Count - 1];
  1007. string lastDomain = (anameRR.RDATA as DnsANAMERecord).Domain;
  1008. int queryCount = 0;
  1009. do
  1010. {
  1011. DnsDatagram newRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord(lastDomain, request.Question[0].Type, request.Question[0].Class) });
  1012. //query authoritative zone first
  1013. lastResponse = _authZoneManager.Query(newRequest);
  1014. if (lastResponse.RCODE == DnsResponseCode.Refused)
  1015. {
  1016. //not found in auth zone; do recursion
  1017. lastResponse = await RecursiveResolveAsync(newRequest, null, null, false, false);
  1018. }
  1019. else if ((lastResponse.Answer.Count == 0) && (lastResponse.Authority.Count > 0))
  1020. {
  1021. //found delegated/forwarded zone
  1022. switch (lastResponse.Authority[0].Type)
  1023. {
  1024. case DnsResourceRecordType.NS:
  1025. //do recursive resolution using last response authority name servers
  1026. List<NameServerAddress> nameServers = NameServerAddress.GetNameServersFromResponse(lastResponse, _preferIPv6, false);
  1027. lastResponse = await RecursiveResolveAsync(newRequest, nameServers, null, false, false);
  1028. break;
  1029. case DnsResourceRecordType.FWD:
  1030. if ((lastResponse.Authority.Count == 1) && (lastResponse.Authority[0].RDATA as DnsForwarderRecord).Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase))
  1031. {
  1032. //do conditional forwarding via "this-server"
  1033. lastResponse = await RecursiveResolveAsync(newRequest, null, null, false, false);
  1034. }
  1035. else
  1036. {
  1037. //do conditional forwarding
  1038. List<NameServerAddress> forwarders = new List<NameServerAddress>(lastResponse.Authority.Count);
  1039. foreach (DnsResourceRecord rr in lastResponse.Authority)
  1040. {
  1041. if (rr.Type == DnsResourceRecordType.FWD)
  1042. {
  1043. DnsForwarderRecord fwd = rr.RDATA as DnsForwarderRecord;
  1044. if (!fwd.Forwarder.Equals("this-server", StringComparison.OrdinalIgnoreCase))
  1045. forwarders.Add(fwd.NameServer);
  1046. }
  1047. }
  1048. lastResponse = await RecursiveResolveAsync(newRequest, null, forwarders, false, false);
  1049. }
  1050. break;
  1051. }
  1052. }
  1053. //check last response
  1054. if (lastResponse.Answer.Count == 0)
  1055. break; //cannot proceed to resolve further
  1056. DnsResourceRecord firstRR = lastResponse.Answer[0];
  1057. if (firstRR.Type == request.Question[0].Type)
  1058. {
  1059. foreach (DnsResourceRecord answer in lastResponse.Answer)
  1060. {
  1061. if (anameRR.TtlValue < answer.TtlValue)
  1062. responseAnswer.Add(new DnsResourceRecord(anameRR.Name, answer.Type, answer.Class, anameRR.TtlValue, answer.RDATA));
  1063. else
  1064. responseAnswer.Add(new DnsResourceRecord(anameRR.Name, answer.Type, answer.Class, answer.TtlValue, answer.RDATA));
  1065. }
  1066. break; //found final answer
  1067. }
  1068. DnsResourceRecord lastRR = lastResponse.Answer[lastResponse.Answer.Count - 1];
  1069. if (lastRR.Type == DnsResourceRecordType.ANAME)
  1070. lastDomain = (lastRR.RDATA as DnsANAMERecord).Domain;
  1071. else if (lastRR.Type == DnsResourceRecordType.CNAME)
  1072. lastDomain = (lastRR.RDATA as DnsCNAMERecord).Domain;
  1073. else
  1074. break; //aname/cname was resolved
  1075. }
  1076. while (++queryCount < MAX_CNAME_HOPS);
  1077. DnsResponseCode rcode = lastResponse.RCODE;
  1078. if (rcode == DnsResponseCode.NameError)
  1079. rcode = DnsResponseCode.NoError;
  1080. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, true, false, request.RecursionDesired, isRecursionAllowed, false, false, rcode, request.Question, responseAnswer, response.Authority, response.Additional) { Tag = response.Tag };
  1081. }
  1082. private DnsDatagram ProcessBlockedQuery(DnsDatagram request)
  1083. {
  1084. DnsDatagram response = _blockedZoneManager.Query(request);
  1085. if (response.RCODE == DnsResponseCode.Refused)
  1086. {
  1087. //domain not blocked in blocked zone
  1088. response = _blockListZoneManager.Query(request); //check in block list zone
  1089. if (response == null)
  1090. return null;
  1091. }
  1092. else
  1093. {
  1094. //domain is blocked in blocked zone
  1095. IReadOnlyList<DnsResourceRecord> answer = null;
  1096. IReadOnlyList<DnsResourceRecord> authority = null;
  1097. switch (response.Question[0].Type)
  1098. {
  1099. case DnsResourceRecordType.A:
  1100. answer = new DnsResourceRecord[] { new DnsResourceRecord(response.Question[0].Name, DnsResourceRecordType.A, response.Question[0].Class, 60, _aRecord) };
  1101. break;
  1102. case DnsResourceRecordType.AAAA:
  1103. answer = new DnsResourceRecord[] { new DnsResourceRecord(response.Question[0].Name, DnsResourceRecordType.AAAA, response.Question[0].Class, 60, _aaaaRecord) };
  1104. break;
  1105. case DnsResourceRecordType.NS:
  1106. answer = response.Answer;
  1107. break;
  1108. case DnsResourceRecordType.TXT:
  1109. answer = new DnsResourceRecord[] { new DnsResourceRecord(response.Question[0].Name, DnsResourceRecordType.TXT, response.Question[0].Class, 60, new DnsTXTRecord("blockList=custom; domain=" + response.Question[0].Name)) };
  1110. break;
  1111. default:
  1112. authority = response.Authority;
  1113. break;
  1114. }
  1115. response = new DnsDatagram(response.Identifier, true, response.OPCODE, false, false, response.RecursionDesired, true, false, false, DnsResponseCode.NoError, response.Question, answer, authority);
  1116. }
  1117. response.Tag = StatsResponseType.Blocked;
  1118. return response;
  1119. }
  1120. private async Task<DnsDatagram> ProcessRecursiveQueryAsync(DnsDatagram request, IReadOnlyList<NameServerAddress> viaNameServers, IReadOnlyList<NameServerAddress> viaForwarders, bool checkForCnameCloaking, bool cacheRefreshOperation)
  1121. {
  1122. DnsDatagram response = await RecursiveResolveAsync(request, viaNameServers, viaForwarders, false, cacheRefreshOperation);
  1123. if (response.Answer.Count > 0)
  1124. {
  1125. DnsResourceRecordType questionType = request.Question[0].Type;
  1126. DnsResourceRecord lastRR = response.Answer[response.Answer.Count - 1];
  1127. if ((lastRR.Type != questionType) && (lastRR.Type == DnsResourceRecordType.CNAME) && (questionType != DnsResourceRecordType.ANY))
  1128. response = await ProcessCNAMEAsync(request, response, true, cacheRefreshOperation);
  1129. if (checkForCnameCloaking)
  1130. {
  1131. for (int i = 0; i < response.Answer.Count; i++)
  1132. {
  1133. DnsResourceRecord record = response.Answer[i];
  1134. if (record.Type != DnsResourceRecordType.CNAME)
  1135. break; //no further CNAME records exists
  1136. DnsDatagram newRequest = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord((record.RDATA as DnsCNAMERecord).Domain, request.Question[0].Type, request.Question[0].Class) });
  1137. //check allowed zone
  1138. bool inAllowedZone = _allowedZoneManager.Query(newRequest).RCODE != DnsResponseCode.Refused;
  1139. if (inAllowedZone)
  1140. break; //CNAME is in allowed zone
  1141. //check blocked zone and block list zone
  1142. DnsDatagram lastResponse = ProcessBlockedQuery(newRequest);
  1143. if (lastResponse != null)
  1144. {
  1145. //found cname cloaking
  1146. List<DnsResourceRecord> answer = new List<DnsResourceRecord>();
  1147. //copy current and previous CNAME records
  1148. for (int j = 0; j <= i; j++)
  1149. answer.Add(response.Answer[j]);
  1150. //copy last response answers
  1151. answer.AddRange(lastResponse.Answer);
  1152. IReadOnlyList<DnsResourceRecord> authority = null;
  1153. if ((lastResponse.Authority.Count > 0) && (lastResponse.Authority[0].Type == DnsResourceRecordType.SOA))
  1154. authority = lastResponse.Authority;
  1155. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, true, true, false, false, DnsResponseCode.NoError, request.Question, answer, authority) { Tag = lastResponse.Tag };
  1156. }
  1157. }
  1158. }
  1159. }
  1160. //return response
  1161. {
  1162. IReadOnlyList<DnsResourceRecord> authority = null;
  1163. if ((authority == null) && (response.Authority.Count > 0) && (response.Authority[0].Type == DnsResourceRecordType.SOA))
  1164. authority = response.Authority;
  1165. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, true, true, false, false, response.RCODE, request.Question, response.Answer, authority) { Tag = response.Tag };
  1166. }
  1167. }
  1168. private async Task<DnsDatagram> RecursiveResolveAsync(DnsDatagram request, IReadOnlyList<NameServerAddress> viaNameServers, IReadOnlyList<NameServerAddress> viaForwarders, bool cachePrefetchOperation, bool cacheRefreshOperation)
  1169. {
  1170. if (!cachePrefetchOperation && !cacheRefreshOperation)
  1171. {
  1172. //query cache zone to see if answer available
  1173. DnsDatagram cacheResponse = QueryCache(request, false);
  1174. if (cacheResponse != null)
  1175. {
  1176. if (_cachePrefetchTrigger > 0)
  1177. {
  1178. //inspect response TTL values to decide if prefetch trigger is needed
  1179. foreach (DnsResourceRecord answer in cacheResponse.Answer)
  1180. {
  1181. if ((answer.OriginalTtlValue > _cachePrefetchEligibility) && (answer.TtlValue < _cachePrefetchTrigger))
  1182. {
  1183. //trigger prefetch async
  1184. _ = PrefetchCacheAsync(request, viaNameServers, viaForwarders);
  1185. break;
  1186. }
  1187. }
  1188. }
  1189. return cacheResponse;
  1190. }
  1191. }
  1192. //recursion with locking
  1193. TaskCompletionSource<DnsDatagram> resolverTaskCompletionSource = new TaskCompletionSource<DnsDatagram>();
  1194. Task<DnsDatagram> resolverTask = _resolverTasks.GetOrAdd(GetResolverQueryKey(request.Question[0]), resolverTaskCompletionSource.Task);
  1195. if (resolverTask.Equals(resolverTaskCompletionSource.Task))
  1196. {
  1197. //got new resolver task added so question is not being resolved; do recursive resolution in another task on resolver thread pool
  1198. _ = Task.Factory.StartNew(delegate ()
  1199. {
  1200. return RecursiveResolveAsync(request, viaNameServers, viaForwarders, cachePrefetchOperation, cacheRefreshOperation, resolverTaskCompletionSource);
  1201. }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, _resolverTaskScheduler);
  1202. }
  1203. //request is being recursively resolved by another thread
  1204. if (cachePrefetchOperation)
  1205. return null; //return null as prefetch worker thread does not need valid response and thus does not need to wait
  1206. DateTime resolverWaitStartTime = DateTime.UtcNow;
  1207. //wait till short timeout for response
  1208. if (await Task.WhenAny(resolverTask, Task.Delay(SERVE_STALE_WAIT_TIME)) == resolverTask) //1.8 sec wait as per draft-ietf-dnsop-serve-stale-04
  1209. {
  1210. //resolver signaled
  1211. DnsDatagram response = await resolverTask;
  1212. if (response != null)
  1213. return response;
  1214. //resolver had exception and no stale record was found
  1215. }
  1216. else
  1217. {
  1218. //wait timed out
  1219. //query cache zone to return stale answer (if available) as per draft-ietf-dnsop-serve-stale-04
  1220. DnsDatagram staleResponse = QueryCache(request, true);
  1221. if (staleResponse != null)
  1222. return staleResponse;
  1223. //wait till full timeout before responding as ServerFailure
  1224. int timeout = Convert.ToInt32(_clientTimeout - (DateTime.UtcNow - resolverWaitStartTime).TotalMilliseconds);
  1225. if (timeout > 0)
  1226. {
  1227. if (await Task.WhenAny(resolverTask, Task.Delay(timeout)) == resolverTask)
  1228. {
  1229. //resolver signaled
  1230. DnsDatagram response = await resolverTask;
  1231. if (response != null)
  1232. return response;
  1233. }
  1234. //no response available from resolver or resolver had exception and no stale record was found
  1235. }
  1236. }
  1237. //no response available; respond with ServerFailure
  1238. return new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.ServerFailure, request.Question);
  1239. }
  1240. private async Task RecursiveResolveAsync(DnsDatagram request, IReadOnlyList<NameServerAddress> viaNameServers, IReadOnlyList<NameServerAddress> viaForwarders, bool cachePrefetchOperation, bool cacheRefreshOperation, TaskCompletionSource<DnsDatagram> taskCompletionSource)
  1241. {
  1242. IReadOnlyList<NameServerAddress> forwarders = _forwarders;
  1243. if (viaForwarders != null)
  1244. forwarders = viaForwarders; //use provided forwarders
  1245. try
  1246. {
  1247. if ((viaNameServers == null) && (forwarders != null))
  1248. {
  1249. //use forwarders
  1250. if (_proxy == null)
  1251. {
  1252. //recursive resolve name server when proxy is null else let proxy resolve it
  1253. foreach (NameServerAddress nameServerAddress in forwarders)
  1254. {
  1255. if (nameServerAddress.IsIPEndPointStale) //refresh forwarder IPEndPoint if stale
  1256. await nameServerAddress.RecursiveResolveIPAddressAsync(_dnsCache, null, _preferIPv6, _resolverRetries, _resolverTimeout);
  1257. }
  1258. }
  1259. //query forwarders and update cache
  1260. DnsClient dnsClient = new DnsClient(forwarders);
  1261. dnsClient.Proxy = _proxy;
  1262. dnsClient.PreferIPv6 = _preferIPv6;
  1263. dnsClient.Retries = _forwarderRetries;
  1264. dnsClient.Timeout = _forwarderTimeout;
  1265. dnsClient.Concurrency = _forwarderConcurrency;
  1266. DnsDatagram response = await dnsClient.ResolveAsync(request.Question[0]);
  1267. _cacheZoneManager.CacheResponse(response);
  1268. taskCompletionSource.SetResult(response);
  1269. }
  1270. else
  1271. {
  1272. //recursive resolve and update cache
  1273. IDnsCache dnsCache;
  1274. if (cachePrefetchOperation || cacheRefreshOperation)
  1275. dnsCache = new ResolverPrefetchDnsCache(_authZoneManager, _cacheZoneManager, request.Question[0]);
  1276. else
  1277. dnsCache = _dnsCache;
  1278. DnsDatagram response = await DnsClient.RecursiveResolveAsync(request.Question[0], viaNameServers, dnsCache, _proxy, _preferIPv6, _resolverRetries, _resolverTimeout, _resolverMaxStackCount);
  1279. taskCompletionSource.SetResult(response);
  1280. }
  1281. }
  1282. catch (Exception ex)
  1283. {
  1284. LogManager log = _log;
  1285. if (log != null)
  1286. {
  1287. string nameServers = null;
  1288. if (viaNameServers != null)
  1289. {
  1290. foreach (NameServerAddress nameServer in viaNameServers)
  1291. {
  1292. if (nameServers == null)
  1293. nameServers = nameServer.ToString();
  1294. else
  1295. nameServers += ", " + nameServer.ToString();
  1296. }
  1297. }
  1298. else if (forwarders != null)
  1299. {
  1300. foreach (NameServerAddress nameServer in forwarders)
  1301. {
  1302. if (nameServers == null)
  1303. nameServers = nameServer.ToString();
  1304. else
  1305. nameServers += ", " + nameServer.ToString();
  1306. }
  1307. }
  1308. log.Write("DNS Server recursive resolution failed for QNAME: " + request.Question[0].Name + "; QTYPE: " + request.Question[0].Type.ToString() + "; QCLASS: " + request.Question[0].Class.ToString() + (nameServers == null ? "" : "; Name Servers: " + nameServers) + ";\r\n" + ex.ToString());
  1309. }
  1310. //fetch stale record
  1311. DnsDatagram staleResponse = QueryCache(request, true);
  1312. if (staleResponse == null)
  1313. {
  1314. //no stale record was found; signal null response to release waiting tasks
  1315. taskCompletionSource.SetResult(null);
  1316. }
  1317. else
  1318. {
  1319. //reset expiry for stale records
  1320. foreach (DnsResourceRecord record in staleResponse.Answer)
  1321. {
  1322. if (record.IsStale)
  1323. record.ResetExpiry(30); //reset expiry by 30 seconds so that resolver tries again only after 30 seconds as per draft-ietf-dnsop-serve-stale-04
  1324. }
  1325. //signal stale response
  1326. taskCompletionSource.SetResult(staleResponse);
  1327. }
  1328. }
  1329. finally
  1330. {
  1331. _resolverTasks.TryRemove(GetResolverQueryKey(request.Question[0]), out _);
  1332. }
  1333. }
  1334. private static string GetResolverQueryKey(DnsQuestionRecord question)
  1335. {
  1336. if (string.IsNullOrEmpty(question.Name))
  1337. return question.Type + "." + question.Class;
  1338. return question.Name + "." + question.Type + "." + question.Class;
  1339. }
  1340. private DnsDatagram QueryCache(DnsDatagram request, bool serveStale)
  1341. {
  1342. DnsDatagram cacheResponse = _cacheZoneManager.Query(request, serveStale);
  1343. if (cacheResponse.RCODE != DnsResponseCode.Refused)
  1344. {
  1345. if ((cacheResponse.Answer.Count > 0) || (cacheResponse.Authority.Count == 0) || (cacheResponse.Authority[0].Type == DnsResourceRecordType.SOA))
  1346. {
  1347. cacheResponse.Tag = StatsResponseType.Cached;
  1348. return cacheResponse;
  1349. }
  1350. }
  1351. return null;
  1352. }
  1353. private async Task PrefetchCacheAsync(DnsDatagram request, IReadOnlyList<NameServerAddress> viaNameServers, IReadOnlyList<NameServerAddress> viaForwarders)
  1354. {
  1355. try
  1356. {
  1357. await RecursiveResolveAsync(request, viaNameServers, viaForwarders, true, false);
  1358. }
  1359. catch (Exception ex)
  1360. {
  1361. LogManager log = _log;
  1362. if (log != null)
  1363. log.Write(ex);
  1364. }
  1365. }
  1366. private async Task RefreshCacheAsync(IList<DnsQuestionRecord> cacheRefreshSampleList, DnsQuestionRecord sampleQuestion, int sampleQuestionIndex)
  1367. {
  1368. try
  1369. {
  1370. //refresh cache
  1371. DnsDatagram request = new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { sampleQuestion });
  1372. DnsDatagram response = await ProcessRecursiveQueryAsync(request, null, null, false, true);
  1373. bool removeFromSampleList = true;
  1374. DateTime utcNow = DateTime.UtcNow;
  1375. foreach (DnsResourceRecord answer in response.Answer)
  1376. {
  1377. if ((answer.OriginalTtlValue > _cachePrefetchEligibility) && (utcNow.AddSeconds(answer.TtlValue) < _cachePrefetchSamplingTimerTriggersOn))
  1378. {
  1379. //answer expires before next sampling so dont remove from list to allow refreshing it
  1380. removeFromSampleList = false;
  1381. break;
  1382. }
  1383. }
  1384. if (removeFromSampleList)
  1385. cacheRefreshSampleList[sampleQuestionIndex] = null;
  1386. }
  1387. catch (Exception ex)
  1388. {
  1389. LogManager log = _log;
  1390. if (log != null)
  1391. log.Write(ex);
  1392. }
  1393. }
  1394. private DnsQuestionRecord GetCacheRefreshNeededQuery(DnsQuestionRecord question, int trigger)
  1395. {
  1396. int queryCount = 0;
  1397. while (true)
  1398. {
  1399. DnsDatagram cacheResponse = QueryCache(new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { question }), false);
  1400. if (cacheResponse == null)
  1401. return question; //cache expired so refresh question
  1402. if (cacheResponse.Answer.Count == 0)
  1403. return null; //dont refresh empty responses
  1404. //inspect response TTL values to decide if refresh is needed
  1405. foreach (DnsResourceRecord answer in cacheResponse.Answer)
  1406. {
  1407. if ((answer.OriginalTtlValue > _cachePrefetchEligibility) && (answer.TtlValue < trigger))
  1408. return question; //TTL eligible and less than trigger so refresh question
  1409. }
  1410. DnsResourceRecord lastRR = cacheResponse.Answer[cacheResponse.Answer.Count - 1];
  1411. if (lastRR.Type == question.Type)
  1412. return null; //answer was resolved
  1413. if (lastRR.Type != DnsResourceRecordType.CNAME)
  1414. return null; //invalid response so ignore question
  1415. queryCount++;
  1416. if (queryCount >= MAX_CNAME_HOPS)
  1417. return null; //too many hops so ignore question
  1418. //follow CNAME chain to inspect TTL further
  1419. question = new DnsQuestionRecord((lastRR.RDATA as DnsCNAMERecord).Domain, question.Type, question.Class);
  1420. }
  1421. }
  1422. private bool IsCacheRefreshNeeded(DnsQuestionRecord question, int trigger)
  1423. {
  1424. DnsDatagram cacheResponse = QueryCache(new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { question }), false);
  1425. if (cacheResponse == null)
  1426. return true; //cache expired so refresh needed
  1427. if (cacheResponse.Answer.Count == 0)
  1428. return false; //dont refresh empty responses
  1429. //inspect response TTL values to decide if refresh is needed
  1430. foreach (DnsResourceRecord answer in cacheResponse.Answer)
  1431. {
  1432. if ((answer.OriginalTtlValue > _cachePrefetchEligibility) && (answer.TtlValue < trigger))
  1433. return true; //TTL eligible less than trigger so refresh
  1434. }
  1435. return false; //no need to refresh for this query
  1436. }
  1437. private void CachePrefetchSamplingTimerCallback(object state)
  1438. {
  1439. try
  1440. {
  1441. StatsManager stats = _stats;
  1442. if (stats != null)
  1443. {
  1444. List<KeyValuePair<DnsQuestionRecord, int>> eligibleQueries = stats.GetLastHourEligibleQueries(_cachePrefetchSampleEligibilityHitsPerHour);
  1445. List<DnsQuestionRecord> cacheRefreshSampleList = new List<DnsQuestionRecord>(eligibleQueries.Count);
  1446. int cacheRefreshTrigger = (_cachePrefetchSampleIntervalInMinutes + 1) * 60;
  1447. foreach (KeyValuePair<DnsQuestionRecord, int> query in eligibleQueries)
  1448. {
  1449. AuthZoneInfo zoneInfo = _authZoneManager.GetAuthZoneInfo(query.Key.Name);
  1450. if (zoneInfo != null)
  1451. {
  1452. switch (zoneInfo.Type)
  1453. {
  1454. case AuthZoneType.Primary:
  1455. case AuthZoneType.Secondary:
  1456. //zone is hosted
  1457. if (!zoneInfo.Disabled)
  1458. continue; //no cache refresh for zone that is hosted and enabled
  1459. break;
  1460. }
  1461. }
  1462. if (query.Key.Type == DnsResourceRecordType.ANY)
  1463. continue; //dont refresh ANY queries
  1464. DnsQuestionRecord refreshQuery = GetCacheRefreshNeededQuery(query.Key, cacheRefreshTrigger);
  1465. if (refreshQuery != null)
  1466. cacheRefreshSampleList.Add(refreshQuery);
  1467. }
  1468. _cachePrefetchSampleList = cacheRefreshSampleList;
  1469. }
  1470. }
  1471. catch (Exception ex)
  1472. {
  1473. LogManager log = _log;
  1474. if (log != null)
  1475. log.Write(ex);
  1476. }
  1477. finally
  1478. {
  1479. lock (_cachePrefetchSamplingTimerLock)
  1480. {
  1481. if (_cachePrefetchSamplingTimer != null)
  1482. {
  1483. _cachePrefetchSamplingTimer.Change(_cachePrefetchSampleIntervalInMinutes * 60 * 1000, System.Threading.Timeout.Infinite);
  1484. _cachePrefetchSamplingTimerTriggersOn = DateTime.UtcNow.AddMinutes(_cachePrefetchSampleIntervalInMinutes);
  1485. }
  1486. }
  1487. }
  1488. }
  1489. private void CachePrefetchRefreshTimerCallback(object state)
  1490. {
  1491. try
  1492. {
  1493. IList<DnsQuestionRecord> cacheRefreshSampleList = _cachePrefetchSampleList;
  1494. if (cacheRefreshSampleList != null)
  1495. {
  1496. for (int i = 0; i < cacheRefreshSampleList.Count; i++)
  1497. {
  1498. DnsQuestionRecord sampleQuestion = cacheRefreshSampleList[i];
  1499. if (sampleQuestion == null)
  1500. continue;
  1501. if (!IsCacheRefreshNeeded(sampleQuestion, _cachePrefetchTrigger + 2))
  1502. continue;
  1503. _ = RefreshCacheAsync(cacheRefreshSampleList, sampleQuestion, i);
  1504. }
  1505. }
  1506. }
  1507. catch (Exception ex)
  1508. {
  1509. LogManager log = _log;
  1510. if (log != null)
  1511. log.Write(ex);
  1512. }
  1513. finally
  1514. {
  1515. lock (_cachePrefetchRefreshTimerLock)
  1516. {
  1517. if (_cachePrefetchRefreshTimer != null)
  1518. _cachePrefetchRefreshTimer.Change((_cachePrefetchTrigger + 1) * 1000, Timeout.Infinite);
  1519. }
  1520. }
  1521. }
  1522. private void CacheMaintenanceTimerCallback(object state)
  1523. {
  1524. try
  1525. {
  1526. _cacheZoneManager.DoMaintenance();
  1527. }
  1528. catch (Exception ex)
  1529. {
  1530. LogManager log = _log;
  1531. if (log != null)
  1532. log.Write(ex);
  1533. }
  1534. }
  1535. private void ResetPrefetchTimers()
  1536. {
  1537. if (_cachePrefetchTrigger == 0)
  1538. {
  1539. lock (_cachePrefetchSamplingTimerLock)
  1540. {
  1541. if (_cachePrefetchSamplingTimer != null)
  1542. _cachePrefetchSamplingTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
  1543. }
  1544. lock (_cachePrefetchRefreshTimerLock)
  1545. {
  1546. if (_cachePrefetchRefreshTimer != null)
  1547. _cachePrefetchRefreshTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
  1548. }
  1549. }
  1550. else if (_state == ServiceState.Running)
  1551. {
  1552. lock (_cachePrefetchSamplingTimerLock)
  1553. {
  1554. if (_cachePrefetchSamplingTimer != null)
  1555. {
  1556. _cachePrefetchSamplingTimer.Change(_cachePrefetchSampleIntervalInMinutes * 60 * 1000, System.Threading.Timeout.Infinite);
  1557. _cachePrefetchSamplingTimerTriggersOn = DateTime.UtcNow.AddMinutes(_cachePrefetchSampleIntervalInMinutes);
  1558. }
  1559. }
  1560. lock (_cachePrefetchRefreshTimerLock)
  1561. {
  1562. if (_cachePrefetchRefreshTimer != null)
  1563. _cachePrefetchRefreshTimer.Change(CACHE_PREFETCH_REFRESH_TIMER_INITIAL_INTEVAL, System.Threading.Timeout.Infinite);
  1564. }
  1565. }
  1566. }
  1567. private void UpdateThisServer()
  1568. {
  1569. if (_thisServer == null)
  1570. {
  1571. if ((_localEndPoints == null) || (_localEndPoints.Count == 0))
  1572. _thisServer = new NameServerAddress(_serverDomain, IPAddress.Loopback);
  1573. else if (_localEndPoints[0].Address.Equals(IPAddress.Any))
  1574. _thisServer = new NameServerAddress(_serverDomain, new IPEndPoint(IPAddress.Loopback, _localEndPoints[0].Port));
  1575. else if (_localEndPoints[0].Equals(IPAddress.IPv6Any))
  1576. _thisServer = new NameServerAddress(_serverDomain, new IPEndPoint(IPAddress.IPv6Loopback, _localEndPoints[0].Port));
  1577. else
  1578. _thisServer = new NameServerAddress(_serverDomain, _localEndPoints[0]);
  1579. }
  1580. else
  1581. {
  1582. _thisServer = new NameServerAddress(_serverDomain, _thisServer.IPEndPoint);
  1583. }
  1584. }
  1585. #endregion
  1586. #region public
  1587. public void Start()
  1588. {
  1589. if (_disposed)
  1590. throw new ObjectDisposedException("DnsServer");
  1591. if (_state != ServiceState.Stopped)
  1592. throw new InvalidOperationException("DNS Server is already running.");
  1593. _state = ServiceState.Starting;
  1594. //bind on all local end points
  1595. foreach (IPEndPoint localEP in _localEndPoints)
  1596. {
  1597. Socket udpListener = null;
  1598. try
  1599. {
  1600. udpListener = new Socket(localEP.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
  1601. #region this code ignores ICMP port unreachable responses which creates SocketException in ReceiveFrom()
  1602. if (Environment.OSVersion.Platform == PlatformID.Win32NT)
  1603. {
  1604. const uint IOC_IN = 0x80000000;
  1605. const uint IOC_VENDOR = 0x18000000;
  1606. const uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
  1607. udpListener.IOControl((IOControlCode)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
  1608. }
  1609. #endregion
  1610. udpListener.ReceiveBufferSize = 64 * 1024;
  1611. udpListener.SendBufferSize = 64 * 1024;
  1612. udpListener.Bind(localEP);
  1613. _udpListeners.Add(udpListener);
  1614. LogManager log = _log;
  1615. if (log != null)
  1616. log.Write(localEP, DnsTransportProtocol.Udp, "DNS Server was bound successfully.");
  1617. }
  1618. catch (Exception ex)
  1619. {
  1620. LogManager log = _log;
  1621. if (log != null)
  1622. log.Write(localEP, DnsTransportProtocol.Udp, "DNS Server failed to bind.\r\n" + ex.ToString());
  1623. if (udpListener != null)
  1624. udpListener.Dispose();
  1625. }
  1626. Socket tcpListener = null;
  1627. try
  1628. {
  1629. tcpListener = new Socket(localEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  1630. tcpListener.Bind(localEP);
  1631. tcpListener.Listen(100);
  1632. _tcpListeners.Add(tcpListener);
  1633. LogManager log = _log;
  1634. if (log != null)
  1635. log.Write(localEP, DnsTransportProtocol.Tcp, "DNS Server was bound successfully.");
  1636. }
  1637. catch (Exception ex)
  1638. {
  1639. LogManager log = _log;
  1640. if (log != null)
  1641. log.Write(localEP, DnsTransportProtocol.Tcp, "DNS Server failed to bind.\r\n" + ex.ToString());
  1642. if (tcpListener != null)
  1643. tcpListener.Dispose();
  1644. }
  1645. if (_enableDnsOverHttp)
  1646. {
  1647. IPEndPoint httpEP = new IPEndPoint(localEP.Address, 8053);
  1648. Socket httpListener = null;
  1649. try
  1650. {
  1651. httpListener = new Socket(httpEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  1652. httpListener.Bind(httpEP);
  1653. httpListener.Listen(100);
  1654. _httpListeners.Add(httpListener);
  1655. _isDnsOverHttpsEnabled = true;
  1656. LogManager log = _log;
  1657. if (log != null)
  1658. log.Write(httpEP, "Http", "DNS Server was bound successfully.");
  1659. }
  1660. catch (Exception ex)
  1661. {
  1662. LogManager log = _log;
  1663. if (log != null)
  1664. log.Write(httpEP, "Http", "DNS Server failed to bind.\r\n" + ex.ToString());
  1665. if (httpListener != null)
  1666. httpListener.Dispose();
  1667. }
  1668. }
  1669. if (_enableDnsOverTls && (_certificate != null))
  1670. {
  1671. IPEndPoint tlsEP = new IPEndPoint(localEP.Address, 853);
  1672. Socket tlsListener = null;
  1673. try
  1674. {
  1675. tlsListener = new Socket(tlsEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  1676. tlsListener.Bind(tlsEP);
  1677. tlsListener.Listen(100);
  1678. _tlsListeners.Add(tlsListener);
  1679. LogManager log = _log;
  1680. if (log != null)
  1681. log.Write(tlsEP, DnsTransportProtocol.Tls, "DNS Server was bound successfully.");
  1682. }
  1683. catch (Exception ex)
  1684. {
  1685. LogManager log = _log;
  1686. if (log != null)
  1687. log.Write(tlsEP, DnsTransportProtocol.Tls, "DNS Server failed to bind.\r\n" + ex.ToString());
  1688. if (tlsListener != null)
  1689. tlsListener.Dispose();
  1690. }
  1691. }
  1692. if (_enableDnsOverHttps)
  1693. {
  1694. //bind to http port 80 for certbot webroot support
  1695. {
  1696. IPEndPoint httpEP = new IPEndPoint(localEP.Address, 80);
  1697. Socket httpListener = null;
  1698. try
  1699. {
  1700. httpListener = new Socket(httpEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  1701. httpListener.Bind(httpEP);
  1702. httpListener.Listen(100);
  1703. _httpListeners.Add(httpListener);
  1704. LogManager log = _log;
  1705. if (log != null)
  1706. log.Write(httpEP, "Http", "DNS Server was bound successfully.");
  1707. }
  1708. catch (Exception ex)
  1709. {
  1710. LogManager log = _log;
  1711. if (log != null)
  1712. log.Write(httpEP, "Http", "DNS Server failed to bind.\r\n" + ex.ToString());
  1713. if (httpListener != null)
  1714. httpListener.Dispose();
  1715. }
  1716. }
  1717. //bind to https port 443
  1718. if (_certificate != null)
  1719. {
  1720. IPEndPoint httpsEP = new IPEndPoint(localEP.Address, 443);
  1721. Socket httpsListener = null;
  1722. try
  1723. {
  1724. httpsListener = new Socket(httpsEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  1725. httpsListener.Bind(httpsEP);
  1726. httpsListener.Listen(100);
  1727. _httpsListeners.Add(httpsListener);
  1728. _isDnsOverHttpsEnabled = true;
  1729. LogManager log = _log;
  1730. if (log != null)
  1731. log.Write(httpsEP, DnsTransportProtocol.Https, "DNS Server was bound successfully.");
  1732. }
  1733. catch (Exception ex)
  1734. {
  1735. LogManager log = _log;
  1736. if (log != null)
  1737. log.Write(httpsEP, DnsTransportProtocol.Https, "DNS Server failed to bind.\r\n" + ex.ToString());
  1738. if (httpsListener != null)
  1739. httpsListener.Dispose();
  1740. }
  1741. }
  1742. }
  1743. }
  1744. //start reading query packets
  1745. int listenerThreadCount = Math.Max(1, Environment.ProcessorCount);
  1746. foreach (Socket udpListener in _udpListeners)
  1747. {
  1748. for (int i = 0; i < listenerThreadCount; i++)
  1749. {
  1750. Thread thread = new Thread(ReadUdpRequestAsync);
  1751. thread.Name = "DNS UDP Read Request [" + i + "]";
  1752. thread.IsBackground = true;
  1753. thread.Start(udpListener);
  1754. }
  1755. }
  1756. foreach (Socket tcpListener in _tcpListeners)
  1757. {
  1758. for (int i = 0; i < listenerThreadCount; i++)
  1759. {
  1760. Thread thread = new Thread(AcceptConnectionAsync);
  1761. thread.Name = "DNS TCP Read Request [" + i + "]";
  1762. thread.IsBackground = true;
  1763. thread.Start(new object[] { tcpListener, DnsTransportProtocol.Tcp });
  1764. }
  1765. }
  1766. foreach (Socket httpListener in _httpListeners)
  1767. {
  1768. for (int i = 0; i < listenerThreadCount; i++)
  1769. {
  1770. Thread thread = new Thread(AcceptConnectionAsync);
  1771. thread.Name = "DNS HTTP Read Request [" + i + "]";
  1772. thread.IsBackground = true;
  1773. thread.Start(new object[] { httpListener, DnsTransportProtocol.Https, false });
  1774. }
  1775. }
  1776. foreach (Socket tlsListener in _tlsListeners)
  1777. {
  1778. for (int i = 0; i < listenerThreadCount; i++)
  1779. {
  1780. Thread thread = new Thread(AcceptConnectionAsync);
  1781. thread.Name = "DNS TLS Read Request [" + i + "]";
  1782. thread.IsBackground = true;
  1783. thread.Start(new object[] { tlsListener, DnsTransportProtocol.Tls });
  1784. }
  1785. }
  1786. foreach (Socket httpsListener in _httpsListeners)
  1787. {
  1788. for (int i = 0; i < listenerThreadCount; i++)
  1789. {
  1790. Thread thread = new Thread(AcceptConnectionAsync);
  1791. thread.Name = "DNS HTTPS Read Request [" + i + "]";
  1792. thread.IsBackground = true;
  1793. thread.Start(new object[] { httpsListener, DnsTransportProtocol.Https });
  1794. }
  1795. }
  1796. _cachePrefetchSamplingTimer = new Timer(CachePrefetchSamplingTimerCallback, null, Timeout.Infinite, Timeout.Infinite);
  1797. _cachePrefetchRefreshTimer = new Timer(CachePrefetchRefreshTimerCallback, null, Timeout.Infinite, Timeout.Infinite);
  1798. _cacheMaintenanceTimer = new Timer(CacheMaintenanceTimerCallback, null, CACHE_MAINTENANCE_TIMER_INITIAL_INTEVAL, CACHE_MAINTENANCE_TIMER_PERIODIC_INTERVAL);
  1799. _state = ServiceState.Running;
  1800. UpdateThisServer();
  1801. ResetPrefetchTimers();
  1802. }
  1803. public void Stop()
  1804. {
  1805. if (_state != ServiceState.Running)
  1806. return;
  1807. _state = ServiceState.Stopping;
  1808. lock (_cachePrefetchSamplingTimerLock)
  1809. {
  1810. if (_cachePrefetchSamplingTimer != null)
  1811. {
  1812. _cachePrefetchSamplingTimer.Dispose();
  1813. _cachePrefetchSamplingTimer = null;
  1814. }
  1815. }
  1816. lock (_cachePrefetchRefreshTimerLock)
  1817. {
  1818. if (_cachePrefetchRefreshTimer != null)
  1819. {
  1820. _cachePrefetchRefreshTimer.Dispose();
  1821. _cachePrefetchRefreshTimer = null;
  1822. }
  1823. }
  1824. if (_cacheMaintenanceTimer != null)
  1825. {
  1826. _cacheMaintenanceTimer.Dispose();
  1827. _cacheMaintenanceTimer = null;
  1828. }
  1829. if (Environment.OSVersion.Platform == PlatformID.Win32NT)
  1830. {
  1831. foreach (Socket udpListener in _udpListeners)
  1832. udpListener.Dispose();
  1833. foreach (Socket tcpListener in _tcpListeners)
  1834. tcpListener.Dispose();
  1835. foreach (Socket httpListener in _httpListeners)
  1836. httpListener.Dispose();
  1837. foreach (Socket tlsListener in _tlsListeners)
  1838. tlsListener.Dispose();
  1839. foreach (Socket httpsListener in _httpsListeners)
  1840. httpsListener.Dispose();
  1841. }
  1842. else
  1843. {
  1844. //issue: https://github.com/dotnet/runtime/issues/37873
  1845. foreach (Socket udpListener in _udpListeners)
  1846. {
  1847. ThreadPool.QueueUserWorkItem(delegate (object state)
  1848. {
  1849. udpListener.Dispose();
  1850. });
  1851. }
  1852. foreach (Socket tcpListener in _tcpListeners)
  1853. {
  1854. ThreadPool.QueueUserWorkItem(delegate (object state)
  1855. {
  1856. tcpListener.Dispose();
  1857. });
  1858. }
  1859. foreach (Socket httpListener in _httpListeners)
  1860. {
  1861. ThreadPool.QueueUserWorkItem(delegate (object state)
  1862. {
  1863. httpListener.Dispose();
  1864. });
  1865. }
  1866. foreach (Socket tlsListener in _tlsListeners)
  1867. {
  1868. ThreadPool.QueueUserWorkItem(delegate (object state)
  1869. {
  1870. tlsListener.Dispose();
  1871. });
  1872. }
  1873. foreach (Socket httpsListener in _httpsListeners)
  1874. {
  1875. ThreadPool.QueueUserWorkItem(delegate (object state)
  1876. {
  1877. httpsListener.Dispose();
  1878. });
  1879. }
  1880. }
  1881. _udpListeners.Clear();
  1882. _tcpListeners.Clear();
  1883. _httpListeners.Clear();
  1884. _tlsListeners.Clear();
  1885. _httpsListeners.Clear();
  1886. _state = ServiceState.Stopped;
  1887. }
  1888. public async Task<DnsDatagram> DirectQueryAsync(DnsQuestionRecord question, int timeout = 2000)
  1889. {
  1890. try
  1891. {
  1892. Task<DnsDatagram> task = ProcessQueryAsync(new DnsDatagram(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { question }), new IPEndPoint(IPAddress.Any, 0), true, DnsTransportProtocol.Tcp);
  1893. using (CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource())
  1894. {
  1895. if (await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token)) != task)
  1896. return null;
  1897. timeoutCancellationTokenSource.Cancel(); //stop delay task
  1898. }
  1899. return await task;
  1900. }
  1901. catch (Exception ex)
  1902. {
  1903. LogManager log = _log;
  1904. if (log != null)
  1905. log.Write(ex);
  1906. return null;
  1907. }
  1908. }
  1909. #endregion
  1910. #region properties
  1911. public string ServerDomain
  1912. {
  1913. get { return _serverDomain; }
  1914. set
  1915. {
  1916. if (!_serverDomain.Equals(value))
  1917. {
  1918. _serverDomain = value.ToLower();
  1919. _authZoneManager.ServerDomain = _serverDomain;
  1920. _allowedZoneManager.ServerDomain = _serverDomain;
  1921. _blockedZoneManager.ServerDomain = _serverDomain;
  1922. _blockListZoneManager.ServerDomain = _serverDomain;
  1923. UpdateThisServer();
  1924. }
  1925. }
  1926. }
  1927. public string ConfigFolder
  1928. { get { return _configFolder; } }
  1929. public IReadOnlyList<IPEndPoint> LocalEndPoints
  1930. {
  1931. get { return _localEndPoints; }
  1932. set { _localEndPoints = value; }
  1933. }
  1934. public NameServerAddress ThisServer
  1935. { get { return _thisServer; } }
  1936. public bool EnableDnsOverHttp
  1937. {
  1938. get { return _enableDnsOverHttp; }
  1939. set { _enableDnsOverHttp = value; }
  1940. }
  1941. public bool EnableDnsOverTls
  1942. {
  1943. get { return _enableDnsOverTls; }
  1944. set { _enableDnsOverTls = value; }
  1945. }
  1946. public bool EnableDnsOverHttps
  1947. {
  1948. get { return _enableDnsOverHttps; }
  1949. set { _enableDnsOverHttps = value; }
  1950. }
  1951. public bool IsDnsOverHttpsEnabled
  1952. { get { return _isDnsOverHttpsEnabled; } }
  1953. public X509Certificate2 Certificate
  1954. {
  1955. get { return _certificate; }
  1956. set
  1957. {
  1958. if (!value.HasPrivateKey)
  1959. throw new ArgumentException("Tls certificate does not contain private key.");
  1960. _certificate = value;
  1961. }
  1962. }
  1963. public AuthZoneManager AuthZoneManager
  1964. { get { return _authZoneManager; } }
  1965. public AllowedZoneManager AllowedZoneManager
  1966. { get { return _allowedZoneManager; } }
  1967. public BlockedZoneManager BlockedZoneManager
  1968. { get { return _blockedZoneManager; } }
  1969. public BlockListZoneManager BlockListZoneManager
  1970. { get { return _blockListZoneManager; } }
  1971. public CacheZoneManager CacheZoneManager
  1972. { get { return _cacheZoneManager; } }
  1973. public IDnsCache DnsCache
  1974. { get { return _dnsCache; } }
  1975. public bool AllowRecursion
  1976. {
  1977. get { return _allowRecursion; }
  1978. set { _allowRecursion = value; }
  1979. }
  1980. public bool AllowRecursionOnlyForPrivateNetworks
  1981. {
  1982. get { return _allowRecursionOnlyForPrivateNetworks; }
  1983. set { _allowRecursionOnlyForPrivateNetworks = value; }
  1984. }
  1985. public NetProxy Proxy
  1986. {
  1987. get { return _proxy; }
  1988. set { _proxy = value; }
  1989. }
  1990. public IReadOnlyList<NameServerAddress> Forwarders
  1991. {
  1992. get { return _forwarders; }
  1993. set { _forwarders = value; }
  1994. }
  1995. public bool PreferIPv6
  1996. {
  1997. get { return _preferIPv6; }
  1998. set { _preferIPv6 = value; }
  1999. }
  2000. public int ForwarderRetries
  2001. {
  2002. get { return _forwarderRetries; }
  2003. set
  2004. {
  2005. if (value > 0)
  2006. _forwarderRetries = value;
  2007. }
  2008. }
  2009. public int ResolverRetries
  2010. {
  2011. get { return _resolverRetries; }
  2012. set
  2013. {
  2014. if (value > 0)
  2015. _resolverRetries = value;
  2016. }
  2017. }
  2018. public int ForwarderTimeout
  2019. {
  2020. get { return _forwarderTimeout; }
  2021. set
  2022. {
  2023. if (value >= 2000)
  2024. _forwarderTimeout = value;
  2025. }
  2026. }
  2027. public int ResolverTimeout
  2028. {
  2029. get { return _resolverTimeout; }
  2030. set
  2031. {
  2032. if (value >= 2000)
  2033. _resolverTimeout = value;
  2034. }
  2035. }
  2036. public int ClientTimeout
  2037. {
  2038. get { return _clientTimeout; }
  2039. set
  2040. {
  2041. if (value >= 2000)
  2042. _clientTimeout = value;
  2043. }
  2044. }
  2045. public int ForwarderConcurrency
  2046. {
  2047. get { return _forwarderConcurrency; }
  2048. set { _forwarderConcurrency = value; }
  2049. }
  2050. public int ResolverMaxStackCount
  2051. {
  2052. get { return _resolverMaxStackCount; }
  2053. set { _resolverMaxStackCount = value; }
  2054. }
  2055. public int CachePrefetchEligibility
  2056. {
  2057. get { return _cachePrefetchEligibility; }
  2058. set
  2059. {
  2060. if (value < 2)
  2061. throw new ArgumentOutOfRangeException("CachePrefetchEligibility", "Valid value is greater that or equal to 2.");
  2062. _cachePrefetchEligibility = value;
  2063. }
  2064. }
  2065. public int CachePrefetchTrigger
  2066. {
  2067. get { return _cachePrefetchTrigger; }
  2068. set
  2069. {
  2070. if (value < 0)
  2071. throw new ArgumentOutOfRangeException("CachePrefetchTrigger", "Valid value is greater that or equal to 0.");
  2072. if (_cachePrefetchTrigger != value)
  2073. {
  2074. _cachePrefetchTrigger = value;
  2075. ResetPrefetchTimers();
  2076. }
  2077. }
  2078. }
  2079. public int CachePrefetchSampleIntervalInMinutes
  2080. {
  2081. get { return _cachePrefetchSampleIntervalInMinutes; }
  2082. set
  2083. {
  2084. if ((value < 1) || (value > 60))
  2085. throw new ArgumentOutOfRangeException("CacheRefreshSampleIntervalInMinutes", "Valid range is between 1 and 60 minutes.");
  2086. if (_cachePrefetchSampleIntervalInMinutes != value)
  2087. {
  2088. _cachePrefetchSampleIntervalInMinutes = value;
  2089. ResetPrefetchTimers();
  2090. }
  2091. }
  2092. }
  2093. public int CachePrefetchSampleEligibilityHitsPerHour
  2094. {
  2095. get { return _cachePrefetchSampleEligibilityHitsPerHour; }
  2096. set
  2097. {
  2098. if (value < 1)
  2099. throw new ArgumentOutOfRangeException("CachePrefetchSampleEligibilityHitsPerHour", "Valid value is greater than or equal to 1.");
  2100. _cachePrefetchSampleEligibilityHitsPerHour = value;
  2101. }
  2102. }
  2103. public LogManager LogManager
  2104. {
  2105. get { return _log; }
  2106. set { _log = value; }
  2107. }
  2108. public LogManager QueryLogManager
  2109. {
  2110. get { return _queryLog; }
  2111. set { _queryLog = value; }
  2112. }
  2113. public StatsManager StatsManager
  2114. { get { return _stats; } }
  2115. public int TcpSendTimeout
  2116. {
  2117. get { return _tcpSendTimeout; }
  2118. set { _tcpSendTimeout = value; }
  2119. }
  2120. public int TcpReceiveTimeout
  2121. {
  2122. get { return _tcpReceiveTimeout; }
  2123. set { _tcpReceiveTimeout = value; }
  2124. }
  2125. #endregion
  2126. }
  2127. }