// /** // * File: CIDR.cs // * Author: haraldwolff // * // * This file and it's content is copyrighted by the Author and / or copyright holder. // * Any use wihtout proper permission is illegal and may lead to legal actions. // * // * // **/ using System; using System.Net; using System.Linq; using System.Collections.Generic; using System.Collections; using Newtonsoft.Json; using LiteDB; namespace ln.types { public class CIDR : IEnumerable { public static CIDR Parse(String source) { string[] toks = source.Split('/'); IPAddress ip = IPAddress.Parse(toks[0]); if (toks.Length == 2) { if (toks[1].IndexOf('.') != -1) { IPAddress mask = IPAddress.Parse(toks[1]); return new CIDR(ip, mask); } else { uint w = uint.Parse(toks[1]); return new CIDR(ip, w); } } return new CIDR(ip, 32); } private readonly uint _ip; private readonly uint _netmask; public int MaskWidth => (int)getNetWidth(_netmask); public CIDR Network => new CIDR(_ip & _netmask, _netmask); public CIDR Host => new CIDR(_ip, 0xffffffff); public int Size => (1 << (32 - MaskWidth)); public byte[] IPBytes { get => BitConverter.GetBytes(_ip).Reverse().ToArray(); //set => _ip = BitConverter.ToUInt32(value.Reverse().ToArray(), 0); } public byte[] MaskBytes { get => BitConverter.GetBytes(_netmask).Reverse().ToArray(); //set => _netmask = BitConverter.ToUInt32(value.Reverse().ToArray(), 0); } public CIDR() { } public CIDR(uint ip, uint netmask) { this._ip = ip; this._netmask = netmask; } public CIDR(CIDR ip) { this._ip = ip._ip; this._netmask = 0xFFFFFFFF; } public CIDR(CIDR ip, uint maskwidth) { this._ip = ip._ip; this._netmask = maskFromWidth(maskwidth); } //public CIDR(IPAddress ip, uint maskwidth) //{ // _ip = BitConverter.ToUInt32(ip.GetAddressBytes().Reverse().ToArray(), 0); // _netmask = maskFromWidth(maskwidth); //} public CIDR(IPAddress ip, IPAddress mask) { _ip = BitConverter.ToUInt32(ip.GetAddressBytes().Reverse().ToArray(), 0); _netmask = BitConverter.ToUInt32(mask.GetAddressBytes().Reverse().ToArray(), 0); getNetWidth(_netmask); } private uint maskFromWidth(uint value) { uint nm = 0; if (value == 0) nm = 0; else if (value == 32) nm = 0xFFFFFFFF; else { nm = 0xFFFFFFFF; nm <<= (int)(32 - value); } return nm; } private uint getNetWidth(uint nm) { uint w = 0; for (w = 32; w > 0; w--) { if ((nm & (1 << (int)(32 - w))) != 0) break; } for (uint n = w; n > 0; n--) { if ((nm & (1 << (int)(32 - n))) == 0) throw new FormatException("Netmask with holes"); } return w; } public CIDR[] Divide(int bits) { if (MaskWidth + bits > 32) throw new ArgumentException("Netmask would be > 32bits", nameof(bits)); int count = (1 << bits); uint newmask = maskFromWidth((uint)(MaskWidth + bits)); uint nip = _ip; CIDR[] result = new CIDR[count]; for (int n = 0; n < count; n++) { nip += (uint)(1 << (32 - MaskWidth - bits)); result[n] = new CIDR(nip, newmask); } return result; } public override string ToString() { if (_netmask == 0xFFFFFFFF) return String.Format("{0}", String.Join(".", IPBytes.Select((x) => x.ToString()))); else return String.Format("{0}/{1}", String.Join(".", IPBytes.Select((x) => x.ToString())), getNetWidth(_netmask)); } public static implicit operator IPAddress(CIDR cidr) { return new IPAddress(cidr.IPBytes); } public static implicit operator CIDR(IPAddress iPAddress) { return new CIDR(BitConverter.ToUInt32(iPAddress.GetAddressBytes().Reverse().ToArray(), 0), 0xFFFFFFFF); } public bool Contains(CIDR you) { return (you.MaskWidth >= MaskWidth) && ((you._ip & _netmask) == (_ip & _netmask)); } public bool Contains(IEnumerable candidates) { foreach (CIDR ip in candidates) if (Contains(ip)) return true; return false; } public override int GetHashCode() { return (int)(_ip ^ _netmask); } public override bool Equals(object obj) { if (obj is IPAddress) obj = (CIDR)(obj as IPAddress); if (obj is CIDR) { CIDR you = obj as CIDR; return (you._ip == _ip) && (you._netmask == _netmask); } return false; } public IEnumerator GetEnumerator() { return new CIDREnumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } class CIDREnumerator : IEnumerator { CIDR network; CIDR curCIDR; public CIDR Current => curCIDR; object IEnumerator.Current => curCIDR; public CIDREnumerator(CIDR network) { this.network = network.Network; Reset(); } public void Dispose() { } public bool MoveNext() { curCIDR = new CIDR(curCIDR._ip + 1, 0xFFFFFFFF); return network.Contains(curCIDR); } public void Reset() { curCIDR = network; } } static CIDR() { BsonMapper.Global.RegisterType( serialize: (ip) => ip.ToString(), deserialize: (bson) => CIDR.Parse(bson.AsString) ); List converters = new List(); converters.Add(new CIDRJsonConverter()); JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = converters }; } } public class CIDRJsonConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(CIDR)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { return CIDR.Parse(reader.ReadAsString()); } public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { writer.WriteValue((value as CIDR).ToString()); } } }