123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470 |
- /*
- Technitium DNS Server
- Copyright (C) 2020 Shreyas Zare (shreyas@technitium.com)
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- using DnsServerCore.Dhcp;
- using DnsServerCore.Dhcp.Options;
- using DnsServerCore.Dns;
- using DnsServerCore.Dns.ResourceRecords;
- using DnsServerCore.Dns.Zones;
- using Newtonsoft.Json;
- using Newtonsoft.Json.Converters;
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.IO;
- using System.Net;
- using System.Net.Http;
- using System.Reflection;
- using System.Security.Cryptography;
- using System.Security.Cryptography.X509Certificates;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using TechnitiumLibrary.IO;
- using TechnitiumLibrary.Net;
- using TechnitiumLibrary.Net.Dns;
- using TechnitiumLibrary.Net.Dns.ResourceRecords;
- using TechnitiumLibrary.Net.Proxy;
- namespace DnsServerCore
- {
- public class WebService : IDisposable
- {
- #region enum
- enum ServiceState
- {
- Stopped = 0,
- Starting = 1,
- Running = 2,
- Stopping = 3
- }
- #endregion
- #region variables
- readonly Version _currentVersion;
- readonly string _appFolder;
- readonly string _configFolder;
- readonly Uri _updateCheckUri;
- readonly LogManager _log;
- DnsServer _dnsServer;
- DhcpServer _dhcpServer;
- int _webServicePort;
- HttpListener _webService;
- Thread _webServiceThread;
- readonly IndependentTaskScheduler _webServiceTaskScheduler = new IndependentTaskScheduler(ThreadPriority.AboveNormal);
- string _webServiceHostname;
- string _tlsCertificatePath;
- string _tlsCertificatePassword;
- Timer _tlsCertificateUpdateTimer;
- DateTime _tlsCertificateLastModifiedOn;
- const int TLS_CERTIFICATE_UPDATE_TIMER_INITIAL_INTERVAL = 60000;
- const int TLS_CERTIFICATE_UPDATE_TIMER_INTERVAL = 60000;
- const int MAX_LOGIN_ATTEMPTS = 5;
- const int BLOCK_ADDRESS_INTERVAL = 5 * 60 * 1000;
- readonly ConcurrentDictionary<IPAddress, int> _failedLoginAttempts = new ConcurrentDictionary<IPAddress, int>();
- readonly ConcurrentDictionary<IPAddress, DateTime> _blockedAddresses = new ConcurrentDictionary<IPAddress, DateTime>();
- readonly ConcurrentDictionary<string, string> _credentials = new ConcurrentDictionary<string, string>();
- readonly ConcurrentDictionary<string, UserSession> _sessions = new ConcurrentDictionary<string, UserSession>();
- volatile ServiceState _state = ServiceState.Stopped;
- Timer _blockListUpdateTimer;
- DateTime _blockListLastUpdatedOn;
- const int BLOCK_LIST_UPDATE_AFTER_HOURS = 24;
- const int BLOCK_LIST_UPDATE_TIMER_INITIAL_INTERVAL = 5000;
- const int BLOCK_LIST_UPDATE_TIMER_INTERVAL = 900000;
- List<string> _configDisabledZones;
- #endregion
- #region constructor
- public WebService(string configFolder = null, Uri updateCheckUri = null)
- {
- Assembly assembly = Assembly.GetExecutingAssembly();
- AssemblyName assemblyName = assembly.GetName();
- _currentVersion = assemblyName.Version;
- _appFolder = Path.GetDirectoryName(assembly.Location);
- if (configFolder == null)
- _configFolder = Path.Combine(_appFolder, "config");
- else
- _configFolder = configFolder;
- if (!Directory.Exists(_configFolder))
- Directory.CreateDirectory(_configFolder);
- _updateCheckUri = updateCheckUri;
- string logFolder = Path.Combine(_configFolder, "logs");
- if (!Directory.Exists(logFolder))
- Directory.CreateDirectory(logFolder);
- _log = new LogManager(logFolder);
- string blockListsFolder = Path.Combine(_configFolder, "blocklists");
- if (!Directory.Exists(blockListsFolder))
- Directory.CreateDirectory(blockListsFolder);
- }
- #endregion
- #region IDisposable
- private bool _disposed = false;
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed)
- return;
- if (disposing)
- {
- Stop();
- if (_webService != null)
- _webService.Close();
- if (_dnsServer != null)
- _dnsServer.Dispose();
- if (_dhcpServer != null)
- _dhcpServer.Dispose();
- if (_log != null)
- _log.Dispose();
- }
- _disposed = true;
- }
- public void Dispose()
- {
- Dispose(true);
- }
- #endregion
- #region private
- private void AcceptWebRequestAsync(object state)
- {
- try
- {
- while (true)
- {
- HttpListenerContext context = _webService.GetContext();
- _ = Task.Factory.StartNew(delegate ()
- {
- return ProcessRequestAsync(context.Request, context.Response);
- }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, _webServiceTaskScheduler);
- }
- }
- catch (Exception ex)
- {
- if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped))
- return; //web service stopping
- _log.Write(ex);
- throw;
- }
- }
- private async Task ProcessRequestAsync(HttpListenerRequest request, HttpListenerResponse response)
- {
- response.AddHeader("Server", "");
- response.AddHeader("X-Robots-Tag", "noindex, nofollow");
- try
- {
- Uri url = request.Url;
- string path = url.AbsolutePath;
- if (!path.StartsWith("/") || path.Contains("/../") || path.Contains("/.../"))
- {
- await SendErrorAsync(response, 404);
- return;
- }
- if (path.StartsWith("/api/"))
- {
- using (MemoryStream mS = new MemoryStream())
- {
- try
- {
- JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS));
- jsonWriter.WriteStartObject();
- switch (path)
- {
- case "/api/login":
- await LoginAsync(request, jsonWriter);
- break;
- case "/api/logout":
- Logout(request);
- break;
- default:
- if (!IsSessionValid(request))
- throw new InvalidTokenWebServiceException("Invalid token or session expired.");
- jsonWriter.WritePropertyName("response");
- jsonWriter.WriteStartObject();
- try
- {
- switch (path)
- {
- case "/api/changePassword":
- ChangePassword(request);
- break;
- case "/api/checkForUpdate":
- await CheckForUpdateAsync(request, jsonWriter);
- break;
- case "/api/getDnsSettings":
- GetDnsSettings(jsonWriter);
- break;
- case "/api/setDnsSettings":
- SetDnsSettings(request, jsonWriter);
- break;
- case "/api/getStats":
- await GetStats(request, jsonWriter);
- break;
- case "/api/flushDnsCache":
- FlushCache(request);
- break;
- case "/api/listCachedZones":
- ListCachedZones(request, jsonWriter);
- break;
- case "/api/deleteCachedZone":
- DeleteCachedZone(request);
- break;
- case "/api/listAllowedZones":
- ListAllowedZones(request, jsonWriter);
- break;
- case "/api/importAllowedZones":
- ImportAllowedZones(request);
- break;
- case "/api/exportAllowedZones":
- ExportAllowedZones(response);
- return;
- case "/api/deleteAllowedZone":
- DeleteAllowedZone(request);
- break;
- case "/api/allowZone":
- AllowZone(request);
- break;
- case "/api/listBlockedZones":
- ListBlockedZones(request, jsonWriter);
- break;
- case "/api/importBlockedZones":
- ImportBlockedZones(request);
- break;
- case "/api/exportBlockedZones":
- ExportBlockedZones(response);
- return;
- case "/api/deleteBlockedZone":
- DeleteBlockedZone(request);
- break;
- case "/api/blockZone":
- BlockZone(request);
- break;
- case "/api/listZones":
- ListZones(jsonWriter);
- break;
- case "/api/createZone":
- await CreateZoneAsync(request, jsonWriter);
- break;
- case "/api/deleteZone":
- DeleteZone(request);
- break;
- case "/api/enableZone":
- EnableZone(request);
- break;
- case "/api/disableZone":
- DisableZone(request);
- break;
- case "/api/addRecord":
- AddRecord(request);
- break;
- case "/api/getRecords":
- GetRecords(request, jsonWriter);
- break;
- case "/api/deleteRecord":
- DeleteRecord(request);
- break;
- case "/api/updateRecord":
- UpdateRecord(request);
- break;
- case "/api/resolveQuery":
- await ResolveQuery(request, jsonWriter);
- break;
- case "/api/listLogs":
- ListLogs(jsonWriter);
- break;
- case "/api/deleteLog":
- DeleteLog(request);
- break;
- case "/api/listDhcpScopes":
- ListDhcpScopes(jsonWriter);
- break;
- case "/api/listDhcpLeases":
- ListDhcpLeases(jsonWriter);
- break;
- case "/api/getDhcpScope":
- GetDhcpScope(request, jsonWriter);
- break;
- case "/api/setDhcpScope":
- await SetDhcpScopeAsync(request);
- break;
- case "/api/enableDhcpScope":
- await EnableDhcpScopeAsync(request);
- break;
- case "/api/disableDhcpScope":
- DisableDhcpScope(request);
- break;
- case "/api/deleteDhcpScope":
- DeleteDhcpScope(request);
- break;
- default:
- await SendErrorAsync(response, 404);
- return;
- }
- }
- finally
- {
- jsonWriter.WriteEndObject();
- }
- break;
- }
- jsonWriter.WritePropertyName("status");
- jsonWriter.WriteValue("ok");
- jsonWriter.WriteEndObject();
- jsonWriter.Flush();
- }
- catch (InvalidTokenWebServiceException ex)
- {
- mS.SetLength(0);
- JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS));
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("status");
- jsonWriter.WriteValue("invalid-token");
- jsonWriter.WritePropertyName("errorMessage");
- jsonWriter.WriteValue(ex.Message);
- jsonWriter.WriteEndObject();
- jsonWriter.Flush();
- }
- catch (Exception ex)
- {
- _log.Write(GetRequestRemoteEndPoint(request), ex);
- mS.SetLength(0);
- JsonTextWriter jsonWriter = new JsonTextWriter(new StreamWriter(mS));
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("status");
- jsonWriter.WriteValue("error");
- jsonWriter.WritePropertyName("errorMessage");
- jsonWriter.WriteValue(ex.Message);
- jsonWriter.WritePropertyName("stackTrace");
- jsonWriter.WriteValue(ex.StackTrace);
- if (ex.InnerException != null)
- {
- jsonWriter.WritePropertyName("innerErrorMessage");
- jsonWriter.WriteValue(ex.InnerException.Message);
- }
- jsonWriter.WriteEndObject();
- jsonWriter.Flush();
- }
- response.ContentType = "application/json; charset=utf-8";
- response.ContentEncoding = Encoding.UTF8;
- response.ContentLength64 = mS.Length;
- using (Stream stream = response.OutputStream)
- {
- mS.WriteTo(response.OutputStream);
- }
- }
- }
- else if (path.StartsWith("/log/"))
- {
- if (!IsSessionValid(request))
- {
- await SendErrorAsync(response, 403, "Invalid token or session expired.");
- return;
- }
- string[] pathParts = path.Split('/');
- string logFileName = pathParts[2];
- string logFile = Path.Combine(_log.LogFolder, logFileName + ".log");
- int limit = 0;
- string strLimit = request.QueryString["limit"];
- if (!string.IsNullOrEmpty(strLimit))
- limit = int.Parse(strLimit);
- LogManager.DownloadLog(response, logFile, limit * 1024 * 1024);
- }
- else
- {
- if (path == "/")
- {
- path = "/index.html";
- }
- else if ((path == "/blocklist.txt") && !IPAddress.IsLoopback(GetRequestRemoteEndPoint(request).Address))
- {
- await SendErrorAsync(response, 403);
- return;
- }
- string wwwroot = Path.Combine(_appFolder, "www");
- path = Path.GetFullPath(wwwroot + path.Replace('/', Path.DirectorySeparatorChar));
- if (!path.StartsWith(wwwroot) || !File.Exists(path))
- {
- await SendErrorAsync(response, 404);
- return;
- }
- await SendFileAsync(response, path);
- }
- }
- catch (Exception ex)
- {
- if ((_state == ServiceState.Stopping) || (_state == ServiceState.Stopped))
- return; //web service stopping
- _log.Write(GetRequestRemoteEndPoint(request), ex);
- await SendError(response, ex);
- }
- }
- private static IPEndPoint GetRequestRemoteEndPoint(HttpListenerRequest request)
- {
- try
- {
- if (request.RemoteEndPoint == null)
- return new IPEndPoint(IPAddress.Any, 0);
- if (NetUtilities.IsPrivateIP(request.RemoteEndPoint.Address))
- {
- string xRealIp = request.Headers["X-Real-IP"];
- if (IPAddress.TryParse(xRealIp, out IPAddress address))
- {
- //get the real IP address of the requesting client from X-Real-IP header set in nginx proxy_pass block
- return new IPEndPoint(address, 0);
- }
- }
- return request.RemoteEndPoint;
- }
- catch
- {
- return new IPEndPoint(IPAddress.Any, 0);
- }
- }
- private static Task SendError(HttpListenerResponse response, Exception ex)
- {
- return SendErrorAsync(response, 500, ex.ToString());
- }
- private static async Task SendErrorAsync(HttpListenerResponse response, int statusCode, string message = null)
- {
- try
- {
- string statusString = statusCode + " " + DnsServer.GetHttpStatusString((HttpStatusCode)statusCode);
- byte[] buffer = Encoding.UTF8.GetBytes("<html><head><title>" + statusString + "</title></head><body><h1>" + statusString + "</h1>" + (message == null ? "" : "<p>" + message + "</p>") + "</body></html>");
- response.StatusCode = statusCode;
- response.ContentType = "text/html";
- response.ContentLength64 = buffer.Length;
- using (Stream stream = response.OutputStream)
- {
- await stream.WriteAsync(buffer, 0, buffer.Length);
- }
- }
- catch
- { }
- }
- private static async Task SendFileAsync(HttpListenerResponse response, string filePath)
- {
- using (FileStream fS = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
- {
- response.ContentType = WebUtilities.GetContentType(filePath).MediaType;
- response.ContentLength64 = fS.Length;
- response.AddHeader("Cache-Control", "private, max-age=300");
- using (Stream stream = response.OutputStream)
- {
- try
- {
- await fS.CopyToAsync(stream);
- }
- catch (HttpListenerException)
- {
- //ignore this error
- }
- }
- }
- }
- private string CreateSession(string username)
- {
- string token = BinaryNumber.GenerateRandomNumber256().ToString();
- if (!_sessions.TryAdd(token, new UserSession(username)))
- throw new WebServiceException("Error while creating session. Please try again.");
- return token;
- }
- private UserSession GetSession(string token)
- {
- if (_sessions.TryGetValue(token, out UserSession session))
- return session;
- return null;
- }
- private UserSession GetSession(HttpListenerRequest request)
- {
- string strToken = request.QueryString["token"];
- if (string.IsNullOrEmpty(strToken))
- throw new WebServiceException("Parameter 'token' missing.");
- return GetSession(strToken);
- }
- private UserSession DeleteSession(string token)
- {
- if (_sessions.TryRemove(token, out UserSession session))
- return session;
- return null;
- }
- private UserSession DeleteSession(HttpListenerRequest request)
- {
- string strToken = request.QueryString["token"];
- if (string.IsNullOrEmpty(strToken))
- throw new WebServiceException("Parameter 'token' missing.");
- return DeleteSession(strToken);
- }
- private void FailedLoginAttempt(IPAddress address)
- {
- _failedLoginAttempts.AddOrUpdate(address, 1, delegate (IPAddress key, int attempts)
- {
- return attempts + 1;
- });
- }
- private bool LoginAttemptsExceedLimit(IPAddress address, int limit)
- {
- if (!_failedLoginAttempts.TryGetValue(address, out int attempts))
- return false;
- return attempts >= limit;
- }
- private void ResetFailedLoginAttempt(IPAddress address)
- {
- _failedLoginAttempts.TryRemove(address, out _);
- }
- private void BlockAddress(IPAddress address, int interval)
- {
- _blockedAddresses.TryAdd(address, DateTime.UtcNow.AddMilliseconds(interval));
- }
- private bool IsAddressBlocked(IPAddress address)
- {
- if (!_blockedAddresses.TryGetValue(address, out DateTime expiry))
- return false;
- if (expiry > DateTime.UtcNow)
- {
- return true;
- }
- else
- {
- UnblockAddress(address);
- ResetFailedLoginAttempt(address);
- return false;
- }
- }
- private void UnblockAddress(IPAddress address)
- {
- _blockedAddresses.TryRemove(address, out _);
- }
- private async Task LoginAsync(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string strUsername = request.QueryString["user"];
- if (string.IsNullOrEmpty(strUsername))
- throw new WebServiceException("Parameter 'user' missing.");
- string strPassword = request.QueryString["pass"];
- if (string.IsNullOrEmpty(strPassword))
- throw new WebServiceException("Parameter 'pass' missing.");
- IPEndPoint remoteEP = GetRequestRemoteEndPoint(request);
- if (IsAddressBlocked(remoteEP.Address))
- throw new WebServiceException("Max limit of " + MAX_LOGIN_ATTEMPTS + " attempts exceeded. Access blocked for " + (BLOCK_ADDRESS_INTERVAL / 1000) + " seconds.");
- strUsername = strUsername.ToLower();
- string strPasswordHash = GetPasswordHash(strUsername, strPassword);
- if (!_credentials.TryGetValue(strUsername, out string passwordHash) || (passwordHash != strPasswordHash))
- {
- if (strPassword != "admin") //exception for default password
- {
- FailedLoginAttempt(remoteEP.Address);
- if (LoginAttemptsExceedLimit(remoteEP.Address, MAX_LOGIN_ATTEMPTS))
- BlockAddress(remoteEP.Address, BLOCK_ADDRESS_INTERVAL);
- await Task.Delay(1000);
- }
- throw new WebServiceException("Invalid username or password: " + strUsername);
- }
- ResetFailedLoginAttempt(remoteEP.Address);
- _log.Write(remoteEP, "[" + strUsername + "] User logged in.");
- string token = CreateSession(strUsername);
- jsonWriter.WritePropertyName("token");
- jsonWriter.WriteValue(token);
- }
- private bool IsSessionValid(HttpListenerRequest request)
- {
- UserSession session = GetSession(request);
- if (session == null)
- return false;
- if (session.HasExpired())
- {
- DeleteSession(request);
- return false;
- }
- session.UpdateLastSeen();
- return true;
- }
- private void ChangePassword(HttpListenerRequest request)
- {
- string strToken = request.QueryString["token"];
- if (string.IsNullOrEmpty(strToken))
- throw new WebServiceException("Parameter 'token' missing.");
- string strPassword = request.QueryString["pass"];
- if (string.IsNullOrEmpty(strPassword))
- throw new WebServiceException("Parameter 'pass' missing.");
- UserSession session = GetSession(strToken);
- if (session == null)
- throw new WebServiceException("User session does not exists.");
- SetCredentials(session.Username, strPassword);
- SaveConfigFile();
- _log.Write(GetRequestRemoteEndPoint(request), "[" + session.Username + "] Password was changed for user.");
- }
- private void Logout(HttpListenerRequest request)
- {
- string strToken = request.QueryString["token"];
- if (string.IsNullOrEmpty(strToken))
- throw new WebServiceException("Parameter 'token' missing.");
- UserSession session = DeleteSession(strToken);
- if (session != null)
- _log.Write(GetRequestRemoteEndPoint(request), "[" + session.Username + "] User logged out.");
- }
- public static void CreateUpdateInfo(Stream s, string version, string displayText, string downloadLink)
- {
- BinaryWriter bW = new BinaryWriter(s);
- bW.Write(Encoding.ASCII.GetBytes("DU")); //format
- bW.Write((byte)2); //version
- bW.WriteShortString(version);
- bW.WriteShortString(displayText);
- bW.WriteShortString(downloadLink);
- }
- private async Task CheckForUpdateAsync(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- Version updateVersion = null;
- string displayText = null;
- string downloadLink = null;
- bool updateAvailable = false;
- if (_updateCheckUri != null)
- {
- try
- {
- HttpClientHandler handler = new HttpClientHandler();
- handler.Proxy = _dnsServer.Proxy;
- using (HttpClient http = new HttpClient(handler))
- {
- byte[] response = await http.GetByteArrayAsync(_updateCheckUri);
- using (MemoryStream mS = new MemoryStream(response, false))
- {
- BinaryReader bR = new BinaryReader(mS);
- if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "DU") //format
- throw new InvalidDataException("DNS Server update info format is invalid.");
- switch (bR.ReadByte()) //version
- {
- case 2:
- updateVersion = new Version(bR.ReadShortString());
- displayText = bR.ReadShortString();
- downloadLink = bR.ReadShortString();
- break;
- default:
- throw new InvalidDataException("DNS Server update info version not supported.");
- }
- updateAvailable = updateVersion > _currentVersion;
- }
- }
- _log.Write(GetRequestRemoteEndPoint(request), "Check for update was done {updateAvailable: " + updateAvailable + "; updateVersion: " + updateVersion + "; displayText: " + displayText + "; downloadLink: " + downloadLink + ";}");
- }
- catch (Exception ex)
- {
- _log.Write(GetRequestRemoteEndPoint(request), "Check for update was done {updateAvailable: False;}\r\n" + ex.ToString());
- }
- }
- jsonWriter.WritePropertyName("updateAvailable");
- jsonWriter.WriteValue(updateAvailable);
- if (updateAvailable)
- {
- if (!string.IsNullOrEmpty(displayText))
- {
- jsonWriter.WritePropertyName("displayText");
- jsonWriter.WriteValue(displayText);
- }
- jsonWriter.WritePropertyName("downloadLink");
- jsonWriter.WriteValue(downloadLink);
- }
- }
- private static string GetCleanVersion(Version version)
- {
- string strVersion = version.Major + "." + version.Minor;
- if (version.Build > 0)
- strVersion += "." + version.Build;
- if (version.Revision > 0)
- strVersion += "." + version.Revision;
- return strVersion;
- }
- private void GetDnsSettings(JsonTextWriter jsonWriter)
- {
- jsonWriter.WritePropertyName("version");
- jsonWriter.WriteValue(GetCleanVersion(_currentVersion));
- jsonWriter.WritePropertyName("serverDomain");
- jsonWriter.WriteValue(_dnsServer.ServerDomain);
- jsonWriter.WritePropertyName("webServicePort");
- jsonWriter.WriteValue(_webServicePort);
- jsonWriter.WritePropertyName("dnsServerLocalEndPoints");
- jsonWriter.WriteStartArray();
- foreach (IPEndPoint localEP in _dnsServer.LocalEndPoints)
- jsonWriter.WriteValue(localEP.ToString());
- jsonWriter.WriteEndArray();
- jsonWriter.WritePropertyName("enableDnsOverHttp");
- jsonWriter.WriteValue(_dnsServer.EnableDnsOverHttp);
- jsonWriter.WritePropertyName("enableDnsOverTls");
- jsonWriter.WriteValue(_dnsServer.EnableDnsOverTls);
- jsonWriter.WritePropertyName("enableDnsOverHttps");
- jsonWriter.WriteValue(_dnsServer.EnableDnsOverHttps);
- jsonWriter.WritePropertyName("tlsCertificatePath");
- jsonWriter.WriteValue(_tlsCertificatePath);
- jsonWriter.WritePropertyName("tlsCertificatePassword");
- jsonWriter.WriteValue("************");
- jsonWriter.WritePropertyName("preferIPv6");
- jsonWriter.WriteValue(_dnsServer.PreferIPv6);
- jsonWriter.WritePropertyName("logQueries");
- jsonWriter.WriteValue(_dnsServer.QueryLogManager != null);
- jsonWriter.WritePropertyName("allowRecursion");
- jsonWriter.WriteValue(_dnsServer.AllowRecursion);
- jsonWriter.WritePropertyName("allowRecursionOnlyForPrivateNetworks");
- jsonWriter.WriteValue(_dnsServer.AllowRecursionOnlyForPrivateNetworks);
- jsonWriter.WritePropertyName("cachePrefetchEligibility");
- jsonWriter.WriteValue(_dnsServer.CachePrefetchEligibility);
- jsonWriter.WritePropertyName("cachePrefetchTrigger");
- jsonWriter.WriteValue(_dnsServer.CachePrefetchTrigger);
- jsonWriter.WritePropertyName("cachePrefetchSampleIntervalInMinutes");
- jsonWriter.WriteValue(_dnsServer.CachePrefetchSampleIntervalInMinutes);
- jsonWriter.WritePropertyName("cachePrefetchSampleEligibilityHitsPerHour");
- jsonWriter.WriteValue(_dnsServer.CachePrefetchSampleEligibilityHitsPerHour);
- jsonWriter.WritePropertyName("proxy");
- if (_dnsServer.Proxy == null)
- {
- jsonWriter.WriteNull();
- }
- else
- {
- jsonWriter.WriteStartObject();
- NetProxy proxy = _dnsServer.Proxy;
- jsonWriter.WritePropertyName("type");
- jsonWriter.WriteValue(proxy.Type.ToString());
- jsonWriter.WritePropertyName("address");
- jsonWriter.WriteValue(proxy.Address);
- jsonWriter.WritePropertyName("port");
- jsonWriter.WriteValue(proxy.Port);
- NetworkCredential credential = proxy.Credential;
- if (credential != null)
- {
- jsonWriter.WritePropertyName("username");
- jsonWriter.WriteValue(credential.UserName);
- jsonWriter.WritePropertyName("password");
- jsonWriter.WriteValue(credential.Password);
- }
- jsonWriter.WritePropertyName("bypass");
- jsonWriter.WriteStartArray();
- foreach (NetProxyBypassItem item in proxy.BypassList)
- jsonWriter.WriteValue(item.Value);
- jsonWriter.WriteEndArray();
- jsonWriter.WriteEndObject();
- }
- jsonWriter.WritePropertyName("forwarders");
- DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp;
- if (_dnsServer.Forwarders == null)
- {
- jsonWriter.WriteNull();
- }
- else
- {
- forwarderProtocol = _dnsServer.Forwarders[0].Protocol;
- jsonWriter.WriteStartArray();
- foreach (NameServerAddress forwarder in _dnsServer.Forwarders)
- jsonWriter.WriteValue(forwarder.OriginalAddress);
- jsonWriter.WriteEndArray();
- }
- jsonWriter.WritePropertyName("forwarderProtocol");
- jsonWriter.WriteValue(forwarderProtocol.ToString());
- jsonWriter.WritePropertyName("blockListUrls");
- if (_dnsServer.BlockListZoneManager.BlockListUrls.Count == 0)
- {
- jsonWriter.WriteNull();
- }
- else
- {
- jsonWriter.WriteStartArray();
- foreach (Uri blockListUrl in _dnsServer.BlockListZoneManager.BlockListUrls)
- jsonWriter.WriteValue(blockListUrl.AbsoluteUri);
- jsonWriter.WriteEndArray();
- }
- }
- private void SetDnsSettings(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string strServerDomain = request.QueryString["serverDomain"];
- if (!string.IsNullOrEmpty(strServerDomain))
- _dnsServer.ServerDomain = strServerDomain;
- string strDnsServerLocalEndPoints = request.QueryString["dnsServerLocalEndPoints"];
- if (strDnsServerLocalEndPoints != null)
- {
- if (string.IsNullOrEmpty(strDnsServerLocalEndPoints))
- strDnsServerLocalEndPoints = "0.0.0.0:53,[::]:53";
- string[] strLocalEndPoints = strDnsServerLocalEndPoints.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- List<IPEndPoint> localEndPoints = new List<IPEndPoint>(strLocalEndPoints.Length);
- for (int i = 0; i < strLocalEndPoints.Length; i++)
- {
- NameServerAddress nameServer = new NameServerAddress(strLocalEndPoints[i]);
- if (nameServer.IPEndPoint != null)
- localEndPoints.Add(nameServer.IPEndPoint);
- }
- _dnsServer.LocalEndPoints = localEndPoints;
- }
- int oldWebServicePort = _webServicePort;
- string strWebServicePort = request.QueryString["webServicePort"];
- if (!string.IsNullOrEmpty(strWebServicePort))
- _webServicePort = int.Parse(strWebServicePort);
- string enableDnsOverHttp = request.QueryString["enableDnsOverHttp"];
- if (!string.IsNullOrEmpty(enableDnsOverHttp))
- _dnsServer.EnableDnsOverHttp = bool.Parse(enableDnsOverHttp);
- string strEnableDnsOverTls = request.QueryString["enableDnsOverTls"];
- if (!string.IsNullOrEmpty(strEnableDnsOverTls))
- _dnsServer.EnableDnsOverTls = bool.Parse(strEnableDnsOverTls);
- string strEnableDnsOverHttps = request.QueryString["enableDnsOverHttps"];
- if (!string.IsNullOrEmpty(strEnableDnsOverHttps))
- _dnsServer.EnableDnsOverHttps = bool.Parse(strEnableDnsOverHttps);
- string strTlsCertificatePath = request.QueryString["tlsCertificatePath"];
- string strTlsCertificatePassword = request.QueryString["tlsCertificatePassword"];
- if (string.IsNullOrEmpty(strTlsCertificatePath))
- {
- StopTlsCertificateUpdateTimer();
- _tlsCertificatePath = null;
- _tlsCertificatePassword = "";
- }
- else
- {
- if (strTlsCertificatePassword == "************")
- strTlsCertificatePassword = _tlsCertificatePassword;
- if ((strTlsCertificatePath != _tlsCertificatePath) || (strTlsCertificatePassword != _tlsCertificatePassword))
- {
- LoadTlsCertificate(strTlsCertificatePath, strTlsCertificatePassword);
- _tlsCertificatePath = strTlsCertificatePath;
- _tlsCertificatePassword = strTlsCertificatePassword;
- StartTlsCertificateUpdateTimer();
- }
- }
- string strPreferIPv6 = request.QueryString["preferIPv6"];
- if (!string.IsNullOrEmpty(strPreferIPv6))
- _dnsServer.PreferIPv6 = bool.Parse(strPreferIPv6);
- string strLogQueries = request.QueryString["logQueries"];
- if (!string.IsNullOrEmpty(strLogQueries))
- {
- if (bool.Parse(strLogQueries))
- _dnsServer.QueryLogManager = _log;
- else
- _dnsServer.QueryLogManager = null;
- }
- string strAllowRecursion = request.QueryString["allowRecursion"];
- if (!string.IsNullOrEmpty(strAllowRecursion))
- _dnsServer.AllowRecursion = bool.Parse(strAllowRecursion);
- string strAllowRecursionOnlyForPrivateNetworks = request.QueryString["allowRecursionOnlyForPrivateNetworks"];
- if (!string.IsNullOrEmpty(strAllowRecursionOnlyForPrivateNetworks))
- _dnsServer.AllowRecursionOnlyForPrivateNetworks = bool.Parse(strAllowRecursionOnlyForPrivateNetworks);
- string strCachePrefetchEligibility = request.QueryString["cachePrefetchEligibility"];
- if (!string.IsNullOrEmpty(strCachePrefetchEligibility))
- _dnsServer.CachePrefetchEligibility = int.Parse(strCachePrefetchEligibility);
- string strCachePrefetchTrigger = request.QueryString["cachePrefetchTrigger"];
- if (!string.IsNullOrEmpty(strCachePrefetchTrigger))
- _dnsServer.CachePrefetchTrigger = int.Parse(strCachePrefetchTrigger);
- string strCachePrefetchSampleIntervalInMinutes = request.QueryString["cachePrefetchSampleIntervalInMinutes"];
- if (!string.IsNullOrEmpty(strCachePrefetchSampleIntervalInMinutes))
- _dnsServer.CachePrefetchSampleIntervalInMinutes = int.Parse(strCachePrefetchSampleIntervalInMinutes);
- string strCachePrefetchSampleEligibilityHitsPerHour = request.QueryString["cachePrefetchSampleEligibilityHitsPerHour"];
- if (!string.IsNullOrEmpty(strCachePrefetchSampleEligibilityHitsPerHour))
- _dnsServer.CachePrefetchSampleEligibilityHitsPerHour = int.Parse(strCachePrefetchSampleEligibilityHitsPerHour);
- string strProxyType = request.QueryString["proxyType"];
- if (!string.IsNullOrEmpty(strProxyType))
- {
- NetProxyType proxyType = (NetProxyType)Enum.Parse(typeof(NetProxyType), strProxyType, true);
- if (proxyType == NetProxyType.None)
- {
- _dnsServer.Proxy = null;
- }
- else
- {
- NetworkCredential credential = null;
- string strUsername = request.QueryString["proxyUsername"];
- if (!string.IsNullOrEmpty(strUsername))
- credential = new NetworkCredential(strUsername, request.QueryString["proxyPassword"]);
- _dnsServer.Proxy = NetProxy.CreateProxy(proxyType, request.QueryString["proxyAddress"], int.Parse(request.QueryString["proxyPort"]), credential);
- string strProxyBypass = request.QueryString["proxyBypass"];
- if (!string.IsNullOrEmpty(strProxyBypass))
- {
- string[] strBypassList = strProxyBypass.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- _dnsServer.Proxy.BypassList.Clear();
- for (int i = 0; i < strBypassList.Length; i++)
- _dnsServer.Proxy.BypassList.Add(new NetProxyBypassItem(strBypassList[i]));
- }
- }
- }
- DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp;
- string strForwarderProtocol = request.QueryString["forwarderProtocol"];
- if (!string.IsNullOrEmpty(strForwarderProtocol))
- forwarderProtocol = (DnsTransportProtocol)Enum.Parse(typeof(DnsTransportProtocol), strForwarderProtocol, true);
- string strForwarders = request.QueryString["forwarders"];
- if (!string.IsNullOrEmpty(strForwarders))
- {
- if (strForwarders == "false")
- {
- _dnsServer.Forwarders = null;
- }
- else
- {
- string[] strForwardersList = strForwarders.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- NameServerAddress[] forwarders = new NameServerAddress[strForwardersList.Length];
- for (int i = 0; i < strForwardersList.Length; i++)
- {
- if ((forwarderProtocol == DnsTransportProtocol.Tls) && IPAddress.TryParse(strForwardersList[i], out _))
- strForwardersList[i] += ":853";
- forwarders[i] = new NameServerAddress(strForwardersList[i], forwarderProtocol);
- }
- _dnsServer.Forwarders = forwarders;
- }
- }
- string strBlockListUrls = request.QueryString["blockListUrls"];
- if (!string.IsNullOrEmpty(strBlockListUrls))
- {
- if (strBlockListUrls == "false")
- {
- StopBlockListUpdateTimer();
- _dnsServer.BlockListZoneManager.BlockListUrls.Clear();
- _dnsServer.BlockListZoneManager.Flush();
- }
- else
- {
- bool updated = false;
- string[] strBlockListUrlList = strBlockListUrls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- if (oldWebServicePort != _webServicePort)
- {
- for (int i = 0; i < strBlockListUrlList.Length; i++)
- {
- if (strBlockListUrlList[i].Contains("http://localhost:" + oldWebServicePort + "/blocklist.txt"))
- {
- strBlockListUrlList[i] = "http://localhost:" + _webServicePort + "/blocklist.txt";
- updated = true;
- break;
- }
- }
- }
- if (!updated)
- {
- if (strBlockListUrlList.Length != _dnsServer.BlockListZoneManager.BlockListUrls.Count)
- {
- updated = true;
- }
- else
- {
- foreach (string strBlockListUrl in strBlockListUrlList)
- {
- if (!_dnsServer.BlockListZoneManager.BlockListUrls.Contains(new Uri(strBlockListUrl)))
- {
- updated = true;
- break;
- }
- }
- }
- }
- if (updated)
- {
- _dnsServer.BlockListZoneManager.BlockListUrls.Clear();
- foreach (string strBlockListUrl in strBlockListUrlList)
- {
- Uri blockListUrl = new Uri(strBlockListUrl);
- if (!_dnsServer.BlockListZoneManager.BlockListUrls.Contains(blockListUrl))
- _dnsServer.BlockListZoneManager.BlockListUrls.Add(blockListUrl);
- }
- _blockListLastUpdatedOn = new DateTime();
- StopBlockListUpdateTimer();
- StartBlockListUpdateTimer();
- }
- }
- }
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DNS Settings were updated {serverDomain: " + _dnsServer.ServerDomain + "; dnsServerLocalEndPoints: " + strDnsServerLocalEndPoints + "; webServicePort: " + _webServicePort + "; enableDnsOverHttp: " + _dnsServer.EnableDnsOverHttp + "; enableDnsOverTls: " + _dnsServer.EnableDnsOverTls + "; enableDnsOverHttps: " + _dnsServer.EnableDnsOverHttps + "; tlsCertificatePath: " + _tlsCertificatePath + "; preferIPv6: " + _dnsServer.PreferIPv6 + "; logQueries: " + (_dnsServer.QueryLogManager != null) + "; allowRecursion: " + _dnsServer.AllowRecursion + "; allowRecursionOnlyForPrivateNetworks: " + _dnsServer.AllowRecursionOnlyForPrivateNetworks + "; proxyType: " + strProxyType + "; forwarders: " + strForwarders + "; forwarderProtocol: " + strForwarderProtocol + "; blockListUrl: " + strBlockListUrls + ";}");
- SaveConfigFile();
- GetDnsSettings(jsonWriter);
- }
- private async Task GetStats(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string strType = request.QueryString["type"];
- if (string.IsNullOrEmpty(strType))
- strType = "lastHour";
- Dictionary<string, List<KeyValuePair<string, int>>> data;
- switch (strType)
- {
- case "lastHour":
- data = _dnsServer.StatsManager.GetLastHourStats();
- break;
- case "lastDay":
- data = _dnsServer.StatsManager.GetLastDayStats();
- break;
- case "lastWeek":
- data = _dnsServer.StatsManager.GetLastWeekStats();
- break;
- case "lastMonth":
- data = _dnsServer.StatsManager.GetLastMonthStats();
- break;
- case "lastYear":
- data = _dnsServer.StatsManager.GetLastYearStats();
- break;
- default:
- throw new WebServiceException("Unknown stats type requested: " + strType);
- }
- //stats
- {
- List<KeyValuePair<string, int>> stats = data["stats"];
- jsonWriter.WritePropertyName("stats");
- jsonWriter.WriteStartObject();
- foreach (KeyValuePair<string, int> item in stats)
- {
- jsonWriter.WritePropertyName(item.Key);
- jsonWriter.WriteValue(item.Value);
- }
- jsonWriter.WritePropertyName("allowedZones");
- jsonWriter.WriteValue(_dnsServer.AllowedZoneManager.TotalZonesAllowed);
- jsonWriter.WritePropertyName("blockedZones");
- jsonWriter.WriteValue(_dnsServer.BlockedZoneManager.TotalZonesBlocked + _dnsServer.BlockListZoneManager.TotalZonesBlocked);
- jsonWriter.WriteEndObject();
- }
- //main chart
- {
- jsonWriter.WritePropertyName("mainChartData");
- jsonWriter.WriteStartObject();
- //label
- {
- List<KeyValuePair<string, int>> statsPerInterval = data["totalQueriesPerInterval"];
- jsonWriter.WritePropertyName("labels");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair<string, int> item in statsPerInterval)
- jsonWriter.WriteValue(item.Key);
- jsonWriter.WriteEndArray();
- }
- //datasets
- {
- jsonWriter.WritePropertyName("datasets");
- jsonWriter.WriteStartArray();
- WriteChartDataSet(jsonWriter, "Total", "rgba(102, 153, 255, 0.1)", "rgb(102, 153, 255)", data["totalQueriesPerInterval"]);
- WriteChartDataSet(jsonWriter, "No Error", "rgba(92, 184, 92, 0.1)", "rgb(92, 184, 92)", data["totalNoErrorPerInterval"]);
- WriteChartDataSet(jsonWriter, "Server Failure", "rgba(217, 83, 79, 0.1)", "rgb(217, 83, 79)", data["totalServerFailurePerInterval"]);
- WriteChartDataSet(jsonWriter, "Name Error", "rgba(7, 7, 7, 0.1)", "rgb(7, 7, 7)", data["totalNameErrorPerInterval"]);
- WriteChartDataSet(jsonWriter, "Refused", "rgba(91, 192, 222, 0.1)", "rgb(91, 192, 222)", data["totalRefusedPerInterval"]);
- WriteChartDataSet(jsonWriter, "Authoritative", "rgba(150, 150, 0, 0.1)", "rgb(150, 150, 0)", data["totalAuthHitPerInterval"]);
- WriteChartDataSet(jsonWriter, "Recursive", "rgba(23, 162, 184, 0.1)", "rgb(23, 162, 184)", data["totalRecursionsPerInterval"]);
- WriteChartDataSet(jsonWriter, "Cached", "rgba(111, 84, 153, 0.1)", "rgb(111, 84, 153)", data["totalCacheHitPerInterval"]);
- WriteChartDataSet(jsonWriter, "Blocked", "rgba(255, 165, 0, 0.1)", "rgb(255, 165, 0)", data["totalBlockedPerInterval"]);
- WriteChartDataSet(jsonWriter, "Clients", "rgba(51, 122, 183, 0.1)", "rgb(51, 122, 183)", data["totalClientsPerInterval"]);
- jsonWriter.WriteEndArray();
- }
- jsonWriter.WriteEndObject();
- }
- //query response chart
- {
- jsonWriter.WritePropertyName("queryResponseChartData");
- jsonWriter.WriteStartObject();
- List<KeyValuePair<string, int>> stats = data["stats"];
- //labels
- {
- jsonWriter.WritePropertyName("labels");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair<string, int> item in stats)
- {
- switch (item.Key)
- {
- case "totalAuthoritative":
- jsonWriter.WriteValue("Authoritative");
- break;
- case "totalRecursive":
- jsonWriter.WriteValue("Recursive");
- break;
- case "totalCached":
- jsonWriter.WriteValue("Cached");
- break;
- case "totalBlocked":
- jsonWriter.WriteValue("Blocked");
- break;
- }
- }
- jsonWriter.WriteEndArray();
- }
- //datasets
- {
- jsonWriter.WritePropertyName("datasets");
- jsonWriter.WriteStartArray();
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("data");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair<string, int> item in stats)
- {
- switch (item.Key)
- {
- case "totalAuthoritative":
- case "totalRecursive":
- case "totalCached":
- case "totalBlocked":
- jsonWriter.WriteValue(item.Value);
- break;
- }
- }
- jsonWriter.WriteEndArray();
- jsonWriter.WritePropertyName("backgroundColor");
- jsonWriter.WriteStartArray();
- jsonWriter.WriteValue("rgba(150, 150, 0, 0.5)");
- jsonWriter.WriteValue("rgba(23, 162, 184, 0.5)");
- jsonWriter.WriteValue("rgba(111, 84, 153, 0.5)");
- jsonWriter.WriteValue("rgba(255, 165, 0, 0.5)");
- jsonWriter.WriteEndArray();
- jsonWriter.WriteEndObject();
- jsonWriter.WriteEndArray();
- }
- jsonWriter.WriteEndObject();
- }
- //query type chart
- {
- jsonWriter.WritePropertyName("queryTypeChartData");
- jsonWriter.WriteStartObject();
- List<KeyValuePair<string, int>> queryTypes = data["queryTypes"];
- //labels
- {
- jsonWriter.WritePropertyName("labels");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair<string, int> item in queryTypes)
- jsonWriter.WriteValue(item.Key);
- jsonWriter.WriteEndArray();
- }
- //datasets
- {
- jsonWriter.WritePropertyName("datasets");
- jsonWriter.WriteStartArray();
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("data");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair<string, int> item in queryTypes)
- jsonWriter.WriteValue(item.Value);
- jsonWriter.WriteEndArray();
- jsonWriter.WritePropertyName("backgroundColor");
- jsonWriter.WriteStartArray();
- jsonWriter.WriteValue("rgba(102, 153, 255, 0.5)");
- jsonWriter.WriteValue("rgba(92, 184, 92, 0.5)");
- jsonWriter.WriteValue("rgba(91, 192, 222, 0.5)");
- jsonWriter.WriteValue("rgba(255, 165, 0, 0.5)");
- jsonWriter.WriteValue("rgba(51, 122, 183, 0.5)");
- jsonWriter.WriteEndArray();
- jsonWriter.WriteEndObject();
- jsonWriter.WriteEndArray();
- }
- jsonWriter.WriteEndObject();
- }
- //top clients
- {
- List<KeyValuePair<string, int>> topClients = data["topClients"];
- IDictionary<string, string> clientIpMap = _dhcpServer.GetAddressClientMap();
- jsonWriter.WritePropertyName("topClients");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair<string, int> item in topClients)
- {
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(item.Key);
- if (clientIpMap.TryGetValue(item.Key, out string clientDomain))
- {
- jsonWriter.WritePropertyName("domain");
- jsonWriter.WriteValue(clientDomain);
- }
- else
- {
- IPAddress address = IPAddress.Parse(item.Key);
- if (IPAddress.IsLoopback(address))
- {
- jsonWriter.WritePropertyName("domain");
- jsonWriter.WriteValue("localhost");
- }
- else
- {
- try
- {
- DnsDatagram ptrResponse = await _dnsServer.DirectQueryAsync(new DnsQuestionRecord(address, DnsClass.IN), 200);
- if ((ptrResponse != null) && (ptrResponse.Answer.Count > 0))
- {
- IReadOnlyList<string> ptrDomains = DnsClient.ParseResponsePTR(ptrResponse);
- if (ptrDomains != null)
- {
- jsonWriter.WritePropertyName("domain");
- jsonWriter.WriteValue(ptrDomains[0]);
- }
- }
- }
- catch
- { }
- }
- }
- jsonWriter.WritePropertyName("hits");
- jsonWriter.WriteValue(item.Value);
- jsonWriter.WriteEndObject();
- }
- jsonWriter.WriteEndArray();
- }
- //top domains
- {
- List<KeyValuePair<string, int>> topDomains = data["topDomains"];
- jsonWriter.WritePropertyName("topDomains");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair<string, int> item in topDomains)
- {
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(item.Key);
- jsonWriter.WritePropertyName("hits");
- jsonWriter.WriteValue(item.Value);
- jsonWriter.WriteEndObject();
- }
- jsonWriter.WriteEndArray();
- }
- //top blocked domains
- {
- List<KeyValuePair<string, int>> topBlockedDomains = data["topBlockedDomains"];
- jsonWriter.WritePropertyName("topBlockedDomains");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair<string, int> item in topBlockedDomains)
- {
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(item.Key);
- jsonWriter.WritePropertyName("hits");
- jsonWriter.WriteValue(item.Value);
- jsonWriter.WriteEndObject();
- }
- jsonWriter.WriteEndArray();
- }
- }
- private static void WriteChartDataSet(JsonTextWriter jsonWriter, string label, string backgroundColor, string borderColor, List<KeyValuePair<string, int>> statsPerInterval)
- {
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("label");
- jsonWriter.WriteValue(label);
- jsonWriter.WritePropertyName("backgroundColor");
- jsonWriter.WriteValue(backgroundColor);
- jsonWriter.WritePropertyName("borderColor");
- jsonWriter.WriteValue(borderColor);
- jsonWriter.WritePropertyName("borderWidth");
- jsonWriter.WriteValue(2);
- jsonWriter.WritePropertyName("fill");
- jsonWriter.WriteValue(true);
- jsonWriter.WritePropertyName("data");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair<string, int> item in statsPerInterval)
- jsonWriter.WriteValue(item.Value);
- jsonWriter.WriteEndArray();
- jsonWriter.WriteEndObject();
- }
- private void FlushCache(HttpListenerRequest request)
- {
- _dnsServer.CacheZoneManager.Flush();
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Cache was flushed.");
- }
- private void ListCachedZones(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string domain = request.QueryString["domain"];
- if (domain == null)
- domain = "";
- string direction = request.QueryString["direction"];
- List<string> subZones;
- List<DnsResourceRecord> records;
- while (true)
- {
- subZones = _dnsServer.CacheZoneManager.ListSubDomains(domain);
- records = _dnsServer.CacheZoneManager.ListAllRecords(domain);
- if (records.Count > 0)
- break;
- if (subZones.Count != 1)
- break;
- if (direction == "up")
- {
- if (domain.Length == 0)
- break;
- int i = domain.IndexOf('.');
- if (i < 0)
- domain = "";
- else
- domain = domain.Substring(i + 1);
- }
- else if (domain.Length == 0)
- {
- domain = subZones[0];
- }
- else
- {
- domain = subZones[0] + "." + domain;
- }
- }
- subZones.Sort();
- jsonWriter.WritePropertyName("domain");
- jsonWriter.WriteValue(domain);
- jsonWriter.WritePropertyName("zones");
- jsonWriter.WriteStartArray();
- if (domain.Length != 0)
- domain = "." + domain;
- foreach (string subZone in subZones)
- jsonWriter.WriteValue(subZone + domain);
- jsonWriter.WriteEndArray();
- WriteRecordsAsJson(records, jsonWriter, false);
- }
- private void DeleteCachedZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (_dnsServer.CacheZoneManager.DeleteZone(domain))
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Cached zone was deleted: " + domain);
- }
- private void ListAllowedZones(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string domain = request.QueryString["domain"];
- if (domain == null)
- domain = "";
- string direction = request.QueryString["direction"];
- List<string> subZones;
- IReadOnlyList<DnsResourceRecord> records;
- while (true)
- {
- subZones = _dnsServer.AllowedZoneManager.ListSubDomains(domain);
- records = _dnsServer.AllowedZoneManager.QueryRecords(domain, DnsResourceRecordType.ANY);
- if (records.Count > 0)
- break;
- if (subZones.Count != 1)
- break;
- if (direction == "up")
- {
- if (domain.Length == 0)
- break;
- int i = domain.IndexOf('.');
- if (i < 0)
- domain = "";
- else
- domain = domain.Substring(i + 1);
- }
- else if (domain.Length == 0)
- {
- domain = subZones[0];
- }
- else
- {
- domain = subZones[0] + "." + domain;
- }
- }
- subZones.Sort();
- jsonWriter.WritePropertyName("domain");
- jsonWriter.WriteValue(domain);
- jsonWriter.WritePropertyName("zones");
- jsonWriter.WriteStartArray();
- if (domain.Length != 0)
- domain = "." + domain;
- foreach (string subZone in subZones)
- jsonWriter.WriteValue(subZone + domain);
- jsonWriter.WriteEndArray();
- WriteRecordsAsJson(new List<DnsResourceRecord>(records), jsonWriter, false);
- }
- private void ImportAllowedZones(HttpListenerRequest request)
- {
- if (!request.ContentType.StartsWith("application/x-www-form-urlencoded"))
- throw new WebServiceException("Invalid content type. Expected application/x-www-form-urlencoded.");
- string formRequest;
- using (StreamReader sR = new StreamReader(request.InputStream, request.ContentEncoding))
- {
- formRequest = sR.ReadToEnd();
- }
- string[] formParts = formRequest.Split('&');
- foreach (string formPart in formParts)
- {
- if (formPart.StartsWith("allowedZones="))
- {
- string[] allowedZones = formPart.Substring(13).Split(',');
- bool added = false;
- foreach (string allowedZone in allowedZones)
- {
- if (_dnsServer.AllowedZoneManager.AllowZone(allowedZone))
- added = true;
- }
- if (added)
- {
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Total " + allowedZones.Length + " zones were imported into allowed zone successfully.");
- _dnsServer.AllowedZoneManager.SaveZoneFile();
- }
- return;
- }
- }
- throw new WebServiceException("Parameter 'allowedZones' missing.");
- }
- private void ExportAllowedZones(HttpListenerResponse response)
- {
- IReadOnlyList<AuthZoneInfo> zoneInfoList = _dnsServer.AllowedZoneManager.ListZones();
- response.ContentType = "text/plain";
- response.AddHeader("Content-Disposition", "attachment;filename=AllowedZones.txt");
- using (StreamWriter sW = new StreamWriter(new BufferedStream(response.OutputStream)))
- {
- foreach (AuthZoneInfo zoneInfo in zoneInfoList)
- sW.WriteLine(zoneInfo.Name);
- }
- }
- private void DeleteAllowedZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (_dnsServer.AllowedZoneManager.DeleteZone(domain))
- {
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Allowed zone was deleted: " + domain);
- _dnsServer.AllowedZoneManager.SaveZoneFile();
- }
- }
- private void AllowZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (IPAddress.TryParse(domain, out IPAddress ipAddress))
- domain = (new DnsQuestionRecord(ipAddress, DnsClass.IN)).Name;
- if (_dnsServer.AllowedZoneManager.AllowZone(domain))
- {
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Zone was allowed: " + domain);
- _dnsServer.AllowedZoneManager.SaveZoneFile();
- }
- }
- private void ListBlockedZones(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string domain = request.QueryString["domain"];
- if (domain == null)
- domain = "";
- string direction = request.QueryString["direction"];
- List<string> subZones;
- IReadOnlyList<DnsResourceRecord> records;
- while (true)
- {
- subZones = _dnsServer.BlockedZoneManager.ListSubDomains(domain);
- records = _dnsServer.BlockedZoneManager.QueryRecords(domain, DnsResourceRecordType.ANY);
- if (records.Count > 0)
- break;
- if (subZones.Count != 1)
- break;
- if (direction == "up")
- {
- if (domain.Length == 0)
- break;
- int i = domain.IndexOf('.');
- if (i < 0)
- domain = "";
- else
- domain = domain.Substring(i + 1);
- }
- else if (domain.Length == 0)
- {
- domain = subZones[0];
- }
- else
- {
- domain = subZones[0] + "." + domain;
- }
- }
- subZones.Sort();
- jsonWriter.WritePropertyName("domain");
- jsonWriter.WriteValue(domain);
- jsonWriter.WritePropertyName("zones");
- jsonWriter.WriteStartArray();
- if (domain.Length != 0)
- domain = "." + domain;
- foreach (string subZone in subZones)
- jsonWriter.WriteValue(subZone + domain);
- jsonWriter.WriteEndArray();
- WriteRecordsAsJson(new List<DnsResourceRecord>(records), jsonWriter, false);
- }
- private void ImportBlockedZones(HttpListenerRequest request)
- {
- if (!request.ContentType.StartsWith("application/x-www-form-urlencoded"))
- throw new WebServiceException("Invalid content type. Expected application/x-www-form-urlencoded.");
- string formRequest;
- using (StreamReader sR = new StreamReader(request.InputStream, request.ContentEncoding))
- {
- formRequest = sR.ReadToEnd();
- }
- string[] formParts = formRequest.Split('&');
- foreach (string formPart in formParts)
- {
- if (formPart.StartsWith("blockedZones="))
- {
- string[] blockedZones = formPart.Substring(13).Split(',');
- bool added = false;
- foreach (string blockedZone in blockedZones)
- {
- if (_dnsServer.BlockedZoneManager.BlockZone(blockedZone))
- added = true;
- }
- if (added)
- {
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Total " + blockedZones.Length + " zones were imported into blocked zone successfully.");
- _dnsServer.BlockedZoneManager.SaveZoneFile();
- }
- return;
- }
- }
- throw new WebServiceException("Parameter 'blockedZones' missing.");
- }
- private void ExportBlockedZones(HttpListenerResponse response)
- {
- IReadOnlyList<AuthZoneInfo> zoneInfoList = _dnsServer.BlockedZoneManager.ListZones();
- response.ContentType = "text/plain";
- response.AddHeader("Content-Disposition", "attachment;filename=BlockedZones.txt");
- using (StreamWriter sW = new StreamWriter(new BufferedStream(response.OutputStream)))
- {
- foreach (AuthZoneInfo zoneInfo in zoneInfoList)
- sW.WriteLine(zoneInfo.Name);
- }
- }
- private void DeleteBlockedZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (_dnsServer.BlockedZoneManager.DeleteZone(domain))
- {
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Blocked zone was deleted: " + domain);
- _dnsServer.BlockedZoneManager.SaveZoneFile();
- }
- }
- private void BlockZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (IPAddress.TryParse(domain, out IPAddress ipAddress))
- domain = (new DnsQuestionRecord(ipAddress, DnsClass.IN)).Name;
- if (_dnsServer.BlockedZoneManager.BlockZone(domain))
- {
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Domain was added to blocked zone: " + domain);
- _dnsServer.BlockedZoneManager.SaveZoneFile();
- }
- }
- private void ListZones(JsonTextWriter jsonWriter)
- {
- List<AuthZoneInfo> zones = _dnsServer.AuthZoneManager.ListZones();
- zones.Sort();
- jsonWriter.WritePropertyName("zones");
- jsonWriter.WriteStartArray();
- foreach (AuthZoneInfo zone in zones)
- {
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(zone.Name);
- jsonWriter.WritePropertyName("type");
- jsonWriter.WriteValue(zone.Type.ToString());
- switch (zone.Type)
- {
- case AuthZoneType.Primary:
- jsonWriter.WritePropertyName("internal");
- jsonWriter.WriteValue(zone.Internal);
- break;
- case AuthZoneType.Secondary:
- case AuthZoneType.Stub:
- jsonWriter.WritePropertyName("expiry");
- jsonWriter.WriteValue(zone.Expiry.ToLocalTime().ToString("dd MMM yyyy HH:mm:ss"));
- jsonWriter.WritePropertyName("isExpired");
- jsonWriter.WriteValue(zone.IsExpired);
- break;
- }
- jsonWriter.WritePropertyName("disabled");
- jsonWriter.WriteValue(zone.Disabled);
- jsonWriter.WriteEndObject();
- }
- jsonWriter.WriteEndArray();
- }
- private async Task CreateZoneAsync(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (domain.Contains("*"))
- throw new WebServiceException("Domain name for a zone cannot contain wildcard character.");
- if (IPAddress.TryParse(domain, out IPAddress ipAddress))
- {
- domain = new DnsQuestionRecord(ipAddress, DnsClass.IN).Name.ToLower();
- }
- else if (domain.Contains("/"))
- {
- string[] parts = domain.Split('/');
- if ((parts.Length == 2) && IPAddress.TryParse(parts[0], out ipAddress) && int.TryParse(parts[1], out int subnetMaskWidth))
- domain = Zone.GetReverseZone(ipAddress, subnetMaskWidth);
- }
- else if (domain.EndsWith("."))
- {
- domain = domain.Substring(0, domain.Length - 1);
- }
- AuthZoneType type = AuthZoneType.Primary;
- string strType = request.QueryString["type"];
- if (!string.IsNullOrEmpty(strType))
- type = (AuthZoneType)Enum.Parse(typeof(AuthZoneType), strType, true);
- switch (type)
- {
- case AuthZoneType.Primary:
- if (_dnsServer.AuthZoneManager.CreatePrimaryZone(domain, _dnsServer.ServerDomain, false) == null)
- throw new WebServiceException("Zone already exists: " + domain);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Authoritative primary zone was created: " + domain);
- _dnsServer.AuthZoneManager.SaveZoneFile(domain);
- break;
- case AuthZoneType.Secondary:
- {
- string strPrimaryNameServerAddresses = request.QueryString["primaryNameServerAddresses"];
- if (string.IsNullOrEmpty(strPrimaryNameServerAddresses))
- strPrimaryNameServerAddresses = null;
- if (await _dnsServer.AuthZoneManager.CreateSecondaryZoneAsync(domain, strPrimaryNameServerAddresses) == null)
- throw new WebServiceException("Zone already exists: " + domain);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Authoritative secondary zone was created: " + domain);
- _dnsServer.AuthZoneManager.SaveZoneFile(domain);
- }
- break;
- case AuthZoneType.Stub:
- {
- string strPrimaryNameServerAddresses = request.QueryString["primaryNameServerAddresses"];
- if (string.IsNullOrEmpty(strPrimaryNameServerAddresses))
- strPrimaryNameServerAddresses = null;
- if (await _dnsServer.AuthZoneManager.CreateStubZoneAsync(domain, strPrimaryNameServerAddresses) == null)
- throw new WebServiceException("Zone already exists: " + domain);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Stub zone was created: " + domain);
- _dnsServer.AuthZoneManager.SaveZoneFile(domain);
- }
- break;
- case AuthZoneType.Forwarder:
- {
- DnsTransportProtocol forwarderProtocol = DnsTransportProtocol.Udp;
- string strForwarderProtocol = request.QueryString["protocol"];
- if (!string.IsNullOrEmpty(strForwarderProtocol))
- forwarderProtocol = (DnsTransportProtocol)Enum.Parse(typeof(DnsTransportProtocol), strForwarderProtocol, true);
- string strForwarder = request.QueryString["forwarder"];
- if (string.IsNullOrEmpty(strForwarder))
- throw new WebServiceException("Parameter 'forwarder' missing.");
- if (_dnsServer.AuthZoneManager.CreateForwarderZone(domain, forwarderProtocol, strForwarder) == null)
- throw new WebServiceException("Zone already exists: " + domain);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Forwarder zone was created: " + domain);
- _dnsServer.AuthZoneManager.SaveZoneFile(domain);
- }
- break;
- default:
- throw new NotSupportedException("Zone type not supported.");
- }
- jsonWriter.WritePropertyName("domain");
- jsonWriter.WriteValue(string.IsNullOrEmpty(domain) ? "." : domain);
- }
- private void DeleteZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
- AuthZoneInfo zoneInfo = _dnsServer.AuthZoneManager.GetAuthZoneInfo(domain);
- if (zoneInfo == null)
- throw new WebServiceException("Zone '" + domain + "' was not found.");
- if (zoneInfo.Internal)
- throw new WebServiceException("Access was denied to manage internal DNS Server zone.");
- if (!_dnsServer.AuthZoneManager.DeleteZone(domain))
- throw new WebServiceException("Zone '" + domain + "' was not found.");
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] " + zoneInfo.Type.ToString() + " zone was deleted: " + domain);
- _dnsServer.AuthZoneManager.DeleteZoneFile(domain);
- }
- private void EnableZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
- AuthZoneInfo zoneInfo = _dnsServer.AuthZoneManager.GetAuthZoneInfo(domain);
- if (zoneInfo == null)
- throw new WebServiceException("Zone '" + domain + "' was not found.");
- if (zoneInfo.Internal)
- throw new WebServiceException("Access was denied to manage internal DNS Server zone.");
- zoneInfo.Disabled = false;
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] " + zoneInfo.Type.ToString() + " zone was enabled: " + domain);
- _dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
- }
- private void DisableZone(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
- AuthZoneInfo zoneInfo = _dnsServer.AuthZoneManager.GetAuthZoneInfo(domain);
- if (zoneInfo == null)
- throw new WebServiceException("Zone '" + domain + "' was not found.");
- if (zoneInfo.Internal)
- throw new WebServiceException("Access was denied to manage internal DNS Server zone.");
- zoneInfo.Disabled = true;
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] " + zoneInfo.Type.ToString() + " zone was disabled: " + domain);
- _dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
- }
- private void AddRecord(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
- AuthZoneInfo zoneInfo = _dnsServer.AuthZoneManager.GetAuthZoneInfo(domain);
- if (zoneInfo == null)
- throw new WebServiceException("Zone '" + domain + "' was not found.");
- if (zoneInfo.Internal)
- throw new WebServiceException("Access was denied to manage internal DNS Server zone.");
- string strType = request.QueryString["type"];
- if (string.IsNullOrEmpty(strType))
- throw new WebServiceException("Parameter 'type' missing.");
- DnsResourceRecordType type = (DnsResourceRecordType)Enum.Parse(typeof(DnsResourceRecordType), strType);
- string value = request.QueryString["value"];
- if (string.IsNullOrEmpty(value))
- throw new WebServiceException("Parameter 'value' missing.");
- uint ttl;
- string strTtl = request.QueryString["ttl"];
- if (string.IsNullOrEmpty(strTtl))
- ttl = 3600;
- else
- ttl = uint.Parse(strTtl);
- switch (type)
- {
- case DnsResourceRecordType.A:
- case DnsResourceRecordType.AAAA:
- IPAddress ipAddress = IPAddress.Parse(value);
- bool ptr = false;
- string strPtr = request.QueryString["ptr"];
- if (!string.IsNullOrEmpty(strPtr))
- ptr = bool.Parse(strPtr);
- if (ptr)
- {
- string ptrDomain = Zone.GetReverseZone(ipAddress, 32);
- AuthZoneInfo reverseZoneInfo = _dnsServer.AuthZoneManager.GetAuthZoneInfo(ptrDomain);
- if (reverseZoneInfo == null)
- throw new DnsServerException("No reverse zone available to add PTR record.");
- if (reverseZoneInfo.Internal)
- throw new DnsServerException("Reverse zone '" + reverseZoneInfo.Name + "' is an internal zone.");
- if (reverseZoneInfo.Type != AuthZoneType.Primary)
- throw new DnsServerException("Reverse zone '" + reverseZoneInfo.Name + "' is not a primary zone.");
- _dnsServer.AuthZoneManager.SetRecords(ptrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecord[] { new DnsPTRRecord(domain) });
- _dnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name);
- }
- if (type == DnsResourceRecordType.A)
- _dnsServer.AuthZoneManager.AddRecord(domain, type, ttl, new DnsARecord(ipAddress));
- else
- _dnsServer.AuthZoneManager.AddRecord(domain, type, ttl, new DnsAAAARecord(ipAddress));
- break;
- case DnsResourceRecordType.MX:
- {
- string preference = request.QueryString["preference"];
- if (string.IsNullOrEmpty(preference))
- throw new WebServiceException("Parameter 'preference' missing.");
- _dnsServer.AuthZoneManager.AddRecord(domain, type, ttl, new DnsMXRecord(ushort.Parse(preference), value));
- }
- break;
- case DnsResourceRecordType.TXT:
- _dnsServer.AuthZoneManager.AddRecord(domain, type, ttl, new DnsTXTRecord(value));
- break;
- case DnsResourceRecordType.NS:
- {
- string glueAddresses = request.QueryString["glue"];
- if (string.IsNullOrEmpty(glueAddresses))
- glueAddresses = null;
- DnsResourceRecord nsRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsNSRecord(value));
- if (glueAddresses != null)
- nsRecord.SetGlueRecords(glueAddresses);
- _dnsServer.AuthZoneManager.AddRecord(nsRecord);
- }
- break;
- case DnsResourceRecordType.PTR:
- _dnsServer.AuthZoneManager.SetRecords(domain, type, ttl, new DnsResourceRecordData[] { new DnsPTRRecord(value) });
- break;
- case DnsResourceRecordType.CNAME:
- _dnsServer.AuthZoneManager.SetRecords(domain, type, ttl, new DnsResourceRecordData[] { new DnsCNAMERecord(value) });
- break;
- case DnsResourceRecordType.SRV:
- {
- string priority = request.QueryString["priority"];
- if (string.IsNullOrEmpty(priority))
- throw new WebServiceException("Parameter 'priority' missing.");
- string weight = request.QueryString["weight"];
- if (string.IsNullOrEmpty(weight))
- throw new WebServiceException("Parameter 'weight' missing.");
- string port = request.QueryString["port"];
- if (string.IsNullOrEmpty(port))
- throw new WebServiceException("Parameter 'port' missing.");
- _dnsServer.AuthZoneManager.AddRecord(domain, type, ttl, new DnsSRVRecord(ushort.Parse(priority), ushort.Parse(weight), ushort.Parse(port), value));
- }
- break;
- case DnsResourceRecordType.CAA:
- {
- string flags = request.QueryString["flags"];
- if (string.IsNullOrEmpty(flags))
- throw new WebServiceException("Parameter 'flags' missing.");
- string tag = request.QueryString["tag"];
- if (string.IsNullOrEmpty(tag))
- throw new WebServiceException("Parameter 'tag' missing.");
- _dnsServer.AuthZoneManager.AddRecord(domain, type, ttl, new DnsCAARecord(byte.Parse(flags), tag, value));
- }
- break;
- case DnsResourceRecordType.ANAME:
- _dnsServer.AuthZoneManager.SetRecords(domain, type, ttl, new DnsResourceRecordData[] { new DnsANAMERecord(value) });
- break;
- case DnsResourceRecordType.FWD:
- {
- string protocol = request.QueryString["protocol"];
- if (string.IsNullOrEmpty(protocol))
- protocol = "Udp";
- _dnsServer.AuthZoneManager.AddRecord(domain, type, 0, new DnsForwarderRecord((DnsTransportProtocol)Enum.Parse(typeof(DnsTransportProtocol), protocol, true), value));
- }
- break;
- default:
- throw new WebServiceException("Type not supported for AddRecords().");
- }
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] New record was added to authoritative zone {domain: " + domain + "; type: " + type + "; value: " + value + "; ttl: " + ttl + ";}");
- _dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
- }
- private void GetRecords(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
- AuthZoneInfo zoneInfo = _dnsServer.AuthZoneManager.GetAuthZoneInfo(domain);
- if (zoneInfo == null)
- throw new WebServiceException("Zone '" + domain + "' was not found.");
- jsonWriter.WritePropertyName("zone");
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(zoneInfo.Name);
- jsonWriter.WritePropertyName("type");
- jsonWriter.WriteValue(zoneInfo.Type.ToString());
- switch (zoneInfo.Type)
- {
- case AuthZoneType.Primary:
- jsonWriter.WritePropertyName("internal");
- jsonWriter.WriteValue(zoneInfo.Internal);
- break;
- case AuthZoneType.Secondary:
- case AuthZoneType.Stub:
- jsonWriter.WritePropertyName("expiry");
- jsonWriter.WriteValue(zoneInfo.Expiry.ToLocalTime().ToString("dd MMM yyyy HH:mm:ss"));
- jsonWriter.WritePropertyName("isExpired");
- jsonWriter.WriteValue(zoneInfo.IsExpired);
- break;
- }
- jsonWriter.WritePropertyName("disabled");
- jsonWriter.WriteValue(zoneInfo.Disabled);
- jsonWriter.WriteEndObject();
- List<DnsResourceRecord> records = _dnsServer.AuthZoneManager.ListAllRecords(domain);
- WriteRecordsAsJson(records, jsonWriter, true);
- }
- private static void WriteRecordsAsJson(List<DnsResourceRecord> records, JsonTextWriter jsonWriter, bool authoritativeZoneRecords)
- {
- if (records == null)
- {
- jsonWriter.WritePropertyName("records");
- jsonWriter.WriteStartArray();
- jsonWriter.WriteEndArray();
- return;
- }
- records.Sort();
- Dictionary<string, Dictionary<DnsResourceRecordType, List<DnsResourceRecord>>> groupedByDomainRecords = DnsResourceRecord.GroupRecords(records);
- jsonWriter.WritePropertyName("records");
- jsonWriter.WriteStartArray();
- foreach (KeyValuePair<string, Dictionary<DnsResourceRecordType, List<DnsResourceRecord>>> groupedByTypeRecords in groupedByDomainRecords)
- {
- foreach (KeyValuePair<DnsResourceRecordType, List<DnsResourceRecord>> groupedRecords in groupedByTypeRecords.Value)
- {
- foreach (DnsResourceRecord record in groupedRecords.Value)
- {
- jsonWriter.WriteStartObject();
- if (authoritativeZoneRecords)
- {
- jsonWriter.WritePropertyName("disabled");
- jsonWriter.WriteValue(record.IsDisabled());
- }
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(record.Name);
- jsonWriter.WritePropertyName("type");
- jsonWriter.WriteValue(record.Type.ToString());
- jsonWriter.WritePropertyName("ttl");
- if (authoritativeZoneRecords)
- jsonWriter.WriteValue(record.TtlValue);
- else
- jsonWriter.WriteValue(record.TTL);
- jsonWriter.WritePropertyName("rData");
- jsonWriter.WriteStartObject();
- switch (record.Type)
- {
- case DnsResourceRecordType.A:
- {
- DnsARecord rdata = (record.RDATA as DnsARecord);
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.IPAddress);
- }
- }
- break;
- case DnsResourceRecordType.AAAA:
- {
- DnsAAAARecord rdata = (record.RDATA as DnsAAAARecord);
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.IPAddress);
- }
- }
- break;
- case DnsResourceRecordType.SOA:
- {
- DnsSOARecord rdata = record.RDATA as DnsSOARecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("primaryNameServer");
- jsonWriter.WriteValue(rdata.PrimaryNameServer);
- jsonWriter.WritePropertyName("responsiblePerson");
- jsonWriter.WriteValue(rdata.ResponsiblePerson);
- jsonWriter.WritePropertyName("serial");
- jsonWriter.WriteValue(rdata.Serial);
- jsonWriter.WritePropertyName("refresh");
- jsonWriter.WriteValue(rdata.Refresh);
- jsonWriter.WritePropertyName("retry");
- jsonWriter.WriteValue(rdata.Retry);
- jsonWriter.WritePropertyName("expire");
- jsonWriter.WriteValue(rdata.Expire);
- jsonWriter.WritePropertyName("minimum");
- jsonWriter.WriteValue(rdata.Minimum);
- }
- IReadOnlyList<DnsResourceRecord> glueRecords = record.GetGlueRecords();
- if (glueRecords.Count > 0)
- {
- string primaryAddresses = null;
- foreach (DnsResourceRecord glueRecord in glueRecords)
- {
- if (primaryAddresses == null)
- primaryAddresses = glueRecord.RDATA.ToString();
- else
- primaryAddresses = primaryAddresses + ", " + glueRecord.RDATA.ToString();
- }
- jsonWriter.WritePropertyName("primaryAddresses");
- jsonWriter.WriteValue(primaryAddresses);
- }
- }
- break;
- case DnsResourceRecordType.PTR:
- {
- DnsPTRRecord rdata = record.RDATA as DnsPTRRecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.Domain);
- }
- }
- break;
- case DnsResourceRecordType.MX:
- {
- DnsMXRecord rdata = record.RDATA as DnsMXRecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("preference");
- jsonWriter.WriteValue(rdata.Preference);
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.Exchange);
- }
- }
- break;
- case DnsResourceRecordType.TXT:
- {
- DnsTXTRecord rdata = record.RDATA as DnsTXTRecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.Text);
- }
- }
- break;
- case DnsResourceRecordType.NS:
- {
- DnsNSRecord rdata = record.RDATA as DnsNSRecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.NameServer);
- }
- IReadOnlyList<DnsResourceRecord> glueRecords = record.GetGlueRecords();
- if (glueRecords.Count > 0)
- {
- string glue = null;
- foreach (DnsResourceRecord glueRecord in glueRecords)
- {
- if (glue == null)
- glue = glueRecord.RDATA.ToString();
- else
- glue = glue + ", " + glueRecord.RDATA.ToString();
- }
- jsonWriter.WritePropertyName("glue");
- jsonWriter.WriteValue(glue);
- }
- }
- break;
- case DnsResourceRecordType.CNAME:
- {
- DnsCNAMERecord rdata = record.RDATA as DnsCNAMERecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.Domain);
- }
- }
- break;
- case DnsResourceRecordType.SRV:
- {
- DnsSRVRecord rdata = record.RDATA as DnsSRVRecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("priority");
- jsonWriter.WriteValue(rdata.Priority);
- jsonWriter.WritePropertyName("weight");
- jsonWriter.WriteValue(rdata.Weight);
- jsonWriter.WritePropertyName("port");
- jsonWriter.WriteValue(rdata.Port);
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.Target);
- }
- }
- break;
- case DnsResourceRecordType.CAA:
- {
- DnsCAARecord rdata = record.RDATA as DnsCAARecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("flags");
- jsonWriter.WriteValue(rdata.Flags);
- jsonWriter.WritePropertyName("tag");
- jsonWriter.WriteValue(rdata.Tag);
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.Value);
- }
- }
- break;
- case DnsResourceRecordType.ANAME:
- {
- DnsANAMERecord rdata = record.RDATA as DnsANAMERecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.Domain);
- }
- }
- break;
- case DnsResourceRecordType.FWD:
- {
- DnsForwarderRecord rdata = record.RDATA as DnsForwarderRecord;
- if (rdata != null)
- {
- jsonWriter.WritePropertyName("protocol");
- jsonWriter.WriteValue(rdata.Protocol.ToString());
- jsonWriter.WritePropertyName("value");
- jsonWriter.WriteValue(rdata.Forwarder);
- }
- }
- break;
- default:
- {
- jsonWriter.WritePropertyName("value");
- using (MemoryStream mS = new MemoryStream())
- {
- record.RDATA.WriteTo(mS, new List<DnsDomainOffset>());
- jsonWriter.WriteValue(Convert.ToBase64String(mS.ToArray()));
- }
- }
- break;
- }
- jsonWriter.WriteEndObject();
- jsonWriter.WriteEndObject();
- }
- }
- }
- jsonWriter.WriteEndArray();
- }
- private void DeleteRecord(HttpListenerRequest request)
- {
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
- AuthZoneInfo zoneInfo = _dnsServer.AuthZoneManager.GetAuthZoneInfo(domain);
- if (zoneInfo == null)
- throw new WebServiceException("Zone '" + domain + "' was not found.");
- if (zoneInfo.Internal)
- throw new WebServiceException("Access was denied to manage internal DNS Server zone.");
- string strType = request.QueryString["type"];
- if (string.IsNullOrEmpty(strType))
- throw new WebServiceException("Parameter 'type' missing.");
- DnsResourceRecordType type = (DnsResourceRecordType)Enum.Parse(typeof(DnsResourceRecordType), strType);
- string value = request.QueryString["value"];
- if (string.IsNullOrEmpty(value))
- throw new WebServiceException("Parameter 'value' missing.");
- switch (type)
- {
- case DnsResourceRecordType.A:
- _dnsServer.AuthZoneManager.DeleteRecord(domain, type, new DnsARecord(IPAddress.Parse(value)));
- break;
- case DnsResourceRecordType.AAAA:
- _dnsServer.AuthZoneManager.DeleteRecord(domain, type, new DnsAAAARecord(IPAddress.Parse(value)));
- break;
- case DnsResourceRecordType.MX:
- _dnsServer.AuthZoneManager.DeleteRecord(domain, type, new DnsMXRecord(0, value));
- break;
- case DnsResourceRecordType.TXT:
- _dnsServer.AuthZoneManager.DeleteRecord(domain, type, new DnsTXTRecord(value));
- break;
- case DnsResourceRecordType.NS:
- _dnsServer.AuthZoneManager.DeleteRecord(domain, type, new DnsNSRecord(value));
- break;
- case DnsResourceRecordType.CNAME:
- case DnsResourceRecordType.PTR:
- case DnsResourceRecordType.ANAME:
- _dnsServer.AuthZoneManager.DeleteRecords(domain, type);
- break;
- case DnsResourceRecordType.SRV:
- {
- string port = request.QueryString["port"];
- if (string.IsNullOrEmpty(port))
- throw new WebServiceException("Parameter 'port' missing.");
- _dnsServer.AuthZoneManager.DeleteRecord(domain, type, new DnsSRVRecord(0, 0, ushort.Parse(port), value));
- }
- break;
- case DnsResourceRecordType.CAA:
- {
- string flags = request.QueryString["flags"];
- if (string.IsNullOrEmpty(flags))
- throw new WebServiceException("Parameter 'flags' missing.");
- string tag = request.QueryString["tag"];
- if (string.IsNullOrEmpty(tag))
- throw new WebServiceException("Parameter 'tag' missing.");
- _dnsServer.AuthZoneManager.DeleteRecord(domain, type, new DnsCAARecord(byte.Parse(flags), tag, value));
- }
- break;
- case DnsResourceRecordType.FWD:
- {
- string strProtocol = request.QueryString["protocol"];
- if (string.IsNullOrEmpty(strProtocol))
- strProtocol = "Udp";
- _dnsServer.AuthZoneManager.DeleteRecord(domain, type, new DnsForwarderRecord((DnsTransportProtocol)Enum.Parse(typeof(DnsTransportProtocol), strProtocol, true), value));
- }
- break;
- default:
- throw new WebServiceException("Type not supported for DeleteRecord().");
- }
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Record was deleted from authoritative zone {domain: " + domain + "; type: " + type + "; value: " + value + ";}");
- _dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
- }
- private void UpdateRecord(HttpListenerRequest request)
- {
- string strType = request.QueryString["type"];
- if (string.IsNullOrEmpty(strType))
- throw new WebServiceException("Parameter 'type' missing.");
- DnsResourceRecordType type = (DnsResourceRecordType)Enum.Parse(typeof(DnsResourceRecordType), strType);
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
- AuthZoneInfo zoneInfo = _dnsServer.AuthZoneManager.GetAuthZoneInfo(domain);
- if (zoneInfo == null)
- throw new WebServiceException("Zone '" + domain + "' was not found.");
- if (zoneInfo.Internal)
- throw new WebServiceException("Access was denied to manage internal DNS Server zone.");
- string newDomain = request.QueryString["newDomain"];
- if (string.IsNullOrEmpty(newDomain))
- newDomain = domain;
- if (newDomain.EndsWith("."))
- newDomain = newDomain.Substring(0, newDomain.Length - 1);
- uint ttl;
- string strTtl = request.QueryString["ttl"];
- if (string.IsNullOrEmpty(strTtl))
- ttl = 3600;
- else
- ttl = uint.Parse(strTtl);
- string value = request.QueryString["value"];
- string newValue = request.QueryString["newValue"];
- if (string.IsNullOrEmpty(newValue))
- newValue = value;
- bool disable = false;
- string strDisable = request.QueryString["disable"];
- if (!string.IsNullOrEmpty(strDisable))
- disable = bool.Parse(strDisable);
- switch (type)
- {
- case DnsResourceRecordType.A:
- case DnsResourceRecordType.AAAA:
- {
- IPAddress oldIpAddress = IPAddress.Parse(value);
- IPAddress newIpAddress = IPAddress.Parse(newValue);
- bool ptr = false;
- string strPtr = request.QueryString["ptr"];
- if (!string.IsNullOrEmpty(strPtr))
- ptr = bool.Parse(strPtr);
- if (ptr)
- {
- //delete old PTR record if any
- _dnsServer.AuthZoneManager.DeleteRecords(Zone.GetReverseZone(oldIpAddress, 32), DnsResourceRecordType.PTR);
- //add new PTR record
- string ptrDomain = Zone.GetReverseZone(newIpAddress, 32);
- AuthZoneInfo reverseZoneInfo = _dnsServer.AuthZoneManager.GetAuthZoneInfo(ptrDomain);
- if (reverseZoneInfo == null)
- throw new DnsServerException("No reverse zone available to add PTR record.");
- if (reverseZoneInfo.Internal)
- throw new DnsServerException("Reverse zone '" + reverseZoneInfo.Name + "' is an internal zone.");
- if (reverseZoneInfo.Type != AuthZoneType.Primary)
- throw new DnsServerException("Reverse zone '" + reverseZoneInfo.Name + "' is not a primary zone.");
- _dnsServer.AuthZoneManager.SetRecords(ptrDomain, DnsResourceRecordType.PTR, ttl, new DnsPTRRecord[] { new DnsPTRRecord(domain) });
- _dnsServer.AuthZoneManager.SaveZoneFile(reverseZoneInfo.Name);
- }
- DnsResourceRecord oldRecord;
- DnsResourceRecord newRecord;
- if (type == DnsResourceRecordType.A)
- {
- oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsARecord(oldIpAddress));
- newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsARecord(newIpAddress));
- }
- else
- {
- oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsAAAARecord(oldIpAddress));
- newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsAAAARecord(newIpAddress));
- }
- if (disable)
- newRecord.Disable();
- _dnsServer.AuthZoneManager.UpdateRecord(oldRecord, newRecord);
- }
- break;
- case DnsResourceRecordType.MX:
- {
- string preference = request.QueryString["preference"];
- if (string.IsNullOrEmpty(preference))
- preference = "1";
- DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsMXRecord(0, value));
- DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsMXRecord(ushort.Parse(preference), newValue));
- if (disable)
- newRecord.Disable();
- _dnsServer.AuthZoneManager.UpdateRecord(oldRecord, newRecord);
- }
- break;
- case DnsResourceRecordType.TXT:
- {
- DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsTXTRecord(value));
- DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsTXTRecord(newValue));
- if (disable)
- newRecord.Disable();
- _dnsServer.AuthZoneManager.UpdateRecord(oldRecord, newRecord);
- }
- break;
- case DnsResourceRecordType.NS:
- {
- DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsNSRecord(value));
- DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsNSRecord(newValue));
- if (disable)
- newRecord.Disable();
- string glueAddresses = request.QueryString["glue"];
- if (!string.IsNullOrEmpty(glueAddresses))
- newRecord.SetGlueRecords(glueAddresses);
- _dnsServer.AuthZoneManager.UpdateRecord(oldRecord, newRecord);
- }
- break;
- case DnsResourceRecordType.SOA:
- {
- string primaryNameServer = request.QueryString["primaryNameServer"];
- if (string.IsNullOrEmpty(primaryNameServer))
- throw new WebServiceException("Parameter 'primaryNameServer' missing.");
- string responsiblePerson = request.QueryString["responsiblePerson"];
- if (string.IsNullOrEmpty(responsiblePerson))
- throw new WebServiceException("Parameter 'responsiblePerson' missing.");
- string serial = request.QueryString["serial"];
- if (string.IsNullOrEmpty(serial))
- throw new WebServiceException("Parameter 'serial' missing.");
- string refresh = request.QueryString["refresh"];
- if (string.IsNullOrEmpty(refresh))
- throw new WebServiceException("Parameter 'refresh' missing.");
- string retry = request.QueryString["retry"];
- if (string.IsNullOrEmpty(retry))
- throw new WebServiceException("Parameter 'retry' missing.");
- string expire = request.QueryString["expire"];
- if (string.IsNullOrEmpty(expire))
- throw new WebServiceException("Parameter 'expire' missing.");
- string minimum = request.QueryString["minimum"];
- if (string.IsNullOrEmpty(minimum))
- throw new WebServiceException("Parameter 'minimum' missing.");
- DnsResourceRecord soaRecord = new DnsResourceRecord(domain, type, DnsClass.IN, ttl, new DnsSOARecord(primaryNameServer, responsiblePerson, uint.Parse(serial), uint.Parse(refresh), uint.Parse(retry), uint.Parse(expire), uint.Parse(minimum)));
- string primaryAddresses = request.QueryString["primaryAddresses"];
- if (!string.IsNullOrEmpty(primaryAddresses))
- soaRecord.SetGlueRecords(primaryAddresses);
- _dnsServer.AuthZoneManager.SetRecord(soaRecord);
- }
- break;
- case DnsResourceRecordType.PTR:
- {
- DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsPTRRecord(value));
- DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsPTRRecord(newValue));
- if (disable)
- newRecord.Disable();
- _dnsServer.AuthZoneManager.UpdateRecord(oldRecord, newRecord);
- }
- break;
- case DnsResourceRecordType.CNAME:
- {
- DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCNAMERecord(value));
- DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCNAMERecord(newValue));
- if (disable)
- newRecord.Disable();
- _dnsServer.AuthZoneManager.UpdateRecord(oldRecord, newRecord);
- }
- break;
- case DnsResourceRecordType.SRV:
- {
- string port = request.QueryString["port"];
- if (string.IsNullOrEmpty(port))
- throw new WebServiceException("Parameter 'port' missing.");
- string priority = request.QueryString["priority"];
- if (string.IsNullOrEmpty(priority))
- throw new WebServiceException("Parameter 'priority' missing.");
- string weight = request.QueryString["weight"];
- if (string.IsNullOrEmpty(weight))
- throw new WebServiceException("Parameter 'weight' missing.");
- string newPort = request.QueryString["newPort"];
- if (string.IsNullOrEmpty(newPort))
- newPort = port;
- DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsSRVRecord(0, 0, ushort.Parse(port), value));
- DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsSRVRecord(ushort.Parse(priority), ushort.Parse(weight), ushort.Parse(newPort), newValue));
- if (disable)
- newRecord.Disable();
- _dnsServer.AuthZoneManager.UpdateRecord(oldRecord, newRecord);
- }
- break;
- case DnsResourceRecordType.CAA:
- {
- string flags = request.QueryString["flags"];
- if (string.IsNullOrEmpty(flags))
- throw new WebServiceException("Parameter 'flags' missing.");
- string tag = request.QueryString["tag"];
- if (string.IsNullOrEmpty(tag))
- throw new WebServiceException("Parameter 'tag' missing.");
- string newFlags = request.QueryString["newFlags"];
- if (string.IsNullOrEmpty(newFlags))
- newFlags = flags;
- string newTag = request.QueryString["newTag"];
- if (string.IsNullOrEmpty(newTag))
- newTag = tag;
- DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsCAARecord(byte.Parse(flags), tag, value));
- DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsCAARecord(byte.Parse(newFlags), newTag, newValue));
- if (disable)
- newRecord.Disable();
- _dnsServer.AuthZoneManager.UpdateRecord(oldRecord, newRecord);
- }
- break;
- case DnsResourceRecordType.ANAME:
- {
- DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsANAMERecord(value));
- DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsANAMERecord(newValue));
- if (disable)
- newRecord.Disable();
- _dnsServer.AuthZoneManager.UpdateRecord(oldRecord, newRecord);
- }
- break;
- case DnsResourceRecordType.FWD:
- {
- string strProtocol = request.QueryString["protocol"];
- if (string.IsNullOrEmpty(strProtocol))
- strProtocol = "Udp";
- DnsTransportProtocol protocol = (DnsTransportProtocol)Enum.Parse(typeof(DnsTransportProtocol), strProtocol, true);
- DnsResourceRecord oldRecord = new DnsResourceRecord(domain, type, DnsClass.IN, 0, new DnsForwarderRecord(protocol, value));
- DnsResourceRecord newRecord = new DnsResourceRecord(newDomain, type, DnsClass.IN, ttl, new DnsForwarderRecord(protocol, newValue));
- if (disable)
- newRecord.Disable();
- _dnsServer.AuthZoneManager.UpdateRecord(oldRecord, newRecord);
- }
- break;
- default:
- throw new WebServiceException("Type not supported for UpdateRecords().");
- }
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Record was updated for authoritative zone {oldDomain: " + domain + "; domain: " + newDomain + "; type: " + type + "; oldValue: " + value + "; value: " + newValue + "; ttl: " + ttl + "; disabled: " + disable + ";}");
- _dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
- }
- private async Task ResolveQuery(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string server = request.QueryString["server"];
- if (string.IsNullOrEmpty(server))
- throw new WebServiceException("Parameter 'server' missing.");
- string domain = request.QueryString["domain"];
- if (string.IsNullOrEmpty(domain))
- throw new WebServiceException("Parameter 'domain' missing.");
- domain = domain.Trim();
- if (domain.EndsWith("."))
- domain = domain.Substring(0, domain.Length - 1);
- string strType = request.QueryString["type"];
- if (string.IsNullOrEmpty(strType))
- throw new WebServiceException("Parameter 'type' missing.");
- DnsResourceRecordType type = (DnsResourceRecordType)Enum.Parse(typeof(DnsResourceRecordType), strType);
- string strProtocol = request.QueryString["protocol"];
- if (string.IsNullOrEmpty(strProtocol))
- strProtocol = "Udp";
- bool importRecords = false;
- string strImport = request.QueryString["import"];
- if (!string.IsNullOrEmpty(strImport))
- importRecords = bool.Parse(strImport);
- NetProxy proxy = _dnsServer.Proxy;
- bool preferIPv6 = _dnsServer.PreferIPv6;
- DnsTransportProtocol protocol = (DnsTransportProtocol)Enum.Parse(typeof(DnsTransportProtocol), strProtocol, true);
- const int RETRIES = 1;
- const int TIMEOUT = 10000;
- DnsDatagram dnsResponse;
- if (server.Equals("recursive-resolver", StringComparison.OrdinalIgnoreCase))
- {
- if (type == DnsResourceRecordType.AXFR)
- throw new DnsServerException("Cannot do zone transfer (AXFR) for 'recursive-resolver'.");
- DnsQuestionRecord question;
- if ((type == DnsResourceRecordType.PTR) && IPAddress.TryParse(domain, out IPAddress address))
- question = new DnsQuestionRecord(address, DnsClass.IN);
- else
- question = new DnsQuestionRecord(domain, type, DnsClass.IN);
- dnsResponse = await DnsClient.RecursiveResolveAsync(question, null, null, proxy, preferIPv6, RETRIES, TIMEOUT);
- }
- else
- {
- if (type == DnsResourceRecordType.AXFR)
- protocol = DnsTransportProtocol.Tcp;
- NameServerAddress nameServer;
- if (server.Equals("this-server", StringComparison.OrdinalIgnoreCase))
- {
- switch (protocol)
- {
- case DnsTransportProtocol.Udp:
- nameServer = _dnsServer.ThisServer;
- break;
- case DnsTransportProtocol.Tcp:
- nameServer = new NameServerAddress(_dnsServer.ThisServer, DnsTransportProtocol.Tcp);
- break;
- case DnsTransportProtocol.Tls:
- throw new DnsServerException("Cannot use DNS-over-TLS protocol for 'this-server'. Please use the TLS certificate domain name as the server.");
- case DnsTransportProtocol.Https:
- throw new DnsServerException("Cannot use DNS-over-HTTPS protocol for 'this-server'. Please use the TLS certificate domain name with a url as the server.");
- case DnsTransportProtocol.HttpsJson:
- throw new DnsServerException("Cannot use DNS-over-HTTPS (JSON) protocol for 'this-server'. Please use the TLS certificate domain name with a url as the server.");
- default:
- throw new InvalidOperationException();
- }
- proxy = null; //no proxy required for this server
- }
- else
- {
- if ((protocol == DnsTransportProtocol.Tls) && !server.Contains(":853"))
- server += ":853";
- nameServer = new NameServerAddress(server, protocol);
- if (nameServer.IPEndPoint == null)
- {
- if (proxy == null)
- {
- if (_dnsServer.AllowRecursion)
- await nameServer.ResolveIPAddressAsync(new NameServerAddress[] { _dnsServer.ThisServer }, proxy, preferIPv6, RETRIES, TIMEOUT);
- else
- await nameServer.RecursiveResolveIPAddressAsync(_dnsServer.DnsCache, proxy, preferIPv6, RETRIES, TIMEOUT);
- }
- }
- else if (protocol != DnsTransportProtocol.Tls)
- {
- try
- {
- if (_dnsServer.AllowRecursion)
- await nameServer.ResolveDomainNameAsync(new NameServerAddress[] { _dnsServer.ThisServer }, proxy, preferIPv6, RETRIES, TIMEOUT);
- else
- await nameServer.RecursiveResolveDomainNameAsync(_dnsServer.DnsCache, proxy, preferIPv6, RETRIES, TIMEOUT);
- }
- catch
- { }
- }
- }
- dnsResponse = await new DnsClient(nameServer) { Proxy = proxy, PreferIPv6 = preferIPv6, Retries = RETRIES, Timeout = TIMEOUT }.ResolveAsync(domain, type);
- }
- if (importRecords)
- {
- AuthZoneInfo zoneInfo = _dnsServer.AuthZoneManager.GetAuthZoneInfo(domain);
- if (zoneInfo == null)
- {
- zoneInfo = _dnsServer.AuthZoneManager.CreatePrimaryZone(domain, _dnsServer.ServerDomain, false);
- if (zoneInfo == null)
- throw new DnsServerException("Cannot import records: failed to create primary zone.");
- }
- else
- {
- switch (zoneInfo.Type)
- {
- case AuthZoneType.Primary:
- case AuthZoneType.Forwarder:
- break;
- default:
- throw new DnsServerException("Cannot import records: import zone must be of primary or forwarder type.");
- }
- }
- if (type == DnsResourceRecordType.AXFR)
- {
- bool dontRemoveRecords = zoneInfo.Type == AuthZoneType.Forwarder;
- _dnsServer.AuthZoneManager.SyncRecords(domain, dnsResponse.Answer, null, dontRemoveRecords);
- }
- else
- {
- List<DnsResourceRecord> syncRecords = new List<DnsResourceRecord>();
- foreach (DnsResourceRecord record in dnsResponse.Answer)
- {
- if (record.Name.Equals(domain, StringComparison.OrdinalIgnoreCase))
- {
- record.RemoveExpiry();
- syncRecords.Add(record);
- }
- }
- _dnsServer.AuthZoneManager.SyncRecords(domain, syncRecords, null, true);
- }
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DNS Client imported record(s) for authoritative zone {server: " + server + "; domain: " + domain + "; type: " + type + ";}");
- _dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
- }
- jsonWriter.WritePropertyName("result");
- jsonWriter.WriteRawValue(JsonConvert.SerializeObject(dnsResponse, new StringEnumConverter()));
- }
- private void ListLogs(JsonTextWriter jsonWriter)
- {
- string[] logFiles = Directory.GetFiles(_log.LogFolder, "*.log");
- Array.Sort(logFiles);
- Array.Reverse(logFiles);
- jsonWriter.WritePropertyName("logFiles");
- jsonWriter.WriteStartArray();
- foreach (string logFile in logFiles)
- {
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("fileName");
- jsonWriter.WriteValue(Path.GetFileNameWithoutExtension(logFile));
- jsonWriter.WritePropertyName("size");
- jsonWriter.WriteValue(WebUtilities.GetFormattedSize(new FileInfo(logFile).Length));
- jsonWriter.WriteEndObject();
- }
- jsonWriter.WriteEndArray();
- }
- private void DeleteLog(HttpListenerRequest request)
- {
- string log = request.QueryString["log"];
- if (string.IsNullOrEmpty(log))
- throw new WebServiceException("Parameter 'log' missing.");
- string logFile = Path.Combine(_log.LogFolder, log + ".log");
- if (_log.CurrentLogFile.Equals(logFile, StringComparison.OrdinalIgnoreCase))
- _log.DeleteCurrentLogFile();
- else
- File.Delete(logFile);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] Log file was deleted: " + log);
- }
- private void ListDhcpLeases(JsonTextWriter jsonWriter)
- {
- ICollection<Scope> scopes = _dhcpServer.Scopes;
- //sort by name
- Scope[] scopesArray = new Scope[scopes.Count];
- scopes.CopyTo(scopesArray, 0);
- Array.Sort(scopesArray);
- jsonWriter.WritePropertyName("leases");
- jsonWriter.WriteStartArray();
- foreach (Scope scope in scopesArray)
- {
- ICollection<Lease> leases = scope.Leases;
- //sort by address
- Lease[] leasesArray = new Lease[leases.Count];
- leases.CopyTo(leasesArray, 0);
- Array.Sort(leasesArray);
- foreach (Lease lease in leasesArray)
- {
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("scope");
- jsonWriter.WriteValue(scope.Name);
- jsonWriter.WritePropertyName("type");
- jsonWriter.WriteValue(lease.Type.ToString());
- jsonWriter.WritePropertyName("hardwareAddress");
- jsonWriter.WriteValue(BitConverter.ToString(lease.HardwareAddress));
- jsonWriter.WritePropertyName("address");
- jsonWriter.WriteValue(lease.Address.ToString());
- jsonWriter.WritePropertyName("hostName");
- jsonWriter.WriteValue(lease.HostName);
- jsonWriter.WritePropertyName("leaseObtained");
- jsonWriter.WriteValue(lease.LeaseObtained.ToLocalTime().ToString());
- jsonWriter.WritePropertyName("leaseExpires");
- jsonWriter.WriteValue(lease.LeaseExpires.ToLocalTime().ToString());
- jsonWriter.WriteEndObject();
- }
- }
- jsonWriter.WriteEndArray();
- }
- private void ListDhcpScopes(JsonTextWriter jsonWriter)
- {
- ICollection<Scope> scopes = _dhcpServer.Scopes;
- //sort by name
- Scope[] scopesArray = new Scope[scopes.Count];
- scopes.CopyTo(scopesArray, 0);
- Array.Sort(scopesArray);
- jsonWriter.WritePropertyName("scopes");
- jsonWriter.WriteStartArray();
- foreach (Scope scope in scopesArray)
- {
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(scope.Name);
- jsonWriter.WritePropertyName("enabled");
- jsonWriter.WriteValue(scope.Enabled);
- jsonWriter.WritePropertyName("startingAddress");
- jsonWriter.WriteValue(scope.StartingAddress.ToString());
- jsonWriter.WritePropertyName("endingAddress");
- jsonWriter.WriteValue(scope.EndingAddress.ToString());
- jsonWriter.WritePropertyName("subnetMask");
- jsonWriter.WriteValue(scope.SubnetMask.ToString());
- jsonWriter.WritePropertyName("networkAddress");
- jsonWriter.WriteValue(scope.NetworkAddress.ToString());
- jsonWriter.WritePropertyName("broadcastAddress");
- jsonWriter.WriteValue(scope.BroadcastAddress.ToString());
- if (scope.InterfaceAddress != null)
- {
- jsonWriter.WritePropertyName("interfaceAddress");
- jsonWriter.WriteValue(scope.InterfaceAddress.ToString());
- }
- jsonWriter.WriteEndObject();
- }
- jsonWriter.WriteEndArray();
- }
- private void GetDhcpScope(HttpListenerRequest request, JsonTextWriter jsonWriter)
- {
- string scopeName = request.QueryString["name"];
- if (string.IsNullOrEmpty(scopeName))
- throw new WebServiceException("Parameter 'name' missing.");
- Scope scope = _dhcpServer.GetScope(scopeName);
- if (scope == null)
- throw new WebServiceException("DHCP scope was not found: " + scopeName);
- jsonWriter.WritePropertyName("name");
- jsonWriter.WriteValue(scope.Name);
- jsonWriter.WritePropertyName("startingAddress");
- jsonWriter.WriteValue(scope.StartingAddress.ToString());
- jsonWriter.WritePropertyName("endingAddress");
- jsonWriter.WriteValue(scope.EndingAddress.ToString());
- jsonWriter.WritePropertyName("subnetMask");
- jsonWriter.WriteValue(scope.SubnetMask.ToString());
- jsonWriter.WritePropertyName("leaseTimeDays");
- jsonWriter.WriteValue(scope.LeaseTimeDays);
- jsonWriter.WritePropertyName("leaseTimeHours");
- jsonWriter.WriteValue(scope.LeaseTimeHours);
- jsonWriter.WritePropertyName("leaseTimeMinutes");
- jsonWriter.WriteValue(scope.LeaseTimeMinutes);
- jsonWriter.WritePropertyName("offerDelayTime");
- jsonWriter.WriteValue(scope.OfferDelayTime);
- if (!string.IsNullOrEmpty(scope.DomainName))
- {
- jsonWriter.WritePropertyName("domainName");
- jsonWriter.WriteValue(scope.DomainName);
- }
- jsonWriter.WritePropertyName("dnsTtl");
- jsonWriter.WriteValue(scope.DnsTtl);
- if (scope.RouterAddress != null)
- {
- jsonWriter.WritePropertyName("routerAddress");
- jsonWriter.WriteValue(scope.RouterAddress.ToString());
- }
- jsonWriter.WritePropertyName("useThisDnsServer");
- jsonWriter.WriteValue(scope.UseThisDnsServer);
- if (scope.DnsServers != null)
- {
- jsonWriter.WritePropertyName("dnsServers");
- jsonWriter.WriteStartArray();
- foreach (IPAddress dnsServer in scope.DnsServers)
- jsonWriter.WriteValue(dnsServer.ToString());
- jsonWriter.WriteEndArray();
- }
- if (scope.WinsServers != null)
- {
- jsonWriter.WritePropertyName("winsServers");
- jsonWriter.WriteStartArray();
- foreach (IPAddress winsServer in scope.WinsServers)
- jsonWriter.WriteValue(winsServer.ToString());
- jsonWriter.WriteEndArray();
- }
- if (scope.NtpServers != null)
- {
- jsonWriter.WritePropertyName("ntpServers");
- jsonWriter.WriteStartArray();
- foreach (IPAddress ntpServer in scope.NtpServers)
- jsonWriter.WriteValue(ntpServer.ToString());
- jsonWriter.WriteEndArray();
- }
- if (scope.StaticRoutes != null)
- {
- jsonWriter.WritePropertyName("staticRoutes");
- jsonWriter.WriteStartArray();
- foreach (ClasslessStaticRouteOption.Route route in scope.StaticRoutes)
- {
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("destination");
- jsonWriter.WriteValue(route.Destination.ToString());
- jsonWriter.WritePropertyName("subnetMask");
- jsonWriter.WriteValue(route.SubnetMask.ToString());
- jsonWriter.WritePropertyName("router");
- jsonWriter.WriteValue(route.Router.ToString());
- jsonWriter.WriteEndObject();
- }
- jsonWriter.WriteEndArray();
- }
- if (scope.Exclusions != null)
- {
- jsonWriter.WritePropertyName("exclusions");
- jsonWriter.WriteStartArray();
- foreach (Exclusion exclusion in scope.Exclusions)
- {
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("startingAddress");
- jsonWriter.WriteValue(exclusion.StartingAddress.ToString());
- jsonWriter.WritePropertyName("endingAddress");
- jsonWriter.WriteValue(exclusion.EndingAddress.ToString());
- jsonWriter.WriteEndObject();
- }
- jsonWriter.WriteEndArray();
- }
- jsonWriter.WritePropertyName("reservedLeases");
- jsonWriter.WriteStartArray();
- foreach (Lease reservedLease in scope.ReservedLeases)
- {
- jsonWriter.WriteStartObject();
- jsonWriter.WritePropertyName("hostName");
- jsonWriter.WriteValue(reservedLease.HostName);
- jsonWriter.WritePropertyName("hardwareAddress");
- jsonWriter.WriteValue(BitConverter.ToString(reservedLease.HardwareAddress));
- jsonWriter.WritePropertyName("address");
- jsonWriter.WriteValue(reservedLease.Address.ToString());
- jsonWriter.WritePropertyName("comments");
- jsonWriter.WriteValue(reservedLease.Comments);
- jsonWriter.WriteEndObject();
- }
- jsonWriter.WriteEndArray();
- jsonWriter.WritePropertyName("allowOnlyReservedLeases");
- jsonWriter.WriteValue(scope.AllowOnlyReservedLeases);
- }
- private async Task SetDhcpScopeAsync(HttpListenerRequest request)
- {
- string scopeName = request.QueryString["name"];
- if (string.IsNullOrEmpty(scopeName))
- throw new WebServiceException("Parameter 'name' missing.");
- string newName = request.QueryString["newName"];
- if (!string.IsNullOrEmpty(newName) && !newName.Equals(scopeName))
- {
- _dhcpServer.RenameScope(scopeName, newName);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DHCP scope was renamed successfully: '" + scopeName + "' to '" + newName + "'");
- scopeName = newName;
- }
- string strStartingAddress = request.QueryString["startingAddress"];
- if (string.IsNullOrEmpty(strStartingAddress))
- throw new WebServiceException("Parameter 'startingAddress' missing.");
- string strEndingAddress = request.QueryString["endingAddress"];
- if (string.IsNullOrEmpty(strStartingAddress))
- throw new WebServiceException("Parameter 'endingAddress' missing.");
- string strSubnetMask = request.QueryString["subnetMask"];
- if (string.IsNullOrEmpty(strStartingAddress))
- throw new WebServiceException("Parameter 'subnetMask' missing.");
- bool scopeExists;
- Scope scope = _dhcpServer.GetScope(scopeName);
- if (scope == null)
- {
- //scope does not exists; create new scope
- scopeExists = false;
- scope = new Scope(scopeName, true, IPAddress.Parse(strStartingAddress), IPAddress.Parse(strEndingAddress), IPAddress.Parse(strSubnetMask));
- }
- else
- {
- scopeExists = true;
- IPAddress startingAddress = IPAddress.Parse(strStartingAddress);
- IPAddress endingAddress = IPAddress.Parse(strEndingAddress);
- //validate scope address
- foreach (Scope existingScope in _dhcpServer.Scopes)
- {
- if (existingScope.Equals(scope))
- continue;
- if (existingScope.IsAddressInRange(startingAddress) || existingScope.IsAddressInRange(endingAddress))
- throw new DhcpServerException("Scope with overlapping range already exists: " + existingScope.StartingAddress.ToString() + "-" + existingScope.EndingAddress.ToString());
- }
- scope.ChangeNetwork(startingAddress, endingAddress, IPAddress.Parse(strSubnetMask));
- }
- string strLeaseTimeDays = request.QueryString["leaseTimeDays"];
- if (!string.IsNullOrEmpty(strLeaseTimeDays))
- scope.LeaseTimeDays = ushort.Parse(strLeaseTimeDays);
- string strLeaseTimeHours = request.QueryString["leaseTimeHours"];
- if (!string.IsNullOrEmpty(strLeaseTimeHours))
- scope.LeaseTimeHours = byte.Parse(strLeaseTimeHours);
- string strLeaseTimeMinutes = request.QueryString["leaseTimeMinutes"];
- if (!string.IsNullOrEmpty(strLeaseTimeMinutes))
- scope.LeaseTimeMinutes = byte.Parse(strLeaseTimeMinutes);
- string strOfferDelayTime = request.QueryString["offerDelayTime"];
- if (!string.IsNullOrEmpty(strOfferDelayTime))
- scope.OfferDelayTime = ushort.Parse(strOfferDelayTime);
- string strDomainName = request.QueryString["domainName"];
- if (strDomainName != null)
- scope.DomainName = strDomainName.Length == 0 ? null : strDomainName;
- string strDnsTtl = request.QueryString["dnsTtl"];
- if (!string.IsNullOrEmpty(strDnsTtl))
- scope.DnsTtl = uint.Parse(strDnsTtl);
- string strRouterAddress = request.QueryString["routerAddress"];
- if (strRouterAddress != null)
- scope.RouterAddress = strRouterAddress.Length == 0 ? null : IPAddress.Parse(strRouterAddress);
- string strUseThisDnsServer = request.QueryString["useThisDnsServer"];
- if (!string.IsNullOrEmpty(strUseThisDnsServer))
- scope.UseThisDnsServer = bool.Parse(strUseThisDnsServer);
- if (!scope.UseThisDnsServer)
- {
- string strDnsServers = request.QueryString["dnsServers"];
- if (strDnsServers != null)
- {
- if (strDnsServers.Length == 0)
- {
- scope.DnsServers = null;
- }
- else
- {
- string[] strDnsServerParts = strDnsServers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- IPAddress[] dnsServers = new IPAddress[strDnsServerParts.Length];
- for (int i = 0; i < strDnsServerParts.Length; i++)
- dnsServers[i] = IPAddress.Parse(strDnsServerParts[i]);
- scope.DnsServers = dnsServers;
- }
- }
- }
- string strWinsServers = request.QueryString["winsServers"];
- if (strWinsServers != null)
- {
- if (strWinsServers.Length == 0)
- {
- scope.WinsServers = null;
- }
- else
- {
- string[] strWinsServerParts = strWinsServers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- IPAddress[] winsServers = new IPAddress[strWinsServerParts.Length];
- for (int i = 0; i < strWinsServerParts.Length; i++)
- winsServers[i] = IPAddress.Parse(strWinsServerParts[i]);
- scope.WinsServers = winsServers;
- }
- }
- string strNtpServers = request.QueryString["ntpServers"];
- if (strNtpServers != null)
- {
- if (strNtpServers.Length == 0)
- {
- scope.NtpServers = null;
- }
- else
- {
- string[] strNtpServerParts = strNtpServers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- IPAddress[] ntpServers = new IPAddress[strNtpServerParts.Length];
- for (int i = 0; i < strNtpServerParts.Length; i++)
- ntpServers[i] = IPAddress.Parse(strNtpServerParts[i]);
- scope.NtpServers = ntpServers;
- }
- }
- string strStaticRoutes = request.QueryString["staticRoutes"];
- if (strStaticRoutes != null)
- {
- if (strStaticRoutes.Length == 0)
- {
- scope.StaticRoutes = null;
- }
- else
- {
- string[] strStaticRoutesParts = strStaticRoutes.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- ClasslessStaticRouteOption.Route[] staticRoutes = new ClasslessStaticRouteOption.Route[strStaticRoutesParts.Length];
- for (int i = 0; i < strStaticRoutesParts.Length; i++)
- {
- string[] routeParts = strStaticRoutesParts[i].Split(';');
- staticRoutes[i] = new ClasslessStaticRouteOption.Route(IPAddress.Parse(routeParts[0]), IPAddress.Parse(routeParts[1]), IPAddress.Parse(routeParts[2]));
- }
- scope.StaticRoutes = staticRoutes;
- }
- }
- string strExclusions = request.QueryString["exclusions"];
- if (strExclusions != null)
- {
- if (strExclusions.Length == 0)
- {
- scope.Exclusions = null;
- }
- else
- {
- string[] strExclusionsParts = strExclusions.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- Exclusion[] exclusions = new Exclusion[strExclusionsParts.Length];
- for (int i = 0; i < strExclusionsParts.Length; i++)
- {
- string[] rangeParts = strExclusionsParts[i].Split(';');
- exclusions[i] = new Exclusion(IPAddress.Parse(rangeParts[0]), IPAddress.Parse(rangeParts[1]));
- }
- scope.Exclusions = exclusions;
- }
- }
- string strReservedLeases = request.QueryString["reservedLeases"];
- if (strReservedLeases != null)
- {
- if (strReservedLeases.Length == 0)
- {
- scope.ReservedLeases = null;
- }
- else
- {
- string[] strReservedLeaseParts = strReservedLeases.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- Lease[] reservedLeases = new Lease[strReservedLeaseParts.Length];
- for (int i = 0; i < strReservedLeaseParts.Length; i++)
- {
- string[] leaseParts = strReservedLeaseParts[i].Split(';');
- Lease reservedLease = new Lease(LeaseType.Reserved, null, leaseParts[0], IPAddress.Parse(leaseParts[1]), leaseParts[2]);
- Lease existingReservedLease = scope.GetReservedLease(reservedLease.ClientIdentifier);
- if (existingReservedLease != null)
- reservedLease.SetHostName(existingReservedLease.HostName);
- reservedLeases[i] = reservedLease;
- }
- scope.ReservedLeases = reservedLeases;
- }
- }
- string strAllowOnlyReservedLeases = request.QueryString["allowOnlyReservedLeases"];
- if (!string.IsNullOrEmpty(strAllowOnlyReservedLeases))
- scope.AllowOnlyReservedLeases = bool.Parse(strAllowOnlyReservedLeases);
- if (scopeExists)
- {
- _dhcpServer.SaveScope(scopeName);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DHCP scope was updated successfully: " + scopeName);
- }
- else
- {
- await _dhcpServer.AddScopeAsync(scope);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DHCP scope was added successfully: " + scopeName);
- }
- }
- private async Task EnableDhcpScopeAsync(HttpListenerRequest request)
- {
- string scopeName = request.QueryString["name"];
- if (string.IsNullOrEmpty(scopeName))
- throw new WebServiceException("Parameter 'name' missing.");
- if (!await _dhcpServer.EnableScopeAsync(scopeName))
- throw new WebServiceException("Failed to enable DHCP scope, please check logs for details: " + scopeName);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DHCP scope was enabled successfully: " + scopeName);
- }
- private void DisableDhcpScope(HttpListenerRequest request)
- {
- string scopeName = request.QueryString["name"];
- if (string.IsNullOrEmpty(scopeName))
- throw new WebServiceException("Parameter 'name' missing.");
- if (!_dhcpServer.DisableScope(scopeName))
- throw new WebServiceException("Failed to disable DHCP scope, please check logs for details: " + scopeName);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DHCP scope was disabled successfully: " + scopeName);
- }
- private void DeleteDhcpScope(HttpListenerRequest request)
- {
- string scopeName = request.QueryString["name"];
- if (string.IsNullOrEmpty(scopeName))
- throw new WebServiceException("Parameter 'name' missing.");
- _dhcpServer.DeleteScope(scopeName);
- _log.Write(GetRequestRemoteEndPoint(request), "[" + GetSession(request).Username + "] DHCP scope was deleted successfully: " + scopeName);
- }
- private void SetCredentials(string username, string password)
- {
- username = username.ToLower();
- string passwordHash = GetPasswordHash(username, password);
- _credentials[username] = passwordHash;
- }
- private void LoadCredentials(string username, string passwordHash)
- {
- username = username.ToLower();
- _credentials[username] = passwordHash;
- }
- private static string GetPasswordHash(string username, string password)
- {
- using (HMAC hmac = new HMACSHA256(Encoding.UTF8.GetBytes(password)))
- {
- return BitConverter.ToString(hmac.ComputeHash(Encoding.UTF8.GetBytes(username))).Replace("-", "").ToLower();
- }
- }
- private void StartBlockListUpdateTimer()
- {
- if (_blockListUpdateTimer == null)
- {
- _blockListUpdateTimer = new Timer(async delegate (object state)
- {
- try
- {
- if (DateTime.UtcNow > _blockListLastUpdatedOn.AddHours(BLOCK_LIST_UPDATE_AFTER_HOURS))
- {
- if (await _dnsServer.BlockListZoneManager.UpdateBlockListsAsync())
- {
- //block lists were updated
- //save last updated on time
- _blockListLastUpdatedOn = DateTime.UtcNow;
- SaveConfigFile();
- }
- }
- }
- catch (Exception ex)
- {
- _log.Write("DNS Server encountered an error while updating block lists.\r\n" + ex.ToString());
- }
- }, null, BLOCK_LIST_UPDATE_TIMER_INITIAL_INTERVAL, BLOCK_LIST_UPDATE_TIMER_INTERVAL);
- }
- }
- private void StopBlockListUpdateTimer()
- {
- if (_blockListUpdateTimer != null)
- {
- _blockListUpdateTimer.Dispose();
- _blockListUpdateTimer = null;
- }
- }
- private void StartTlsCertificateUpdateTimer()
- {
- if (_tlsCertificateUpdateTimer == null)
- {
- _tlsCertificateUpdateTimer = new Timer(delegate (object state)
- {
- try
- {
- FileInfo fileInfo = new FileInfo(_tlsCertificatePath);
- if (fileInfo.Exists && (fileInfo.LastWriteTimeUtc != _tlsCertificateLastModifiedOn))
- LoadTlsCertificate(_tlsCertificatePath, _tlsCertificatePassword);
- }
- catch (Exception ex)
- {
- _log.Write("DNS Server encountered an error while updating TLS Certificate: " + _tlsCertificatePath + "\r\n" + ex.ToString());
- }
- }, null, TLS_CERTIFICATE_UPDATE_TIMER_INITIAL_INTERVAL, TLS_CERTIFICATE_UPDATE_TIMER_INTERVAL);
- }
- }
- private void StopTlsCertificateUpdateTimer()
- {
- if (_tlsCertificateUpdateTimer != null)
- {
- _tlsCertificateUpdateTimer.Dispose();
- _tlsCertificateUpdateTimer = null;
- }
- }
- private void LoadTlsCertificate(string tlsCertificatePath, string tlsCertificatePassword)
- {
- FileInfo fileInfo = new FileInfo(tlsCertificatePath);
- if (!fileInfo.Exists)
- throw new ArgumentException("Tls certificate file does not exists: " + tlsCertificatePath);
- if (Path.GetExtension(tlsCertificatePath) != ".pfx")
- throw new ArgumentException("Tls certificate file must be PKCS #12 formatted with .pfx extension: " + tlsCertificatePath);
- X509Certificate2 certificate = new X509Certificate2(tlsCertificatePath, tlsCertificatePassword);
- if (!certificate.Verify())
- throw new ArgumentException("Tls certificate is invalid.");
- _dnsServer.Certificate = certificate;
- _tlsCertificateLastModifiedOn = fileInfo.LastWriteTimeUtc;
- _log.Write("DNS Server TLS certificate was loaded: " + tlsCertificatePath);
- }
- private void LoadConfigFile()
- {
- string configFile = Path.Combine(_configFolder, "dns.config");
- try
- {
- bool passwordResetOption = false;
- if (!File.Exists(configFile))
- {
- string passwordResetConfigFile = Path.Combine(_configFolder, "reset.config");
- if (File.Exists(passwordResetConfigFile))
- {
- passwordResetOption = true;
- configFile = passwordResetConfigFile;
- }
- }
- byte version;
- using (FileStream fS = new FileStream(configFile, FileMode.Open, FileAccess.Read))
- {
- BinaryReader bR = new BinaryReader(fS);
- if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "DS") //format
- throw new InvalidDataException("DnsServer config file format is invalid.");
- version = bR.ReadByte();
- switch (version)
- {
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- case 11:
- _dnsServer.ServerDomain = bR.ReadShortString();
- _webServicePort = bR.ReadInt32();
- _dnsServer.PreferIPv6 = bR.ReadBoolean();
- if (bR.ReadBoolean()) //logQueries
- _dnsServer.QueryLogManager = _log;
- _dnsServer.AllowRecursion = bR.ReadBoolean();
- if (version >= 4)
- _dnsServer.AllowRecursionOnlyForPrivateNetworks = bR.ReadBoolean();
- else
- _dnsServer.AllowRecursionOnlyForPrivateNetworks = true; //default true for security reasons
- if (version >= 9)
- {
- _dnsServer.CachePrefetchEligibility = bR.ReadInt32();
- _dnsServer.CachePrefetchTrigger = bR.ReadInt32();
- _dnsServer.CachePrefetchSampleIntervalInMinutes = bR.ReadInt32();
- _dnsServer.CachePrefetchSampleEligibilityHitsPerHour = bR.ReadInt32();
- }
- NetProxyType proxyType = (NetProxyType)bR.ReadByte();
- if (proxyType != NetProxyType.None)
- {
- string address = bR.ReadShortString();
- int port = bR.ReadInt32();
- NetworkCredential credential = null;
- if (bR.ReadBoolean()) //credential set
- credential = new NetworkCredential(bR.ReadShortString(), bR.ReadShortString());
- _dnsServer.Proxy = NetProxy.CreateProxy(proxyType, address, port, credential);
- if (version >= 10)
- {
- int count = bR.ReadByte();
- _dnsServer.Proxy.BypassList.Clear();
- for (int i = 0; i < count; i++)
- _dnsServer.Proxy.BypassList.Add(new NetProxyBypassItem(bR.ReadShortString()));
- }
- }
- else
- {
- _dnsServer.Proxy = null;
- }
- {
- int count = bR.ReadByte();
- if (count > 0)
- {
- NameServerAddress[] forwarders = new NameServerAddress[count];
- for (int i = 0; i < count; i++)
- forwarders[i] = new NameServerAddress(bR);
- _dnsServer.Forwarders = forwarders;
- }
- }
- if (version <= 10)
- {
- DnsTransportProtocol forwarderProtocol = (DnsTransportProtocol)bR.ReadByte();
- if (_dnsServer.Forwarders != null)
- {
- List<NameServerAddress> forwarders = new List<NameServerAddress>();
- foreach (NameServerAddress forwarder in _dnsServer.Forwarders)
- {
- if (forwarder.Protocol == forwarderProtocol)
- forwarders.Add(forwarder);
- else
- forwarders.Add(new NameServerAddress(forwarder, forwarderProtocol));
- }
- _dnsServer.Forwarders = forwarders;
- }
- }
- {
- int count = bR.ReadByte();
- if (count > 0)
- {
- if (version > 2)
- {
- for (int i = 0; i < count; i++)
- LoadCredentials(bR.ReadShortString(), bR.ReadShortString());
- }
- else
- {
- for (int i = 0; i < count; i++)
- SetCredentials(bR.ReadShortString(), bR.ReadShortString());
- }
- }
- }
- if (version <= 6)
- {
- int count = bR.ReadInt32();
- _configDisabledZones = new List<string>(count);
- for (int i = 0; i < count; i++)
- {
- string domain = bR.ReadShortString();
- _configDisabledZones.Add(domain);
- }
- }
- if (version > 4)
- {
- //read block list urls
- int count = bR.ReadByte();
- for (int i = 0; i < count; i++)
- _dnsServer.BlockListZoneManager.BlockListUrls.Add(new Uri(bR.ReadShortString()));
- _blockListLastUpdatedOn = bR.ReadDate();
- }
- if (version >= 11)
- {
- int count = bR.ReadByte();
- if (count > 0)
- {
- IPEndPoint[] localEndPoints = new IPEndPoint[count];
- for (int i = 0; i < count; i++)
- localEndPoints[i] = (IPEndPoint)EndPointExtension.Parse(bR);
- _dnsServer.LocalEndPoints = localEndPoints;
- }
- }
- else if (version >= 6)
- {
- int count = bR.ReadByte();
- if (count > 0)
- {
- IPEndPoint[] localEndPoints = new IPEndPoint[count];
- for (int i = 0; i < count; i++)
- localEndPoints[i] = new IPEndPoint(IPAddressExtension.Parse(bR), 53);
- _dnsServer.LocalEndPoints = localEndPoints;
- }
- }
- if (version >= 8)
- {
- _dnsServer.EnableDnsOverHttp = bR.ReadBoolean();
- _dnsServer.EnableDnsOverTls = bR.ReadBoolean();
- _dnsServer.EnableDnsOverHttps = bR.ReadBoolean();
- _tlsCertificatePath = bR.ReadShortString();
- _tlsCertificatePassword = bR.ReadShortString();
- if (_tlsCertificatePath.Length == 0)
- _tlsCertificatePath = null;
- if (_tlsCertificatePath != null)
- {
- try
- {
- LoadTlsCertificate(_tlsCertificatePath, _tlsCertificatePassword);
- }
- catch (Exception ex)
- {
- _log.Write("DNS Server encountered an error while loading TLS certificate: " + _tlsCertificatePath + "\r\n" + ex.ToString());
- }
- StartTlsCertificateUpdateTimer();
- }
- }
- break;
- default:
- throw new InvalidDataException("DnsServer config version not supported.");
- }
- }
- _log.Write("DNS Server config file was loaded: " + configFile);
- if (passwordResetOption)
- {
- SetCredentials("admin", "admin");
- _log.Write("DNS Server reset password for user: admin");
- SaveConfigFile();
- try
- {
- File.Delete(configFile);
- }
- catch
- { }
- }
- if (version <= 6)
- SaveConfigFile(); //save as new config version to avoid loading old version next time
- }
- catch (FileNotFoundException)
- {
- _log.Write("DNS Server config file was not found: " + configFile);
- _log.Write("DNS Server is restoring default config file.");
- _webServicePort = 5380;
- SetCredentials("admin", "admin");
- _dnsServer.AllowRecursion = true;
- _dnsServer.AllowRecursionOnlyForPrivateNetworks = true; //default true for security reasons
- SaveConfigFile();
- }
- catch (Exception ex)
- {
- _log.Write("DNS Server encountered an error while loading config file: " + configFile + "\r\n" + ex.ToString());
- _log.Write("Note: You may try deleting the config file to fix this issue. However, you will lose DNS settings but, zone data wont be affected.");
- throw;
- }
- }
- private void SaveConfigFile()
- {
- string configFile = Path.Combine(_configFolder, "dns.config");
- using (MemoryStream mS = new MemoryStream())
- {
- //serialize config
- BinaryWriter bW = new BinaryWriter(mS);
- bW.Write(Encoding.ASCII.GetBytes("DS")); //format
- bW.Write((byte)11); //version
- bW.WriteShortString(_dnsServer.ServerDomain);
- bW.Write(_webServicePort);
- bW.Write(_dnsServer.PreferIPv6);
- bW.Write(_dnsServer.QueryLogManager != null); //logQueries
- bW.Write(_dnsServer.AllowRecursion);
- bW.Write(_dnsServer.AllowRecursionOnlyForPrivateNetworks);
- bW.Write(_dnsServer.CachePrefetchEligibility);
- bW.Write(_dnsServer.CachePrefetchTrigger);
- bW.Write(_dnsServer.CachePrefetchSampleIntervalInMinutes);
- bW.Write(_dnsServer.CachePrefetchSampleEligibilityHitsPerHour);
- if (_dnsServer.Proxy == null)
- {
- bW.Write((byte)NetProxyType.None);
- }
- else
- {
- bW.Write((byte)_dnsServer.Proxy.Type);
- bW.WriteShortString(_dnsServer.Proxy.Address);
- bW.Write(_dnsServer.Proxy.Port);
- NetworkCredential credential = _dnsServer.Proxy.Credential;
- if (credential == null)
- {
- bW.Write(false);
- }
- else
- {
- bW.Write(true);
- bW.WriteShortString(credential.UserName);
- bW.WriteShortString(credential.Password);
- }
- //bypass list
- {
- bW.Write(Convert.ToByte(_dnsServer.Proxy.BypassList.Count));
- foreach (NetProxyBypassItem item in _dnsServer.Proxy.BypassList)
- bW.WriteShortString(item.Value);
- }
- }
- if (_dnsServer.Forwarders == null)
- {
- bW.Write((byte)0);
- }
- else
- {
- bW.Write(Convert.ToByte(_dnsServer.Forwarders.Count));
- foreach (NameServerAddress forwarder in _dnsServer.Forwarders)
- forwarder.WriteTo(bW);
- }
- {
- bW.Write(Convert.ToByte(_credentials.Count));
- foreach (KeyValuePair<string, string> credential in _credentials)
- {
- bW.WriteShortString(credential.Key);
- bW.WriteShortString(credential.Value);
- }
- }
- //block list
- {
- bW.Write(Convert.ToByte(_dnsServer.BlockListZoneManager.BlockListUrls.Count));
- foreach (Uri blockListUrl in _dnsServer.BlockListZoneManager.BlockListUrls)
- bW.WriteShortString(blockListUrl.AbsoluteUri);
- bW.Write(_blockListLastUpdatedOn);
- }
- {
- bW.Write(Convert.ToByte(_dnsServer.LocalEndPoints.Count));
- foreach (IPEndPoint localEP in _dnsServer.LocalEndPoints)
- localEP.WriteTo(bW);
- }
- bW.Write(_dnsServer.EnableDnsOverHttp);
- bW.Write(_dnsServer.EnableDnsOverTls);
- bW.Write(_dnsServer.EnableDnsOverHttps);
- if (_tlsCertificatePath == null)
- bW.WriteShortString(string.Empty);
- else
- bW.WriteShortString(_tlsCertificatePath);
- if (_tlsCertificatePassword == null)
- bW.WriteShortString(string.Empty);
- else
- bW.WriteShortString(_tlsCertificatePassword);
- //write config
- mS.Position = 0;
- using (FileStream fS = new FileStream(configFile, FileMode.Create, FileAccess.Write))
- {
- mS.CopyTo(fS);
- }
- }
- _log.Write("DNS Server config file was saved: " + configFile);
- }
- #endregion
- #region public
- public void Start()
- {
- if (_disposed)
- throw new ObjectDisposedException("WebService");
- if (_state != ServiceState.Stopped)
- throw new InvalidOperationException("Web Service is already running.");
- _state = ServiceState.Starting;
- try
- {
- //init dns server
- _dnsServer = new DnsServer(_configFolder, Path.Combine(_appFolder, "dohwww"), _log);
- //init dhcp server
- _dhcpServer = new DhcpServer(Path.Combine(_configFolder, "scopes"), _log);
- _dhcpServer.AuthZoneManager = _dnsServer.AuthZoneManager;
- //load config
- LoadConfigFile();
- //load all zones files
- _dnsServer.AuthZoneManager.LoadAllZoneFiles();
- //disable zones from old config format
- if (_configDisabledZones != null)
- {
- foreach (string domain in _configDisabledZones)
- {
- AuthZoneInfo zoneInfo = _dnsServer.AuthZoneManager.GetAuthZoneInfo(domain);
- if (zoneInfo != null)
- {
- zoneInfo.Disabled = true;
- _dnsServer.AuthZoneManager.SaveZoneFile(zoneInfo.Name);
- }
- }
- }
- //load allowed zone and blocked zone
- _dnsServer.AllowedZoneManager.LoadAllowedZoneFile();
- _dnsServer.BlockedZoneManager.LoadBlockedZoneFile();
- //load block list zone async
- if (_dnsServer.BlockListZoneManager.BlockListUrls.Count > 0)
- {
- ThreadPool.QueueUserWorkItem(delegate (object state)
- {
- try
- {
- _dnsServer.BlockListZoneManager.LoadBlockLists();
- StartBlockListUpdateTimer();
- }
- catch (Exception ex)
- {
- _log.Write(ex);
- }
- });
- }
- //start dns and dhcp
- _dnsServer.Start();
- _dhcpServer.Start();
- //start web service
- try
- {
- _webService = new HttpListener();
- _webService.Prefixes.Add("http://+:" + _webServicePort + "/");
- _webService.Start();
- _webServiceHostname = Environment.MachineName.ToLower();
- }
- catch (Exception ex)
- {
- _log.Write("Web Service failed to bind using default hostname. Attempting to bind again using 'localhost' hostname.\r\n" + ex.ToString());
- _webService = new HttpListener();
- _webService.Prefixes.Add("http://localhost:" + _webServicePort + "/");
- _webService.Start();
- _webServiceHostname = "localhost";
- }
- _webService.IgnoreWriteExceptions = true;
- _webServiceThread = new Thread(AcceptWebRequestAsync);
- _webServiceThread.Name = "WebService";
- _webServiceThread.IsBackground = true;
- _webServiceThread.Start();
- _state = ServiceState.Running;
- _log.Write(new IPEndPoint(IPAddress.Any, _webServicePort), "Web Service (v" + _currentVersion.ToString() + ") was started successfully.");
- }
- catch (Exception ex)
- {
- _log.Write("Failed to start Web Service (v" + _currentVersion.ToString() + ")\r\n" + ex.ToString());
- throw;
- }
- }
- public void Stop()
- {
- if (_state != ServiceState.Running)
- return;
- _state = ServiceState.Stopping;
- try
- {
- _webService.Stop();
- _dnsServer.Stop();
- _dhcpServer.Stop();
- StopBlockListUpdateTimer();
- StopTlsCertificateUpdateTimer();
- _state = ServiceState.Stopped;
- _log.Write(new IPEndPoint(IPAddress.Loopback, _webServicePort), "Web Service (v" + _currentVersion.ToString() + ") was stopped successfully.");
- }
- catch (Exception ex)
- {
- _log.Write("Failed to stop Web Service (v" + _currentVersion.ToString() + ")\r\n" + ex.ToString());
- throw;
- }
- }
- #endregion
- #region properties
- public string ConfigFolder
- { get { return _configFolder; } }
- public int WebServicePort
- { get { return _webServicePort; } }
- public string WebServiceHostname
- { get { return _webServiceHostname; } }
- #endregion
- }
- }
|