From 53559403953b406cb3e33a52df48552dc6a569be Mon Sep 17 00:00:00 2001 From: Harald Wolff Date: Fri, 10 May 2019 13:27:06 +0200 Subject: [PATCH] WIP --- Program.cs | 11 +++-- doc/radius.txt | 11 +++++ hotspot/ClientProfile.cs | 12 +++++ hotspot/HotspotManager.cs | 48 +++++++++++++++++--- hotspot/HotspotNetwork.cs | 24 +++++++++- hotspot/HotspotNetworkRuntime.cs | 54 +++++++++++++++++++++++ hotspot/HotspotUser.cs | 10 +++++ ip/IPPool.cs | 76 ++++++++++++++++++++++++++++++++ session/ClientSession.cs | 46 +++++++++++++++++++ session/SessionManager.cs | 31 +++++++++---- skyspot.csproj | 8 ++++ 11 files changed, 312 insertions(+), 19 deletions(-) create mode 100644 doc/radius.txt create mode 100644 hotspot/ClientProfile.cs create mode 100644 hotspot/HotspotNetworkRuntime.cs create mode 100644 hotspot/HotspotUser.cs create mode 100644 ip/IPPool.cs create mode 100644 session/ClientSession.cs diff --git a/Program.cs b/Program.cs index 053a1ce..ac71bfd 100644 --- a/Program.cs +++ b/Program.cs @@ -20,6 +20,7 @@ using ln.http; using ln.http.resources; using skyspot.http; using skyspot.session; +using skyspot.hotspot; namespace skyspot { @@ -29,16 +30,18 @@ namespace skyspot { HTTPServer httpServer = new HTTPServer(); httpServer.AddEndpoint(new IPEndPoint(IPAddress.Any, 80)); + httpServer.Start(); + + HotspotManager hotspotManager = new HotspotManager(); + + + ResourceApplication app = new SkySpotApplication(); httpServer.DefaultApplication = app; - //DHCP httpDHCP = new DHCP(null,dhcpServer); - //(app.RootResource as DirectoryResource).InjectResource(httpDHCP); - SessionManager sessionManager = new SessionManager(); - httpServer.Start(); } } diff --git a/doc/radius.txt b/doc/radius.txt new file mode 100644 index 0000000..9d3160c --- /dev/null +++ b/doc/radius.txt @@ -0,0 +1,11 @@ + + +Radius Secret Lookup: +--------------------- + + 1. SecretStore individual secret + 2. HotSpot Default Secret + 3. SecretStore default secret + + + \ No newline at end of file diff --git a/hotspot/ClientProfile.cs b/hotspot/ClientProfile.cs new file mode 100644 index 0000000..6d1884a --- /dev/null +++ b/hotspot/ClientProfile.cs @@ -0,0 +1,12 @@ +using System; +namespace skyspot.hotspot +{ + public class ClientProfile + { + public String Name { get; set; } + + public ClientProfile() + { + } + } +} diff --git a/hotspot/HotspotManager.cs b/hotspot/HotspotManager.cs index a44ad1c..e08b66f 100644 --- a/hotspot/HotspotManager.cs +++ b/hotspot/HotspotManager.cs @@ -16,6 +16,7 @@ using System.Collections.Generic; using System.IO; using skyspot.radius; using System.Linq; +using skyspot.session; namespace skyspot.hotspot { public class HotspotManager @@ -28,7 +29,12 @@ namespace skyspot.hotspot public ODBCollection hotspotNetworks { get; private set; } public ODBCollection radiusSecretsCollection; - Dictionary instances = new Dictionary(); + + + + MappingBTree hotspotRuntimes = new MappingBTree((hr) => hr.HotspotNetwork); + + public SessionManager SessionManager { get; private set; } public HotspotManager() { @@ -39,17 +45,49 @@ namespace skyspot.hotspot SecretsStore = radiusSecretsCollection.FirstOrDefault(); if (SecretsStore == null) SecretsStore = new RadiusSecretsStore(); + + SessionManager = new SessionManager(this); } public void SaveSecretsStore() => radiusSecretsCollection.Upsert(SecretsStore); - - class HotspotRuntime + public void AddHotspotNetwork(HotspotNetwork hotspotNetwork) { - public BTree currentSessions { get; } = new BTree(); - + if (!hotspotRuntimes.ContainsKey(hotspotNetwork)) + hotspotRuntimes.Add(new HotspotNetworkRuntime(hotspotNetwork)); } + public void RemoveHotspotNetwork(HotspotNetwork hotspotNetwork) + { + if (hotspotRuntimes.ContainsKey(hotspotNetwork)) + { + hotspotRuntimes.RemoveKey(hotspotNetwork); + } + } + public HotspotNetworkRuntime GetHotspotNetworkRuntime(HotspotNetwork hotspotNetwork) + { + return hotspotRuntimes[hotspotNetwork]; + } + public HotspotNetworkRuntime GetHotspotNetworkRuntime(string networkName) + { + foreach (HotspotNetworkRuntime hotspotNetworkRuntime in hotspotRuntimes) + { + if (hotspotNetworkRuntime.HotspotNetwork.Name.Equals(networkName)) + return hotspotNetworkRuntime; + } + throw new KeyNotFoundException(); + } + + public HotspotNetwork GetHotspotNetwork(String name) + { + foreach (HotspotNetworkRuntime hotspotNetworkRuntime in hotspotRuntimes) + { + if (hotspotNetworkRuntime.HotspotNetwork.Name.Equals(name)) + return hotspotNetworkRuntime.HotspotNetwork; + } + throw new KeyNotFoundException(); + } + } } diff --git a/hotspot/HotspotNetwork.cs b/hotspot/HotspotNetwork.cs index dfbda13..8f9af08 100644 --- a/hotspot/HotspotNetwork.cs +++ b/hotspot/HotspotNetwork.cs @@ -10,9 +10,10 @@ using System; using ln.types.odb.attributes; using ln.types.net; +using System.Text; namespace skyspot.hotspot { - public class HotspotNetwork + public class HotspotNetwork : IComparable { [DocumentID] public readonly Guid ID = Guid.NewGuid(); @@ -23,10 +24,31 @@ namespace skyspot.hotspot public string SID { get; set; } public Network4 ClientsNetwork { get; set; } + public IPv4 Gateway { get; set; } + public byte[] RadiusSecret { get; set; } + public string RadiusTextSecret + { + get => Encoding.UTF8.GetString(RadiusSecret); + set => RadiusSecret = Encoding.UTF8.GetBytes(value); + } + + public TimeSpan ClientDefaultSessionTime { get; set; } + public ClientProfile DefaultClientProfile { get; set; } + public HotspotNetwork() { } + + public int CompareTo(object obj) + { + if (obj is HotspotNetwork) + { + HotspotNetwork you = obj as HotspotNetwork; + return string.Compare(Name, you.Name, StringComparison.Ordinal); + } + return -1; + } } } diff --git a/hotspot/HotspotNetworkRuntime.cs b/hotspot/HotspotNetworkRuntime.cs new file mode 100644 index 0000000..be50653 --- /dev/null +++ b/hotspot/HotspotNetworkRuntime.cs @@ -0,0 +1,54 @@ +using System; +using ln.types.btree; +using ln.types.net; +using skyspot.session; +using skyspot.ip; +namespace skyspot.hotspot +{ + public class HotspotNetworkRuntime + { + public HotspotNetwork HotspotNetwork { get; private set; } + + MappingBTree currentSessions = new MappingBTree((ClientSession clientSession)=>clientSession.ClientMAC); + IPPool pool = new IPPool(); + + + private HotspotNetworkRuntime() + { + } + public HotspotNetworkRuntime(HotspotNetwork hotspotNetwork) + { + HotspotNetwork = hotspotNetwork; + } + + public ClientSession GetSession(MAC clientMac) + { + if (!currentSessions.ContainsKey(clientMac)) + { + ClientSession newSession = new ClientSession(HotspotNetwork, clientMac); + FixupSession(newSession); + currentSessions.Add(newSession); + return newSession; + } + else + { + ClientSession clientSession = currentSessions[clientMac]; + FixupSession(clientSession); + return clientSession; ; + } + } + public void RemoveSession(MAC clientMac) + { + currentSessions.RemoveKey(clientMac); + } + + private void FixupSession(ClientSession clientSession) + { + if (clientSession.ClientIP == null) + { + // Todo: Implement IP allocation from pool + } + } + + } +} diff --git a/hotspot/HotspotUser.cs b/hotspot/HotspotUser.cs new file mode 100644 index 0000000..f83eb50 --- /dev/null +++ b/hotspot/HotspotUser.cs @@ -0,0 +1,10 @@ +using System; +namespace skyspot.hotspot +{ + public class HotspotUser + { + public HotspotUser() + { + } + } +} diff --git a/ip/IPPool.cs b/ip/IPPool.cs new file mode 100644 index 0000000..95b560f --- /dev/null +++ b/ip/IPPool.cs @@ -0,0 +1,76 @@ +using System; +using ln.types.btree; +using ln.types.net; +namespace skyspot.ip +{ + public class IPPool where T : IComparable + { + public IPv4 FirstIP { get; set; } + public IPv4 LastIP { get; set; } + + public IPv4 NextIP { get; set;} + + BTree forward = new BTree(); + BTree reverse = new BTree(); + + public IPPool() + { + } + + public T FindForward(IPv4 ip) + { + lock (this) + { + return forward[ip]; + } + } + public IPv4 FindReverse(T lookup) + { + lock (this) + { + return reverse[lookup]; + } + } + + public void Assign(IPv4 ip, T assigned) + { + lock (this) + { + if (forward.ContainsKey(ip) || reverse.ContainsKey(assigned)) + throw new ArgumentException(" or already in pool"); + forward.Add(ip, assigned); + reverse.Add(assigned, ip); + } + } + public void Remove(IPv4 ip) + { + lock (this) + { + if (forward.ContainsKey(ip)) + { + reverse.Remove(forward[ip]); + forward.Remove(ip); + } + } + } + public void RemoveAssigned(T assigned) + { + lock (this) + { + if (reverse.ContainsKey(assigned)) + { + forward.Remove(reverse[assigned]); + reverse.Remove(assigned); + } + } + } + + public IPv4 Allocate(T assigned) + { + if (reverse.ContainsKey(assigned)) + return reverse[assigned]; + + } + + } +} diff --git a/session/ClientSession.cs b/session/ClientSession.cs new file mode 100644 index 0000000..b9ce535 --- /dev/null +++ b/session/ClientSession.cs @@ -0,0 +1,46 @@ +using System; +using skyspot.hotspot; +using ln.types.net; +using ln.types.odb.attributes; +namespace skyspot.session +{ + public class ClientSession : IComparable + { + [DocumentID] + Guid id = Guid.NewGuid(); + + public DateTimeOffset Created { get; } + public DateTimeOffset ValidThrough { get; set; } + + public HotspotNetwork HotspotNetwork { get; } + + public MAC ClientMAC { get; } + public IPv4 ClientIP { get; set; } + + public HotspotUser HotspotUser { get; set; } + public ClientProfile CurrentProfile { get; set; } + + private ClientSession() + { + Created = DateTimeOffset.Now; + ValidThrough = Created + TimeSpan.FromMinutes(3); + } + + public ClientSession(HotspotNetwork hotspotNetwork,MAC clientMac) + :this() + { + HotspotNetwork = hotspotNetwork; + ClientMAC = clientMac; + } + + public int CompareTo(object obj) + { + if (obj is ClientSession) + { + ClientSession you = obj as ClientSession; + return ClientMAC.CompareTo(you.ClientMAC); + } + return -1; + } + } +} diff --git a/session/SessionManager.cs b/session/SessionManager.cs index dcb54b3..b2ac36d 100644 --- a/session/SessionManager.cs +++ b/session/SessionManager.cs @@ -17,17 +17,22 @@ using ln.logging; using ln.types.odb; using ln.types.odb.mapped; using skyspot.radius; +using System.Text; +using skyspot.hotspot; namespace skyspot.session { public class SessionManager { - public RadiusSecretsStore SecretsStore { get; private set; } + public HotspotManager HotspotManager { get; } + public RadiusSecretsStore SecretsStore => HotspotManager.SecretsStore; + RadiusServer accountingRadius; RadiusServer locatorRadius; - public SessionManager() + public SessionManager(HotspotManager hotspotManager) { + HotspotManager = hotspotManager; InitializeRadius(); } @@ -48,6 +53,9 @@ namespace skyspot.session accountingRadius.MessageReceived = AccountingMessageReceived; } + + + /** * Locator Service * @@ -97,18 +105,23 @@ namespace skyspot.session } MAC clientMac = new MAC(userName.AsText); - String instanceName = calledStationID.AsText; + String networkName = calledStationID.AsText; + HotspotNetworkRuntime hotspotNetworkRuntime = HotspotManager.GetHotspotNetworkRuntime(networkName); + ClientSession clientSession = hotspotNetworkRuntime.GetSession(clientMac); - Logging.Log(LogLevel.INFO, "Accounting: Session start for client {0} on Network {1}",clientMac, instanceName); + if (clientSession.CurrentProfile == null) + clientSession.CurrentProfile = hotspotNetworkRuntime.HotspotNetwork.DefaultClientProfile; - RadiusMessage reply = new RadiusMessage(radiusMessage.EndPoint, RadiusCode.AccessAccept); - reply.Identifier = radiusMessage.Identifier; + Logging.Log(LogLevel.INFO, "Accounting: Session start for client {0} on Network {1}",clientMac, networkName); + + RadiusMessage reply = radiusMessage.ConstructReply(RadiusCode.AccessAccept); + reply.AddAttribute(new RadiusAttribute.FramedIPAddress().SetIP(IPv4.Parse("10.123.0.4"))); + if (clientSession.CurrentProfile != null) + reply.AddAttribute(new RadiusAttribute.FilterID().SetText(clientSession.CurrentProfile.Name)); - reply.Authenticate(SecretsStore.LookupSecret(reply.EndPoint)); radiusServer.Send(reply); - } - + } } } diff --git a/skyspot.csproj b/skyspot.csproj index 0f98767..5ff3295 100644 --- a/skyspot.csproj +++ b/skyspot.csproj @@ -49,6 +49,11 @@ + + + + + @@ -89,6 +94,8 @@ + + @@ -201,6 +208,7 @@ PreserveNewest + \ No newline at end of file