IPNetwork.cs 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Net;
  5. using System.Net.Sockets;
  6. using System.Numerics;
  7. using System.Text.RegularExpressions;
  8. namespace Emby.Server.Implementations.Networking.IPNetwork
  9. {
  10. /// <summary>
  11. /// IP Network utility class.
  12. /// Use IPNetwork.Parse to create instances.
  13. /// </summary>
  14. public class IPNetwork : IComparable<IPNetwork>
  15. {
  16. #region properties
  17. //private uint _network;
  18. private BigInteger _ipaddress;
  19. private AddressFamily _family;
  20. //private uint _netmask;
  21. //private uint _broadcast;
  22. //private uint _firstUsable;
  23. //private uint _lastUsable;
  24. //private uint _usable;
  25. private byte _cidr;
  26. #endregion
  27. #region accessors
  28. private BigInteger _network
  29. {
  30. get
  31. {
  32. var uintNetwork = this._ipaddress & this._netmask;
  33. return uintNetwork;
  34. }
  35. }
  36. /// <summary>
  37. /// Network address
  38. /// </summary>
  39. public IPAddress Network => IPNetwork.ToIPAddress(this._network, this._family);
  40. /// <summary>
  41. /// Address Family
  42. /// </summary>
  43. public AddressFamily AddressFamily => this._family;
  44. private BigInteger _netmask => IPNetwork.ToUint(this._cidr, this._family);
  45. /// <summary>
  46. /// Netmask
  47. /// </summary>
  48. public IPAddress Netmask => IPNetwork.ToIPAddress(this._netmask, this._family);
  49. private BigInteger _broadcast
  50. {
  51. get
  52. {
  53. int width = this._family == System.Net.Sockets.AddressFamily.InterNetwork ? 4 : 16;
  54. var uintBroadcast = this._network + this._netmask.PositiveReverse(width);
  55. return uintBroadcast;
  56. }
  57. }
  58. /// <summary>
  59. /// Broadcast address
  60. /// </summary>
  61. public IPAddress Broadcast
  62. {
  63. get
  64. {
  65. if (this._family == System.Net.Sockets.AddressFamily.InterNetworkV6)
  66. {
  67. return null;
  68. }
  69. return IPNetwork.ToIPAddress(this._broadcast, this._family);
  70. }
  71. }
  72. /// <summary>
  73. /// First usable IP adress in Network
  74. /// </summary>
  75. public IPAddress FirstUsable
  76. {
  77. get
  78. {
  79. var fisrt = this._family == System.Net.Sockets.AddressFamily.InterNetworkV6
  80. ? this._network
  81. : (this.Usable <= 0) ? this._network : this._network + 1;
  82. return IPNetwork.ToIPAddress(fisrt, this._family);
  83. }
  84. }
  85. /// <summary>
  86. /// Last usable IP adress in Network
  87. /// </summary>
  88. public IPAddress LastUsable
  89. {
  90. get
  91. {
  92. var last = this._family == System.Net.Sockets.AddressFamily.InterNetworkV6
  93. ? this._broadcast
  94. : (this.Usable <= 0) ? this._network : this._broadcast - 1;
  95. return IPNetwork.ToIPAddress(last, this._family);
  96. }
  97. }
  98. /// <summary>
  99. /// Number of usable IP adress in Network
  100. /// </summary>
  101. public BigInteger Usable
  102. {
  103. get
  104. {
  105. if (this._family == System.Net.Sockets.AddressFamily.InterNetworkV6)
  106. {
  107. return this.Total;
  108. }
  109. byte[] mask = new byte[] { 0xff, 0xff, 0xff, 0xff, 0x00 };
  110. var bmask = new BigInteger(mask);
  111. var usableIps = (_cidr > 30) ? 0 : ((bmask >> _cidr) - 1);
  112. return usableIps;
  113. }
  114. }
  115. /// <summary>
  116. /// Number of IP adress in Network
  117. /// </summary>
  118. public BigInteger Total
  119. {
  120. get
  121. {
  122. int max = this._family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
  123. var count = BigInteger.Pow(2, (max - _cidr));
  124. return count;
  125. }
  126. }
  127. /// <summary>
  128. /// The CIDR netmask notation
  129. /// </summary>
  130. public byte Cidr => this._cidr;
  131. #endregion
  132. #region constructor
  133. #if TRAVISCI
  134. public
  135. #else
  136. internal
  137. #endif
  138. IPNetwork(BigInteger ipaddress, AddressFamily family, byte cidr)
  139. {
  140. int maxCidr = family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
  141. if (cidr > maxCidr)
  142. {
  143. throw new ArgumentOutOfRangeException(nameof(cidr));
  144. }
  145. this._ipaddress = ipaddress;
  146. this._family = family;
  147. this._cidr = cidr;
  148. }
  149. #endregion
  150. #region parsers
  151. /// <summary>
  152. /// 192.168.168.100 - 255.255.255.0
  153. ///
  154. /// Network : 192.168.168.0
  155. /// Netmask : 255.255.255.0
  156. /// Cidr : 24
  157. /// Start : 192.168.168.1
  158. /// End : 192.168.168.254
  159. /// Broadcast : 192.168.168.255
  160. /// </summary>
  161. /// <param name="ipaddress"></param>
  162. /// <param name="netmask"></param>
  163. /// <returns></returns>
  164. public static IPNetwork Parse(string ipaddress, string netmask)
  165. {
  166. IPNetwork ipnetwork = null;
  167. IPNetwork.InternalParse(false, ipaddress, netmask, out ipnetwork);
  168. return ipnetwork;
  169. }
  170. /// <summary>
  171. /// 192.168.168.100/24
  172. ///
  173. /// Network : 192.168.168.0
  174. /// Netmask : 255.255.255.0
  175. /// Cidr : 24
  176. /// Start : 192.168.168.1
  177. /// End : 192.168.168.254
  178. /// Broadcast : 192.168.168.255
  179. /// </summary>
  180. /// <param name="ipaddress"></param>
  181. /// <param name="cidr"></param>
  182. /// <returns></returns>
  183. public static IPNetwork Parse(string ipaddress, byte cidr)
  184. {
  185. IPNetwork ipnetwork = null;
  186. IPNetwork.InternalParse(false, ipaddress, cidr, out ipnetwork);
  187. return ipnetwork;
  188. }
  189. /// <summary>
  190. /// 192.168.168.100 255.255.255.0
  191. ///
  192. /// Network : 192.168.168.0
  193. /// Netmask : 255.255.255.0
  194. /// Cidr : 24
  195. /// Start : 192.168.168.1
  196. /// End : 192.168.168.254
  197. /// Broadcast : 192.168.168.255
  198. /// </summary>
  199. /// <param name="ipaddress"></param>
  200. /// <param name="netmask"></param>
  201. /// <returns></returns>
  202. public static IPNetwork Parse(IPAddress ipaddress, IPAddress netmask)
  203. {
  204. IPNetwork ipnetwork = null;
  205. IPNetwork.InternalParse(false, ipaddress, netmask, out ipnetwork);
  206. return ipnetwork;
  207. }
  208. /// <summary>
  209. /// 192.168.0.1/24
  210. /// 192.168.0.1 255.255.255.0
  211. ///
  212. /// Network : 192.168.0.0
  213. /// Netmask : 255.255.255.0
  214. /// Cidr : 24
  215. /// Start : 192.168.0.1
  216. /// End : 192.168.0.254
  217. /// Broadcast : 192.168.0.255
  218. /// </summary>
  219. /// <param name="network"></param>
  220. /// <returns></returns>
  221. public static IPNetwork Parse(string network)
  222. {
  223. IPNetwork ipnetwork = null;
  224. IPNetwork.InternalParse(false, network, out ipnetwork);
  225. return ipnetwork;
  226. }
  227. #endregion
  228. #region TryParse
  229. /// <summary>
  230. /// 192.168.168.100 - 255.255.255.0
  231. ///
  232. /// Network : 192.168.168.0
  233. /// Netmask : 255.255.255.0
  234. /// Cidr : 24
  235. /// Start : 192.168.168.1
  236. /// End : 192.168.168.254
  237. /// Broadcast : 192.168.168.255
  238. /// </summary>
  239. /// <param name="ipaddress"></param>
  240. /// <param name="netmask"></param>
  241. /// <returns></returns>
  242. public static bool TryParse(string ipaddress, string netmask, out IPNetwork ipnetwork)
  243. {
  244. IPNetwork ipnetwork2 = null;
  245. IPNetwork.InternalParse(true, ipaddress, netmask, out ipnetwork2);
  246. bool parsed = (ipnetwork2 != null);
  247. ipnetwork = ipnetwork2;
  248. return parsed;
  249. }
  250. /// <summary>
  251. /// 192.168.168.100/24
  252. ///
  253. /// Network : 192.168.168.0
  254. /// Netmask : 255.255.255.0
  255. /// Cidr : 24
  256. /// Start : 192.168.168.1
  257. /// End : 192.168.168.254
  258. /// Broadcast : 192.168.168.255
  259. /// </summary>
  260. /// <param name="ipaddress"></param>
  261. /// <param name="cidr"></param>
  262. /// <returns></returns>
  263. public static bool TryParse(string ipaddress, byte cidr, out IPNetwork ipnetwork)
  264. {
  265. IPNetwork ipnetwork2 = null;
  266. IPNetwork.InternalParse(true, ipaddress, cidr, out ipnetwork2);
  267. bool parsed = (ipnetwork2 != null);
  268. ipnetwork = ipnetwork2;
  269. return parsed;
  270. }
  271. /// <summary>
  272. /// 192.168.0.1/24
  273. /// 192.168.0.1 255.255.255.0
  274. ///
  275. /// Network : 192.168.0.0
  276. /// Netmask : 255.255.255.0
  277. /// Cidr : 24
  278. /// Start : 192.168.0.1
  279. /// End : 192.168.0.254
  280. /// Broadcast : 192.168.0.255
  281. /// </summary>
  282. /// <param name="network"></param>
  283. /// <param name="ipnetwork"></param>
  284. /// <returns></returns>
  285. public static bool TryParse(string network, out IPNetwork ipnetwork)
  286. {
  287. IPNetwork ipnetwork2 = null;
  288. IPNetwork.InternalParse(true, network, out ipnetwork2);
  289. bool parsed = (ipnetwork2 != null);
  290. ipnetwork = ipnetwork2;
  291. return parsed;
  292. }
  293. /// <summary>
  294. /// 192.168.0.1/24
  295. /// 192.168.0.1 255.255.255.0
  296. ///
  297. /// Network : 192.168.0.0
  298. /// Netmask : 255.255.255.0
  299. /// Cidr : 24
  300. /// Start : 192.168.0.1
  301. /// End : 192.168.0.254
  302. /// Broadcast : 192.168.0.255
  303. /// </summary>
  304. /// <param name="ipaddress"></param>
  305. /// <param name="netmask"></param>
  306. /// <param name="ipnetwork"></param>
  307. /// <returns></returns>
  308. public static bool TryParse(IPAddress ipaddress, IPAddress netmask, out IPNetwork ipnetwork)
  309. {
  310. IPNetwork ipnetwork2 = null;
  311. IPNetwork.InternalParse(true, ipaddress, netmask, out ipnetwork2);
  312. bool parsed = (ipnetwork2 != null);
  313. ipnetwork = ipnetwork2;
  314. return parsed;
  315. }
  316. #endregion
  317. #region InternalParse
  318. /// <summary>
  319. /// 192.168.168.100 - 255.255.255.0
  320. ///
  321. /// Network : 192.168.168.0
  322. /// Netmask : 255.255.255.0
  323. /// Cidr : 24
  324. /// Start : 192.168.168.1
  325. /// End : 192.168.168.254
  326. /// Broadcast : 192.168.168.255
  327. /// </summary>
  328. /// <param name="ipaddress"></param>
  329. /// <param name="netmask"></param>
  330. /// <returns></returns>
  331. private static void InternalParse(bool tryParse, string ipaddress, string netmask, out IPNetwork ipnetwork)
  332. {
  333. if (string.IsNullOrEmpty(ipaddress))
  334. {
  335. if (tryParse == false)
  336. {
  337. throw new ArgumentNullException(nameof(ipaddress));
  338. }
  339. ipnetwork = null;
  340. return;
  341. }
  342. if (string.IsNullOrEmpty(netmask))
  343. {
  344. if (tryParse == false)
  345. {
  346. throw new ArgumentNullException(nameof(netmask));
  347. }
  348. ipnetwork = null;
  349. return;
  350. }
  351. IPAddress ip = null;
  352. bool ipaddressParsed = IPAddress.TryParse(ipaddress, out ip);
  353. if (ipaddressParsed == false)
  354. {
  355. if (tryParse == false)
  356. {
  357. throw new ArgumentException("ipaddress");
  358. }
  359. ipnetwork = null;
  360. return;
  361. }
  362. IPAddress mask = null;
  363. bool netmaskParsed = IPAddress.TryParse(netmask, out mask);
  364. if (netmaskParsed == false)
  365. {
  366. if (tryParse == false)
  367. {
  368. throw new ArgumentException("netmask");
  369. }
  370. ipnetwork = null;
  371. return;
  372. }
  373. IPNetwork.InternalParse(tryParse, ip, mask, out ipnetwork);
  374. }
  375. private static void InternalParse(bool tryParse, string network, out IPNetwork ipnetwork)
  376. {
  377. if (string.IsNullOrEmpty(network))
  378. {
  379. if (tryParse == false)
  380. {
  381. throw new ArgumentNullException(nameof(network));
  382. }
  383. ipnetwork = null;
  384. return;
  385. }
  386. network = Regex.Replace(network, @"[^0-9a-fA-F\.\/\s\:]+", "");
  387. network = Regex.Replace(network, @"\s{2,}", " ");
  388. network = network.Trim();
  389. string[] args = network.Split(new char[] { ' ', '/' });
  390. byte cidr = 0;
  391. if (args.Length == 1)
  392. {
  393. if (IPNetwork.TryGuessCidr(args[0], out cidr))
  394. {
  395. IPNetwork.InternalParse(tryParse, args[0], cidr, out ipnetwork);
  396. return;
  397. }
  398. if (tryParse == false)
  399. {
  400. throw new ArgumentException("network");
  401. }
  402. ipnetwork = null;
  403. return;
  404. }
  405. if (byte.TryParse(args[1], out cidr))
  406. {
  407. IPNetwork.InternalParse(tryParse, args[0], cidr, out ipnetwork);
  408. return;
  409. }
  410. IPNetwork.InternalParse(tryParse, args[0], args[1], out ipnetwork);
  411. return;
  412. }
  413. /// <summary>
  414. /// 192.168.168.100 255.255.255.0
  415. ///
  416. /// Network : 192.168.168.0
  417. /// Netmask : 255.255.255.0
  418. /// Cidr : 24
  419. /// Start : 192.168.168.1
  420. /// End : 192.168.168.254
  421. /// Broadcast : 192.168.168.255
  422. /// </summary>
  423. /// <param name="ipaddress"></param>
  424. /// <param name="netmask"></param>
  425. /// <returns></returns>
  426. private static void InternalParse(bool tryParse, IPAddress ipaddress, IPAddress netmask, out IPNetwork ipnetwork)
  427. {
  428. if (ipaddress == null)
  429. {
  430. if (tryParse == false)
  431. {
  432. throw new ArgumentNullException(nameof(ipaddress));
  433. }
  434. ipnetwork = null;
  435. return;
  436. }
  437. if (netmask == null)
  438. {
  439. if (tryParse == false)
  440. {
  441. throw new ArgumentNullException(nameof(netmask));
  442. }
  443. ipnetwork = null;
  444. return;
  445. }
  446. var uintIpAddress = IPNetwork.ToBigInteger(ipaddress);
  447. bool parsed = IPNetwork.TryToCidr(netmask, out var cidr2);
  448. if (parsed == false)
  449. {
  450. if (tryParse == false)
  451. {
  452. throw new ArgumentException("netmask");
  453. }
  454. ipnetwork = null;
  455. return;
  456. }
  457. byte cidr = (byte)cidr2;
  458. var ipnet = new IPNetwork(uintIpAddress, ipaddress.AddressFamily, cidr);
  459. ipnetwork = ipnet;
  460. return;
  461. }
  462. /// <summary>
  463. /// 192.168.168.100/24
  464. ///
  465. /// Network : 192.168.168.0
  466. /// Netmask : 255.255.255.0
  467. /// Cidr : 24
  468. /// Start : 192.168.168.1
  469. /// End : 192.168.168.254
  470. /// Broadcast : 192.168.168.255
  471. /// </summary>
  472. /// <param name="ipaddress"></param>
  473. /// <param name="cidr"></param>
  474. /// <returns></returns>
  475. private static void InternalParse(bool tryParse, string ipaddress, byte cidr, out IPNetwork ipnetwork)
  476. {
  477. if (string.IsNullOrEmpty(ipaddress))
  478. {
  479. if (tryParse == false)
  480. {
  481. throw new ArgumentNullException(nameof(ipaddress));
  482. }
  483. ipnetwork = null;
  484. return;
  485. }
  486. IPAddress ip = null;
  487. bool ipaddressParsed = IPAddress.TryParse(ipaddress, out ip);
  488. if (ipaddressParsed == false)
  489. {
  490. if (tryParse == false)
  491. {
  492. throw new ArgumentException("ipaddress");
  493. }
  494. ipnetwork = null;
  495. return;
  496. }
  497. IPAddress mask = null;
  498. bool parsedNetmask = IPNetwork.TryToNetmask(cidr, ip.AddressFamily, out mask);
  499. if (parsedNetmask == false)
  500. {
  501. if (tryParse == false)
  502. {
  503. throw new ArgumentException("cidr");
  504. }
  505. ipnetwork = null;
  506. return;
  507. }
  508. IPNetwork.InternalParse(tryParse, ip, mask, out ipnetwork);
  509. }
  510. #endregion
  511. #region converters
  512. #region ToUint
  513. /// <summary>
  514. /// Convert an ipadress to decimal
  515. /// 0.0.0.0 -> 0
  516. /// 0.0.1.0 -> 256
  517. /// </summary>
  518. /// <param name="ipaddress"></param>
  519. /// <returns></returns>
  520. public static BigInteger ToBigInteger(IPAddress ipaddress)
  521. {
  522. IPNetwork.InternalToBigInteger(false, ipaddress, out var uintIpAddress);
  523. return (BigInteger)uintIpAddress;
  524. }
  525. /// <summary>
  526. /// Convert an ipadress to decimal
  527. /// 0.0.0.0 -> 0
  528. /// 0.0.1.0 -> 256
  529. /// </summary>
  530. /// <param name="ipaddress"></param>
  531. /// <returns></returns>
  532. public static bool TryToBigInteger(IPAddress ipaddress, out BigInteger? uintIpAddress)
  533. {
  534. IPNetwork.InternalToBigInteger(true, ipaddress, out var uintIpAddress2);
  535. bool parsed = (uintIpAddress2 != null);
  536. uintIpAddress = uintIpAddress2;
  537. return parsed;
  538. }
  539. #if TRAVISCI
  540. public
  541. #else
  542. internal
  543. #endif
  544. static void InternalToBigInteger(bool tryParse, IPAddress ipaddress, out BigInteger? uintIpAddress)
  545. {
  546. if (ipaddress == null)
  547. {
  548. if (tryParse == false)
  549. {
  550. throw new ArgumentNullException(nameof(ipaddress));
  551. }
  552. uintIpAddress = null;
  553. return;
  554. }
  555. byte[] bytes = ipaddress.GetAddressBytes();
  556. /// 20180217 lduchosal
  557. /// code impossible to reach, GetAddressBytes returns either 4 or 16 bytes length addresses
  558. /// if (bytes.Length != 4 && bytes.Length != 16) {
  559. /// if (tryParse == false) {
  560. /// throw new ArgumentException("bytes");
  561. /// }
  562. /// uintIpAddress = null;
  563. /// return;
  564. /// }
  565. Array.Reverse(bytes);
  566. var unsigned = new List<byte>(bytes);
  567. unsigned.Add(0);
  568. uintIpAddress = new BigInteger(unsigned.ToArray());
  569. return;
  570. }
  571. /// <summary>
  572. /// Convert a cidr to BigInteger netmask
  573. /// </summary>
  574. /// <param name="cidr"></param>
  575. /// <returns></returns>
  576. public static BigInteger ToUint(byte cidr, AddressFamily family)
  577. {
  578. IPNetwork.InternalToBigInteger(false, cidr, family, out var uintNetmask);
  579. return (BigInteger)uintNetmask;
  580. }
  581. /// <summary>
  582. /// Convert a cidr to uint netmask
  583. /// </summary>
  584. /// <param name="cidr"></param>
  585. /// <returns></returns>
  586. public static bool TryToUint(byte cidr, AddressFamily family, out BigInteger? uintNetmask)
  587. {
  588. IPNetwork.InternalToBigInteger(true, cidr, family, out var uintNetmask2);
  589. bool parsed = (uintNetmask2 != null);
  590. uintNetmask = uintNetmask2;
  591. return parsed;
  592. }
  593. /// <summary>
  594. /// Convert a cidr to uint netmask
  595. /// </summary>
  596. /// <param name="cidr"></param>
  597. /// <returns></returns>
  598. #if TRAVISCI
  599. public
  600. #else
  601. internal
  602. #endif
  603. static void InternalToBigInteger(bool tryParse, byte cidr, AddressFamily family, out BigInteger? uintNetmask)
  604. {
  605. if (family == AddressFamily.InterNetwork && cidr > 32)
  606. {
  607. if (tryParse == false)
  608. {
  609. throw new ArgumentOutOfRangeException(nameof(cidr));
  610. }
  611. uintNetmask = null;
  612. return;
  613. }
  614. if (family == AddressFamily.InterNetworkV6 && cidr > 128)
  615. {
  616. if (tryParse == false)
  617. {
  618. throw new ArgumentOutOfRangeException(nameof(cidr));
  619. }
  620. uintNetmask = null;
  621. return;
  622. }
  623. if (family != AddressFamily.InterNetwork
  624. && family != AddressFamily.InterNetworkV6)
  625. {
  626. if (tryParse == false)
  627. {
  628. throw new NotSupportedException(family.ToString());
  629. }
  630. uintNetmask = null;
  631. return;
  632. }
  633. if (family == AddressFamily.InterNetwork)
  634. {
  635. uintNetmask = cidr == 0 ? 0 : 0xffffffff << (32 - cidr);
  636. return;
  637. }
  638. var mask = new BigInteger(new byte[] {
  639. 0xff, 0xff, 0xff, 0xff,
  640. 0xff, 0xff, 0xff, 0xff,
  641. 0xff, 0xff, 0xff, 0xff,
  642. 0xff, 0xff, 0xff, 0xff,
  643. 0x00
  644. });
  645. var masked = cidr == 0 ? 0 : mask << (128 - cidr);
  646. byte[] m = masked.ToByteArray();
  647. byte[] bmask = new byte[17];
  648. int copy = m.Length > 16 ? 16 : m.Length;
  649. Array.Copy(m, 0, bmask, 0, copy);
  650. uintNetmask = new BigInteger(bmask);
  651. }
  652. #endregion
  653. #region ToCidr
  654. /// <summary>
  655. /// Convert netmask to CIDR
  656. /// 255.255.255.0 -> 24
  657. /// 255.255.0.0 -> 16
  658. /// 255.0.0.0 -> 8
  659. /// </summary>
  660. /// <param name="netmask"></param>
  661. /// <returns></returns>
  662. private static void InternalToCidr(bool tryParse, BigInteger netmask, AddressFamily family, out byte? cidr)
  663. {
  664. if (!IPNetwork.InternalValidNetmask(netmask, family))
  665. {
  666. if (tryParse == false)
  667. {
  668. throw new ArgumentException("netmask");
  669. }
  670. cidr = null;
  671. return;
  672. }
  673. byte cidr2 = IPNetwork.BitsSet(netmask, family);
  674. cidr = cidr2;
  675. return;
  676. }
  677. /// <summary>
  678. /// Convert netmask to CIDR
  679. /// 255.255.255.0 -> 24
  680. /// 255.255.0.0 -> 16
  681. /// 255.0.0.0 -> 8
  682. /// </summary>
  683. /// <param name="netmask"></param>
  684. /// <returns></returns>
  685. public static byte ToCidr(IPAddress netmask)
  686. {
  687. IPNetwork.InternalToCidr(false, netmask, out var cidr);
  688. return (byte)cidr;
  689. }
  690. /// <summary>
  691. /// Convert netmask to CIDR
  692. /// 255.255.255.0 -> 24
  693. /// 255.255.0.0 -> 16
  694. /// 255.0.0.0 -> 8
  695. /// </summary>
  696. /// <param name="netmask"></param>
  697. /// <returns></returns>
  698. public static bool TryToCidr(IPAddress netmask, out byte? cidr)
  699. {
  700. IPNetwork.InternalToCidr(true, netmask, out var cidr2);
  701. bool parsed = (cidr2 != null);
  702. cidr = cidr2;
  703. return parsed;
  704. }
  705. private static void InternalToCidr(bool tryParse, IPAddress netmask, out byte? cidr)
  706. {
  707. if (netmask == null)
  708. {
  709. if (tryParse == false)
  710. {
  711. throw new ArgumentNullException(nameof(netmask));
  712. }
  713. cidr = null;
  714. return;
  715. }
  716. bool parsed = IPNetwork.TryToBigInteger(netmask, out var uintNetmask2);
  717. /// 20180217 lduchosal
  718. /// impossible to reach code.
  719. /// if (parsed == false) {
  720. /// if (tryParse == false) {
  721. /// throw new ArgumentException("netmask");
  722. /// }
  723. /// cidr = null;
  724. /// return;
  725. /// }
  726. var uintNetmask = (BigInteger)uintNetmask2;
  727. IPNetwork.InternalToCidr(tryParse, uintNetmask, netmask.AddressFamily, out var cidr2);
  728. cidr = cidr2;
  729. return;
  730. }
  731. #endregion
  732. #region ToNetmask
  733. /// <summary>
  734. /// Convert CIDR to netmask
  735. /// 24 -> 255.255.255.0
  736. /// 16 -> 255.255.0.0
  737. /// 8 -> 255.0.0.0
  738. /// </summary>
  739. /// <see cref="http://snipplr.com/view/15557/cidr-class-for-ipv4/"/>
  740. /// <param name="cidr"></param>
  741. /// <returns></returns>
  742. public static IPAddress ToNetmask(byte cidr, AddressFamily family)
  743. {
  744. IPAddress netmask = null;
  745. IPNetwork.InternalToNetmask(false, cidr, family, out netmask);
  746. return netmask;
  747. }
  748. /// <summary>
  749. /// Convert CIDR to netmask
  750. /// 24 -> 255.255.255.0
  751. /// 16 -> 255.255.0.0
  752. /// 8 -> 255.0.0.0
  753. /// </summary>
  754. /// <see cref="http://snipplr.com/view/15557/cidr-class-for-ipv4/"/>
  755. /// <param name="cidr"></param>
  756. /// <returns></returns>
  757. public static bool TryToNetmask(byte cidr, AddressFamily family, out IPAddress netmask)
  758. {
  759. IPAddress netmask2 = null;
  760. IPNetwork.InternalToNetmask(true, cidr, family, out netmask2);
  761. bool parsed = (netmask2 != null);
  762. netmask = netmask2;
  763. return parsed;
  764. }
  765. #if TRAVISCI
  766. public
  767. #else
  768. internal
  769. #endif
  770. static void InternalToNetmask(bool tryParse, byte cidr, AddressFamily family, out IPAddress netmask)
  771. {
  772. if (family != AddressFamily.InterNetwork
  773. && family != AddressFamily.InterNetworkV6)
  774. {
  775. if (tryParse == false)
  776. {
  777. throw new ArgumentException("family");
  778. }
  779. netmask = null;
  780. return;
  781. }
  782. /// 20180217 lduchosal
  783. /// impossible to reach code, byte cannot be negative :
  784. ///
  785. /// if (cidr < 0) {
  786. /// if (tryParse == false) {
  787. /// throw new ArgumentOutOfRangeException("cidr");
  788. /// }
  789. /// netmask = null;
  790. /// return;
  791. /// }
  792. int maxCidr = family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
  793. if (cidr > maxCidr)
  794. {
  795. if (tryParse == false)
  796. {
  797. throw new ArgumentOutOfRangeException(nameof(cidr));
  798. }
  799. netmask = null;
  800. return;
  801. }
  802. var mask = IPNetwork.ToUint(cidr, family);
  803. var netmask2 = IPNetwork.ToIPAddress(mask, family);
  804. netmask = netmask2;
  805. return;
  806. }
  807. #endregion
  808. #endregion
  809. #region utils
  810. #region BitsSet
  811. /// <summary>
  812. /// Count bits set to 1 in netmask
  813. /// </summary>
  814. /// <see cref="http://stackoverflow.com/questions/109023/best-algorithm-to-count-the-number-of-set-bits-in-a-32-bit-integer"/>
  815. /// <param name="netmask"></param>
  816. /// <returns></returns>
  817. private static byte BitsSet(BigInteger netmask, AddressFamily family)
  818. {
  819. string s = netmask.ToBinaryString();
  820. return (byte)s.Replace("0", "")
  821. .ToCharArray()
  822. .Length;
  823. }
  824. /// <summary>
  825. /// Count bits set to 1 in netmask
  826. /// </summary>
  827. /// <param name="netmask"></param>
  828. /// <returns></returns>
  829. public static uint BitsSet(IPAddress netmask)
  830. {
  831. var uintNetmask = IPNetwork.ToBigInteger(netmask);
  832. uint bits = IPNetwork.BitsSet(uintNetmask, netmask.AddressFamily);
  833. return bits;
  834. }
  835. #endregion
  836. #region ValidNetmask
  837. /// <summary>
  838. /// return true if netmask is a valid netmask
  839. /// 255.255.255.0, 255.0.0.0, 255.255.240.0, ...
  840. /// </summary>
  841. /// <see cref="http://www.actionsnip.com/snippets/tomo_atlacatl/calculate-if-a-netmask-is-valid--as2-"/>
  842. /// <param name="netmask"></param>
  843. /// <returns></returns>
  844. public static bool ValidNetmask(IPAddress netmask)
  845. {
  846. if (netmask == null)
  847. {
  848. throw new ArgumentNullException(nameof(netmask));
  849. }
  850. var uintNetmask = IPNetwork.ToBigInteger(netmask);
  851. bool valid = IPNetwork.InternalValidNetmask(uintNetmask, netmask.AddressFamily);
  852. return valid;
  853. }
  854. #if TRAVISCI
  855. public
  856. #else
  857. internal
  858. #endif
  859. static bool InternalValidNetmask(BigInteger netmask, AddressFamily family)
  860. {
  861. if (family != AddressFamily.InterNetwork
  862. && family != AddressFamily.InterNetworkV6)
  863. {
  864. throw new ArgumentException("family");
  865. }
  866. var mask = family == AddressFamily.InterNetwork
  867. ? new BigInteger(0x0ffffffff)
  868. : new BigInteger(new byte[]{
  869. 0xff, 0xff, 0xff, 0xff,
  870. 0xff, 0xff, 0xff, 0xff,
  871. 0xff, 0xff, 0xff, 0xff,
  872. 0xff, 0xff, 0xff, 0xff,
  873. 0x00
  874. });
  875. var neg = ((~netmask) & (mask));
  876. bool isNetmask = ((neg + 1) & neg) == 0;
  877. return isNetmask;
  878. }
  879. #endregion
  880. #region ToIPAddress
  881. /// <summary>
  882. /// Transform a uint ipaddress into IPAddress object
  883. /// </summary>
  884. /// <param name="ipaddress"></param>
  885. /// <returns></returns>
  886. public static IPAddress ToIPAddress(BigInteger ipaddress, AddressFamily family)
  887. {
  888. int width = family == AddressFamily.InterNetwork ? 4 : 16;
  889. byte[] bytes = ipaddress.ToByteArray();
  890. byte[] bytes2 = new byte[width];
  891. int copy = bytes.Length > width ? width : bytes.Length;
  892. Array.Copy(bytes, 0, bytes2, 0, copy);
  893. Array.Reverse(bytes2);
  894. byte[] sized = Resize(bytes2, family);
  895. var ip = new IPAddress(sized);
  896. return ip;
  897. }
  898. #if TRAVISCI
  899. public
  900. #else
  901. internal
  902. #endif
  903. static byte[] Resize(byte[] bytes, AddressFamily family)
  904. {
  905. if (family != AddressFamily.InterNetwork
  906. && family != AddressFamily.InterNetworkV6)
  907. {
  908. throw new ArgumentException("family");
  909. }
  910. int width = family == AddressFamily.InterNetwork ? 4 : 16;
  911. if (bytes.Length > width)
  912. {
  913. throw new ArgumentException("bytes");
  914. }
  915. byte[] result = new byte[width];
  916. Array.Copy(bytes, 0, result, 0, bytes.Length);
  917. return result;
  918. }
  919. #endregion
  920. #endregion
  921. #region contains
  922. /// <summary>
  923. /// return true if ipaddress is contained in network
  924. /// </summary>
  925. /// <param name="ipaddress"></param>
  926. /// <returns></returns>
  927. public bool Contains(IPAddress ipaddress)
  928. {
  929. if (ipaddress == null)
  930. {
  931. throw new ArgumentNullException(nameof(ipaddress));
  932. }
  933. if (AddressFamily != ipaddress.AddressFamily)
  934. {
  935. return false;
  936. }
  937. var uintNetwork = _network;
  938. var uintBroadcast = _broadcast;
  939. var uintAddress = IPNetwork.ToBigInteger(ipaddress);
  940. bool contains = (uintAddress >= uintNetwork
  941. && uintAddress <= uintBroadcast);
  942. return contains;
  943. }
  944. /// <summary>
  945. /// return true is network2 is fully contained in network
  946. /// </summary>
  947. /// <param name="network2"></param>
  948. /// <returns></returns>
  949. public bool Contains(IPNetwork network2)
  950. {
  951. if (network2 == null)
  952. {
  953. throw new ArgumentNullException(nameof(network2));
  954. }
  955. var uintNetwork = _network;
  956. var uintBroadcast = _broadcast;
  957. var uintFirst = network2._network;
  958. var uintLast = network2._broadcast;
  959. bool contains = (uintFirst >= uintNetwork
  960. && uintLast <= uintBroadcast);
  961. return contains;
  962. }
  963. #endregion
  964. #region overlap
  965. /// <summary>
  966. /// return true is network2 overlap network
  967. /// </summary>
  968. /// <param name="network2"></param>
  969. /// <returns></returns>
  970. public bool Overlap(IPNetwork network2)
  971. {
  972. if (network2 == null)
  973. {
  974. throw new ArgumentNullException(nameof(network2));
  975. }
  976. var uintNetwork = _network;
  977. var uintBroadcast = _broadcast;
  978. var uintFirst = network2._network;
  979. var uintLast = network2._broadcast;
  980. bool overlap =
  981. (uintFirst >= uintNetwork && uintFirst <= uintBroadcast)
  982. || (uintLast >= uintNetwork && uintLast <= uintBroadcast)
  983. || (uintFirst <= uintNetwork && uintLast >= uintBroadcast)
  984. || (uintFirst >= uintNetwork && uintLast <= uintBroadcast);
  985. return overlap;
  986. }
  987. #endregion
  988. #region ToString
  989. public override string ToString()
  990. {
  991. return string.Format("{0}/{1}", this.Network, this.Cidr);
  992. }
  993. #endregion
  994. #region IANA block
  995. private static readonly Lazy<IPNetwork> _iana_ablock_reserved = new Lazy<IPNetwork>(() => IPNetwork.Parse("10.0.0.0/8"));
  996. private static readonly Lazy<IPNetwork> _iana_bblock_reserved = new Lazy<IPNetwork>(() => IPNetwork.Parse("172.16.0.0/12"));
  997. private static readonly Lazy<IPNetwork> _iana_cblock_reserved = new Lazy<IPNetwork>(() => IPNetwork.Parse("192.168.0.0/16"));
  998. /// <summary>
  999. /// 10.0.0.0/8
  1000. /// </summary>
  1001. /// <returns></returns>
  1002. public static IPNetwork IANA_ABLK_RESERVED1 => _iana_ablock_reserved.Value;
  1003. /// <summary>
  1004. /// 172.12.0.0/12
  1005. /// </summary>
  1006. /// <returns></returns>
  1007. public static IPNetwork IANA_BBLK_RESERVED1 => _iana_bblock_reserved.Value;
  1008. /// <summary>
  1009. /// 192.168.0.0/16
  1010. /// </summary>
  1011. /// <returns></returns>
  1012. public static IPNetwork IANA_CBLK_RESERVED1 => _iana_cblock_reserved.Value;
  1013. /// <summary>
  1014. /// return true if ipaddress is contained in
  1015. /// IANA_ABLK_RESERVED1, IANA_BBLK_RESERVED1, IANA_CBLK_RESERVED1
  1016. /// </summary>
  1017. /// <param name="ipaddress"></param>
  1018. /// <returns></returns>
  1019. public static bool IsIANAReserved(IPAddress ipaddress)
  1020. {
  1021. if (ipaddress == null)
  1022. {
  1023. throw new ArgumentNullException(nameof(ipaddress));
  1024. }
  1025. return IPNetwork.IANA_ABLK_RESERVED1.Contains(ipaddress)
  1026. || IPNetwork.IANA_BBLK_RESERVED1.Contains(ipaddress)
  1027. || IPNetwork.IANA_CBLK_RESERVED1.Contains(ipaddress);
  1028. }
  1029. /// <summary>
  1030. /// return true if ipnetwork is contained in
  1031. /// IANA_ABLK_RESERVED1, IANA_BBLK_RESERVED1, IANA_CBLK_RESERVED1
  1032. /// </summary>
  1033. /// <returns></returns>
  1034. public bool IsIANAReserved()
  1035. {
  1036. return IPNetwork.IANA_ABLK_RESERVED1.Contains(this)
  1037. || IPNetwork.IANA_BBLK_RESERVED1.Contains(this)
  1038. || IPNetwork.IANA_CBLK_RESERVED1.Contains(this);
  1039. }
  1040. #endregion
  1041. #region Subnet
  1042. /// <summary>
  1043. /// Subnet a network into multiple nets of cidr mask
  1044. /// Subnet 192.168.0.0/24 into cidr 25 gives 192.168.0.0/25, 192.168.0.128/25
  1045. /// Subnet 10.0.0.0/8 into cidr 9 gives 10.0.0.0/9, 10.128.0.0/9
  1046. /// </summary>
  1047. /// <param name="cidr"></param>
  1048. /// <returns></returns>
  1049. public IPNetworkCollection Subnet(byte cidr)
  1050. {
  1051. IPNetworkCollection ipnetworkCollection = null;
  1052. IPNetwork.InternalSubnet(false, this, cidr, out ipnetworkCollection);
  1053. return ipnetworkCollection;
  1054. }
  1055. /// <summary>
  1056. /// Subnet a network into multiple nets of cidr mask
  1057. /// Subnet 192.168.0.0/24 into cidr 25 gives 192.168.0.0/25, 192.168.0.128/25
  1058. /// Subnet 10.0.0.0/8 into cidr 9 gives 10.0.0.0/9, 10.128.0.0/9
  1059. /// </summary>
  1060. /// <param name="cidr"></param>
  1061. /// <returns></returns>
  1062. public bool TrySubnet(byte cidr, out IPNetworkCollection ipnetworkCollection)
  1063. {
  1064. IPNetworkCollection inc = null;
  1065. IPNetwork.InternalSubnet(true, this, cidr, out inc);
  1066. if (inc == null)
  1067. {
  1068. ipnetworkCollection = null;
  1069. return false;
  1070. }
  1071. ipnetworkCollection = inc;
  1072. return true;
  1073. }
  1074. #if TRAVISCI
  1075. public
  1076. #else
  1077. internal
  1078. #endif
  1079. static void InternalSubnet(bool trySubnet, IPNetwork network, byte cidr, out IPNetworkCollection ipnetworkCollection)
  1080. {
  1081. if (network == null)
  1082. {
  1083. if (trySubnet == false)
  1084. {
  1085. throw new ArgumentNullException(nameof(network));
  1086. }
  1087. ipnetworkCollection = null;
  1088. return;
  1089. }
  1090. int maxCidr = network._family == System.Net.Sockets.AddressFamily.InterNetwork ? 32 : 128;
  1091. if (cidr > maxCidr)
  1092. {
  1093. if (trySubnet == false)
  1094. {
  1095. throw new ArgumentOutOfRangeException(nameof(cidr));
  1096. }
  1097. ipnetworkCollection = null;
  1098. return;
  1099. }
  1100. if (cidr < network.Cidr)
  1101. {
  1102. if (trySubnet == false)
  1103. {
  1104. throw new ArgumentException("cidr");
  1105. }
  1106. ipnetworkCollection = null;
  1107. return;
  1108. }
  1109. ipnetworkCollection = new IPNetworkCollection(network, cidr);
  1110. return;
  1111. }
  1112. #endregion
  1113. #region Supernet
  1114. /// <summary>
  1115. /// Supernet two consecutive cidr equal subnet into a single one
  1116. /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
  1117. /// 10.1.0.0/16 + 10.0.0.0/16 = 10.0.0.0/15
  1118. /// 192.168.0.0/24 + 192.168.0.0/25 = 192.168.0.0/24
  1119. /// </summary>
  1120. /// <param name="network2"></param>
  1121. /// <returns></returns>
  1122. public IPNetwork Supernet(IPNetwork network2)
  1123. {
  1124. IPNetwork supernet = null;
  1125. IPNetwork.InternalSupernet(false, this, network2, out supernet);
  1126. return supernet;
  1127. }
  1128. /// <summary>
  1129. /// Try to supernet two consecutive cidr equal subnet into a single one
  1130. /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
  1131. /// 10.1.0.0/16 + 10.0.0.0/16 = 10.0.0.0/15
  1132. /// 192.168.0.0/24 + 192.168.0.0/25 = 192.168.0.0/24
  1133. /// </summary>
  1134. /// <param name="network2"></param>
  1135. /// <returns></returns>
  1136. public bool TrySupernet(IPNetwork network2, out IPNetwork supernet)
  1137. {
  1138. IPNetwork outSupernet = null;
  1139. IPNetwork.InternalSupernet(true, this, network2, out outSupernet);
  1140. bool parsed = (outSupernet != null);
  1141. supernet = outSupernet;
  1142. return parsed;
  1143. }
  1144. #if TRAVISCI
  1145. public
  1146. #else
  1147. internal
  1148. #endif
  1149. static void InternalSupernet(bool trySupernet, IPNetwork network1, IPNetwork network2, out IPNetwork supernet)
  1150. {
  1151. if (network1 == null)
  1152. {
  1153. if (trySupernet == false)
  1154. {
  1155. throw new ArgumentNullException(nameof(network1));
  1156. }
  1157. supernet = null;
  1158. return;
  1159. }
  1160. if (network2 == null)
  1161. {
  1162. if (trySupernet == false)
  1163. {
  1164. throw new ArgumentNullException(nameof(network2));
  1165. }
  1166. supernet = null;
  1167. return;
  1168. }
  1169. if (network1.Contains(network2))
  1170. {
  1171. supernet = new IPNetwork(network1._network, network1._family, network1.Cidr);
  1172. return;
  1173. }
  1174. if (network2.Contains(network1))
  1175. {
  1176. supernet = new IPNetwork(network2._network, network2._family, network2.Cidr);
  1177. return;
  1178. }
  1179. if (network1._cidr != network2._cidr)
  1180. {
  1181. if (trySupernet == false)
  1182. {
  1183. throw new ArgumentException("cidr");
  1184. }
  1185. supernet = null;
  1186. return;
  1187. }
  1188. var first = (network1._network < network2._network) ? network1 : network2;
  1189. var last = (network1._network > network2._network) ? network1 : network2;
  1190. /// Starting from here :
  1191. /// network1 and network2 have the same cidr,
  1192. /// network1 does not contain network2,
  1193. /// network2 does not contain network1,
  1194. /// first is the lower subnet
  1195. /// last is the higher subnet
  1196. if ((first._broadcast + 1) != last._network)
  1197. {
  1198. if (trySupernet == false)
  1199. {
  1200. throw new ArgumentOutOfRangeException(nameof(trySupernet), "TrySupernet was false while the first and last networks are not adjacent.");
  1201. }
  1202. supernet = null;
  1203. return;
  1204. }
  1205. var uintSupernet = first._network;
  1206. byte cidrSupernet = (byte)(first._cidr - 1);
  1207. var networkSupernet = new IPNetwork(uintSupernet, first._family, cidrSupernet);
  1208. if (networkSupernet._network != first._network)
  1209. {
  1210. if (trySupernet == false)
  1211. {
  1212. throw new ArgumentException("network");
  1213. }
  1214. supernet = null;
  1215. return;
  1216. }
  1217. supernet = networkSupernet;
  1218. return;
  1219. }
  1220. #endregion
  1221. #region GetHashCode
  1222. public override int GetHashCode()
  1223. {
  1224. return string.Format("{0}|{1}|{2}",
  1225. this._ipaddress.GetHashCode(),
  1226. this._network.GetHashCode(),
  1227. this._cidr.GetHashCode()).GetHashCode();
  1228. }
  1229. #endregion
  1230. #region SupernetArray
  1231. /// <summary>
  1232. /// Supernet a list of subnet
  1233. /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
  1234. /// 192.168.0.0/24 + 192.168.1.0/24 + 192.168.2.0/24 + 192.168.3.0/24 = 192.168.0.0/22
  1235. /// </summary>
  1236. /// <param name="ipnetworks">The IP networks</param>
  1237. /// <returns></returns>
  1238. public static IPNetwork[] Supernet(IPNetwork[] ipnetworks)
  1239. {
  1240. InternalSupernet(false, ipnetworks, out var supernet);
  1241. return supernet;
  1242. }
  1243. /// <summary>
  1244. /// Supernet a list of subnet
  1245. /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
  1246. /// 192.168.0.0/24 + 192.168.1.0/24 + 192.168.2.0/24 + 192.168.3.0/24 = 192.168.0.0/22
  1247. /// </summary>
  1248. /// <param name="ipnetworks"></param>
  1249. /// <param name="supernet"></param>
  1250. /// <returns></returns>
  1251. public static bool TrySupernet(IPNetwork[] ipnetworks, out IPNetwork[] supernet)
  1252. {
  1253. bool supernetted = InternalSupernet(true, ipnetworks, out supernet);
  1254. return supernetted;
  1255. }
  1256. #if TRAVISCI
  1257. public
  1258. #else
  1259. internal
  1260. #endif
  1261. static bool InternalSupernet(bool trySupernet, IPNetwork[] ipnetworks, out IPNetwork[] supernet)
  1262. {
  1263. if (ipnetworks == null)
  1264. {
  1265. if (trySupernet == false)
  1266. {
  1267. throw new ArgumentNullException(nameof(ipnetworks));
  1268. }
  1269. supernet = null;
  1270. return false;
  1271. }
  1272. if (ipnetworks.Length <= 0)
  1273. {
  1274. supernet = new IPNetwork[0];
  1275. return true;
  1276. }
  1277. var supernetted = new List<IPNetwork>();
  1278. var ipns = IPNetwork.Array2List(ipnetworks);
  1279. var current = IPNetwork.List2Stack(ipns);
  1280. int previousCount = 0;
  1281. int currentCount = current.Count;
  1282. while (previousCount != currentCount)
  1283. {
  1284. supernetted.Clear();
  1285. while (current.Count > 1)
  1286. {
  1287. var ipn1 = current.Pop();
  1288. var ipn2 = current.Peek();
  1289. IPNetwork outNetwork = null;
  1290. bool success = ipn1.TrySupernet(ipn2, out outNetwork);
  1291. if (success)
  1292. {
  1293. current.Pop();
  1294. current.Push(outNetwork);
  1295. }
  1296. else
  1297. {
  1298. supernetted.Add(ipn1);
  1299. }
  1300. }
  1301. if (current.Count == 1)
  1302. {
  1303. supernetted.Add(current.Pop());
  1304. }
  1305. previousCount = currentCount;
  1306. currentCount = supernetted.Count;
  1307. current = IPNetwork.List2Stack(supernetted);
  1308. }
  1309. supernet = supernetted.ToArray();
  1310. return true;
  1311. }
  1312. private static Stack<IPNetwork> List2Stack(List<IPNetwork> list)
  1313. {
  1314. var stack = new Stack<IPNetwork>();
  1315. list.ForEach(new Action<IPNetwork>(
  1316. delegate (IPNetwork ipn)
  1317. {
  1318. stack.Push(ipn);
  1319. }
  1320. ));
  1321. return stack;
  1322. }
  1323. private static List<IPNetwork> Array2List(IPNetwork[] array)
  1324. {
  1325. var ipns = new List<IPNetwork>();
  1326. ipns.AddRange(array);
  1327. IPNetwork.RemoveNull(ipns);
  1328. ipns.Sort(new Comparison<IPNetwork>(
  1329. delegate (IPNetwork ipn1, IPNetwork ipn2)
  1330. {
  1331. int networkCompare = ipn1._network.CompareTo(ipn2._network);
  1332. if (networkCompare == 0)
  1333. {
  1334. int cidrCompare = ipn1._cidr.CompareTo(ipn2._cidr);
  1335. return cidrCompare;
  1336. }
  1337. return networkCompare;
  1338. }
  1339. ));
  1340. ipns.Reverse();
  1341. return ipns;
  1342. }
  1343. private static void RemoveNull(List<IPNetwork> ipns)
  1344. {
  1345. ipns.RemoveAll(new Predicate<IPNetwork>(
  1346. delegate (IPNetwork ipn)
  1347. {
  1348. if (ipn == null)
  1349. {
  1350. return true;
  1351. }
  1352. return false;
  1353. }
  1354. ));
  1355. }
  1356. #endregion
  1357. #region WideSubnet
  1358. public static IPNetwork WideSubnet(string start, string end)
  1359. {
  1360. if (string.IsNullOrEmpty(start))
  1361. {
  1362. throw new ArgumentNullException(nameof(start));
  1363. }
  1364. if (string.IsNullOrEmpty(end))
  1365. {
  1366. throw new ArgumentNullException(nameof(end));
  1367. }
  1368. if (!IPAddress.TryParse(start, out var startIP))
  1369. {
  1370. throw new ArgumentException("start");
  1371. }
  1372. if (!IPAddress.TryParse(end, out var endIP))
  1373. {
  1374. throw new ArgumentException("end");
  1375. }
  1376. if (startIP.AddressFamily != endIP.AddressFamily)
  1377. {
  1378. throw new NotSupportedException("MixedAddressFamily");
  1379. }
  1380. var ipnetwork = new IPNetwork(0, startIP.AddressFamily, 0);
  1381. for (byte cidr = 32; cidr >= 0; cidr--)
  1382. {
  1383. var wideSubnet = IPNetwork.Parse(start, cidr);
  1384. if (wideSubnet.Contains(endIP))
  1385. {
  1386. ipnetwork = wideSubnet;
  1387. break;
  1388. }
  1389. }
  1390. return ipnetwork;
  1391. }
  1392. public static bool TryWideSubnet(IPNetwork[] ipnetworks, out IPNetwork ipnetwork)
  1393. {
  1394. IPNetwork ipn = null;
  1395. IPNetwork.InternalWideSubnet(true, ipnetworks, out ipn);
  1396. if (ipn == null)
  1397. {
  1398. ipnetwork = null;
  1399. return false;
  1400. }
  1401. ipnetwork = ipn;
  1402. return true;
  1403. }
  1404. public static IPNetwork WideSubnet(IPNetwork[] ipnetworks)
  1405. {
  1406. IPNetwork ipn = null;
  1407. IPNetwork.InternalWideSubnet(false, ipnetworks, out ipn);
  1408. return ipn;
  1409. }
  1410. internal static void InternalWideSubnet(bool tryWide, IPNetwork[] ipnetworks, out IPNetwork ipnetwork)
  1411. {
  1412. if (ipnetworks == null)
  1413. {
  1414. if (tryWide == false)
  1415. {
  1416. throw new ArgumentNullException(nameof(ipnetworks));
  1417. }
  1418. ipnetwork = null;
  1419. return;
  1420. }
  1421. IPNetwork[] nnin = Array.FindAll(ipnetworks, new Predicate<IPNetwork>(
  1422. delegate (IPNetwork ipnet)
  1423. {
  1424. return ipnet != null;
  1425. }
  1426. ));
  1427. if (nnin.Length <= 0)
  1428. {
  1429. if (tryWide == false)
  1430. {
  1431. throw new ArgumentException("ipnetworks");
  1432. }
  1433. ipnetwork = null;
  1434. return;
  1435. }
  1436. if (nnin.Length == 1)
  1437. {
  1438. var ipn0 = nnin[0];
  1439. ipnetwork = ipn0;
  1440. return;
  1441. }
  1442. Array.Sort(nnin);
  1443. var nnin0 = nnin[0];
  1444. var uintNnin0 = nnin0._ipaddress;
  1445. var nninX = nnin[nnin.Length - 1];
  1446. var ipaddressX = nninX.Broadcast;
  1447. var family = ipnetworks[0]._family;
  1448. foreach (var ipnx in ipnetworks)
  1449. {
  1450. if (ipnx._family != family)
  1451. {
  1452. throw new ArgumentException("MixedAddressFamily");
  1453. }
  1454. }
  1455. var ipn = new IPNetwork(0, family, 0);
  1456. for (byte cidr = nnin0._cidr; cidr >= 0; cidr--)
  1457. {
  1458. var wideSubnet = new IPNetwork(uintNnin0, family, cidr);
  1459. if (wideSubnet.Contains(ipaddressX))
  1460. {
  1461. ipn = wideSubnet;
  1462. break;
  1463. }
  1464. }
  1465. ipnetwork = ipn;
  1466. return;
  1467. }
  1468. #endregion
  1469. #region Print
  1470. /// <summary>
  1471. /// Print an ipnetwork in a clear representation string
  1472. /// </summary>
  1473. /// <returns></returns>
  1474. public string Print()
  1475. {
  1476. var sw = new StringWriter();
  1477. sw.WriteLine("IPNetwork : {0}", ToString());
  1478. sw.WriteLine("Network : {0}", Network);
  1479. sw.WriteLine("Netmask : {0}", Netmask);
  1480. sw.WriteLine("Cidr : {0}", Cidr);
  1481. sw.WriteLine("Broadcast : {0}", Broadcast);
  1482. sw.WriteLine("FirstUsable : {0}", FirstUsable);
  1483. sw.WriteLine("LastUsable : {0}", LastUsable);
  1484. sw.WriteLine("Usable : {0}", Usable);
  1485. return sw.ToString();
  1486. }
  1487. #endregion
  1488. #region TryGuessCidr
  1489. /// <summary>
  1490. ///
  1491. /// Class Leading bits Default netmask
  1492. /// A (CIDR /8) 00 255.0.0.0
  1493. /// A (CIDR /8) 01 255.0.0.0
  1494. /// B (CIDR /16) 10 255.255.0.0
  1495. /// C (CIDR /24) 11 255.255.255.0
  1496. ///
  1497. /// </summary>
  1498. /// <param name="ip"></param>
  1499. /// <param name="cidr"></param>
  1500. /// <returns></returns>
  1501. public static bool TryGuessCidr(string ip, out byte cidr)
  1502. {
  1503. IPAddress ipaddress = null;
  1504. bool parsed = IPAddress.TryParse(string.Format("{0}", ip), out ipaddress);
  1505. if (parsed == false)
  1506. {
  1507. cidr = 0;
  1508. return false;
  1509. }
  1510. if (ipaddress.AddressFamily == AddressFamily.InterNetworkV6)
  1511. {
  1512. cidr = 64;
  1513. return true;
  1514. }
  1515. var uintIPAddress = IPNetwork.ToBigInteger(ipaddress);
  1516. uintIPAddress = uintIPAddress >> 29;
  1517. if (uintIPAddress <= 3)
  1518. {
  1519. cidr = 8;
  1520. return true;
  1521. }
  1522. else if (uintIPAddress <= 5)
  1523. {
  1524. cidr = 16;
  1525. return true;
  1526. }
  1527. else if (uintIPAddress <= 6)
  1528. {
  1529. cidr = 24;
  1530. return true;
  1531. }
  1532. cidr = 0;
  1533. return false;
  1534. }
  1535. /// <summary>
  1536. /// Try to parse cidr. Have to be >= 0 and <= 32 or 128
  1537. /// </summary>
  1538. /// <param name="sidr"></param>
  1539. /// <param name="cidr"></param>
  1540. /// <returns></returns>
  1541. public static bool TryParseCidr(string sidr, AddressFamily family, out byte? cidr)
  1542. {
  1543. byte b = 0;
  1544. if (!byte.TryParse(sidr, out b))
  1545. {
  1546. cidr = null;
  1547. return false;
  1548. }
  1549. IPAddress netmask = null;
  1550. if (!IPNetwork.TryToNetmask(b, family, out netmask))
  1551. {
  1552. cidr = null;
  1553. return false;
  1554. }
  1555. cidr = b;
  1556. return true;
  1557. }
  1558. #endregion
  1559. #region ListIPAddress
  1560. public IPAddressCollection ListIPAddress()
  1561. {
  1562. return new IPAddressCollection(this);
  1563. }
  1564. #endregion
  1565. /**
  1566. * Need a better way to do it
  1567. *
  1568. #region TrySubstractNetwork
  1569. public static bool TrySubstractNetwork(IPNetwork[] ipnetworks, IPNetwork substract, out IEnumerable<IPNetwork> result) {
  1570. if (ipnetworks == null) {
  1571. result = null;
  1572. return false;
  1573. }
  1574. if (ipnetworks.Length <= 0) {
  1575. result = null;
  1576. return false;
  1577. }
  1578. if (substract == null) {
  1579. result = null;
  1580. return false;
  1581. }
  1582. var results = new List<IPNetwork>();
  1583. foreach (var ipn in ipnetworks) {
  1584. if (!Overlap(ipn, substract)) {
  1585. results.Add(ipn);
  1586. continue;
  1587. }
  1588. var collection = ipn.Subnet(substract.Cidr);
  1589. var rtemp = new List<IPNetwork>();
  1590. foreach(var subnet in collection) {
  1591. if (subnet != substract) {
  1592. rtemp.Add(subnet);
  1593. }
  1594. }
  1595. var supernets = Supernet(rtemp.ToArray());
  1596. results.AddRange(supernets);
  1597. }
  1598. result = results;
  1599. return true;
  1600. }
  1601. #endregion
  1602. * **/
  1603. #region IComparable<IPNetwork> Members
  1604. public static int Compare(IPNetwork left, IPNetwork right)
  1605. {
  1606. // two null IPNetworks are equal
  1607. if (ReferenceEquals(left, null) && ReferenceEquals(right, null)) return 0;
  1608. // two same IPNetworks are equal
  1609. if (ReferenceEquals(left, right)) return 0;
  1610. // null is always sorted first
  1611. if (ReferenceEquals(left, null)) return -1;
  1612. if (ReferenceEquals(right, null)) return 1;
  1613. // first test the network
  1614. var result = left._network.CompareTo(right._network);
  1615. if (result != 0) return result;
  1616. // then test the cidr
  1617. result = left._cidr.CompareTo(right._cidr);
  1618. return result;
  1619. }
  1620. public int CompareTo(IPNetwork other)
  1621. {
  1622. return Compare(this, other);
  1623. }
  1624. public int CompareTo(object obj)
  1625. {
  1626. // null is at less
  1627. if (obj == null) return 1;
  1628. // convert to a proper Cidr object
  1629. var other = obj as IPNetwork;
  1630. // type problem if null
  1631. if (other == null)
  1632. {
  1633. throw new ArgumentException(
  1634. "The supplied parameter is an invalid type. Please supply an IPNetwork type.",
  1635. nameof(obj));
  1636. }
  1637. // perform the comparision
  1638. return CompareTo(other);
  1639. }
  1640. #endregion
  1641. #region IEquatable<IPNetwork> Members
  1642. public static bool Equals(IPNetwork left, IPNetwork right)
  1643. {
  1644. return Compare(left, right) == 0;
  1645. }
  1646. public bool Equals(IPNetwork other)
  1647. {
  1648. return Equals(this, other);
  1649. }
  1650. public override bool Equals(object obj)
  1651. {
  1652. return Equals(this, obj as IPNetwork);
  1653. }
  1654. #endregion
  1655. #region Operators
  1656. public static bool operator ==(IPNetwork left, IPNetwork right)
  1657. {
  1658. return Equals(left, right);
  1659. }
  1660. public static bool operator !=(IPNetwork left, IPNetwork right)
  1661. {
  1662. return !Equals(left, right);
  1663. }
  1664. public static bool operator <(IPNetwork left, IPNetwork right)
  1665. {
  1666. return Compare(left, right) < 0;
  1667. }
  1668. public static bool operator >(IPNetwork left, IPNetwork right)
  1669. {
  1670. return Compare(left, right) > 0;
  1671. }
  1672. #endregion
  1673. }
  1674. }