cloud.insecurity.docker/cloud.insecurity.docker.ipam/Scope.cs
2021-10-21 19:29:07 -07:00

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;
}
}
}
}
}