WebServiceZonesApi.cs 225 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452
  1. /*
  2. Technitium DNS Server
  3. Copyright (C) 2024 Shreyas Zare (shreyas@technitium.com)
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. using DnsServerCore.Auth;
  16. using DnsServerCore.Dns.Dnssec;
  17. using DnsServerCore.Dns.ResourceRecords;
  18. using DnsServerCore.Dns.Zones;
  19. using Microsoft.AspNetCore.Http;
  20. using System;
  21. using System.Collections.Generic;
  22. using System.IO;
  23. using System.Net;
  24. using System.Text;
  25. using System.Text.Json;
  26. using System.Threading.Tasks;
  27. using TechnitiumLibrary;
  28. using TechnitiumLibrary.Net;
  29. using TechnitiumLibrary.Net.Dns;
  30. using TechnitiumLibrary.Net.Dns.ResourceRecords;
  31. namespace DnsServerCore
  32. {
  33. class WebServiceZonesApi
  34. {
  35. #region variables
  36. static readonly char[] _commaSeparator = new char[] { ',' };
  37. static readonly char[] _pipeSeparator = new char[] { '|' };
  38. static readonly char[] _commaSpaceSeparator = new char[] { ',', ' ' };
  39. static readonly char[] _newLineSeparator = new char[] { '\r', '\n' };
  40. readonly DnsWebService _dnsWebService;
  41. uint _defaultRecordTtl = 3600;
  42. #endregion
  43. #region constructor
  44. public WebServiceZonesApi(DnsWebService dnsWebService)
  45. {
  46. _dnsWebService = dnsWebService;
  47. }
  48. #endregion
  49. #region static
  50. public static void WriteRecordsAsJson(List<DnsResourceRecord> records, Utf8JsonWriter jsonWriter, bool authoritativeZoneRecords, AuthZoneInfo zoneInfo = null)
  51. {
  52. if (records is null)
  53. {
  54. jsonWriter.WritePropertyName("records");
  55. jsonWriter.WriteStartArray();
  56. jsonWriter.WriteEndArray();
  57. return;
  58. }
  59. records.Sort();
  60. Dictionary<string, Dictionary<DnsResourceRecordType, List<DnsResourceRecord>>> groupedByDomainRecords = DnsResourceRecord.GroupRecords(records);
  61. jsonWriter.WritePropertyName("records");
  62. jsonWriter.WriteStartArray();
  63. foreach (KeyValuePair<string, Dictionary<DnsResourceRecordType, List<DnsResourceRecord>>> groupedByTypeRecords in groupedByDomainRecords)
  64. {
  65. foreach (KeyValuePair<DnsResourceRecordType, List<DnsResourceRecord>> groupedRecords in groupedByTypeRecords.Value)
  66. {
  67. foreach (DnsResourceRecord record in groupedRecords.Value)
  68. WriteRecordAsJson(record, jsonWriter, authoritativeZoneRecords, zoneInfo);
  69. }
  70. }
  71. jsonWriter.WriteEndArray();
  72. }
  73. #endregion
  74. #region private
  75. private static void WriteRecordAsJson(DnsResourceRecord record, Utf8JsonWriter jsonWriter, bool authoritativeZoneRecords, AuthZoneInfo zoneInfo = null)
  76. {
  77. jsonWriter.WriteStartObject();
  78. jsonWriter.WriteString("name", record.Name);
  79. if (DnsClient.TryConvertDomainNameToUnicode(record.Name, out string idn))
  80. jsonWriter.WriteString("nameIdn", idn);
  81. jsonWriter.WriteString("type", record.Type.ToString());
  82. if (authoritativeZoneRecords)
  83. {
  84. GenericRecordInfo authRecordInfo = record.GetAuthGenericRecordInfo();
  85. jsonWriter.WriteNumber("ttl", record.TTL);
  86. jsonWriter.WriteBoolean("disabled", authRecordInfo.Disabled);
  87. string comments = authRecordInfo.Comments;
  88. if (!string.IsNullOrEmpty(comments))
  89. jsonWriter.WriteString("comments", comments);
  90. }
  91. else
  92. {
  93. if (record.IsStale)
  94. jsonWriter.WriteString("ttl", "0 (0 sec)");
  95. else
  96. jsonWriter.WriteString("ttl", record.TTL + " (" + WebUtilities.GetFormattedTime((int)record.TTL) + ")");
  97. }
  98. jsonWriter.WritePropertyName("rData");
  99. jsonWriter.WriteStartObject();
  100. switch (record.Type)
  101. {
  102. case DnsResourceRecordType.A:
  103. {
  104. if (record.RDATA is DnsARecordData rdata)
  105. {
  106. jsonWriter.WriteString("ipAddress", rdata.Address.ToString());
  107. }
  108. else
  109. {
  110. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  111. jsonWriter.WriteString("data", record.RDATA.ToString());
  112. }
  113. }
  114. break;
  115. case DnsResourceRecordType.NS:
  116. {
  117. if (record.RDATA is DnsNSRecordData rdata)
  118. {
  119. jsonWriter.WriteString("nameServer", rdata.NameServer.Length == 0 ? "." : rdata.NameServer);
  120. if (DnsClient.TryConvertDomainNameToUnicode(rdata.NameServer, out string nameServerIdn))
  121. jsonWriter.WriteString("nameServerIdn", nameServerIdn);
  122. if (!authoritativeZoneRecords)
  123. {
  124. if (rdata.IsParentSideTtlSet)
  125. jsonWriter.WriteString("parentSideTtl", rdata.ParentSideTtl + " (" + WebUtilities.GetFormattedTime((int)rdata.ParentSideTtl) + ")");
  126. }
  127. }
  128. else
  129. {
  130. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  131. jsonWriter.WriteString("data", record.RDATA.ToString());
  132. }
  133. }
  134. break;
  135. case DnsResourceRecordType.CNAME:
  136. {
  137. if (record.RDATA is DnsCNAMERecordData rdata)
  138. {
  139. jsonWriter.WriteString("cname", rdata.Domain.Length == 0 ? "." : rdata.Domain);
  140. if (DnsClient.TryConvertDomainNameToUnicode(rdata.Domain, out string cnameIdn))
  141. jsonWriter.WriteString("cnameIdn", cnameIdn);
  142. }
  143. else
  144. {
  145. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  146. jsonWriter.WriteString("data", record.RDATA.ToString());
  147. }
  148. }
  149. break;
  150. case DnsResourceRecordType.SOA:
  151. {
  152. if (record.RDATA is DnsSOARecordData rdata)
  153. {
  154. jsonWriter.WriteString("primaryNameServer", rdata.PrimaryNameServer);
  155. if (DnsClient.TryConvertDomainNameToUnicode(rdata.PrimaryNameServer, out string primaryNameServerIdn))
  156. jsonWriter.WriteString("primaryNameServerIdn", primaryNameServerIdn);
  157. jsonWriter.WriteString("responsiblePerson", rdata.ResponsiblePerson);
  158. jsonWriter.WriteNumber("serial", rdata.Serial);
  159. jsonWriter.WriteNumber("refresh", rdata.Refresh);
  160. jsonWriter.WriteNumber("retry", rdata.Retry);
  161. jsonWriter.WriteNumber("expire", rdata.Expire);
  162. jsonWriter.WriteNumber("minimum", rdata.Minimum);
  163. }
  164. else
  165. {
  166. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  167. jsonWriter.WriteString("data", record.RDATA.ToString());
  168. }
  169. if (authoritativeZoneRecords && (zoneInfo is not null))
  170. {
  171. switch (zoneInfo.Type)
  172. {
  173. case AuthZoneType.Primary:
  174. case AuthZoneType.Forwarder:
  175. case AuthZoneType.Catalog:
  176. jsonWriter.WriteBoolean("useSerialDateScheme", record.GetAuthSOARecordInfo().UseSoaSerialDateScheme);
  177. break;
  178. }
  179. }
  180. }
  181. break;
  182. case DnsResourceRecordType.PTR:
  183. {
  184. if (record.RDATA is DnsPTRRecordData rdata)
  185. {
  186. jsonWriter.WriteString("ptrName", rdata.Domain.Length == 0 ? "." : rdata.Domain);
  187. if (DnsClient.TryConvertDomainNameToUnicode(rdata.Domain, out string ptrNameIdn))
  188. jsonWriter.WriteString("ptrNameIdn", ptrNameIdn);
  189. }
  190. else
  191. {
  192. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  193. jsonWriter.WriteString("data", record.RDATA.ToString());
  194. }
  195. }
  196. break;
  197. case DnsResourceRecordType.MX:
  198. {
  199. if (record.RDATA is DnsMXRecordData rdata)
  200. {
  201. jsonWriter.WriteNumber("preference", rdata.Preference);
  202. jsonWriter.WriteString("exchange", rdata.Exchange.Length == 0 ? "." : rdata.Exchange);
  203. if (DnsClient.TryConvertDomainNameToUnicode(rdata.Exchange, out string exchangeIdn))
  204. jsonWriter.WriteString("exchangeIdn", exchangeIdn);
  205. }
  206. else
  207. {
  208. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  209. jsonWriter.WriteString("data", record.RDATA.ToString());
  210. }
  211. }
  212. break;
  213. case DnsResourceRecordType.TXT:
  214. {
  215. if (record.RDATA is DnsTXTRecordData rdata)
  216. {
  217. jsonWriter.WriteString("text", rdata.GetText());
  218. jsonWriter.WriteBoolean("splitText", rdata.CharacterStrings.Count > 1);
  219. jsonWriter.WriteStartArray("characterStrings");
  220. foreach (string characterString in rdata.CharacterStrings)
  221. jsonWriter.WriteStringValue(characterString);
  222. jsonWriter.WriteEndArray();
  223. }
  224. else
  225. {
  226. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  227. jsonWriter.WriteString("data", record.RDATA.ToString());
  228. }
  229. }
  230. break;
  231. case DnsResourceRecordType.RP:
  232. {
  233. if (record.RDATA is DnsRPRecordData rdata)
  234. {
  235. jsonWriter.WriteString("mailbox", rdata.Mailbox);
  236. jsonWriter.WriteString("txtDomain", rdata.TxtDomain);
  237. if (DnsClient.TryConvertDomainNameToUnicode(rdata.Mailbox, out string txtDomainIdn))
  238. jsonWriter.WriteString("txtDomainIdn", txtDomainIdn);
  239. }
  240. else
  241. {
  242. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  243. jsonWriter.WriteString("data", record.RDATA.ToString());
  244. }
  245. }
  246. break;
  247. case DnsResourceRecordType.AAAA:
  248. {
  249. if (record.RDATA is DnsAAAARecordData rdata)
  250. {
  251. jsonWriter.WriteString("ipAddress", rdata.Address.ToString());
  252. }
  253. else
  254. {
  255. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  256. jsonWriter.WriteString("data", record.RDATA.ToString());
  257. }
  258. }
  259. break;
  260. case DnsResourceRecordType.SRV:
  261. {
  262. if (record.RDATA is DnsSRVRecordData rdata)
  263. {
  264. jsonWriter.WriteNumber("priority", rdata.Priority);
  265. jsonWriter.WriteNumber("weight", rdata.Weight);
  266. jsonWriter.WriteNumber("port", rdata.Port);
  267. jsonWriter.WriteString("target", rdata.Target.Length == 0 ? "." : rdata.Target);
  268. if (DnsClient.TryConvertDomainNameToUnicode(rdata.Target, out string targetIdn))
  269. jsonWriter.WriteString("targetIdn", targetIdn);
  270. }
  271. else
  272. {
  273. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  274. jsonWriter.WriteString("data", record.RDATA.ToString());
  275. }
  276. }
  277. break;
  278. case DnsResourceRecordType.NAPTR:
  279. {
  280. if (record.RDATA is DnsNAPTRRecordData rdata)
  281. {
  282. jsonWriter.WriteNumber("order", rdata.Order);
  283. jsonWriter.WriteNumber("preference", rdata.Preference);
  284. jsonWriter.WriteString("flags", rdata.Flags);
  285. jsonWriter.WriteString("services", rdata.Services);
  286. jsonWriter.WriteString("regexp", rdata.Regexp);
  287. jsonWriter.WriteString("replacement", rdata.Replacement.Length == 0 ? "." : rdata.Replacement);
  288. if (DnsClient.TryConvertDomainNameToUnicode(rdata.Replacement, out string replacementIdn))
  289. jsonWriter.WriteString("replacementIdn", replacementIdn);
  290. }
  291. else
  292. {
  293. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  294. jsonWriter.WriteString("data", record.RDATA.ToString());
  295. }
  296. }
  297. break;
  298. case DnsResourceRecordType.DNAME:
  299. {
  300. if (record.RDATA is DnsDNAMERecordData rdata)
  301. {
  302. jsonWriter.WriteString("dname", rdata.Domain.Length == 0 ? "." : rdata.Domain);
  303. if (DnsClient.TryConvertDomainNameToUnicode(rdata.Domain, out string dnameIdn))
  304. jsonWriter.WriteString("dnameIdn", dnameIdn);
  305. }
  306. else
  307. {
  308. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  309. jsonWriter.WriteString("data", record.RDATA.ToString());
  310. }
  311. }
  312. break;
  313. case DnsResourceRecordType.APL:
  314. {
  315. if (record.RDATA is DnsAPLRecordData rdata)
  316. {
  317. jsonWriter.WriteStartArray("addressPrefixes");
  318. foreach (DnsAPLRecordData.APItem apItem in rdata.APItems)
  319. {
  320. jsonWriter.WriteStartObject();
  321. jsonWriter.WriteString("addressFamily", apItem.AddressFamily.ToString());
  322. jsonWriter.WriteNumber("prefix", apItem.Prefix);
  323. jsonWriter.WriteBoolean("negation", apItem.Negation);
  324. jsonWriter.WriteString("afdPart", apItem.NetworkAddress.Address.ToString());
  325. jsonWriter.WriteEndObject();
  326. }
  327. jsonWriter.WriteEndArray();
  328. }
  329. else
  330. {
  331. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  332. jsonWriter.WriteString("data", record.RDATA.ToString());
  333. }
  334. }
  335. break;
  336. case DnsResourceRecordType.DS:
  337. {
  338. if (record.RDATA is DnsDSRecordData rdata)
  339. {
  340. jsonWriter.WriteNumber("keyTag", rdata.KeyTag);
  341. jsonWriter.WriteString("algorithm", rdata.Algorithm.ToString());
  342. jsonWriter.WriteString("digestType", rdata.DigestType.ToString());
  343. jsonWriter.WriteString("digest", Convert.ToHexString(rdata.Digest));
  344. }
  345. else
  346. {
  347. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  348. jsonWriter.WriteString("data", record.RDATA.ToString());
  349. }
  350. }
  351. break;
  352. case DnsResourceRecordType.SSHFP:
  353. {
  354. if (record.RDATA is DnsSSHFPRecordData rdata)
  355. {
  356. jsonWriter.WriteString("algorithm", rdata.Algorithm.ToString());
  357. jsonWriter.WriteString("fingerprintType", rdata.FingerprintType.ToString());
  358. jsonWriter.WriteString("fingerprint", Convert.ToHexString(rdata.Fingerprint));
  359. }
  360. else
  361. {
  362. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  363. jsonWriter.WriteString("data", record.RDATA.ToString());
  364. }
  365. }
  366. break;
  367. case DnsResourceRecordType.RRSIG:
  368. {
  369. if (record.RDATA is DnsRRSIGRecordData rdata)
  370. {
  371. jsonWriter.WriteString("typeCovered", rdata.TypeCovered.ToString());
  372. jsonWriter.WriteString("algorithm", rdata.Algorithm.ToString());
  373. jsonWriter.WriteNumber("labels", rdata.Labels);
  374. jsonWriter.WriteNumber("originalTtl", rdata.OriginalTtl);
  375. jsonWriter.WriteString("signatureExpiration", DateTime.UnixEpoch.AddSeconds(rdata.SignatureExpiration));
  376. jsonWriter.WriteString("signatureInception", DateTime.UnixEpoch.AddSeconds(rdata.SignatureInception));
  377. jsonWriter.WriteNumber("keyTag", rdata.KeyTag);
  378. jsonWriter.WriteString("signersName", rdata.SignersName.Length == 0 ? "." : rdata.SignersName);
  379. jsonWriter.WriteString("signature", Convert.ToBase64String(rdata.Signature));
  380. }
  381. else
  382. {
  383. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  384. jsonWriter.WriteString("data", record.RDATA.ToString());
  385. }
  386. }
  387. break;
  388. case DnsResourceRecordType.NSEC:
  389. {
  390. if (record.RDATA is DnsNSECRecordData rdata)
  391. {
  392. jsonWriter.WriteString("nextDomainName", rdata.NextDomainName);
  393. jsonWriter.WritePropertyName("types");
  394. jsonWriter.WriteStartArray();
  395. foreach (DnsResourceRecordType type in rdata.Types)
  396. jsonWriter.WriteStringValue(type.ToString());
  397. jsonWriter.WriteEndArray();
  398. }
  399. else
  400. {
  401. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  402. jsonWriter.WriteString("data", record.RDATA.ToString());
  403. }
  404. }
  405. break;
  406. case DnsResourceRecordType.DNSKEY:
  407. {
  408. if (record.RDATA is DnsDNSKEYRecordData rdata)
  409. {
  410. jsonWriter.WriteString("flags", rdata.Flags.ToString());
  411. jsonWriter.WriteNumber("protocol", rdata.Protocol);
  412. jsonWriter.WriteString("algorithm", rdata.Algorithm.ToString());
  413. jsonWriter.WriteString("publicKey", rdata.PublicKey.ToString());
  414. jsonWriter.WriteNumber("computedKeyTag", rdata.ComputedKeyTag);
  415. if (authoritativeZoneRecords)
  416. {
  417. if ((zoneInfo is not null) && (zoneInfo.Type == AuthZoneType.Primary))
  418. {
  419. IReadOnlyCollection<DnssecPrivateKey> dnssecPrivateKeys = zoneInfo.DnssecPrivateKeys;
  420. if (dnssecPrivateKeys is not null)
  421. {
  422. foreach (DnssecPrivateKey dnssecPrivateKey in dnssecPrivateKeys)
  423. {
  424. if (dnssecPrivateKey.KeyTag == rdata.ComputedKeyTag)
  425. {
  426. jsonWriter.WriteString("dnsKeyState", dnssecPrivateKey.State.ToString());
  427. if ((dnssecPrivateKey.KeyType == DnssecPrivateKeyType.KeySigningKey) && (dnssecPrivateKey.State == DnssecPrivateKeyState.Published))
  428. jsonWriter.WriteString("dnsKeyStateReadyBy", (zoneInfo.ApexZone as PrimaryZone).GetKskDnsKeyStateReadyBy(dnssecPrivateKey));
  429. break;
  430. }
  431. }
  432. }
  433. }
  434. if (rdata.Flags.HasFlag(DnsDnsKeyFlag.SecureEntryPoint))
  435. {
  436. jsonWriter.WritePropertyName("computedDigests");
  437. jsonWriter.WriteStartArray();
  438. {
  439. jsonWriter.WriteStartObject();
  440. jsonWriter.WriteString("digestType", "SHA256");
  441. jsonWriter.WriteString("digest", Convert.ToHexString(rdata.CreateDS(record.Name, DnssecDigestType.SHA256).Digest));
  442. jsonWriter.WriteEndObject();
  443. }
  444. {
  445. jsonWriter.WriteStartObject();
  446. jsonWriter.WriteString("digestType", "SHA384");
  447. jsonWriter.WriteString("digest", Convert.ToHexString(rdata.CreateDS(record.Name, DnssecDigestType.SHA384).Digest));
  448. jsonWriter.WriteEndObject();
  449. }
  450. jsonWriter.WriteEndArray();
  451. }
  452. }
  453. }
  454. else
  455. {
  456. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  457. jsonWriter.WriteString("data", record.RDATA.ToString());
  458. }
  459. }
  460. break;
  461. case DnsResourceRecordType.NSEC3:
  462. {
  463. if (record.RDATA is DnsNSEC3RecordData rdata)
  464. {
  465. jsonWriter.WriteString("hashAlgorithm", rdata.HashAlgorithm.ToString());
  466. jsonWriter.WriteString("flags", rdata.Flags.ToString());
  467. jsonWriter.WriteNumber("iterations", rdata.Iterations);
  468. jsonWriter.WriteString("salt", Convert.ToHexString(rdata.Salt));
  469. jsonWriter.WriteString("nextHashedOwnerName", rdata.NextHashedOwnerName);
  470. jsonWriter.WritePropertyName("types");
  471. jsonWriter.WriteStartArray();
  472. foreach (DnsResourceRecordType type in rdata.Types)
  473. jsonWriter.WriteStringValue(type.ToString());
  474. jsonWriter.WriteEndArray();
  475. }
  476. else
  477. {
  478. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  479. jsonWriter.WriteString("data", record.RDATA.ToString());
  480. }
  481. }
  482. break;
  483. case DnsResourceRecordType.NSEC3PARAM:
  484. {
  485. if (record.RDATA is DnsNSEC3PARAMRecordData rdata)
  486. {
  487. jsonWriter.WriteString("hashAlgorithm", rdata.HashAlgorithm.ToString());
  488. jsonWriter.WriteString("flags", rdata.Flags.ToString());
  489. jsonWriter.WriteNumber("iterations", rdata.Iterations);
  490. jsonWriter.WriteString("salt", Convert.ToHexString(rdata.Salt));
  491. }
  492. else
  493. {
  494. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  495. jsonWriter.WriteString("data", record.RDATA.ToString());
  496. }
  497. }
  498. break;
  499. case DnsResourceRecordType.TLSA:
  500. {
  501. if (record.RDATA is DnsTLSARecordData rdata)
  502. {
  503. jsonWriter.WriteString("certificateUsage", rdata.CertificateUsage.ToString().Replace('_', '-'));
  504. jsonWriter.WriteString("selector", rdata.Selector.ToString());
  505. jsonWriter.WriteString("matchingType", rdata.MatchingType.ToString().Replace('_', '-'));
  506. jsonWriter.WriteString("certificateAssociationData", Convert.ToHexString(rdata.CertificateAssociationData));
  507. }
  508. else
  509. {
  510. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  511. jsonWriter.WriteString("data", record.RDATA.ToString());
  512. }
  513. }
  514. break;
  515. case DnsResourceRecordType.ZONEMD:
  516. {
  517. if (record.RDATA is DnsZONEMDRecordData rdata)
  518. {
  519. jsonWriter.WriteNumber("serial", rdata.Serial);
  520. jsonWriter.WriteString("scheme", rdata.Scheme.ToString());
  521. jsonWriter.WriteString("hashAlgorithm", rdata.HashAlgorithm.ToString());
  522. jsonWriter.WriteString("digest", Convert.ToHexString(rdata.Digest));
  523. }
  524. else
  525. {
  526. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  527. jsonWriter.WriteString("data", record.RDATA.ToString());
  528. }
  529. }
  530. break;
  531. case DnsResourceRecordType.SVCB:
  532. case DnsResourceRecordType.HTTPS:
  533. {
  534. if (record.RDATA is DnsSVCBRecordData rdata)
  535. {
  536. jsonWriter.WriteNumber("svcPriority", rdata.SvcPriority);
  537. jsonWriter.WriteString("svcTargetName", rdata.TargetName);
  538. jsonWriter.WritePropertyName("svcParams");
  539. jsonWriter.WriteStartObject();
  540. foreach (KeyValuePair<DnsSvcParamKey, DnsSvcParamValue> svcParam in rdata.SvcParams)
  541. jsonWriter.WriteString(svcParam.Key.ToString().ToLowerInvariant().Replace('_', '-'), svcParam.Value.ToString());
  542. jsonWriter.WriteEndObject();
  543. if (authoritativeZoneRecords)
  544. {
  545. SVCBRecordInfo rrInfo = record.GetAuthSVCBRecordInfo();
  546. jsonWriter.WriteBoolean("autoIpv4Hint", rrInfo.AutoIpv4Hint);
  547. jsonWriter.WriteBoolean("autoIpv6Hint", rrInfo.AutoIpv6Hint);
  548. }
  549. }
  550. else
  551. {
  552. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  553. jsonWriter.WriteString("data", record.RDATA.ToString());
  554. }
  555. }
  556. break;
  557. case DnsResourceRecordType.URI:
  558. {
  559. if (record.RDATA is DnsURIRecordData rdata)
  560. {
  561. jsonWriter.WriteNumber("priority", rdata.Priority);
  562. jsonWriter.WriteNumber("weight", rdata.Weight);
  563. jsonWriter.WriteString("uri", rdata.Uri.AbsoluteUri);
  564. }
  565. else
  566. {
  567. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  568. jsonWriter.WriteString("data", record.RDATA.ToString());
  569. }
  570. }
  571. break;
  572. case DnsResourceRecordType.CAA:
  573. {
  574. if (record.RDATA is DnsCAARecordData rdata)
  575. {
  576. jsonWriter.WriteNumber("flags", rdata.Flags);
  577. jsonWriter.WriteString("tag", rdata.Tag);
  578. jsonWriter.WriteString("value", rdata.Value);
  579. }
  580. else
  581. {
  582. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  583. jsonWriter.WriteString("data", record.RDATA.ToString());
  584. }
  585. }
  586. break;
  587. case DnsResourceRecordType.ANAME:
  588. {
  589. if (record.RDATA is DnsANAMERecordData rdata)
  590. {
  591. jsonWriter.WriteString("aname", rdata.Domain.Length == 0 ? "." : rdata.Domain);
  592. if (DnsClient.TryConvertDomainNameToUnicode(rdata.Domain, out string anameIdn))
  593. jsonWriter.WriteString("anameIdn", anameIdn);
  594. }
  595. else
  596. {
  597. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  598. jsonWriter.WriteString("data", record.RDATA.ToString());
  599. }
  600. }
  601. break;
  602. case DnsResourceRecordType.FWD:
  603. {
  604. if (record.RDATA is DnsForwarderRecordData rdata)
  605. {
  606. jsonWriter.WriteString("protocol", rdata.Protocol.ToString());
  607. jsonWriter.WriteString("forwarder", rdata.Forwarder);
  608. jsonWriter.WriteNumber("priority", rdata.Priority);
  609. jsonWriter.WriteBoolean("dnssecValidation", rdata.DnssecValidation);
  610. jsonWriter.WriteString("proxyType", rdata.ProxyType.ToString());
  611. switch (rdata.ProxyType)
  612. {
  613. case DnsForwarderRecordProxyType.Http:
  614. case DnsForwarderRecordProxyType.Socks5:
  615. jsonWriter.WriteString("proxyAddress", rdata.ProxyAddress);
  616. jsonWriter.WriteNumber("proxyPort", rdata.ProxyPort);
  617. jsonWriter.WriteString("proxyUsername", rdata.ProxyUsername);
  618. jsonWriter.WriteString("proxyPassword", rdata.ProxyPassword);
  619. break;
  620. }
  621. }
  622. }
  623. break;
  624. case DnsResourceRecordType.APP:
  625. {
  626. if (record.RDATA is DnsApplicationRecordData rdata)
  627. {
  628. jsonWriter.WriteString("appName", rdata.AppName);
  629. jsonWriter.WriteString("classPath", rdata.ClassPath);
  630. jsonWriter.WriteString("data", rdata.Data);
  631. }
  632. }
  633. break;
  634. case DnsResourceRecordType.ALIAS:
  635. {
  636. if (record.RDATA is DnsALIASRecordData rdata)
  637. {
  638. jsonWriter.WriteString("type", rdata.Type.ToString());
  639. jsonWriter.WriteString("alias", rdata.Domain.Length == 0 ? "." : rdata.Domain);
  640. if (DnsClient.TryConvertDomainNameToUnicode(rdata.Domain, out string aliasIdn))
  641. jsonWriter.WriteString("aliasIdn", aliasIdn);
  642. }
  643. else
  644. {
  645. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  646. jsonWriter.WriteString("data", record.RDATA.ToString());
  647. }
  648. }
  649. break;
  650. default:
  651. {
  652. if (record.RDATA is DnsUnknownRecordData rdata)
  653. {
  654. jsonWriter.WriteString("value", BitConverter.ToString(rdata.DATA).Replace('-', ':'));
  655. }
  656. else
  657. {
  658. jsonWriter.WriteString("dataType", record.RDATA.GetType().Name);
  659. jsonWriter.WriteString("data", record.RDATA.ToString());
  660. }
  661. }
  662. break;
  663. }
  664. jsonWriter.WriteEndObject();
  665. jsonWriter.WriteString("dnssecStatus", record.DnssecStatus.ToString());
  666. if (authoritativeZoneRecords)
  667. {
  668. GenericRecordInfo authRecordInfo = record.GetAuthGenericRecordInfo();
  669. if (authRecordInfo is NSRecordInfo nsRecordInfo)
  670. {
  671. IReadOnlyList<DnsResourceRecord> glueRecords = nsRecordInfo.GlueRecords;
  672. if (glueRecords is not null)
  673. {
  674. jsonWriter.WritePropertyName("glueRecords");
  675. jsonWriter.WriteStartArray();
  676. foreach (DnsResourceRecord glueRecord in glueRecords)
  677. jsonWriter.WriteStringValue(glueRecord.RDATA.ToString());
  678. jsonWriter.WriteEndArray();
  679. }
  680. }
  681. jsonWriter.WriteString("lastUsedOn", authRecordInfo.LastUsedOn);
  682. jsonWriter.WriteString("lastModified", authRecordInfo.LastModified);
  683. jsonWriter.WriteNumber("expiryTtl", authRecordInfo.ExpiryTtl);
  684. }
  685. else
  686. {
  687. CacheRecordInfo cacheRecordInfo = record.GetCacheRecordInfo();
  688. IReadOnlyList<DnsResourceRecord> glueRecords = cacheRecordInfo.GlueRecords;
  689. if (glueRecords is not null)
  690. {
  691. jsonWriter.WritePropertyName("glueRecords");
  692. jsonWriter.WriteStartArray();
  693. foreach (DnsResourceRecord glueRecord in glueRecords)
  694. jsonWriter.WriteStringValue(glueRecord.RDATA.ToString());
  695. jsonWriter.WriteEndArray();
  696. }
  697. IReadOnlyList<DnsResourceRecord> rrsigRecords = cacheRecordInfo.RRSIGRecords;
  698. IReadOnlyList<DnsResourceRecord> nsecRecords = cacheRecordInfo.NSECRecords;
  699. if ((rrsigRecords is not null) || (nsecRecords is not null))
  700. {
  701. jsonWriter.WritePropertyName("dnssecRecords");
  702. jsonWriter.WriteStartArray();
  703. if (rrsigRecords is not null)
  704. {
  705. foreach (DnsResourceRecord rrsigRecord in rrsigRecords)
  706. jsonWriter.WriteStringValue(rrsigRecord.ToString());
  707. }
  708. if (nsecRecords is not null)
  709. {
  710. foreach (DnsResourceRecord nsecRecord in nsecRecords)
  711. jsonWriter.WriteStringValue(nsecRecord.ToString());
  712. }
  713. jsonWriter.WriteEndArray();
  714. }
  715. NetworkAddress eDnsClientSubnet = cacheRecordInfo.EDnsClientSubnet;
  716. if (eDnsClientSubnet is not null)
  717. jsonWriter.WriteString("eDnsClientSubnet", eDnsClientSubnet.ToString());
  718. if (record.RDATA is DnsNSRecordData nsRData)
  719. {
  720. NameServerMetadata metadata = nsRData.Metadata;
  721. jsonWriter.WriteStartObject("nameServerMetadata");
  722. jsonWriter.WriteNumber("totalQueries", metadata.TotalQueries);
  723. jsonWriter.WriteString("answerRate", Math.Round(metadata.GetAnswerRate(), 2) + "%");
  724. jsonWriter.WriteString("smoothedRoundTripTime", Math.Round(metadata.SRTT, 2) + " ms");
  725. jsonWriter.WriteString("smoothedPenaltyRoundTripTime", Math.Round(metadata.SPRTT, 2) + " ms");
  726. jsonWriter.WriteString("netRoundTripTime", Math.Round(metadata.GetNetRTT(), 2) + " ms");
  727. jsonWriter.WriteEndObject();
  728. }
  729. DnsDatagramMetadata responseMetadata = cacheRecordInfo.ResponseMetadata;
  730. if (responseMetadata is not null)
  731. {
  732. jsonWriter.WritePropertyName("responseMetadata");
  733. jsonWriter.WriteStartObject();
  734. jsonWriter.WriteString("nameServer", responseMetadata.NameServer?.ToString());
  735. jsonWriter.WriteString("protocol", (responseMetadata.NameServer is null ? DnsTransportProtocol.Udp : responseMetadata.NameServer.Protocol).ToString());
  736. jsonWriter.WriteString("datagramSize", responseMetadata.DatagramSize + " bytes");
  737. jsonWriter.WriteString("roundTripTime", Math.Round(responseMetadata.RoundTripTime, 2) + " ms");
  738. jsonWriter.WriteEndObject();
  739. }
  740. jsonWriter.WriteString("lastUsedOn", cacheRecordInfo.LastUsedOn);
  741. }
  742. jsonWriter.WriteEndObject();
  743. }
  744. private static void WriteZoneInfoAsJson(AuthZoneInfo zoneInfo, Utf8JsonWriter jsonWriter)
  745. {
  746. jsonWriter.WriteStartObject();
  747. jsonWriter.WriteString("name", zoneInfo.Name);
  748. if (DnsClient.TryConvertDomainNameToUnicode(zoneInfo.Name, out string nameIdn))
  749. jsonWriter.WriteString("nameIdn", nameIdn);
  750. jsonWriter.WriteString("type", zoneInfo.Type.ToString());
  751. jsonWriter.WriteString("lastModified", zoneInfo.LastModified);
  752. jsonWriter.WriteBoolean("disabled", zoneInfo.Disabled);
  753. jsonWriter.WriteNumber("soaSerial", zoneInfo.ApexZone.GetZoneSoaSerial());
  754. switch (zoneInfo.Type)
  755. {
  756. case AuthZoneType.Primary:
  757. jsonWriter.WriteBoolean("internal", zoneInfo.Internal);
  758. break;
  759. }
  760. switch (zoneInfo.Type)
  761. {
  762. case AuthZoneType.Primary:
  763. case AuthZoneType.Secondary:
  764. case AuthZoneType.Stub:
  765. case AuthZoneType.Forwarder:
  766. case AuthZoneType.SecondaryForwarder:
  767. jsonWriter.WriteString("catalog", zoneInfo.CatalogZoneName);
  768. break;
  769. }
  770. switch (zoneInfo.Type)
  771. {
  772. case AuthZoneType.Primary:
  773. case AuthZoneType.Secondary:
  774. jsonWriter.WriteString("dnssecStatus", zoneInfo.ApexZone.DnssecStatus.ToString());
  775. break;
  776. }
  777. switch (zoneInfo.Type)
  778. {
  779. case AuthZoneType.Secondary:
  780. jsonWriter.WriteBoolean("validationFailed", zoneInfo.ValidationFailed);
  781. break;
  782. }
  783. switch (zoneInfo.Type)
  784. {
  785. case AuthZoneType.Secondary:
  786. case AuthZoneType.Stub:
  787. case AuthZoneType.SecondaryForwarder:
  788. case AuthZoneType.SecondaryCatalog:
  789. jsonWriter.WriteString("expiry", zoneInfo.Expiry);
  790. jsonWriter.WriteBoolean("isExpired", zoneInfo.IsExpired);
  791. jsonWriter.WriteBoolean("syncFailed", zoneInfo.SyncFailed);
  792. break;
  793. }
  794. switch (zoneInfo.Type)
  795. {
  796. case AuthZoneType.Primary:
  797. case AuthZoneType.Secondary:
  798. case AuthZoneType.Forwarder:
  799. case AuthZoneType.Catalog:
  800. if (!zoneInfo.Internal)
  801. {
  802. string[] notifyFailed = zoneInfo.NotifyFailed;
  803. jsonWriter.WriteBoolean("notifyFailed", notifyFailed.Length > 0);
  804. jsonWriter.WritePropertyName("notifyFailedFor");
  805. jsonWriter.WriteStartArray();
  806. foreach (string server in notifyFailed)
  807. jsonWriter.WriteStringValue(server);
  808. jsonWriter.WriteEndArray();
  809. }
  810. break;
  811. }
  812. jsonWriter.WriteEndObject();
  813. }
  814. private static string[] DecodeCharacterStrings(string text)
  815. {
  816. string[] characterStrings = text.Split(_newLineSeparator, StringSplitOptions.RemoveEmptyEntries);
  817. for (int i = 0; i < characterStrings.Length; i++)
  818. characterStrings[i] = Unescape(characterStrings[i]);
  819. return characterStrings;
  820. }
  821. private static string Unescape(string text)
  822. {
  823. StringBuilder sb = new StringBuilder(text.Length);
  824. for (int i = 0, j; i < text.Length; i++)
  825. {
  826. char c = text[i];
  827. if (c == '\\')
  828. {
  829. j = i + 1;
  830. if (j == text.Length)
  831. {
  832. sb.Append(c);
  833. break;
  834. }
  835. char next = text[j];
  836. switch (next)
  837. {
  838. case 'n':
  839. sb.Append('\n');
  840. break;
  841. case 'r':
  842. sb.Append('\r');
  843. break;
  844. case 't':
  845. sb.Append('\t');
  846. break;
  847. case '\\':
  848. sb.Append('\\');
  849. break;
  850. default:
  851. sb.Append(c).Append(next);
  852. break;
  853. }
  854. i++;
  855. }
  856. else
  857. {
  858. sb.Append(c);
  859. }
  860. }
  861. return sb.ToString();
  862. }
  863. private static string GetSvcbTargetName(DnsResourceRecord svcbRecord)
  864. {
  865. DnsSVCBRecordData rData = svcbRecord.RDATA as DnsSVCBRecordData;
  866. if (rData.TargetName.Length > 0)
  867. return rData.TargetName;
  868. if (rData.SvcPriority == 0) //alias mode
  869. return null;
  870. //service mode
  871. return svcbRecord.Name;
  872. }
  873. private void ResolveSvcbAutoHints(string zoneName, DnsResourceRecord svcbRecord, bool resolveIpv4Hint, bool resolveIpv6Hint, Dictionary<DnsSvcParamKey, DnsSvcParamValue> svcParams, IReadOnlyCollection<DnsResourceRecord> importRecords = null)
  874. {
  875. string targetName = GetSvcbTargetName(svcbRecord);
  876. if (targetName is not null)
  877. ResolveSvcbAutoHints(zoneName, targetName, resolveIpv4Hint, resolveIpv6Hint, svcParams, importRecords);
  878. }
  879. private void ResolveSvcbAutoHints(string zoneName, string targetName, bool resolveIpv4Hint, bool resolveIpv6Hint, Dictionary<DnsSvcParamKey, DnsSvcParamValue> svcParams, IReadOnlyCollection<DnsResourceRecord> importRecords = null)
  880. {
  881. if (resolveIpv4Hint)
  882. {
  883. List<IPAddress> ipv4Hint = new List<IPAddress>();
  884. IReadOnlyList<DnsResourceRecord> records = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(zoneName, targetName, DnsResourceRecordType.A);
  885. foreach (DnsResourceRecord record in records)
  886. {
  887. if (record.GetAuthGenericRecordInfo().Disabled)
  888. continue;
  889. ipv4Hint.Add((record.RDATA as DnsARecordData).Address);
  890. }
  891. if (importRecords is not null)
  892. {
  893. foreach (DnsResourceRecord record in importRecords)
  894. {
  895. if (record.Type != DnsResourceRecordType.A)
  896. continue;
  897. if (record.Name.Equals(targetName, StringComparison.OrdinalIgnoreCase))
  898. {
  899. IPAddress address = (record.RDATA as DnsARecordData).Address;
  900. if (!ipv4Hint.Contains(address))
  901. ipv4Hint.Add(address);
  902. }
  903. }
  904. }
  905. if (ipv4Hint.Count > 0)
  906. svcParams[DnsSvcParamKey.IPv4Hint] = new DnsSvcIPv4HintParamValue(ipv4Hint);
  907. else
  908. svcParams.Remove(DnsSvcParamKey.IPv4Hint);
  909. }
  910. if (resolveIpv6Hint)
  911. {
  912. List<IPAddress> ipv6Hint = new List<IPAddress>();
  913. IReadOnlyList<DnsResourceRecord> records = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(zoneName, targetName, DnsResourceRecordType.AAAA);
  914. foreach (DnsResourceRecord record in records)
  915. {
  916. if (record.GetAuthGenericRecordInfo().Disabled)
  917. continue;
  918. ipv6Hint.Add((record.RDATA as DnsAAAARecordData).Address);
  919. }
  920. if (importRecords is not null)
  921. {
  922. foreach (DnsResourceRecord record in importRecords)
  923. {
  924. if (record.Type != DnsResourceRecordType.AAAA)
  925. continue;
  926. if (record.Name.Equals(targetName, StringComparison.OrdinalIgnoreCase))
  927. {
  928. IPAddress address = (record.RDATA as DnsAAAARecordData).Address;
  929. if (!ipv6Hint.Contains(address))
  930. ipv6Hint.Add(address);
  931. }
  932. }
  933. }
  934. if (ipv6Hint.Count > 0)
  935. svcParams[DnsSvcParamKey.IPv6Hint] = new DnsSvcIPv6HintParamValue(ipv6Hint);
  936. else
  937. svcParams.Remove(DnsSvcParamKey.IPv6Hint);
  938. }
  939. }
  940. private void UpdateSvcbAutoHints(string zoneName, string targetName, bool resolveIpv4Hint, bool resolveIpv6Hint)
  941. {
  942. List<DnsResourceRecord> allSvcbRecords = new List<DnsResourceRecord>();
  943. _dnsWebService.DnsServer.AuthZoneManager.ListAllZoneRecords(zoneName, [DnsResourceRecordType.SVCB, DnsResourceRecordType.HTTPS], allSvcbRecords);
  944. foreach (DnsResourceRecord record in allSvcbRecords)
  945. {
  946. SVCBRecordInfo info = record.GetAuthSVCBRecordInfo();
  947. if ((info.AutoIpv4Hint && resolveIpv4Hint) || (info.AutoIpv6Hint && resolveIpv6Hint))
  948. {
  949. string scvbTargetName = GetSvcbTargetName(record);
  950. if (targetName.Equals(scvbTargetName, StringComparison.OrdinalIgnoreCase))
  951. {
  952. DnsSVCBRecordData oldRData = record.RDATA as DnsSVCBRecordData;
  953. Dictionary<DnsSvcParamKey, DnsSvcParamValue> newSvcParams = new Dictionary<DnsSvcParamKey, DnsSvcParamValue>(oldRData.SvcParams);
  954. ResolveSvcbAutoHints(zoneName, targetName, resolveIpv4Hint, resolveIpv6Hint, newSvcParams);
  955. DnsSVCBRecordData newRData = new DnsSVCBRecordData(oldRData.SvcPriority, oldRData.TargetName, newSvcParams);
  956. DnsResourceRecord newRecord = new DnsResourceRecord(record.Name, record.Type, record.Class, record.TTL, newRData) { Tag = record.Tag };
  957. _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneName, record, newRecord);
  958. }
  959. }
  960. }
  961. }
  962. #endregion
  963. #region public
  964. public void ListZones(HttpContext context)
  965. {
  966. UserSession session = context.GetCurrentSession();
  967. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.View))
  968. throw new DnsWebServiceException("Access was denied.");
  969. HttpRequest request = context.Request;
  970. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  971. IReadOnlyList<AuthZoneInfo> zoneInfoList = _dnsWebService.DnsServer.AuthZoneManager.GetZones(delegate (AuthZoneInfo zoneInfo)
  972. {
  973. return _dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View);
  974. });
  975. if (request.TryGetQueryOrForm("pageNumber", int.Parse, out int pageNumber))
  976. {
  977. int zonesPerPage = request.GetQueryOrForm("zonesPerPage", int.Parse, 10);
  978. int totalPages;
  979. int totalZones = zoneInfoList.Count;
  980. if (totalZones > 0)
  981. {
  982. if (pageNumber == 0)
  983. pageNumber = 1;
  984. totalPages = (totalZones / zonesPerPage) + (totalZones % zonesPerPage > 0 ? 1 : 0);
  985. if ((pageNumber > totalPages) || (pageNumber < 0))
  986. pageNumber = totalPages;
  987. int start = (pageNumber - 1) * zonesPerPage;
  988. int end = Math.Min(start + zonesPerPage, totalZones);
  989. List<AuthZoneInfo> zoneInfoPageList = new List<AuthZoneInfo>(end - start);
  990. for (int i = start; i < end; i++)
  991. zoneInfoPageList.Add(zoneInfoList[i]);
  992. zoneInfoList = zoneInfoPageList;
  993. }
  994. else
  995. {
  996. pageNumber = 0;
  997. totalPages = 0;
  998. }
  999. jsonWriter.WriteNumber("pageNumber", pageNumber);
  1000. jsonWriter.WriteNumber("totalPages", totalPages);
  1001. jsonWriter.WriteNumber("totalZones", totalZones);
  1002. }
  1003. jsonWriter.WritePropertyName("zones");
  1004. jsonWriter.WriteStartArray();
  1005. foreach (AuthZoneInfo zoneInfo in zoneInfoList)
  1006. WriteZoneInfoAsJson(zoneInfo, jsonWriter);
  1007. jsonWriter.WriteEndArray();
  1008. }
  1009. public void ListCatalogZones(HttpContext context)
  1010. {
  1011. UserSession session = context.GetCurrentSession();
  1012. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.View))
  1013. throw new DnsWebServiceException("Access was denied.");
  1014. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  1015. IReadOnlyList<AuthZoneInfo> catalogZoneInfoList = _dnsWebService.DnsServer.AuthZoneManager.GetCatalogZones(delegate (AuthZoneInfo catalogZoneInfo)
  1016. {
  1017. return !catalogZoneInfo.Disabled && _dnsWebService._authManager.IsPermitted(PermissionSection.Zones, catalogZoneInfo.Name, session.User, PermissionFlag.Modify);
  1018. });
  1019. jsonWriter.WritePropertyName("catalogZoneNames");
  1020. jsonWriter.WriteStartArray();
  1021. foreach (AuthZoneInfo catalogZoneInfo in catalogZoneInfoList)
  1022. jsonWriter.WriteStringValue(catalogZoneInfo.Name);
  1023. jsonWriter.WriteEndArray();
  1024. }
  1025. public async Task CreateZoneAsync(HttpContext context)
  1026. {
  1027. UserSession session = context.GetCurrentSession();
  1028. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1029. throw new DnsWebServiceException("Access was denied.");
  1030. HttpRequest request = context.Request;
  1031. string zoneName = request.GetQueryOrFormAlt("zone", "domain");
  1032. if (zoneName.Contains('*'))
  1033. throw new DnsWebServiceException("Domain name for a zone cannot contain wildcard character.");
  1034. if (IPAddress.TryParse(zoneName, out IPAddress ipAddress))
  1035. {
  1036. zoneName = ipAddress.GetReverseDomain().ToLowerInvariant();
  1037. }
  1038. else if (zoneName.Contains('/'))
  1039. {
  1040. string[] parts = zoneName.Split('/');
  1041. if ((parts.Length == 2) && IPAddress.TryParse(parts[0], out ipAddress) && int.TryParse(parts[1], out int subnetMaskWidth))
  1042. zoneName = Zone.GetReverseZone(ipAddress, subnetMaskWidth);
  1043. }
  1044. else if (zoneName.EndsWith('.'))
  1045. {
  1046. zoneName = zoneName.Substring(0, zoneName.Length - 1);
  1047. }
  1048. if (DnsClient.IsDomainNameUnicode(zoneName))
  1049. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1050. AuthZoneType type = request.GetQueryOrFormEnum("type", AuthZoneType.Primary);
  1051. AuthZoneInfo zoneInfo;
  1052. switch (type)
  1053. {
  1054. case AuthZoneType.Primary:
  1055. {
  1056. bool useSoaSerialDateScheme = request.GetQueryOrForm("useSoaSerialDateScheme", bool.Parse, _dnsWebService.DnsServer.AuthZoneManager.UseSoaSerialDateScheme);
  1057. string catalogZoneName = request.GetQueryOrForm("catalog", null);
  1058. AuthZoneInfo catalogZoneInfo = null;
  1059. if (catalogZoneName is not null)
  1060. {
  1061. catalogZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(catalogZoneName);
  1062. if (catalogZoneInfo is null)
  1063. throw new DnsWebServiceException("No such Catalog zone was found: " + catalogZoneName);
  1064. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, catalogZoneInfo.Name, session.User, PermissionFlag.Modify))
  1065. throw new DnsWebServiceException("Access was denied to use Catalog zone: " + catalogZoneInfo.Name);
  1066. }
  1067. zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreatePrimaryZone(zoneName, useSoaSerialDateScheme);
  1068. if (zoneInfo is null)
  1069. throw new DnsWebServiceException("Zone already exists: " + zoneName);
  1070. //set permissions
  1071. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete);
  1072. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1073. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1074. _dnsWebService._authManager.SaveConfigFile();
  1075. //add membership for catalog zone
  1076. if (catalogZoneInfo is not null)
  1077. _dnsWebService.DnsServer.AuthZoneManager.AddCatalogMemberZone(catalogZoneInfo.Name, zoneInfo);
  1078. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Authoritative Primary zone was created: " + zoneInfo.DisplayName);
  1079. }
  1080. break;
  1081. case AuthZoneType.Secondary:
  1082. {
  1083. string primaryNameServerAddresses = request.GetQueryOrForm("primaryNameServerAddresses", null);
  1084. DnsTransportProtocol primaryZoneTransferProtocol = request.GetQueryOrFormEnum("zoneTransferProtocol", DnsTransportProtocol.Tcp);
  1085. string primaryZoneTransferTsigKeyName = request.GetQueryOrForm("tsigKeyName", null);
  1086. bool validateZone = request.GetQueryOrForm("validateZone", bool.Parse, false);
  1087. if (primaryZoneTransferProtocol == DnsTransportProtocol.Quic)
  1088. DnsWebService.ValidateQuicSupport();
  1089. zoneInfo = await _dnsWebService.DnsServer.AuthZoneManager.CreateSecondaryZoneAsync(zoneName, primaryNameServerAddresses, primaryZoneTransferProtocol, primaryZoneTransferTsigKeyName, validateZone);
  1090. if (zoneInfo is null)
  1091. throw new DnsWebServiceException("Zone already exists: " + zoneName);
  1092. //set permissions
  1093. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete);
  1094. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1095. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1096. _dnsWebService._authManager.SaveConfigFile();
  1097. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Authoritative Secondary zone was created: " + zoneInfo.DisplayName);
  1098. }
  1099. break;
  1100. case AuthZoneType.Stub:
  1101. {
  1102. string primaryNameServerAddresses = request.GetQueryOrForm("primaryNameServerAddresses", null);
  1103. string catalogZoneName = request.GetQueryOrForm("catalog", null);
  1104. AuthZoneInfo catalogZoneInfo = null;
  1105. if (catalogZoneName is not null)
  1106. {
  1107. catalogZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(catalogZoneName);
  1108. if (catalogZoneInfo is null)
  1109. throw new DnsWebServiceException("No such Catalog zone was found: " + catalogZoneName);
  1110. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, catalogZoneInfo.Name, session.User, PermissionFlag.Modify))
  1111. throw new DnsWebServiceException("Access was denied to use Catalog zone: " + catalogZoneInfo.Name);
  1112. }
  1113. zoneInfo = await _dnsWebService.DnsServer.AuthZoneManager.CreateStubZoneAsync(zoneName, primaryNameServerAddresses);
  1114. if (zoneInfo is null)
  1115. throw new DnsWebServiceException("Zone already exists: " + zoneName);
  1116. //set permissions
  1117. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete);
  1118. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1119. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1120. _dnsWebService._authManager.SaveConfigFile();
  1121. //add membership for catalog zone
  1122. if (catalogZoneInfo is not null)
  1123. _dnsWebService.DnsServer.AuthZoneManager.AddCatalogMemberZone(catalogZoneInfo.Name, zoneInfo);
  1124. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Stub zone was created: " + zoneInfo.DisplayName);
  1125. }
  1126. break;
  1127. case AuthZoneType.Forwarder:
  1128. {
  1129. DnsTransportProtocol forwarderProtocol = request.GetQueryOrFormEnum("protocol", DnsTransportProtocol.Udp);
  1130. string forwarder = request.GetQueryOrForm("forwarder");
  1131. bool dnssecValidation = request.GetQueryOrForm("dnssecValidation", bool.Parse, false);
  1132. DnsForwarderRecordProxyType proxyType = request.GetQueryOrFormEnum("proxyType", DnsForwarderRecordProxyType.DefaultProxy);
  1133. string proxyAddress = null;
  1134. ushort proxyPort = 0;
  1135. string proxyUsername = null;
  1136. string proxyPassword = null;
  1137. switch (proxyType)
  1138. {
  1139. case DnsForwarderRecordProxyType.Http:
  1140. case DnsForwarderRecordProxyType.Socks5:
  1141. proxyAddress = request.GetQueryOrForm("proxyAddress");
  1142. proxyPort = request.GetQueryOrForm("proxyPort", ushort.Parse);
  1143. proxyUsername = request.QueryOrForm("proxyUsername");
  1144. proxyPassword = request.QueryOrForm("proxyPassword");
  1145. break;
  1146. }
  1147. if (forwarderProtocol == DnsTransportProtocol.Quic)
  1148. DnsWebService.ValidateQuicSupport();
  1149. string catalogZoneName = request.GetQueryOrForm("catalog", null);
  1150. AuthZoneInfo catalogZoneInfo = null;
  1151. if (catalogZoneName is not null)
  1152. {
  1153. catalogZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(catalogZoneName);
  1154. if (catalogZoneInfo is null)
  1155. throw new DnsWebServiceException("No such Catalog zone was found: " + catalogZoneName);
  1156. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, catalogZoneInfo.Name, session.User, PermissionFlag.Modify))
  1157. throw new DnsWebServiceException("Access was denied to use Catalog zone: " + catalogZoneInfo.Name);
  1158. }
  1159. zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreateForwarderZone(zoneName, forwarderProtocol, forwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword, null);
  1160. if (zoneInfo is null)
  1161. throw new DnsWebServiceException("Zone already exists: " + zoneName);
  1162. //set permissions
  1163. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete);
  1164. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1165. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1166. _dnsWebService._authManager.SaveConfigFile();
  1167. //add membership for catalog zone
  1168. if (catalogZoneInfo is not null)
  1169. _dnsWebService.DnsServer.AuthZoneManager.AddCatalogMemberZone(catalogZoneInfo.Name, zoneInfo);
  1170. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Forwarder zone was created: " + zoneInfo.DisplayName);
  1171. }
  1172. break;
  1173. case AuthZoneType.SecondaryForwarder:
  1174. {
  1175. string primaryNameServerAddresses = request.GetQueryOrForm("primaryNameServerAddresses");
  1176. DnsTransportProtocol primaryZoneTransferProtocol = request.GetQueryOrFormEnum("zoneTransferProtocol", DnsTransportProtocol.Tcp);
  1177. string primaryZoneTransferTsigKeyName = request.GetQueryOrForm("tsigKeyName", null);
  1178. if (primaryZoneTransferProtocol == DnsTransportProtocol.Quic)
  1179. DnsWebService.ValidateQuicSupport();
  1180. zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreateSecondaryForwarderZone(zoneName, primaryNameServerAddresses, primaryZoneTransferProtocol, primaryZoneTransferTsigKeyName);
  1181. if (zoneInfo is null)
  1182. throw new DnsWebServiceException("Zone already exists: " + zoneName);
  1183. //set permissions
  1184. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete);
  1185. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1186. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1187. _dnsWebService._authManager.SaveConfigFile();
  1188. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Secondary Forwarder zone was created: " + zoneInfo.DisplayName);
  1189. }
  1190. break;
  1191. case AuthZoneType.Catalog:
  1192. {
  1193. zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreateCatalogZone(zoneName);
  1194. if (zoneInfo is null)
  1195. throw new DnsWebServiceException("Zone already exists: " + zoneName);
  1196. //set permissions
  1197. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete);
  1198. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1199. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1200. _dnsWebService._authManager.SaveConfigFile();
  1201. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Catalog zone was created: " + zoneInfo.DisplayName);
  1202. }
  1203. break;
  1204. case AuthZoneType.SecondaryCatalog:
  1205. {
  1206. string primaryNameServerAddresses = request.GetQueryOrForm("primaryNameServerAddresses");
  1207. DnsTransportProtocol primaryZoneTransferProtocol = request.GetQueryOrFormEnum("zoneTransferProtocol", DnsTransportProtocol.Tcp);
  1208. string primaryZoneTransferTsigKeyName = request.GetQueryOrForm("tsigKeyName", null);
  1209. if (primaryZoneTransferProtocol == DnsTransportProtocol.Quic)
  1210. DnsWebService.ValidateQuicSupport();
  1211. zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreateSecondaryCatalogZone(zoneName, primaryNameServerAddresses, primaryZoneTransferProtocol, primaryZoneTransferTsigKeyName);
  1212. if (zoneInfo is null)
  1213. throw new DnsWebServiceException("Zone already exists: " + zoneName);
  1214. //set permissions
  1215. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete);
  1216. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1217. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1218. _dnsWebService._authManager.SaveConfigFile();
  1219. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Secondary Catalog zone was created: " + zoneInfo.DisplayName);
  1220. }
  1221. break;
  1222. default:
  1223. throw new NotSupportedException("Zone type not supported.");
  1224. }
  1225. //delete cache for this zone to allow rebuilding cache data as needed by stub or forwarder zones
  1226. _dnsWebService.DnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name);
  1227. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  1228. jsonWriter.WriteString("domain", string.IsNullOrEmpty(zoneInfo.Name) ? "." : zoneInfo.Name);
  1229. }
  1230. public async Task ImportZoneAsync(HttpContext context)
  1231. {
  1232. UserSession session = context.GetCurrentSession();
  1233. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1234. throw new DnsWebServiceException("Access was denied.");
  1235. HttpRequest request = context.Request;
  1236. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1237. if (DnsClient.IsDomainNameUnicode(zoneName))
  1238. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1239. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName);
  1240. if (zoneInfo is null)
  1241. throw new DnsWebServiceException("No such zone was found: " + zoneName);
  1242. if (zoneInfo.Internal)
  1243. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  1244. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify))
  1245. throw new DnsWebServiceException("Access was denied.");
  1246. bool overwrite = request.GetQueryOrForm("overwrite", bool.Parse, true);
  1247. bool overwriteSoaSerial = request.GetQueryOrForm("overwriteSoaSerial", bool.Parse, false);
  1248. TextReader textReader;
  1249. switch (request.ContentType?.ToLowerInvariant())
  1250. {
  1251. case "application/x-www-form-urlencoded":
  1252. string zoneRecords = request.GetQueryOrForm("records");
  1253. textReader = new StringReader(zoneRecords);
  1254. break;
  1255. case "text/plain":
  1256. textReader = new StreamReader(request.Body);
  1257. break;
  1258. default:
  1259. throw new DnsWebServiceException("Content type is not supported: " + request.ContentType);
  1260. }
  1261. using TextReader zoneReader = textReader;
  1262. IReadOnlyCollection<DnsResourceRecord> records = await ZoneFile.ReadZoneFileFromAsync(zoneReader, zoneInfo.Name, _dnsWebService._zonesApi.DefaultRecordTtl);
  1263. List<DnsResourceRecord> newRecords = new List<DnsResourceRecord>(records.Count);
  1264. foreach (DnsResourceRecord record in records)
  1265. {
  1266. if (record.Class != DnsClass.IN)
  1267. throw new DnsWebServiceException("Cannot import records: only IN class is supported by the DNS server.");
  1268. switch (record.Type)
  1269. {
  1270. case DnsResourceRecordType.DNSKEY:
  1271. case DnsResourceRecordType.RRSIG:
  1272. case DnsResourceRecordType.NSEC:
  1273. case DnsResourceRecordType.NSEC3:
  1274. case DnsResourceRecordType.NSEC3PARAM:
  1275. continue; //skip DNSSEC records
  1276. case DnsResourceRecordType.SVCB:
  1277. case DnsResourceRecordType.HTTPS:
  1278. {
  1279. if (record.Tag is string comments)
  1280. {
  1281. SVCBRecordInfo rrInfo = new SVCBRecordInfo();
  1282. rrInfo.Comments = comments;
  1283. record.Tag = rrInfo;
  1284. }
  1285. if (record.RDATA is DnsSVCBRecordData rdata && (rdata.AutoIpv4Hint || rdata.AutoIpv6Hint))
  1286. {
  1287. if (rdata.AutoIpv4Hint)
  1288. record.GetAuthSVCBRecordInfo().AutoIpv4Hint = true;
  1289. if (rdata.AutoIpv6Hint)
  1290. record.GetAuthSVCBRecordInfo().AutoIpv6Hint = true;
  1291. Dictionary<DnsSvcParamKey, DnsSvcParamValue> svcParams = new Dictionary<DnsSvcParamKey, DnsSvcParamValue>(rdata.SvcParams);
  1292. DnsResourceRecord newRecord = new DnsResourceRecord(record.Name, record.Type, record.Class, record.TTL, new DnsSVCBRecordData(rdata.SvcPriority, rdata.TargetName, svcParams)) { Tag = record.Tag };
  1293. ResolveSvcbAutoHints(zoneInfo.Name, record, rdata.AutoIpv4Hint, rdata.AutoIpv6Hint, svcParams, records);
  1294. newRecords.Add(newRecord);
  1295. break;
  1296. }
  1297. newRecords.Add(record);
  1298. }
  1299. break;
  1300. default:
  1301. {
  1302. if (record.Tag is string comments)
  1303. {
  1304. GenericRecordInfo rrInfo = new GenericRecordInfo();
  1305. rrInfo.Comments = comments;
  1306. record.Tag = rrInfo;
  1307. }
  1308. newRecords.Add(record);
  1309. }
  1310. break;
  1311. }
  1312. }
  1313. _dnsWebService.DnsServer.AuthZoneManager.ImportRecords(zoneInfo.Name, newRecords, overwrite, overwriteSoaSerial);
  1314. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Total " + newRecords.Count + " record(s) were imported successfully into " + zoneInfo.TypeName + " zone: " + zoneInfo.DisplayName);
  1315. }
  1316. public async Task ExportZoneAsync(HttpContext context)
  1317. {
  1318. UserSession session = context.GetCurrentSession();
  1319. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.View))
  1320. throw new DnsWebServiceException("Access was denied.");
  1321. HttpRequest request = context.Request;
  1322. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1323. if (DnsClient.IsDomainNameUnicode(zoneName))
  1324. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1325. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName);
  1326. if (zoneInfo is null)
  1327. throw new DnsWebServiceException("No such zone was found: " + zoneName);
  1328. if (zoneInfo.Internal)
  1329. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  1330. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View))
  1331. throw new DnsWebServiceException("Access was denied.");
  1332. List<DnsResourceRecord> records = new List<DnsResourceRecord>();
  1333. _dnsWebService.DnsServer.AuthZoneManager.ListAllZoneRecords(zoneInfo.Name, records);
  1334. foreach (DnsResourceRecord record in records)
  1335. {
  1336. switch (record.Type)
  1337. {
  1338. case DnsResourceRecordType.SVCB:
  1339. case DnsResourceRecordType.HTTPS:
  1340. SVCBRecordInfo info = record.GetAuthSVCBRecordInfo();
  1341. if (info.AutoIpv4Hint)
  1342. (record.RDATA as DnsSVCBRecordData).AutoIpv4Hint = true;
  1343. if (info.AutoIpv6Hint)
  1344. (record.RDATA as DnsSVCBRecordData).AutoIpv6Hint = true;
  1345. break;
  1346. }
  1347. }
  1348. HttpResponse response = context.Response;
  1349. response.ContentType = "text/plain";
  1350. response.Headers.ContentDisposition = "attachment;filename=" + (zoneInfo.Name.Length == 0 ? "root.zone" : zoneInfo.Name + ".zone");
  1351. await using (StreamWriter sW = new StreamWriter(response.Body))
  1352. {
  1353. await ZoneFile.WriteZoneFileToAsync(sW, zoneInfo.Name, records, delegate (DnsResourceRecord record)
  1354. {
  1355. if (record.Tag is null)
  1356. return null;
  1357. return record.GetAuthGenericRecordInfo().Comments;
  1358. });
  1359. }
  1360. }
  1361. public void CloneZone(HttpContext context)
  1362. {
  1363. UserSession session = context.GetCurrentSession();
  1364. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1365. throw new DnsWebServiceException("Access was denied.");
  1366. HttpRequest request = context.Request;
  1367. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1368. if (DnsClient.IsDomainNameUnicode(zoneName))
  1369. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1370. string sourceZoneName = request.GetQueryOrForm("sourceZone").TrimEnd('.');
  1371. if (DnsClient.IsDomainNameUnicode(sourceZoneName))
  1372. sourceZoneName = DnsClient.ConvertDomainNameToAscii(sourceZoneName);
  1373. AuthZoneInfo sourceZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(sourceZoneName);
  1374. if (sourceZoneInfo is null)
  1375. throw new DnsWebServiceException("No such zone was found: " + sourceZoneName);
  1376. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, sourceZoneInfo.Name, session.User, PermissionFlag.View))
  1377. throw new DnsWebServiceException("Access was denied.");
  1378. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CloneZone(zoneName, sourceZoneInfo.Name);
  1379. //clone user/group permissions from source zone
  1380. Permission sourceZonePermissions = _dnsWebService._authManager.GetPermission(PermissionSection.Zones, sourceZoneInfo.Name);
  1381. foreach (KeyValuePair<User, PermissionFlag> userPermission in sourceZonePermissions.UserPermissions)
  1382. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, userPermission.Key, userPermission.Value);
  1383. foreach (KeyValuePair<Group, PermissionFlag> groupPermissions in sourceZonePermissions.GroupPermissions)
  1384. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, groupPermissions.Key, groupPermissions.Value);
  1385. //set default permissions
  1386. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete);
  1387. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1388. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, zoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  1389. _dnsWebService._authManager.SaveConfigFile();
  1390. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] " + sourceZoneInfo.TypeName + " zone '" + sourceZoneInfo.DisplayName + "' was cloned as '" + zoneInfo.DisplayName + "' sucessfully.");
  1391. }
  1392. public void ConvertZone(HttpContext context)
  1393. {
  1394. UserSession session = context.GetCurrentSession();
  1395. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Delete))
  1396. throw new DnsWebServiceException("Access was denied.");
  1397. HttpRequest request = context.Request;
  1398. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1399. AuthZoneType type = request.GetQueryOrFormEnum<AuthZoneType>("type");
  1400. if (DnsClient.IsDomainNameUnicode(zoneName))
  1401. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1402. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName);
  1403. if (zoneInfo is null)
  1404. throw new DnsWebServiceException("No such zone was found: " + zoneName);
  1405. if (zoneInfo.Internal)
  1406. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  1407. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete))
  1408. throw new DnsWebServiceException("Access was denied.");
  1409. _dnsWebService.DnsServer.AuthZoneManager.ConvertZoneType(zoneInfo.Name, type);
  1410. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] " + zoneInfo.TypeName + " zone '" + zoneInfo.DisplayName + "' was converted to " + AuthZoneInfo.GetZoneTypeName(type) + " zone sucessfully.");
  1411. }
  1412. public void SignPrimaryZone(HttpContext context)
  1413. {
  1414. UserSession session = context.GetCurrentSession();
  1415. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1416. throw new DnsWebServiceException("Access was denied.");
  1417. HttpRequest request = context.Request;
  1418. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1419. if (DnsClient.IsDomainNameUnicode(zoneName))
  1420. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1421. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1422. throw new DnsWebServiceException("Access was denied.");
  1423. string algorithm = request.GetQueryOrForm("algorithm");
  1424. uint dnsKeyTtl = request.GetQueryOrForm<uint>("dnsKeyTtl", uint.Parse, 24 * 60 * 60);
  1425. ushort zskRolloverDays = request.GetQueryOrForm<ushort>("zskRolloverDays", ushort.Parse, 30);
  1426. bool useNSEC3 = false;
  1427. string strNxProof = request.QueryOrForm("nxProof");
  1428. if (!string.IsNullOrEmpty(strNxProof))
  1429. {
  1430. switch (strNxProof.ToUpper())
  1431. {
  1432. case "NSEC":
  1433. useNSEC3 = false;
  1434. break;
  1435. case "NSEC3":
  1436. useNSEC3 = true;
  1437. break;
  1438. default:
  1439. throw new NotSupportedException("Non-existence proof type is not supported: " + strNxProof);
  1440. }
  1441. }
  1442. ushort iterations = 0;
  1443. byte saltLength = 0;
  1444. if (useNSEC3)
  1445. {
  1446. iterations = request.GetQueryOrForm<ushort>("iterations", ushort.Parse, 0);
  1447. saltLength = request.GetQueryOrForm<byte>("saltLength", byte.Parse, 0);
  1448. }
  1449. switch (algorithm.ToUpper())
  1450. {
  1451. case "RSA":
  1452. string hashAlgorithm = request.GetQueryOrForm("hashAlgorithm");
  1453. int kskKeySize = request.GetQueryOrForm("kskKeySize", int.Parse);
  1454. int zskKeySize = request.GetQueryOrForm("zskKeySize", int.Parse);
  1455. if (useNSEC3)
  1456. _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithRsaNSEC3(zoneName, hashAlgorithm, kskKeySize, zskKeySize, iterations, saltLength, dnsKeyTtl, zskRolloverDays);
  1457. else
  1458. _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithRsaNSEC(zoneName, hashAlgorithm, kskKeySize, zskKeySize, dnsKeyTtl, zskRolloverDays);
  1459. break;
  1460. case "ECDSA":
  1461. string curve = request.GetQueryOrForm("curve");
  1462. if (useNSEC3)
  1463. _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithEcdsaNSEC3(zoneName, curve, iterations, saltLength, dnsKeyTtl, zskRolloverDays);
  1464. else
  1465. _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZoneWithEcdsaNSEC(zoneName, curve, dnsKeyTtl, zskRolloverDays);
  1466. break;
  1467. default:
  1468. throw new NotSupportedException("Algorithm is not supported: " + algorithm);
  1469. }
  1470. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Primary zone was signed successfully: " + zoneName);
  1471. }
  1472. public void UnsignPrimaryZone(HttpContext context)
  1473. {
  1474. UserSession session = context.GetCurrentSession();
  1475. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1476. throw new DnsWebServiceException("Access was denied.");
  1477. string zoneName = context.Request.GetQueryOrForm("zone").TrimEnd('.');
  1478. if (DnsClient.IsDomainNameUnicode(zoneName))
  1479. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1480. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1481. throw new DnsWebServiceException("Access was denied.");
  1482. _dnsWebService.DnsServer.AuthZoneManager.UnsignPrimaryZone(zoneName);
  1483. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Primary zone was unsigned successfully: " + zoneName);
  1484. }
  1485. public void GetPrimaryZoneDsInfo(HttpContext context)
  1486. {
  1487. UserSession session = context.GetCurrentSession();
  1488. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.View))
  1489. throw new DnsWebServiceException("Access was denied.");
  1490. string zoneName = context.Request.GetQueryOrForm("zone").TrimEnd('.');
  1491. if (DnsClient.IsDomainNameUnicode(zoneName))
  1492. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1493. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName);
  1494. if (zoneInfo is null)
  1495. throw new DnsWebServiceException("No such zone was found: " + zoneName);
  1496. if (zoneInfo.Internal)
  1497. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  1498. if (zoneInfo.Type != AuthZoneType.Primary)
  1499. throw new DnsWebServiceException("The zone must be a primary zone.");
  1500. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View))
  1501. throw new DnsWebServiceException("Access was denied.");
  1502. if (zoneInfo.ApexZone.DnssecStatus == AuthZoneDnssecStatus.Unsigned)
  1503. throw new DnsWebServiceException("The zone must be signed with DNSSEC.");
  1504. IReadOnlyList<DnsResourceRecord> dnsKeyRecords = zoneInfo.ApexZone.GetRecords(DnsResourceRecordType.DNSKEY);
  1505. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  1506. jsonWriter.WriteString("name", zoneInfo.Name);
  1507. jsonWriter.WriteString("type", zoneInfo.Type.ToString());
  1508. jsonWriter.WriteBoolean("internal", zoneInfo.Internal);
  1509. jsonWriter.WriteBoolean("disabled", zoneInfo.Disabled);
  1510. jsonWriter.WriteString("dnssecStatus", zoneInfo.ApexZone.DnssecStatus.ToString());
  1511. jsonWriter.WritePropertyName("dsRecords");
  1512. jsonWriter.WriteStartArray();
  1513. foreach (DnsResourceRecord record in dnsKeyRecords)
  1514. {
  1515. if (record.RDATA is DnsDNSKEYRecordData rdata && rdata.Flags.HasFlag(DnsDnsKeyFlag.SecureEntryPoint))
  1516. {
  1517. jsonWriter.WriteStartObject();
  1518. jsonWriter.WriteNumber("keyTag", rdata.ComputedKeyTag);
  1519. IReadOnlyCollection<DnssecPrivateKey> dnssecPrivateKeys = zoneInfo.DnssecPrivateKeys;
  1520. if (dnssecPrivateKeys is not null)
  1521. {
  1522. foreach (DnssecPrivateKey dnssecPrivateKey in dnssecPrivateKeys)
  1523. {
  1524. if ((dnssecPrivateKey.KeyType == DnssecPrivateKeyType.KeySigningKey) && (dnssecPrivateKey.KeyTag == rdata.ComputedKeyTag))
  1525. {
  1526. jsonWriter.WriteString("dnsKeyState", dnssecPrivateKey.State.ToString());
  1527. if (dnssecPrivateKey.State == DnssecPrivateKeyState.Published)
  1528. jsonWriter.WriteString("dnsKeyStateReadyBy", (zoneInfo.ApexZone as PrimaryZone).GetKskDnsKeyStateReadyBy(dnssecPrivateKey));
  1529. break;
  1530. }
  1531. }
  1532. }
  1533. jsonWriter.WriteString("algorithm", rdata.Algorithm.ToString());
  1534. jsonWriter.WriteString("publicKey", rdata.PublicKey.ToString());
  1535. jsonWriter.WritePropertyName("digests");
  1536. jsonWriter.WriteStartArray();
  1537. {
  1538. jsonWriter.WriteStartObject();
  1539. jsonWriter.WriteString("digestType", "SHA256");
  1540. jsonWriter.WriteString("digest", Convert.ToHexString(rdata.CreateDS(record.Name, DnssecDigestType.SHA256).Digest));
  1541. jsonWriter.WriteEndObject();
  1542. }
  1543. {
  1544. jsonWriter.WriteStartObject();
  1545. jsonWriter.WriteString("digestType", "SHA384");
  1546. jsonWriter.WriteString("digest", Convert.ToHexString(rdata.CreateDS(record.Name, DnssecDigestType.SHA384).Digest));
  1547. jsonWriter.WriteEndObject();
  1548. }
  1549. jsonWriter.WriteEndArray();
  1550. jsonWriter.WriteEndObject();
  1551. }
  1552. }
  1553. jsonWriter.WriteEndArray();
  1554. }
  1555. public void GetPrimaryZoneDnssecProperties(HttpContext context)
  1556. {
  1557. UserSession session = context.GetCurrentSession();
  1558. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1559. throw new DnsWebServiceException("Access was denied.");
  1560. string zoneName = context.Request.GetQueryOrForm("zone").TrimEnd('.');
  1561. if (DnsClient.IsDomainNameUnicode(zoneName))
  1562. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1563. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName);
  1564. if (zoneInfo is null)
  1565. throw new DnsWebServiceException("No such zone was found: " + zoneName);
  1566. if (zoneInfo.Internal)
  1567. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  1568. if (zoneInfo.Type != AuthZoneType.Primary)
  1569. throw new DnsWebServiceException("The zone must be a primary zone.");
  1570. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View))
  1571. throw new DnsWebServiceException("Access was denied.");
  1572. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  1573. jsonWriter.WriteString("name", zoneInfo.Name);
  1574. jsonWriter.WriteString("type", zoneInfo.Type.ToString());
  1575. jsonWriter.WriteBoolean("internal", zoneInfo.Internal);
  1576. jsonWriter.WriteBoolean("disabled", zoneInfo.Disabled);
  1577. jsonWriter.WriteString("dnssecStatus", zoneInfo.ApexZone.DnssecStatus.ToString());
  1578. if (zoneInfo.ApexZone.DnssecStatus == AuthZoneDnssecStatus.SignedWithNSEC3)
  1579. {
  1580. IReadOnlyList<DnsResourceRecord> nsec3ParamRecords = zoneInfo.ApexZone.GetRecords(DnsResourceRecordType.NSEC3PARAM);
  1581. DnsNSEC3PARAMRecordData nsec3Param = nsec3ParamRecords[0].RDATA as DnsNSEC3PARAMRecordData;
  1582. jsonWriter.WriteNumber("nsec3Iterations", nsec3Param.Iterations);
  1583. jsonWriter.WriteNumber("nsec3SaltLength", nsec3Param.Salt.Length);
  1584. }
  1585. jsonWriter.WriteNumber("dnsKeyTtl", zoneInfo.DnsKeyTtl);
  1586. jsonWriter.WritePropertyName("dnssecPrivateKeys");
  1587. jsonWriter.WriteStartArray();
  1588. IReadOnlyCollection<DnssecPrivateKey> dnssecPrivateKeys = zoneInfo.DnssecPrivateKeys;
  1589. if (dnssecPrivateKeys is not null)
  1590. {
  1591. List<DnssecPrivateKey> sortedDnssecPrivateKey = new List<DnssecPrivateKey>(dnssecPrivateKeys);
  1592. sortedDnssecPrivateKey.Sort(delegate (DnssecPrivateKey key1, DnssecPrivateKey key2)
  1593. {
  1594. int value = key1.KeyType.CompareTo(key2.KeyType);
  1595. if (value == 0)
  1596. value = key1.StateChangedOn.CompareTo(key2.StateChangedOn);
  1597. return value;
  1598. });
  1599. foreach (DnssecPrivateKey dnssecPrivateKey in sortedDnssecPrivateKey)
  1600. {
  1601. jsonWriter.WriteStartObject();
  1602. jsonWriter.WriteNumber("keyTag", dnssecPrivateKey.KeyTag);
  1603. jsonWriter.WriteString("keyType", dnssecPrivateKey.KeyType.ToString());
  1604. switch (dnssecPrivateKey.Algorithm)
  1605. {
  1606. case DnssecAlgorithm.RSAMD5:
  1607. case DnssecAlgorithm.RSASHA1:
  1608. case DnssecAlgorithm.RSASHA1_NSEC3_SHA1:
  1609. case DnssecAlgorithm.RSASHA256:
  1610. case DnssecAlgorithm.RSASHA512:
  1611. jsonWriter.WriteString("algorithm", dnssecPrivateKey.Algorithm.ToString() + " (" + (dnssecPrivateKey as DnssecRsaPrivateKey).KeySize + " bits)");
  1612. break;
  1613. default:
  1614. jsonWriter.WriteString("algorithm", dnssecPrivateKey.Algorithm.ToString());
  1615. break;
  1616. }
  1617. jsonWriter.WriteString("state", dnssecPrivateKey.State.ToString());
  1618. jsonWriter.WriteString("stateChangedOn", dnssecPrivateKey.StateChangedOn);
  1619. if ((dnssecPrivateKey.KeyType == DnssecPrivateKeyType.KeySigningKey) && (dnssecPrivateKey.State == DnssecPrivateKeyState.Published))
  1620. jsonWriter.WriteString("stateReadyBy", (zoneInfo.ApexZone as PrimaryZone).GetKskDnsKeyStateReadyBy(dnssecPrivateKey));
  1621. jsonWriter.WriteBoolean("isRetiring", dnssecPrivateKey.IsRetiring);
  1622. jsonWriter.WriteNumber("rolloverDays", dnssecPrivateKey.RolloverDays);
  1623. jsonWriter.WriteEndObject();
  1624. }
  1625. }
  1626. jsonWriter.WriteEndArray();
  1627. }
  1628. public void ConvertPrimaryZoneToNSEC(HttpContext context)
  1629. {
  1630. UserSession session = context.GetCurrentSession();
  1631. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1632. throw new DnsWebServiceException("Access was denied.");
  1633. string zoneName = context.Request.GetQueryOrForm("zone").TrimEnd('.');
  1634. if (DnsClient.IsDomainNameUnicode(zoneName))
  1635. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1636. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1637. throw new DnsWebServiceException("Access was denied.");
  1638. _dnsWebService.DnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC(zoneName);
  1639. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Primary zone was converted to NSEC successfully: " + zoneName);
  1640. }
  1641. public void ConvertPrimaryZoneToNSEC3(HttpContext context)
  1642. {
  1643. UserSession session = context.GetCurrentSession();
  1644. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1645. throw new DnsWebServiceException("Access was denied.");
  1646. HttpRequest request = context.Request;
  1647. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1648. if (DnsClient.IsDomainNameUnicode(zoneName))
  1649. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1650. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1651. throw new DnsWebServiceException("Access was denied.");
  1652. ushort iterations = request.GetQueryOrForm<ushort>("iterations", ushort.Parse, 0);
  1653. byte saltLength = request.GetQueryOrForm<byte>("saltLength", byte.Parse, 0);
  1654. _dnsWebService.DnsServer.AuthZoneManager.ConvertPrimaryZoneToNSEC3(zoneName, iterations, saltLength);
  1655. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Primary zone was converted to NSEC3 successfully: " + zoneName);
  1656. }
  1657. public void UpdatePrimaryZoneNSEC3Parameters(HttpContext context)
  1658. {
  1659. UserSession session = context.GetCurrentSession();
  1660. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1661. throw new DnsWebServiceException("Access was denied.");
  1662. HttpRequest request = context.Request;
  1663. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1664. if (DnsClient.IsDomainNameUnicode(zoneName))
  1665. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1666. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1667. throw new DnsWebServiceException("Access was denied.");
  1668. ushort iterations = request.GetQueryOrForm<ushort>("iterations", ushort.Parse, 0);
  1669. byte saltLength = request.GetQueryOrForm<byte>("saltLength", byte.Parse, 0);
  1670. _dnsWebService.DnsServer.AuthZoneManager.UpdatePrimaryZoneNSEC3Parameters(zoneName, iterations, saltLength);
  1671. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Primary zone NSEC3 parameters were updated successfully: " + zoneName);
  1672. }
  1673. public void UpdatePrimaryZoneDnssecDnsKeyTtl(HttpContext context)
  1674. {
  1675. UserSession session = context.GetCurrentSession();
  1676. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1677. throw new DnsWebServiceException("Access was denied.");
  1678. HttpRequest request = context.Request;
  1679. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1680. if (DnsClient.IsDomainNameUnicode(zoneName))
  1681. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1682. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1683. throw new DnsWebServiceException("Access was denied.");
  1684. uint dnsKeyTtl = request.GetQueryOrForm("ttl", uint.Parse);
  1685. _dnsWebService.DnsServer.AuthZoneManager.UpdatePrimaryZoneDnsKeyTtl(zoneName, dnsKeyTtl);
  1686. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Primary zone DNSKEY TTL was updated successfully: " + zoneName);
  1687. }
  1688. public void GenerateAndAddPrimaryZoneDnssecPrivateKey(HttpContext context)
  1689. {
  1690. UserSession session = context.GetCurrentSession();
  1691. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1692. throw new DnsWebServiceException("Access was denied.");
  1693. HttpRequest request = context.Request;
  1694. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1695. if (DnsClient.IsDomainNameUnicode(zoneName))
  1696. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1697. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1698. throw new DnsWebServiceException("Access was denied.");
  1699. DnssecPrivateKeyType keyType = request.GetQueryOrFormEnum<DnssecPrivateKeyType>("keyType");
  1700. ushort rolloverDays = request.GetQueryOrForm("rolloverDays", ushort.Parse, (ushort)(keyType == DnssecPrivateKeyType.ZoneSigningKey ? 30 : 0));
  1701. string algorithm = request.GetQueryOrForm("algorithm");
  1702. switch (algorithm.ToUpper())
  1703. {
  1704. case "RSA":
  1705. string hashAlgorithm = request.GetQueryOrForm("hashAlgorithm");
  1706. int keySize = request.GetQueryOrForm("keySize", int.Parse);
  1707. _dnsWebService.DnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecRsaPrivateKey(zoneName, keyType, hashAlgorithm, keySize, rolloverDays);
  1708. break;
  1709. case "ECDSA":
  1710. string curve = request.GetQueryOrForm("curve");
  1711. _dnsWebService.DnsServer.AuthZoneManager.GenerateAndAddPrimaryZoneDnssecEcdsaPrivateKey(zoneName, keyType, curve, rolloverDays);
  1712. break;
  1713. default:
  1714. throw new NotSupportedException("Algorithm is not supported: " + algorithm);
  1715. }
  1716. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] DNSSEC private key was generated and added to the primary zone successfully: " + zoneName);
  1717. }
  1718. public void UpdatePrimaryZoneDnssecPrivateKey(HttpContext context)
  1719. {
  1720. UserSession session = context.GetCurrentSession();
  1721. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1722. throw new DnsWebServiceException("Access was denied.");
  1723. HttpRequest request = context.Request;
  1724. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1725. if (DnsClient.IsDomainNameUnicode(zoneName))
  1726. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1727. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1728. throw new DnsWebServiceException("Access was denied.");
  1729. ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse);
  1730. ushort rolloverDays = request.GetQueryOrForm("rolloverDays", ushort.Parse);
  1731. _dnsWebService.DnsServer.AuthZoneManager.UpdatePrimaryZoneDnssecPrivateKey(zoneName, keyTag, rolloverDays);
  1732. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Primary zone DNSSEC private key config was updated successfully: " + zoneName);
  1733. }
  1734. public void DeletePrimaryZoneDnssecPrivateKey(HttpContext context)
  1735. {
  1736. UserSession session = context.GetCurrentSession();
  1737. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1738. throw new DnsWebServiceException("Access was denied.");
  1739. HttpRequest request = context.Request;
  1740. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1741. if (DnsClient.IsDomainNameUnicode(zoneName))
  1742. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1743. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1744. throw new DnsWebServiceException("Access was denied.");
  1745. ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse);
  1746. _dnsWebService.DnsServer.AuthZoneManager.DeletePrimaryZoneDnssecPrivateKey(zoneName, keyTag);
  1747. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] DNSSEC private key was deleted from primary zone successfully: " + zoneName);
  1748. }
  1749. public void PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(HttpContext context)
  1750. {
  1751. UserSession session = context.GetCurrentSession();
  1752. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1753. throw new DnsWebServiceException("Access was denied.");
  1754. string zoneName = context.Request.GetQueryOrForm("zone").TrimEnd('.');
  1755. if (DnsClient.IsDomainNameUnicode(zoneName))
  1756. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1757. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1758. throw new DnsWebServiceException("Access was denied.");
  1759. _dnsWebService.DnsServer.AuthZoneManager.PublishAllGeneratedPrimaryZoneDnssecPrivateKeys(zoneName);
  1760. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] All DNSSEC private keys from the primary zone were published successfully: " + zoneName);
  1761. }
  1762. public void RolloverPrimaryZoneDnsKey(HttpContext context)
  1763. {
  1764. UserSession session = context.GetCurrentSession();
  1765. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1766. throw new DnsWebServiceException("Access was denied.");
  1767. HttpRequest request = context.Request;
  1768. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1769. if (DnsClient.IsDomainNameUnicode(zoneName))
  1770. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1771. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1772. throw new DnsWebServiceException("Access was denied.");
  1773. ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse);
  1774. _dnsWebService.DnsServer.AuthZoneManager.RolloverPrimaryZoneDnsKey(zoneName, keyTag);
  1775. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was rolled over successfully: " + zoneName);
  1776. }
  1777. public void RetirePrimaryZoneDnsKey(HttpContext context)
  1778. {
  1779. UserSession session = context.GetCurrentSession();
  1780. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1781. throw new DnsWebServiceException("Access was denied.");
  1782. HttpRequest request = context.Request;
  1783. string zoneName = request.GetQueryOrForm("zone").TrimEnd('.');
  1784. if (DnsClient.IsDomainNameUnicode(zoneName))
  1785. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1786. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneName, session.User, PermissionFlag.Delete))
  1787. throw new DnsWebServiceException("Access was denied.");
  1788. ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse);
  1789. _dnsWebService.DnsServer.AuthZoneManager.RetirePrimaryZoneDnsKey(zoneName, keyTag);
  1790. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] The DNSKEY (" + keyTag + ") from the primary zone was retired successfully: " + zoneName);
  1791. }
  1792. public void DeleteZone(HttpContext context)
  1793. {
  1794. UserSession session = context.GetCurrentSession();
  1795. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Delete))
  1796. throw new DnsWebServiceException("Access was denied.");
  1797. string zoneName = context.Request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.');
  1798. if (DnsClient.IsDomainNameUnicode(zoneName))
  1799. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1800. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName);
  1801. if (zoneInfo is null)
  1802. throw new DnsWebServiceException("No such zone was found: " + zoneName);
  1803. if (zoneInfo.Internal)
  1804. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  1805. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete))
  1806. throw new DnsWebServiceException("Access was denied.");
  1807. if (!_dnsWebService.DnsServer.AuthZoneManager.DeleteZone(zoneInfo, true))
  1808. throw new DnsWebServiceException("Failed to delete the zone: " + zoneInfo.DisplayName);
  1809. _dnsWebService._authManager.RemoveAllPermissions(PermissionSection.Zones, zoneInfo.Name);
  1810. _dnsWebService._authManager.SaveConfigFile();
  1811. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] " + zoneInfo.TypeName + " zone was deleted: " + zoneInfo.DisplayName);
  1812. }
  1813. public void EnableZone(HttpContext context)
  1814. {
  1815. UserSession session = context.GetCurrentSession();
  1816. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1817. throw new DnsWebServiceException("Access was denied.");
  1818. string zoneName = context.Request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.');
  1819. if (DnsClient.IsDomainNameUnicode(zoneName))
  1820. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1821. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName);
  1822. if (zoneInfo is null)
  1823. throw new DnsWebServiceException("No such zone was found: " + zoneName);
  1824. if (zoneInfo.Internal)
  1825. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  1826. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify))
  1827. throw new DnsWebServiceException("Access was denied.");
  1828. zoneInfo.Disabled = false;
  1829. _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
  1830. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] " + zoneInfo.TypeName + " zone was enabled: " + zoneInfo.DisplayName);
  1831. //delete cache for this zone to allow rebuilding cache data as needed by stub or forwarder zones
  1832. _dnsWebService.DnsServer.CacheZoneManager.DeleteZone(zoneInfo.Name);
  1833. }
  1834. public void DisableZone(HttpContext context)
  1835. {
  1836. UserSession session = context.GetCurrentSession();
  1837. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1838. throw new DnsWebServiceException("Access was denied.");
  1839. string zoneName = context.Request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.');
  1840. if (DnsClient.IsDomainNameUnicode(zoneName))
  1841. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1842. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName);
  1843. if (zoneInfo is null)
  1844. throw new DnsWebServiceException("No such zone was found: " + zoneName);
  1845. if (zoneInfo.Internal)
  1846. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  1847. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify))
  1848. throw new DnsWebServiceException("Access was denied.");
  1849. zoneInfo.Disabled = true;
  1850. _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
  1851. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] " + zoneInfo.TypeName + " zone was disabled: " + zoneInfo.DisplayName);
  1852. }
  1853. public void GetZoneOptions(HttpContext context)
  1854. {
  1855. UserSession session = context.GetCurrentSession();
  1856. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  1857. throw new DnsWebServiceException("Access was denied.");
  1858. HttpRequest request = context.Request;
  1859. string zoneName = request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.');
  1860. if (DnsClient.IsDomainNameUnicode(zoneName))
  1861. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  1862. bool includeAvailableCatalogZoneNames = request.GetQueryOrForm("includeAvailableCatalogZoneNames", bool.Parse, false);
  1863. bool includeAvailableTsigKeyNames = request.GetQueryOrForm("includeAvailableTsigKeyNames", bool.Parse, false);
  1864. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName);
  1865. if (zoneInfo is null)
  1866. throw new DnsWebServiceException("No such zone was found: " + zoneName);
  1867. if (zoneInfo.Internal)
  1868. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  1869. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View))
  1870. throw new DnsWebServiceException("Access was denied.");
  1871. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  1872. jsonWriter.WriteString("name", zoneInfo.Name);
  1873. if (DnsClient.TryConvertDomainNameToUnicode(zoneInfo.Name, out string nameIdn))
  1874. jsonWriter.WriteString("nameIdn", nameIdn);
  1875. jsonWriter.WriteString("type", zoneInfo.Type.ToString());
  1876. if (zoneInfo.Type == AuthZoneType.Primary)
  1877. jsonWriter.WriteBoolean("internal", zoneInfo.Internal);
  1878. switch (zoneInfo.Type)
  1879. {
  1880. case AuthZoneType.Primary:
  1881. case AuthZoneType.Secondary:
  1882. jsonWriter.WriteString("dnssecStatus", zoneInfo.ApexZone.DnssecStatus.ToString());
  1883. break;
  1884. }
  1885. switch (zoneInfo.Type)
  1886. {
  1887. case AuthZoneType.Primary:
  1888. case AuthZoneType.Secondary:
  1889. case AuthZoneType.Forwarder:
  1890. case AuthZoneType.Catalog:
  1891. if (!zoneInfo.Internal)
  1892. {
  1893. string[] notifyFailed = zoneInfo.NotifyFailed;
  1894. jsonWriter.WriteBoolean("notifyFailed", notifyFailed.Length > 0);
  1895. jsonWriter.WritePropertyName("notifyFailedFor");
  1896. jsonWriter.WriteStartArray();
  1897. foreach (string server in notifyFailed)
  1898. jsonWriter.WriteStringValue(server);
  1899. jsonWriter.WriteEndArray();
  1900. }
  1901. break;
  1902. }
  1903. jsonWriter.WriteBoolean("disabled", zoneInfo.Disabled);
  1904. //catalog zone
  1905. switch (zoneInfo.Type)
  1906. {
  1907. case AuthZoneType.Primary:
  1908. case AuthZoneType.Forwarder:
  1909. jsonWriter.WriteString("catalog", zoneInfo.CatalogZoneName);
  1910. if (zoneInfo.CatalogZoneName is not null)
  1911. {
  1912. jsonWriter.WriteBoolean("overrideCatalogQueryAccess", zoneInfo.OverrideCatalogQueryAccess);
  1913. jsonWriter.WriteBoolean("overrideCatalogZoneTransfer", zoneInfo.OverrideCatalogZoneTransfer);
  1914. jsonWriter.WriteBoolean("overrideCatalogNotify", zoneInfo.OverrideCatalogNotify);
  1915. }
  1916. break;
  1917. case AuthZoneType.Stub:
  1918. jsonWriter.WriteString("catalog", zoneInfo.CatalogZoneName);
  1919. if (zoneInfo.CatalogZoneName is not null)
  1920. {
  1921. jsonWriter.WriteBoolean("isSecondaryCatalogMember", zoneInfo.ApexZone.SecondaryCatalogZone is not null);
  1922. jsonWriter.WriteBoolean("overrideCatalogQueryAccess", zoneInfo.OverrideCatalogQueryAccess);
  1923. }
  1924. break;
  1925. case AuthZoneType.Secondary:
  1926. jsonWriter.WriteString("catalog", zoneInfo.CatalogZoneName);
  1927. if (zoneInfo.CatalogZoneName is not null)
  1928. {
  1929. jsonWriter.WriteBoolean("overrideCatalogQueryAccess", zoneInfo.OverrideCatalogQueryAccess);
  1930. jsonWriter.WriteBoolean("overrideCatalogZoneTransfer", zoneInfo.OverrideCatalogZoneTransfer);
  1931. jsonWriter.WriteBoolean("overrideCatalogPrimaryNameServers", zoneInfo.OverrideCatalogPrimaryNameServers);
  1932. }
  1933. break;
  1934. case AuthZoneType.SecondaryForwarder:
  1935. jsonWriter.WriteString("catalog", zoneInfo.CatalogZoneName);
  1936. if (zoneInfo.CatalogZoneName is not null)
  1937. jsonWriter.WriteBoolean("overrideCatalogQueryAccess", zoneInfo.OverrideCatalogQueryAccess);
  1938. break;
  1939. }
  1940. //primary server
  1941. switch (zoneInfo.Type)
  1942. {
  1943. case AuthZoneType.Secondary:
  1944. case AuthZoneType.SecondaryForwarder:
  1945. case AuthZoneType.SecondaryCatalog:
  1946. case AuthZoneType.Stub:
  1947. jsonWriter.WriteStartArray("primaryNameServerAddresses");
  1948. IReadOnlyList<NameServerAddress> primaryNameServerAddresses = zoneInfo.PrimaryNameServerAddresses;
  1949. if (primaryNameServerAddresses is not null)
  1950. {
  1951. foreach (NameServerAddress primaryNameServerAddress in primaryNameServerAddresses)
  1952. jsonWriter.WriteStringValue(primaryNameServerAddress.OriginalAddress);
  1953. }
  1954. jsonWriter.WriteEndArray();
  1955. break;
  1956. }
  1957. switch (zoneInfo.Type)
  1958. {
  1959. case AuthZoneType.Secondary:
  1960. case AuthZoneType.SecondaryForwarder:
  1961. case AuthZoneType.SecondaryCatalog:
  1962. if (zoneInfo.PrimaryZoneTransferProtocol == DnsTransportProtocol.Udp)
  1963. jsonWriter.WriteString("primaryZoneTransferProtocol", "Tcp");
  1964. else
  1965. jsonWriter.WriteString("primaryZoneTransferProtocol", zoneInfo.PrimaryZoneTransferProtocol.ToString());
  1966. jsonWriter.WriteString("primaryZoneTransferTsigKeyName", zoneInfo.PrimaryZoneTransferTsigKeyName);
  1967. break;
  1968. }
  1969. if (zoneInfo.Type == AuthZoneType.Secondary)
  1970. jsonWriter.WriteBoolean("validateZone", zoneInfo.ValidateZone);
  1971. //query access
  1972. {
  1973. jsonWriter.WriteString("queryAccess", zoneInfo.QueryAccess.ToString());
  1974. jsonWriter.WriteStartArray("queryAccessNetworkACL");
  1975. if (zoneInfo.QueryAccessNetworkACL is not null)
  1976. {
  1977. foreach (NetworkAccessControl nac in zoneInfo.QueryAccessNetworkACL)
  1978. jsonWriter.WriteStringValue(nac.ToString());
  1979. }
  1980. jsonWriter.WriteEndArray();
  1981. }
  1982. //zone transfer
  1983. switch (zoneInfo.Type)
  1984. {
  1985. case AuthZoneType.Primary:
  1986. case AuthZoneType.Secondary:
  1987. case AuthZoneType.Forwarder:
  1988. case AuthZoneType.Catalog:
  1989. case AuthZoneType.SecondaryCatalog:
  1990. jsonWriter.WriteString("zoneTransfer", zoneInfo.ZoneTransfer.ToString());
  1991. jsonWriter.WritePropertyName("zoneTransferNetworkACL");
  1992. {
  1993. jsonWriter.WriteStartArray();
  1994. if (zoneInfo.ZoneTransferNetworkACL is not null)
  1995. {
  1996. foreach (NetworkAccessControl nac in zoneInfo.ZoneTransferNetworkACL)
  1997. jsonWriter.WriteStringValue(nac.ToString());
  1998. }
  1999. jsonWriter.WriteEndArray();
  2000. }
  2001. jsonWriter.WritePropertyName("zoneTransferTsigKeyNames");
  2002. {
  2003. jsonWriter.WriteStartArray();
  2004. if (zoneInfo.ZoneTransferTsigKeyNames is not null)
  2005. {
  2006. foreach (KeyValuePair<string, object> tsigKeyName in zoneInfo.ZoneTransferTsigKeyNames)
  2007. jsonWriter.WriteStringValue(tsigKeyName.Key);
  2008. }
  2009. jsonWriter.WriteEndArray();
  2010. }
  2011. break;
  2012. }
  2013. //notify
  2014. switch (zoneInfo.Type)
  2015. {
  2016. case AuthZoneType.Primary:
  2017. case AuthZoneType.Secondary:
  2018. case AuthZoneType.Forwarder:
  2019. case AuthZoneType.Catalog:
  2020. jsonWriter.WriteString("notify", zoneInfo.Notify.ToString());
  2021. jsonWriter.WritePropertyName("notifyNameServers");
  2022. {
  2023. jsonWriter.WriteStartArray();
  2024. if (zoneInfo.NotifyNameServers is not null)
  2025. {
  2026. foreach (IPAddress nameServer in zoneInfo.NotifyNameServers)
  2027. jsonWriter.WriteStringValue(nameServer.ToString());
  2028. }
  2029. jsonWriter.WriteEndArray();
  2030. }
  2031. if (zoneInfo.Type == AuthZoneType.Catalog)
  2032. {
  2033. jsonWriter.WriteStartArray("notifySecondaryCatalogsNameServers");
  2034. if (zoneInfo.NotifySecondaryCatalogNameServers is not null)
  2035. {
  2036. foreach (IPAddress nameServer in zoneInfo.NotifySecondaryCatalogNameServers)
  2037. jsonWriter.WriteStringValue(nameServer.ToString());
  2038. }
  2039. jsonWriter.WriteEndArray();
  2040. }
  2041. break;
  2042. }
  2043. //update
  2044. switch (zoneInfo.Type)
  2045. {
  2046. case AuthZoneType.Primary:
  2047. case AuthZoneType.Secondary:
  2048. case AuthZoneType.SecondaryForwarder:
  2049. case AuthZoneType.Forwarder:
  2050. jsonWriter.WriteString("update", zoneInfo.Update.ToString());
  2051. jsonWriter.WritePropertyName("updateNetworkACL");
  2052. {
  2053. jsonWriter.WriteStartArray();
  2054. if (zoneInfo.UpdateNetworkACL is not null)
  2055. {
  2056. foreach (NetworkAccessControl nac in zoneInfo.UpdateNetworkACL)
  2057. jsonWriter.WriteStringValue(nac.ToString());
  2058. }
  2059. jsonWriter.WriteEndArray();
  2060. }
  2061. break;
  2062. }
  2063. switch (zoneInfo.Type)
  2064. {
  2065. case AuthZoneType.Primary:
  2066. case AuthZoneType.Forwarder:
  2067. jsonWriter.WritePropertyName("updateSecurityPolicies");
  2068. {
  2069. jsonWriter.WriteStartArray();
  2070. if (zoneInfo.UpdateSecurityPolicies is not null)
  2071. {
  2072. foreach (KeyValuePair<string, IReadOnlyDictionary<string, IReadOnlyList<DnsResourceRecordType>>> updateSecurityPolicy in zoneInfo.UpdateSecurityPolicies)
  2073. {
  2074. foreach (KeyValuePair<string, IReadOnlyList<DnsResourceRecordType>> policy in updateSecurityPolicy.Value)
  2075. {
  2076. jsonWriter.WriteStartObject();
  2077. jsonWriter.WriteString("tsigKeyName", updateSecurityPolicy.Key);
  2078. jsonWriter.WriteString("domain", policy.Key);
  2079. jsonWriter.WritePropertyName("allowedTypes");
  2080. jsonWriter.WriteStartArray();
  2081. foreach (DnsResourceRecordType allowedType in policy.Value)
  2082. jsonWriter.WriteStringValue(allowedType.ToString());
  2083. jsonWriter.WriteEndArray();
  2084. jsonWriter.WriteEndObject();
  2085. }
  2086. }
  2087. }
  2088. jsonWriter.WriteEndArray();
  2089. }
  2090. break;
  2091. }
  2092. if (includeAvailableCatalogZoneNames)
  2093. {
  2094. IReadOnlyList<AuthZoneInfo> catalogZoneInfoList = _dnsWebService.DnsServer.AuthZoneManager.GetCatalogZones(delegate (AuthZoneInfo catalogZoneInfo)
  2095. {
  2096. return !catalogZoneInfo.Disabled && _dnsWebService._authManager.IsPermitted(PermissionSection.Zones, catalogZoneInfo.Name, session.User, PermissionFlag.Modify);
  2097. });
  2098. jsonWriter.WritePropertyName("availableCatalogZoneNames");
  2099. jsonWriter.WriteStartArray();
  2100. foreach (AuthZoneInfo catalogZoneInfo in catalogZoneInfoList)
  2101. jsonWriter.WriteStringValue(catalogZoneInfo.Name);
  2102. jsonWriter.WriteEndArray();
  2103. }
  2104. if (includeAvailableTsigKeyNames)
  2105. {
  2106. jsonWriter.WritePropertyName("availableTsigKeyNames");
  2107. {
  2108. jsonWriter.WriteStartArray();
  2109. if (_dnsWebService.DnsServer.TsigKeys is not null)
  2110. {
  2111. foreach (KeyValuePair<string, TsigKey> tsigKey in _dnsWebService.DnsServer.TsigKeys)
  2112. jsonWriter.WriteStringValue(tsigKey.Key);
  2113. }
  2114. jsonWriter.WriteEndArray();
  2115. }
  2116. }
  2117. }
  2118. public void SetZoneOptions(HttpContext context)
  2119. {
  2120. UserSession session = context.GetCurrentSession();
  2121. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  2122. throw new DnsWebServiceException("Access was denied.");
  2123. HttpRequest request = context.Request;
  2124. string zoneName = request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.');
  2125. if (DnsClient.IsDomainNameUnicode(zoneName))
  2126. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  2127. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName);
  2128. if (zoneInfo is null)
  2129. throw new DnsWebServiceException("No such zone was found: " + zoneName);
  2130. if (zoneInfo.Internal)
  2131. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  2132. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete))
  2133. throw new DnsWebServiceException("Access was denied.");
  2134. if (request.TryGetQueryOrForm("disabled", bool.Parse, out bool disabled))
  2135. zoneInfo.Disabled = disabled;
  2136. //catalog zone override options
  2137. switch (zoneInfo.Type)
  2138. {
  2139. case AuthZoneType.Primary:
  2140. case AuthZoneType.Forwarder:
  2141. {
  2142. if (request.TryGetQueryOrForm("overrideCatalogQueryAccess", bool.Parse, out bool overrideCatalogQueryAccess))
  2143. zoneInfo.OverrideCatalogQueryAccess = overrideCatalogQueryAccess;
  2144. if (request.TryGetQueryOrForm("overrideCatalogZoneTransfer", bool.Parse, out bool overrideCatalogZoneTransfer))
  2145. zoneInfo.OverrideCatalogZoneTransfer = overrideCatalogZoneTransfer;
  2146. if (request.TryGetQueryOrForm("overrideCatalogNotify", bool.Parse, out bool overrideCatalogNotify))
  2147. zoneInfo.OverrideCatalogNotify = overrideCatalogNotify;
  2148. }
  2149. break;
  2150. case AuthZoneType.Stub:
  2151. {
  2152. if (zoneInfo.ApexZone.SecondaryCatalogZone is not null)
  2153. break; //cannot set option for Stub zone that is a member of Secondary Catalog Zone
  2154. if (request.TryGetQueryOrForm("overrideCatalogQueryAccess", bool.Parse, out bool overrideCatalogQueryAccess))
  2155. zoneInfo.OverrideCatalogQueryAccess = overrideCatalogQueryAccess;
  2156. }
  2157. break;
  2158. }
  2159. //primary server
  2160. switch (zoneInfo.Type)
  2161. {
  2162. case AuthZoneType.Secondary:
  2163. case AuthZoneType.SecondaryForwarder:
  2164. case AuthZoneType.SecondaryCatalog:
  2165. {
  2166. if (zoneInfo.ApexZone.SecondaryCatalogZone is not null)
  2167. break; //cannot set option for zone that is a member of Secondary Catalog Zone
  2168. if (request.TryGetQueryOrFormEnum("primaryZoneTransferProtocol", out DnsTransportProtocol primaryZoneTransferProtocol))
  2169. {
  2170. if (primaryZoneTransferProtocol == DnsTransportProtocol.Quic)
  2171. DnsWebService.ValidateQuicSupport();
  2172. zoneInfo.PrimaryZoneTransferProtocol = primaryZoneTransferProtocol;
  2173. }
  2174. string primaryNameServerAddresses = request.QueryOrForm("primaryNameServerAddresses");
  2175. if (primaryNameServerAddresses is not null)
  2176. {
  2177. if (primaryNameServerAddresses.Length == 0)
  2178. {
  2179. zoneInfo.PrimaryNameServerAddresses = null;
  2180. }
  2181. else
  2182. {
  2183. zoneInfo.PrimaryNameServerAddresses = primaryNameServerAddresses.Split(delegate (string address)
  2184. {
  2185. NameServerAddress nameServer = NameServerAddress.Parse(address);
  2186. if (nameServer.Protocol != primaryZoneTransferProtocol)
  2187. nameServer = nameServer.ChangeProtocol(primaryZoneTransferProtocol);
  2188. return nameServer;
  2189. }, ',');
  2190. }
  2191. }
  2192. string primaryZoneTransferTsigKeyName = request.QueryOrForm("primaryZoneTransferTsigKeyName");
  2193. if (primaryZoneTransferTsigKeyName is not null)
  2194. {
  2195. if (primaryZoneTransferTsigKeyName.Length == 0)
  2196. zoneInfo.PrimaryZoneTransferTsigKeyName = null;
  2197. else
  2198. zoneInfo.PrimaryZoneTransferTsigKeyName = primaryZoneTransferTsigKeyName;
  2199. }
  2200. }
  2201. break;
  2202. case AuthZoneType.Stub:
  2203. {
  2204. if (zoneInfo.ApexZone.SecondaryCatalogZone is not null)
  2205. break; //cannot set option for Stub zone that is a member of Secondary Catalog Zone
  2206. string primaryNameServerAddresses = request.QueryOrForm("primaryNameServerAddresses");
  2207. if (primaryNameServerAddresses is not null)
  2208. {
  2209. if (primaryNameServerAddresses.Length == 0)
  2210. {
  2211. zoneInfo.PrimaryNameServerAddresses = null;
  2212. }
  2213. else
  2214. {
  2215. zoneInfo.PrimaryNameServerAddresses = primaryNameServerAddresses.Split(delegate (string address)
  2216. {
  2217. NameServerAddress nameServer = NameServerAddress.Parse(address);
  2218. if (nameServer.Protocol != DnsTransportProtocol.Udp)
  2219. nameServer = nameServer.ChangeProtocol(DnsTransportProtocol.Udp);
  2220. return nameServer;
  2221. }, ',');
  2222. }
  2223. }
  2224. }
  2225. break;
  2226. }
  2227. if (zoneInfo.Type == AuthZoneType.Secondary)
  2228. {
  2229. if (zoneInfo.ApexZone.SecondaryCatalogZone is not null)
  2230. {
  2231. //cannot set option for zone that is a member of Secondary Catalog Zone
  2232. }
  2233. else if (request.TryGetQueryOrForm("validateZone", bool.Parse, out bool validateZone))
  2234. {
  2235. zoneInfo.ValidateZone = validateZone;
  2236. }
  2237. }
  2238. //query access
  2239. switch (zoneInfo.Type)
  2240. {
  2241. case AuthZoneType.Primary:
  2242. case AuthZoneType.Secondary:
  2243. case AuthZoneType.Stub:
  2244. case AuthZoneType.Forwarder:
  2245. case AuthZoneType.SecondaryForwarder:
  2246. case AuthZoneType.Catalog:
  2247. if (zoneInfo.ApexZone.SecondaryCatalogZone is not null)
  2248. break; //cannot set option for zone that is a member of Secondary Catalog Zone
  2249. string queryAccessNetworkACL = request.QueryOrForm("queryAccessNetworkACL");
  2250. if (queryAccessNetworkACL is not null)
  2251. {
  2252. if ((queryAccessNetworkACL.Length == 0) || queryAccessNetworkACL.Equals("false", StringComparison.OrdinalIgnoreCase))
  2253. zoneInfo.QueryAccessNetworkACL = null;
  2254. else
  2255. zoneInfo.QueryAccessNetworkACL = queryAccessNetworkACL.Split(NetworkAccessControl.Parse, ',');
  2256. }
  2257. if (request.TryGetQueryOrFormEnum("queryAccess", out AuthZoneQueryAccess queryAccess))
  2258. zoneInfo.QueryAccess = queryAccess;
  2259. break;
  2260. }
  2261. //zone transfer
  2262. switch (zoneInfo.Type)
  2263. {
  2264. case AuthZoneType.Primary:
  2265. case AuthZoneType.Secondary:
  2266. case AuthZoneType.Forwarder:
  2267. case AuthZoneType.Catalog:
  2268. if (zoneInfo.ApexZone.SecondaryCatalogZone is not null)
  2269. break; //cannot set option for zone that is a member of Secondary Catalog Zone
  2270. string strZoneTransferNetworkACL = request.QueryOrForm("zoneTransferNetworkACL");
  2271. if (strZoneTransferNetworkACL is not null)
  2272. {
  2273. if ((strZoneTransferNetworkACL.Length == 0) || strZoneTransferNetworkACL.Equals("false", StringComparison.OrdinalIgnoreCase))
  2274. zoneInfo.ZoneTransferNetworkACL = null;
  2275. else
  2276. zoneInfo.ZoneTransferNetworkACL = strZoneTransferNetworkACL.Split(NetworkAccessControl.Parse, ',');
  2277. }
  2278. if (request.TryGetQueryOrFormEnum("zoneTransfer", out AuthZoneTransfer zoneTransfer))
  2279. zoneInfo.ZoneTransfer = zoneTransfer;
  2280. string strZoneTransferTsigKeyNames = request.QueryOrForm("zoneTransferTsigKeyNames");
  2281. if (strZoneTransferTsigKeyNames is not null)
  2282. {
  2283. if ((strZoneTransferTsigKeyNames.Length == 0) || strZoneTransferTsigKeyNames.Equals("false", StringComparison.OrdinalIgnoreCase))
  2284. {
  2285. zoneInfo.ZoneTransferTsigKeyNames = null;
  2286. }
  2287. else
  2288. {
  2289. string[] strZoneTransferTsigKeyNamesParts = strZoneTransferTsigKeyNames.Split(_commaSeparator, StringSplitOptions.RemoveEmptyEntries);
  2290. Dictionary<string, object> zoneTransferTsigKeyNames = new Dictionary<string, object>(strZoneTransferTsigKeyNamesParts.Length);
  2291. for (int i = 0; i < strZoneTransferTsigKeyNamesParts.Length; i++)
  2292. zoneTransferTsigKeyNames.Add(strZoneTransferTsigKeyNamesParts[i].TrimEnd('.').ToLowerInvariant(), null);
  2293. zoneInfo.ZoneTransferTsigKeyNames = zoneTransferTsigKeyNames;
  2294. }
  2295. }
  2296. break;
  2297. }
  2298. //notify
  2299. switch (zoneInfo.Type)
  2300. {
  2301. case AuthZoneType.Primary:
  2302. case AuthZoneType.Secondary:
  2303. case AuthZoneType.Forwarder:
  2304. case AuthZoneType.Catalog:
  2305. if (request.TryGetQueryOrFormEnum("notify", out AuthZoneNotify notify))
  2306. zoneInfo.Notify = notify;
  2307. string strNotifyNameServers = request.QueryOrForm("notifyNameServers");
  2308. if (strNotifyNameServers is not null)
  2309. {
  2310. if ((strNotifyNameServers.Length == 0) || strNotifyNameServers.Equals("false", StringComparison.OrdinalIgnoreCase))
  2311. zoneInfo.NotifyNameServers = null;
  2312. else
  2313. zoneInfo.NotifyNameServers = strNotifyNameServers.Split(IPAddress.Parse, ',');
  2314. }
  2315. if (zoneInfo.Type == AuthZoneType.Catalog)
  2316. {
  2317. string strNotifySecondaryCatalogNameServers = request.QueryOrForm("notifySecondaryCatalogsNameServers");
  2318. if (strNotifySecondaryCatalogNameServers is not null)
  2319. {
  2320. if ((strNotifySecondaryCatalogNameServers.Length == 0) || strNotifySecondaryCatalogNameServers.Equals("false", StringComparison.OrdinalIgnoreCase))
  2321. zoneInfo.NotifySecondaryCatalogNameServers = null;
  2322. else
  2323. zoneInfo.NotifySecondaryCatalogNameServers = strNotifySecondaryCatalogNameServers.Split(IPAddress.Parse, ',');
  2324. }
  2325. }
  2326. break;
  2327. }
  2328. //update
  2329. switch (zoneInfo.Type)
  2330. {
  2331. case AuthZoneType.Primary:
  2332. case AuthZoneType.Secondary:
  2333. case AuthZoneType.SecondaryForwarder:
  2334. case AuthZoneType.Forwarder:
  2335. if (request.TryGetQueryOrFormEnum("update", out AuthZoneUpdate update))
  2336. zoneInfo.Update = update;
  2337. string strUpdateNetworkACL = request.QueryOrForm("updateNetworkACL");
  2338. if (strUpdateNetworkACL is not null)
  2339. {
  2340. if ((strUpdateNetworkACL.Length == 0) || strUpdateNetworkACL.Equals("false", StringComparison.OrdinalIgnoreCase))
  2341. zoneInfo.UpdateNetworkACL = null;
  2342. else
  2343. zoneInfo.UpdateNetworkACL = strUpdateNetworkACL.Split(NetworkAccessControl.Parse, ',');
  2344. }
  2345. break;
  2346. }
  2347. switch (zoneInfo.Type)
  2348. {
  2349. case AuthZoneType.Primary:
  2350. case AuthZoneType.Forwarder:
  2351. string strUpdateSecurityPolicies = request.QueryOrForm("updateSecurityPolicies");
  2352. if (strUpdateSecurityPolicies is not null)
  2353. {
  2354. if ((strUpdateSecurityPolicies.Length == 0) || strUpdateSecurityPolicies.Equals("false", StringComparison.OrdinalIgnoreCase))
  2355. {
  2356. zoneInfo.UpdateSecurityPolicies = null;
  2357. }
  2358. else
  2359. {
  2360. string[] strUpdateSecurityPoliciesParts = strUpdateSecurityPolicies.Split(_pipeSeparator, StringSplitOptions.RemoveEmptyEntries);
  2361. Dictionary<string, IReadOnlyDictionary<string, IReadOnlyList<DnsResourceRecordType>>> updateSecurityPolicies = new Dictionary<string, IReadOnlyDictionary<string, IReadOnlyList<DnsResourceRecordType>>>(strUpdateSecurityPoliciesParts.Length);
  2362. for (int i = 0; i < strUpdateSecurityPoliciesParts.Length; i += 3)
  2363. {
  2364. string tsigKeyName = strUpdateSecurityPoliciesParts[i].TrimEnd('.').ToLowerInvariant();
  2365. string domain = strUpdateSecurityPoliciesParts[i + 1].TrimEnd('.').ToLowerInvariant();
  2366. string strTypes = strUpdateSecurityPoliciesParts[i + 2];
  2367. if (!domain.Equals(zoneInfo.Name, StringComparison.OrdinalIgnoreCase) && !domain.EndsWith("." + zoneInfo.Name, StringComparison.OrdinalIgnoreCase))
  2368. throw new DnsWebServiceException("Cannot set Dynamic Updates security policies: the domain '" + domain + "' must be part of the current zone.");
  2369. if (!updateSecurityPolicies.TryGetValue(tsigKeyName, out IReadOnlyDictionary<string, IReadOnlyList<DnsResourceRecordType>> policyMap))
  2370. {
  2371. policyMap = new Dictionary<string, IReadOnlyList<DnsResourceRecordType>>();
  2372. updateSecurityPolicies.Add(tsigKeyName, policyMap);
  2373. }
  2374. if (!policyMap.TryGetValue(domain, out IReadOnlyList<DnsResourceRecordType> types))
  2375. {
  2376. types = new List<DnsResourceRecordType>();
  2377. (policyMap as Dictionary<string, IReadOnlyList<DnsResourceRecordType>>).Add(domain, types);
  2378. }
  2379. foreach (string strType in strTypes.Split(_commaSpaceSeparator, StringSplitOptions.RemoveEmptyEntries))
  2380. (types as List<DnsResourceRecordType>).Add(Enum.Parse<DnsResourceRecordType>(strType, true));
  2381. }
  2382. zoneInfo.UpdateSecurityPolicies = updateSecurityPolicies;
  2383. }
  2384. }
  2385. break;
  2386. }
  2387. //catalog zone; done last to allow using updated properties when there is change of ownership
  2388. switch (zoneInfo.Type)
  2389. {
  2390. case AuthZoneType.Primary:
  2391. case AuthZoneType.Stub:
  2392. case AuthZoneType.Forwarder:
  2393. if (zoneInfo.ApexZone.SecondaryCatalogZone is not null)
  2394. break; //cannot set option for Stub zone that is a member of Secondary Catalog Zone
  2395. string catalogZoneName = request.QueryOrForm("catalog");
  2396. if (catalogZoneName is not null)
  2397. {
  2398. string oldCatalogZoneName = zoneInfo.CatalogZoneName;
  2399. if (catalogZoneName.Length == 0)
  2400. {
  2401. if (!string.IsNullOrEmpty(oldCatalogZoneName))
  2402. _dnsWebService.DnsServer.AuthZoneManager.RemoveCatalogMemberZone(zoneInfo);
  2403. }
  2404. else
  2405. {
  2406. if (string.IsNullOrEmpty(oldCatalogZoneName))
  2407. {
  2408. //check catalog permissions
  2409. AuthZoneInfo catalogZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(catalogZoneName);
  2410. if (catalogZoneInfo is null)
  2411. throw new DnsWebServiceException("No such Catalog zone was found: " + catalogZoneName);
  2412. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, catalogZoneInfo.Name, session.User, PermissionFlag.Modify))
  2413. throw new DnsWebServiceException("Access was denied to use Catalog zone: " + catalogZoneInfo.Name);
  2414. _dnsWebService.DnsServer.AuthZoneManager.AddCatalogMemberZone(catalogZoneName, zoneInfo);
  2415. }
  2416. else if (!catalogZoneName.Equals(oldCatalogZoneName, StringComparison.OrdinalIgnoreCase))
  2417. {
  2418. //check catalog permissions
  2419. AuthZoneInfo catalogZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(catalogZoneName);
  2420. if (catalogZoneInfo is null)
  2421. throw new DnsWebServiceException("No such Catalog zone was found: " + catalogZoneName);
  2422. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, catalogZoneInfo.Name, session.User, PermissionFlag.Modify))
  2423. throw new DnsWebServiceException("Access was denied to use Catalog zone: " + catalogZoneInfo.Name);
  2424. _dnsWebService.DnsServer.AuthZoneManager.ChangeCatalogMemberZoneOwnership(zoneInfo, catalogZoneName);
  2425. }
  2426. }
  2427. }
  2428. if (zoneInfo.ApexZone.CatalogZone is not null)
  2429. _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.ApexZone.CatalogZoneName);
  2430. break;
  2431. }
  2432. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] " + zoneInfo.TypeName + " zone options were updated successfully: " + zoneInfo.DisplayName);
  2433. _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
  2434. }
  2435. public void ResyncZone(HttpContext context)
  2436. {
  2437. UserSession session = context.GetCurrentSession();
  2438. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  2439. throw new DnsWebServiceException("Access was denied.");
  2440. string zoneName = context.Request.GetQueryOrFormAlt("zone", "domain").TrimEnd('.');
  2441. if (DnsClient.IsDomainNameUnicode(zoneName))
  2442. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  2443. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(zoneName);
  2444. if (zoneInfo is null)
  2445. throw new DnsWebServiceException("No such zone was found: " + zoneName);
  2446. if (zoneInfo.Internal)
  2447. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  2448. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify))
  2449. throw new DnsWebServiceException("Access was denied.");
  2450. switch (zoneInfo.Type)
  2451. {
  2452. case AuthZoneType.Secondary:
  2453. case AuthZoneType.SecondaryForwarder:
  2454. case AuthZoneType.SecondaryCatalog:
  2455. case AuthZoneType.Stub:
  2456. zoneInfo.TriggerResync();
  2457. break;
  2458. default:
  2459. throw new DnsWebServiceException("Only Secondary, Secondary Forwarder, Secondary Catalog, and Stub zones support resync.");
  2460. }
  2461. }
  2462. public void AddRecord(HttpContext context)
  2463. {
  2464. HttpRequest request = context.Request;
  2465. string domain = request.GetQueryOrForm("domain").TrimEnd('.');
  2466. if (DnsClient.IsDomainNameUnicode(domain))
  2467. domain = DnsClient.ConvertDomainNameToAscii(domain);
  2468. string zoneName = request.QueryOrForm("zone");
  2469. if (zoneName is not null)
  2470. {
  2471. zoneName = zoneName.TrimEnd('.');
  2472. if (DnsClient.IsDomainNameUnicode(zoneName))
  2473. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  2474. }
  2475. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName);
  2476. if (zoneInfo is null)
  2477. throw new DnsWebServiceException("No such zone was found: " + domain);
  2478. if (zoneInfo.Internal)
  2479. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  2480. UserSession session = context.GetCurrentSession();
  2481. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify))
  2482. throw new DnsWebServiceException("Access was denied.");
  2483. DnsResourceRecordType type = request.GetQueryOrFormEnum<DnsResourceRecordType>("type");
  2484. uint ttl = request.GetQueryOrForm("ttl", uint.Parse, _defaultRecordTtl);
  2485. bool overwrite = request.GetQueryOrForm("overwrite", bool.Parse, false);
  2486. string comments = request.QueryOrForm("comments");
  2487. uint expiryTtl = request.GetQueryOrForm("expiryTtl", uint.Parse, 0u);
  2488. DnsResourceRecord newRecord;
  2489. switch (type)
  2490. {
  2491. case DnsResourceRecordType.A:
  2492. case DnsResourceRecordType.AAAA:
  2493. {
  2494. string strIPAddress = request.GetQueryOrFormAlt("ipAddress", "value");
  2495. IPAddress ipAddress;
  2496. if (strIPAddress.Equals("request-ip-address"))
  2497. ipAddress = context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader).Address;
  2498. else
  2499. ipAddress = IPAddress.Parse(strIPAddress);
  2500. bool ptr = request.GetQueryOrForm("ptr", bool.Parse, false);
  2501. if (ptr)
  2502. {
  2503. string ptrDomain = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 32 : 128);
  2504. AuthZoneInfo reverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain);
  2505. if (reverseZoneInfo is null)
  2506. {
  2507. bool createPtrZone = request.GetQueryOrForm("createPtrZone", bool.Parse, false);
  2508. if (!createPtrZone)
  2509. throw new DnsWebServiceException("No reverse zone available to add PTR record.");
  2510. string ptrZone = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 24 : 64);
  2511. reverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone);
  2512. if (reverseZoneInfo == null)
  2513. throw new DnsWebServiceException("Failed to create reverse zone to add PTR record: " + ptrZone);
  2514. //set permissions
  2515. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete);
  2516. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  2517. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, reverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  2518. _dnsWebService._authManager.SaveConfigFile();
  2519. }
  2520. if (reverseZoneInfo.Internal)
  2521. throw new DnsWebServiceException("Reverse zone '" + reverseZoneInfo.DisplayName + "' is an internal zone.");
  2522. if ((reverseZoneInfo.Type != AuthZoneType.Primary) && (reverseZoneInfo.Type != AuthZoneType.Forwarder))
  2523. throw new DnsWebServiceException("Reverse zone '" + reverseZoneInfo.DisplayName + "' is not a primary or forwarder zone.");
  2524. DnsResourceRecord ptrRecord = new DnsResourceRecord(ptrDomain, DnsResourceRecordType.PTR, DnsClass.IN, ttl, new DnsPTRRecordData(domain));
  2525. ptrRecord.GetAuthGenericRecordInfo().LastModified = DateTime.UtcNow;
  2526. ptrRecord.GetAuthGenericRecordInfo().ExpiryTtl = expiryTtl;
  2527. _dnsWebService.DnsServer.AuthZoneManager.SetRecord(reverseZoneInfo.Name, ptrRecord);
  2528. _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name);
  2529. }
  2530. if (type == DnsResourceRecordType.A)
  2531. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsARecordData(ipAddress));
  2532. else
  2533. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsAAAARecordData(ipAddress));
  2534. }
  2535. break;
  2536. case DnsResourceRecordType.NS:
  2537. {
  2538. string nameServer = request.GetQueryOrFormAlt("nameServer", "value").TrimEnd('.');
  2539. string glueAddresses = request.GetQueryOrForm("glue", null);
  2540. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsNSRecordData(nameServer));
  2541. if (!string.IsNullOrEmpty(glueAddresses))
  2542. newRecord.SetGlueRecords(glueAddresses);
  2543. }
  2544. break;
  2545. case DnsResourceRecordType.CNAME:
  2546. {
  2547. if (!overwrite)
  2548. {
  2549. IReadOnlyList<DnsResourceRecord> existingRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type);
  2550. if (existingRecords.Count > 0)
  2551. throw new DnsWebServiceException("Record already exists. Use overwrite option if you wish to overwrite existing record.");
  2552. }
  2553. string cname = request.GetQueryOrFormAlt("cname", "value").TrimEnd('.');
  2554. if (cname.Equals(domain, StringComparison.OrdinalIgnoreCase))
  2555. throw new DnsWebServiceException("CNAME domain name cannot be same as that of the record name.");
  2556. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsCNAMERecordData(cname));
  2557. overwrite = true; //force SetRecord
  2558. }
  2559. break;
  2560. case DnsResourceRecordType.PTR:
  2561. {
  2562. string ptrName = request.GetQueryOrFormAlt("ptrName", "value").TrimEnd('.');
  2563. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsPTRRecordData(ptrName));
  2564. }
  2565. break;
  2566. case DnsResourceRecordType.MX:
  2567. {
  2568. ushort preference = request.GetQueryOrForm("preference", ushort.Parse);
  2569. string exchange = request.GetQueryOrFormAlt("exchange", "value").TrimEnd('.');
  2570. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsMXRecordData(preference, exchange));
  2571. }
  2572. break;
  2573. case DnsResourceRecordType.TXT:
  2574. {
  2575. string text = request.GetQueryOrFormAlt("text", "value");
  2576. bool splitText = request.GetQueryOrForm("splitText", bool.Parse, false);
  2577. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, splitText ? new DnsTXTRecordData(DecodeCharacterStrings(text)) : new DnsTXTRecordData(text));
  2578. }
  2579. break;
  2580. case DnsResourceRecordType.RP:
  2581. {
  2582. string mailbox = request.GetQueryOrForm("mailbox", "").TrimEnd('.');
  2583. string txtDomain = request.GetQueryOrForm("txtDomain", "").TrimEnd('.');
  2584. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsRPRecordData(mailbox, txtDomain));
  2585. }
  2586. break;
  2587. case DnsResourceRecordType.SRV:
  2588. {
  2589. ushort priority = request.GetQueryOrForm("priority", ushort.Parse);
  2590. ushort weight = request.GetQueryOrForm("weight", ushort.Parse);
  2591. ushort port = request.GetQueryOrForm("port", ushort.Parse);
  2592. string target = request.GetQueryOrFormAlt("target", "value").TrimEnd('.');
  2593. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSRVRecordData(priority, weight, port, target));
  2594. }
  2595. break;
  2596. case DnsResourceRecordType.NAPTR:
  2597. {
  2598. ushort order = request.GetQueryOrForm("naptrOrder", ushort.Parse);
  2599. ushort preference = request.GetQueryOrForm("naptrPreference", ushort.Parse);
  2600. string flags = request.GetQueryOrForm("naptrFlags", "");
  2601. string services = request.GetQueryOrForm("naptrServices", "");
  2602. string regexp = request.GetQueryOrForm("naptrRegexp", "");
  2603. string replacement = request.GetQueryOrForm("naptrReplacement", "").TrimEnd('.');
  2604. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsNAPTRRecordData(order, preference, flags, services, regexp, replacement));
  2605. }
  2606. break;
  2607. case DnsResourceRecordType.DNAME:
  2608. {
  2609. if (!overwrite)
  2610. {
  2611. IReadOnlyList<DnsResourceRecord> existingRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type);
  2612. if (existingRecords.Count > 0)
  2613. throw new DnsWebServiceException("Record already exists. Use overwrite option if you wish to overwrite existing record.");
  2614. }
  2615. string dname = request.GetQueryOrFormAlt("dname", "value").TrimEnd('.');
  2616. if (dname.EndsWith("." + domain, StringComparison.OrdinalIgnoreCase))
  2617. throw new DnsWebServiceException("DNAME domain name cannot be a sub domain of the record name.");
  2618. if (dname.Equals(domain, StringComparison.OrdinalIgnoreCase))
  2619. throw new DnsWebServiceException("DNAME domain name cannot be same as that of the record name.");
  2620. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsDNAMERecordData(dname));
  2621. overwrite = true; //force SetRecord
  2622. }
  2623. break;
  2624. case DnsResourceRecordType.DS:
  2625. {
  2626. ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse);
  2627. DnssecAlgorithm algorithm = Enum.Parse<DnssecAlgorithm>(request.GetQueryOrForm("algorithm").Replace('-', '_'), true);
  2628. DnssecDigestType digestType = Enum.Parse<DnssecDigestType>(request.GetQueryOrForm("digestType").Replace('-', '_'), true);
  2629. byte[] digest = request.GetQueryOrFormAlt("digest", "value", Convert.FromHexString);
  2630. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsDSRecordData(keyTag, algorithm, digestType, digest));
  2631. }
  2632. break;
  2633. case DnsResourceRecordType.SSHFP:
  2634. {
  2635. DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrFormEnum<DnsSSHFPAlgorithm>("sshfpAlgorithm");
  2636. DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrFormEnum<DnsSSHFPFingerprintType>("sshfpFingerprintType");
  2637. byte[] sshfpFingerprint = request.GetQueryOrForm("sshfpFingerprint", Convert.FromHexString);
  2638. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint));
  2639. }
  2640. break;
  2641. case DnsResourceRecordType.TLSA:
  2642. {
  2643. DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse<DnsTLSACertificateUsage>(request.GetQueryOrForm("tlsaCertificateUsage").Replace('-', '_'), true);
  2644. DnsTLSASelector tlsaSelector = request.GetQueryOrFormEnum<DnsTLSASelector>("tlsaSelector");
  2645. DnsTLSAMatchingType tlsaMatchingType = Enum.Parse<DnsTLSAMatchingType>(request.GetQueryOrForm("tlsaMatchingType").Replace('-', '_'), true);
  2646. string tlsaCertificateAssociationData = request.GetQueryOrForm("tlsaCertificateAssociationData");
  2647. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsTLSARecordData(tlsaCertificateUsage, tlsaSelector, tlsaMatchingType, tlsaCertificateAssociationData));
  2648. }
  2649. break;
  2650. case DnsResourceRecordType.SVCB:
  2651. case DnsResourceRecordType.HTTPS:
  2652. {
  2653. ushort svcPriority = request.GetQueryOrForm("svcPriority", ushort.Parse);
  2654. string targetName = request.GetQueryOrForm("svcTargetName").TrimEnd('.');
  2655. string strSvcParams = request.GetQueryOrForm("svcParams");
  2656. bool autoIpv4Hint = request.GetQueryOrForm("autoIpv4Hint", bool.Parse, false);
  2657. bool autoIpv6Hint = request.GetQueryOrForm("autoIpv6Hint", bool.Parse, false);
  2658. Dictionary<DnsSvcParamKey, DnsSvcParamValue> svcParams;
  2659. if (strSvcParams.Equals("false", StringComparison.OrdinalIgnoreCase))
  2660. {
  2661. svcParams = new Dictionary<DnsSvcParamKey, DnsSvcParamValue>(0);
  2662. }
  2663. else
  2664. {
  2665. string[] strSvcParamsParts = strSvcParams.Split('|');
  2666. svcParams = new Dictionary<DnsSvcParamKey, DnsSvcParamValue>(strSvcParamsParts.Length / 2);
  2667. for (int i = 0; i < strSvcParamsParts.Length; i += 2)
  2668. {
  2669. DnsSvcParamKey svcParamKey = Enum.Parse<DnsSvcParamKey>(strSvcParamsParts[i].Replace('-', '_'), true);
  2670. DnsSvcParamValue svcParamValue = DnsSvcParamValue.Parse(svcParamKey, strSvcParamsParts[i + 1]);
  2671. svcParams.Add(svcParamKey, svcParamValue);
  2672. }
  2673. }
  2674. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSVCBRecordData(svcPriority, targetName, svcParams));
  2675. if (autoIpv4Hint)
  2676. newRecord.GetAuthSVCBRecordInfo().AutoIpv4Hint = true;
  2677. if (autoIpv6Hint)
  2678. newRecord.GetAuthSVCBRecordInfo().AutoIpv6Hint = true;
  2679. if (autoIpv4Hint || autoIpv6Hint)
  2680. ResolveSvcbAutoHints(zoneInfo.Name, newRecord, autoIpv4Hint, autoIpv6Hint, svcParams);
  2681. }
  2682. break;
  2683. case DnsResourceRecordType.URI:
  2684. {
  2685. ushort priority = request.GetQueryOrForm("uriPriority", ushort.Parse);
  2686. ushort weight = request.GetQueryOrForm("uriWeight", ushort.Parse);
  2687. Uri uri = request.GetQueryOrForm("uri", delegate (string value) { return new Uri(value); });
  2688. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsURIRecordData(priority, weight, uri));
  2689. }
  2690. break;
  2691. case DnsResourceRecordType.CAA:
  2692. {
  2693. byte flags = request.GetQueryOrForm("flags", byte.Parse);
  2694. string tag = request.GetQueryOrForm("tag");
  2695. string value = request.GetQueryOrForm("value");
  2696. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsCAARecordData(flags, tag, value));
  2697. }
  2698. break;
  2699. case DnsResourceRecordType.ANAME:
  2700. {
  2701. string aname = request.GetQueryOrFormAlt("aname", "value").TrimEnd('.');
  2702. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsANAMERecordData(aname));
  2703. }
  2704. break;
  2705. case DnsResourceRecordType.FWD:
  2706. {
  2707. DnsTransportProtocol protocol = request.GetQueryOrFormEnum("protocol", DnsTransportProtocol.Udp);
  2708. string forwarder = request.GetQueryOrFormAlt("forwarder", "value");
  2709. bool dnssecValidation = request.GetQueryOrForm("dnssecValidation", bool.Parse, false);
  2710. DnsForwarderRecordProxyType proxyType = DnsForwarderRecordProxyType.DefaultProxy;
  2711. string proxyAddress = null;
  2712. ushort proxyPort = 0;
  2713. string proxyUsername = null;
  2714. string proxyPassword = null;
  2715. if (!forwarder.Equals("this-server"))
  2716. {
  2717. proxyType = request.GetQueryOrFormEnum("proxyType", DnsForwarderRecordProxyType.DefaultProxy);
  2718. switch (proxyType)
  2719. {
  2720. case DnsForwarderRecordProxyType.Http:
  2721. case DnsForwarderRecordProxyType.Socks5:
  2722. proxyAddress = request.GetQueryOrForm("proxyAddress");
  2723. proxyPort = request.GetQueryOrForm("proxyPort", ushort.Parse);
  2724. proxyUsername = request.QueryOrForm("proxyUsername");
  2725. proxyPassword = request.QueryOrForm("proxyPassword");
  2726. break;
  2727. }
  2728. }
  2729. byte priority = request.GetQueryOrForm("forwarderPriority", byte.Parse, byte.MinValue);
  2730. if (protocol == DnsTransportProtocol.Quic)
  2731. DnsWebService.ValidateQuicSupport();
  2732. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsForwarderRecordData(protocol, forwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword, priority));
  2733. }
  2734. break;
  2735. case DnsResourceRecordType.APP:
  2736. {
  2737. if (!overwrite)
  2738. {
  2739. IReadOnlyList<DnsResourceRecord> existingRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(zoneInfo.Name, domain, type);
  2740. if (existingRecords.Count > 0)
  2741. throw new DnsWebServiceException("Record already exists. Use overwrite option if you wish to overwrite existing record.");
  2742. }
  2743. string appName = request.GetQueryOrFormAlt("appName", "value");
  2744. string classPath = request.GetQueryOrForm("classPath");
  2745. string recordData = request.GetQueryOrForm("recordData", "");
  2746. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsApplicationRecordData(appName, classPath, recordData));
  2747. overwrite = true; //force SetRecord
  2748. }
  2749. break;
  2750. default:
  2751. {
  2752. string strRData = request.GetQueryOrForm("rdata");
  2753. byte[] rdata;
  2754. if (strRData.Contains(':'))
  2755. rdata = strRData.ParseColonHexString();
  2756. else
  2757. rdata = Convert.FromHexString(strRData);
  2758. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, DnsResourceRecord.ReadRecordDataFrom(type, rdata));
  2759. }
  2760. break;
  2761. }
  2762. //update record info
  2763. GenericRecordInfo recordInfo = newRecord.GetAuthGenericRecordInfo();
  2764. recordInfo.LastModified = DateTime.UtcNow;
  2765. recordInfo.ExpiryTtl = expiryTtl;
  2766. if (!string.IsNullOrEmpty(comments))
  2767. recordInfo.Comments = comments;
  2768. //add record
  2769. if (overwrite)
  2770. _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord);
  2771. else
  2772. _dnsWebService.DnsServer.AuthZoneManager.AddRecord(zoneInfo.Name, newRecord);
  2773. //additional processing
  2774. if ((type == DnsResourceRecordType.A) || (type == DnsResourceRecordType.AAAA))
  2775. {
  2776. bool updateSvcbHints = request.GetQueryOrForm("updateSvcbHints", bool.Parse, false);
  2777. if (updateSvcbHints)
  2778. UpdateSvcbAutoHints(zoneInfo.Name, domain, type == DnsResourceRecordType.A, type == DnsResourceRecordType.AAAA);
  2779. }
  2780. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] New record was added to " + zoneInfo.TypeName + " zone '" + zoneInfo.DisplayName + "' successfully {record: " + newRecord.ToString() + "}");
  2781. //save zone
  2782. _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
  2783. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  2784. jsonWriter.WritePropertyName("zone");
  2785. WriteZoneInfoAsJson(zoneInfo, jsonWriter);
  2786. jsonWriter.WritePropertyName("addedRecord");
  2787. WriteRecordAsJson(newRecord, jsonWriter, true, null);
  2788. }
  2789. public void GetRecords(HttpContext context)
  2790. {
  2791. HttpRequest request = context.Request;
  2792. string domain = request.GetQueryOrForm("domain").TrimEnd('.');
  2793. if (DnsClient.IsDomainNameUnicode(domain))
  2794. domain = DnsClient.ConvertDomainNameToAscii(domain);
  2795. string zoneName = request.QueryOrForm("zone");
  2796. if (zoneName is not null)
  2797. {
  2798. zoneName = zoneName.TrimEnd('.');
  2799. if (DnsClient.IsDomainNameUnicode(zoneName))
  2800. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  2801. }
  2802. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName);
  2803. if (zoneInfo is null)
  2804. throw new DnsWebServiceException("No such zone was found: " + domain);
  2805. UserSession session = context.GetCurrentSession();
  2806. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.View))
  2807. throw new DnsWebServiceException("Access was denied.");
  2808. bool listZone = request.GetQueryOrForm("listZone", bool.Parse, false);
  2809. List<DnsResourceRecord> records = new List<DnsResourceRecord>();
  2810. if (listZone)
  2811. _dnsWebService.DnsServer.AuthZoneManager.ListAllZoneRecords(zoneInfo.Name, records);
  2812. else
  2813. _dnsWebService.DnsServer.AuthZoneManager.ListAllRecords(zoneInfo.Name, domain, records);
  2814. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  2815. jsonWriter.WritePropertyName("zone");
  2816. WriteZoneInfoAsJson(zoneInfo, jsonWriter);
  2817. WriteRecordsAsJson(records, jsonWriter, true, zoneInfo);
  2818. }
  2819. public void DeleteRecord(HttpContext context)
  2820. {
  2821. HttpRequest request = context.Request;
  2822. string domain = request.GetQueryOrForm("domain").TrimEnd('.');
  2823. if (DnsClient.IsDomainNameUnicode(domain))
  2824. domain = DnsClient.ConvertDomainNameToAscii(domain);
  2825. string zoneName = request.QueryOrForm("zone");
  2826. if (zoneName is not null)
  2827. {
  2828. zoneName = zoneName.TrimEnd('.');
  2829. if (DnsClient.IsDomainNameUnicode(zoneName))
  2830. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  2831. }
  2832. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName);
  2833. if (zoneInfo is null)
  2834. throw new DnsWebServiceException("No such zone was found: " + domain);
  2835. if (zoneInfo.Internal)
  2836. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  2837. UserSession session = context.GetCurrentSession();
  2838. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Delete))
  2839. throw new DnsWebServiceException("Access was denied.");
  2840. DnsResourceRecordType type = request.GetQueryOrFormEnum<DnsResourceRecordType>("type");
  2841. switch (type)
  2842. {
  2843. case DnsResourceRecordType.A:
  2844. case DnsResourceRecordType.AAAA:
  2845. {
  2846. IPAddress ipAddress = IPAddress.Parse(request.GetQueryOrFormAlt("ipAddress", "value"));
  2847. if (type == DnsResourceRecordType.A)
  2848. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsARecordData(ipAddress));
  2849. else
  2850. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsAAAARecordData(ipAddress));
  2851. string ptrDomain = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 32 : 128);
  2852. AuthZoneInfo reverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(ptrDomain);
  2853. if ((reverseZoneInfo is not null) && !reverseZoneInfo.Internal && ((reverseZoneInfo.Type == AuthZoneType.Primary) || (reverseZoneInfo.Type == AuthZoneType.Forwarder)))
  2854. {
  2855. IReadOnlyList<DnsResourceRecord> ptrRecords = _dnsWebService.DnsServer.AuthZoneManager.GetRecords(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR);
  2856. if (ptrRecords.Count > 0)
  2857. {
  2858. foreach (DnsResourceRecord ptrRecord in ptrRecords)
  2859. {
  2860. if ((ptrRecord.RDATA as DnsPTRRecordData).Domain.Equals(domain, StringComparison.OrdinalIgnoreCase))
  2861. {
  2862. //delete PTR record and save reverse zone
  2863. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(reverseZoneInfo.Name, ptrDomain, DnsResourceRecordType.PTR, ptrRecord.RDATA);
  2864. _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name);
  2865. break;
  2866. }
  2867. }
  2868. }
  2869. }
  2870. bool updateSvcbHints = request.GetQueryOrForm("updateSvcbHints", bool.Parse, false);
  2871. if (updateSvcbHints)
  2872. UpdateSvcbAutoHints(zoneInfo.Name, domain, type == DnsResourceRecordType.A, type == DnsResourceRecordType.AAAA);
  2873. }
  2874. break;
  2875. case DnsResourceRecordType.NS:
  2876. {
  2877. string nameServer = request.GetQueryOrFormAlt("nameServer", "value").TrimEnd('.');
  2878. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsNSRecordData(nameServer, false));
  2879. }
  2880. break;
  2881. case DnsResourceRecordType.CNAME:
  2882. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type);
  2883. break;
  2884. case DnsResourceRecordType.PTR:
  2885. {
  2886. string ptrName = request.GetQueryOrFormAlt("ptrName", "value").TrimEnd('.');
  2887. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsPTRRecordData(ptrName));
  2888. }
  2889. break;
  2890. case DnsResourceRecordType.MX:
  2891. {
  2892. ushort preference = request.GetQueryOrForm("preference", ushort.Parse);
  2893. string exchange = request.GetQueryOrFormAlt("exchange", "value").TrimEnd('.');
  2894. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsMXRecordData(preference, exchange));
  2895. }
  2896. break;
  2897. case DnsResourceRecordType.TXT:
  2898. {
  2899. string text = request.GetQueryOrFormAlt("text", "value");
  2900. bool splitText = request.GetQueryOrForm("splitText", bool.Parse, false);
  2901. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, splitText ? new DnsTXTRecordData(DecodeCharacterStrings(text)) : new DnsTXTRecordData(text));
  2902. }
  2903. break;
  2904. case DnsResourceRecordType.RP:
  2905. {
  2906. string mailbox = request.GetQueryOrForm("mailbox", "").TrimEnd('.');
  2907. string txtDomain = request.GetQueryOrForm("txtDomain", "").TrimEnd('.');
  2908. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsRPRecordData(mailbox, txtDomain));
  2909. }
  2910. break;
  2911. case DnsResourceRecordType.SRV:
  2912. {
  2913. ushort priority = request.GetQueryOrForm("priority", ushort.Parse);
  2914. ushort weight = request.GetQueryOrForm("weight", ushort.Parse);
  2915. ushort port = request.GetQueryOrForm("port", ushort.Parse);
  2916. string target = request.GetQueryOrFormAlt("target", "value").TrimEnd('.');
  2917. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSRVRecordData(priority, weight, port, target));
  2918. }
  2919. break;
  2920. case DnsResourceRecordType.NAPTR:
  2921. {
  2922. ushort order = request.GetQueryOrForm("naptrOrder", ushort.Parse);
  2923. ushort preference = request.GetQueryOrForm("naptrPreference", ushort.Parse);
  2924. string flags = request.GetQueryOrForm("naptrFlags", "");
  2925. string services = request.GetQueryOrForm("naptrServices", "");
  2926. string regexp = request.GetQueryOrForm("naptrRegexp", "");
  2927. string replacement = request.GetQueryOrForm("naptrReplacement", "").TrimEnd('.');
  2928. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsNAPTRRecordData(order, preference, flags, services, regexp, replacement));
  2929. }
  2930. break;
  2931. case DnsResourceRecordType.DNAME:
  2932. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type);
  2933. break;
  2934. case DnsResourceRecordType.DS:
  2935. {
  2936. ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse);
  2937. DnssecAlgorithm algorithm = Enum.Parse<DnssecAlgorithm>(request.GetQueryOrForm("algorithm").Replace('-', '_'), true);
  2938. DnssecDigestType digestType = Enum.Parse<DnssecDigestType>(request.GetQueryOrForm("digestType").Replace('-', '_'), true);
  2939. byte[] digest = Convert.FromHexString(request.GetQueryOrFormAlt("digest", "value"));
  2940. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsDSRecordData(keyTag, algorithm, digestType, digest));
  2941. }
  2942. break;
  2943. case DnsResourceRecordType.SSHFP:
  2944. {
  2945. DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrFormEnum<DnsSSHFPAlgorithm>("sshfpAlgorithm");
  2946. DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrFormEnum<DnsSSHFPFingerprintType>("sshfpFingerprintType");
  2947. byte[] sshfpFingerprint = request.GetQueryOrForm("sshfpFingerprint", Convert.FromHexString);
  2948. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint));
  2949. }
  2950. break;
  2951. case DnsResourceRecordType.TLSA:
  2952. {
  2953. DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse<DnsTLSACertificateUsage>(request.GetQueryOrForm("tlsaCertificateUsage").Replace('-', '_'), true);
  2954. DnsTLSASelector tlsaSelector = request.GetQueryOrFormEnum<DnsTLSASelector>("tlsaSelector");
  2955. DnsTLSAMatchingType tlsaMatchingType = Enum.Parse<DnsTLSAMatchingType>(request.GetQueryOrForm("tlsaMatchingType").Replace('-', '_'), true);
  2956. string tlsaCertificateAssociationData = request.GetQueryOrForm("tlsaCertificateAssociationData");
  2957. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsTLSARecordData(tlsaCertificateUsage, tlsaSelector, tlsaMatchingType, tlsaCertificateAssociationData));
  2958. }
  2959. break;
  2960. case DnsResourceRecordType.SVCB:
  2961. case DnsResourceRecordType.HTTPS:
  2962. {
  2963. ushort svcPriority = request.GetQueryOrForm("svcPriority", ushort.Parse);
  2964. string targetName = request.GetQueryOrForm("svcTargetName").TrimEnd('.');
  2965. string strSvcParams = request.GetQueryOrForm("svcParams");
  2966. Dictionary<DnsSvcParamKey, DnsSvcParamValue> svcParams;
  2967. if (strSvcParams.Equals("false", StringComparison.OrdinalIgnoreCase))
  2968. {
  2969. svcParams = new Dictionary<DnsSvcParamKey, DnsSvcParamValue>(0);
  2970. }
  2971. else
  2972. {
  2973. string[] strSvcParamsParts = strSvcParams.Split('|');
  2974. svcParams = new Dictionary<DnsSvcParamKey, DnsSvcParamValue>(strSvcParamsParts.Length / 2);
  2975. for (int i = 0; i < strSvcParamsParts.Length; i += 2)
  2976. {
  2977. DnsSvcParamKey svcParamKey = Enum.Parse<DnsSvcParamKey>(strSvcParamsParts[i].Replace('-', '_'), true);
  2978. DnsSvcParamValue svcParamValue = DnsSvcParamValue.Parse(svcParamKey, strSvcParamsParts[i + 1]);
  2979. svcParams.Add(svcParamKey, svcParamValue);
  2980. }
  2981. }
  2982. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsSVCBRecordData(svcPriority, targetName, svcParams));
  2983. }
  2984. break;
  2985. case DnsResourceRecordType.URI:
  2986. {
  2987. ushort priority = request.GetQueryOrForm("uriPriority", ushort.Parse);
  2988. ushort weight = request.GetQueryOrForm("uriWeight", ushort.Parse);
  2989. Uri uri = request.GetQueryOrForm("uri", delegate (string value) { return new Uri(value); });
  2990. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsURIRecordData(priority, weight, uri));
  2991. }
  2992. break;
  2993. case DnsResourceRecordType.CAA:
  2994. {
  2995. byte flags = request.GetQueryOrForm("flags", byte.Parse);
  2996. string tag = request.GetQueryOrForm("tag");
  2997. string value = request.GetQueryOrForm("value");
  2998. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsCAARecordData(flags, tag, value));
  2999. }
  3000. break;
  3001. case DnsResourceRecordType.ANAME:
  3002. {
  3003. string aname = request.GetQueryOrFormAlt("aname", "value").TrimEnd('.');
  3004. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsANAMERecordData(aname));
  3005. }
  3006. break;
  3007. case DnsResourceRecordType.FWD:
  3008. {
  3009. DnsTransportProtocol protocol = request.GetQueryOrFormEnum("protocol", DnsTransportProtocol.Udp);
  3010. string forwarder = request.GetQueryOrFormAlt("forwarder", "value");
  3011. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, DnsForwarderRecordData.CreatePartialRecordData(protocol, forwarder));
  3012. }
  3013. break;
  3014. case DnsResourceRecordType.APP:
  3015. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(zoneInfo.Name, domain, type);
  3016. break;
  3017. default:
  3018. {
  3019. string strRData = request.GetQueryOrForm("rdata", string.Empty);
  3020. byte[] rdata;
  3021. if (strRData.Contains(':'))
  3022. rdata = strRData.ParseColonHexString();
  3023. else
  3024. rdata = Convert.FromHexString(strRData);
  3025. if (!_dnsWebService.DnsServer.AuthZoneManager.DeleteRecord(zoneInfo.Name, domain, type, new DnsUnknownRecordData(rdata)))
  3026. throw new DnsWebServiceException("Failed to delete the record.");
  3027. }
  3028. break;
  3029. }
  3030. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Record was deleted from " + zoneInfo.TypeName + " zone '" + zoneInfo.DisplayName + "' successfully {domain: " + domain + "; type: " + type + ";}");
  3031. _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
  3032. }
  3033. public void UpdateRecord(HttpContext context)
  3034. {
  3035. HttpRequest request = context.Request;
  3036. string domain = request.GetQueryOrForm("domain").TrimEnd('.');
  3037. if (DnsClient.IsDomainNameUnicode(domain))
  3038. domain = DnsClient.ConvertDomainNameToAscii(domain);
  3039. string zoneName = request.QueryOrForm("zone");
  3040. if (zoneName is not null)
  3041. {
  3042. zoneName = zoneName.TrimEnd('.');
  3043. if (DnsClient.IsDomainNameUnicode(zoneName))
  3044. zoneName = DnsClient.ConvertDomainNameToAscii(zoneName);
  3045. }
  3046. AuthZoneInfo zoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(string.IsNullOrEmpty(zoneName) ? domain : zoneName);
  3047. if (zoneInfo is null)
  3048. throw new DnsWebServiceException("No such zone was found: " + domain);
  3049. if (zoneInfo.Internal)
  3050. throw new DnsWebServiceException("Access was denied to manage internal DNS Server zone.");
  3051. UserSession session = context.GetCurrentSession();
  3052. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, zoneInfo.Name, session.User, PermissionFlag.Modify))
  3053. throw new DnsWebServiceException("Access was denied.");
  3054. string newDomain = request.GetQueryOrForm("newDomain", domain).TrimEnd('.');
  3055. uint ttl = request.GetQueryOrForm("ttl", uint.Parse, _defaultRecordTtl);
  3056. bool disable = request.GetQueryOrForm("disable", bool.Parse, false);
  3057. string comments = request.QueryOrForm("comments");
  3058. uint expiryTtl = request.GetQueryOrForm("expiryTtl", uint.Parse, 0u);
  3059. DnsResourceRecordType type = request.GetQueryOrFormEnum<DnsResourceRecordType>("type");
  3060. DnsResourceRecord oldRecord = null;
  3061. DnsResourceRecord newRecord;
  3062. switch (type)
  3063. {
  3064. case DnsResourceRecordType.A:
  3065. case DnsResourceRecordType.AAAA:
  3066. {
  3067. IPAddress ipAddress = IPAddress.Parse(request.GetQueryOrFormAlt("ipAddress", "value"));
  3068. IPAddress newIpAddress = IPAddress.Parse(request.GetQueryOrFormAlt("newIpAddress", "newValue", ipAddress.ToString()));
  3069. bool ptr = request.GetQueryOrForm("ptr", bool.Parse, false);
  3070. if (ptr)
  3071. {
  3072. string newPtrDomain = Zone.GetReverseZone(newIpAddress, type == DnsResourceRecordType.A ? 32 : 128);
  3073. AuthZoneInfo newReverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(newPtrDomain);
  3074. if (newReverseZoneInfo is null)
  3075. {
  3076. bool createPtrZone = request.GetQueryOrForm("createPtrZone", bool.Parse, false);
  3077. if (!createPtrZone)
  3078. throw new DnsWebServiceException("No reverse zone available to add PTR record.");
  3079. string ptrZone = Zone.GetReverseZone(newIpAddress, type == DnsResourceRecordType.A ? 24 : 64);
  3080. newReverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.CreatePrimaryZone(ptrZone);
  3081. if (newReverseZoneInfo is null)
  3082. throw new DnsWebServiceException("Failed to create reverse zone to add PTR record: " + ptrZone);
  3083. //set permissions
  3084. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, newReverseZoneInfo.Name, session.User, PermissionFlag.ViewModifyDelete);
  3085. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, newReverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  3086. _dnsWebService._authManager.SetPermission(PermissionSection.Zones, newReverseZoneInfo.Name, _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS), PermissionFlag.ViewModifyDelete);
  3087. _dnsWebService._authManager.SaveConfigFile();
  3088. }
  3089. if (newReverseZoneInfo.Internal)
  3090. throw new DnsWebServiceException("Reverse zone '" + newReverseZoneInfo.DisplayName + "' is an internal zone.");
  3091. if ((newReverseZoneInfo.Type != AuthZoneType.Primary) && (newReverseZoneInfo.Type != AuthZoneType.Forwarder))
  3092. throw new DnsWebServiceException("Reverse zone '" + newReverseZoneInfo.DisplayName + "' is not a primary or forwarder zone.");
  3093. string oldPtrDomain = Zone.GetReverseZone(ipAddress, type == DnsResourceRecordType.A ? 32 : 128);
  3094. AuthZoneInfo oldReverseZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.FindAuthZoneInfo(oldPtrDomain);
  3095. if ((oldReverseZoneInfo is not null) && !oldReverseZoneInfo.Internal && ((oldReverseZoneInfo.Type == AuthZoneType.Primary) || (oldReverseZoneInfo.Type == AuthZoneType.Forwarder)))
  3096. {
  3097. //delete old PTR record if any and save old reverse zone
  3098. _dnsWebService.DnsServer.AuthZoneManager.DeleteRecords(oldReverseZoneInfo.Name, oldPtrDomain, DnsResourceRecordType.PTR);
  3099. _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(oldReverseZoneInfo.Name);
  3100. }
  3101. //add new PTR record and save reverse zone
  3102. DnsResourceRecord ptrRecord = new DnsResourceRecord(newPtrDomain, DnsResourceRecordType.PTR, DnsClass.IN, ttl, new DnsPTRRecordData(domain));
  3103. ptrRecord.GetAuthGenericRecordInfo().LastModified = DateTime.UtcNow;
  3104. ptrRecord.GetAuthGenericRecordInfo().ExpiryTtl = expiryTtl;
  3105. _dnsWebService.DnsServer.AuthZoneManager.SetRecord(newReverseZoneInfo.Name, ptrRecord);
  3106. _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(newReverseZoneInfo.Name);
  3107. }
  3108. if (type == DnsResourceRecordType.A)
  3109. {
  3110. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsARecordData(ipAddress));
  3111. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsARecordData(newIpAddress));
  3112. }
  3113. else
  3114. {
  3115. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsAAAARecordData(ipAddress));
  3116. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsAAAARecordData(newIpAddress));
  3117. }
  3118. }
  3119. break;
  3120. case DnsResourceRecordType.NS:
  3121. {
  3122. string nameServer = request.GetQueryOrFormAlt("nameServer", "value").TrimEnd('.');
  3123. string newNameServer = request.GetQueryOrFormAlt("newNameServer", "newValue", nameServer).TrimEnd('.');
  3124. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsNSRecordData(nameServer));
  3125. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsNSRecordData(newNameServer));
  3126. if (request.TryGetQueryOrForm("glue", out string glueAddresses))
  3127. newRecord.SetGlueRecords(glueAddresses);
  3128. }
  3129. break;
  3130. case DnsResourceRecordType.CNAME:
  3131. {
  3132. string cname = request.GetQueryOrFormAlt("cname", "value").TrimEnd('.');
  3133. if (cname.Equals(newDomain, StringComparison.OrdinalIgnoreCase))
  3134. throw new DnsWebServiceException("CNAME domain name cannot be same as that of the record name.");
  3135. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCNAMERecordData(cname));
  3136. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCNAMERecordData(cname));
  3137. }
  3138. break;
  3139. case DnsResourceRecordType.SOA:
  3140. {
  3141. string primaryNameServer = request.GetQueryOrForm("primaryNameServer").TrimEnd('.');
  3142. string responsiblePerson = request.GetQueryOrForm("responsiblePerson").TrimEnd('.');
  3143. uint serial = request.GetQueryOrForm("serial", uint.Parse);
  3144. uint refresh = request.GetQueryOrForm("refresh", uint.Parse);
  3145. uint retry = request.GetQueryOrForm("retry", uint.Parse);
  3146. uint expire = request.GetQueryOrForm("expire", uint.Parse);
  3147. uint minimum = request.GetQueryOrForm("minimum", uint.Parse);
  3148. newRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSOARecordData(primaryNameServer, responsiblePerson, serial, refresh, retry, expire, minimum));
  3149. switch (zoneInfo.Type)
  3150. {
  3151. case AuthZoneType.Primary:
  3152. case AuthZoneType.Forwarder:
  3153. case AuthZoneType.Catalog:
  3154. {
  3155. if (request.TryGetQueryOrForm("useSerialDateScheme", bool.Parse, out bool useSerialDateScheme))
  3156. newRecord.GetAuthSOARecordInfo().UseSoaSerialDateScheme = useSerialDateScheme;
  3157. }
  3158. break;
  3159. }
  3160. }
  3161. break;
  3162. case DnsResourceRecordType.PTR:
  3163. {
  3164. string ptrName = request.GetQueryOrFormAlt("ptrName", "value").TrimEnd('.');
  3165. string newPtrName = request.GetQueryOrFormAlt("newPtrName", "newValue", ptrName).TrimEnd('.');
  3166. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsPTRRecordData(ptrName));
  3167. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsPTRRecordData(newPtrName));
  3168. }
  3169. break;
  3170. case DnsResourceRecordType.MX:
  3171. {
  3172. ushort preference = request.GetQueryOrForm("preference", ushort.Parse);
  3173. ushort newPreference = request.GetQueryOrForm("newPreference", ushort.Parse, preference);
  3174. string exchange = request.GetQueryOrFormAlt("exchange", "value").TrimEnd('.');
  3175. string newExchange = request.GetQueryOrFormAlt("newExchange", "newValue", exchange).TrimEnd('.');
  3176. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsMXRecordData(preference, exchange));
  3177. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsMXRecordData(newPreference, newExchange));
  3178. }
  3179. break;
  3180. case DnsResourceRecordType.TXT:
  3181. {
  3182. string text = request.GetQueryOrFormAlt("text", "value");
  3183. string newText = request.GetQueryOrFormAlt("newText", "newValue", text);
  3184. bool splitText = request.GetQueryOrForm("splitText", bool.Parse, false);
  3185. bool newSplitText = request.GetQueryOrForm("newSplitText", bool.Parse, splitText);
  3186. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, splitText ? new DnsTXTRecordData(DecodeCharacterStrings(text)) : new DnsTXTRecordData(text));
  3187. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, newSplitText ? new DnsTXTRecordData(DecodeCharacterStrings(newText)) : new DnsTXTRecordData(newText));
  3188. }
  3189. break;
  3190. case DnsResourceRecordType.RP:
  3191. {
  3192. string mailbox = request.GetQueryOrForm("mailbox", "").TrimEnd('.');
  3193. string newMailbox = request.GetQueryOrForm("newMailbox", mailbox).TrimEnd('.');
  3194. string txtDomain = request.GetQueryOrForm("txtDomain", "").TrimEnd('.');
  3195. string newTxtDomain = request.GetQueryOrForm("newTxtDomain", txtDomain).TrimEnd('.');
  3196. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsRPRecordData(mailbox, txtDomain));
  3197. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsRPRecordData(newMailbox, newTxtDomain));
  3198. }
  3199. break;
  3200. case DnsResourceRecordType.SRV:
  3201. {
  3202. ushort priority = request.GetQueryOrForm("priority", ushort.Parse);
  3203. ushort newPriority = request.GetQueryOrForm("newPriority", ushort.Parse, priority);
  3204. ushort weight = request.GetQueryOrForm("weight", ushort.Parse);
  3205. ushort newWeight = request.GetQueryOrForm("newWeight", ushort.Parse, weight);
  3206. ushort port = request.GetQueryOrForm("port", ushort.Parse);
  3207. ushort newPort = request.GetQueryOrForm("newPort", ushort.Parse, port);
  3208. string target = request.GetQueryOrFormAlt("target", "value").TrimEnd('.');
  3209. string newTarget = request.GetQueryOrFormAlt("newTarget", "newValue", target).TrimEnd('.');
  3210. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsSRVRecordData(priority, weight, port, target));
  3211. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsSRVRecordData(newPriority, newWeight, newPort, newTarget));
  3212. }
  3213. break;
  3214. case DnsResourceRecordType.NAPTR:
  3215. {
  3216. ushort order = request.GetQueryOrForm("naptrOrder", ushort.Parse);
  3217. ushort newOrder = request.GetQueryOrForm("naptrNewOrder", ushort.Parse, order);
  3218. ushort preference = request.GetQueryOrForm("naptrPreference", ushort.Parse);
  3219. ushort newPreference = request.GetQueryOrForm("naptrNewPreference", ushort.Parse, preference);
  3220. string flags = request.GetQueryOrForm("naptrFlags", "");
  3221. string newFlags = request.GetQueryOrForm("naptrNewFlags", flags);
  3222. string services = request.GetQueryOrForm("naptrServices", "");
  3223. string newServices = request.GetQueryOrForm("naptrNewServices", services);
  3224. string regexp = request.GetQueryOrForm("naptrRegexp", "");
  3225. string newRegexp = request.GetQueryOrForm("naptrNewRegexp", regexp);
  3226. string replacement = request.GetQueryOrForm("naptrReplacement", "").TrimEnd('.');
  3227. string newReplacement = request.GetQueryOrForm("naptrNewReplacement", replacement).TrimEnd('.');
  3228. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsNAPTRRecordData(order, preference, flags, services, regexp, replacement));
  3229. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsNAPTRRecordData(newOrder, newPreference, newFlags, newServices, newRegexp, newReplacement));
  3230. }
  3231. break;
  3232. case DnsResourceRecordType.DNAME:
  3233. {
  3234. string dname = request.GetQueryOrFormAlt("dname", "value").TrimEnd('.');
  3235. if (dname.EndsWith("." + newDomain, StringComparison.OrdinalIgnoreCase))
  3236. throw new DnsWebServiceException("DNAME domain name cannot be a sub domain of the record name.");
  3237. if (dname.Equals(newDomain, StringComparison.OrdinalIgnoreCase))
  3238. throw new DnsWebServiceException("DNAME domain name cannot be same as that of the record name.");
  3239. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsDNAMERecordData(dname));
  3240. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsDNAMERecordData(dname));
  3241. }
  3242. break;
  3243. case DnsResourceRecordType.DS:
  3244. {
  3245. ushort keyTag = request.GetQueryOrForm("keyTag", ushort.Parse);
  3246. ushort newKeyTag = request.GetQueryOrForm("newKeyTag", ushort.Parse, keyTag);
  3247. DnssecAlgorithm algorithm = Enum.Parse<DnssecAlgorithm>(request.GetQueryOrForm("algorithm").Replace('-', '_'), true);
  3248. DnssecAlgorithm newAlgorithm = Enum.Parse<DnssecAlgorithm>(request.GetQueryOrForm("newAlgorithm", algorithm.ToString()).Replace('-', '_'), true);
  3249. DnssecDigestType digestType = Enum.Parse<DnssecDigestType>(request.GetQueryOrForm("digestType").Replace('-', '_'), true);
  3250. DnssecDigestType newDigestType = Enum.Parse<DnssecDigestType>(request.GetQueryOrForm("newDigestType", digestType.ToString()).Replace('-', '_'), true);
  3251. byte[] digest = request.GetQueryOrFormAlt("digest", "value", Convert.FromHexString);
  3252. byte[] newDigest = request.GetQueryOrFormAlt("newDigest", "newValue", Convert.FromHexString, digest);
  3253. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsDSRecordData(keyTag, algorithm, digestType, digest));
  3254. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsDSRecordData(newKeyTag, newAlgorithm, newDigestType, newDigest));
  3255. }
  3256. break;
  3257. case DnsResourceRecordType.SSHFP:
  3258. {
  3259. DnsSSHFPAlgorithm sshfpAlgorithm = request.GetQueryOrFormEnum<DnsSSHFPAlgorithm>("sshfpAlgorithm");
  3260. DnsSSHFPAlgorithm newSshfpAlgorithm = request.GetQueryOrFormEnum("newSshfpAlgorithm", sshfpAlgorithm);
  3261. DnsSSHFPFingerprintType sshfpFingerprintType = request.GetQueryOrFormEnum<DnsSSHFPFingerprintType>("sshfpFingerprintType");
  3262. DnsSSHFPFingerprintType newSshfpFingerprintType = request.GetQueryOrFormEnum("newSshfpFingerprintType", sshfpFingerprintType);
  3263. byte[] sshfpFingerprint = request.GetQueryOrForm("sshfpFingerprint", Convert.FromHexString);
  3264. byte[] newSshfpFingerprint = request.GetQueryOrForm("newSshfpFingerprint", Convert.FromHexString, sshfpFingerprint);
  3265. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsSSHFPRecordData(sshfpAlgorithm, sshfpFingerprintType, sshfpFingerprint));
  3266. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsSSHFPRecordData(newSshfpAlgorithm, newSshfpFingerprintType, newSshfpFingerprint));
  3267. }
  3268. break;
  3269. case DnsResourceRecordType.TLSA:
  3270. {
  3271. DnsTLSACertificateUsage tlsaCertificateUsage = Enum.Parse<DnsTLSACertificateUsage>(request.GetQueryOrForm("tlsaCertificateUsage").Replace('-', '_'), true);
  3272. DnsTLSACertificateUsage newTlsaCertificateUsage = Enum.Parse<DnsTLSACertificateUsage>(request.GetQueryOrForm("newTlsaCertificateUsage", tlsaCertificateUsage.ToString()).Replace('-', '_'), true);
  3273. DnsTLSASelector tlsaSelector = request.GetQueryOrFormEnum<DnsTLSASelector>("tlsaSelector");
  3274. DnsTLSASelector newTlsaSelector = request.GetQueryOrFormEnum("newTlsaSelector", tlsaSelector);
  3275. DnsTLSAMatchingType tlsaMatchingType = Enum.Parse<DnsTLSAMatchingType>(request.GetQueryOrForm("tlsaMatchingType").Replace('-', '_'), true);
  3276. DnsTLSAMatchingType newTlsaMatchingType = Enum.Parse<DnsTLSAMatchingType>(request.GetQueryOrForm("newTlsaMatchingType", tlsaMatchingType.ToString()).Replace('-', '_'), true);
  3277. string tlsaCertificateAssociationData = request.GetQueryOrForm("tlsaCertificateAssociationData");
  3278. string newTlsaCertificateAssociationData = request.GetQueryOrForm("newTlsaCertificateAssociationData", tlsaCertificateAssociationData);
  3279. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsTLSARecordData(tlsaCertificateUsage, tlsaSelector, tlsaMatchingType, tlsaCertificateAssociationData));
  3280. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsTLSARecordData(newTlsaCertificateUsage, newTlsaSelector, newTlsaMatchingType, newTlsaCertificateAssociationData));
  3281. }
  3282. break;
  3283. case DnsResourceRecordType.SVCB:
  3284. case DnsResourceRecordType.HTTPS:
  3285. {
  3286. ushort svcPriority = request.GetQueryOrForm("svcPriority", ushort.Parse);
  3287. ushort newSvcPriority = request.GetQueryOrForm("newSvcPriority", ushort.Parse, svcPriority);
  3288. string targetName = request.GetQueryOrForm("svcTargetName").TrimEnd('.');
  3289. string newTargetName = request.GetQueryOrForm("newSvcTargetName", targetName).TrimEnd('.');
  3290. string strSvcParams = request.GetQueryOrForm("svcParams");
  3291. string strNewSvcParams = request.GetQueryOrForm("newSvcParams", strSvcParams);
  3292. bool autoIpv4Hint = request.GetQueryOrForm("autoIpv4Hint", bool.Parse, false);
  3293. bool autoIpv6Hint = request.GetQueryOrForm("autoIpv6Hint", bool.Parse, false);
  3294. Dictionary<DnsSvcParamKey, DnsSvcParamValue> svcParams;
  3295. if (strSvcParams.Equals("false", StringComparison.OrdinalIgnoreCase))
  3296. {
  3297. svcParams = new Dictionary<DnsSvcParamKey, DnsSvcParamValue>(0);
  3298. }
  3299. else
  3300. {
  3301. string[] strSvcParamsParts = strSvcParams.Split('|');
  3302. svcParams = new Dictionary<DnsSvcParamKey, DnsSvcParamValue>(strSvcParamsParts.Length / 2);
  3303. for (int i = 0; i < strSvcParamsParts.Length; i += 2)
  3304. {
  3305. DnsSvcParamKey svcParamKey = Enum.Parse<DnsSvcParamKey>(strSvcParamsParts[i].Replace('-', '_'), true);
  3306. DnsSvcParamValue svcParamValue = DnsSvcParamValue.Parse(svcParamKey, strSvcParamsParts[i + 1]);
  3307. svcParams.Add(svcParamKey, svcParamValue);
  3308. }
  3309. }
  3310. Dictionary<DnsSvcParamKey, DnsSvcParamValue> newSvcParams;
  3311. if (strNewSvcParams.Equals("false", StringComparison.OrdinalIgnoreCase))
  3312. {
  3313. newSvcParams = new Dictionary<DnsSvcParamKey, DnsSvcParamValue>(0);
  3314. }
  3315. else
  3316. {
  3317. string[] strSvcParamsParts = strNewSvcParams.Split('|');
  3318. newSvcParams = new Dictionary<DnsSvcParamKey, DnsSvcParamValue>(strSvcParamsParts.Length / 2);
  3319. for (int i = 0; i < strSvcParamsParts.Length; i += 2)
  3320. {
  3321. DnsSvcParamKey svcParamKey = Enum.Parse<DnsSvcParamKey>(strSvcParamsParts[i].Replace('-', '_'), true);
  3322. DnsSvcParamValue svcParamValue = DnsSvcParamValue.Parse(svcParamKey, strSvcParamsParts[i + 1]);
  3323. newSvcParams.Add(svcParamKey, svcParamValue);
  3324. }
  3325. }
  3326. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsSVCBRecordData(svcPriority, targetName, svcParams));
  3327. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsSVCBRecordData(newSvcPriority, newTargetName, newSvcParams));
  3328. if (autoIpv4Hint)
  3329. newRecord.GetAuthSVCBRecordInfo().AutoIpv4Hint = true;
  3330. if (autoIpv6Hint)
  3331. newRecord.GetAuthSVCBRecordInfo().AutoIpv6Hint = true;
  3332. if (autoIpv4Hint || autoIpv6Hint)
  3333. ResolveSvcbAutoHints(zoneInfo.Name, newRecord, autoIpv4Hint, autoIpv6Hint, newSvcParams);
  3334. }
  3335. break;
  3336. case DnsResourceRecordType.URI:
  3337. {
  3338. ushort priority = request.GetQueryOrForm("uriPriority", ushort.Parse);
  3339. ushort newPriority = request.GetQueryOrForm("newUriPriority", ushort.Parse, priority);
  3340. ushort weight = request.GetQueryOrForm("uriWeight", ushort.Parse);
  3341. ushort newWeight = request.GetQueryOrForm("newUriWeight", ushort.Parse, weight);
  3342. Uri uri = request.GetQueryOrForm("uri", delegate (string value) { return new Uri(value); });
  3343. Uri newUri = request.GetQueryOrForm("newUri", delegate (string value) { return new Uri(value); }, uri);
  3344. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsURIRecordData(priority, weight, uri));
  3345. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsURIRecordData(newPriority, newWeight, newUri));
  3346. }
  3347. break;
  3348. case DnsResourceRecordType.CAA:
  3349. {
  3350. byte flags = request.GetQueryOrForm("flags", byte.Parse);
  3351. byte newFlags = request.GetQueryOrForm("newFlags", byte.Parse, flags);
  3352. string tag = request.GetQueryOrForm("tag");
  3353. string newTag = request.GetQueryOrForm("newTag", tag);
  3354. string value = request.GetQueryOrForm("value");
  3355. string newValue = request.GetQueryOrForm("newValue", value);
  3356. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCAARecordData(flags, tag, value));
  3357. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCAARecordData(newFlags, newTag, newValue));
  3358. }
  3359. break;
  3360. case DnsResourceRecordType.ANAME:
  3361. {
  3362. string aname = request.GetQueryOrFormAlt("aname", "value").TrimEnd('.');
  3363. string newAName = request.GetQueryOrFormAlt("newAName", "newValue", aname).TrimEnd('.');
  3364. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsANAMERecordData(aname));
  3365. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsANAMERecordData(newAName));
  3366. }
  3367. break;
  3368. case DnsResourceRecordType.FWD:
  3369. {
  3370. DnsTransportProtocol protocol = request.GetQueryOrFormEnum("protocol", DnsTransportProtocol.Udp);
  3371. DnsTransportProtocol newProtocol = request.GetQueryOrFormEnum("newProtocol", protocol);
  3372. string forwarder = request.GetQueryOrFormAlt("forwarder", "value");
  3373. string newForwarder = request.GetQueryOrFormAlt("newForwarder", "newValue", forwarder);
  3374. bool dnssecValidation = request.GetQueryOrForm("dnssecValidation", bool.Parse, false);
  3375. DnsForwarderRecordProxyType proxyType = DnsForwarderRecordProxyType.DefaultProxy;
  3376. string proxyAddress = null;
  3377. ushort proxyPort = 0;
  3378. string proxyUsername = null;
  3379. string proxyPassword = null;
  3380. if (!newForwarder.Equals("this-server"))
  3381. {
  3382. proxyType = request.GetQueryOrFormEnum("proxyType", DnsForwarderRecordProxyType.DefaultProxy);
  3383. switch (proxyType)
  3384. {
  3385. case DnsForwarderRecordProxyType.Http:
  3386. case DnsForwarderRecordProxyType.Socks5:
  3387. proxyAddress = request.GetQueryOrForm("proxyAddress");
  3388. proxyPort = request.GetQueryOrForm("proxyPort", ushort.Parse);
  3389. proxyUsername = request.QueryOrForm("proxyUsername");
  3390. proxyPassword = request.QueryOrForm("proxyPassword");
  3391. break;
  3392. }
  3393. }
  3394. byte priority = request.GetQueryOrForm("forwarderPriority", byte.Parse, byte.MinValue);
  3395. if (newProtocol == DnsTransportProtocol.Quic)
  3396. DnsWebService.ValidateQuicSupport();
  3397. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, DnsForwarderRecordData.CreatePartialRecordData(protocol, forwarder));
  3398. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, 0, new DnsForwarderRecordData(newProtocol, newForwarder, dnssecValidation, proxyType, proxyAddress, proxyPort, proxyUsername, proxyPassword, priority));
  3399. }
  3400. break;
  3401. case DnsResourceRecordType.APP:
  3402. {
  3403. string appName = request.GetQueryOrFormAlt("appName", "value");
  3404. string classPath = request.GetQueryOrForm("classPath");
  3405. string recordData = request.GetQueryOrForm("recordData", "");
  3406. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsApplicationRecordData(appName, classPath, recordData));
  3407. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsApplicationRecordData(appName, classPath, recordData));
  3408. }
  3409. break;
  3410. default:
  3411. {
  3412. string strRData = request.GetQueryOrForm("rdata");
  3413. string strNewRData = request.GetQueryOrForm("newRData", strRData);
  3414. byte[] rdata;
  3415. if (strRData.Contains(':'))
  3416. rdata = strRData.ParseColonHexString();
  3417. else
  3418. rdata = Convert.FromHexString(strRData);
  3419. byte[] newRData;
  3420. if (strNewRData.Contains(':'))
  3421. newRData = strNewRData.ParseColonHexString();
  3422. else
  3423. newRData = Convert.FromHexString(strNewRData);
  3424. oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsUnknownRecordData(rdata));
  3425. newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsUnknownRecordData(newRData));
  3426. }
  3427. break;
  3428. }
  3429. //update record info
  3430. GenericRecordInfo recordInfo = newRecord.GetAuthGenericRecordInfo();
  3431. recordInfo.LastModified = DateTime.UtcNow;
  3432. recordInfo.ExpiryTtl = expiryTtl;
  3433. recordInfo.Disabled = disable;
  3434. recordInfo.Comments = comments;
  3435. //update record
  3436. if (type == DnsResourceRecordType.SOA)
  3437. {
  3438. //special SOA case
  3439. switch (zoneInfo.Type)
  3440. {
  3441. case AuthZoneType.Primary:
  3442. case AuthZoneType.Forwarder:
  3443. case AuthZoneType.Catalog:
  3444. _dnsWebService.DnsServer.AuthZoneManager.SetRecord(zoneInfo.Name, newRecord);
  3445. break;
  3446. }
  3447. //get updated record to return json
  3448. newRecord = zoneInfo.ApexZone.GetRecords(DnsResourceRecordType.SOA)[0];
  3449. }
  3450. else
  3451. {
  3452. _dnsWebService.DnsServer.AuthZoneManager.UpdateRecord(zoneInfo.Name, oldRecord, newRecord);
  3453. }
  3454. //additional processing
  3455. if ((type == DnsResourceRecordType.A) || (type == DnsResourceRecordType.AAAA))
  3456. {
  3457. bool updateSvcbHints = request.GetQueryOrForm("updateSvcbHints", bool.Parse, false);
  3458. if (updateSvcbHints)
  3459. UpdateSvcbAutoHints(zoneInfo.Name, newDomain, type == DnsResourceRecordType.A, type == DnsResourceRecordType.AAAA);
  3460. }
  3461. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Record was updated for " + zoneInfo.TypeName + " zone '" + zoneInfo.DisplayName + "' successfully {" + (oldRecord is null ? "" : "oldRecord: " + oldRecord.ToString() + "; ") + "newRecord: " + newRecord.ToString() + "}");
  3462. //save zone
  3463. _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
  3464. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  3465. jsonWriter.WritePropertyName("zone");
  3466. WriteZoneInfoAsJson(zoneInfo, jsonWriter);
  3467. jsonWriter.WritePropertyName("updatedRecord");
  3468. WriteRecordAsJson(newRecord, jsonWriter, true, zoneInfo);
  3469. }
  3470. #endregion
  3471. #region properties
  3472. public uint DefaultRecordTtl
  3473. {
  3474. get { return _defaultRecordTtl; }
  3475. set { _defaultRecordTtl = value; }
  3476. }
  3477. #endregion
  3478. }
  3479. }