diff --git a/agents/radagent.go b/agents/radagent.go
new file mode 100644
index 000000000..aff97b8c4
--- /dev/null
+++ b/agents/radagent.go
@@ -0,0 +1,76 @@
+/*
+Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
+Copyright (C) ITsysCOM GmbH
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+package agents
+
+import (
+ "fmt"
+
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/utils"
+ "github.com/cgrates/radigo"
+ "github.com/cgrates/rpcclient"
+)
+
+func NewRadiusAgent(cgrCfg *config.CGRConfig, smg rpcclient.RpcClientConnection) (ra *RadiusAgent, err error) {
+ dicts := make(map[string]*radigo.Dictionary, len(cgrCfg.RadiusAgentCfg().ClientDictionaries))
+ for clntID, dictPath := range cgrCfg.RadiusAgentCfg().ClientDictionaries {
+ if dicts[clntID], err = radigo.NewDictionaryFromFolderWithRFC2865(dictPath); err != nil {
+ return
+ }
+ }
+ ra = &RadiusAgent{cgrCfg: cgrCfg, smg: smg}
+ ra.rsAuth = radigo.NewServer(cgrCfg.RadiusAgentCfg().ListenNet, cgrCfg.RadiusAgentCfg().ListenAuth, cgrCfg.RadiusAgentCfg().ClientSecrets, dicts,
+ map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){radigo.AccessRequest: ra.handleAuth})
+ ra.rsAcct = radigo.NewServer(cgrCfg.RadiusAgentCfg().ListenNet, cgrCfg.RadiusAgentCfg().ListenAcct, cgrCfg.RadiusAgentCfg().ClientSecrets, dicts,
+ map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){radigo.AccountingRequest: ra.handleAcct})
+ return
+
+}
+
+type RadiusAgent struct {
+ cgrCfg *config.CGRConfig // reference for future config reloads
+ smg rpcclient.RpcClientConnection // Connection towards CGR-SMG component
+ rsAuth *radigo.Server
+ rsAcct *radigo.Server
+}
+
+func (ra *RadiusAgent) handleAuth(req *radigo.Packet) (rpl *radigo.Packet, err error) {
+ return
+}
+
+func (ra *RadiusAgent) handleAcct(req *radigo.Packet) (rpl *radigo.Packet, err error) {
+ return
+}
+
+func (ra *RadiusAgent) ListenAndServe() (err error) {
+ var errListen chan error
+ go func() {
+ utils.Logger.Info(fmt.Sprintf(" Start listening for auth requests on <%s>", ra.cgrCfg.RadiusAgentCfg().ListenAuth))
+ if err := ra.rsAuth.ListenAndServe(); err != nil {
+ errListen <- err
+ }
+ }()
+ go func() {
+ utils.Logger.Info(fmt.Sprintf(" Start listening for acct requests on <%s>", ra.cgrCfg.RadiusAgentCfg().ListenAcct))
+ if err := ra.rsAcct.ListenAndServe(); err != nil {
+ errListen <- err
+ }
+ }()
+ err = <-errListen
+ return
+}
diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go
index a971acec1..5a0e77e42 100644
--- a/cmd/cgr-engine/cgr-engine.go
+++ b/cmd/cgr-engine/cgr-engine.go
@@ -210,7 +210,7 @@ func startSMAsterisk(internalSMGChan chan *sessionmanager.SMGeneric, exitChan ch
}
func startDiameterAgent(internalSMGChan chan *sessionmanager.SMGeneric, internalPubSubSChan chan rpcclient.RpcClientConnection, exitChan chan bool) {
- utils.Logger.Info("Starting CGRateS DiameterAgent service.")
+ utils.Logger.Info("Starting CGRateS DiameterAgent service")
smgChan := make(chan rpcclient.RpcClientConnection, 1) // Use it to pass smg
go func(internalSMGChan chan *sessionmanager.SMGeneric, smgChan chan rpcclient.RpcClientConnection) {
// Need this to pass from *sessionmanager.SMGeneric to rpcclient.RpcClientConnection
@@ -250,8 +250,39 @@ func startDiameterAgent(internalSMGChan chan *sessionmanager.SMGeneric, internal
exitChan <- true
}
+func startRadiusAgent(internalSMGChan chan *sessionmanager.SMGeneric, exitChan chan bool) {
+ utils.Logger.Info("Starting CGRateS RadiusAgent service")
+ smgChan := make(chan rpcclient.RpcClientConnection, 1) // Use it to pass smg
+ go func(internalSMGChan chan *sessionmanager.SMGeneric, smgChan chan rpcclient.RpcClientConnection) {
+ // Need this to pass from *sessionmanager.SMGeneric to rpcclient.RpcClientConnection
+ smg := <-internalSMGChan
+ internalSMGChan <- smg
+ smgChan <- smg
+ }(internalSMGChan, smgChan)
+ var smgConn *rpcclient.RpcClientPool
+ if len(cfg.RadiusAgentCfg().SMGenericConns) != 0 {
+ smgConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout,
+ cfg.RadiusAgentCfg().SMGenericConns, smgChan, cfg.InternalTtl)
+ if err != nil {
+ utils.Logger.Crit(fmt.Sprintf(" Could not connect to SMG: %s", err.Error()))
+ exitChan <- true
+ return
+ }
+ }
+ ra, err := agents.NewRadiusAgent(cfg, smgConn)
+ if err != nil {
+ utils.Logger.Err(fmt.Sprintf(" error: <%s>", err.Error()))
+ exitChan <- true
+ return
+ }
+ if err = ra.ListenAndServe(); err != nil {
+ utils.Logger.Err(fmt.Sprintf(" error: <%s>", err.Error()))
+ }
+ exitChan <- true
+}
+
func startSmFreeSWITCH(internalRaterChan, internalCDRSChan, rlsChan chan rpcclient.RpcClientConnection, cdrDb engine.CdrStorage, exitChan chan bool) {
- utils.Logger.Info("Starting CGRateS SMFreeSWITCH service.")
+ utils.Logger.Info("Starting CGRateS SMFreeSWITCH service")
var ralsConn, cdrsConn, rlsConn *rpcclient.RpcClientPool
if len(cfg.SmFsConfig.RALsConns) != 0 {
ralsConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout,
@@ -730,6 +761,10 @@ func main() {
go startDiameterAgent(internalSMGChan, internalPubSubSChan, exitChan)
}
+ if cfg.RadiusAgentCfg().Enabled {
+ go startRadiusAgent(internalSMGChan, exitChan)
+ }
+
// Start HistoryS service
if cfg.HistoryServerEnabled {
go startHistoryServer(internalHistorySChan, server, exitChan)
diff --git a/config/config_defaults.go b/config/config_defaults.go
index 4efc80674..c7a326679 100644
--- a/config/config_defaults.go
+++ b/config/config_defaults.go
@@ -359,7 +359,9 @@ const CGRATES_CFG_JSON = `
"listen_net": "udp", // network to listen on
"listen_auth": "127.0.0.1:1812", // address where to listen for radius authentication requests
"listen_acct": "127.0.0.1:1813", // address where to listen for radius accounting requests
- "client_secrets": {"*default": "CGRateS.org"}, // hash containing secrets for clients connecting here <*default|$client_ip>
+ "client_secrets": { // hash containing secrets for clients connecting here <*default|$client_ip>
+ "*default": "CGRateS.org"
+ },
"client_dictionaries": { // per client path towards directory holding additional dictionaries to load (extra to RFC)
"*default": "/usr/share/cgrates/radius/dict/", // key represents the client IP or catch-all <*default|$client_ip>
},
diff --git a/data/conf/samples/radagent/cgrates.json b/data/conf/samples/radagent/cgrates.json
new file mode 100644
index 000000000..ab571a016
--- /dev/null
+++ b/data/conf/samples/radagent/cgrates.json
@@ -0,0 +1,79 @@
+{
+// CGRateS Configuration file
+//
+// Used for cgradmin
+// Starts rater, scheduler
+
+"listen": {
+ "rpc_json": ":2012", // RPC JSON listening address
+ "rpc_gob": ":2013", // RPC GOB listening address
+ "http": ":2080", // HTTP listening address
+},
+
+"data_db": { // database used to store runtime data (eg: accounts, cdr stats)
+ "db_type": "mongo", // stor database type to use:
+ "db_port": 27017, // the port to reach the stordb
+ "db_name": "datadb",
+ "db_password": "",
+},
+
+"stor_db": {
+ "db_type": "mongo", // stor database type to use:
+ "db_port": 27017, // the port to reach the stordb
+ "db_name": "stordb",
+ "db_password": "",
+},
+
+"rals": {
+ "enabled": true,
+ "cdrstats_conns": [
+ {"address": "*internal"}
+ ],
+ "pubsubs_conns": [
+ {"address": "*internal"}
+ ],
+ "users_conns": [
+ {"address": "*internal"}
+ ],
+ "aliases_conns": [
+ {"address": "*internal"}
+ ],
+},
+
+"scheduler": {
+ "enabled": true,
+},
+
+"cdrs": {
+ "enabled": true,
+ "cdrstats_conns": [
+ {"address": "*internal"}
+ ],
+},
+
+"cdrstats": {
+ "enabled": true,
+},
+
+"pubsubs": {
+ "enabled": true, // starts PubSub service: .
+},
+
+"aliases": {
+ "enabled": true, // starts Aliases service: .
+},
+
+"users": {
+ "enabled": true,
+ "indexes": ["SubscriberId"],
+},
+
+"sm_generic": {
+ "enabled": true,
+},
+
+"radius_agent": {
+ "enabled": true,
+},
+
+}
diff --git a/glide.lock b/glide.lock
index 6dec8fdf7..0f91516f3 100644
--- a/glide.lock
+++ b/glide.lock
@@ -18,7 +18,7 @@ imports:
- name: github.com/cgrates/osipsdagram
version: 3d6beed663452471dec3ca194137a30d379d9e8f
- name: github.com/cgrates/radigo
- version: 8ee4c8409a0f8b8084d427dfb81010fd2add788c
+ version: b0690a5c829349f3c1bb0973f422788b870a9acc
- name: github.com/cgrates/rpcclient
version: dddae42e9344e877627cd4b7aba075d63b452c0b
- name: github.com/ChrisTrenkamp/goxpath