Scope.cs 78 KB

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