master
Harald Wolff 2019-05-10 13:27:06 +02:00
parent dd1cbcfb86
commit 5355940395
11 changed files with 312 additions and 19 deletions

View File

@ -20,6 +20,7 @@ using ln.http;
using ln.http.resources; using ln.http.resources;
using skyspot.http; using skyspot.http;
using skyspot.session; using skyspot.session;
using skyspot.hotspot;
namespace skyspot namespace skyspot
{ {
@ -29,16 +30,18 @@ namespace skyspot
{ {
HTTPServer httpServer = new HTTPServer(); HTTPServer httpServer = new HTTPServer();
httpServer.AddEndpoint(new IPEndPoint(IPAddress.Any, 80)); httpServer.AddEndpoint(new IPEndPoint(IPAddress.Any, 80));
httpServer.Start();
HotspotManager hotspotManager = new HotspotManager();
ResourceApplication app = new SkySpotApplication(); ResourceApplication app = new SkySpotApplication();
httpServer.DefaultApplication = app; httpServer.DefaultApplication = app;
//DHCP httpDHCP = new DHCP(null,dhcpServer);
//(app.RootResource as DirectoryResource).InjectResource(httpDHCP);
SessionManager sessionManager = new SessionManager();
httpServer.Start();
} }
} }

11
doc/radius.txt 100644
View File

@ -0,0 +1,11 @@

Radius Secret Lookup:
---------------------
1. SecretStore individual secret
2. HotSpot Default Secret
3. SecretStore default secret

View File

@ -0,0 +1,12 @@
using System;
namespace skyspot.hotspot
{
public class ClientProfile
{
public String Name { get; set; }
public ClientProfile()
{
}
}
}

View File

@ -16,6 +16,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using skyspot.radius; using skyspot.radius;
using System.Linq; using System.Linq;
using skyspot.session;
namespace skyspot.hotspot namespace skyspot.hotspot
{ {
public class HotspotManager public class HotspotManager
@ -28,7 +29,12 @@ namespace skyspot.hotspot
public ODBCollection<HotspotNetwork> hotspotNetworks { get; private set; } public ODBCollection<HotspotNetwork> hotspotNetworks { get; private set; }
public ODBCollection<RadiusSecretsStore> radiusSecretsCollection; public ODBCollection<RadiusSecretsStore> radiusSecretsCollection;
Dictionary<HotspotNetwork, HotspotRuntime> instances = new Dictionary<HotspotNetwork, HotspotRuntime>();
MappingBTree<HotspotNetwork, HotspotNetworkRuntime> hotspotRuntimes = new MappingBTree<HotspotNetwork, HotspotNetworkRuntime>((hr) => hr.HotspotNetwork);
public SessionManager SessionManager { get; private set; }
public HotspotManager() public HotspotManager()
{ {
@ -39,17 +45,49 @@ namespace skyspot.hotspot
SecretsStore = radiusSecretsCollection.FirstOrDefault(); SecretsStore = radiusSecretsCollection.FirstOrDefault();
if (SecretsStore == null) if (SecretsStore == null)
SecretsStore = new RadiusSecretsStore(); SecretsStore = new RadiusSecretsStore();
SessionManager = new SessionManager(this);
} }
public void SaveSecretsStore() => radiusSecretsCollection.Upsert(SecretsStore); public void SaveSecretsStore() => radiusSecretsCollection.Upsert(SecretsStore);
public void AddHotspotNetwork(HotspotNetwork hotspotNetwork)
class HotspotRuntime
{ {
public BTree<MAC, HotspotSession> currentSessions { get; } = new BTree<MAC, HotspotSession>(); 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();
}
} }
} }

View File

@ -10,9 +10,10 @@
using System; using System;
using ln.types.odb.attributes; using ln.types.odb.attributes;
using ln.types.net; using ln.types.net;
using System.Text;
namespace skyspot.hotspot namespace skyspot.hotspot
{ {
public class HotspotNetwork public class HotspotNetwork : IComparable
{ {
[DocumentID] [DocumentID]
public readonly Guid ID = Guid.NewGuid(); public readonly Guid ID = Guid.NewGuid();
@ -23,10 +24,31 @@ namespace skyspot.hotspot
public string SID { get; set; } public string SID { get; set; }
public Network4 ClientsNetwork { get; set; } public Network4 ClientsNetwork { get; set; }
public IPv4 Gateway { get; set; }
public byte[] RadiusSecret { 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 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;
}
} }
} }

View File

@ -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<MAC, ClientSession> currentSessions = new MappingBTree<MAC, ClientSession>((ClientSession clientSession)=>clientSession.ClientMAC);
IPPool<ClientSession> pool = new IPPool<ClientSession>();
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
}
}
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace skyspot.hotspot
{
public class HotspotUser
{
public HotspotUser()
{
}
}
}

76
ip/IPPool.cs 100644
View File

@ -0,0 +1,76 @@
using System;
using ln.types.btree;
using ln.types.net;
namespace skyspot.ip
{
public class IPPool<T> where T : IComparable
{
public IPv4 FirstIP { get; set; }
public IPv4 LastIP { get; set; }
public IPv4 NextIP { get; set;}
BTree<IPv4, T> forward = new BTree<IPv4, T>();
BTree<T, IPv4> reverse = new BTree<T, IPv4>();
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("<ip> or <assigend> 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];
}
}
}

View File

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

View File

@ -17,17 +17,22 @@ using ln.logging;
using ln.types.odb; using ln.types.odb;
using ln.types.odb.mapped; using ln.types.odb.mapped;
using skyspot.radius; using skyspot.radius;
using System.Text;
using skyspot.hotspot;
namespace skyspot.session namespace skyspot.session
{ {
public class SessionManager public class SessionManager
{ {
public RadiusSecretsStore SecretsStore { get; private set; } public HotspotManager HotspotManager { get; }
public RadiusSecretsStore SecretsStore => HotspotManager.SecretsStore;
RadiusServer accountingRadius; RadiusServer accountingRadius;
RadiusServer locatorRadius; RadiusServer locatorRadius;
public SessionManager() public SessionManager(HotspotManager hotspotManager)
{ {
HotspotManager = hotspotManager;
InitializeRadius(); InitializeRadius();
} }
@ -48,6 +53,9 @@ namespace skyspot.session
accountingRadius.MessageReceived = AccountingMessageReceived; accountingRadius.MessageReceived = AccountingMessageReceived;
} }
/** /**
* Locator Service * Locator Service
* *
@ -97,18 +105,23 @@ namespace skyspot.session
} }
MAC clientMac = new MAC(userName.AsText); 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); Logging.Log(LogLevel.INFO, "Accounting: Session start for client {0} on Network {1}",clientMac, networkName);
reply.Identifier = radiusMessage.Identifier;
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); radiusServer.Send(reply);
} }
} }
} }

View File

@ -49,6 +49,11 @@
<Compile Include="hotspot\HotspotManager.cs" /> <Compile Include="hotspot\HotspotManager.cs" />
<Compile Include="hotspot\locator\MACLocation.cs" /> <Compile Include="hotspot\locator\MACLocation.cs" />
<Compile Include="radius\RadiusSecretsStore.cs" /> <Compile Include="radius\RadiusSecretsStore.cs" />
<Compile Include="session\ClientSession.cs" />
<Compile Include="hotspot\HotspotUser.cs" />
<Compile Include="hotspot\ClientProfile.cs" />
<Compile Include="ip\IPPool.cs" />
<Compile Include="hotspot\HotspotNetworkRuntime.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ln.http\ln.http.csproj"> <ProjectReference Include="..\ln.http\ln.http.csproj">
@ -89,6 +94,8 @@
<Folder Include="hotspot\" /> <Folder Include="hotspot\" />
<Folder Include="hotspot\locator\" /> <Folder Include="hotspot\locator\" />
<Folder Include="radius\" /> <Folder Include="radius\" />
<Folder Include="doc\" />
<Folder Include="ip\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="packages.config" /> <None Include="packages.config" />
@ -201,6 +208,7 @@
<None Include="www\js\sky.controls.js"> <None Include="www\js\sky.controls.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Include="doc\radius.txt" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project> </Project>