ApexZone.cs 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512
  1. /*
  2. Technitium DNS Server
  3. Copyright (C) 2024 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.ResourceRecords;
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Net;
  19. using System.Threading;
  20. using System.Threading.Tasks;
  21. using TechnitiumLibrary.Net;
  22. using TechnitiumLibrary.Net.Dns;
  23. using TechnitiumLibrary.Net.Dns.ResourceRecords;
  24. namespace DnsServerCore.Dns.Zones
  25. {
  26. public enum AuthZoneQueryAccess : byte
  27. {
  28. Deny = 0,
  29. Allow = 1,
  30. AllowOnlyPrivateNetworks = 2,
  31. AllowOnlyZoneNameServers = 3,
  32. UseSpecifiedNetworkACL = 4,
  33. AllowZoneNameServersAndUseSpecifiedNetworkACL = 5
  34. }
  35. public enum AuthZoneTransfer : byte
  36. {
  37. Deny = 0,
  38. Allow = 1,
  39. AllowOnlyZoneNameServers = 2,
  40. UseSpecifiedNetworkACL = 3,
  41. AllowZoneNameServersAndUseSpecifiedNetworkACL = 4
  42. }
  43. public enum AuthZoneNotify : byte
  44. {
  45. None = 0,
  46. ZoneNameServers = 1,
  47. SpecifiedNameServers = 2,
  48. BothZoneAndSpecifiedNameServers = 3,
  49. SeparateNameServersForCatalogAndMemberZones = 4
  50. }
  51. public enum AuthZoneUpdate : byte
  52. {
  53. Deny = 0,
  54. Allow = 1,
  55. AllowOnlyZoneNameServers = 2,
  56. UseSpecifiedNetworkACL = 3,
  57. AllowZoneNameServersAndUseSpecifiedNetworkACL = 4
  58. }
  59. abstract class ApexZone : AuthZone, IDisposable
  60. {
  61. #region variables
  62. protected readonly DnsServer _dnsServer;
  63. protected DateTime _lastModified;
  64. string _catalogZoneName;
  65. bool _overrideCatalogQueryAccess;
  66. bool _overrideCatalogZoneTransfer;
  67. bool _overrideCatalogNotify;
  68. protected AuthZoneQueryAccess _queryAccess;
  69. IReadOnlyCollection<NetworkAccessControl> _queryAccessNetworkACL;
  70. protected AuthZoneTransfer _zoneTransfer;
  71. IReadOnlyCollection<NetworkAccessControl> _zoneTransferNetworkACL;
  72. IReadOnlyDictionary<string, object> _zoneTransferTsigKeyNames;
  73. readonly List<DnsResourceRecord> _zoneHistory; //for IXFR support
  74. AuthZoneNotify _notify;
  75. IReadOnlyCollection<IPAddress> _notifyNameServers;
  76. IReadOnlyCollection<IPAddress> _notifySecondaryCatalogNameServers;
  77. AuthZoneUpdate _update;
  78. IReadOnlyCollection<NetworkAccessControl> _updateNetworkACL;
  79. IReadOnlyDictionary<string, IReadOnlyDictionary<string, IReadOnlyList<DnsResourceRecordType>>> _updateSecurityPolicies;
  80. protected AuthZoneDnssecStatus _dnssecStatus;
  81. Timer _notifyTimer;
  82. bool _notifyTimerTriggered;
  83. const int NOTIFY_TIMER_INTERVAL = 10000;
  84. List<string> _notifyList;
  85. List<string> _notifyFailed;
  86. const int NOTIFY_TIMEOUT = 10000;
  87. const int NOTIFY_RETRIES = 5;
  88. protected bool _syncFailed;
  89. Timer _recordExpiryTimer;
  90. readonly object _recordExpiryTimerLock = new object();
  91. DateTime _recordExpiryTimerStartedOn;
  92. uint _recordExpiryTimerTtl;
  93. bool _recordExpiryTimerRunning;
  94. CatalogZone _catalogZone;
  95. SecondaryCatalogZone _secondaryCatalogZone;
  96. #endregion
  97. #region constructor
  98. protected ApexZone(DnsServer dnsServer, AuthZoneInfo zoneInfo)
  99. : base(zoneInfo)
  100. {
  101. _dnsServer = dnsServer;
  102. _catalogZoneName = zoneInfo.CatalogZoneName;
  103. _overrideCatalogQueryAccess = zoneInfo.OverrideCatalogQueryAccess;
  104. _overrideCatalogZoneTransfer = zoneInfo.OverrideCatalogZoneTransfer;
  105. _overrideCatalogNotify = zoneInfo.OverrideCatalogNotify;
  106. _queryAccess = zoneInfo.QueryAccess;
  107. _queryAccessNetworkACL = zoneInfo.QueryAccessNetworkACL;
  108. _zoneTransfer = zoneInfo.ZoneTransfer;
  109. _zoneTransferNetworkACL = zoneInfo.ZoneTransferNetworkACL;
  110. _zoneTransferTsigKeyNames = zoneInfo.ZoneTransferTsigKeyNames;
  111. if (zoneInfo.ZoneHistory is null)
  112. _zoneHistory = new List<DnsResourceRecord>();
  113. else
  114. _zoneHistory = new List<DnsResourceRecord>(zoneInfo.ZoneHistory);
  115. _notify = zoneInfo.Notify;
  116. _notifyNameServers = zoneInfo.NotifyNameServers;
  117. _notifySecondaryCatalogNameServers = zoneInfo.NotifySecondaryCatalogNameServers;
  118. _update = zoneInfo.Update;
  119. _updateNetworkACL = zoneInfo.UpdateNetworkACL;
  120. _updateSecurityPolicies = zoneInfo.UpdateSecurityPolicies;
  121. _lastModified = zoneInfo.LastModified;
  122. }
  123. protected ApexZone(DnsServer dnsServer, string name)
  124. : base(name)
  125. {
  126. _dnsServer = dnsServer;
  127. _queryAccess = AuthZoneQueryAccess.Allow;
  128. _zoneHistory = new List<DnsResourceRecord>();
  129. _lastModified = DateTime.UtcNow;
  130. }
  131. #endregion
  132. #region IDisposable
  133. bool _disposed;
  134. protected virtual void Dispose(bool disposing)
  135. {
  136. if (_disposed)
  137. return;
  138. if (disposing)
  139. {
  140. _notifyTimer?.Dispose();
  141. lock (_recordExpiryTimerLock)
  142. {
  143. if (_recordExpiryTimer is not null)
  144. {
  145. _recordExpiryTimer.Dispose();
  146. _recordExpiryTimer = null;
  147. }
  148. }
  149. }
  150. _disposed = true;
  151. }
  152. public void Dispose()
  153. {
  154. Dispose(true);
  155. }
  156. #endregion
  157. #region notify
  158. protected void InitNotify()
  159. {
  160. _notifyTimer = new Timer(NotifyTimerCallback, null, Timeout.Infinite, Timeout.Infinite);
  161. _notifyList = new List<string>();
  162. _notifyFailed = new List<string>();
  163. }
  164. protected void DisableNotifyTimer()
  165. {
  166. if (_notifyTimer is not null)
  167. _notifyTimer.Change(Timeout.Infinite, Timeout.Infinite);
  168. }
  169. private async void NotifyTimerCallback(object state)
  170. {
  171. ApexZone apexZone = this;
  172. if ((apexZone.CatalogZone is not null) && !apexZone.OverrideCatalogNotify)
  173. apexZone = apexZone.CatalogZone;
  174. List<string> notifiedNameServers = new List<string>();
  175. async Task NotifyZoneNameServersAsync(bool onlyFailedNameServers)
  176. {
  177. string primaryNameServer = (_entries[DnsResourceRecordType.SOA][0].RDATA as DnsSOARecordData).PrimaryNameServer;
  178. IReadOnlyList<DnsResourceRecord> nsRecords = GetRecords(DnsResourceRecordType.NS); //stub zone has no authority so cant use QueryRecords
  179. //notify all secondary name servers
  180. List<Task> tasks = new List<Task>();
  181. foreach (DnsResourceRecord nsRecord in nsRecords)
  182. {
  183. if (nsRecord.GetAuthGenericRecordInfo().Disabled)
  184. continue;
  185. string nameServerHost = (nsRecord.RDATA as DnsNSRecordData).NameServer;
  186. if (primaryNameServer.Equals(nameServerHost, StringComparison.OrdinalIgnoreCase))
  187. continue; //skip primary name server
  188. if (onlyFailedNameServers)
  189. {
  190. lock (_notifyFailed)
  191. {
  192. if (!_notifyFailed.Contains(nameServerHost))
  193. continue;
  194. }
  195. }
  196. notifiedNameServers.Add(nameServerHost);
  197. List<NameServerAddress> nameServers = new List<NameServerAddress>(2);
  198. await ResolveNameServerAddressesAsync(nsRecord, nameServers);
  199. if (nameServers.Count > 0)
  200. {
  201. tasks.Add(NotifyNameServerAsync(nameServerHost, nameServers));
  202. }
  203. else
  204. {
  205. lock (_notifyFailed)
  206. {
  207. if (!_notifyFailed.Contains(nameServerHost))
  208. _notifyFailed.Add(nameServerHost);
  209. }
  210. _dnsServer.LogManager?.Write("DNS Server failed to notify name server '" + nameServerHost + "' due to failure in resolving its IP address for zone: " + ToString());
  211. }
  212. }
  213. await Task.WhenAll(tasks);
  214. }
  215. Task NotifySpecifiedNameServersAsync(bool onlyFailedNameServers)
  216. {
  217. IReadOnlyCollection<IPAddress> specifiedNameServers = apexZone._notifyNameServers;
  218. if (specifiedNameServers is not null)
  219. return NotifyNameServersAsync(specifiedNameServers, onlyFailedNameServers);
  220. return Task.CompletedTask;
  221. }
  222. Task NotifySecondaryCatalogNameServersAsync(bool onlyFailedNameServers)
  223. {
  224. IReadOnlyCollection<IPAddress> secondaryCatalogNameServers = apexZone._notifySecondaryCatalogNameServers;
  225. if (secondaryCatalogNameServers is not null)
  226. return NotifyNameServersAsync(secondaryCatalogNameServers, onlyFailedNameServers);
  227. return Task.CompletedTask;
  228. }
  229. async Task NotifyNameServersAsync(IReadOnlyCollection<IPAddress> nameServerIpAddresses, bool onlyFailedNameServers)
  230. {
  231. List<Task> tasks = new List<Task>();
  232. foreach (IPAddress nameServerIpAddress in nameServerIpAddresses)
  233. {
  234. string nameServerHost = nameServerIpAddress.ToString();
  235. if (onlyFailedNameServers)
  236. {
  237. lock (_notifyFailed)
  238. {
  239. if (!_notifyFailed.Contains(nameServerHost))
  240. continue;
  241. }
  242. }
  243. notifiedNameServers.Add(nameServerHost);
  244. tasks.Add(NotifyNameServerAsync(nameServerHost, [new NameServerAddress(nameServerIpAddress)]));
  245. }
  246. await Task.WhenAll(tasks);
  247. }
  248. try
  249. {
  250. switch (apexZone._notify)
  251. {
  252. case AuthZoneNotify.ZoneNameServers:
  253. await NotifyZoneNameServersAsync(!_notifyTimerTriggered);
  254. break;
  255. case AuthZoneNotify.SpecifiedNameServers:
  256. await NotifySpecifiedNameServersAsync(!_notifyTimerTriggered);
  257. break;
  258. case AuthZoneNotify.BothZoneAndSpecifiedNameServers:
  259. Task t1 = NotifyZoneNameServersAsync(!_notifyTimerTriggered);
  260. Task t2 = NotifySpecifiedNameServersAsync(!_notifyTimerTriggered);
  261. await Task.WhenAll(t1, t2);
  262. break;
  263. case AuthZoneNotify.SeparateNameServersForCatalogAndMemberZones:
  264. if (this is CatalogZone)
  265. await NotifySecondaryCatalogNameServersAsync(!_notifyTimerTriggered);
  266. else
  267. await NotifySpecifiedNameServersAsync(!_notifyTimerTriggered);
  268. break;
  269. }
  270. //remove non-existent name servers from notify failed list
  271. lock (_notifyFailed)
  272. {
  273. if (_notifyFailed.Count > 0)
  274. {
  275. List<string> toRemove = new List<string>();
  276. foreach (string failedNameServer in _notifyFailed)
  277. {
  278. if (!notifiedNameServers.Contains(failedNameServer))
  279. toRemove.Add(failedNameServer);
  280. }
  281. foreach (string failedNameServer in toRemove)
  282. _notifyFailed.Remove(failedNameServer);
  283. if (_notifyFailed.Count > 0)
  284. {
  285. //set timer to notify failed name servers again
  286. int retryInterval = (int)((_entries[DnsResourceRecordType.SOA][0].RDATA as DnsSOARecordData).Retry * 1000);
  287. _notifyTimer.Change(retryInterval, Timeout.Infinite);
  288. }
  289. }
  290. }
  291. }
  292. catch (Exception ex)
  293. {
  294. _dnsServer.LogManager?.Write(ex);
  295. }
  296. finally
  297. {
  298. _notifyTimerTriggered = false;
  299. }
  300. }
  301. private async Task NotifyNameServerAsync(string nameServerHost, IReadOnlyList<NameServerAddress> nameServers)
  302. {
  303. //use notify list to prevent multiple threads from notifying the same name server
  304. lock (_notifyList)
  305. {
  306. if (_notifyList.Contains(nameServerHost))
  307. return; //already notifying the name server in another thread
  308. _notifyList.Add(nameServerHost);
  309. }
  310. try
  311. {
  312. DnsClient client = new DnsClient(nameServers);
  313. client.Proxy = _dnsServer.Proxy;
  314. client.Timeout = NOTIFY_TIMEOUT;
  315. client.Retries = NOTIFY_RETRIES;
  316. DnsDatagram notifyRequest = new DnsDatagram(0, false, DnsOpcode.Notify, true, false, false, false, false, false, DnsResponseCode.NoError, new DnsQuestionRecord[] { new DnsQuestionRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN) }, _entries[DnsResourceRecordType.SOA]);
  317. DnsDatagram response = await client.RawResolveAsync(notifyRequest);
  318. switch (response.RCODE)
  319. {
  320. case DnsResponseCode.NoError:
  321. case DnsResponseCode.NotImplemented:
  322. {
  323. //transaction complete
  324. lock (_notifyFailed)
  325. {
  326. _notifyFailed.Remove(nameServerHost);
  327. }
  328. _dnsServer.LogManager?.Write("DNS Server successfully notified name server '" + nameServerHost + "' for zone: " + ToString());
  329. }
  330. break;
  331. default:
  332. {
  333. //transaction failed
  334. lock (_notifyFailed)
  335. {
  336. if (!_notifyFailed.Contains(nameServerHost))
  337. _notifyFailed.Add(nameServerHost);
  338. }
  339. _dnsServer.LogManager?.Write("DNS Server failed to notify name server '" + nameServerHost + "' (RCODE=" + response.RCODE.ToString() + ") for zone: " + ToString());
  340. }
  341. break;
  342. }
  343. }
  344. catch (Exception ex)
  345. {
  346. lock (_notifyFailed)
  347. {
  348. if (!_notifyFailed.Contains(nameServerHost))
  349. _notifyFailed.Add(nameServerHost);
  350. }
  351. _dnsServer.LogManager?.Write("DNS Server failed to notify name server '" + nameServerHost + "' for zone: " + ToString() + "\r\n" + ex.ToString());
  352. }
  353. finally
  354. {
  355. lock (_notifyList)
  356. {
  357. _notifyList.Remove(nameServerHost);
  358. }
  359. }
  360. }
  361. internal void RemoveFromNotifyFailedList(NameServerAddress allowedZoneNameServer, IPAddress allowedIPAddress)
  362. {
  363. if (_notifyFailed is null)
  364. return;
  365. lock (_notifyFailed)
  366. {
  367. if (_notifyFailed.Count == 0)
  368. return;
  369. if ((allowedZoneNameServer is not null) && (allowedZoneNameServer.DomainEndPoint is not null))
  370. _notifyFailed.Remove(allowedZoneNameServer.DomainEndPoint.Address);
  371. _notifyFailed.Remove(allowedIPAddress.ToString());
  372. }
  373. }
  374. public void TriggerNotify()
  375. {
  376. if (Disabled)
  377. return;
  378. ApexZone apexZone = this;
  379. if ((apexZone.CatalogZone is not null) && !apexZone.OverrideCatalogNotify)
  380. apexZone = apexZone.CatalogZone;
  381. if (apexZone._notify == AuthZoneNotify.None)
  382. {
  383. if (_notifyFailed is not null)
  384. {
  385. lock (_notifyFailed)
  386. {
  387. _notifyFailed.Clear();
  388. }
  389. }
  390. return;
  391. }
  392. if (_notifyTimerTriggered)
  393. return;
  394. if (_disposed)
  395. return;
  396. if (_notifyTimer is null)
  397. return;
  398. _notifyTimer.Change(NOTIFY_TIMER_INTERVAL, Timeout.Infinite);
  399. _notifyTimerTriggered = true;
  400. }
  401. #endregion
  402. #region record expiry
  403. protected void InitRecordExpiry()
  404. {
  405. _recordExpiryTimer = new Timer(RecordExpiryTimerCallback, null, Timeout.Infinite, Timeout.Infinite);
  406. }
  407. private uint GetMinRecordExpiryTtl(uint minExpiryTtl)
  408. {
  409. if (!_recordExpiryTimerRunning)
  410. return Math.Min(minExpiryTtl, uint.MaxValue / 1000);
  411. uint elapsedSeconds = Convert.ToUInt32((DateTime.UtcNow - _recordExpiryTimerStartedOn).TotalSeconds);
  412. if (elapsedSeconds >= _recordExpiryTimerTtl)
  413. return 0u;
  414. uint pendingExpiryTtl = _recordExpiryTimerTtl - elapsedSeconds;
  415. return Math.Min(Math.Min(pendingExpiryTtl, minExpiryTtl), uint.MaxValue / 1000);
  416. }
  417. public void StartRecordExpiryTimer(uint minExpiryTtl)
  418. {
  419. lock (_recordExpiryTimerLock)
  420. {
  421. if (_recordExpiryTimer is not null)
  422. {
  423. uint minTtl = GetMinRecordExpiryTtl(minExpiryTtl);
  424. _recordExpiryTimer.Change(minTtl * 1000, Timeout.Infinite);
  425. _recordExpiryTimerStartedOn = DateTime.UtcNow;
  426. _recordExpiryTimerTtl = minTtl;
  427. _recordExpiryTimerRunning = true;
  428. }
  429. }
  430. }
  431. private void RecordExpiryTimerCallback(object state)
  432. {
  433. _recordExpiryTimerRunning = false;
  434. uint minExpiryTtl = 0u;
  435. try
  436. {
  437. IReadOnlyList<AuthZone> authZones = _dnsServer.AuthZoneManager.GetApexZoneWithSubDomainZones(_name);
  438. bool recordsDeleted = false;
  439. foreach (AuthZone authZone in authZones)
  440. {
  441. foreach (KeyValuePair<DnsResourceRecordType, IReadOnlyList<DnsResourceRecord>> entry in authZone.Entries)
  442. {
  443. foreach (DnsResourceRecord record in entry.Value)
  444. {
  445. GenericRecordInfo recordInfo = record.GetAuthGenericRecordInfo();
  446. if (recordInfo.ExpiryTtl > 0u)
  447. {
  448. uint pendingExpiryTtl = recordInfo.GetPendingExpiryTtl();
  449. if (pendingExpiryTtl == 0u)
  450. {
  451. if (_dnsServer.AuthZoneManager.DeleteRecord(_name, record))
  452. recordsDeleted = true;
  453. }
  454. else
  455. {
  456. if (minExpiryTtl == 0u)
  457. minExpiryTtl = pendingExpiryTtl;
  458. else
  459. minExpiryTtl = Math.Min(minExpiryTtl, pendingExpiryTtl);
  460. }
  461. }
  462. }
  463. }
  464. }
  465. if (recordsDeleted)
  466. _dnsServer.AuthZoneManager.SaveZoneFile(_name);
  467. }
  468. catch (Exception ex)
  469. {
  470. _dnsServer.LogManager?.Write(ex);
  471. }
  472. finally
  473. {
  474. if (minExpiryTtl > 0u)
  475. StartRecordExpiryTimer(minExpiryTtl);
  476. }
  477. }
  478. #endregion
  479. #region internal
  480. internal virtual void UpdateDnssecStatus()
  481. {
  482. if (!_entries.ContainsKey(DnsResourceRecordType.DNSKEY))
  483. _dnssecStatus = AuthZoneDnssecStatus.Unsigned;
  484. else if (_entries.ContainsKey(DnsResourceRecordType.NSEC3PARAM))
  485. _dnssecStatus = AuthZoneDnssecStatus.SignedWithNSEC3;
  486. else
  487. _dnssecStatus = AuthZoneDnssecStatus.SignedWithNSEC;
  488. }
  489. #endregion
  490. #region versioning
  491. internal virtual void CommitAndIncrementSerial(IReadOnlyList<DnsResourceRecord> deletedRecords = null, IReadOnlyList<DnsResourceRecord> addedRecords = null)
  492. {
  493. _lastModified = DateTime.UtcNow;
  494. if (addedRecords is not null)
  495. {
  496. uint minExpiryTtl = 0u;
  497. foreach (DnsResourceRecord addedRecord in addedRecords)
  498. {
  499. uint expiryTtl = addedRecord.GetAuthGenericRecordInfo().ExpiryTtl;
  500. if (expiryTtl > 0u)
  501. {
  502. if (minExpiryTtl == 0u)
  503. minExpiryTtl = expiryTtl;
  504. else
  505. minExpiryTtl = Math.Min(minExpiryTtl, expiryTtl);
  506. }
  507. }
  508. if (minExpiryTtl > 0u)
  509. StartRecordExpiryTimer(minExpiryTtl);
  510. }
  511. lock (_zoneHistory)
  512. {
  513. DnsResourceRecord oldSoaRecord = _entries[DnsResourceRecordType.SOA][0];
  514. DnsResourceRecord newSoaRecord;
  515. {
  516. DnsSOARecordData oldSoa = oldSoaRecord.RDATA as DnsSOARecordData;
  517. if ((addedRecords is not null) && (addedRecords.Count == 1) && (addedRecords[0].Type == DnsResourceRecordType.SOA))
  518. {
  519. DnsResourceRecord addSoaRecord = addedRecords[0];
  520. DnsSOARecordData addSoa = addSoaRecord.RDATA as DnsSOARecordData;
  521. uint serial = GetNewSerial(oldSoa.Serial, addSoa.Serial, addSoaRecord.GetAuthSOARecordInfo().UseSoaSerialDateScheme);
  522. newSoaRecord = new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, addSoaRecord.TTL, new DnsSOARecordData(addSoa.PrimaryNameServer, addSoa.ResponsiblePerson, serial, addSoa.Refresh, addSoa.Retry, addSoa.Expire, addSoa.Minimum)) { Tag = addSoaRecord.Tag };
  523. addedRecords = null;
  524. }
  525. else
  526. {
  527. uint serial = GetNewSerial(oldSoa.Serial, 0, oldSoaRecord.GetAuthSOARecordInfo().UseSoaSerialDateScheme);
  528. newSoaRecord = new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, oldSoaRecord.TTL, new DnsSOARecordData(oldSoa.PrimaryNameServer, oldSoa.ResponsiblePerson, serial, oldSoa.Refresh, oldSoa.Retry, oldSoa.Expire, oldSoa.Minimum)) { Tag = oldSoaRecord.Tag };
  529. }
  530. }
  531. DnsResourceRecord[] newSoaRecords = [newSoaRecord];
  532. //update SOA
  533. _entries[DnsResourceRecordType.SOA] = newSoaRecords;
  534. IReadOnlyList<DnsResourceRecord> newRRSigRecords = null;
  535. IReadOnlyList<DnsResourceRecord> deletedRRSigRecords = null;
  536. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  537. {
  538. //sign SOA and update RRSig
  539. newRRSigRecords = SignRRSet(newSoaRecords);
  540. AddOrUpdateRRSigRecords(newRRSigRecords, out deletedRRSigRecords);
  541. }
  542. //remove RR info from old SOA to allow creating new history RR info for setting DeletedOn
  543. oldSoaRecord.Tag = null;
  544. //start commit
  545. oldSoaRecord.GetAuthHistoryRecordInfo().DeletedOn = DateTime.UtcNow;
  546. //write removed
  547. _zoneHistory.Add(oldSoaRecord);
  548. if (deletedRecords is not null)
  549. {
  550. foreach (DnsResourceRecord deletedRecord in deletedRecords)
  551. {
  552. if (deletedRecord.GetAuthGenericRecordInfo().Disabled)
  553. continue;
  554. _zoneHistory.Add(deletedRecord);
  555. if (deletedRecord.Type == DnsResourceRecordType.NS)
  556. {
  557. IReadOnlyList<DnsResourceRecord> glueRecords = deletedRecord.GetAuthNSRecordInfo().GlueRecords;
  558. if (glueRecords is not null)
  559. _zoneHistory.AddRange(glueRecords);
  560. }
  561. }
  562. }
  563. if (deletedRRSigRecords is not null)
  564. _zoneHistory.AddRange(deletedRRSigRecords);
  565. //write added
  566. _zoneHistory.Add(newSoaRecord);
  567. if (addedRecords is not null)
  568. {
  569. foreach (DnsResourceRecord addedRecord in addedRecords)
  570. {
  571. if (addedRecord.GetAuthGenericRecordInfo().Disabled)
  572. continue;
  573. _zoneHistory.Add(addedRecord);
  574. if (addedRecord.Type == DnsResourceRecordType.NS)
  575. {
  576. IReadOnlyList<DnsResourceRecord> glueRecords = addedRecord.GetAuthNSRecordInfo().GlueRecords;
  577. if (glueRecords is not null)
  578. _zoneHistory.AddRange(glueRecords);
  579. }
  580. }
  581. }
  582. if (newRRSigRecords is not null)
  583. _zoneHistory.AddRange(newRRSigRecords);
  584. //end commit
  585. CleanupHistory();
  586. }
  587. }
  588. protected static uint GetNewSerial(uint oldSerial, uint updateSerial, bool useSoaSerialDateScheme)
  589. {
  590. if (useSoaSerialDateScheme)
  591. {
  592. string strOldSerial = oldSerial.ToString();
  593. string strOldSerialDate = null;
  594. byte counter = 0;
  595. if (strOldSerial.Length == 10)
  596. {
  597. //parse old serial
  598. strOldSerialDate = strOldSerial.Substring(0, 8);
  599. counter = byte.Parse(strOldSerial.Substring(8));
  600. }
  601. string strSerialDate = DateTime.UtcNow.ToString("yyyyMMdd");
  602. if (strOldSerialDate is null)
  603. {
  604. //transitioning to date scheme
  605. return uint.Parse(strSerialDate + counter.ToString().PadLeft(2, '0'));
  606. }
  607. else if (strSerialDate.Equals(strOldSerialDate))
  608. {
  609. //same date
  610. if (counter < 99)
  611. {
  612. counter++;
  613. return uint.Parse(strSerialDate + counter.ToString().PadLeft(2, '0'));
  614. }
  615. else
  616. {
  617. //more than 100 increments
  618. return uint.Parse(strSerialDate + counter.ToString().PadLeft(2, '0')) + 1;
  619. }
  620. }
  621. else if (uint.Parse(strSerialDate) > uint.Parse(strOldSerialDate))
  622. {
  623. //later date
  624. return uint.Parse(strSerialDate + "00");
  625. }
  626. }
  627. //default
  628. uint serial = oldSerial;
  629. if (updateSerial > serial)
  630. serial = updateSerial;
  631. else if (serial < uint.MaxValue)
  632. serial++;
  633. else
  634. serial = 1;
  635. return serial;
  636. }
  637. internal void SetSoaSerial(uint newSerial)
  638. {
  639. lock (_zoneHistory)
  640. {
  641. DnsResourceRecord oldSoaRecord = _entries[DnsResourceRecordType.SOA][0];
  642. DnsSOARecordData oldSoa = oldSoaRecord.RDATA as DnsSOARecordData;
  643. DnsResourceRecord newSoaRecord = new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, oldSoaRecord.TTL, new DnsSOARecordData(oldSoa.PrimaryNameServer, oldSoa.ResponsiblePerson, newSerial, oldSoa.Refresh, oldSoa.Retry, oldSoa.Expire, oldSoa.Minimum)) { Tag = oldSoaRecord.Tag };
  644. DnsResourceRecord[] newSoaRecords = [newSoaRecord];
  645. //update SOA
  646. _entries[DnsResourceRecordType.SOA] = newSoaRecords;
  647. //clear history
  648. _zoneHistory.Clear();
  649. }
  650. }
  651. public IReadOnlyList<DnsResourceRecord> GetZoneHistory()
  652. {
  653. lock (_zoneHistory)
  654. {
  655. return _zoneHistory.ToArray();
  656. }
  657. }
  658. protected void CleanupHistory()
  659. {
  660. DnsSOARecordData soa = _entries[DnsResourceRecordType.SOA][0].RDATA as DnsSOARecordData;
  661. DateTime expiry = DateTime.UtcNow.AddSeconds(-soa.Expire);
  662. int index = 0;
  663. while (index < _zoneHistory.Count)
  664. {
  665. //check difference sequence
  666. if (_zoneHistory[index].GetAuthHistoryRecordInfo().DeletedOn > expiry)
  667. break; //found record to keep
  668. //skip to next difference sequence
  669. index++;
  670. int soaCount = 1;
  671. while (index < _zoneHistory.Count)
  672. {
  673. if (_zoneHistory[index].Type == DnsResourceRecordType.SOA)
  674. {
  675. soaCount++;
  676. if (soaCount == 3)
  677. break;
  678. }
  679. index++;
  680. }
  681. }
  682. if (index == _zoneHistory.Count)
  683. {
  684. //delete entire history
  685. _zoneHistory.Clear();
  686. return;
  687. }
  688. //remove expired records
  689. _zoneHistory.RemoveRange(0, index);
  690. }
  691. protected void CommitZoneHistory(IReadOnlyList<DnsResourceRecord> historyRecords)
  692. {
  693. lock (_zoneHistory)
  694. {
  695. historyRecords[0].GetAuthHistoryRecordInfo().DeletedOn = DateTime.UtcNow;
  696. //write history
  697. _zoneHistory.AddRange(historyRecords);
  698. CleanupHistory();
  699. }
  700. }
  701. protected void ClearZoneHistory()
  702. {
  703. lock (_zoneHistory)
  704. {
  705. _zoneHistory.Clear();
  706. }
  707. }
  708. #endregion
  709. #region catalog zone
  710. private IReadOnlyCollection<NetworkAccessControl> GetQueryAccessACL()
  711. {
  712. switch (_queryAccess)
  713. {
  714. case AuthZoneQueryAccess.Allow:
  715. return [
  716. new NetworkAccessControl(IPAddress.Any, 0),
  717. new NetworkAccessControl(IPAddress.IPv6Any, 0)
  718. ];
  719. case AuthZoneQueryAccess.AllowOnlyPrivateNetworks:
  720. return [
  721. new NetworkAccessControl(IPAddress.Parse("127.0.0.0"), 8),
  722. new NetworkAccessControl(IPAddress.Parse("10.0.0.0"), 8),
  723. new NetworkAccessControl(IPAddress.Parse("100.64.0.0"), 10),
  724. new NetworkAccessControl(IPAddress.Parse("169.254.0.0"), 16),
  725. new NetworkAccessControl(IPAddress.Parse("172.16.0.0"), 12),
  726. new NetworkAccessControl(IPAddress.Parse("192.168.0.0"), 16),
  727. new NetworkAccessControl(IPAddress.Parse("2000::"), 3, true),
  728. new NetworkAccessControl(IPAddress.IPv6Any, 0)
  729. ];
  730. case AuthZoneQueryAccess.AllowOnlyZoneNameServers:
  731. return [
  732. new NetworkAccessControl(IPAddress.Parse("224.0.0.0"), 32)
  733. ];
  734. case AuthZoneQueryAccess.UseSpecifiedNetworkACL:
  735. return _queryAccessNetworkACL;
  736. case AuthZoneQueryAccess.AllowZoneNameServersAndUseSpecifiedNetworkACL:
  737. if (_queryAccessNetworkACL is null)
  738. {
  739. return [
  740. new NetworkAccessControl(IPAddress.Parse("224.0.0.0"), 32)
  741. ];
  742. }
  743. return [
  744. new NetworkAccessControl(IPAddress.Parse("224.0.0.0"), 32),
  745. .._queryAccessNetworkACL
  746. ];
  747. case AuthZoneQueryAccess.Deny:
  748. default:
  749. return [
  750. new NetworkAccessControl(IPAddress.Parse("127.0.0.0"), 8),
  751. new NetworkAccessControl(IPAddress.Parse("::1"), 128)
  752. ];
  753. }
  754. }
  755. private IReadOnlyCollection<NetworkAccessControl> GetZoneTranferACL()
  756. {
  757. switch (_zoneTransfer)
  758. {
  759. case AuthZoneTransfer.Allow:
  760. return [
  761. new NetworkAccessControl(IPAddress.Any, 0),
  762. new NetworkAccessControl(IPAddress.IPv6Any, 0)
  763. ];
  764. case AuthZoneTransfer.AllowOnlyZoneNameServers:
  765. return [
  766. new NetworkAccessControl(IPAddress.Parse("224.0.0.0"), 32)
  767. ];
  768. case AuthZoneTransfer.UseSpecifiedNetworkACL:
  769. return _zoneTransferNetworkACL;
  770. case AuthZoneTransfer.AllowZoneNameServersAndUseSpecifiedNetworkACL:
  771. if (_zoneTransferNetworkACL is null)
  772. {
  773. return [
  774. new NetworkAccessControl(IPAddress.Parse("224.0.0.0"), 32)
  775. ];
  776. }
  777. return [
  778. new NetworkAccessControl(IPAddress.Parse("224.0.0.0"), 32),
  779. .._zoneTransferNetworkACL
  780. ];
  781. case AuthZoneTransfer.Deny:
  782. default:
  783. return [
  784. new NetworkAccessControl(IPAddress.Any, 0, true),
  785. new NetworkAccessControl(IPAddress.IPv6Any, 0, true)
  786. ];
  787. }
  788. }
  789. #endregion
  790. #region public
  791. public uint GetZoneSoaMinimum()
  792. {
  793. return (_entries[DnsResourceRecordType.SOA][0].RDATA as DnsSOARecordData).Minimum;
  794. }
  795. public uint GetZoneSoaExpire()
  796. {
  797. return (_entries[DnsResourceRecordType.SOA][0].RDATA as DnsSOARecordData).Expire;
  798. }
  799. public uint GetZoneSoaSerial()
  800. {
  801. return (_entries[DnsResourceRecordType.SOA][0].RDATA as DnsSOARecordData).Serial;
  802. }
  803. public abstract string GetZoneTypeName();
  804. public override string ToString()
  805. {
  806. return _name.Length == 0 ? "<root>" : _name;
  807. }
  808. #endregion
  809. #region name server address resolution
  810. public async Task<IReadOnlyList<NameServerAddress>> GetResolvedPrimaryNameServerAddressesAsync()
  811. {
  812. IReadOnlyList<NameServerAddress> primaryNameServers;
  813. if (this is SecondaryZone secondary)
  814. primaryNameServers = secondary.PrimaryNameServerAddresses;
  815. else if (this is StubZone stub)
  816. primaryNameServers = stub.PrimaryNameServerAddresses;
  817. else
  818. primaryNameServers = null;
  819. if (primaryNameServers is not null)
  820. return await GetResolvedNameServerAddressesAsync(primaryNameServers);
  821. DnsResourceRecord soaRecord = _entries[DnsResourceRecordType.SOA][0];
  822. string primaryNameServer = (soaRecord.RDATA as DnsSOARecordData).PrimaryNameServer;
  823. IReadOnlyList<DnsResourceRecord> nsRecords = GetRecords(DnsResourceRecordType.NS); //stub zone has no authority so cant use QueryRecords
  824. List<NameServerAddress> nameServers = new List<NameServerAddress>(nsRecords.Count * 2);
  825. foreach (DnsResourceRecord nsRecord in nsRecords)
  826. {
  827. if (nsRecord.GetAuthGenericRecordInfo().Disabled)
  828. continue;
  829. if (primaryNameServer.Equals((nsRecord.RDATA as DnsNSRecordData).NameServer, StringComparison.OrdinalIgnoreCase))
  830. {
  831. //found primary NS
  832. await ResolveNameServerAddressesAsync(nsRecord, nameServers);
  833. break;
  834. }
  835. }
  836. if (nameServers.Count < 1)
  837. await ResolveNameServerAddressesAsync(primaryNameServer, 53, DnsTransportProtocol.Udp, nameServers);
  838. return nameServers;
  839. }
  840. public async Task<IReadOnlyList<NameServerAddress>> GetResolvedSecondaryNameServerAddressesAsync()
  841. {
  842. string primaryNameServer = (_entries[DnsResourceRecordType.SOA][0].RDATA as DnsSOARecordData).PrimaryNameServer;
  843. IReadOnlyList<DnsResourceRecord> nsRecords = GetRecords(DnsResourceRecordType.NS); //stub zone has no authority so cant use QueryRecords
  844. List<NameServerAddress> nameServers = new List<NameServerAddress>(nsRecords.Count * 2);
  845. foreach (DnsResourceRecord nsRecord in nsRecords)
  846. {
  847. if (nsRecord.GetAuthGenericRecordInfo().Disabled)
  848. continue;
  849. if (primaryNameServer.Equals((nsRecord.RDATA as DnsNSRecordData).NameServer, StringComparison.OrdinalIgnoreCase))
  850. continue; //skip primary name server
  851. await ResolveNameServerAddressesAsync(nsRecord, nameServers);
  852. }
  853. return nameServers;
  854. }
  855. public async Task<IReadOnlyList<NameServerAddress>> GetAllResolvedNameServerAddressesAsync()
  856. {
  857. IReadOnlyList<DnsResourceRecord> nsRecords = GetRecords(DnsResourceRecordType.NS); //stub zone has no authority so cant use QueryRecords
  858. List<NameServerAddress> nameServers = new List<NameServerAddress>(nsRecords.Count * 2);
  859. foreach (DnsResourceRecord nsRecord in nsRecords)
  860. {
  861. if (nsRecord.GetAuthGenericRecordInfo().Disabled)
  862. continue;
  863. await ResolveNameServerAddressesAsync(nsRecord, nameServers);
  864. }
  865. return nameServers;
  866. }
  867. public async Task<IReadOnlyList<NameServerAddress>> GetResolvedNameServerAddressesAsync(IReadOnlyList<NameServerAddress> nameServers)
  868. {
  869. List<NameServerAddress> resolvedNameServers = new List<NameServerAddress>(nameServers.Count * 2);
  870. foreach (NameServerAddress nameServer in nameServers)
  871. {
  872. if (nameServer.IsIPEndPointStale)
  873. await ResolveNameServerAddressesAsync(nameServer.Host, nameServer.Port, nameServer.Protocol, resolvedNameServers);
  874. else
  875. resolvedNameServers.Add(nameServer);
  876. }
  877. return resolvedNameServers;
  878. }
  879. private async Task ResolveNameServerAddressesAsync(string nsDomain, int port, DnsTransportProtocol protocol, List<NameServerAddress> outNameServers)
  880. {
  881. try
  882. {
  883. DnsDatagram response = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(nsDomain, DnsResourceRecordType.A, DnsClass.IN));
  884. if (response.Answer.Count > 0)
  885. {
  886. IReadOnlyList<IPAddress> addresses = DnsClient.ParseResponseA(response);
  887. foreach (IPAddress address in addresses)
  888. outNameServers.Add(new NameServerAddress(nsDomain, new IPEndPoint(address, port), protocol));
  889. }
  890. }
  891. catch
  892. { }
  893. if (_dnsServer.PreferIPv6)
  894. {
  895. try
  896. {
  897. DnsDatagram response = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(nsDomain, DnsResourceRecordType.AAAA, DnsClass.IN));
  898. if (response.Answer.Count > 0)
  899. {
  900. IReadOnlyList<IPAddress> addresses = DnsClient.ParseResponseAAAA(response);
  901. foreach (IPAddress address in addresses)
  902. outNameServers.Add(new NameServerAddress(nsDomain, new IPEndPoint(address, port), protocol));
  903. }
  904. }
  905. catch
  906. { }
  907. }
  908. }
  909. private Task ResolveNameServerAddressesAsync(DnsResourceRecord nsRecord, List<NameServerAddress> outNameServers)
  910. {
  911. string nsDomain = (nsRecord.RDATA as DnsNSRecordData).NameServer;
  912. IReadOnlyList<DnsResourceRecord> glueRecords = nsRecord.GetAuthNSRecordInfo().GlueRecords;
  913. if (glueRecords is not null)
  914. {
  915. foreach (DnsResourceRecord glueRecord in glueRecords)
  916. {
  917. switch (glueRecord.Type)
  918. {
  919. case DnsResourceRecordType.A:
  920. outNameServers.Add(new NameServerAddress(nsDomain, (glueRecord.RDATA as DnsARecordData).Address));
  921. break;
  922. case DnsResourceRecordType.AAAA:
  923. if (_dnsServer.PreferIPv6)
  924. outNameServers.Add(new NameServerAddress(nsDomain, (glueRecord.RDATA as DnsAAAARecordData).Address));
  925. break;
  926. }
  927. }
  928. return Task.CompletedTask;
  929. }
  930. else
  931. {
  932. return ResolveNameServerAddressesAsync(nsDomain, 53, DnsTransportProtocol.Udp, outNameServers);
  933. }
  934. }
  935. #endregion
  936. #region properties
  937. public override bool Disabled
  938. {
  939. get { return base.Disabled; }
  940. set
  941. {
  942. if (base.Disabled == value)
  943. return;
  944. base.Disabled = value; //set value early to be able to use it for setting catalog properties
  945. CatalogZone catalogZone = CatalogZone;
  946. if (catalogZone is not null)
  947. {
  948. if (value)
  949. {
  950. //remove catalog zone membership without removing it from zone's options
  951. catalogZone.RemoveMemberZone(_name);
  952. _dnsServer.AuthZoneManager.SaveZoneFile(catalogZone._name);
  953. }
  954. else
  955. {
  956. //add catalog zone membership
  957. _dnsServer.AuthZoneManager.AddCatalogMemberZone(_catalogZoneName, new AuthZoneInfo(this), true);
  958. }
  959. }
  960. }
  961. }
  962. public DateTime LastModified
  963. { get { return _lastModified; } }
  964. public virtual string CatalogZoneName
  965. {
  966. get { return _catalogZoneName; }
  967. set
  968. {
  969. if (string.IsNullOrEmpty(value))
  970. _catalogZoneName = null;
  971. else
  972. _catalogZoneName = value;
  973. //reset
  974. _catalogZone = null;
  975. _secondaryCatalogZone = null;
  976. }
  977. }
  978. public virtual bool OverrideCatalogQueryAccess
  979. {
  980. get { return _overrideCatalogQueryAccess; }
  981. set { _overrideCatalogQueryAccess = value; }
  982. }
  983. public virtual bool OverrideCatalogZoneTransfer
  984. {
  985. get { return _overrideCatalogZoneTransfer; }
  986. set { _overrideCatalogZoneTransfer = value; }
  987. }
  988. public virtual bool OverrideCatalogNotify
  989. {
  990. get { return _overrideCatalogNotify; }
  991. set { _overrideCatalogNotify = value; }
  992. }
  993. public virtual AuthZoneQueryAccess QueryAccess
  994. {
  995. get { return _queryAccess; }
  996. set
  997. {
  998. _queryAccess = value;
  999. //update catalog zone property
  1000. if (this is CatalogZone thisCatalogZone)
  1001. {
  1002. //update global custom property
  1003. thisCatalogZone.SetAllowQueryProperty(GetQueryAccessACL());
  1004. }
  1005. else if (!Disabled && ((this is PrimaryZone) || (this is StubZone) || (this is ForwarderZone)))
  1006. {
  1007. CatalogZone catalogZone = CatalogZone;
  1008. if (catalogZone is not null)
  1009. {
  1010. if (_overrideCatalogQueryAccess)
  1011. catalogZone.SetAllowQueryProperty(GetQueryAccessACL(), _name); //update member zone custom property
  1012. else
  1013. catalogZone.SetAllowQueryProperty(null, _name); //remove member zone custom property
  1014. }
  1015. }
  1016. }
  1017. }
  1018. public IReadOnlyCollection<NetworkAccessControl> QueryAccessNetworkACL
  1019. {
  1020. get { return _queryAccessNetworkACL; }
  1021. set
  1022. {
  1023. if ((value is null) || (value.Count == 0))
  1024. _queryAccessNetworkACL = null;
  1025. else if (value.Count > byte.MaxValue)
  1026. throw new ArgumentOutOfRangeException(nameof(QueryAccessNetworkACL), "Network ACL cannot have more than 255 entries.");
  1027. else
  1028. _queryAccessNetworkACL = value;
  1029. }
  1030. }
  1031. public virtual AuthZoneTransfer ZoneTransfer
  1032. {
  1033. get { return _zoneTransfer; }
  1034. set
  1035. {
  1036. _zoneTransfer = value;
  1037. //update catalog zone property
  1038. if (this is CatalogZone thisCatalogZone)
  1039. {
  1040. //update global custom property
  1041. thisCatalogZone.SetAllowTransferProperty(GetZoneTranferACL());
  1042. }
  1043. else if (!Disabled && (this is PrimaryZone))
  1044. {
  1045. CatalogZone catalogZone = CatalogZone;
  1046. if (catalogZone is not null)
  1047. {
  1048. if (_overrideCatalogZoneTransfer)
  1049. catalogZone.SetAllowTransferProperty(GetZoneTranferACL(), _name); //update member zone custom property
  1050. else
  1051. catalogZone.SetAllowTransferProperty(null, _name); //remove member zone custom property
  1052. }
  1053. }
  1054. }
  1055. }
  1056. public IReadOnlyCollection<NetworkAccessControl> ZoneTransferNetworkACL
  1057. {
  1058. get { return _zoneTransferNetworkACL; }
  1059. set
  1060. {
  1061. if ((value is null) || (value.Count == 0))
  1062. _zoneTransferNetworkACL = null;
  1063. else if (value.Count > byte.MaxValue)
  1064. throw new ArgumentOutOfRangeException(nameof(ZoneTransferNetworkACL), "Network ACL cannot have more than 255 entries.");
  1065. else
  1066. _zoneTransferNetworkACL = value;
  1067. }
  1068. }
  1069. public IReadOnlyDictionary<string, object> ZoneTransferTsigKeyNames
  1070. {
  1071. get { return _zoneTransferTsigKeyNames; }
  1072. set
  1073. {
  1074. if ((value is null) || (value.Count == 0))
  1075. _zoneTransferTsigKeyNames = null;
  1076. else if (value.Count > byte.MaxValue)
  1077. throw new ArgumentOutOfRangeException(nameof(ZoneTransferTsigKeyNames), "Zone transfer TSIG key names cannot have more than 255 entries.");
  1078. else
  1079. _zoneTransferTsigKeyNames = value;
  1080. //update catalog zone property
  1081. if (this is CatalogZone thisCatalogZone)
  1082. {
  1083. //update global custom property
  1084. thisCatalogZone.SetZoneTransferTsigKeyNamesProperty(_zoneTransferTsigKeyNames);
  1085. }
  1086. else if (!Disabled && (this is PrimaryZone))
  1087. {
  1088. CatalogZone catalogZone = CatalogZone;
  1089. if (catalogZone is not null)
  1090. {
  1091. if (_overrideCatalogZoneTransfer)
  1092. catalogZone.SetZoneTransferTsigKeyNamesProperty(_zoneTransferTsigKeyNames, _name); //update member zone custom property
  1093. else
  1094. catalogZone.SetZoneTransferTsigKeyNamesProperty(null, _name); //remove member zone custom property
  1095. }
  1096. }
  1097. }
  1098. }
  1099. public virtual AuthZoneNotify Notify
  1100. {
  1101. get { return _notify; }
  1102. set
  1103. {
  1104. _notify = value;
  1105. lock (_notifyFailed)
  1106. {
  1107. _notifyFailed.Clear();
  1108. }
  1109. }
  1110. }
  1111. public IReadOnlyCollection<IPAddress> NotifyNameServers
  1112. {
  1113. get { return _notifyNameServers; }
  1114. set
  1115. {
  1116. if ((value is null) || (value.Count == 0))
  1117. _notifyNameServers = null;
  1118. else if (value.Count > byte.MaxValue)
  1119. throw new ArgumentOutOfRangeException(nameof(NotifyNameServers), "Name server addresses cannot have more than 255 entries.");
  1120. else
  1121. _notifyNameServers = value;
  1122. lock (_notifyFailed)
  1123. {
  1124. _notifyFailed.Clear();
  1125. }
  1126. }
  1127. }
  1128. public IReadOnlyCollection<IPAddress> NotifySecondaryCatalogNameServers
  1129. {
  1130. get { return _notifySecondaryCatalogNameServers; }
  1131. set
  1132. {
  1133. if ((value is null) || (value.Count == 0))
  1134. _notifySecondaryCatalogNameServers = null;
  1135. else if (value.Count > byte.MaxValue)
  1136. throw new ArgumentOutOfRangeException(nameof(NotifySecondaryCatalogNameServers), "Secondary Catalog name server addresses cannot have more than 255 entries.");
  1137. else
  1138. _notifySecondaryCatalogNameServers = value;
  1139. lock (_notifyFailed)
  1140. {
  1141. _notifyFailed.Clear();
  1142. }
  1143. }
  1144. }
  1145. public virtual AuthZoneUpdate Update
  1146. {
  1147. get { return _update; }
  1148. set { _update = value; }
  1149. }
  1150. public IReadOnlyCollection<NetworkAccessControl> UpdateNetworkACL
  1151. {
  1152. get { return _updateNetworkACL; }
  1153. set
  1154. {
  1155. if ((value is null) || (value.Count == 0))
  1156. _updateNetworkACL = null;
  1157. else if (value.Count > byte.MaxValue)
  1158. throw new ArgumentOutOfRangeException(nameof(UpdateNetworkACL), "Network ACL cannot have more than 255 entries.");
  1159. else
  1160. _updateNetworkACL = value;
  1161. }
  1162. }
  1163. public IReadOnlyDictionary<string, IReadOnlyDictionary<string, IReadOnlyList<DnsResourceRecordType>>> UpdateSecurityPolicies
  1164. {
  1165. get { return _updateSecurityPolicies; }
  1166. set { _updateSecurityPolicies = value; }
  1167. }
  1168. public AuthZoneDnssecStatus DnssecStatus
  1169. { get { return _dnssecStatus; } }
  1170. public string[] NotifyFailed
  1171. {
  1172. get
  1173. {
  1174. if (_notifyFailed is null)
  1175. return Array.Empty<string>();
  1176. lock (_notifyFailed)
  1177. {
  1178. if (_notifyFailed.Count > 0)
  1179. return _notifyFailed.ToArray();
  1180. return Array.Empty<string>();
  1181. }
  1182. }
  1183. }
  1184. public bool SyncFailed
  1185. { get { return _syncFailed; } }
  1186. public CatalogZone CatalogZone
  1187. {
  1188. get
  1189. {
  1190. if (_catalogZoneName is null)
  1191. return null;
  1192. if (_secondaryCatalogZone is not null)
  1193. return null;
  1194. if (_catalogZone is null)
  1195. {
  1196. if ((this is PrimaryZone) || (this is ForwarderZone))
  1197. {
  1198. ApexZone apexZone = _dnsServer.AuthZoneManager.GetApexZone(_catalogZoneName);
  1199. if (apexZone is CatalogZone catalogZone)
  1200. _catalogZone = catalogZone;
  1201. }
  1202. else if (this is StubZone)
  1203. {
  1204. ApexZone apexZone = _dnsServer.AuthZoneManager.GetApexZone(_catalogZoneName);
  1205. if (apexZone is CatalogZone catalogZone)
  1206. _catalogZone = catalogZone;
  1207. else if (apexZone is SecondaryCatalogZone secondaryCatalogZone)
  1208. _secondaryCatalogZone = secondaryCatalogZone;
  1209. }
  1210. }
  1211. return _catalogZone;
  1212. }
  1213. }
  1214. public SecondaryCatalogZone SecondaryCatalogZone
  1215. {
  1216. get
  1217. {
  1218. if (_catalogZoneName is null)
  1219. return null;
  1220. if (_catalogZone is not null)
  1221. return null;
  1222. if (_secondaryCatalogZone is null)
  1223. {
  1224. if (this is SecondaryZone)
  1225. {
  1226. ApexZone apexZone = _dnsServer.AuthZoneManager.GetApexZone(_catalogZoneName);
  1227. if (apexZone is SecondaryCatalogZone secondaryCatalogZone)
  1228. _secondaryCatalogZone = secondaryCatalogZone;
  1229. }
  1230. else if (this is StubZone)
  1231. {
  1232. ApexZone apexZone = _dnsServer.AuthZoneManager.GetApexZone(_catalogZoneName);
  1233. if (apexZone is SecondaryCatalogZone secondaryCatalogZone)
  1234. _secondaryCatalogZone = secondaryCatalogZone;
  1235. else if (apexZone is CatalogZone catalogZone)
  1236. _catalogZone = catalogZone;
  1237. }
  1238. }
  1239. return _secondaryCatalogZone;
  1240. }
  1241. }
  1242. #endregion
  1243. }
  1244. }