PrimaryZone.cs 124 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042
  1. /*
  2. Technitium DNS Server
  3. Copyright (C) 2023 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.Dnssec;
  16. using DnsServerCore.Dns.ResourceRecords;
  17. using DnsServerCore.Dns.ZoneManagers;
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Security.Cryptography;
  21. using System.Threading;
  22. using System.Threading.Tasks;
  23. using TechnitiumLibrary.Net.Dns;
  24. using TechnitiumLibrary.Net.Dns.ResourceRecords;
  25. namespace DnsServerCore.Dns.Zones
  26. {
  27. public enum AuthZoneDnssecStatus : byte
  28. {
  29. Unsigned = 0,
  30. SignedWithNSEC = 1,
  31. SignedWithNSEC3 = 2,
  32. }
  33. //DNSSEC Operational Practices, Version 2
  34. //https://datatracker.ietf.org/doc/html/rfc6781
  35. //DNSSEC Key Rollover Timing Considerations
  36. //https://datatracker.ietf.org/doc/html/rfc7583
  37. class PrimaryZone : ApexZone
  38. {
  39. #region variables
  40. readonly DnsServer _dnsServer;
  41. readonly bool _internal;
  42. Dictionary<ushort, DnssecPrivateKey> _dnssecPrivateKeys;
  43. const uint DNSSEC_SIGNATURE_INCEPTION_OFFSET = 60 * 60;
  44. Timer _dnssecTimer;
  45. const int DNSSEC_TIMER_INITIAL_INTERVAL = 30000;
  46. const int DNSSEC_TIMER_PERIODIC_INTERVAL = 900000;
  47. DateTime _lastSignatureRefreshCheckedOn;
  48. readonly object _dnssecUpdateLock = new object();
  49. #endregion
  50. #region constructor
  51. public PrimaryZone(DnsServer dnsServer, AuthZoneInfo zoneInfo)
  52. : base(zoneInfo)
  53. {
  54. _dnsServer = dnsServer;
  55. IReadOnlyCollection<DnssecPrivateKey> dnssecPrivateKeys = zoneInfo.DnssecPrivateKeys;
  56. if (dnssecPrivateKeys is not null)
  57. {
  58. _dnssecPrivateKeys = new Dictionary<ushort, DnssecPrivateKey>(dnssecPrivateKeys.Count);
  59. foreach (DnssecPrivateKey dnssecPrivateKey in dnssecPrivateKeys)
  60. _dnssecPrivateKeys.Add(dnssecPrivateKey.KeyTag, dnssecPrivateKey);
  61. }
  62. InitNotify(_dnsServer);
  63. }
  64. public PrimaryZone(DnsServer dnsServer, string name, string primaryNameServer, bool @internal)
  65. : base(name)
  66. {
  67. _dnsServer = dnsServer;
  68. _internal = @internal;
  69. if (_internal)
  70. {
  71. _zoneTransfer = AuthZoneTransfer.Deny;
  72. _notify = AuthZoneNotify.None;
  73. _update = AuthZoneUpdate.Deny;
  74. }
  75. else
  76. {
  77. _zoneTransfer = AuthZoneTransfer.AllowOnlyZoneNameServers;
  78. _notify = AuthZoneNotify.ZoneNameServers;
  79. _update = AuthZoneUpdate.Deny;
  80. InitNotify(_dnsServer);
  81. }
  82. DnsSOARecordData soa = new DnsSOARecordData(primaryNameServer, _name.Length == 0 ? "hostadmin@localhost" : "hostadmin@" + _name, 1, 900, 300, 604800, 900);
  83. _entries[DnsResourceRecordType.SOA] = new DnsResourceRecord[] { new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, soa.Minimum, soa) };
  84. _entries[DnsResourceRecordType.NS] = new DnsResourceRecord[] { new DnsResourceRecord(_name, DnsResourceRecordType.NS, DnsClass.IN, 3600, new DnsNSRecordData(soa.PrimaryNameServer)) };
  85. }
  86. internal PrimaryZone(DnsServer dnsServer, string name, DnsSOARecordData soa, DnsNSRecordData ns)
  87. : base(name)
  88. {
  89. _dnsServer = dnsServer;
  90. _internal = true;
  91. _zoneTransfer = AuthZoneTransfer.Deny;
  92. _notify = AuthZoneNotify.None;
  93. _update = AuthZoneUpdate.Deny;
  94. _entries[DnsResourceRecordType.SOA] = new DnsResourceRecord[] { new DnsResourceRecord(_name, DnsResourceRecordType.SOA, DnsClass.IN, soa.Minimum, soa) };
  95. _entries[DnsResourceRecordType.NS] = new DnsResourceRecord[] { new DnsResourceRecord(_name, DnsResourceRecordType.NS, DnsClass.IN, 3600, ns) };
  96. }
  97. #endregion
  98. #region IDisposable
  99. bool _disposed;
  100. protected override void Dispose(bool disposing)
  101. {
  102. try
  103. {
  104. if (_disposed)
  105. return;
  106. if (disposing)
  107. {
  108. Timer dnssecTimer = _dnssecTimer;
  109. if (dnssecTimer is not null)
  110. {
  111. lock (dnssecTimer)
  112. {
  113. dnssecTimer.Dispose();
  114. _dnssecTimer = null;
  115. }
  116. }
  117. }
  118. _disposed = true;
  119. }
  120. finally
  121. {
  122. base.Dispose(disposing);
  123. }
  124. }
  125. #endregion
  126. #region DNSSEC
  127. internal override void UpdateDnssecStatus()
  128. {
  129. base.UpdateDnssecStatus();
  130. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  131. _dnssecTimer = new Timer(DnssecTimerCallback, null, DNSSEC_TIMER_INITIAL_INTERVAL, Timeout.Infinite);
  132. }
  133. private async void DnssecTimerCallback(object state)
  134. {
  135. try
  136. {
  137. List<DnssecPrivateKey> kskToReady = null;
  138. List<DnssecPrivateKey> kskToActivate = null;
  139. List<DnssecPrivateKey> kskToRetire = null;
  140. List<DnssecPrivateKey> kskToRevoke = null;
  141. List<DnssecPrivateKey> zskToActivate = null;
  142. List<DnssecPrivateKey> zskToRetire = null;
  143. List<DnssecPrivateKey> zskToRollover = null;
  144. List<DnssecPrivateKey> keysToUnpublish = null;
  145. bool saveZone = false;
  146. lock (_dnssecPrivateKeys)
  147. {
  148. foreach (KeyValuePair<ushort, DnssecPrivateKey> privateKeyEntry in _dnssecPrivateKeys)
  149. {
  150. DnssecPrivateKey privateKey = privateKeyEntry.Value;
  151. if (privateKey.KeyType == DnssecPrivateKeyType.KeySigningKey)
  152. {
  153. //KSK
  154. switch (privateKey.State)
  155. {
  156. case DnssecPrivateKeyState.Published:
  157. if (DateTime.UtcNow > GetDnsKeyStateReadyOn(privateKey))
  158. {
  159. //long enough time for old RRsets to expire from caches
  160. if (kskToReady is null)
  161. kskToReady = new List<DnssecPrivateKey>();
  162. kskToReady.Add(privateKey);
  163. }
  164. break;
  165. case DnssecPrivateKeyState.Ready:
  166. if (privateKey.IsRetiring)
  167. {
  168. if (kskToRetire is null)
  169. kskToRetire = new List<DnssecPrivateKey>();
  170. kskToRetire.Add(privateKey);
  171. }
  172. else
  173. {
  174. if (kskToActivate is null)
  175. kskToActivate = new List<DnssecPrivateKey>();
  176. kskToActivate.Add(privateKey);
  177. }
  178. break;
  179. case DnssecPrivateKeyState.Active:
  180. if (privateKey.IsRetiring)
  181. {
  182. if (kskToRetire is null)
  183. kskToRetire = new List<DnssecPrivateKey>();
  184. kskToRetire.Add(privateKey);
  185. }
  186. break;
  187. case DnssecPrivateKeyState.Retired:
  188. //KSK needs to be revoked for RFC5011 consideration
  189. if (kskToRevoke is null)
  190. kskToRevoke = new List<DnssecPrivateKey>();
  191. kskToRevoke.Add(privateKey);
  192. break;
  193. case DnssecPrivateKeyState.Revoked:
  194. //rfc7583#section-3.3.4
  195. //modifiedQueryInterval = MAX(1hr, MIN(15 days, TTLkey / 2))
  196. uint modifiedQueryInterval = Math.Max(3600u, Math.Min(15 * 24 * 60 * 60, GetDnsKeyTtl() / 2));
  197. if (DateTime.UtcNow > privateKey.StateChangedOn.AddSeconds(modifiedQueryInterval))
  198. {
  199. //key has been revoked for sufficient time
  200. if (keysToUnpublish is null)
  201. keysToUnpublish = new List<DnssecPrivateKey>();
  202. keysToUnpublish.Add(privateKey);
  203. }
  204. break;
  205. }
  206. }
  207. else
  208. {
  209. //ZSK
  210. switch (privateKey.State)
  211. {
  212. case DnssecPrivateKeyState.Published:
  213. if (DateTime.UtcNow > privateKey.StateChangedOn.AddSeconds(GetDnsKeyTtl() + GetPropagationDelay()))
  214. {
  215. //long enough time old RRset to expire from caches
  216. privateKey.SetState(DnssecPrivateKeyState.Ready);
  217. if (zskToActivate is null)
  218. zskToActivate = new List<DnssecPrivateKey>();
  219. zskToActivate.Add(privateKey);
  220. }
  221. break;
  222. case DnssecPrivateKeyState.Ready:
  223. if (zskToActivate is null)
  224. zskToActivate = new List<DnssecPrivateKey>();
  225. zskToActivate.Add(privateKey);
  226. break;
  227. case DnssecPrivateKeyState.Active:
  228. if (privateKey.IsRetiring)
  229. {
  230. if (zskToRetire is null)
  231. zskToRetire = new List<DnssecPrivateKey>();
  232. zskToRetire.Add(privateKey);
  233. }
  234. else
  235. {
  236. if (privateKey.IsRolloverNeeded())
  237. {
  238. if (zskToRollover is null)
  239. zskToRollover = new List<DnssecPrivateKey>();
  240. zskToRollover.Add(privateKey);
  241. }
  242. }
  243. break;
  244. case DnssecPrivateKeyState.Retired:
  245. if (DateTime.UtcNow > privateKey.StateChangedOn.AddSeconds(GetMaxRRSigTtl() + GetPropagationDelay()))
  246. {
  247. //key has been retired for sufficient time
  248. if (keysToUnpublish is null)
  249. keysToUnpublish = new List<DnssecPrivateKey>();
  250. keysToUnpublish.Add(privateKey);
  251. }
  252. break;
  253. }
  254. }
  255. }
  256. }
  257. #region KSK actions
  258. if (kskToReady is not null)
  259. {
  260. string dnsKeyTags = null;
  261. foreach (DnssecPrivateKey kskPrivateKey in kskToReady)
  262. {
  263. kskPrivateKey.SetState(DnssecPrivateKeyState.Ready);
  264. if (kskToActivate is null)
  265. kskToActivate = new List<DnssecPrivateKey>();
  266. kskToActivate.Add(kskPrivateKey);
  267. if (dnsKeyTags is null)
  268. dnsKeyTags = kskPrivateKey.KeyTag.ToString();
  269. else
  270. dnsKeyTags += ", " + kskPrivateKey.KeyTag.ToString();
  271. }
  272. saveZone = true;
  273. LogManager log = _dnsServer.LogManager;
  274. if (log is not null)
  275. log.Write("The KSK DNSKEYs (" + dnsKeyTags + ") from the primary zone are ready for changing the DS records at the parent zone: " + _name);
  276. }
  277. if (kskToActivate is not null)
  278. {
  279. try
  280. {
  281. IReadOnlyList<DnssecPrivateKey> kskPrivateKeys = await GetDSPublishedPrivateKeys(kskToActivate);
  282. if (kskPrivateKeys.Count > 0)
  283. {
  284. string dnsKeyTags = null;
  285. foreach (DnssecPrivateKey kskPrivateKey in kskPrivateKeys)
  286. {
  287. kskPrivateKey.SetState(DnssecPrivateKeyState.Active);
  288. if (dnsKeyTags is null)
  289. dnsKeyTags = kskPrivateKey.KeyTag.ToString();
  290. else
  291. dnsKeyTags += ", " + kskPrivateKey.KeyTag.ToString();
  292. }
  293. saveZone = true;
  294. LogManager log = _dnsServer.LogManager;
  295. if (log is not null)
  296. log.Write("The KSK DNSKEYs (" + dnsKeyTags + ") from the primary zone were activated successfully: " + _name);
  297. }
  298. }
  299. catch (Exception ex)
  300. {
  301. LogManager log = _dnsServer.LogManager;
  302. if (log is not null)
  303. log.Write(ex);
  304. }
  305. }
  306. if (kskToRetire is not null)
  307. saveZone = RetireKskDnsKeys(kskToRetire, false);
  308. if (kskToRevoke is not null)
  309. {
  310. uint dsTtl = await GetDSTtl();
  311. uint parentSidePropagationDelay = await GetParentSidePropagationDelayAsync();
  312. List<DnssecPrivateKey> revokeKskPrivateKeys = null;
  313. foreach (DnssecPrivateKey privateKey in kskToRevoke)
  314. {
  315. if (DateTime.UtcNow > privateKey.StateChangedOn.AddSeconds(dsTtl + parentSidePropagationDelay))
  316. {
  317. if (revokeKskPrivateKeys is null)
  318. revokeKskPrivateKeys = new List<DnssecPrivateKey>();
  319. revokeKskPrivateKeys.Add(privateKey);
  320. }
  321. }
  322. if (revokeKskPrivateKeys is not null)
  323. {
  324. RevokeKskDnsKeys(revokeKskPrivateKeys);
  325. saveZone = true;
  326. }
  327. }
  328. #endregion
  329. #region ZSK actions
  330. if (zskToActivate is not null)
  331. {
  332. ActivateZskDnsKeys(zskToActivate);
  333. saveZone = true;
  334. }
  335. if (zskToRetire is not null)
  336. saveZone = RetireZskDnsKeys(zskToRetire, false);
  337. if (zskToRollover is not null)
  338. {
  339. foreach (DnssecPrivateKey zskPrivateKey in zskToRollover)
  340. RolloverDnsKey(zskPrivateKey.KeyTag);
  341. saveZone = true;
  342. }
  343. #endregion
  344. if (keysToUnpublish is not null)
  345. {
  346. UnpublishDnsKeys(keysToUnpublish);
  347. saveZone = true;
  348. }
  349. //re-signing task
  350. uint reSignPeriod = GetSignatureValidityPeriod() / 10; //the period when signature refresh check is done
  351. if (DateTime.UtcNow > _lastSignatureRefreshCheckedOn.AddSeconds(reSignPeriod))
  352. {
  353. if (TryRefreshAllSignatures())
  354. saveZone = true;
  355. _lastSignatureRefreshCheckedOn = DateTime.UtcNow;
  356. }
  357. if (saveZone)
  358. _dnsServer.AuthZoneManager.SaveZoneFile(_name);
  359. }
  360. catch (Exception ex)
  361. {
  362. LogManager log = _dnsServer.LogManager;
  363. if (log is not null)
  364. log.Write(ex);
  365. }
  366. finally
  367. {
  368. Timer dnssecTimer = _dnssecTimer;
  369. if (dnssecTimer is not null)
  370. {
  371. lock (dnssecTimer)
  372. {
  373. dnssecTimer.Change(DNSSEC_TIMER_PERIODIC_INTERVAL, Timeout.Infinite);
  374. }
  375. }
  376. }
  377. }
  378. public void SignZoneWithRsaNSec(string hashAlgorithm, int kskKeySize, int zskKeySize, uint dnsKeyTtl, ushort zskRolloverDays)
  379. {
  380. SignZoneWithRsa(hashAlgorithm, kskKeySize, zskKeySize, false, 0, 0, dnsKeyTtl, zskRolloverDays);
  381. }
  382. public void SignZoneWithRsaNSec3(string hashAlgorithm, int kskKeySize, int zskKeySize, ushort iterations, byte saltLength, uint dnsKeyTtl, ushort zskRolloverDays)
  383. {
  384. SignZoneWithRsa(hashAlgorithm, kskKeySize, zskKeySize, true, iterations, saltLength, dnsKeyTtl, zskRolloverDays);
  385. }
  386. private void SignZoneWithRsa(string hashAlgorithm, int kskKeySize, int zskKeySize, bool useNSec3, ushort iterations, byte saltLength, uint dnsKeyTtl, ushort zskRolloverDays)
  387. {
  388. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  389. throw new DnsServerException("Cannot sign zone: the zone is already signed.");
  390. if (iterations > 50)
  391. throw new ArgumentOutOfRangeException(nameof(iterations), "NSEC3 iterations valid range is 0-50");
  392. if (saltLength > 32)
  393. throw new ArgumentOutOfRangeException(nameof(saltLength), "NSEC3 salt length valid range is 0-32");
  394. //generate private keys
  395. DnssecAlgorithm algorithm;
  396. switch (hashAlgorithm.ToUpper())
  397. {
  398. case "MD5":
  399. algorithm = DnssecAlgorithm.RSAMD5;
  400. break;
  401. case "SHA1":
  402. algorithm = DnssecAlgorithm.RSASHA1;
  403. break;
  404. case "SHA256":
  405. algorithm = DnssecAlgorithm.RSASHA256;
  406. break;
  407. case "SHA512":
  408. algorithm = DnssecAlgorithm.RSASHA512;
  409. break;
  410. default:
  411. throw new NotSupportedException("Hash algorithm is not supported: " + hashAlgorithm);
  412. }
  413. DnssecPrivateKey kskPrivateKey = DnssecPrivateKey.Create(algorithm, DnssecPrivateKeyType.KeySigningKey, kskKeySize);
  414. DnssecPrivateKey zskPrivateKey = DnssecPrivateKey.Create(algorithm, DnssecPrivateKeyType.ZoneSigningKey, zskKeySize);
  415. zskPrivateKey.RolloverDays = zskRolloverDays;
  416. _dnssecPrivateKeys = new Dictionary<ushort, DnssecPrivateKey>(4);
  417. _dnssecPrivateKeys.Add(kskPrivateKey.KeyTag, kskPrivateKey);
  418. _dnssecPrivateKeys.Add(zskPrivateKey.KeyTag, zskPrivateKey);
  419. //sign zone
  420. SignZone(useNSec3, iterations, saltLength, dnsKeyTtl);
  421. }
  422. public void SignZoneWithEcdsaNSec(string curve, uint dnsKeyTtl, ushort zskRolloverDays)
  423. {
  424. SignZoneWithEcdsa(curve, false, 0, 0, dnsKeyTtl, zskRolloverDays);
  425. }
  426. public void SignZoneWithEcdsaNSec3(string curve, ushort iterations, byte saltLength, uint dnsKeyTtl, ushort zskRolloverDays)
  427. {
  428. SignZoneWithEcdsa(curve, true, iterations, saltLength, dnsKeyTtl, zskRolloverDays);
  429. }
  430. private void SignZoneWithEcdsa(string curve, bool useNSec3, ushort iterations, byte saltLength, uint dnsKeyTtl, ushort zskRolloverDays)
  431. {
  432. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  433. throw new DnsServerException("Cannot sign zone: the zone is already signed.");
  434. if (iterations > 50)
  435. throw new ArgumentOutOfRangeException(nameof(iterations), "NSEC3 iterations valid range is 0-50");
  436. if (saltLength > 32)
  437. throw new ArgumentOutOfRangeException(nameof(saltLength), "NSEC3 salt length valid range is 0-32");
  438. //generate private keys
  439. DnssecAlgorithm algorithm;
  440. switch (curve.ToUpper())
  441. {
  442. case "P256":
  443. algorithm = DnssecAlgorithm.ECDSAP256SHA256;
  444. break;
  445. case "P384":
  446. algorithm = DnssecAlgorithm.ECDSAP384SHA384;
  447. break;
  448. default:
  449. throw new NotSupportedException("ECDSA curve is not supported: " + curve);
  450. }
  451. DnssecPrivateKey kskPrivateKey = DnssecPrivateKey.Create(algorithm, DnssecPrivateKeyType.KeySigningKey);
  452. DnssecPrivateKey zskPrivateKey = DnssecPrivateKey.Create(algorithm, DnssecPrivateKeyType.ZoneSigningKey);
  453. zskPrivateKey.RolloverDays = zskRolloverDays;
  454. _dnssecPrivateKeys = new Dictionary<ushort, DnssecPrivateKey>(4);
  455. _dnssecPrivateKeys.Add(kskPrivateKey.KeyTag, kskPrivateKey);
  456. _dnssecPrivateKeys.Add(zskPrivateKey.KeyTag, zskPrivateKey);
  457. //sign zone
  458. SignZone(useNSec3, iterations, saltLength, dnsKeyTtl);
  459. }
  460. private void SignZone(bool useNSec3, ushort iterations, byte saltLength, uint dnsKeyTtl)
  461. {
  462. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  463. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  464. try
  465. {
  466. //update private key state
  467. foreach (KeyValuePair<ushort, DnssecPrivateKey> privateKeyEntry in _dnssecPrivateKeys)
  468. {
  469. DnssecPrivateKey privateKey = privateKeyEntry.Value;
  470. switch (privateKey.KeyType)
  471. {
  472. case DnssecPrivateKeyType.KeySigningKey:
  473. privateKey.SetState(DnssecPrivateKeyState.Published);
  474. break;
  475. case DnssecPrivateKeyType.ZoneSigningKey:
  476. privateKey.SetState(DnssecPrivateKeyState.Ready);
  477. break;
  478. }
  479. }
  480. //add DNSKEYs
  481. List<DnsResourceRecord> dnsKeyRecords = new List<DnsResourceRecord>(_dnssecPrivateKeys.Count);
  482. foreach (KeyValuePair<ushort, DnssecPrivateKey> privateKey in _dnssecPrivateKeys)
  483. dnsKeyRecords.Add(new DnsResourceRecord(_name, DnsResourceRecordType.DNSKEY, DnsClass.IN, dnsKeyTtl, privateKey.Value.DnsKey));
  484. if (!TrySetRecords(DnsResourceRecordType.DNSKEY, dnsKeyRecords, out IReadOnlyList<DnsResourceRecord> deletedDnsKeyRecords))
  485. throw new InvalidOperationException("Failed to add DNSKEY.");
  486. addedRecords.AddRange(dnsKeyRecords);
  487. deletedRecords.AddRange(deletedDnsKeyRecords);
  488. //sign all RRSets
  489. IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetZoneWithSubDomainZones(_name);
  490. foreach (AuthZone zone in zones)
  491. {
  492. IReadOnlyList<DnsResourceRecord> newRRSigRecords = zone.SignAllRRSets();
  493. if (newRRSigRecords.Count > 0)
  494. {
  495. zone.AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  496. addedRecords.AddRange(newRRSigRecords);
  497. deletedRecords.AddRange(deletedRRSigRecords);
  498. }
  499. }
  500. if (useNSec3)
  501. {
  502. EnableNSec3(zones, iterations, saltLength);
  503. _dnssecStatus = AuthZoneDnssecStatus.SignedWithNSEC3;
  504. }
  505. else
  506. {
  507. EnableNSec(zones);
  508. _dnssecStatus = AuthZoneDnssecStatus.SignedWithNSEC;
  509. }
  510. //update private key state
  511. foreach (KeyValuePair<ushort, DnssecPrivateKey> privateKeyEntry in _dnssecPrivateKeys)
  512. {
  513. DnssecPrivateKey privateKey = privateKeyEntry.Value;
  514. switch (privateKey.KeyType)
  515. {
  516. case DnssecPrivateKeyType.ZoneSigningKey:
  517. privateKey.SetState(DnssecPrivateKeyState.Active);
  518. break;
  519. }
  520. }
  521. _dnssecTimer = new Timer(DnssecTimerCallback, null, DNSSEC_TIMER_INITIAL_INTERVAL, Timeout.Infinite);
  522. CommitAndIncrementSerial(deletedRecords, addedRecords);
  523. TriggerNotify();
  524. }
  525. catch
  526. {
  527. _dnssecStatus = AuthZoneDnssecStatus.Unsigned;
  528. _dnssecPrivateKeys = null;
  529. foreach (DnsResourceRecord addedRecord in addedRecords)
  530. TryDeleteRecord(addedRecord.Type, addedRecord.RDATA, out _);
  531. foreach (DnsResourceRecord deletedRecord in deletedRecords)
  532. AddRecord(deletedRecord, out _, out _);
  533. throw;
  534. }
  535. }
  536. public void UnsignZone()
  537. {
  538. if (_dnssecStatus == AuthZoneDnssecStatus.Unsigned)
  539. throw new DnsServerException("Cannot unsign zone: the is zone not signed.");
  540. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  541. IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetZoneWithSubDomainZones(_name);
  542. foreach (AuthZone zone in zones)
  543. {
  544. deletedRecords.AddRange(zone.RemoveAllDnssecRecords());
  545. if (zone is SubDomainZone subDomainZone)
  546. {
  547. if (zone.IsEmpty)
  548. _dnsServer.AuthZoneManager.RemoveSubDomainZone(zone.Name); //remove empty sub zone
  549. else
  550. subDomainZone.AutoUpdateState();
  551. }
  552. }
  553. Timer dnssecTimer = _dnssecTimer;
  554. if (dnssecTimer is not null)
  555. {
  556. lock (dnssecTimer)
  557. {
  558. dnssecTimer.Dispose();
  559. _dnssecTimer = null;
  560. }
  561. }
  562. _dnssecPrivateKeys = null;
  563. _dnssecStatus = AuthZoneDnssecStatus.Unsigned;
  564. CommitAndIncrementSerial(deletedRecords);
  565. TriggerNotify();
  566. }
  567. public void ConvertToNSec()
  568. {
  569. if (_dnssecStatus != AuthZoneDnssecStatus.SignedWithNSEC3)
  570. throw new DnsServerException("Cannot convert to NSEC: the zone must be signed with NSEC3 for conversion.");
  571. lock (_dnssecUpdateLock)
  572. {
  573. IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetZoneWithSubDomainZones(_name);
  574. DisableNSec3(zones);
  575. //since zones were removed when disabling NSEC3; get updated non empty zones list
  576. List<AuthZone> nonEmptyZones = new List<AuthZone>(zones.Count);
  577. foreach (AuthZone zone in zones)
  578. {
  579. if (!zone.IsEmpty)
  580. nonEmptyZones.Add(zone);
  581. }
  582. EnableNSec(nonEmptyZones);
  583. _dnssecStatus = AuthZoneDnssecStatus.SignedWithNSEC;
  584. }
  585. TriggerNotify();
  586. }
  587. public void ConvertToNSec3(ushort iterations, byte saltLength)
  588. {
  589. if (_dnssecStatus != AuthZoneDnssecStatus.SignedWithNSEC)
  590. throw new DnsServerException("Cannot convert to NSEC3: the zone must be signed with NSEC for conversion.");
  591. if (iterations > 50)
  592. throw new ArgumentOutOfRangeException(nameof(iterations), "NSEC3 iterations valid range is 0-50");
  593. if (saltLength > 32)
  594. throw new ArgumentOutOfRangeException(nameof(saltLength), "NSEC3 salt length valid range is 0-32");
  595. lock (_dnssecUpdateLock)
  596. {
  597. IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetZoneWithSubDomainZones(_name);
  598. DisableNSec(zones);
  599. EnableNSec3(zones, iterations, saltLength);
  600. _dnssecStatus = AuthZoneDnssecStatus.SignedWithNSEC3;
  601. }
  602. TriggerNotify();
  603. }
  604. public void UpdateNSec3Parameters(ushort iterations, byte saltLength)
  605. {
  606. if (_dnssecStatus != AuthZoneDnssecStatus.SignedWithNSEC3)
  607. throw new DnsServerException("Cannot update NSEC3 parameters: the zone must be signed with NSEC3 first.");
  608. if (iterations > 50)
  609. throw new ArgumentOutOfRangeException(nameof(iterations), "NSEC3 iterations valid range is 0-50");
  610. if (saltLength > 32)
  611. throw new ArgumentOutOfRangeException(nameof(saltLength), "NSEC3 salt length valid range is 0-32");
  612. lock (_dnssecUpdateLock)
  613. {
  614. IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetZoneWithSubDomainZones(_name);
  615. DisableNSec3(zones);
  616. //since zones were removed when disabling NSEC3; get updated non empty zones list
  617. List<AuthZone> nonEmptyZones = new List<AuthZone>(zones.Count);
  618. foreach (AuthZone zone in zones)
  619. {
  620. if (!zone.IsEmpty)
  621. nonEmptyZones.Add(zone);
  622. }
  623. EnableNSec3(nonEmptyZones, iterations, saltLength);
  624. }
  625. TriggerNotify();
  626. }
  627. private void RefreshNSec()
  628. {
  629. lock (_dnssecUpdateLock)
  630. {
  631. IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetZoneWithSubDomainZones(_name);
  632. EnableNSec(zones);
  633. }
  634. }
  635. private void RefreshNSec3()
  636. {
  637. lock (_dnssecUpdateLock)
  638. {
  639. IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetZoneWithSubDomainZones(_name);
  640. //get non NSEC3 zones
  641. List<AuthZone> nonNSec3Zones = new List<AuthZone>(zones.Count);
  642. foreach (AuthZone zone in zones)
  643. {
  644. if (zone.HasOnlyNSec3Records())
  645. continue;
  646. nonNSec3Zones.Add(zone);
  647. }
  648. IReadOnlyList<DnsResourceRecord> nsec3ParamRecords = GetRecords(DnsResourceRecordType.NSEC3PARAM);
  649. DnsNSEC3PARAMRecordData nsec3Param = nsec3ParamRecords[0].RDATA as DnsNSEC3PARAMRecordData;
  650. EnableNSec3(nonNSec3Zones, nsec3Param.Iterations, nsec3Param.Salt);
  651. }
  652. }
  653. private void EnableNSec(IReadOnlyList<AuthZone> zones)
  654. {
  655. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  656. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  657. uint ttl = GetZoneSoaMinimum();
  658. for (int i = 0; i < zones.Count; i++)
  659. {
  660. AuthZone zone = zones[i];
  661. AuthZone nextZone;
  662. if (i < zones.Count - 1)
  663. nextZone = zones[i + 1];
  664. else
  665. nextZone = zones[0];
  666. IReadOnlyList<DnsResourceRecord> newNSecRecords = zone.GetUpdatedNSecRRSet(nextZone.Name, ttl);
  667. if (newNSecRecords.Count > 0)
  668. {
  669. if (!zone.TrySetRecords(DnsResourceRecordType.NSEC, newNSecRecords, out IReadOnlyList<DnsResourceRecord> deletedNSecRecords))
  670. throw new DnsServerException("Failed to set DNSSEC records. Please try again.");
  671. addedRecords.AddRange(newNSecRecords);
  672. deletedRecords.AddRange(deletedNSecRecords);
  673. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(newNSecRecords);
  674. if (newRRSigRecords.Count > 0)
  675. {
  676. zone.AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  677. addedRecords.AddRange(newRRSigRecords);
  678. deletedRecords.AddRange(deletedRRSigRecords);
  679. }
  680. }
  681. }
  682. CommitAndIncrementSerial(deletedRecords, addedRecords);
  683. }
  684. private void DisableNSec(IReadOnlyList<AuthZone> zones)
  685. {
  686. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  687. foreach (AuthZone zone in zones)
  688. deletedRecords.AddRange(zone.RemoveNSecRecordsWithRRSig());
  689. CommitAndIncrementSerial(deletedRecords);
  690. }
  691. private void EnableNSec3(IReadOnlyList<AuthZone> zones, ushort iterations, byte saltLength)
  692. {
  693. byte[] salt;
  694. if (saltLength > 0)
  695. {
  696. salt = new byte[saltLength];
  697. using RandomNumberGenerator rng = RandomNumberGenerator.Create();
  698. rng.GetBytes(salt);
  699. }
  700. else
  701. {
  702. salt = Array.Empty<byte>();
  703. }
  704. EnableNSec3(zones, iterations, salt);
  705. }
  706. private void EnableNSec3(IReadOnlyList<AuthZone> zones, ushort iterations, byte[] salt)
  707. {
  708. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  709. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  710. List<DnsResourceRecord> partialNSec3Records = new List<DnsResourceRecord>(zones.Count);
  711. int apexLabelCount = DnsRRSIGRecordData.GetLabelCount(_name);
  712. uint ttl = GetZoneSoaMinimum();
  713. //list all partial NSEC3 records
  714. foreach (AuthZone zone in zones)
  715. {
  716. partialNSec3Records.Add(zone.GetPartialNSec3Record(_name, ttl, iterations, salt));
  717. int zoneLabelCount = DnsRRSIGRecordData.GetLabelCount(zone.Name);
  718. if ((zoneLabelCount - apexLabelCount) > 1)
  719. {
  720. //empty non-terminal (ENT) may exists
  721. string currentOwnerName = zone.Name;
  722. while (true)
  723. {
  724. currentOwnerName = AuthZoneManager.GetParentZone(currentOwnerName);
  725. if (currentOwnerName.Equals(_name, StringComparison.OrdinalIgnoreCase))
  726. break;
  727. //add partial NSEC3 record for ENT
  728. AuthZone entZone = new PrimarySubDomainZone(null, currentOwnerName); //dummy empty non-terminal (ENT) sub domain object
  729. partialNSec3Records.Add(entZone.GetPartialNSec3Record(_name, ttl, iterations, salt));
  730. }
  731. }
  732. }
  733. //sort partial NSEC3 records
  734. partialNSec3Records.Sort(delegate (DnsResourceRecord rr1, DnsResourceRecord rr2)
  735. {
  736. return string.CompareOrdinal(rr1.Name, rr2.Name);
  737. });
  738. //deduplicate partial NSEC3 records and insert next hashed owner name to complete them
  739. List<DnsResourceRecord> uniqueNSec3Records = new List<DnsResourceRecord>(partialNSec3Records.Count);
  740. for (int i = 0; i < partialNSec3Records.Count; i++)
  741. {
  742. DnsResourceRecord partialNSec3Record = partialNSec3Records[i];
  743. DnsResourceRecord nextPartialNSec3Record;
  744. if (i < partialNSec3Records.Count - 1)
  745. {
  746. nextPartialNSec3Record = partialNSec3Records[i + 1];
  747. //check for duplicates
  748. if (partialNSec3Record.Name.Equals(nextPartialNSec3Record.Name, StringComparison.OrdinalIgnoreCase))
  749. {
  750. //found duplicate; merge current nsec3 into next nsec3
  751. DnsNSEC3RecordData nsec3 = partialNSec3Record.RDATA as DnsNSEC3RecordData;
  752. DnsNSEC3RecordData nextNSec3 = nextPartialNSec3Record.RDATA as DnsNSEC3RecordData;
  753. List<DnsResourceRecordType> uniqueTypes = new List<DnsResourceRecordType>(nsec3.Types.Count + nextNSec3.Types.Count);
  754. uniqueTypes.AddRange(nsec3.Types);
  755. foreach (DnsResourceRecordType type in nextNSec3.Types)
  756. {
  757. if (!uniqueTypes.Contains(type))
  758. uniqueTypes.Add(type);
  759. }
  760. uniqueTypes.Sort();
  761. //update the next nsec3 record and continue
  762. DnsNSEC3RecordData mergedPartialNSec3 = new DnsNSEC3RecordData(DnssecNSEC3HashAlgorithm.SHA1, DnssecNSEC3Flags.None, iterations, salt, Array.Empty<byte>(), uniqueTypes);
  763. partialNSec3Records[i + 1] = new DnsResourceRecord(partialNSec3Record.Name, DnsResourceRecordType.NSEC3, DnsClass.IN, ttl, mergedPartialNSec3);
  764. continue;
  765. }
  766. }
  767. else
  768. {
  769. //for last NSEC3, next NSEC3 is the first in list
  770. nextPartialNSec3Record = partialNSec3Records[0];
  771. }
  772. //add NSEC3 record with next hashed owner name
  773. {
  774. DnsNSEC3RecordData partialNSec3 = partialNSec3Record.RDATA as DnsNSEC3RecordData;
  775. byte[] nextHashedOwnerName = DnsNSEC3RecordData.GetHashedOwnerNameFrom(nextPartialNSec3Record.Name);
  776. DnsNSEC3RecordData updatedNSec3 = new DnsNSEC3RecordData(DnssecNSEC3HashAlgorithm.SHA1, DnssecNSEC3Flags.None, iterations, salt, nextHashedOwnerName, partialNSec3.Types);
  777. uniqueNSec3Records.Add(new DnsResourceRecord(partialNSec3Record.Name, DnsResourceRecordType.NSEC3, DnsClass.IN, ttl, updatedNSec3));
  778. }
  779. }
  780. //insert and sign NSEC3 records
  781. foreach (DnsResourceRecord uniqueNSec3Record in uniqueNSec3Records)
  782. {
  783. AuthZone zone = _dnsServer.AuthZoneManager.GetOrAddSubDomainZone(_name, uniqueNSec3Record.Name);
  784. DnsResourceRecord[] newNSec3Records = new DnsResourceRecord[] { uniqueNSec3Record };
  785. if (!zone.TrySetRecords(DnsResourceRecordType.NSEC3, newNSec3Records, out IReadOnlyList<DnsResourceRecord> deletedNSec3Records))
  786. throw new InvalidOperationException();
  787. addedRecords.AddRange(newNSec3Records);
  788. deletedRecords.AddRange(deletedNSec3Records);
  789. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(newNSec3Records);
  790. if (newRRSigRecords.Count > 0)
  791. {
  792. zone.AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  793. addedRecords.AddRange(newRRSigRecords);
  794. deletedRecords.AddRange(deletedRRSigRecords);
  795. }
  796. }
  797. //insert and sign NSEC3PARAM record
  798. {
  799. DnsNSEC3PARAMRecordData newNSec3Param = new DnsNSEC3PARAMRecordData(DnssecNSEC3HashAlgorithm.SHA1, DnssecNSEC3Flags.None, iterations, salt);
  800. DnsResourceRecord[] newNSec3ParamRecords = new DnsResourceRecord[] { new DnsResourceRecord(_name, DnsResourceRecordType.NSEC3PARAM, DnsClass.IN, ttl, newNSec3Param) };
  801. if (!TrySetRecords(DnsResourceRecordType.NSEC3PARAM, newNSec3ParamRecords, out IReadOnlyList<DnsResourceRecord> deletedNSec3ParamRecords))
  802. throw new InvalidOperationException();
  803. addedRecords.AddRange(newNSec3ParamRecords);
  804. deletedRecords.AddRange(deletedNSec3ParamRecords);
  805. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(newNSec3ParamRecords);
  806. if (newRRSigRecords.Count > 0)
  807. {
  808. AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  809. addedRecords.AddRange(newRRSigRecords);
  810. deletedRecords.AddRange(deletedRRSigRecords);
  811. }
  812. }
  813. CommitAndIncrementSerial(deletedRecords, addedRecords);
  814. }
  815. private void DisableNSec3(IReadOnlyList<AuthZone> zones)
  816. {
  817. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  818. foreach (AuthZone zone in zones)
  819. {
  820. deletedRecords.AddRange(zone.RemoveNSec3RecordsWithRRSig());
  821. if (zone is SubDomainZone subDomainZone)
  822. {
  823. if (zone.IsEmpty)
  824. _dnsServer.AuthZoneManager.RemoveSubDomainZone(zone.Name); //remove empty sub zone
  825. else
  826. subDomainZone.AutoUpdateState();
  827. }
  828. }
  829. CommitAndIncrementSerial(deletedRecords);
  830. }
  831. public void GenerateAndAddRsaKey(DnssecPrivateKeyType keyType, string hashAlgorithm, int keySize, ushort rolloverDays)
  832. {
  833. if (_dnssecStatus == AuthZoneDnssecStatus.Unsigned)
  834. throw new DnsServerException("The zone must be signed.");
  835. DnssecAlgorithm algorithm;
  836. switch (hashAlgorithm.ToUpper())
  837. {
  838. case "MD5":
  839. algorithm = DnssecAlgorithm.RSAMD5;
  840. break;
  841. case "SHA1":
  842. algorithm = DnssecAlgorithm.RSASHA1;
  843. break;
  844. case "SHA256":
  845. algorithm = DnssecAlgorithm.RSASHA256;
  846. break;
  847. case "SHA512":
  848. algorithm = DnssecAlgorithm.RSASHA512;
  849. break;
  850. default:
  851. throw new NotSupportedException("Hash algorithm is not supported: " + hashAlgorithm);
  852. }
  853. GenerateAndAddRsaKey(keyType, algorithm, keySize, rolloverDays);
  854. }
  855. private void GenerateAndAddRsaKey(DnssecPrivateKeyType keyType, DnssecAlgorithm algorithm, int keySize, ushort rolloverDays)
  856. {
  857. int i = 0;
  858. while (i++ < 5)
  859. {
  860. DnssecPrivateKey privateKey = DnssecPrivateKey.Create(algorithm, keyType, keySize);
  861. privateKey.RolloverDays = rolloverDays;
  862. lock (_dnssecPrivateKeys)
  863. {
  864. if (_dnssecPrivateKeys.TryAdd(privateKey.KeyTag, privateKey))
  865. return;
  866. }
  867. }
  868. throw new DnsServerException("Failed to add private key: key tag collision.");
  869. }
  870. public void GenerateAndAddEcdsaKey(DnssecPrivateKeyType keyType, string curve, ushort rolloverDays)
  871. {
  872. if (_dnssecStatus == AuthZoneDnssecStatus.Unsigned)
  873. throw new DnsServerException("The zone must be signed.");
  874. DnssecAlgorithm algorithm;
  875. switch (curve.ToUpper())
  876. {
  877. case "P256":
  878. algorithm = DnssecAlgorithm.ECDSAP256SHA256;
  879. break;
  880. case "P384":
  881. algorithm = DnssecAlgorithm.ECDSAP384SHA384;
  882. break;
  883. default:
  884. throw new NotSupportedException("ECDSA curve is not supported: " + curve);
  885. }
  886. GenerateAndAddEcdsaKey(keyType, algorithm, rolloverDays);
  887. }
  888. private void GenerateAndAddEcdsaKey(DnssecPrivateKeyType keyType, DnssecAlgorithm algorithm, ushort rolloverDays)
  889. {
  890. int i = 0;
  891. while (i++ < 5)
  892. {
  893. DnssecPrivateKey privateKey = DnssecPrivateKey.Create(algorithm, keyType);
  894. privateKey.RolloverDays = rolloverDays;
  895. lock (_dnssecPrivateKeys)
  896. {
  897. if (_dnssecPrivateKeys.TryAdd(privateKey.KeyTag, privateKey))
  898. return;
  899. }
  900. }
  901. throw new DnsServerException("Failed to add private key: key tag collision.");
  902. }
  903. public void UpdatePrivateKey(ushort keyTag, ushort rolloverDays)
  904. {
  905. lock (_dnssecPrivateKeys)
  906. {
  907. if (!_dnssecPrivateKeys.TryGetValue(keyTag, out DnssecPrivateKey privateKey))
  908. throw new DnsServerException("Cannot update private key: no such private key was found.");
  909. privateKey.RolloverDays = rolloverDays;
  910. }
  911. }
  912. public void DeletePrivateKey(ushort keyTag)
  913. {
  914. if (_dnssecStatus == AuthZoneDnssecStatus.Unsigned)
  915. throw new DnsServerException("The zone must be signed.");
  916. lock (_dnssecPrivateKeys)
  917. {
  918. if (!_dnssecPrivateKeys.TryGetValue(keyTag, out DnssecPrivateKey privateKey))
  919. throw new DnsServerException("Cannot delete private key: no such private key was found.");
  920. if (privateKey.State != DnssecPrivateKeyState.Generated)
  921. throw new DnsServerException("Cannot delete private key: only keys with Generated state can be deleted.");
  922. _dnssecPrivateKeys.Remove(keyTag);
  923. }
  924. }
  925. public void PublishAllGeneratedKeys()
  926. {
  927. if (_dnssecStatus == AuthZoneDnssecStatus.Unsigned)
  928. throw new DnsServerException("The zone must be signed.");
  929. List<DnssecPrivateKey> generatedPrivateKeys = new List<DnssecPrivateKey>();
  930. List<DnsResourceRecord> newDnsKeyRecords = new List<DnsResourceRecord>();
  931. uint dnsKeyTtl = GetDnsKeyTtl();
  932. lock (_dnssecPrivateKeys)
  933. {
  934. foreach (KeyValuePair<ushort, DnssecPrivateKey> privateKeyEntry in _dnssecPrivateKeys)
  935. {
  936. DnssecPrivateKey privateKey = privateKeyEntry.Value;
  937. if (privateKey.State == DnssecPrivateKeyState.Generated)
  938. {
  939. generatedPrivateKeys.Add(privateKey);
  940. newDnsKeyRecords.Add(new DnsResourceRecord(_name, DnsResourceRecordType.DNSKEY, DnsClass.IN, dnsKeyTtl, privateKey.DnsKey));
  941. }
  942. }
  943. }
  944. if (generatedPrivateKeys.Count == 0)
  945. throw new DnsServerException("Cannot publish DNSKEY: no generated private keys were found.");
  946. IReadOnlyList<DnsResourceRecord> dnsKeyRecords = _entries.AddOrUpdate(DnsResourceRecordType.DNSKEY, delegate (DnsResourceRecordType key)
  947. {
  948. return newDnsKeyRecords;
  949. },
  950. delegate (DnsResourceRecordType key, IReadOnlyList<DnsResourceRecord> existingRecords)
  951. {
  952. foreach (DnsResourceRecord existingRecord in existingRecords)
  953. {
  954. foreach (DnsResourceRecord newDnsKeyRecord in newDnsKeyRecords)
  955. {
  956. if (existingRecord.Equals(newDnsKeyRecord))
  957. throw new DnsServerException("Cannot publish DNSKEY: the key is already published.");
  958. }
  959. }
  960. List<DnsResourceRecord> dnsKeyRecords = new List<DnsResourceRecord>(existingRecords.Count + newDnsKeyRecords.Count);
  961. dnsKeyRecords.AddRange(existingRecords);
  962. dnsKeyRecords.AddRange(newDnsKeyRecords);
  963. return dnsKeyRecords;
  964. });
  965. //update private key state before signing
  966. foreach (DnssecPrivateKey privateKey in generatedPrivateKeys)
  967. privateKey.SetState(DnssecPrivateKeyState.Published);
  968. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  969. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  970. addedRecords.AddRange(newDnsKeyRecords);
  971. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(dnsKeyRecords);
  972. if (newRRSigRecords.Count > 0)
  973. {
  974. AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  975. addedRecords.AddRange(newRRSigRecords);
  976. deletedRecords.AddRange(deletedRRSigRecords);
  977. }
  978. CommitAndIncrementSerial(deletedRecords, addedRecords);
  979. TriggerNotify();
  980. }
  981. private void ActivateZskDnsKeys(IReadOnlyList<DnssecPrivateKey> zskPrivateKeys)
  982. {
  983. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  984. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  985. //re-sign all records with new private keys
  986. IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetZoneWithSubDomainZones(_name);
  987. foreach (AuthZone zone in zones)
  988. {
  989. IReadOnlyList<DnsResourceRecord> newRRSigRecords = zone.SignAllRRSets();
  990. if (newRRSigRecords.Count > 0)
  991. {
  992. zone.AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  993. addedRecords.AddRange(newRRSigRecords);
  994. deletedRecords.AddRange(deletedRRSigRecords);
  995. }
  996. }
  997. CommitAndIncrementSerial(deletedRecords, addedRecords);
  998. TriggerNotify();
  999. //update private key state
  1000. string dnsKeyTags = null;
  1001. foreach (DnssecPrivateKey privateKey in zskPrivateKeys)
  1002. {
  1003. privateKey.SetState(DnssecPrivateKeyState.Active);
  1004. if (dnsKeyTags is null)
  1005. dnsKeyTags = privateKey.KeyTag.ToString();
  1006. else
  1007. dnsKeyTags += ", " + privateKey.KeyTag.ToString();
  1008. }
  1009. LogManager log = _dnsServer.LogManager;
  1010. if (log is not null)
  1011. log.Write("The ZSK DNSKEYs (" + dnsKeyTags + ") from the primary zone were activated successfully: " + _name);
  1012. }
  1013. public void RolloverDnsKey(ushort keyTag)
  1014. {
  1015. if (_dnssecStatus == AuthZoneDnssecStatus.Unsigned)
  1016. throw new DnsServerException("The zone must be signed.");
  1017. DnssecPrivateKey privateKey;
  1018. lock (_dnssecPrivateKeys)
  1019. {
  1020. if (!_dnssecPrivateKeys.TryGetValue(keyTag, out privateKey))
  1021. throw new DnsServerException("Cannot rollover private key: no such private key was found.");
  1022. }
  1023. switch (privateKey.State)
  1024. {
  1025. case DnssecPrivateKeyState.Ready:
  1026. case DnssecPrivateKeyState.Active:
  1027. if (privateKey.IsRetiring)
  1028. throw new DnsServerException("Cannot rollover private key: the private key is already set to retire.");
  1029. break;
  1030. default:
  1031. throw new DnsServerException("Cannot rollover private key: the private key state must be Ready or Active to be able to rollover.");
  1032. }
  1033. switch (privateKey.Algorithm)
  1034. {
  1035. case DnssecAlgorithm.RSAMD5:
  1036. case DnssecAlgorithm.RSASHA1:
  1037. case DnssecAlgorithm.RSASHA1_NSEC3_SHA1:
  1038. case DnssecAlgorithm.RSASHA256:
  1039. case DnssecAlgorithm.RSASHA512:
  1040. GenerateAndAddRsaKey(privateKey.KeyType, privateKey.Algorithm, (privateKey as DnssecRsaPrivateKey).KeySize, privateKey.RolloverDays);
  1041. break;
  1042. case DnssecAlgorithm.ECDSAP256SHA256:
  1043. case DnssecAlgorithm.ECDSAP384SHA384:
  1044. GenerateAndAddEcdsaKey(privateKey.KeyType, privateKey.Algorithm, privateKey.RolloverDays);
  1045. break;
  1046. default:
  1047. throw new NotSupportedException("DNSSEC algorithm is not supported: " + privateKey.Algorithm.ToString());
  1048. }
  1049. PublishAllGeneratedKeys();
  1050. privateKey.SetToRetire();
  1051. }
  1052. public void RetireDnsKey(ushort keyTag)
  1053. {
  1054. if (_dnssecStatus == AuthZoneDnssecStatus.Unsigned)
  1055. throw new DnsServerException("The zone must be signed.");
  1056. DnssecPrivateKey privateKeyToRetire;
  1057. lock (_dnssecPrivateKeys)
  1058. {
  1059. if (!_dnssecPrivateKeys.TryGetValue(keyTag, out privateKeyToRetire))
  1060. throw new DnsServerException("Cannot retire private key: no such private key was found.");
  1061. }
  1062. switch (privateKeyToRetire.KeyType)
  1063. {
  1064. case DnssecPrivateKeyType.KeySigningKey:
  1065. switch (privateKeyToRetire.State)
  1066. {
  1067. case DnssecPrivateKeyState.Ready:
  1068. case DnssecPrivateKeyState.Active:
  1069. if (!RetireKskDnsKeys(new DnssecPrivateKey[] { privateKeyToRetire }, true))
  1070. throw new DnsServerException("Cannot retire private key: no successor key was found to safely retire the key.");
  1071. break;
  1072. default:
  1073. throw new DnsServerException("Cannot retire private key: the KSK private key state must be Ready or Active to be able to retire.");
  1074. }
  1075. break;
  1076. case DnssecPrivateKeyType.ZoneSigningKey:
  1077. switch (privateKeyToRetire.State)
  1078. {
  1079. case DnssecPrivateKeyState.Active:
  1080. if (!RetireZskDnsKeys(new DnssecPrivateKey[] { privateKeyToRetire }, true))
  1081. throw new DnsServerException("Cannot retire private key: no successor key was found to safely retire the key.");
  1082. break;
  1083. default:
  1084. throw new DnsServerException("Cannot retire private key: the ZSK private key state must be Active to be able to retire.");
  1085. }
  1086. break;
  1087. default:
  1088. throw new InvalidOperationException();
  1089. }
  1090. }
  1091. private bool RetireKskDnsKeys(IReadOnlyList<DnssecPrivateKey> kskPrivateKeys, bool ignoreAlgorithm)
  1092. {
  1093. string dnsKeyTags = null;
  1094. foreach (DnssecPrivateKey kskPrivateKey in kskPrivateKeys)
  1095. {
  1096. bool isSafeToRetire = false;
  1097. lock (_dnssecPrivateKeys)
  1098. {
  1099. foreach (KeyValuePair<ushort, DnssecPrivateKey> privateKeyEntry in _dnssecPrivateKeys)
  1100. {
  1101. DnssecPrivateKey privateKey = privateKeyEntry.Value;
  1102. if ((privateKey.KeyType == DnssecPrivateKeyType.KeySigningKey) && (privateKey.KeyTag != kskPrivateKey.KeyTag) && !privateKey.IsRetiring)
  1103. {
  1104. if (ignoreAlgorithm)
  1105. {
  1106. //manual retire case
  1107. if (privateKey.Algorithm != kskPrivateKey.Algorithm)
  1108. {
  1109. //check if the sucessor ksk has a matching zsk
  1110. bool foundMatchingZsk = false;
  1111. foreach (KeyValuePair<ushort, DnssecPrivateKey> zskPrivateKeyEntry in _dnssecPrivateKeys)
  1112. {
  1113. DnssecPrivateKey zskPrivateKey = zskPrivateKeyEntry.Value;
  1114. if ((zskPrivateKey.KeyType == DnssecPrivateKeyType.ZoneSigningKey) && (zskPrivateKey.Algorithm == privateKey.Algorithm) && (zskPrivateKey.State == DnssecPrivateKeyState.Active) && !zskPrivateKey.IsRetiring)
  1115. {
  1116. foundMatchingZsk = true;
  1117. break;
  1118. }
  1119. }
  1120. if (!foundMatchingZsk)
  1121. continue;
  1122. }
  1123. }
  1124. else
  1125. {
  1126. //rollover case
  1127. if (privateKey.Algorithm != kskPrivateKey.Algorithm)
  1128. continue;
  1129. }
  1130. if (privateKey.State == DnssecPrivateKeyState.Active)
  1131. {
  1132. isSafeToRetire = true;
  1133. break;
  1134. }
  1135. if ((privateKey.State == DnssecPrivateKeyState.Ready) && (kskPrivateKey.State == DnssecPrivateKeyState.Ready))
  1136. {
  1137. isSafeToRetire = true;
  1138. break;
  1139. }
  1140. }
  1141. }
  1142. }
  1143. if (isSafeToRetire)
  1144. {
  1145. kskPrivateKey.SetState(DnssecPrivateKeyState.Retired);
  1146. if (dnsKeyTags is null)
  1147. dnsKeyTags = kskPrivateKey.KeyTag.ToString();
  1148. else
  1149. dnsKeyTags += ", " + kskPrivateKey.KeyTag.ToString();
  1150. }
  1151. }
  1152. if (dnsKeyTags is not null)
  1153. {
  1154. LogManager log = _dnsServer.LogManager;
  1155. if (log is not null)
  1156. log.Write("The KSK DNSKEYs (" + dnsKeyTags + ") from the primary zone were retired successfully: " + _name);
  1157. return true;
  1158. }
  1159. return false;
  1160. }
  1161. private bool RetireZskDnsKeys(IReadOnlyList<DnssecPrivateKey> zskPrivateKeys, bool ignoreAlgorithm)
  1162. {
  1163. string dnsKeyTags = null;
  1164. List<DnssecPrivateKey> zskToDeactivate = null;
  1165. foreach (DnssecPrivateKey zskPrivateKey in zskPrivateKeys)
  1166. {
  1167. bool isSafeToRetire = false;
  1168. lock (_dnssecPrivateKeys)
  1169. {
  1170. foreach (KeyValuePair<ushort, DnssecPrivateKey> privateKeyEntry in _dnssecPrivateKeys)
  1171. {
  1172. DnssecPrivateKey privateKey = privateKeyEntry.Value;
  1173. if ((privateKey.KeyType == DnssecPrivateKeyType.ZoneSigningKey) && (privateKey.KeyTag != zskPrivateKey.KeyTag) && (privateKey.State == DnssecPrivateKeyState.Active) && !privateKey.IsRetiring)
  1174. {
  1175. if (ignoreAlgorithm)
  1176. {
  1177. //manual retire case
  1178. if (privateKey.Algorithm != zskPrivateKey.Algorithm)
  1179. {
  1180. //check if the sucessor zsk has a matching ksk
  1181. bool foundMatchingKsk = false;
  1182. foreach (KeyValuePair<ushort, DnssecPrivateKey> kskPrivateKeyEntry in _dnssecPrivateKeys)
  1183. {
  1184. DnssecPrivateKey kskPrivateKey = kskPrivateKeyEntry.Value;
  1185. if ((kskPrivateKey.KeyType == DnssecPrivateKeyType.KeySigningKey) && (kskPrivateKey.Algorithm == privateKey.Algorithm) && ((kskPrivateKey.State == DnssecPrivateKeyState.Ready) || (kskPrivateKey.State == DnssecPrivateKeyState.Active)) && !kskPrivateKey.IsRetiring)
  1186. {
  1187. foundMatchingKsk = true;
  1188. break;
  1189. }
  1190. }
  1191. if (!foundMatchingKsk)
  1192. continue;
  1193. }
  1194. }
  1195. else
  1196. {
  1197. //rollover case
  1198. if (privateKey.Algorithm != zskPrivateKey.Algorithm)
  1199. continue;
  1200. }
  1201. isSafeToRetire = true;
  1202. break;
  1203. }
  1204. }
  1205. }
  1206. if (isSafeToRetire)
  1207. {
  1208. zskPrivateKey.SetState(DnssecPrivateKeyState.Retired);
  1209. if (zskToDeactivate is null)
  1210. zskToDeactivate = new List<DnssecPrivateKey>();
  1211. zskToDeactivate.Add(zskPrivateKey);
  1212. if (dnsKeyTags is null)
  1213. dnsKeyTags = zskPrivateKey.KeyTag.ToString();
  1214. else
  1215. dnsKeyTags += ", " + zskPrivateKey.KeyTag.ToString();
  1216. }
  1217. }
  1218. if (zskToDeactivate is not null)
  1219. DeactivateZskDnsKeys(zskToDeactivate);
  1220. if (dnsKeyTags is not null)
  1221. {
  1222. LogManager log = _dnsServer.LogManager;
  1223. if (log is not null)
  1224. log.Write("The ZSK DNSKEYs (" + dnsKeyTags + ") from the primary zone were retired successfully: " + _name);
  1225. return true;
  1226. }
  1227. return false;
  1228. }
  1229. private void DeactivateZskDnsKeys(IReadOnlyList<DnssecPrivateKey> zskPrivateKeys)
  1230. {
  1231. //remove all RRSIGs for the DNSKEYs
  1232. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  1233. IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetZoneWithSubDomainZones(_name);
  1234. foreach (AuthZone zone in zones)
  1235. {
  1236. IReadOnlyList<DnsResourceRecord> rrsigRecords = zone.GetRecords(DnsResourceRecordType.RRSIG);
  1237. List<DnsResourceRecord> rrsigsToRemove = new List<DnsResourceRecord>();
  1238. foreach (DnsResourceRecord rrsigRecord in rrsigRecords)
  1239. {
  1240. DnsRRSIGRecordData rrsig = rrsigRecord.RDATA as DnsRRSIGRecordData;
  1241. foreach (DnssecPrivateKey privateKey in zskPrivateKeys)
  1242. {
  1243. if (rrsig.KeyTag == privateKey.KeyTag)
  1244. {
  1245. rrsigsToRemove.Add(rrsigRecord);
  1246. break;
  1247. }
  1248. }
  1249. }
  1250. if (zone.TryDeleteRecords(DnsResourceRecordType.RRSIG, rrsigsToRemove, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords))
  1251. deletedRecords.AddRange(deletedRRSigRecords);
  1252. }
  1253. CommitAndIncrementSerial(deletedRecords);
  1254. TriggerNotify();
  1255. string dnsKeyTags = null;
  1256. foreach (DnssecPrivateKey privateKey in zskPrivateKeys)
  1257. {
  1258. if (dnsKeyTags is null)
  1259. dnsKeyTags = privateKey.KeyTag.ToString();
  1260. else
  1261. dnsKeyTags += ", " + privateKey.KeyTag.ToString();
  1262. }
  1263. LogManager log = _dnsServer.LogManager;
  1264. if (log is not null)
  1265. log.Write("The ZSK DNSKEYs (" + dnsKeyTags + ") from the primary zone were deactivated successfully: " + _name);
  1266. }
  1267. private void RevokeKskDnsKeys(IReadOnlyList<DnssecPrivateKey> kskPrivateKeys)
  1268. {
  1269. if (!_entries.TryGetValue(DnsResourceRecordType.DNSKEY, out IReadOnlyList<DnsResourceRecord> existingDnsKeyRecords))
  1270. throw new InvalidOperationException();
  1271. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  1272. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  1273. List<DnsResourceRecord> dnsKeyRecords = new List<DnsResourceRecord>();
  1274. foreach (DnsResourceRecord existingDnsKeyRecord in existingDnsKeyRecords)
  1275. {
  1276. bool found = false;
  1277. foreach (DnssecPrivateKey privateKey in kskPrivateKeys)
  1278. {
  1279. if (existingDnsKeyRecord.RDATA.Equals(privateKey.DnsKey))
  1280. {
  1281. found = true;
  1282. break;
  1283. }
  1284. }
  1285. if (!found)
  1286. dnsKeyRecords.Add(existingDnsKeyRecord);
  1287. }
  1288. uint dnsKeyTtl = existingDnsKeyRecords[0].OriginalTtlValue;
  1289. List<ushort> keyTagsToRemove = new List<ushort>(kskPrivateKeys.Count);
  1290. foreach (DnssecPrivateKey privateKey in kskPrivateKeys)
  1291. {
  1292. keyTagsToRemove.Add(privateKey.KeyTag);
  1293. privateKey.SetState(DnssecPrivateKeyState.Revoked);
  1294. DnsResourceRecord revokedDnsKeyRecord = new DnsResourceRecord(_name, DnsResourceRecordType.DNSKEY, DnsClass.IN, dnsKeyTtl, privateKey.DnsKey);
  1295. dnsKeyRecords.Add(revokedDnsKeyRecord);
  1296. }
  1297. if (!TrySetRecords(DnsResourceRecordType.DNSKEY, dnsKeyRecords, out IReadOnlyList<DnsResourceRecord> deletedDnsKeyRecords))
  1298. throw new InvalidOperationException();
  1299. addedRecords.AddRange(dnsKeyRecords);
  1300. deletedRecords.AddRange(deletedDnsKeyRecords);
  1301. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(dnsKeyRecords);
  1302. if (newRRSigRecords.Count > 0)
  1303. {
  1304. AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  1305. addedRecords.AddRange(newRRSigRecords);
  1306. deletedRecords.AddRange(deletedRRSigRecords);
  1307. }
  1308. //remove RRSIG for removed keys
  1309. {
  1310. IReadOnlyList<DnsResourceRecord> rrsigRecords = GetRecords(DnsResourceRecordType.RRSIG);
  1311. List<DnsResourceRecord> rrsigsToRemove = new List<DnsResourceRecord>();
  1312. foreach (DnsResourceRecord rrsigRecord in rrsigRecords)
  1313. {
  1314. DnsRRSIGRecordData rrsig = rrsigRecord.RDATA as DnsRRSIGRecordData;
  1315. if (rrsig.TypeCovered != DnsResourceRecordType.DNSKEY)
  1316. continue;
  1317. foreach (ushort keyTagToRemove in keyTagsToRemove)
  1318. {
  1319. if (rrsig.KeyTag == keyTagToRemove)
  1320. {
  1321. rrsigsToRemove.Add(rrsigRecord);
  1322. break;
  1323. }
  1324. }
  1325. }
  1326. if (TryDeleteRecords(DnsResourceRecordType.RRSIG, rrsigsToRemove, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords))
  1327. deletedRecords.AddRange(deletedRRSigRecords);
  1328. }
  1329. CommitAndIncrementSerial(deletedRecords, addedRecords);
  1330. TriggerNotify();
  1331. //update revoked private keys
  1332. string dnsKeyTags = null;
  1333. lock (_dnssecPrivateKeys)
  1334. {
  1335. //remove old entry
  1336. foreach (ushort keyTag in keyTagsToRemove)
  1337. {
  1338. if (_dnssecPrivateKeys.Remove(keyTag))
  1339. {
  1340. if (dnsKeyTags is null)
  1341. dnsKeyTags = keyTag.ToString();
  1342. else
  1343. dnsKeyTags += ", " + keyTag.ToString();
  1344. }
  1345. }
  1346. //add new entry
  1347. foreach (DnssecPrivateKey privateKey in kskPrivateKeys)
  1348. _dnssecPrivateKeys.Add(privateKey.KeyTag, privateKey);
  1349. }
  1350. LogManager log = _dnsServer.LogManager;
  1351. if (log is not null)
  1352. log.Write("The KSK DNSKEYs (" + dnsKeyTags + ") from the primary zone were revoked successfully: " + _name);
  1353. }
  1354. private void UnpublishDnsKeys(IReadOnlyList<DnssecPrivateKey> deadPrivateKeys)
  1355. {
  1356. if (!_entries.TryGetValue(DnsResourceRecordType.DNSKEY, out IReadOnlyList<DnsResourceRecord> existingDnsKeyRecords))
  1357. throw new InvalidOperationException();
  1358. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  1359. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  1360. List<DnsResourceRecord> dnsKeyRecords = new List<DnsResourceRecord>();
  1361. foreach (DnsResourceRecord existingDnsKeyRecord in existingDnsKeyRecords)
  1362. {
  1363. bool found = false;
  1364. foreach (DnssecPrivateKey privateKey in deadPrivateKeys)
  1365. {
  1366. if (existingDnsKeyRecord.RDATA.Equals(privateKey.DnsKey))
  1367. {
  1368. found = true;
  1369. break;
  1370. }
  1371. }
  1372. if (!found)
  1373. dnsKeyRecords.Add(existingDnsKeyRecord);
  1374. }
  1375. if (dnsKeyRecords.Count < 2)
  1376. throw new InvalidOperationException();
  1377. if (!TrySetRecords(DnsResourceRecordType.DNSKEY, dnsKeyRecords, out IReadOnlyList<DnsResourceRecord> deletedDnsKeyRecords))
  1378. throw new InvalidOperationException();
  1379. addedRecords.AddRange(dnsKeyRecords);
  1380. deletedRecords.AddRange(deletedDnsKeyRecords);
  1381. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(dnsKeyRecords);
  1382. if (newRRSigRecords.Count > 0)
  1383. {
  1384. AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  1385. addedRecords.AddRange(newRRSigRecords);
  1386. deletedRecords.AddRange(deletedRRSigRecords);
  1387. }
  1388. //remove RRSig for revoked keys
  1389. {
  1390. IReadOnlyList<DnsResourceRecord> rrsigRecords = GetRecords(DnsResourceRecordType.RRSIG);
  1391. List<DnsResourceRecord> rrsigsToRemove = new List<DnsResourceRecord>();
  1392. foreach (DnsResourceRecord rrsigRecord in rrsigRecords)
  1393. {
  1394. DnsRRSIGRecordData rrsig = rrsigRecord.RDATA as DnsRRSIGRecordData;
  1395. if (rrsig.TypeCovered != DnsResourceRecordType.DNSKEY)
  1396. continue;
  1397. foreach (DnssecPrivateKey privateKey in deadPrivateKeys)
  1398. {
  1399. if (rrsig.KeyTag == privateKey.KeyTag)
  1400. {
  1401. rrsigsToRemove.Add(rrsigRecord);
  1402. break;
  1403. }
  1404. }
  1405. }
  1406. if (TryDeleteRecords(DnsResourceRecordType.RRSIG, rrsigsToRemove, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords))
  1407. deletedRecords.AddRange(deletedRRSigRecords);
  1408. }
  1409. CommitAndIncrementSerial(deletedRecords, addedRecords);
  1410. TriggerNotify();
  1411. //remove private keys permanently
  1412. string dnsKeyTags = null;
  1413. lock (_dnssecPrivateKeys)
  1414. {
  1415. foreach (DnssecPrivateKey privateKey in deadPrivateKeys)
  1416. {
  1417. if (_dnssecPrivateKeys.Remove(privateKey.KeyTag))
  1418. {
  1419. if (dnsKeyTags is null)
  1420. dnsKeyTags = privateKey.KeyTag.ToString();
  1421. else
  1422. dnsKeyTags += ", " + privateKey.KeyTag.ToString();
  1423. }
  1424. }
  1425. }
  1426. LogManager log = _dnsServer.LogManager;
  1427. if (log is not null)
  1428. log.Write("The DNSKEYs (" + dnsKeyTags + ") from the primary zone were unpublished successfully: " + _name);
  1429. }
  1430. private async Task<IReadOnlyList<DnssecPrivateKey>> GetDSPublishedPrivateKeys(IReadOnlyList<DnssecPrivateKey> privateKeys)
  1431. {
  1432. if (_name.Length == 0)
  1433. return privateKeys; //zone is root
  1434. //delete any existing DS entries from cache to allow resolving latest ones
  1435. _dnsServer.CacheZoneManager.DeleteZone(_name);
  1436. IReadOnlyList<DnsDSRecordData> dsRecords = DnsClient.ParseResponseDS(await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(_name, DnsResourceRecordType.DS, DnsClass.IN)));
  1437. List<DnssecPrivateKey> activePrivateKeys = new List<DnssecPrivateKey>(dsRecords.Count);
  1438. foreach (DnsDSRecordData dsRecord in dsRecords)
  1439. {
  1440. foreach (DnssecPrivateKey privateKey in privateKeys)
  1441. {
  1442. if ((dsRecord.KeyTag == privateKey.DnsKey.ComputedKeyTag) && (dsRecord.Algorithm == privateKey.DnsKey.Algorithm) && privateKey.DnsKey.IsDnsKeyValid(_name, dsRecord))
  1443. {
  1444. activePrivateKeys.Add(privateKey);
  1445. break;
  1446. }
  1447. }
  1448. }
  1449. return activePrivateKeys;
  1450. }
  1451. private bool TryRefreshAllSignatures()
  1452. {
  1453. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  1454. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  1455. IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetZoneWithSubDomainZones(_name);
  1456. foreach (AuthZone zone in zones)
  1457. {
  1458. IReadOnlyList<DnsResourceRecord> newRRSigRecords = zone.RefreshSignatures();
  1459. if (newRRSigRecords.Count > 0)
  1460. {
  1461. zone.AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  1462. addedRecords.AddRange(newRRSigRecords);
  1463. deletedRecords.AddRange(deletedRRSigRecords);
  1464. }
  1465. }
  1466. if ((deletedRecords.Count > 0) || (addedRecords.Count > 0))
  1467. {
  1468. CommitAndIncrementSerial(deletedRecords, addedRecords);
  1469. TriggerNotify();
  1470. return true;
  1471. }
  1472. return false;
  1473. }
  1474. internal override IReadOnlyList<DnsResourceRecord> SignRRSet(IReadOnlyList<DnsResourceRecord> records)
  1475. {
  1476. DnsResourceRecordType rrsetType = records[0].Type;
  1477. List<DnsResourceRecord> rrsigRecords = new List<DnsResourceRecord>();
  1478. uint signatureValidityPeriod = GetSignatureValidityPeriod();
  1479. switch (rrsetType)
  1480. {
  1481. case DnsResourceRecordType.DNSKEY:
  1482. lock (_dnssecPrivateKeys)
  1483. {
  1484. foreach (KeyValuePair<ushort, DnssecPrivateKey> privateKeyEntry in _dnssecPrivateKeys)
  1485. {
  1486. DnssecPrivateKey privateKey = privateKeyEntry.Value;
  1487. if (privateKey.KeyType != DnssecPrivateKeyType.KeySigningKey)
  1488. continue;
  1489. switch (privateKey.State)
  1490. {
  1491. case DnssecPrivateKeyState.Published:
  1492. case DnssecPrivateKeyState.Ready:
  1493. case DnssecPrivateKeyState.Active:
  1494. case DnssecPrivateKeyState.Revoked:
  1495. rrsigRecords.Add(privateKey.SignRRSet(_name, records, DNSSEC_SIGNATURE_INCEPTION_OFFSET, signatureValidityPeriod));
  1496. break;
  1497. }
  1498. }
  1499. }
  1500. break;
  1501. case DnsResourceRecordType.RRSIG:
  1502. throw new InvalidOperationException();
  1503. case DnsResourceRecordType.ANAME:
  1504. case DnsResourceRecordType.APP:
  1505. throw new DnsServerException("Cannot sign RRSet: The record type [" + rrsetType.ToString() + "] is not supported by DNSSEC signed primary zones.");
  1506. default:
  1507. if ((rrsetType == DnsResourceRecordType.NS) && (records[0].Name.Length > _name.Length))
  1508. return Array.Empty<DnsResourceRecord>(); //referrer NS records are not signed
  1509. lock (_dnssecPrivateKeys)
  1510. {
  1511. foreach (KeyValuePair<ushort, DnssecPrivateKey> privateKeyEntry in _dnssecPrivateKeys)
  1512. {
  1513. DnssecPrivateKey privateKey = privateKeyEntry.Value;
  1514. if (privateKey.KeyType != DnssecPrivateKeyType.ZoneSigningKey)
  1515. continue;
  1516. switch (privateKey.State)
  1517. {
  1518. case DnssecPrivateKeyState.Ready:
  1519. case DnssecPrivateKeyState.Active:
  1520. rrsigRecords.Add(privateKey.SignRRSet(_name, records, DNSSEC_SIGNATURE_INCEPTION_OFFSET, signatureValidityPeriod));
  1521. break;
  1522. }
  1523. }
  1524. }
  1525. break;
  1526. }
  1527. if (rrsigRecords.Count == 0)
  1528. throw new InvalidOperationException("Cannot sign RRSet: no private key was available.");
  1529. return rrsigRecords;
  1530. }
  1531. internal void UpdateDnssecRecordsFor(AuthZone zone, DnsResourceRecordType type)
  1532. {
  1533. //lock to sync this call to prevent inconsistent NSEC/NSEC3 updates
  1534. lock (_dnssecUpdateLock)
  1535. {
  1536. IReadOnlyList<DnsResourceRecord> records = zone.GetRecords(type);
  1537. if (records.Count > 0)
  1538. {
  1539. //rrset added or updated
  1540. //sign rrset
  1541. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(records);
  1542. if (newRRSigRecords.Count > 0)
  1543. {
  1544. zone.AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  1545. CommitAndIncrementSerial(deletedRRSigRecords, newRRSigRecords);
  1546. }
  1547. }
  1548. else
  1549. {
  1550. //rrset deleted
  1551. //delete rrsig
  1552. IReadOnlyList<DnsResourceRecord> existingRRSigRecords = zone.GetRecords(DnsResourceRecordType.RRSIG);
  1553. if (existingRRSigRecords.Count > 0)
  1554. {
  1555. List<DnsResourceRecord> recordsToDelete = new List<DnsResourceRecord>();
  1556. foreach (DnsResourceRecord existingRRSigRecord in existingRRSigRecords)
  1557. {
  1558. DnsRRSIGRecordData rrsig = existingRRSigRecord.RDATA as DnsRRSIGRecordData;
  1559. if (rrsig.TypeCovered == type)
  1560. recordsToDelete.Add(existingRRSigRecord);
  1561. }
  1562. if (zone.TryDeleteRecords(DnsResourceRecordType.RRSIG, recordsToDelete, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords))
  1563. CommitAndIncrementSerial(deletedRRSigRecords);
  1564. }
  1565. }
  1566. if (_dnssecStatus == AuthZoneDnssecStatus.SignedWithNSEC)
  1567. {
  1568. UpdateNSecRRSetFor(zone);
  1569. }
  1570. else
  1571. {
  1572. UpdateNSec3RRSetFor(zone);
  1573. int apexLabelCount = DnsRRSIGRecordData.GetLabelCount(_name);
  1574. int zoneLabelCount = DnsRRSIGRecordData.GetLabelCount(zone.Name);
  1575. if ((zoneLabelCount - apexLabelCount) > 1)
  1576. {
  1577. //empty non-terminal (ENT) may exists
  1578. string currentOwnerName = zone.Name;
  1579. while (true)
  1580. {
  1581. currentOwnerName = AuthZoneManager.GetParentZone(currentOwnerName);
  1582. if (currentOwnerName.Equals(_name, StringComparison.OrdinalIgnoreCase))
  1583. break;
  1584. //update NSEC3 rrset for current owner name
  1585. AuthZone entZone = _dnsServer.AuthZoneManager.GetAuthZone(_name, currentOwnerName);
  1586. if (entZone is null)
  1587. entZone = new PrimarySubDomainZone(null, currentOwnerName); //dummy empty non-terminal (ENT) sub domain object
  1588. UpdateNSec3RRSetFor(entZone);
  1589. }
  1590. }
  1591. }
  1592. }
  1593. }
  1594. private void UpdateNSecRRSetFor(AuthZone zone)
  1595. {
  1596. uint ttl = GetZoneSoaMinimum();
  1597. IReadOnlyList<DnsResourceRecord> newNSecRecords = GetUpdatedNSecRRSetFor(zone, ttl);
  1598. if (newNSecRecords.Count > 0)
  1599. {
  1600. DnsResourceRecord newNSecRecord = newNSecRecords[0];
  1601. DnsNSECRecordData newNSec = newNSecRecord.RDATA as DnsNSECRecordData;
  1602. if (newNSec.Types.Count == 2)
  1603. {
  1604. //only NSEC and RRSIG exists so remove NSEC
  1605. IReadOnlyList<DnsResourceRecord> deletedNSecRecords = zone.RemoveNSecRecordsWithRRSig();
  1606. if (deletedNSecRecords.Count > 0)
  1607. CommitAndIncrementSerial(deletedNSecRecords);
  1608. //relink previous nsec
  1609. RelinkPreviousNSecRRSetFor(newNSecRecord, ttl, true);
  1610. }
  1611. else
  1612. {
  1613. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  1614. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  1615. if (!zone.TrySetRecords(DnsResourceRecordType.NSEC, newNSecRecords, out IReadOnlyList<DnsResourceRecord> deletedNSecRecords))
  1616. throw new DnsServerException("Failed to set DNSSEC records. Please try again.");
  1617. addedRecords.AddRange(newNSecRecords);
  1618. deletedRecords.AddRange(deletedNSecRecords);
  1619. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(newNSecRecords);
  1620. if (newRRSigRecords.Count > 0)
  1621. {
  1622. zone.AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  1623. addedRecords.AddRange(newRRSigRecords);
  1624. deletedRecords.AddRange(deletedRRSigRecords);
  1625. }
  1626. CommitAndIncrementSerial(deletedRecords, addedRecords);
  1627. if (deletedNSecRecords.Count == 0)
  1628. {
  1629. //new NSEC created since no old NSEC was removed
  1630. //relink previous nsec
  1631. RelinkPreviousNSecRRSetFor(newNSecRecord, ttl, false);
  1632. }
  1633. }
  1634. }
  1635. }
  1636. private void UpdateNSec3RRSetFor(AuthZone zone)
  1637. {
  1638. uint ttl = GetZoneSoaMinimum();
  1639. bool noSubDomainExistsForEmptyZone = (zone.IsEmpty || zone.HasOnlyNSec3Records()) && !_dnsServer.AuthZoneManager.SubDomainExists(_name, zone.Name);
  1640. IReadOnlyList<DnsResourceRecord> newNSec3Records = GetUpdatedNSec3RRSetFor(zone, ttl, noSubDomainExistsForEmptyZone);
  1641. if (newNSec3Records.Count > 0)
  1642. {
  1643. DnsResourceRecord newNSec3Record = newNSec3Records[0];
  1644. AuthZone nsec3Zone = _dnsServer.AuthZoneManager.GetOrAddSubDomainZone(_name, newNSec3Record.Name);
  1645. if (nsec3Zone is null)
  1646. throw new InvalidOperationException();
  1647. if (noSubDomainExistsForEmptyZone)
  1648. {
  1649. //no records exists in real zone and no sub domain exists, so remove NSEC3
  1650. IReadOnlyList<DnsResourceRecord> deletedNSec3Records = nsec3Zone.RemoveNSec3RecordsWithRRSig();
  1651. if (deletedNSec3Records.Count > 0)
  1652. CommitAndIncrementSerial(deletedNSec3Records);
  1653. //remove nsec3 sub domain zone if empty since it wont get removed otherwise
  1654. if (nsec3Zone is SubDomainZone nsec3SubDomainZone)
  1655. {
  1656. if (nsec3Zone.IsEmpty)
  1657. _dnsServer.AuthZoneManager.RemoveSubDomainZone(nsec3Zone.Name); //remove empty sub zone
  1658. else
  1659. nsec3SubDomainZone.AutoUpdateState();
  1660. }
  1661. //remove the real zone if empty so that any of the ENT that exists can also be removed later
  1662. if (zone is SubDomainZone subDomainZone)
  1663. {
  1664. if (zone.IsEmpty)
  1665. _dnsServer.AuthZoneManager.RemoveSubDomainZone(zone.Name); //remove empty sub zone
  1666. else
  1667. subDomainZone.AutoUpdateState();
  1668. }
  1669. //relink previous nsec3
  1670. RelinkPreviousNSec3RRSet(newNSec3Record, ttl, true);
  1671. }
  1672. else
  1673. {
  1674. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  1675. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  1676. if (!nsec3Zone.TrySetRecords(DnsResourceRecordType.NSEC3, newNSec3Records, out IReadOnlyList<DnsResourceRecord> deletedNSec3Records))
  1677. throw new DnsServerException("Failed to set DNSSEC records. Please try again.");
  1678. addedRecords.AddRange(newNSec3Records);
  1679. deletedRecords.AddRange(deletedNSec3Records);
  1680. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(newNSec3Records);
  1681. if (newRRSigRecords.Count > 0)
  1682. {
  1683. nsec3Zone.AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  1684. addedRecords.AddRange(newRRSigRecords);
  1685. deletedRecords.AddRange(deletedRRSigRecords);
  1686. }
  1687. CommitAndIncrementSerial(deletedRecords, addedRecords);
  1688. if (deletedNSec3Records.Count == 0)
  1689. {
  1690. //new NSEC3 created since no old NSEC3 was removed
  1691. //relink previous nsec
  1692. RelinkPreviousNSec3RRSet(newNSec3Record, ttl, false);
  1693. }
  1694. }
  1695. }
  1696. }
  1697. private IReadOnlyList<DnsResourceRecord> GetUpdatedNSecRRSetFor(AuthZone zone, uint ttl)
  1698. {
  1699. AuthZone nextZone = _dnsServer.AuthZoneManager.FindNextSubDomainZone(_name, zone.Name);
  1700. if (nextZone is null)
  1701. nextZone = this;
  1702. return zone.GetUpdatedNSecRRSet(nextZone.Name, ttl);
  1703. }
  1704. private IReadOnlyList<DnsResourceRecord> GetUpdatedNSec3RRSetFor(AuthZone zone, uint ttl, bool forceGetNewRRSet)
  1705. {
  1706. if (!_entries.TryGetValue(DnsResourceRecordType.NSEC3PARAM, out IReadOnlyList<DnsResourceRecord> nsec3ParamRecords))
  1707. throw new InvalidOperationException();
  1708. DnsResourceRecord nsec3ParamRecord = nsec3ParamRecords[0];
  1709. DnsNSEC3PARAMRecordData nsec3Param = nsec3ParamRecord.RDATA as DnsNSEC3PARAMRecordData;
  1710. string hashedOwnerName = nsec3Param.ComputeHashedOwnerNameBase32HexString(zone.Name) + (_name.Length > 0 ? "." + _name : "");
  1711. byte[] nextHashedOwnerName = null;
  1712. //find next hashed owner name
  1713. string currentOwnerName = hashedOwnerName;
  1714. while (true)
  1715. {
  1716. AuthZone nextZone = _dnsServer.AuthZoneManager.FindNextSubDomainZone(_name, currentOwnerName);
  1717. if (nextZone is null)
  1718. break;
  1719. IReadOnlyList<DnsResourceRecord> nextNSec3Records = nextZone.GetRecords(DnsResourceRecordType.NSEC3);
  1720. if (nextNSec3Records.Count > 0)
  1721. {
  1722. nextHashedOwnerName = DnsNSEC3RecordData.GetHashedOwnerNameFrom(nextNSec3Records[0].Name);
  1723. break;
  1724. }
  1725. currentOwnerName = nextZone.Name;
  1726. }
  1727. if (nextHashedOwnerName is null)
  1728. {
  1729. //didnt find next NSEC3 record since current must be last; find the first NSEC3 record
  1730. DnsResourceRecord previousNSec3Record = null;
  1731. while (true)
  1732. {
  1733. AuthZone previousZone = _dnsServer.AuthZoneManager.FindPreviousSubDomainZone(_name, currentOwnerName);
  1734. if (previousZone is null)
  1735. break;
  1736. IReadOnlyList<DnsResourceRecord> previousNSec3Records = previousZone.GetRecords(DnsResourceRecordType.NSEC3);
  1737. if (previousNSec3Records.Count > 0)
  1738. previousNSec3Record = previousNSec3Records[0];
  1739. currentOwnerName = previousZone.Name;
  1740. }
  1741. if (previousNSec3Record is not null)
  1742. nextHashedOwnerName = DnsNSEC3RecordData.GetHashedOwnerNameFrom(previousNSec3Record.Name);
  1743. }
  1744. if (nextHashedOwnerName is null)
  1745. nextHashedOwnerName = DnsNSEC3RecordData.GetHashedOwnerNameFrom(hashedOwnerName); //only 1 NSEC3 record in zone
  1746. IReadOnlyList<DnsResourceRecord> newNSec3Records = zone.CreateNSec3RRSet(hashedOwnerName, nextHashedOwnerName, ttl, nsec3Param.Iterations, nsec3Param.Salt);
  1747. if (forceGetNewRRSet)
  1748. return newNSec3Records;
  1749. AuthZone nsec3Zone = _dnsServer.AuthZoneManager.GetAuthZone(_name, hashedOwnerName);
  1750. if (nsec3Zone is null)
  1751. return newNSec3Records;
  1752. return nsec3Zone.GetUpdatedNSec3RRSet(newNSec3Records);
  1753. }
  1754. private void RelinkPreviousNSecRRSetFor(DnsResourceRecord currentNSecRecord, uint ttl, bool wasRemoved)
  1755. {
  1756. AuthZone previousNsecZone = _dnsServer.AuthZoneManager.FindPreviousSubDomainZone(_name, currentNSecRecord.Name);
  1757. if (previousNsecZone is null)
  1758. return; //current zone is apex
  1759. IReadOnlyList<DnsResourceRecord> newPreviousNSecRecords;
  1760. if (wasRemoved)
  1761. newPreviousNSecRecords = previousNsecZone.GetUpdatedNSecRRSet((currentNSecRecord.RDATA as DnsNSECRecordData).NextDomainName, ttl);
  1762. else
  1763. newPreviousNSecRecords = previousNsecZone.GetUpdatedNSecRRSet(currentNSecRecord.Name, ttl);
  1764. if (newPreviousNSecRecords.Count > 0)
  1765. {
  1766. if (!previousNsecZone.TrySetRecords(DnsResourceRecordType.NSEC, newPreviousNSecRecords, out IReadOnlyList<DnsResourceRecord> deletedNSecRecords))
  1767. throw new DnsServerException("Failed to set DNSSEC records. Please try again.");
  1768. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  1769. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  1770. addedRecords.AddRange(newPreviousNSecRecords);
  1771. deletedRecords.AddRange(deletedNSecRecords);
  1772. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(newPreviousNSecRecords);
  1773. if (newRRSigRecords.Count > 0)
  1774. {
  1775. previousNsecZone.AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  1776. addedRecords.AddRange(newRRSigRecords);
  1777. deletedRecords.AddRange(deletedRRSigRecords);
  1778. }
  1779. CommitAndIncrementSerial(deletedRecords, addedRecords);
  1780. }
  1781. }
  1782. private void RelinkPreviousNSec3RRSet(DnsResourceRecord currentNSec3Record, uint ttl, bool wasRemoved)
  1783. {
  1784. DnsNSEC3RecordData currentNSec3 = currentNSec3Record.RDATA as DnsNSEC3RecordData;
  1785. //find the previous NSEC3 and update it
  1786. DnsResourceRecord previousNSec3Record = null;
  1787. AuthZone previousNSec3Zone;
  1788. string currentOwnerName = currentNSec3Record.Name;
  1789. while (true)
  1790. {
  1791. previousNSec3Zone = _dnsServer.AuthZoneManager.FindPreviousSubDomainZone(_name, currentOwnerName);
  1792. if (previousNSec3Zone is null)
  1793. break;
  1794. IReadOnlyList<DnsResourceRecord> previousNSec3Records = previousNSec3Zone.GetRecords(DnsResourceRecordType.NSEC3);
  1795. if (previousNSec3Records.Count > 0)
  1796. {
  1797. previousNSec3Record = previousNSec3Records[0];
  1798. break;
  1799. }
  1800. currentOwnerName = previousNSec3Zone.Name;
  1801. }
  1802. if (previousNSec3Record is null)
  1803. {
  1804. //didnt find previous NSEC3; find the last NSEC3 to update
  1805. if (wasRemoved)
  1806. currentOwnerName = currentNSec3.NextHashedOwnerName + (_name.Length > 0 ? "." + _name : "");
  1807. else
  1808. currentOwnerName = currentNSec3Record.Name;
  1809. while (true)
  1810. {
  1811. AuthZone nextNSec3Zone = _dnsServer.AuthZoneManager.GetAuthZone(_name, currentOwnerName);
  1812. if (nextNSec3Zone is null)
  1813. break;
  1814. IReadOnlyList<DnsResourceRecord> nextNSec3Records = nextNSec3Zone.GetRecords(DnsResourceRecordType.NSEC3);
  1815. if (nextNSec3Records.Count > 0)
  1816. {
  1817. previousNSec3Record = nextNSec3Records[0];
  1818. previousNSec3Zone = nextNSec3Zone;
  1819. string nextHashedOwnerNameString = (previousNSec3Record.RDATA as DnsNSEC3RecordData).NextHashedOwnerName + (_name.Length > 0 ? "." + _name : "");
  1820. if (DnsNSECRecordData.CanonicalComparison(previousNSec3Record.Name, nextHashedOwnerNameString) >= 0)
  1821. break; //found last NSEC3
  1822. //jump to next hashed owner
  1823. currentOwnerName = nextHashedOwnerNameString;
  1824. }
  1825. else
  1826. {
  1827. currentOwnerName = nextNSec3Zone.Name;
  1828. }
  1829. }
  1830. }
  1831. if (previousNSec3Record is null)
  1832. throw new InvalidOperationException();
  1833. DnsNSEC3RecordData previousNSec3 = previousNSec3Record.RDATA as DnsNSEC3RecordData;
  1834. DnsNSEC3RecordData newPreviousNSec3;
  1835. if (wasRemoved)
  1836. newPreviousNSec3 = new DnsNSEC3RecordData(DnssecNSEC3HashAlgorithm.SHA1, DnssecNSEC3Flags.None, previousNSec3.Iterations, previousNSec3.Salt, currentNSec3.NextHashedOwnerNameValue, previousNSec3.Types);
  1837. else
  1838. newPreviousNSec3 = new DnsNSEC3RecordData(DnssecNSEC3HashAlgorithm.SHA1, DnssecNSEC3Flags.None, previousNSec3.Iterations, previousNSec3.Salt, DnsNSEC3RecordData.GetHashedOwnerNameFrom(currentNSec3Record.Name), previousNSec3.Types);
  1839. DnsResourceRecord[] newPreviousNSec3Records = new DnsResourceRecord[] { new DnsResourceRecord(previousNSec3Record.Name, DnsResourceRecordType.NSEC3, DnsClass.IN, ttl, newPreviousNSec3) };
  1840. if (!previousNSec3Zone.TrySetRecords(DnsResourceRecordType.NSEC3, newPreviousNSec3Records, out IReadOnlyList<DnsResourceRecord> deletedNSec3Records))
  1841. throw new DnsServerException("Failed to set DNSSEC records. Please try again.");
  1842. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  1843. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  1844. addedRecords.AddRange(newPreviousNSec3Records);
  1845. deletedRecords.AddRange(deletedNSec3Records);
  1846. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(newPreviousNSec3Records);
  1847. if (newRRSigRecords.Count > 0)
  1848. {
  1849. previousNSec3Zone.AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  1850. addedRecords.AddRange(newRRSigRecords);
  1851. deletedRecords.AddRange(deletedRRSigRecords);
  1852. }
  1853. CommitAndIncrementSerial(deletedRecords, addedRecords);
  1854. }
  1855. private uint GetSignatureValidityPeriod()
  1856. {
  1857. //SOA EXPIRE + 3 days
  1858. return (_entries[DnsResourceRecordType.SOA][0].RDATA as DnsSOARecordData).Expire + (3 * 24 * 60 * 60);
  1859. }
  1860. internal DateTime GetDnsKeyStateReadyBy(DnssecPrivateKey privateKey)
  1861. {
  1862. return GetDnsKeyStateReadyOn(privateKey).AddMilliseconds(DNSSEC_TIMER_PERIODIC_INTERVAL);
  1863. }
  1864. private DateTime GetDnsKeyStateReadyOn(DnssecPrivateKey privateKey)
  1865. {
  1866. bool foundOldKsk = false;
  1867. lock (_dnssecPrivateKeys)
  1868. {
  1869. foreach (KeyValuePair<ushort, DnssecPrivateKey> dnssecPrivateKey in _dnssecPrivateKeys)
  1870. {
  1871. DnssecPrivateKey kskPrivateKey = dnssecPrivateKey.Value;
  1872. if (kskPrivateKey.KeyType == DnssecPrivateKeyType.KeySigningKey)
  1873. {
  1874. if ((kskPrivateKey.State == DnssecPrivateKeyState.Ready) || (kskPrivateKey.State == DnssecPrivateKeyState.Active))
  1875. {
  1876. foundOldKsk = true;
  1877. break;
  1878. }
  1879. }
  1880. }
  1881. }
  1882. if (foundOldKsk)
  1883. return privateKey.StateChangedOn.AddSeconds(GetDnsKeyTtl() + GetPropagationDelay());
  1884. else
  1885. return privateKey.StateChangedOn.AddSeconds(GetMaxRecordTtl() + GetPropagationDelay()); //newly signed zone case
  1886. }
  1887. private uint GetPropagationDelay()
  1888. {
  1889. //the max time required to sync zone changes to secondaries if NOTIFY fails to trigger a zone transfer
  1890. DnsSOARecordData soa = _entries[DnsResourceRecordType.SOA][0].RDATA as DnsSOARecordData;
  1891. return soa.Refresh + soa.Retry;
  1892. }
  1893. private async Task<uint> GetParentSidePropagationDelayAsync()
  1894. {
  1895. uint parentSidePropagationDelay = 24 * 60 * 60;
  1896. try
  1897. {
  1898. string parent = AuthZoneManager.GetParentZone(_name);
  1899. if (parent is null)
  1900. parent = "";
  1901. DnsDatagram soaResponse = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(parent, DnsResourceRecordType.SOA, DnsClass.IN), 10000);
  1902. if (soaResponse.RCODE == DnsResponseCode.NoError)
  1903. {
  1904. IReadOnlyList<DnsResourceRecord> records;
  1905. if (soaResponse.Answer.Count > 0)
  1906. records = soaResponse.Answer;
  1907. else if (soaResponse.Authority.Count > 0)
  1908. records = soaResponse.Authority;
  1909. else
  1910. records = null;
  1911. if (records is not null)
  1912. {
  1913. foreach (DnsResourceRecord record in records)
  1914. {
  1915. if (record.Type == DnsResourceRecordType.SOA)
  1916. {
  1917. DnsSOARecordData parentSoa = record.RDATA as DnsSOARecordData;
  1918. parentSidePropagationDelay = parentSoa.Refresh + parentSoa.Retry;
  1919. break;
  1920. }
  1921. }
  1922. }
  1923. }
  1924. }
  1925. catch (Exception ex)
  1926. {
  1927. LogManager log = _dnsServer.LogManager;
  1928. if (log is not null)
  1929. log.Write(ex);
  1930. }
  1931. return parentSidePropagationDelay;
  1932. }
  1933. private uint GetMaxRecordTtl()
  1934. {
  1935. uint maxTtl = 0;
  1936. foreach (KeyValuePair<DnsResourceRecordType, IReadOnlyList<DnsResourceRecord>> entry in _entries)
  1937. {
  1938. if (entry.Key == DnsResourceRecordType.RRSIG)
  1939. continue;
  1940. IReadOnlyList<DnsResourceRecord> rrset = entry.Value;
  1941. //find min TTL
  1942. uint rrsetTtl = 0;
  1943. foreach (DnsResourceRecord rr in rrset)
  1944. {
  1945. if ((rrsetTtl == 0) || (rrsetTtl > rr.OriginalTtlValue))
  1946. rrsetTtl = rr.OriginalTtlValue;
  1947. }
  1948. if (rrsetTtl > maxTtl)
  1949. maxTtl = rrsetTtl;
  1950. }
  1951. return maxTtl;
  1952. }
  1953. private uint GetMaxRRSigTtl()
  1954. {
  1955. uint maxTtl = 0;
  1956. if (!_entries.TryGetValue(DnsResourceRecordType.RRSIG, out IReadOnlyList<DnsResourceRecord> rrsigRecords))
  1957. throw new InvalidOperationException();
  1958. foreach (DnsResourceRecord rr in rrsigRecords)
  1959. {
  1960. if (rr.OriginalTtlValue > maxTtl)
  1961. maxTtl = rr.OriginalTtlValue;
  1962. }
  1963. return maxTtl;
  1964. }
  1965. private uint GetZoneSoaMinimum()
  1966. {
  1967. return (_entries[DnsResourceRecordType.SOA][0].RDATA as DnsSOARecordData).Minimum;
  1968. }
  1969. internal uint GetZoneSoaExpire()
  1970. {
  1971. return (_entries[DnsResourceRecordType.SOA][0].RDATA as DnsSOARecordData).Expire;
  1972. }
  1973. private async Task<uint> GetDSTtl()
  1974. {
  1975. uint dsTtl = 24 * 60 * 60;
  1976. try
  1977. {
  1978. DnsDatagram dsResponse = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(_name, DnsResourceRecordType.DS, DnsClass.IN), 10000);
  1979. if (dsResponse.RCODE == DnsResponseCode.NoError)
  1980. {
  1981. if (dsResponse.Answer.Count > 0)
  1982. {
  1983. //find min TTL
  1984. dsTtl = 0;
  1985. foreach (DnsResourceRecord answer in dsResponse.Answer)
  1986. {
  1987. if (answer.Type == DnsResourceRecordType.DS)
  1988. {
  1989. if ((dsTtl == 0) || (dsTtl > answer.OriginalTtlValue))
  1990. dsTtl = answer.OriginalTtlValue;
  1991. }
  1992. }
  1993. }
  1994. else
  1995. {
  1996. dsTtl = 0; //no DS was found
  1997. }
  1998. }
  1999. }
  2000. catch (Exception ex)
  2001. {
  2002. LogManager log = _dnsServer.LogManager;
  2003. if (log is not null)
  2004. log.Write(ex);
  2005. }
  2006. return dsTtl;
  2007. }
  2008. public uint GetDnsKeyTtl()
  2009. {
  2010. if (_entries.TryGetValue(DnsResourceRecordType.DNSKEY, out IReadOnlyList<DnsResourceRecord> dnsKeyRecords))
  2011. return dnsKeyRecords[0].OriginalTtlValue;
  2012. return 24 * 60 * 60;
  2013. }
  2014. public void UpdateDnsKeyTtl(uint dnsKeyTtl)
  2015. {
  2016. if (_dnssecStatus == AuthZoneDnssecStatus.Unsigned)
  2017. throw new DnsServerException("The zone must be signed.");
  2018. lock (_dnssecPrivateKeys)
  2019. {
  2020. foreach (KeyValuePair<ushort, DnssecPrivateKey> privateKeyEntry in _dnssecPrivateKeys)
  2021. {
  2022. switch (privateKeyEntry.Value.State)
  2023. {
  2024. case DnssecPrivateKeyState.Ready:
  2025. case DnssecPrivateKeyState.Active:
  2026. break;
  2027. default:
  2028. throw new DnsServerException("Cannot update DNSKEY TTL value: one or more private keys have state other than Ready or Active.");
  2029. }
  2030. }
  2031. }
  2032. if (!_entries.TryGetValue(DnsResourceRecordType.DNSKEY, out IReadOnlyList<DnsResourceRecord> dnsKeyRecords))
  2033. throw new InvalidOperationException();
  2034. DnsResourceRecord[] newDnsKeyRecords = new DnsResourceRecord[dnsKeyRecords.Count];
  2035. for (int i = 0; i < dnsKeyRecords.Count; i++)
  2036. {
  2037. DnsResourceRecord dnsKeyRecord = dnsKeyRecords[i];
  2038. newDnsKeyRecords[i] = new DnsResourceRecord(dnsKeyRecord.Name, DnsResourceRecordType.DNSKEY, DnsClass.IN, dnsKeyTtl, dnsKeyRecord.RDATA);
  2039. }
  2040. List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
  2041. List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
  2042. if (!TrySetRecords(DnsResourceRecordType.DNSKEY, newDnsKeyRecords, out IReadOnlyList<DnsResourceRecord> deletedDnsKeyRecords))
  2043. throw new DnsServerException("Failed to update DNSKEY TTL. Please try again.");
  2044. addedRecords.AddRange(newDnsKeyRecords);
  2045. deletedRecords.AddRange(deletedDnsKeyRecords);
  2046. IReadOnlyList<DnsResourceRecord> newRRSigRecords = SignRRSet(newDnsKeyRecords);
  2047. if (newRRSigRecords.Count > 0)
  2048. {
  2049. AddOrUpdateRRSigRecords(newRRSigRecords, out IReadOnlyList<DnsResourceRecord> deletedRRSigRecords);
  2050. addedRecords.AddRange(newRRSigRecords);
  2051. deletedRecords.AddRange(deletedRRSigRecords);
  2052. }
  2053. CommitAndIncrementSerial(deletedRecords, addedRecords);
  2054. TriggerNotify();
  2055. }
  2056. #endregion
  2057. #region versioning
  2058. internal void CommitAndIncrementSerial(IReadOnlyList<DnsResourceRecord> deletedRecords = null, IReadOnlyList<DnsResourceRecord> addedRecords = null)
  2059. {
  2060. if (_internal)
  2061. return;
  2062. lock (_zoneHistory)
  2063. {
  2064. DnsResourceRecord oldSoaRecord = _entries[DnsResourceRecordType.SOA][0];
  2065. DnsResourceRecord newSoaRecord;
  2066. {
  2067. DnsSOARecordData oldSoa = oldSoaRecord.RDATA as DnsSOARecordData;
  2068. if ((addedRecords is not null) && (addedRecords.Count == 1) && (addedRecords[0].Type == DnsResourceRecordType.SOA))
  2069. {
  2070. DnsResourceRecord addSoaRecord = addedRecords[0];
  2071. DnsSOARecordData addSoa = addSoaRecord.RDATA as DnsSOARecordData;
  2072. uint serial = oldSoa.Serial;
  2073. if (addSoa.Serial > serial)
  2074. serial = addSoa.Serial;
  2075. else if (serial < uint.MaxValue)
  2076. serial++;
  2077. else
  2078. serial = 1;
  2079. 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 };
  2080. addedRecords = null;
  2081. }
  2082. else
  2083. {
  2084. uint serial = oldSoa.Serial;
  2085. if (serial < uint.MaxValue)
  2086. serial++;
  2087. else
  2088. serial = 1;
  2089. 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 };
  2090. }
  2091. }
  2092. DnsResourceRecord[] newSoaRecords = new DnsResourceRecord[] { newSoaRecord };
  2093. //update SOA
  2094. _entries[DnsResourceRecordType.SOA] = newSoaRecords;
  2095. IReadOnlyList<DnsResourceRecord> newRRSigRecords = null;
  2096. IReadOnlyList<DnsResourceRecord> deletedRRSigRecords = null;
  2097. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  2098. {
  2099. //sign SOA and update RRSig
  2100. newRRSigRecords = SignRRSet(newSoaRecords);
  2101. AddOrUpdateRRSigRecords(newRRSigRecords, out deletedRRSigRecords);
  2102. }
  2103. //remove RR info from old SOA to allow creating new RR info for it during SetDeletedOn()
  2104. oldSoaRecord.Tag = null;
  2105. //start commit
  2106. oldSoaRecord.GetAuthRecordInfo().DeletedOn = DateTime.UtcNow;
  2107. //write removed
  2108. _zoneHistory.Add(oldSoaRecord);
  2109. if (deletedRecords is not null)
  2110. {
  2111. foreach (DnsResourceRecord deletedRecord in deletedRecords)
  2112. {
  2113. if (deletedRecord.GetAuthRecordInfo().Disabled)
  2114. continue;
  2115. _zoneHistory.Add(deletedRecord);
  2116. if (deletedRecord.Type == DnsResourceRecordType.NS)
  2117. {
  2118. IReadOnlyList<DnsResourceRecord> glueRecords = deletedRecord.GetAuthRecordInfo().GlueRecords;
  2119. if (glueRecords is not null)
  2120. _zoneHistory.AddRange(glueRecords);
  2121. }
  2122. }
  2123. }
  2124. if (deletedRRSigRecords is not null)
  2125. _zoneHistory.AddRange(deletedRRSigRecords);
  2126. //write added
  2127. _zoneHistory.Add(newSoaRecord);
  2128. if (addedRecords is not null)
  2129. {
  2130. foreach (DnsResourceRecord addedRecord in addedRecords)
  2131. {
  2132. if (addedRecord.GetAuthRecordInfo().Disabled)
  2133. continue;
  2134. _zoneHistory.Add(addedRecord);
  2135. if (addedRecord.Type == DnsResourceRecordType.NS)
  2136. {
  2137. IReadOnlyList<DnsResourceRecord> glueRecords = addedRecord.GetAuthRecordInfo().GlueRecords;
  2138. if (glueRecords is not null)
  2139. _zoneHistory.AddRange(glueRecords);
  2140. }
  2141. }
  2142. }
  2143. if (newRRSigRecords is not null)
  2144. _zoneHistory.AddRange(newRRSigRecords);
  2145. //end commit
  2146. CleanupHistory(_zoneHistory);
  2147. }
  2148. }
  2149. #endregion
  2150. #region public
  2151. public override void SetRecords(DnsResourceRecordType type, IReadOnlyList<DnsResourceRecord> records)
  2152. {
  2153. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  2154. {
  2155. switch (type)
  2156. {
  2157. case DnsResourceRecordType.ANAME:
  2158. case DnsResourceRecordType.APP:
  2159. throw new DnsServerException("The record type is not supported by DNSSEC signed primary zones.");
  2160. default:
  2161. foreach (DnsResourceRecord record in records)
  2162. {
  2163. if (record.GetAuthRecordInfo().Disabled)
  2164. throw new DnsServerException("Cannot set records: disabling records in a signed zones is not supported.");
  2165. }
  2166. break;
  2167. }
  2168. }
  2169. switch (type)
  2170. {
  2171. case DnsResourceRecordType.CNAME:
  2172. case DnsResourceRecordType.DS:
  2173. throw new InvalidOperationException("Cannot set " + type.ToString() + " record at zone apex.");
  2174. case DnsResourceRecordType.SOA:
  2175. if ((records.Count != 1) || !records[0].Name.Equals(_name, StringComparison.OrdinalIgnoreCase))
  2176. throw new InvalidOperationException("Invalid SOA record.");
  2177. DnsResourceRecord newSoaRecord = records[0];
  2178. DnsSOARecordData newSoa = newSoaRecord.RDATA as DnsSOARecordData;
  2179. if (newSoaRecord.OriginalTtlValue > newSoa.Expire)
  2180. throw new DnsServerException("Failed to set records: TTL cannot be greater than SOA EXPIRE.");
  2181. if (newSoa.Retry > newSoa.Refresh)
  2182. throw new DnsServerException("Failed to set records: SOA RETRY cannot be greater than SOA REFRESH.");
  2183. if (newSoa.Refresh > newSoa.Expire)
  2184. throw new DnsServerException("Failed to set records: SOA REFRESH cannot be greater than SOA EXPIRE.");
  2185. //remove any record info except comments
  2186. string comments = newSoaRecord.GetAuthRecordInfo().Comments;
  2187. newSoaRecord.Tag = null; //remove old record info
  2188. newSoaRecord.GetAuthRecordInfo().Comments = comments;
  2189. uint oldSoaMinimum = GetZoneSoaMinimum();
  2190. //setting new SOA
  2191. CommitAndIncrementSerial(null, records);
  2192. if (oldSoaMinimum != newSoa.Minimum)
  2193. {
  2194. switch (_dnssecStatus)
  2195. {
  2196. case AuthZoneDnssecStatus.SignedWithNSEC:
  2197. RefreshNSec();
  2198. break;
  2199. case AuthZoneDnssecStatus.SignedWithNSEC3:
  2200. RefreshNSec3();
  2201. break;
  2202. }
  2203. }
  2204. TriggerNotify();
  2205. break;
  2206. case DnsResourceRecordType.DNSKEY:
  2207. case DnsResourceRecordType.RRSIG:
  2208. case DnsResourceRecordType.NSEC:
  2209. case DnsResourceRecordType.NSEC3PARAM:
  2210. case DnsResourceRecordType.NSEC3:
  2211. throw new InvalidOperationException("Cannot set DNSSEC records.");
  2212. case DnsResourceRecordType.FWD:
  2213. throw new DnsServerException("The record type is not supported by primary zones.");
  2214. default:
  2215. if (records[0].OriginalTtlValue > GetZoneSoaExpire())
  2216. throw new DnsServerException("Failed to set records: TTL cannot be greater than SOA EXPIRE.");
  2217. if (!TrySetRecords(type, records, out IReadOnlyList<DnsResourceRecord> deletedRecords))
  2218. throw new DnsServerException("Failed to set records. Please try again.");
  2219. CommitAndIncrementSerial(deletedRecords, records);
  2220. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  2221. UpdateDnssecRecordsFor(this, type);
  2222. TriggerNotify();
  2223. break;
  2224. }
  2225. }
  2226. public override void AddRecord(DnsResourceRecord record)
  2227. {
  2228. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  2229. {
  2230. switch (record.Type)
  2231. {
  2232. case DnsResourceRecordType.ANAME:
  2233. case DnsResourceRecordType.APP:
  2234. throw new DnsServerException("The record type is not supported by DNSSEC signed primary zones.");
  2235. default:
  2236. if (record.GetAuthRecordInfo().Disabled)
  2237. throw new DnsServerException("Cannot add record: disabling records in a signed zones is not supported.");
  2238. break;
  2239. }
  2240. }
  2241. switch (record.Type)
  2242. {
  2243. case DnsResourceRecordType.APP:
  2244. throw new InvalidOperationException("Cannot add record: use SetRecords() for " + record.Type.ToString() + " record");
  2245. case DnsResourceRecordType.DS:
  2246. throw new InvalidOperationException("Cannot set DS record at zone apex.");
  2247. case DnsResourceRecordType.DNSKEY:
  2248. case DnsResourceRecordType.RRSIG:
  2249. case DnsResourceRecordType.NSEC:
  2250. case DnsResourceRecordType.NSEC3PARAM:
  2251. case DnsResourceRecordType.NSEC3:
  2252. throw new InvalidOperationException("Cannot add DNSSEC record.");
  2253. case DnsResourceRecordType.FWD:
  2254. throw new DnsServerException("The record type is not supported by primary zones.");
  2255. default:
  2256. if (record.OriginalTtlValue > GetZoneSoaExpire())
  2257. throw new DnsServerException("Failed to add record: TTL cannot be greater than SOA EXPIRE.");
  2258. AddRecord(record, out IReadOnlyList<DnsResourceRecord> addedRecords, out IReadOnlyList<DnsResourceRecord> deletedRecords);
  2259. if (addedRecords.Count > 0)
  2260. {
  2261. CommitAndIncrementSerial(deletedRecords, addedRecords);
  2262. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  2263. UpdateDnssecRecordsFor(this, record.Type);
  2264. TriggerNotify();
  2265. }
  2266. break;
  2267. }
  2268. }
  2269. public override bool DeleteRecords(DnsResourceRecordType type)
  2270. {
  2271. switch (type)
  2272. {
  2273. case DnsResourceRecordType.SOA:
  2274. throw new InvalidOperationException("Cannot delete SOA record.");
  2275. case DnsResourceRecordType.DNSKEY:
  2276. case DnsResourceRecordType.RRSIG:
  2277. case DnsResourceRecordType.NSEC:
  2278. case DnsResourceRecordType.NSEC3PARAM:
  2279. case DnsResourceRecordType.NSEC3:
  2280. throw new InvalidOperationException("Cannot delete DNSSEC records.");
  2281. default:
  2282. if (_entries.TryRemove(type, out IReadOnlyList<DnsResourceRecord> removedRecords))
  2283. {
  2284. CommitAndIncrementSerial(removedRecords);
  2285. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  2286. UpdateDnssecRecordsFor(this, type);
  2287. TriggerNotify();
  2288. return true;
  2289. }
  2290. return false;
  2291. }
  2292. }
  2293. public override bool DeleteRecord(DnsResourceRecordType type, DnsResourceRecordData record)
  2294. {
  2295. switch (type)
  2296. {
  2297. case DnsResourceRecordType.SOA:
  2298. throw new InvalidOperationException("Cannot delete SOA record.");
  2299. case DnsResourceRecordType.DNSKEY:
  2300. case DnsResourceRecordType.RRSIG:
  2301. case DnsResourceRecordType.NSEC:
  2302. case DnsResourceRecordType.NSEC3PARAM:
  2303. case DnsResourceRecordType.NSEC3:
  2304. throw new InvalidOperationException("Cannot delete DNSSEC records.");
  2305. default:
  2306. if (TryDeleteRecord(type, record, out DnsResourceRecord deletedRecord))
  2307. {
  2308. CommitAndIncrementSerial(new DnsResourceRecord[] { deletedRecord });
  2309. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  2310. UpdateDnssecRecordsFor(this, type);
  2311. TriggerNotify();
  2312. return true;
  2313. }
  2314. return false;
  2315. }
  2316. }
  2317. public override void UpdateRecord(DnsResourceRecord oldRecord, DnsResourceRecord newRecord)
  2318. {
  2319. switch (oldRecord.Type)
  2320. {
  2321. case DnsResourceRecordType.SOA:
  2322. throw new InvalidOperationException("Cannot update record: use SetRecords() for " + oldRecord.Type.ToString() + " record");
  2323. case DnsResourceRecordType.DNSKEY:
  2324. case DnsResourceRecordType.RRSIG:
  2325. case DnsResourceRecordType.NSEC:
  2326. case DnsResourceRecordType.NSEC3PARAM:
  2327. case DnsResourceRecordType.NSEC3:
  2328. throw new InvalidOperationException("Cannot update DNSSEC records.");
  2329. default:
  2330. if (oldRecord.Type != newRecord.Type)
  2331. throw new InvalidOperationException("Old and new record types do not match.");
  2332. if ((_dnssecStatus != AuthZoneDnssecStatus.Unsigned) && newRecord.GetAuthRecordInfo().Disabled)
  2333. throw new DnsServerException("Cannot update record: disabling records in a signed zones is not supported.");
  2334. if (newRecord.OriginalTtlValue > GetZoneSoaExpire())
  2335. throw new DnsServerException("Cannot update record: TTL cannot be greater than SOA EXPIRE.");
  2336. if (!TryDeleteRecord(oldRecord.Type, oldRecord.RDATA, out DnsResourceRecord deletedRecord))
  2337. throw new InvalidOperationException("Cannot update record: the record does not exists to be updated.");
  2338. AddRecord(newRecord, out IReadOnlyList<DnsResourceRecord> addedRecords, out IReadOnlyList<DnsResourceRecord> deletedRecords);
  2339. List<DnsResourceRecord> allDeletedRecords = new List<DnsResourceRecord>(deletedRecords.Count + 1);
  2340. allDeletedRecords.Add(deletedRecord);
  2341. allDeletedRecords.AddRange(deletedRecords);
  2342. CommitAndIncrementSerial(allDeletedRecords, addedRecords);
  2343. if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
  2344. UpdateDnssecRecordsFor(this, oldRecord.Type);
  2345. TriggerNotify();
  2346. break;
  2347. }
  2348. }
  2349. #endregion
  2350. #region properties
  2351. public bool Internal
  2352. { get { return _internal; } }
  2353. public override bool Disabled
  2354. {
  2355. get { return _disabled; }
  2356. set
  2357. {
  2358. if (_disabled != value)
  2359. {
  2360. _disabled = value;
  2361. if (_disabled)
  2362. DisableNotifyTimer();
  2363. else
  2364. TriggerNotify();
  2365. }
  2366. }
  2367. }
  2368. public override AuthZoneTransfer ZoneTransfer
  2369. {
  2370. get { return _zoneTransfer; }
  2371. set
  2372. {
  2373. if (_internal)
  2374. throw new InvalidOperationException();
  2375. base.ZoneTransfer = value;
  2376. }
  2377. }
  2378. public override AuthZoneNotify Notify
  2379. {
  2380. get { return _notify; }
  2381. set
  2382. {
  2383. if (_internal)
  2384. throw new InvalidOperationException();
  2385. base.Notify = value;
  2386. }
  2387. }
  2388. public override AuthZoneUpdate Update
  2389. {
  2390. get { return _update; }
  2391. set
  2392. {
  2393. if (_internal)
  2394. throw new InvalidOperationException();
  2395. base.Update = value;
  2396. }
  2397. }
  2398. public IReadOnlyCollection<DnssecPrivateKey> DnssecPrivateKeys
  2399. {
  2400. get
  2401. {
  2402. if (_dnssecPrivateKeys is null)
  2403. return null;
  2404. lock (_dnssecPrivateKeys)
  2405. {
  2406. return _dnssecPrivateKeys.Values;
  2407. }
  2408. }
  2409. }
  2410. #endregion
  2411. }
  2412. }