Scope.cs 75 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109
  1. /*
  2. Technitium DNS Server
  3. Copyright (C) 2023 Shreyas Zare (shreyas@technitium.com)
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. using DnsServerCore.Dhcp.Options;
  16. using DnsServerCore.Dns;
  17. using System;
  18. using System.Collections.Concurrent;
  19. using System.Collections.Generic;
  20. using System.IO;
  21. using System.Linq;
  22. using System.Net;
  23. using System.Net.NetworkInformation;
  24. using System.Net.Sockets;
  25. using System.Text;
  26. using System.Threading;
  27. using System.Threading.Tasks;
  28. using TechnitiumLibrary;
  29. using TechnitiumLibrary.IO;
  30. using TechnitiumLibrary.Net;
  31. using TechnitiumLibrary.Net.Dns;
  32. using TechnitiumLibrary.Net.Dns.ResourceRecords;
  33. namespace DnsServerCore.Dhcp
  34. {
  35. public sealed class Scope : IComparable<Scope>, IDisposable
  36. {
  37. #region variables
  38. //required parameters
  39. string _name;
  40. bool _enabled;
  41. IPAddress _startingAddress;
  42. IPAddress _endingAddress;
  43. IPAddress _subnetMask;
  44. ushort _leaseTimeDays = 1; //default 1 day lease
  45. byte _leaseTimeHours = 0;
  46. byte _leaseTimeMinutes = 0;
  47. ushort _offerDelayTime;
  48. readonly LogManager _log;
  49. bool _pingCheckEnabled;
  50. ushort _pingCheckTimeout = 1000;
  51. byte _pingCheckRetries = 2;
  52. //dhcp options
  53. string _domainName;
  54. IReadOnlyCollection<string> _domainSearchList;
  55. bool _dnsUpdates = true;
  56. uint _dnsTtl = 900;
  57. IPAddress _serverAddress;
  58. string _serverHostName;
  59. string _bootFileName;
  60. IPAddress _routerAddress;
  61. bool _useThisDnsServer;
  62. IReadOnlyCollection<IPAddress> _dnsServers;
  63. IReadOnlyCollection<IPAddress> _winsServers;
  64. IReadOnlyCollection<IPAddress> _ntpServers;
  65. IReadOnlyCollection<string> _ntpServerDomainNames;
  66. IReadOnlyCollection<ClasslessStaticRouteOption.Route> _staticRoutes;
  67. IReadOnlyDictionary<string, VendorSpecificInformationOption> _vendorInfo;
  68. IReadOnlyCollection<IPAddress> _capwapAcIpAddresses;
  69. IReadOnlyCollection<IPAddress> _tftpServerAddreses;
  70. //advanced options
  71. IReadOnlyCollection<DhcpOption> _genericOptions;
  72. IReadOnlyCollection<Exclusion> _exclusions;
  73. readonly ConcurrentDictionary<ClientIdentifierOption, Lease> _reservedLeases = new ConcurrentDictionary<ClientIdentifierOption, Lease>();
  74. bool _allowOnlyReservedLeases;
  75. bool _blockLocallyAdministeredMacAddresses;
  76. //leases
  77. readonly ConcurrentDictionary<ClientIdentifierOption, Lease> _leases = new ConcurrentDictionary<ClientIdentifierOption, Lease>();
  78. //internal computed parameters
  79. IPAddress _networkAddress;
  80. IPAddress _broadcastAddress;
  81. //internal parameters
  82. const int OFFER_EXPIRY_SECONDS = 60; //1 mins offer expiry
  83. readonly ConcurrentDictionary<ClientIdentifierOption, Lease> _offers = new ConcurrentDictionary<ClientIdentifierOption, Lease>();
  84. IPAddress _lastAddressOffered;
  85. readonly SemaphoreSlim _lastAddressOfferedLock = new SemaphoreSlim(1, 1);
  86. IPAddress _interfaceAddress;
  87. int _interfaceIndex;
  88. DateTime _lastModified = DateTime.UtcNow;
  89. #endregion
  90. #region constructor
  91. public Scope(string name, bool enabled, IPAddress startingAddress, IPAddress endingAddress, IPAddress subnetMask, LogManager log)
  92. {
  93. ValidateScopeName(name);
  94. _name = name;
  95. _enabled = enabled;
  96. ChangeNetwork(startingAddress, endingAddress, subnetMask);
  97. _log = log;
  98. }
  99. public Scope(BinaryReader bR, LogManager log)
  100. {
  101. if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "SC")
  102. throw new InvalidDataException("DhcpServer scope file format is invalid.");
  103. byte version = bR.ReadByte();
  104. switch (version)
  105. {
  106. case 1:
  107. case 2:
  108. case 3:
  109. case 4:
  110. case 5:
  111. case 6:
  112. case 7:
  113. case 8:
  114. _name = bR.ReadShortString();
  115. _enabled = bR.ReadBoolean();
  116. ChangeNetwork(IPAddressExtensions.ReadFrom(bR), IPAddressExtensions.ReadFrom(bR), IPAddressExtensions.ReadFrom(bR));
  117. _leaseTimeDays = bR.ReadUInt16();
  118. _leaseTimeHours = bR.ReadByte();
  119. _leaseTimeMinutes = bR.ReadByte();
  120. _offerDelayTime = bR.ReadUInt16();
  121. if (version >= 5)
  122. {
  123. _pingCheckEnabled = bR.ReadBoolean();
  124. _pingCheckTimeout = bR.ReadUInt16();
  125. _pingCheckRetries = bR.ReadByte();
  126. }
  127. _domainName = bR.ReadShortString();
  128. if (string.IsNullOrWhiteSpace(_domainName))
  129. _domainName = null;
  130. if (version >= 7)
  131. {
  132. int count = bR.ReadByte();
  133. if (count > 0)
  134. {
  135. string[] domainSearchStrings = new string[count];
  136. for (int i = 0; i < count; i++)
  137. domainSearchStrings[i] = bR.ReadShortString();
  138. _domainSearchList = domainSearchStrings;
  139. }
  140. _dnsUpdates = bR.ReadBoolean();
  141. }
  142. _dnsTtl = bR.ReadUInt32();
  143. if (version >= 2)
  144. {
  145. _serverAddress = IPAddressExtensions.ReadFrom(bR);
  146. if (_serverAddress.Equals(IPAddress.Any))
  147. _serverAddress = null;
  148. }
  149. if (version >= 3)
  150. {
  151. _serverHostName = bR.ReadShortString();
  152. if (string.IsNullOrEmpty(_serverHostName))
  153. _serverHostName = null;
  154. _bootFileName = bR.ReadShortString();
  155. if (string.IsNullOrEmpty(_bootFileName))
  156. _bootFileName = null;
  157. }
  158. _routerAddress = IPAddressExtensions.ReadFrom(bR);
  159. if (_routerAddress.Equals(IPAddress.Any))
  160. _routerAddress = null;
  161. {
  162. int count = bR.ReadByte();
  163. if (count > 0)
  164. {
  165. if (count == 255)
  166. {
  167. _useThisDnsServer = true;
  168. FindThisDnsServerAddress();
  169. }
  170. else
  171. {
  172. IPAddress[] dnsServers = new IPAddress[count];
  173. for (int i = 0; i < count; i++)
  174. dnsServers[i] = IPAddressExtensions.ReadFrom(bR);
  175. _dnsServers = dnsServers;
  176. }
  177. }
  178. }
  179. {
  180. int count = bR.ReadByte();
  181. if (count > 0)
  182. {
  183. IPAddress[] winsServers = new IPAddress[count];
  184. for (int i = 0; i < count; i++)
  185. winsServers[i] = IPAddressExtensions.ReadFrom(bR);
  186. _winsServers = winsServers;
  187. }
  188. }
  189. {
  190. int count = bR.ReadByte();
  191. if (count > 0)
  192. {
  193. IPAddress[] ntpServers = new IPAddress[count];
  194. for (int i = 0; i < count; i++)
  195. ntpServers[i] = IPAddressExtensions.ReadFrom(bR);
  196. _ntpServers = ntpServers;
  197. }
  198. }
  199. if (version >= 7)
  200. {
  201. int count = bR.ReadByte();
  202. if (count > 0)
  203. {
  204. string[] ntpServerDomainNames = new string[count];
  205. for (int i = 0; i < count; i++)
  206. ntpServerDomainNames[i] = bR.ReadShortString();
  207. _ntpServerDomainNames = ntpServerDomainNames;
  208. }
  209. }
  210. {
  211. int count = bR.ReadByte();
  212. if (count > 0)
  213. {
  214. ClasslessStaticRouteOption.Route[] staticRoutes = new ClasslessStaticRouteOption.Route[count];
  215. for (int i = 0; i < count; i++)
  216. staticRoutes[i] = new ClasslessStaticRouteOption.Route(bR.BaseStream);
  217. _staticRoutes = staticRoutes;
  218. }
  219. }
  220. if (version >= 4)
  221. {
  222. int count = bR.ReadByte();
  223. if (count > 0)
  224. {
  225. Dictionary<string, VendorSpecificInformationOption> vendorInfo = new Dictionary<string, VendorSpecificInformationOption>(count);
  226. for (int i = 0; i < count; i++)
  227. {
  228. string vendorClassIdentifier = bR.ReadShortString();
  229. VendorSpecificInformationOption vendorSpecificInformation = new VendorSpecificInformationOption(bR.ReadBuffer());
  230. vendorInfo.Add(vendorClassIdentifier, vendorSpecificInformation);
  231. }
  232. _vendorInfo = vendorInfo;
  233. }
  234. }
  235. if (version >= 7)
  236. {
  237. int count = bR.ReadByte();
  238. if (count > 0)
  239. {
  240. IPAddress[] capwapAcIpAddresses = new IPAddress[count];
  241. for (int i = 0; i < count; i++)
  242. capwapAcIpAddresses[i] = IPAddressExtensions.ReadFrom(bR);
  243. _capwapAcIpAddresses = capwapAcIpAddresses;
  244. }
  245. }
  246. if (version >= 8)
  247. {
  248. int count = bR.ReadByte();
  249. if (count > 0)
  250. {
  251. IPAddress[] tftpServerAddreses = new IPAddress[count];
  252. for (int i = 0; i < count; i++)
  253. tftpServerAddreses[i] = IPAddressExtensions.ReadFrom(bR);
  254. _tftpServerAddreses = tftpServerAddreses;
  255. }
  256. }
  257. if (version >= 8)
  258. {
  259. int count = bR.ReadByte();
  260. if (count > 0)
  261. {
  262. DhcpOption[] genericOptions = new DhcpOption[count];
  263. for (int i = 0; i < count; i++)
  264. {
  265. DhcpOptionCode code = (DhcpOptionCode)bR.ReadByte();
  266. short length = bR.ReadInt16();
  267. byte[] value = bR.ReadBytes(length);
  268. genericOptions[i] = new DhcpOption(code, value);
  269. }
  270. _genericOptions = genericOptions;
  271. }
  272. }
  273. {
  274. int count = bR.ReadByte();
  275. if (count > 0)
  276. {
  277. Exclusion[] exclusions = new Exclusion[count];
  278. for (int i = 0; i < count; i++)
  279. exclusions[i] = new Exclusion(IPAddressExtensions.ReadFrom(bR), IPAddressExtensions.ReadFrom(bR));
  280. _exclusions = exclusions;
  281. }
  282. }
  283. {
  284. int count = bR.ReadInt32();
  285. if (count > 0)
  286. {
  287. for (int i = 0; i < count; i++)
  288. {
  289. Lease reservedLease = new Lease(bR);
  290. _reservedLeases.TryAdd(reservedLease.ClientIdentifier, reservedLease);
  291. }
  292. }
  293. _allowOnlyReservedLeases = bR.ReadBoolean();
  294. }
  295. if (version >= 6)
  296. _blockLocallyAdministeredMacAddresses = bR.ReadBoolean();
  297. else
  298. _blockLocallyAdministeredMacAddresses = false;
  299. {
  300. int count = bR.ReadInt32();
  301. if (count > 0)
  302. {
  303. for (int i = 0; i < count; i++)
  304. {
  305. Lease lease = new Lease(bR);
  306. _leases.TryAdd(lease.ClientIdentifier, lease);
  307. }
  308. }
  309. }
  310. break;
  311. default:
  312. throw new InvalidDataException("Scope data format version not supported.");
  313. }
  314. _log = log;
  315. }
  316. #endregion
  317. #region IDisposable
  318. bool _disposed;
  319. public void Dispose()
  320. {
  321. if (_disposed)
  322. return;
  323. if (_lastAddressOfferedLock is not null)
  324. _lastAddressOfferedLock.Dispose();
  325. _disposed = true;
  326. }
  327. #endregion
  328. #region static
  329. internal static void ValidateScopeName(string name)
  330. {
  331. foreach (char invalidChar in Path.GetInvalidFileNameChars())
  332. {
  333. if (name.Contains(invalidChar))
  334. throw new DhcpServerException("The scope name contains an invalid character: " + invalidChar);
  335. }
  336. }
  337. private static bool IsAddressInRange(IPAddress address, IPAddress startingAddress, IPAddress endingAddress)
  338. {
  339. uint addressNumber = address.ConvertIpToNumber();
  340. uint startingAddressNumber = startingAddress.ConvertIpToNumber();
  341. uint endingAddressNumber = endingAddress.ConvertIpToNumber();
  342. return (startingAddressNumber <= addressNumber) && (addressNumber <= endingAddressNumber);
  343. }
  344. private static void ValidateIpv4(IReadOnlyCollection<IPAddress> value, string paramName)
  345. {
  346. if (value is not null)
  347. {
  348. foreach (IPAddress ip in value)
  349. {
  350. if (ip.AddressFamily != AddressFamily.InterNetwork)
  351. throw new ArgumentException("The address must be an IPv4 address: " + ip.ToString(), paramName);
  352. }
  353. }
  354. }
  355. private static void ValidateIpv4(IPAddress value, string paramName)
  356. {
  357. if ((value is not null) && (value.AddressFamily != AddressFamily.InterNetwork))
  358. throw new ArgumentException("The address must be an IPv4 address: " + value.ToString(), paramName);
  359. }
  360. #endregion
  361. #region private
  362. private uint GetLeaseTime()
  363. {
  364. return Convert.ToUInt32((_leaseTimeDays * 24 * 60 * 60) + (_leaseTimeHours * 60 * 60) + (_leaseTimeMinutes * 60));
  365. }
  366. private async Task<AddressStatus> IsAddressAvailableAsync(IPAddress address)
  367. {
  368. if (address.Equals(_routerAddress))
  369. return AddressStatus.FALSE;
  370. if ((_dnsServers != null) && _dnsServers.Contains(address))
  371. return AddressStatus.FALSE;
  372. if ((_winsServers != null) && _winsServers.Contains(address))
  373. return AddressStatus.FALSE;
  374. if ((_ntpServers != null) && _ntpServers.Contains(address))
  375. return AddressStatus.FALSE;
  376. if (_exclusions != null)
  377. {
  378. foreach (Exclusion exclusion in _exclusions)
  379. {
  380. if (IsAddressInRange(address, exclusion.StartingAddress, exclusion.EndingAddress))
  381. return new AddressStatus(false, exclusion.EndingAddress);
  382. }
  383. }
  384. foreach (KeyValuePair<ClientIdentifierOption, Lease> reservedLease in _reservedLeases)
  385. {
  386. if (address.Equals(reservedLease.Value.Address))
  387. return AddressStatus.FALSE;
  388. }
  389. foreach (KeyValuePair<ClientIdentifierOption, Lease> lease in _leases)
  390. {
  391. if (address.Equals(lease.Value.Address))
  392. return AddressStatus.FALSE;
  393. }
  394. foreach (KeyValuePair<ClientIdentifierOption, Lease> offer in _offers)
  395. {
  396. if (address.Equals(offer.Value.Address))
  397. return AddressStatus.FALSE;
  398. }
  399. if (_pingCheckEnabled)
  400. {
  401. try
  402. {
  403. using (Ping ping = new Ping())
  404. {
  405. int retry = 0;
  406. do
  407. {
  408. PingReply reply = await ping.SendPingAsync(address, _pingCheckTimeout);
  409. if (reply.Status == IPStatus.Success)
  410. return AddressStatus.FALSE; //address is in use
  411. }
  412. while (++retry < _pingCheckRetries);
  413. }
  414. }
  415. catch
  416. { }
  417. }
  418. return AddressStatus.TRUE;
  419. }
  420. private bool IsAddressAlreadyAllocated(IPAddress address, ClientIdentifierOption clientIdentifier)
  421. {
  422. foreach (KeyValuePair<ClientIdentifierOption, Lease> lease in _leases)
  423. {
  424. if (address.Equals(lease.Value.Address))
  425. return !lease.Key.Equals(clientIdentifier);
  426. }
  427. foreach (KeyValuePair<ClientIdentifierOption, Lease> offer in _offers)
  428. {
  429. if (address.Equals(offer.Value.Address))
  430. return !offer.Key.Equals(clientIdentifier);
  431. }
  432. return false;
  433. }
  434. private ClientFullyQualifiedDomainNameOption GetClientFullyQualifiedDomainNameOption(DhcpMessage request, string overrideClientDomainName)
  435. {
  436. ClientFullyQualifiedDomainNameFlags responseFlags = ClientFullyQualifiedDomainNameFlags.None;
  437. if (request.ClientFullyQualifiedDomainName.Flags.HasFlag(ClientFullyQualifiedDomainNameFlags.EncodeUsingCanonicalWireFormat))
  438. responseFlags |= ClientFullyQualifiedDomainNameFlags.EncodeUsingCanonicalWireFormat;
  439. if (request.ClientFullyQualifiedDomainName.Flags.HasFlag(ClientFullyQualifiedDomainNameFlags.NoDnsUpdate))
  440. {
  441. responseFlags |= ClientFullyQualifiedDomainNameFlags.ShouldUpdateDns;
  442. responseFlags |= ClientFullyQualifiedDomainNameFlags.OverrideByServer;
  443. }
  444. else if (request.ClientFullyQualifiedDomainName.Flags.HasFlag(ClientFullyQualifiedDomainNameFlags.ShouldUpdateDns))
  445. {
  446. responseFlags |= ClientFullyQualifiedDomainNameFlags.ShouldUpdateDns;
  447. }
  448. else
  449. {
  450. responseFlags |= ClientFullyQualifiedDomainNameFlags.ShouldUpdateDns;
  451. responseFlags |= ClientFullyQualifiedDomainNameFlags.OverrideByServer;
  452. }
  453. string clientDomainName;
  454. if (!string.IsNullOrWhiteSpace(overrideClientDomainName))
  455. {
  456. //domain name override by server
  457. clientDomainName = overrideClientDomainName;
  458. }
  459. else if (string.IsNullOrWhiteSpace(request.ClientFullyQualifiedDomainName.DomainName))
  460. {
  461. //client domain empty and expects server for a fqdn domain name
  462. if (request.HostName is null)
  463. return null; //server unable to decide a name for client
  464. clientDomainName = request.HostName.HostName + "." + _domainName;
  465. }
  466. else if (request.ClientFullyQualifiedDomainName.DomainName.Contains('.'))
  467. {
  468. //client domain is fqdn
  469. if (request.ClientFullyQualifiedDomainName.DomainName.EndsWith("." + _domainName, StringComparison.OrdinalIgnoreCase))
  470. {
  471. clientDomainName = request.ClientFullyQualifiedDomainName.DomainName;
  472. }
  473. else
  474. {
  475. string[] parts = request.ClientFullyQualifiedDomainName.DomainName.Split('.');
  476. clientDomainName = parts[0] + "." + _domainName;
  477. }
  478. }
  479. else
  480. {
  481. //client domain is just hostname
  482. clientDomainName = request.ClientFullyQualifiedDomainName.DomainName + "." + _domainName;
  483. }
  484. return new ClientFullyQualifiedDomainNameOption(responseFlags, 255, 255, clientDomainName);
  485. }
  486. private void ConvertToReservedLease(Lease lease)
  487. {
  488. //convert dynamic to reserved lease
  489. lease.ConvertToReserved();
  490. //add reserved lease
  491. Lease reservedLease = new Lease(LeaseType.Reserved, null, DhcpMessageHardwareAddressType.Ethernet, lease.HardwareAddress, lease.Address, null);
  492. _reservedLeases[reservedLease.ClientIdentifier] = reservedLease;
  493. }
  494. private void ConvertToDynamicLease(Lease lease)
  495. {
  496. //convert reserved to dynamic lease
  497. lease.ConvertToDynamic();
  498. //remove reserved lease
  499. Lease reservedLease = new Lease(LeaseType.Reserved, null, DhcpMessageHardwareAddressType.Ethernet, lease.HardwareAddress, lease.Address, null);
  500. _reservedLeases.TryRemove(reservedLease.ClientIdentifier, out _);
  501. //remove any old single address exclusion entry
  502. if (_exclusions != null)
  503. {
  504. foreach (Exclusion exclusion in _exclusions)
  505. {
  506. if (exclusion.StartingAddress.Equals(lease.Address) && exclusion.EndingAddress.Equals(lease.Address))
  507. {
  508. //remove single address exclusion entry
  509. if (_exclusions.Count == 1)
  510. {
  511. _exclusions = null;
  512. }
  513. else
  514. {
  515. List<Exclusion> exclusions = new List<Exclusion>();
  516. foreach (Exclusion exc in _exclusions)
  517. {
  518. if (exc.Equals(exclusion))
  519. continue;
  520. exclusions.Add(exc);
  521. }
  522. _exclusions = exclusions;
  523. }
  524. break;
  525. }
  526. }
  527. }
  528. }
  529. #endregion
  530. #region internal
  531. internal bool FindInterface()
  532. {
  533. //find network with static ip address in scope range
  534. uint networkAddressNumber = _networkAddress.ConvertIpToNumber();
  535. uint subnetMaskNumber = _subnetMask.ConvertIpToNumber();
  536. foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
  537. {
  538. if (nic.OperationalStatus != OperationalStatus.Up)
  539. continue;
  540. IPInterfaceProperties ipInterface = nic.GetIPProperties();
  541. foreach (UnicastIPAddressInformation ip in ipInterface.UnicastAddresses)
  542. {
  543. if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
  544. {
  545. uint addressNumber = ip.Address.ConvertIpToNumber();
  546. if ((addressNumber & subnetMaskNumber) == networkAddressNumber)
  547. {
  548. //found interface for this scope range
  549. try
  550. {
  551. //check if interface has dynamic ipv4 address assigned via dhcp
  552. if (!OperatingSystem.IsMacOS())
  553. {
  554. foreach (IPAddress dhcpServerAddress in ipInterface.DhcpServerAddresses)
  555. {
  556. if (dhcpServerAddress.AddressFamily == AddressFamily.InterNetwork)
  557. throw new DhcpServerException("DHCP Server requires static IP address to work correctly but the network interface was found to have a dynamic IP address [" + ip.Address.ToString() + "] assigned by another DHCP server: " + dhcpServerAddress.ToString());
  558. }
  559. }
  560. }
  561. catch (PlatformNotSupportedException)
  562. {
  563. //DhcpServerAddresses() not supported on macOs
  564. //ignore the exception
  565. }
  566. _interfaceAddress = ip.Address;
  567. _interfaceIndex = ipInterface.GetIPv4Properties().Index;
  568. return true;
  569. }
  570. }
  571. }
  572. }
  573. try
  574. {
  575. if (!OperatingSystem.IsMacOS())
  576. {
  577. //check if at least one interface has static ip address
  578. foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
  579. {
  580. if (nic.OperationalStatus != OperationalStatus.Up)
  581. continue;
  582. IPInterfaceProperties ipInterface = nic.GetIPProperties();
  583. foreach (UnicastIPAddressInformation ip in ipInterface.UnicastAddresses)
  584. {
  585. if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
  586. {
  587. //check if address is static
  588. if (ipInterface.DhcpServerAddresses.Count < 1)
  589. {
  590. //found static ip address so this scope can be activated
  591. //using ANY ip address for this scope interface since we dont know the relay agent network
  592. _interfaceAddress = IPAddress.Any;
  593. _interfaceIndex = -1;
  594. return true;
  595. }
  596. }
  597. }
  598. }
  599. }
  600. }
  601. catch (PlatformNotSupportedException)
  602. {
  603. //DhcpServerAddresses() not supported on macOs
  604. //ignore the exception
  605. }
  606. //server has no static ip address configured
  607. return false;
  608. }
  609. internal void FindThisDnsServerAddress()
  610. {
  611. NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
  612. //find interface in current scope network range
  613. uint networkAddressNumber = _networkAddress.ConvertIpToNumber();
  614. uint subnetMaskNumber = _subnetMask.ConvertIpToNumber();
  615. foreach (NetworkInterface nic in networkInterfaces)
  616. {
  617. if (nic.OperationalStatus != OperationalStatus.Up)
  618. continue;
  619. IPInterfaceProperties ipInterface = nic.GetIPProperties();
  620. foreach (UnicastIPAddressInformation ip in ipInterface.UnicastAddresses)
  621. {
  622. if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
  623. {
  624. uint addressNumber = ip.Address.ConvertIpToNumber();
  625. if ((addressNumber & subnetMaskNumber) == networkAddressNumber)
  626. {
  627. //found address in this scope range to use as dns server
  628. _dnsServers = new IPAddress[] { ip.Address };
  629. return;
  630. }
  631. }
  632. }
  633. }
  634. //find unicast ip address on an interface which has gateway
  635. foreach (NetworkInterface nic in networkInterfaces)
  636. {
  637. if (nic.OperationalStatus != OperationalStatus.Up)
  638. continue;
  639. IPInterfaceProperties ipInterface = nic.GetIPProperties();
  640. if (ipInterface.GatewayAddresses.Count > 0)
  641. {
  642. foreach (UnicastIPAddressInformation ip in ipInterface.UnicastAddresses)
  643. {
  644. if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
  645. {
  646. //use this address for dns
  647. _dnsServers = new IPAddress[] { ip.Address };
  648. return;
  649. }
  650. }
  651. }
  652. }
  653. //find any unicast ip address available
  654. foreach (NetworkInterface nic in networkInterfaces)
  655. {
  656. if (nic.OperationalStatus != OperationalStatus.Up)
  657. continue;
  658. IPInterfaceProperties ipInterface = nic.GetIPProperties();
  659. foreach (UnicastIPAddressInformation ip in ipInterface.UnicastAddresses)
  660. {
  661. if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
  662. {
  663. //use this address for dns
  664. _dnsServers = new IPAddress[] { ip.Address };
  665. return;
  666. }
  667. }
  668. }
  669. //no useable address was found
  670. _dnsServers = null;
  671. }
  672. internal bool IsAddressInRange(IPAddress address)
  673. {
  674. return IsAddressInRange(address, _startingAddress, _endingAddress);
  675. }
  676. internal bool IsAddressInNetwork(IPAddress address)
  677. {
  678. uint addressNumber = address.ConvertIpToNumber();
  679. uint networkAddressNumber = _networkAddress.ConvertIpToNumber();
  680. uint broadcastAddressNumber = _broadcastAddress.ConvertIpToNumber();
  681. return (networkAddressNumber < addressNumber) && (addressNumber < broadcastAddressNumber);
  682. }
  683. internal bool IsAddressExcluded(IPAddress address)
  684. {
  685. if (_exclusions != null)
  686. {
  687. foreach (Exclusion exclusion in _exclusions)
  688. {
  689. if (IsAddressInRange(address, exclusion.StartingAddress, exclusion.EndingAddress))
  690. return true;
  691. }
  692. }
  693. return false;
  694. }
  695. internal bool IsAddressReserved(IPAddress address)
  696. {
  697. foreach (KeyValuePair<ClientIdentifierOption, Lease> reservedLease in _reservedLeases)
  698. {
  699. if (address.Equals(reservedLease.Value.Address))
  700. return true;
  701. }
  702. return false;
  703. }
  704. internal Lease GetReservedLease(DhcpMessage request)
  705. {
  706. return GetReservedLease(new ClientIdentifierOption((byte)request.HardwareAddressType, request.ClientHardwareAddress), request.ClientIdentifier);
  707. }
  708. private Lease GetReservedLease(ClientIdentifierOption reservedLeasesClientIdentifier, ClientIdentifierOption clientIdentifier)
  709. {
  710. if (_reservedLeases.TryGetValue(reservedLeasesClientIdentifier, out Lease reservedLease))
  711. {
  712. //reserved address exists
  713. if (IsAddressAlreadyAllocated(reservedLease.Address, clientIdentifier))
  714. {
  715. //reserved lease address is already allocated so ignore reserved lease
  716. if (_log is not null)
  717. _log.Write("DHCP Server cannot allocate reserved lease [" + reservedLease.Address.ToString() + "] to " + BitConverter.ToString(reservedLeasesClientIdentifier.Identifier) + " for scope '" + _name + "': The IP address is already allocated.");
  718. return null;
  719. }
  720. return reservedLease;
  721. }
  722. return null;
  723. }
  724. internal async Task<Lease> GetOfferAsync(DhcpMessage request)
  725. {
  726. if (_leases.TryGetValue(request.ClientIdentifier, out Lease existingLease))
  727. {
  728. //lease already exists
  729. if (existingLease.Type == LeaseType.Reserved)
  730. {
  731. Lease existingReservedLease = GetReservedLease(request);
  732. if ((existingReservedLease is not null) && (existingReservedLease.Address == existingLease.Address))
  733. return existingLease; //return existing reserved lease
  734. //reserved lease address was changed; proceed to offer new lease
  735. }
  736. else
  737. {
  738. //is dynamic lease
  739. if (IsAddressExcluded(existingLease.Address))
  740. {
  741. //remove existing dynamic lease; proceed to offer new lease
  742. ReleaseLease(existingLease);
  743. }
  744. else
  745. {
  746. //return existing dynamic lease
  747. return existingLease;
  748. }
  749. }
  750. }
  751. Lease reservedLease = GetReservedLease(request);
  752. if (reservedLease != null)
  753. {
  754. Lease reservedOffer = new Lease(LeaseType.Reserved, request.ClientIdentifier, null, request.ClientHardwareAddress, reservedLease.Address, null, GetLeaseTime());
  755. _offers[request.ClientIdentifier] = reservedOffer;
  756. return reservedOffer;
  757. }
  758. if (_allowOnlyReservedLeases)
  759. {
  760. if (_log is not null)
  761. _log.Write("DHCP Server failed to offer IP address to " + request.GetClientFullIdentifier() + " for scope '" + _name + "': the scope allows only reserved lease allocations.");
  762. return null;
  763. }
  764. if (_blockLocallyAdministeredMacAddresses)
  765. {
  766. if ((request.HardwareAddressType == DhcpMessageHardwareAddressType.Ethernet) && ((request.ClientHardwareAddress[0] & 0x02) > 0))
  767. {
  768. if (_log is not null)
  769. _log.Write("DHCP Server failed to offer IP address to " + request.GetClientFullIdentifier() + " for scope '" + _name + "': the scope does not allow locally administered MAC addresses.");
  770. return null;
  771. }
  772. }
  773. Lease dummyOffer = new Lease(LeaseType.None, null, null, null, null, null, 0);
  774. Lease existingOffer = _offers.GetOrAdd(request.ClientIdentifier, dummyOffer);
  775. if (dummyOffer != existingOffer)
  776. {
  777. if (existingOffer.Type == LeaseType.None)
  778. return null; //dummy offer so another thread is handling offer; do nothing
  779. //offer already exists
  780. existingOffer.ExtendLease(GetLeaseTime());
  781. return existingOffer;
  782. }
  783. //find offer ip address
  784. IPAddress offerAddress = null;
  785. if (request.RequestedIpAddress != null)
  786. {
  787. //client wish to get this address
  788. IPAddress requestedAddress = request.RequestedIpAddress.Address;
  789. if (IsAddressInRange(requestedAddress))
  790. {
  791. AddressStatus addressStatus = await IsAddressAvailableAsync(requestedAddress);
  792. if (addressStatus.IsAddressAvailable)
  793. offerAddress = requestedAddress;
  794. }
  795. }
  796. if (offerAddress is null)
  797. {
  798. await _lastAddressOfferedLock.WaitAsync();
  799. try
  800. {
  801. //find free address from scope
  802. offerAddress = _lastAddressOffered;
  803. uint endingAddressNumber = _endingAddress.ConvertIpToNumber();
  804. bool offerAddressWasResetFromEnd = false;
  805. while (true)
  806. {
  807. uint nextOfferAddressNumber = offerAddress.ConvertIpToNumber() + 1u;
  808. if (nextOfferAddressNumber > endingAddressNumber)
  809. {
  810. if (offerAddressWasResetFromEnd)
  811. {
  812. if (_log is not null)
  813. _log.Write("DHCP Server failed to offer IP address to " + request.GetClientFullIdentifier() + " for scope '" + _name + "': address unavailable due to address pool exhaustion.");
  814. return null;
  815. }
  816. offerAddress = IPAddressExtensions.ConvertNumberToIp(_startingAddress.ConvertIpToNumber() - 1u);
  817. offerAddressWasResetFromEnd = true;
  818. continue;
  819. }
  820. offerAddress = IPAddressExtensions.ConvertNumberToIp(nextOfferAddressNumber);
  821. AddressStatus addressStatus = await IsAddressAvailableAsync(offerAddress);
  822. if (addressStatus.IsAddressAvailable)
  823. break;
  824. if (addressStatus.NewAddress is not null)
  825. offerAddress = addressStatus.NewAddress;
  826. }
  827. _lastAddressOffered = offerAddress;
  828. }
  829. finally
  830. {
  831. _lastAddressOfferedLock.Release();
  832. }
  833. }
  834. Lease offerLease = new Lease(LeaseType.Dynamic, request.ClientIdentifier, null, request.ClientHardwareAddress, offerAddress, null, GetLeaseTime());
  835. return _offers[request.ClientIdentifier] = offerLease;
  836. }
  837. internal Lease GetExistingLeaseOrOffer(DhcpMessage request)
  838. {
  839. //check for lease offer first since it may have a different IP address to offer
  840. if (_offers.TryGetValue(request.ClientIdentifier, out Lease existingOffer))
  841. return existingOffer;
  842. if (_leases.TryGetValue(request.ClientIdentifier, out Lease existingLease))
  843. return existingLease;
  844. return null;
  845. }
  846. internal async Task<List<DhcpOption>> GetOptionsAsync(DhcpMessage request, IPAddress serverIdentifierAddress, string overrideClientDomainName, DnsServer dnsServer)
  847. {
  848. List<DhcpOption> options = new List<DhcpOption>();
  849. switch (request.DhcpMessageType.Type)
  850. {
  851. case DhcpMessageType.Discover:
  852. options.Add(new DhcpMessageTypeOption(DhcpMessageType.Offer));
  853. break;
  854. case DhcpMessageType.Request:
  855. case DhcpMessageType.Inform:
  856. options.Add(new DhcpMessageTypeOption(DhcpMessageType.Ack));
  857. break;
  858. default:
  859. return null;
  860. }
  861. options.Add(new ServerIdentifierOption(serverIdentifierAddress));
  862. switch (request.DhcpMessageType.Type)
  863. {
  864. case DhcpMessageType.Discover:
  865. case DhcpMessageType.Request:
  866. uint leaseTime = GetLeaseTime();
  867. options.Add(new IpAddressLeaseTimeOption(leaseTime));
  868. options.Add(new RenewalTimeValueOption(leaseTime / 2));
  869. options.Add(new RebindingTimeValueOption(Convert.ToUInt32(leaseTime * 0.875)));
  870. break;
  871. }
  872. if (request.ParameterRequestList is null)
  873. {
  874. options.Add(new SubnetMaskOption(_subnetMask));
  875. options.Add(new BroadcastAddressOption(_broadcastAddress));
  876. if (!string.IsNullOrEmpty(_domainName))
  877. {
  878. options.Add(new DomainNameOption(_domainName));
  879. if (request.ClientFullyQualifiedDomainName != null)
  880. options.Add(GetClientFullyQualifiedDomainNameOption(request, overrideClientDomainName));
  881. }
  882. if (_domainSearchList is not null)
  883. options.Add(new DomainSearchOption(_domainSearchList));
  884. if (_routerAddress is not null)
  885. options.Add(new RouterOption(new IPAddress[] { _routerAddress }));
  886. if (_dnsServers is not null)
  887. options.Add(new DomainNameServerOption(_dnsServers));
  888. if (_winsServers is not null)
  889. options.Add(new NetBiosNameServerOption(_winsServers));
  890. if ((_ntpServers is not null) || (_ntpServerDomainNames is not null))
  891. options.Add(await GetNetworkTimeProtocolServersOptionAsync(dnsServer));
  892. if (_staticRoutes is not null)
  893. options.Add(new ClasslessStaticRouteOption(_staticRoutes));
  894. }
  895. else
  896. {
  897. foreach (DhcpOptionCode optionCode in request.ParameterRequestList.OptionCodes)
  898. {
  899. switch (optionCode)
  900. {
  901. case DhcpOptionCode.SubnetMask:
  902. options.Add(new SubnetMaskOption(_subnetMask));
  903. options.Add(new BroadcastAddressOption(_broadcastAddress));
  904. break;
  905. case DhcpOptionCode.DomainName:
  906. if (!string.IsNullOrEmpty(_domainName))
  907. {
  908. options.Add(new DomainNameOption(_domainName));
  909. if (request.ClientFullyQualifiedDomainName != null)
  910. options.Add(GetClientFullyQualifiedDomainNameOption(request, overrideClientDomainName));
  911. }
  912. break;
  913. case DhcpOptionCode.DomainSearch:
  914. if (_domainSearchList is not null)
  915. options.Add(new DomainSearchOption(_domainSearchList));
  916. break;
  917. case DhcpOptionCode.Router:
  918. if (_routerAddress is not null)
  919. options.Add(new RouterOption(new IPAddress[] { _routerAddress }));
  920. break;
  921. case DhcpOptionCode.DomainNameServer:
  922. if (_dnsServers is not null)
  923. options.Add(new DomainNameServerOption(_dnsServers));
  924. break;
  925. case DhcpOptionCode.NetBiosOverTcpIpNameServer:
  926. if (_winsServers is not null)
  927. options.Add(new NetBiosNameServerOption(_winsServers));
  928. break;
  929. case DhcpOptionCode.NetworkTimeProtocolServers:
  930. if ((_ntpServers is not null) || (_ntpServerDomainNames is not null))
  931. options.Add(await GetNetworkTimeProtocolServersOptionAsync(dnsServer));
  932. break;
  933. case DhcpOptionCode.ClasslessStaticRoute:
  934. if (_staticRoutes is not null)
  935. options.Add(new ClasslessStaticRouteOption(_staticRoutes));
  936. break;
  937. case DhcpOptionCode.CAPWAPAccessControllerAddresses:
  938. if (_capwapAcIpAddresses is not null)
  939. options.Add(new CAPWAPAccessControllerOption(_capwapAcIpAddresses));
  940. break;
  941. case DhcpOptionCode.TftpServerAddress:
  942. if (_tftpServerAddreses is not null)
  943. options.Add(new TftpServerAddressOption(_tftpServerAddreses));
  944. break;
  945. default:
  946. if (_genericOptions is not null)
  947. {
  948. foreach (DhcpOption genericOption in _genericOptions)
  949. {
  950. if (optionCode == genericOption.Code)
  951. {
  952. options.Add(genericOption);
  953. break;
  954. }
  955. }
  956. }
  957. break;
  958. }
  959. }
  960. }
  961. if ((_vendorInfo is not null) && (request.VendorClassIdentifier is not null))
  962. {
  963. if (_vendorInfo.TryGetValue(request.VendorClassIdentifier.Identifier, out VendorSpecificInformationOption vendorSpecificInformationOption) || _vendorInfo.TryGetValue("", out vendorSpecificInformationOption))
  964. {
  965. options.Add(new VendorClassIdentifierOption(request.VendorClassIdentifier.Identifier));
  966. options.Add(vendorSpecificInformationOption);
  967. }
  968. else
  969. {
  970. string match = "substring(vendor-class-identifier,";
  971. foreach (KeyValuePair<string, VendorSpecificInformationOption> entry in _vendorInfo)
  972. {
  973. if (entry.Key.StartsWith(match))
  974. {
  975. int i = entry.Key.IndexOf(')', match.Length);
  976. if (i < match.Length)
  977. continue;
  978. string[] parts = entry.Key.Substring(match.Length, i - match.Length).Split(',');
  979. if (parts.Length != 2)
  980. continue;
  981. if (!int.TryParse(parts[0], out int startIndex))
  982. continue;
  983. if (!int.TryParse(parts[1], out int length))
  984. continue;
  985. if ((startIndex + length) > request.VendorClassIdentifier.Identifier.Length)
  986. continue;
  987. int j = entry.Key.IndexOf("==", i);
  988. if (j < i)
  989. continue;
  990. string value = entry.Key.Substring(j + 2);
  991. value = value.Trim();
  992. value = value.Trim('"');
  993. if (request.VendorClassIdentifier.Identifier.Substring(startIndex, length).Equals(value))
  994. {
  995. options.Add(new VendorClassIdentifierOption(value));
  996. options.Add(entry.Value);
  997. break;
  998. }
  999. }
  1000. }
  1001. }
  1002. }
  1003. options.Add(DhcpOption.CreateEndOption());
  1004. return options;
  1005. }
  1006. private async Task<NetworkTimeProtocolServersOption> GetNetworkTimeProtocolServersOptionAsync(DnsServer dnsServer)
  1007. {
  1008. if (_ntpServerDomainNames is not null)
  1009. {
  1010. Task<DnsDatagram>[] tasks = new Task<DnsDatagram>[_ntpServerDomainNames.Count];
  1011. int i = 0;
  1012. foreach (string ntpServerDomainName in _ntpServerDomainNames)
  1013. tasks[i++] = dnsServer.DirectQueryAsync(new DnsQuestionRecord(ntpServerDomainName, DnsResourceRecordType.A, DnsClass.IN), 1000);
  1014. List<IPAddress> ntpServers = new List<IPAddress>(_ntpServerDomainNames.Count + (_ntpServers is null ? 0 : _ntpServers.Count));
  1015. if (_ntpServers is not null)
  1016. ntpServers.AddRange(_ntpServers);
  1017. foreach (Task<DnsDatagram> task in tasks)
  1018. {
  1019. try
  1020. {
  1021. ntpServers.AddRange(DnsClient.ParseResponseA(await task));
  1022. }
  1023. catch
  1024. { }
  1025. }
  1026. return new NetworkTimeProtocolServersOption(ntpServers);
  1027. }
  1028. else
  1029. {
  1030. return new NetworkTimeProtocolServersOption(_ntpServers);
  1031. }
  1032. }
  1033. internal void CommitLease(Lease lease)
  1034. {
  1035. lease.ExtendLease(GetLeaseTime());
  1036. _leases[lease.ClientIdentifier] = lease;
  1037. _offers.TryRemove(lease.ClientIdentifier, out _);
  1038. _lastModified = DateTime.UtcNow;
  1039. }
  1040. internal void ReleaseLease(Lease lease)
  1041. {
  1042. _leases.TryRemove(lease.ClientIdentifier, out _);
  1043. _lastModified = DateTime.UtcNow;
  1044. }
  1045. internal void SetEnabled(bool enabled)
  1046. {
  1047. _enabled = enabled;
  1048. if (!enabled)
  1049. {
  1050. _interfaceAddress = null;
  1051. _interfaceIndex = 0;
  1052. }
  1053. }
  1054. internal void RemoveExpiredOffers()
  1055. {
  1056. DateTime utcNow = DateTime.UtcNow;
  1057. foreach (KeyValuePair<ClientIdentifierOption, Lease> offer in _offers)
  1058. {
  1059. if (utcNow > offer.Value.LeaseObtained.AddSeconds(OFFER_EXPIRY_SECONDS))
  1060. {
  1061. //offer expired
  1062. _offers.TryRemove(offer.Key, out _);
  1063. }
  1064. }
  1065. }
  1066. internal List<Lease> RemoveExpiredLeases()
  1067. {
  1068. List<Lease> expiredLeases = new List<Lease>();
  1069. DateTime utcNow = DateTime.UtcNow;
  1070. foreach (KeyValuePair<ClientIdentifierOption, Lease> lease in _leases)
  1071. {
  1072. if (utcNow > lease.Value.LeaseExpires)
  1073. {
  1074. //lease expired
  1075. if (_leases.TryRemove(lease.Key, out Lease expiredLease))
  1076. expiredLeases.Add(expiredLease);
  1077. }
  1078. }
  1079. if (expiredLeases.Count > 0)
  1080. _lastModified = DateTime.UtcNow;
  1081. return expiredLeases;
  1082. }
  1083. #endregion
  1084. #region public
  1085. public void ChangeNetwork(IPAddress startingAddress, IPAddress endingAddress, IPAddress subnetMask)
  1086. {
  1087. if (startingAddress.AddressFamily != AddressFamily.InterNetwork)
  1088. throw new ArgumentException("The address must be an IPv4 address: " + startingAddress.ToString(), nameof(startingAddress));
  1089. if (endingAddress.AddressFamily != AddressFamily.InterNetwork)
  1090. throw new ArgumentException("The address must be an IPv4 address: " + endingAddress.ToString(), nameof(endingAddress));
  1091. if (subnetMask.AddressFamily != AddressFamily.InterNetwork)
  1092. throw new ArgumentException("The address must be an IPv4 address: " + subnetMask.ToString(), nameof(subnetMask));
  1093. uint startingAddressNumber = startingAddress.ConvertIpToNumber();
  1094. uint endingAddressNumber = endingAddress.ConvertIpToNumber();
  1095. if (startingAddressNumber >= endingAddressNumber)
  1096. throw new ArgumentException("Ending address must be greater than starting address.");
  1097. _startingAddress = startingAddress;
  1098. _endingAddress = endingAddress;
  1099. _subnetMask = subnetMask;
  1100. //compute other parameters
  1101. uint subnetMaskNumber = _subnetMask.ConvertIpToNumber();
  1102. uint networkAddressNumber = startingAddressNumber & subnetMaskNumber;
  1103. uint broadcastAddressNumber = networkAddressNumber | ~subnetMaskNumber;
  1104. if (networkAddressNumber == startingAddressNumber)
  1105. throw new ArgumentException("Starting address cannot be same as the network address.");
  1106. if (broadcastAddressNumber == endingAddressNumber)
  1107. throw new ArgumentException("Ending address cannot be same as the broadcast address.");
  1108. _networkAddress = IPAddressExtensions.ConvertNumberToIp(networkAddressNumber);
  1109. _broadcastAddress = IPAddressExtensions.ConvertNumberToIp(broadcastAddressNumber);
  1110. _lastAddressOfferedLock.Wait();
  1111. try
  1112. {
  1113. _lastAddressOffered = IPAddressExtensions.ConvertNumberToIp(startingAddressNumber - 1u);
  1114. }
  1115. finally
  1116. {
  1117. _lastAddressOfferedLock.Release();
  1118. }
  1119. }
  1120. public bool AddReservedLease(Lease reservedLease)
  1121. {
  1122. return _reservedLeases.TryAdd(reservedLease.ClientIdentifier, reservedLease);
  1123. }
  1124. public bool RemoveReservedLease(string hardwareAddress)
  1125. {
  1126. byte[] hardwareAddressBytes = Lease.ParseHardwareAddress(hardwareAddress);
  1127. ClientIdentifierOption reservedLeaseClientIdentifier = new ClientIdentifierOption((byte)DhcpMessageHardwareAddressType.Ethernet, hardwareAddressBytes);
  1128. return _reservedLeases.TryRemove(reservedLeaseClientIdentifier, out _);
  1129. }
  1130. public Lease RemoveLease(string hardwareAddress)
  1131. {
  1132. byte[] hardwareAddressBytes = Lease.ParseHardwareAddress(hardwareAddress);
  1133. foreach (KeyValuePair<ClientIdentifierOption, Lease> entry in _leases)
  1134. {
  1135. if (BinaryNumber.Equals(entry.Value.HardwareAddress, hardwareAddressBytes))
  1136. return RemoveLease(entry.Key);
  1137. }
  1138. throw new DhcpServerException("No lease was found for hardware address: " + hardwareAddress);
  1139. }
  1140. public Lease RemoveLease(ClientIdentifierOption clientIdentifier)
  1141. {
  1142. if (!_leases.TryRemove(clientIdentifier, out Lease removedLease))
  1143. throw new DhcpServerException("No lease was found for client identifier: " + clientIdentifier.ToString());
  1144. if (removedLease.Type == LeaseType.Reserved)
  1145. {
  1146. //remove reserved lease
  1147. ClientIdentifierOption reservedLeaseClientIdentifier = new ClientIdentifierOption((byte)DhcpMessageHardwareAddressType.Ethernet, removedLease.HardwareAddress);
  1148. if (_reservedLeases.TryGetValue(reservedLeaseClientIdentifier, out Lease existingReservedLease))
  1149. {
  1150. //remove reserved lease only if the IP addresses match
  1151. if (existingReservedLease.Address.Equals(removedLease.Address))
  1152. _reservedLeases.TryRemove(reservedLeaseClientIdentifier, out _);
  1153. }
  1154. }
  1155. return removedLease;
  1156. }
  1157. public void ConvertToReservedLease(string hardwareAddress)
  1158. {
  1159. byte[] hardwareAddressBytes = Lease.ParseHardwareAddress(hardwareAddress);
  1160. foreach (KeyValuePair<ClientIdentifierOption, Lease> entry in _leases)
  1161. {
  1162. Lease lease = entry.Value;
  1163. if ((lease.Type == LeaseType.Dynamic) && BinaryNumber.Equals(lease.HardwareAddress, hardwareAddressBytes))
  1164. {
  1165. ConvertToReservedLease(lease);
  1166. return;
  1167. }
  1168. }
  1169. throw new DhcpServerException("No dynamic lease was found for hardware address: " + hardwareAddress);
  1170. }
  1171. public void ConvertToReservedLease(ClientIdentifierOption clientIdentifier)
  1172. {
  1173. if (!_leases.TryGetValue(clientIdentifier, out Lease lease) || (lease.Type != LeaseType.Dynamic))
  1174. throw new DhcpServerException("No dynamic lease was found for client identifier: " + clientIdentifier.ToString());
  1175. ConvertToReservedLease(lease);
  1176. }
  1177. public void ConvertToDynamicLease(string hardwareAddress)
  1178. {
  1179. byte[] hardwareAddressBytes = Lease.ParseHardwareAddress(hardwareAddress);
  1180. foreach (KeyValuePair<ClientIdentifierOption, Lease> entry in _leases)
  1181. {
  1182. Lease lease = entry.Value;
  1183. if ((lease.Type == LeaseType.Reserved) && BinaryNumber.Equals(lease.HardwareAddress, hardwareAddressBytes))
  1184. {
  1185. ConvertToDynamicLease(lease);
  1186. return;
  1187. }
  1188. }
  1189. throw new DhcpServerException("No reserved lease was found for hardware address: " + hardwareAddress);
  1190. }
  1191. public void ConvertToDynamicLease(ClientIdentifierOption clientIdentifier)
  1192. {
  1193. if (!_leases.TryGetValue(clientIdentifier, out Lease lease) || (lease.Type != LeaseType.Reserved))
  1194. throw new DhcpServerException("No reserved lease was found for client identifier: " + clientIdentifier.ToString());
  1195. ConvertToDynamicLease(lease);
  1196. }
  1197. public void WriteTo(BinaryWriter bW)
  1198. {
  1199. bW.Write(Encoding.ASCII.GetBytes("SC"));
  1200. bW.Write((byte)8); //version
  1201. bW.WriteShortString(_name);
  1202. bW.Write(_enabled);
  1203. _startingAddress.WriteTo(bW);
  1204. _endingAddress.WriteTo(bW);
  1205. _subnetMask.WriteTo(bW);
  1206. bW.Write(_leaseTimeDays);
  1207. bW.Write(_leaseTimeHours);
  1208. bW.Write(_leaseTimeMinutes);
  1209. bW.Write(_offerDelayTime);
  1210. bW.Write(_pingCheckEnabled);
  1211. bW.Write(_pingCheckTimeout);
  1212. bW.Write(_pingCheckRetries);
  1213. if (string.IsNullOrWhiteSpace(_domainName))
  1214. bW.Write((byte)0);
  1215. else
  1216. bW.WriteShortString(_domainName);
  1217. if (_domainSearchList is null)
  1218. {
  1219. bW.Write((byte)0);
  1220. }
  1221. else
  1222. {
  1223. bW.Write(Convert.ToByte(_domainSearchList.Count));
  1224. foreach (string domainSearchString in _domainSearchList)
  1225. bW.WriteShortString(domainSearchString);
  1226. }
  1227. bW.Write(_dnsUpdates);
  1228. bW.Write(_dnsTtl);
  1229. if (_serverAddress is null)
  1230. IPAddress.Any.WriteTo(bW);
  1231. else
  1232. _serverAddress.WriteTo(bW);
  1233. if (string.IsNullOrEmpty(_serverHostName))
  1234. bW.Write((byte)0);
  1235. else
  1236. bW.WriteShortString(_serverHostName);
  1237. if (string.IsNullOrEmpty(_bootFileName))
  1238. bW.Write((byte)0);
  1239. else
  1240. bW.WriteShortString(_bootFileName);
  1241. if (_routerAddress is null)
  1242. IPAddress.Any.WriteTo(bW);
  1243. else
  1244. _routerAddress.WriteTo(bW);
  1245. if (_useThisDnsServer)
  1246. {
  1247. bW.Write((byte)255);
  1248. }
  1249. else if (_dnsServers is null)
  1250. {
  1251. bW.Write((byte)0);
  1252. }
  1253. else
  1254. {
  1255. bW.Write(Convert.ToByte(_dnsServers.Count));
  1256. foreach (IPAddress dnsServer in _dnsServers)
  1257. dnsServer.WriteTo(bW);
  1258. }
  1259. if (_winsServers is null)
  1260. {
  1261. bW.Write((byte)0);
  1262. }
  1263. else
  1264. {
  1265. bW.Write(Convert.ToByte(_winsServers.Count));
  1266. foreach (IPAddress winsServer in _winsServers)
  1267. winsServer.WriteTo(bW);
  1268. }
  1269. if (_ntpServers is null)
  1270. {
  1271. bW.Write((byte)0);
  1272. }
  1273. else
  1274. {
  1275. bW.Write(Convert.ToByte(_ntpServers.Count));
  1276. foreach (IPAddress ntpServer in _ntpServers)
  1277. ntpServer.WriteTo(bW);
  1278. }
  1279. if (_ntpServerDomainNames is null)
  1280. {
  1281. bW.Write((byte)0);
  1282. }
  1283. else
  1284. {
  1285. bW.Write(Convert.ToByte(_ntpServerDomainNames.Count));
  1286. foreach (string ntpServerDomainName in _ntpServerDomainNames)
  1287. bW.WriteShortString(ntpServerDomainName);
  1288. }
  1289. if (_staticRoutes is null)
  1290. {
  1291. bW.Write((byte)0);
  1292. }
  1293. else
  1294. {
  1295. bW.Write(Convert.ToByte(_staticRoutes.Count));
  1296. foreach (ClasslessStaticRouteOption.Route route in _staticRoutes)
  1297. route.WriteTo(bW.BaseStream);
  1298. }
  1299. if (_vendorInfo is null)
  1300. {
  1301. bW.Write((byte)0);
  1302. }
  1303. else
  1304. {
  1305. bW.Write(Convert.ToByte(_vendorInfo.Count));
  1306. foreach (KeyValuePair<string, VendorSpecificInformationOption> entry in _vendorInfo)
  1307. {
  1308. bW.WriteShortString(entry.Key);
  1309. bW.WriteBuffer(entry.Value.Information);
  1310. }
  1311. }
  1312. if (_capwapAcIpAddresses is null)
  1313. {
  1314. bW.Write((byte)0);
  1315. }
  1316. else
  1317. {
  1318. bW.Write(Convert.ToByte(_capwapAcIpAddresses.Count));
  1319. foreach (IPAddress capwapAcIpAddress in _capwapAcIpAddresses)
  1320. capwapAcIpAddress.WriteTo(bW);
  1321. }
  1322. if (_tftpServerAddreses is null)
  1323. {
  1324. bW.Write((byte)0);
  1325. }
  1326. else
  1327. {
  1328. bW.Write(Convert.ToByte(_tftpServerAddreses.Count));
  1329. foreach (IPAddress tftpServerAddress in _tftpServerAddreses)
  1330. tftpServerAddress.WriteTo(bW);
  1331. }
  1332. if (_genericOptions is null)
  1333. {
  1334. bW.Write((byte)0);
  1335. }
  1336. else
  1337. {
  1338. bW.Write(Convert.ToByte(_genericOptions.Count));
  1339. foreach (DhcpOption genericOption in _genericOptions)
  1340. {
  1341. bW.Write((byte)genericOption.Code);
  1342. bW.Write(Convert.ToInt16(genericOption.RawValue.Length));
  1343. bW.Write(genericOption.RawValue);
  1344. }
  1345. }
  1346. if (_exclusions is null)
  1347. {
  1348. bW.Write((byte)0);
  1349. }
  1350. else
  1351. {
  1352. bW.Write(Convert.ToByte(_exclusions.Count));
  1353. foreach (Exclusion exclusion in _exclusions)
  1354. {
  1355. exclusion.StartingAddress.WriteTo(bW);
  1356. exclusion.EndingAddress.WriteTo(bW);
  1357. }
  1358. }
  1359. bW.Write(_reservedLeases.Count);
  1360. foreach (KeyValuePair<ClientIdentifierOption, Lease> reservedLease in _reservedLeases)
  1361. reservedLease.Value.WriteTo(bW);
  1362. bW.Write(_allowOnlyReservedLeases);
  1363. bW.Write(_blockLocallyAdministeredMacAddresses);
  1364. {
  1365. bW.Write(_leases.Count);
  1366. foreach (KeyValuePair<ClientIdentifierOption, Lease> lease in _leases)
  1367. lease.Value.WriteTo(bW);
  1368. }
  1369. }
  1370. public override bool Equals(object obj)
  1371. {
  1372. if (obj is null)
  1373. return false;
  1374. if (ReferenceEquals(this, obj))
  1375. return true;
  1376. return Equals(obj as Scope);
  1377. }
  1378. public bool Equals(Scope other)
  1379. {
  1380. if (other is null)
  1381. return false;
  1382. if (!_startingAddress.Equals(other._startingAddress))
  1383. return false;
  1384. if (!_endingAddress.Equals(other._endingAddress))
  1385. return false;
  1386. return true;
  1387. }
  1388. public override int GetHashCode()
  1389. {
  1390. return HashCode.Combine(_startingAddress, _endingAddress, _subnetMask);
  1391. }
  1392. public override string ToString()
  1393. {
  1394. return _name;
  1395. }
  1396. public int CompareTo(Scope other)
  1397. {
  1398. return _name.CompareTo(other._name);
  1399. }
  1400. #endregion
  1401. #region properties
  1402. public string Name
  1403. {
  1404. get { return _name; }
  1405. set
  1406. {
  1407. ValidateScopeName(value);
  1408. _name = value;
  1409. }
  1410. }
  1411. public bool Enabled
  1412. { get { return _enabled; } }
  1413. public IPAddress StartingAddress
  1414. { get { return _startingAddress; } }
  1415. public IPAddress EndingAddress
  1416. { get { return _endingAddress; } }
  1417. public IPAddress SubnetMask
  1418. { get { return _subnetMask; } }
  1419. public ushort LeaseTimeDays
  1420. {
  1421. get { return _leaseTimeDays; }
  1422. set
  1423. {
  1424. if (value > 999)
  1425. throw new ArgumentOutOfRangeException(nameof(LeaseTimeDays), "Lease time in days must be between 0 to 999.");
  1426. _leaseTimeDays = value;
  1427. }
  1428. }
  1429. public byte LeaseTimeHours
  1430. {
  1431. get { return _leaseTimeHours; }
  1432. set
  1433. {
  1434. if (value > 23)
  1435. throw new ArgumentOutOfRangeException(nameof(LeaseTimeHours), "Lease time in hours must be between 0 to 23.");
  1436. _leaseTimeHours = value;
  1437. }
  1438. }
  1439. public byte LeaseTimeMinutes
  1440. {
  1441. get { return _leaseTimeMinutes; }
  1442. set
  1443. {
  1444. if (value > 59)
  1445. throw new ArgumentOutOfRangeException(nameof(LeaseTimeMinutes), "Lease time in minutes must be between 0 to 59.");
  1446. _leaseTimeMinutes = value;
  1447. }
  1448. }
  1449. public ushort OfferDelayTime
  1450. {
  1451. get { return _offerDelayTime; }
  1452. set { _offerDelayTime = value; }
  1453. }
  1454. public bool PingCheckEnabled
  1455. {
  1456. get { return _pingCheckEnabled; }
  1457. set { _pingCheckEnabled = value; }
  1458. }
  1459. public ushort PingCheckTimeout
  1460. {
  1461. get { return _pingCheckTimeout; }
  1462. set { _pingCheckTimeout = value; }
  1463. }
  1464. public byte PingCheckRetries
  1465. {
  1466. get { return _pingCheckRetries; }
  1467. set { _pingCheckRetries = value; }
  1468. }
  1469. public string DomainName
  1470. {
  1471. get { return _domainName; }
  1472. set
  1473. {
  1474. if (value != null)
  1475. DnsClient.IsDomainNameValid(value, true);
  1476. _domainName = value;
  1477. }
  1478. }
  1479. public IReadOnlyCollection<string> DomainSearchList
  1480. {
  1481. get { return _domainSearchList; }
  1482. set
  1483. {
  1484. if (value is not null)
  1485. {
  1486. foreach (string domainSearchString in value)
  1487. DnsClient.IsDomainNameValid(domainSearchString, true);
  1488. }
  1489. _domainSearchList = value;
  1490. }
  1491. }
  1492. public bool DnsUpdates
  1493. {
  1494. get { return _dnsUpdates; }
  1495. set { _dnsUpdates = value; }
  1496. }
  1497. public uint DnsTtl
  1498. {
  1499. get { return _dnsTtl; }
  1500. set { _dnsTtl = value; }
  1501. }
  1502. public IPAddress ServerAddress
  1503. {
  1504. get { return _serverAddress; }
  1505. set
  1506. {
  1507. ValidateIpv4(value, nameof(ServerAddress));
  1508. _serverAddress = value;
  1509. }
  1510. }
  1511. public string ServerHostName
  1512. {
  1513. get { return _serverHostName; }
  1514. set
  1515. {
  1516. if ((value != null) && (value.Length >= 64))
  1517. throw new ArgumentException("Server host name cannot exceed 63 bytes.");
  1518. _serverHostName = value;
  1519. }
  1520. }
  1521. public string BootFileName
  1522. {
  1523. get { return _bootFileName; }
  1524. set
  1525. {
  1526. if ((value != null) && (value.Length >= 128))
  1527. throw new ArgumentException("Boot file name cannot exceed 127 bytes.");
  1528. _bootFileName = value;
  1529. }
  1530. }
  1531. public IPAddress RouterAddress
  1532. {
  1533. get { return _routerAddress; }
  1534. set
  1535. {
  1536. ValidateIpv4(value, nameof(RouterAddress));
  1537. _routerAddress = value;
  1538. }
  1539. }
  1540. public bool UseThisDnsServer
  1541. {
  1542. get { return _useThisDnsServer; }
  1543. set
  1544. {
  1545. _useThisDnsServer = value;
  1546. if (_useThisDnsServer)
  1547. FindThisDnsServerAddress();
  1548. }
  1549. }
  1550. public IReadOnlyCollection<IPAddress> DnsServers
  1551. {
  1552. get { return _dnsServers; }
  1553. set
  1554. {
  1555. ValidateIpv4(value, nameof(DnsServers));
  1556. _dnsServers = value;
  1557. if ((_dnsServers != null) && _dnsServers.Count > 0)
  1558. _useThisDnsServer = false;
  1559. }
  1560. }
  1561. public IReadOnlyCollection<IPAddress> WinsServers
  1562. {
  1563. get { return _winsServers; }
  1564. set
  1565. {
  1566. ValidateIpv4(value, nameof(WinsServers));
  1567. _winsServers = value;
  1568. }
  1569. }
  1570. public IReadOnlyCollection<IPAddress> NtpServers
  1571. {
  1572. get { return _ntpServers; }
  1573. set
  1574. {
  1575. ValidateIpv4(value, nameof(NtpServers));
  1576. _ntpServers = value;
  1577. }
  1578. }
  1579. public IReadOnlyCollection<string> NtpServerDomainNames
  1580. {
  1581. get { return _ntpServerDomainNames; }
  1582. set
  1583. {
  1584. if (value is not null)
  1585. {
  1586. foreach (string ntpServerDomainName in value)
  1587. DnsClient.IsDomainNameValid(ntpServerDomainName, true);
  1588. }
  1589. _ntpServerDomainNames = value;
  1590. }
  1591. }
  1592. public IReadOnlyCollection<ClasslessStaticRouteOption.Route> StaticRoutes
  1593. {
  1594. get { return _staticRoutes; }
  1595. set { _staticRoutes = value; }
  1596. }
  1597. public IReadOnlyDictionary<string, VendorSpecificInformationOption> VendorInfo
  1598. {
  1599. get { return _vendorInfo; }
  1600. set { _vendorInfo = value; }
  1601. }
  1602. public IReadOnlyCollection<IPAddress> CAPWAPAcIpAddresses
  1603. {
  1604. get { return _capwapAcIpAddresses; }
  1605. set
  1606. {
  1607. ValidateIpv4(value, nameof(CAPWAPAcIpAddresses));
  1608. _capwapAcIpAddresses = value;
  1609. }
  1610. }
  1611. public IReadOnlyCollection<IPAddress> TftpServerAddresses
  1612. {
  1613. get { return _tftpServerAddreses; }
  1614. set
  1615. {
  1616. ValidateIpv4(value, nameof(TftpServerAddresses));
  1617. _tftpServerAddreses = value;
  1618. }
  1619. }
  1620. public IReadOnlyCollection<DhcpOption> GenericOptions
  1621. {
  1622. get { return _genericOptions; }
  1623. set { _genericOptions = value; }
  1624. }
  1625. public IReadOnlyCollection<Exclusion> Exclusions
  1626. {
  1627. get { return _exclusions; }
  1628. set
  1629. {
  1630. if (value is null)
  1631. {
  1632. _exclusions = null;
  1633. }
  1634. else
  1635. {
  1636. foreach (Exclusion exclusion in value)
  1637. {
  1638. if (!IsAddressInRange(exclusion.StartingAddress))
  1639. throw new ArgumentOutOfRangeException(nameof(Exclusions), "Exclusion starting address must be in scope range.");
  1640. if (!IsAddressInRange(exclusion.EndingAddress))
  1641. throw new ArgumentOutOfRangeException(nameof(Exclusions), "Exclusion ending address must be in scope range.");
  1642. }
  1643. _exclusions = value;
  1644. }
  1645. }
  1646. }
  1647. public IReadOnlyCollection<Lease> ReservedLeases
  1648. {
  1649. get
  1650. {
  1651. List<Lease> leases = new List<Lease>(_reservedLeases.Count);
  1652. foreach (KeyValuePair<ClientIdentifierOption, Lease> entry in _reservedLeases)
  1653. leases.Add(entry.Value);
  1654. leases.Sort();
  1655. return leases;
  1656. }
  1657. set
  1658. {
  1659. if (value is null)
  1660. {
  1661. _reservedLeases.Clear();
  1662. }
  1663. else
  1664. {
  1665. foreach (Lease reservedLease in value)
  1666. {
  1667. if (!IsAddressInRange(reservedLease.Address))
  1668. throw new ArgumentOutOfRangeException(nameof(ReservedLeases), "Reserved address must be in scope range.");
  1669. }
  1670. _reservedLeases.Clear();
  1671. foreach (Lease reservedLease in value)
  1672. _reservedLeases.TryAdd(reservedLease.ClientIdentifier, reservedLease);
  1673. }
  1674. }
  1675. }
  1676. public bool AllowOnlyReservedLeases
  1677. {
  1678. get { return _allowOnlyReservedLeases; }
  1679. set { _allowOnlyReservedLeases = value; }
  1680. }
  1681. public bool BlockLocallyAdministeredMacAddresses
  1682. {
  1683. get { return _blockLocallyAdministeredMacAddresses; }
  1684. set { _blockLocallyAdministeredMacAddresses = value; }
  1685. }
  1686. public IReadOnlyDictionary<ClientIdentifierOption, Lease> Leases
  1687. { get { return _leases; } }
  1688. public IPAddress NetworkAddress
  1689. { get { return _networkAddress; } }
  1690. public IPAddress BroadcastAddress
  1691. { get { return _broadcastAddress; } }
  1692. public IPAddress InterfaceAddress
  1693. { get { return _interfaceAddress; } }
  1694. internal int InterfaceIndex
  1695. { get { return _interfaceIndex; } }
  1696. internal DateTime LastModified
  1697. { get { return _lastModified; } }
  1698. #endregion
  1699. class AddressStatus
  1700. {
  1701. public static readonly AddressStatus TRUE = new AddressStatus(true, null);
  1702. public static readonly AddressStatus FALSE = new AddressStatus(false, null);
  1703. public readonly bool IsAddressAvailable;
  1704. public readonly IPAddress NewAddress;
  1705. public AddressStatus(bool isAddressAvailable, IPAddress newAddress)
  1706. {
  1707. IsAddressAvailable = isAddressAvailable;
  1708. NewAddress = newAddress;
  1709. }
  1710. }
  1711. }
  1712. }