Initial Work

Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
This commit is contained in:
stephb9959
2022-06-15 07:29:29 -07:00
13 changed files with 189 additions and 10 deletions

View File

@@ -4,7 +4,6 @@ on:
pull_request:
branches:
- master
- 'release/*'
types: [ closed ]
defaults:

View File

@@ -702,7 +702,7 @@ on its behalf and send them to the device.
```
{
"radius" : <type, can be auth, acct, das> ,
"radius" : <type, can be auth, acct, coa> ,
"data" : <base 64 encoded raw RADIUS payload>
"dst" : <ip:port> as a string - optional. If this is supplied, the GW will send the data to that destination,
if not provided, the GW will use one of the radius servers it has in its configuration. This is only

View File

@@ -1129,6 +1129,8 @@ components:
$ref: '#/components/schemas/RadiusProxyServerConfig'
acctConfig:
$ref: '#/components/schemas/RadiusProxyServerConfig'
coaConfig:
$ref: '#/components/schemas/RadiusProxyServerConfig'
RadiusProxyPoolList:
type: object
@@ -2592,6 +2594,16 @@ paths:
403:
$ref: '#/components/responses/Unauthorized'
delete:
tags:
- RADIUSProxy
summary: Delete RADIUS Proxy configuration.
operationId: deleteRadiusProxyConfig
responses:
204:
$ref: '#/components/responses/Success'
403:
$ref: '#/components/responses/Unauthorized'
/deviceDashboard:
get:

64
radius_config_sample.json Normal file
View File

@@ -0,0 +1,64 @@
{
"pools" : [
{
"name" : "master" ,
"description" : "master pool",
"authConfig" : {
"strategy" : "weighted",
"monitor" : false,
"monitorMethod" : "none",
"methodParameters" : [],
"servers" : [ {
"name" : "svr1",
"ip" : "10.100.0.1",
"port" : 1812,
"weight" : 10
},
{
"name" : "svr2",
"ip" : "10.100.10.1",
"port" : 1812,
"weight" : 20
}
]
},
"acctConfig" : {
"strategy" : "random",
"monitor" : false,
"monitorMethod" : "none",
"methodParameters" : [],
"servers" : [ {
"name" : "svr1",
"ip" : "10.100.0.1",
"port" : 1813,
"weight" : 10
},
{
"name" : "svr2",
"ip" : "10.100.10.1",
"port" : 1813,
"weight" : 20 }
]
},
"coaConfig" : {
"strategy" : "round_robin",
"monitor" : false,
"monitorMethod" : "none",
"methodParameters" : [],
"servers" : [ {
"name" : "svr1",
"ip" : "10.100.0.1",
"port" : 3799,
"weight" : 10
},
{
"name" : "svr2",
"ip" : "10.100.10.1",
"port" : 3799,
"weight" : 20
}
]
}
}
]
}

View File

@@ -173,6 +173,23 @@ namespace OpenWifi {
return false;
}
bool DeviceRegistry::SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(Utils::SerialNumberToInt(SerialNumber));
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
try {
return Device->second->WSConn_->SendRadiusCoAData(buffer,size);
} catch (...) {
Logger().debug(fmt::format("Could not send data to device '{}'", SerialNumber));
Device->second->Conn_.Address = "";
Device->second->WSConn_ = nullptr;
Device->second->Conn_.Connected = false;
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
}
}
return false;
}
void DeviceRegistry::SetPendingUUID(uint64_t SerialNumber, uint64_t PendingUUID) {
std::lock_guard Guard(Mutex_);
auto Device = Devices_.find(SerialNumber);

View File

@@ -105,6 +105,7 @@ namespace OpenWifi {
bool SendRadiusAuthenticationData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
bool SendRadiusAccountingData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
bool SendRadiusCoAData(const std::string & SerialNumber, const unsigned char * buffer, std::size_t size);
private:
inline static std::atomic_uint64_t Id_=1;

View File

@@ -11,6 +11,7 @@ namespace OpenWifi {
const int RADIUS_BUFFER_SIZE = 2048;
const int DEFAULT_RADIUS_AUTHENTICATION_PORT = 1812;
const int DEFAULT_RADIUS_ACCOUNTING_PORT = 1813;
const int DEFAULT_RADIUS_CoA_PORT = 3799;
int RADIUS_proxy_server::Start() {
@@ -30,35 +31,59 @@ namespace OpenWifi {
MicroService::instance().ConfigGetInt("radius.proxy.accounting.port",DEFAULT_RADIUS_ACCOUNTING_PORT));
AccountingSocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6,true);
Poco::Net::SocketAddress CoASockAddrV4(Poco::Net::AddressFamily::IPv4,
MicroService::instance().ConfigGetInt("radius.proxy.coa.port",DEFAULT_RADIUS_CoA_PORT));
CoASocketV4_ = std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV4,true);
Poco::Net::SocketAddress CoASockAddrV6(Poco::Net::AddressFamily::IPv6,
MicroService::instance().ConfigGetInt("radius.proxy.coa.port",DEFAULT_RADIUS_CoA_PORT));
CoASocketV6_ = std::make_unique<Poco::Net::DatagramSocket>(AcctSockAddrV6,true);
AuthenticationReactor_.addEventHandler(*AuthenticationSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
AuthenticationReactor_.addEventHandler(*AuthenticationSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
AccountingReactor_.addEventHandler(*AccountingSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
AuthenticationReactor_.addEventHandler(*AuthenticationSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
AccountingReactor_.addEventHandler(*AccountingSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
CoAReactor_.addEventHandler(*CoASocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
CoAReactor_.addEventHandler(*CoASocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnCoASocketReadable));
AuthenticationReactorThread_.start(AuthenticationReactor_);
AccountingReactorThread_.start(AccountingReactor_);
CoAReactorThread_.start(CoAReactor_);
return 0;
}
void RADIUS_proxy_server::Stop() {
AuthenticationReactor_.removeEventHandler(*AuthenticationSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
AuthenticationReactor_.removeEventHandler(*AuthenticationSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
AccountingReactor_.removeEventHandler(*AccountingSocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
AuthenticationReactor_.removeEventHandler(*AuthenticationSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAuthenticationSocketReadable));
AccountingReactor_.removeEventHandler(*AccountingSocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
CoAReactor_.removeEventHandler(*CoASocketV4_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
CoAReactor_.removeEventHandler(*CoASocketV6_,Poco::NObserver<RADIUS_proxy_server, Poco::Net::ReadableNotification>(
*this, &RADIUS_proxy_server::OnAccountingSocketReadable));
AuthenticationReactor_.stop();
AuthenticationReactorThread_.join();
AccountingReactor_.stop();
AccountingReactorThread_.join();
CoAReactor_.stop();
CoAReactorThread_.join();
}
std::string ExtractSerialNumber(const unsigned char *b, uint32_t s) {
@@ -117,7 +142,6 @@ namespace OpenWifi {
return result;
}
void RADIUS_proxy_server::OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
Poco::Net::SocketAddress Sender;
unsigned char Buffer[RADIUS_BUFFER_SIZE];
@@ -144,6 +168,19 @@ namespace OpenWifi {
DeviceRegistry()->SendRadiusAuthenticationData(SerialNumber,Buffer,ReceiveSize);
}
void RADIUS_proxy_server::OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
Poco::Net::SocketAddress Sender;
unsigned char Buffer[RADIUS_BUFFER_SIZE];
auto ReceiveSize = pNf.get()->socket().impl()->receiveBytes(Buffer,sizeof(Buffer));
if(ReceiveSize<SMALLEST_RADIUS_PACKET)
return;
auto SerialNumber = ExtractSerialNumber(&Buffer[20],ReceiveSize);
Logger().information(fmt::format("CoA Packet received for {}",SerialNumber));
std::cout << "Received an CoA packet for :" << SerialNumber << std::endl;
DeviceRegistry()->SendRadiusCoAData(SerialNumber,Buffer,ReceiveSize);
}
void RADIUS_proxy_server::SendAccountingData(const std::string &serialNumber, const std::string &Destination,const char *buffer, std::size_t size) {
Poco::Net::SocketAddress Dst(Destination);
@@ -168,6 +205,18 @@ namespace OpenWifi {
std::cout << "Sending Authentication data to " << Destination << std::endl;
}
void RADIUS_proxy_server::SendCoAData(const std::string &serialNumber, const std::string &Destination,const char *buffer, std::size_t size) {
Poco::Net::SocketAddress Dst(Destination);
std::lock_guard G(Mutex_);
if(Dst.af()==Poco::Net::AddressFamily::IPv4)
CoASocketV4_->sendTo(buffer,(int)size,Route(Dst,CoAPoolsV4_,CoAPoolsIndexV4_));
else
CoASocketV6_->sendTo(buffer,(int)size,Route(Dst,CoAPoolsV6_,CoAPoolsIndexV6_));
Logger().information(fmt::format("{}: Sending CoA Packet to {}", serialNumber, Destination));
std::cout << "Sending CoA data to " << Destination << std::endl;
}
void RADIUS_proxy_server::ParseServerList(const GWObjects::RadiusProxyServerConfig & Config, PoolIndexMap_t &MapV4, PoolIndexMap_t &MapV6, PoolIndexVec_t &VecV4, PoolIndexVec_t &VecV6) {
std::vector<Destination> DestsV4,DestsV6;
@@ -228,8 +277,9 @@ namespace OpenWifi {
ResetConfig();
PoolList_ = RPC;
for(const auto &pool:RPC.pools) {
ParseServerList(pool.authConfig,AuthPoolsIndexV4_, AuthPoolsIndexV6_, AuthPoolsV4_, AuthPoolsV6_);
ParseServerList(pool.acctConfig,AcctPoolsIndexV4_, AcctPoolsIndexV6_, AcctPoolsV4_, AcctPoolsV6_);
ParseServerList(pool.authConfig, AuthPoolsIndexV4_, AuthPoolsIndexV6_, AuthPoolsV4_, AuthPoolsV6_);
ParseServerList(pool.acctConfig, AcctPoolsIndexV4_, AcctPoolsIndexV6_, AcctPoolsV4_, AcctPoolsV6_);
ParseServerList(pool.coaConfig, CoAPoolsIndexV4_, CoAPoolsIndexV6_, CoAPoolsV4_, CoAPoolsV6_);
}
} else {
Logger().warning(fmt::format("Configuration file '{}' is bad.",ConfigFilename_));
@@ -331,10 +381,14 @@ namespace OpenWifi {
AuthPoolsIndexV6_.clear();
AcctPoolsIndexV4_.clear();
AcctPoolsIndexV6_.clear();
CoAPoolsIndexV4_.clear();
CoAPoolsIndexV6_.clear();
AuthPoolsV4_.clear();
AuthPoolsV6_.clear();
AcctPoolsV4_.clear();
AcctPoolsV6_.clear();
CoAPoolsV4_.clear();
CoAPoolsV6_.clear();
}
void RADIUS_proxy_server::DeleteConfig() {

View File

@@ -22,8 +22,11 @@ namespace OpenWifi {
void OnAccountingSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
void OnAuthenticationSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
void OnCoASocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
void SendAccountingData(const std::string &serialNumber, const std::string &Destination,const char *buffer, std::size_t size);
void SendAuthenticationData(const std::string &serialNumber, const std::string &Destination,const char *buffer, std::size_t size);
void SendCoAData(const std::string &serialNumber, const std::string &Destination,const char *buffer, std::size_t size);
void SetConfig(const GWObjects::RadiusProxyPoolList &C);
void DeleteConfig();
@@ -46,25 +49,38 @@ namespace OpenWifi {
std::unique_ptr<Poco::Net::DatagramSocket> AccountingSocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> AuthenticationSocketV6_;
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV4_;
std::unique_ptr<Poco::Net::DatagramSocket> CoASocketV6_;
Poco::Net::SocketReactor AccountingReactor_;
Poco::Net::SocketReactor AuthenticationReactor_;
Poco::Net::SocketReactor CoAReactor_;
Poco::Thread AuthenticationReactorThread_;
Poco::Thread AccountingReactorThread_;
Poco::Thread CoAReactorThread_;
GWObjects::RadiusProxyPoolList PoolList_;
std::string ConfigFilename_;
typedef std::map<Poco::Net::SocketAddress,uint> PoolIndexMap_t;
PoolIndexMap_t AuthPoolsIndexV4_;
PoolIndexMap_t AcctPoolsIndexV4_;
PoolIndexMap_t AuthPoolsIndexV6_;
PoolIndexMap_t AcctPoolsIndexV4_;
PoolIndexMap_t AcctPoolsIndexV6_;
PoolIndexMap_t CoAPoolsIndexV4_;
PoolIndexMap_t CoAPoolsIndexV6_;
typedef std::vector<std::vector<Destination>> PoolIndexVec_t;
PoolIndexVec_t AuthPoolsV4_;
PoolIndexVec_t AuthPoolsV6_;
PoolIndexVec_t AcctPoolsV4_;
PoolIndexVec_t AcctPoolsV6_;
PoolIndexVec_t CoAPoolsV4_;
PoolIndexVec_t CoAPoolsV6_;
RADIUS_proxy_server() noexcept:
SubSystemServer("RADIUS-PROXY", "RADIUS-PROXY", "radius.proxy")
{

View File

@@ -314,6 +314,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"description",description);
field_to_json(Obj,"authConfig",authConfig);
field_to_json(Obj,"acctConfig",acctConfig);
field_to_json(Obj,"coaConfig",coaConfig);
}
bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -322,6 +323,7 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj,"description",description);
field_from_json(Obj,"authConfig",authConfig);
field_from_json(Obj,"acctConfig",acctConfig);
field_from_json(Obj,"coaConfig",coaConfig);
return true;
} catch (const Poco::Exception &E) {
}

View File

@@ -237,6 +237,7 @@ namespace OpenWifi::GWObjects {
std::string description;
RadiusProxyServerConfig authConfig;
RadiusProxyServerConfig acctConfig;
RadiusProxyServerConfig coaConfig;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);

View File

@@ -1113,6 +1113,16 @@ namespace OpenWifi {
return Send(Payload.str());
}
bool WSConnection::SendRadiusCoAData(const unsigned char * buffer, std::size_t size) {
Poco::JSON::Object Answer;
Answer.set(uCentralProtocol::RADIUS,uCentralProtocol::RADIUSCOA);
Answer.set(uCentralProtocol::RADIUSDATA, Base64Encode(buffer,size));
std::ostringstream Payload;
Answer.stringify(Payload);
return Send(Payload.str());
}
void WSConnection::ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc) {
if( Doc->has(uCentralProtocol::RADIUSDATA)) {
auto Type = Doc->get(uCentralProtocol::RADIUS).toString();

View File

@@ -29,8 +29,10 @@ namespace OpenWifi {
void ProcessIncomingRadiusData(const Poco::JSON::Object::Ptr &Doc);
bool Send(const std::string &Payload);
bool SendRadiusAuthenticationData(const unsigned char * buffer, std::size_t size);
bool SendRadiusAccountingData(const unsigned char * buffer, std::size_t size);
bool SendRadiusCoAData(const unsigned char * buffer, std::size_t size);
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf);

View File

@@ -428,6 +428,7 @@ namespace OpenWifi::uCentralProtocol {
static const char *RADIUSDATA = "data";
static const char *RADIUSACCT = "acct";
static const char *RADIUSAUTH = "auth";
static const char *RADIUSCOA = "coa";
static const char *RADIUSDST = "dst";
static const char *IES = "ies";
}