ln.types/CIDR.cs

273 lines
7.4 KiB
C#

// /**
// * 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<CIDR>
{
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<CIDR> 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<CIDR> GetEnumerator()
{
return new CIDREnumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
class CIDREnumerator : IEnumerator<CIDR>
{
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<CIDR>(
serialize: (ip) => ip.ToString(),
deserialize: (bson) => CIDR.Parse(bson.AsString)
);
List<JsonConverter> converters = new List<JsonConverter>();
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());
}
}
}