240 lines
7.4 KiB
C#
240 lines
7.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Numerics;
|
|
using System.Text.Json.Serialization;
|
|
using cloud.insecurity.docker.ipam.schema;
|
|
using cloud.insecurity.docker.ipam.schema;
|
|
using LiteDB;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace cloud.insecurity.docker.ipam
|
|
{
|
|
public class Scope
|
|
{
|
|
private Scope? ParentScope;
|
|
private bool _Locked;
|
|
|
|
public Guid Id
|
|
{
|
|
get
|
|
{
|
|
return GetUniqueId(Net, PrefixLen);
|
|
}
|
|
}
|
|
|
|
public string Net { get; set; }
|
|
public int PrefixLen { get; set; }
|
|
public List<string>? Tags { get; set; }
|
|
public int? TcpIpVersion { get; set; }
|
|
|
|
public bool Allocated { get; set; }
|
|
|
|
private static LiteDatabase Db = new LiteDatabase(@"IPAM.db");
|
|
private static log4net.ILog Log
|
|
{
|
|
get
|
|
{
|
|
return log4net.LogManager.GetLogger(typeof(Scope));
|
|
}
|
|
}
|
|
|
|
private schema.Scope Schema;
|
|
|
|
public bool Locked
|
|
{
|
|
get
|
|
{
|
|
return _Locked;
|
|
}
|
|
internal set
|
|
{
|
|
_Locked = value;
|
|
}
|
|
}
|
|
|
|
public Guid Parent
|
|
{
|
|
get
|
|
{
|
|
if (ParentScope == null)
|
|
return System.Guid.Empty;
|
|
|
|
return ParentScope.Id;
|
|
}
|
|
}
|
|
|
|
private bool Tagged
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
private IPNetwork Network
|
|
{
|
|
get
|
|
{
|
|
return IPNetwork.Parse(string.Format("{0}/{1}", Net, PrefixLen.ToString()));
|
|
}
|
|
}
|
|
|
|
public Scope LockScope()
|
|
{
|
|
if (Locked)
|
|
throw new InvalidOperationException("scope is already locked");
|
|
|
|
_Locked = true;
|
|
return this;
|
|
}
|
|
public Scope()
|
|
{
|
|
|
|
}
|
|
|
|
public static IPNetwork GetNetworkObject(string network, int prefixLen)
|
|
{
|
|
return IPNetwork.Parse(string.Format("{0}/{1}", network, prefixLen.ToString()));
|
|
}
|
|
public static Guid GetUniqueId(string network, int prefixLen)
|
|
{
|
|
var test = GetNetworkObject(network, prefixLen);
|
|
var bytes = GetNetworkObject(network, prefixLen)
|
|
.LastUsable
|
|
.GetAddressBytes();
|
|
|
|
if (bytes == null || bytes.Length < 4)
|
|
throw new ArgumentException("need at least 4 bytes");
|
|
|
|
if (bytes.Length == 4)
|
|
{
|
|
bytes = new byte[] {0, 0, 0, 0}.Concat(bytes).ToArray()
|
|
.Concat(new byte[] {0, 0, 0, 0, 0, 0, 0, 0}).ToArray();
|
|
}
|
|
|
|
//bytes = bytes.Select(b => Convert.ToByte(b ^ prefixLen)).ToArray();
|
|
|
|
using (MemoryStream ms = new MemoryStream(bytes))
|
|
{
|
|
using (BinaryReader b = new BinaryReader(ms))
|
|
{
|
|
// https://en.wikipedia.org/wiki/Universally_unique_identifier#History
|
|
return new Guid(
|
|
b.ReadUInt32(),
|
|
b.ReadUInt16(),
|
|
b.ReadUInt16(),
|
|
b.ReadByte(),
|
|
b.ReadByte(),
|
|
b.ReadByte(),
|
|
b.ReadByte(),
|
|
b.ReadByte(),
|
|
b.ReadByte(),
|
|
b.ReadByte(),
|
|
b.ReadByte());
|
|
// however this is RFC4122 (g)UUID and the information
|
|
// is definitely not relevant but a nice piece of
|
|
// nostalgia.
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public Scope GetUnassignedScope()
|
|
{
|
|
if (Locked)
|
|
throw new InvalidOperationException("scope is locked");
|
|
|
|
return Network.Subnet(Convert.ToByte(Schema.child_prefix)).Where(s =>
|
|
{
|
|
return !Db.GetCollection<Scope>("Scopes")
|
|
.Find(scope => scope.Id == GetUniqueId(s.Network.ToString(), s.Cidr)
|
|
&& scope.Allocated)
|
|
.Any();
|
|
}).Select(s => new Scope()
|
|
{
|
|
Net = s.Network.ToString(),
|
|
PrefixLen = Schema.child_prefix.GetValueOrDefault(),
|
|
ParentScope = this,
|
|
}).Single();
|
|
}
|
|
|
|
public IPAddress LeaseNetworkAddress()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public static IEnumerable<Scope> GetParentScopes()
|
|
{
|
|
var enumerable = JsonConvert.DeserializeObject<schema.Schema>(
|
|
new StreamReader(System.IO.File
|
|
.Open(@"schema.json", FileMode.Open))
|
|
.ReadToEnd())
|
|
?.scopes;
|
|
|
|
if (enumerable == null)
|
|
throw new NotImplementedException();
|
|
|
|
return EnumerateSchemaScopes(enumerable);
|
|
}
|
|
|
|
private static IEnumerable<Scope> EnumerateSchemaScopes(IEnumerable<schema.Scope> enumerable,
|
|
Scope? parent = null)
|
|
{
|
|
foreach (var scope in enumerable)
|
|
{
|
|
Scope newScope = null;
|
|
|
|
Db.GetCollection<Scope>("Scopes").EnsureIndex(s => s.Id,true);
|
|
|
|
try
|
|
{
|
|
newScope = Db.GetCollection<Scope>("Scopes")
|
|
.Find(s => s.Id == GetUniqueId(scope.network, (scope.prefix != 0)
|
|
? scope.prefix
|
|
: (int)parent.Schema.child_prefix)).SingleOrDefault();
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
Log.Debug("DB not initialized?", ex);
|
|
}
|
|
|
|
if (newScope == null)
|
|
{
|
|
newScope = new Scope()
|
|
{
|
|
Net = scope.network,
|
|
PrefixLen = (scope.prefix == 0)
|
|
? (int)parent.Schema.child_prefix
|
|
: scope.prefix,
|
|
Tags = scope.tags,
|
|
Schema = scope,
|
|
TcpIpVersion = scope.tcp_ip_version,
|
|
Locked = (scope.lock_down.GetValueOrDefault()) ? true : false,
|
|
ParentScope = parent
|
|
};
|
|
|
|
Db.GetCollection<Scope>("Scopes")
|
|
.Insert(new BsonValue(newScope.Id), newScope);
|
|
|
|
newScope = newScope;
|
|
}
|
|
else
|
|
{
|
|
newScope.ParentScope = parent;
|
|
newScope.Schema = scope;
|
|
}
|
|
|
|
yield return newScope;
|
|
|
|
if (newScope?.Schema.scopes.Count > 0)
|
|
foreach (var s in EnumerateSchemaScopes(newScope.Schema.scopes, newScope))
|
|
{
|
|
yield return s;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |