mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-17 06:09:53 +05:00
cfg: support multiple radius auth/acct listeners
This commit is contained in:
committed by
Dan Christian Bogos
parent
43e1630a55
commit
43930547b9
@@ -21,6 +21,7 @@ package agents
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/birpc/context"
|
||||
@@ -43,37 +44,56 @@ const (
|
||||
MSCHAP2SuccessAVP = "MS-CHAP2-Success"
|
||||
)
|
||||
|
||||
func NewRadiusAgent(cgrCfg *config.CGRConfig, filterS *engine.FilterS,
|
||||
connMgr *engine.ConnManager) (ra *RadiusAgent, err error) {
|
||||
dts := make(map[string]*radigo.Dictionary, len(cgrCfg.RadiusAgentCfg().ClientDictionaries))
|
||||
for clntID, dictPath := range cgrCfg.RadiusAgentCfg().ClientDictionaries {
|
||||
utils.Logger.Info(
|
||||
fmt.Sprintf("<%s> loading dictionary for clientID: <%s> out of path <%s>",
|
||||
utils.RadiusAgent, clntID, dictPath))
|
||||
if dts[clntID], err = radigo.NewDictionaryFromFoldersWithRFC2865(dictPath); err != nil {
|
||||
return
|
||||
func NewRadiusAgent(cfg *config.CGRConfig, fltrs *engine.FilterS,
|
||||
cm *engine.ConnManager) (*RadiusAgent, error) {
|
||||
ra := &RadiusAgent{
|
||||
cfg: cfg,
|
||||
fltrs: fltrs,
|
||||
cm: cm,
|
||||
}
|
||||
|
||||
raCfg := cfg.RadiusAgentCfg()
|
||||
dts := make(map[string]*radigo.Dictionary, len(raCfg.ClientDictionaries))
|
||||
for clntID, dictPath := range raCfg.ClientDictionaries {
|
||||
utils.Logger.Info(fmt.Sprintf(
|
||||
"<%s> loading dictionary for clientID %q out of path %q",
|
||||
utils.RadiusAgent, clntID, dictPath))
|
||||
dt, err := radigo.NewDictionaryFromFoldersWithRFC2865(dictPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dts[clntID] = dt
|
||||
}
|
||||
dicts := radigo.NewDictionaries(dts)
|
||||
ra = &RadiusAgent{cgrCfg: cgrCfg, filterS: filterS, connMgr: connMgr}
|
||||
secrets := radigo.NewSecrets(cgrCfg.RadiusAgentCfg().ClientSecrets)
|
||||
ra.rsAuth = radigo.NewServer(cgrCfg.RadiusAgentCfg().ListenNet,
|
||||
cgrCfg.RadiusAgentCfg().ListenAuth, secrets, dicts,
|
||||
map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){
|
||||
radigo.AccessRequest: ra.handleAuth}, nil, utils.Logger)
|
||||
ra.rsAcct = radigo.NewServer(cgrCfg.RadiusAgentCfg().ListenNet,
|
||||
cgrCfg.RadiusAgentCfg().ListenAcct, secrets, dicts,
|
||||
map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){
|
||||
radigo.AccountingRequest: ra.handleAcct}, nil, utils.Logger)
|
||||
return
|
||||
secrets := radigo.NewSecrets(raCfg.ClientSecrets)
|
||||
|
||||
ra.rsAuth = make(map[string]*radigo.Server, len(raCfg.Listeners))
|
||||
ra.rsAcct = make(map[string]*radigo.Server, len(raCfg.Listeners))
|
||||
for i := range raCfg.Listeners {
|
||||
net := raCfg.Listeners[i].Network
|
||||
authAddr := raCfg.Listeners[i].AuthAddr
|
||||
ra.rsAuth[net+"://"+authAddr] = radigo.NewServer(net, authAddr, secrets, dicts,
|
||||
map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){
|
||||
radigo.AccessRequest: ra.handleAuth,
|
||||
}, nil, utils.Logger)
|
||||
acctAddr := raCfg.Listeners[i].AcctAddr
|
||||
ra.rsAcct[net+"://"+acctAddr] = radigo.NewServer(net, acctAddr, secrets, dicts,
|
||||
map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){
|
||||
radigo.AccountingRequest: ra.handleAcct,
|
||||
}, nil, utils.Logger)
|
||||
}
|
||||
|
||||
return ra, nil
|
||||
}
|
||||
|
||||
type RadiusAgent struct {
|
||||
cgrCfg *config.CGRConfig // reference for future config reloads
|
||||
connMgr *engine.ConnManager
|
||||
filterS *engine.FilterS
|
||||
rsAuth *radigo.Server
|
||||
rsAcct *radigo.Server
|
||||
mu sync.RWMutex
|
||||
cfg *config.CGRConfig // reference for future config reloads
|
||||
cm *engine.ConnManager
|
||||
fltrs *engine.FilterS
|
||||
rsAuth map[string]*radigo.Server
|
||||
rsAcct map[string]*radigo.Server
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// handleAuth handles RADIUS Authorization request
|
||||
@@ -87,12 +107,12 @@ func (ra *RadiusAgent) handleAuth(req *radigo.Packet) (rpl *radigo.Packet, err e
|
||||
opts := utils.MapStorage{}
|
||||
var processed bool
|
||||
reqVars := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{utils.RemoteHost: utils.NewLeafNode(req.RemoteAddr().String())}}
|
||||
for _, reqProcessor := range ra.cgrCfg.RadiusAgentCfg().RequestProcessors {
|
||||
for _, reqProcessor := range ra.cfg.RadiusAgentCfg().RequestProcessors {
|
||||
agReq := NewAgentRequest(dcdr, reqVars, cgrRplyNM, rplyNM, opts,
|
||||
reqProcessor.Tenant, ra.cgrCfg.GeneralCfg().DefaultTenant,
|
||||
reqProcessor.Tenant, ra.cfg.GeneralCfg().DefaultTenant,
|
||||
utils.FirstNonEmpty(reqProcessor.Timezone,
|
||||
config.CgrConfig().GeneralCfg().DefaultTimezone),
|
||||
ra.filterS, nil)
|
||||
ra.fltrs, nil)
|
||||
agReq.Vars.Map[MetaRadReqType] = utils.NewLeafNode(MetaRadAuth)
|
||||
var lclProcessed bool
|
||||
if lclProcessed, err = ra.processRequest(req, reqProcessor, agReq, rpl); lclProcessed {
|
||||
@@ -132,12 +152,12 @@ func (ra *RadiusAgent) handleAcct(req *radigo.Packet) (rpl *radigo.Packet, err e
|
||||
opts := utils.MapStorage{}
|
||||
var processed bool
|
||||
reqVars := &utils.DataNode{Type: utils.NMMapType, Map: map[string]*utils.DataNode{utils.RemoteHost: utils.NewLeafNode(req.RemoteAddr().String())}}
|
||||
for _, reqProcessor := range ra.cgrCfg.RadiusAgentCfg().RequestProcessors {
|
||||
for _, reqProcessor := range ra.cfg.RadiusAgentCfg().RequestProcessors {
|
||||
agReq := NewAgentRequest(dcdr, reqVars, cgrRplyNM, rplyNM, opts,
|
||||
reqProcessor.Tenant, ra.cgrCfg.GeneralCfg().DefaultTenant,
|
||||
reqProcessor.Tenant, ra.cfg.GeneralCfg().DefaultTenant,
|
||||
utils.FirstNonEmpty(reqProcessor.Timezone,
|
||||
config.CgrConfig().GeneralCfg().DefaultTimezone),
|
||||
ra.filterS, nil)
|
||||
ra.fltrs, nil)
|
||||
var lclProcessed bool
|
||||
if lclProcessed, err = ra.processRequest(req, reqProcessor, agReq, rpl); lclProcessed {
|
||||
processed = lclProcessed
|
||||
@@ -167,7 +187,7 @@ func (ra *RadiusAgent) handleAcct(req *radigo.Packet) (rpl *radigo.Packet, err e
|
||||
func (ra *RadiusAgent) processRequest(req *radigo.Packet, reqProcessor *config.RequestProcessor,
|
||||
agReq *AgentRequest, rpl *radigo.Packet) (processed bool, err error) {
|
||||
startTime := time.Now()
|
||||
if pass, err := ra.filterS.Pass(context.TODO(), agReq.Tenant,
|
||||
if pass, err := ra.fltrs.Pass(context.TODO(), agReq.Tenant,
|
||||
reqProcessor.Filters, agReq); err != nil || !pass {
|
||||
return pass, err
|
||||
}
|
||||
@@ -202,30 +222,30 @@ func (ra *RadiusAgent) processRequest(req *radigo.Packet, reqProcessor *config.R
|
||||
utils.RadiusAgent, reqProcessor.ID, utils.ToJSON(cgrEv)))
|
||||
case utils.MetaAuthorize:
|
||||
rply := new(sessions.V1AuthorizeReply)
|
||||
err = ra.connMgr.Call(context.TODO(), ra.cgrCfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1AuthorizeEvent,
|
||||
err = ra.cm.Call(context.TODO(), ra.cfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1AuthorizeEvent,
|
||||
cgrEv, rply)
|
||||
rply.SetMaxUsageNeeded(utils.OptAsBool(cgrEv.APIOpts, utils.MetaAccounts))
|
||||
agReq.setCGRReply(rply, err)
|
||||
case utils.MetaInitiate:
|
||||
rply := new(sessions.V1InitSessionReply)
|
||||
err = ra.connMgr.Call(context.TODO(), ra.cgrCfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1InitiateSession,
|
||||
err = ra.cm.Call(context.TODO(), ra.cfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1InitiateSession,
|
||||
cgrEv, rply)
|
||||
rply.SetMaxUsageNeeded(utils.OptAsBool(cgrEv.APIOpts, utils.OptsSesInitiate))
|
||||
agReq.setCGRReply(rply, err)
|
||||
case utils.MetaUpdate:
|
||||
rply := new(sessions.V1UpdateSessionReply)
|
||||
err = ra.connMgr.Call(context.TODO(), ra.cgrCfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1UpdateSession,
|
||||
err = ra.cm.Call(context.TODO(), ra.cfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1UpdateSession,
|
||||
cgrEv, rply)
|
||||
rply.SetMaxUsageNeeded(utils.OptAsBool(cgrEv.APIOpts, utils.OptsSesUpdate))
|
||||
agReq.setCGRReply(rply, err)
|
||||
case utils.MetaTerminate:
|
||||
var rply string
|
||||
err = ra.connMgr.Call(context.TODO(), ra.cgrCfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1TerminateSession,
|
||||
err = ra.cm.Call(context.TODO(), ra.cfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1TerminateSession,
|
||||
cgrEv, &rply)
|
||||
agReq.setCGRReply(nil, err)
|
||||
case utils.MetaMessage:
|
||||
rply := new(sessions.V1ProcessMessageReply)
|
||||
err = ra.connMgr.Call(context.TODO(), ra.cgrCfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1ProcessMessage, cgrEv, rply)
|
||||
err = ra.cm.Call(context.TODO(), ra.cfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1ProcessMessage, cgrEv, rply)
|
||||
// if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
|
||||
// cgrEv.Event[utils.Usage] = 0 // avoid further debits
|
||||
// } else
|
||||
@@ -237,7 +257,7 @@ func (ra *RadiusAgent) processRequest(req *radigo.Packet, reqProcessor *config.R
|
||||
agReq.setCGRReply(rply, err)
|
||||
case utils.MetaEvent:
|
||||
rply := new(sessions.V1ProcessEventReply)
|
||||
err = ra.connMgr.Call(context.TODO(), ra.cgrCfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1ProcessEvent,
|
||||
err = ra.cm.Call(context.TODO(), ra.cfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1ProcessEvent,
|
||||
cgrEv, rply)
|
||||
// if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
|
||||
// cgrEv.Event[utils.Usage] = 0 // avoid further debits
|
||||
@@ -257,7 +277,7 @@ func (ra *RadiusAgent) processRequest(req *radigo.Packet, reqProcessor *config.R
|
||||
// separate request so we can capture the Terminate/Event also here
|
||||
if reqProcessor.Flags.GetBool(utils.MetaCDRs) {
|
||||
var rplyCDRs string
|
||||
if err = ra.connMgr.Call(context.TODO(), ra.cgrCfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1ProcessCDR,
|
||||
if err = ra.cm.Call(context.TODO(), ra.cfg.RadiusAgentCfg().SessionSConns, utils.SessionSv1ProcessCDR,
|
||||
cgrEv, &rplyCDRs); err != nil {
|
||||
agReq.CGRReply.Map[utils.Error] = utils.NewLeafNode(err.Error())
|
||||
}
|
||||
@@ -303,7 +323,7 @@ func (ra *RadiusAgent) processRequest(req *radigo.Packet, reqProcessor *config.R
|
||||
statIDs := strings.Split(rawStatIDs, utils.ANDSep)
|
||||
ev.APIOpts[utils.OptsStatsProfileIDs] = statIDs
|
||||
var reply []string
|
||||
if err := ra.connMgr.Call(context.TODO(), ra.cgrCfg.RadiusAgentCfg().StatSConns,
|
||||
if err := ra.cm.Call(context.TODO(), ra.cfg.RadiusAgentCfg().StatSConns,
|
||||
utils.StatSv1ProcessEvent, ev, &reply); err != nil {
|
||||
return false, fmt.Errorf("failed to process %s event in %s: %v",
|
||||
utils.RadiusAgent, utils.StatS, err)
|
||||
@@ -315,7 +335,7 @@ func (ra *RadiusAgent) processRequest(req *radigo.Packet, reqProcessor *config.R
|
||||
thIDs := strings.Split(rawThIDs, utils.ANDSep)
|
||||
ev.APIOpts[utils.OptsThresholdsProfileIDs] = thIDs
|
||||
var reply []string
|
||||
if err := ra.connMgr.Call(context.TODO(), ra.cgrCfg.RadiusAgentCfg().ThresholdSConns,
|
||||
if err := ra.cm.Call(context.TODO(), ra.cfg.RadiusAgentCfg().ThresholdSConns,
|
||||
utils.ThresholdSv1ProcessEvent, ev, &reply); err != nil {
|
||||
return false, fmt.Errorf("failed to process %s event in %s: %v",
|
||||
utils.RadiusAgent, utils.ThresholdS, err)
|
||||
@@ -326,18 +346,38 @@ func (ra *RadiusAgent) processRequest(req *radigo.Packet, reqProcessor *config.R
|
||||
|
||||
func (ra *RadiusAgent) ListenAndServe(stopChan <-chan struct{}) (err error) {
|
||||
errListen := make(chan error, 2)
|
||||
go func() {
|
||||
utils.Logger.Info(fmt.Sprintf("<%s> Start listening for auth requests on <%s>", utils.RadiusAgent, ra.cgrCfg.RadiusAgentCfg().ListenAuth))
|
||||
if err := ra.rsAuth.ListenAndServe(stopChan); err != nil {
|
||||
errListen <- err
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
utils.Logger.Info(fmt.Sprintf("<%s> Start listening for acct req on <%s>", utils.RadiusAgent, ra.cgrCfg.RadiusAgentCfg().ListenAcct))
|
||||
if err := ra.rsAcct.ListenAndServe(stopChan); err != nil {
|
||||
errListen <- err
|
||||
}
|
||||
}()
|
||||
for uri, server := range ra.rsAuth {
|
||||
ra.wg.Add(1)
|
||||
go func(srv *radigo.Server, uri string) {
|
||||
defer ra.wg.Done()
|
||||
utils.Logger.Info(fmt.Sprintf("<%s> Start listening for auth requests on <%s>", utils.RadiusAgent, uri))
|
||||
if err := srv.ListenAndServe(stopChan); err != nil {
|
||||
utils.Logger.Warning(fmt.Sprintf("<%s> error <%v>, on ListenAndServe <%s>",
|
||||
utils.RadiusAgent, err, uri))
|
||||
if strings.Contains(err.Error(), "address already in use") {
|
||||
return
|
||||
}
|
||||
errListen <- err
|
||||
}
|
||||
}(server, uri)
|
||||
}
|
||||
for uri, server := range ra.rsAcct {
|
||||
ra.wg.Add(1)
|
||||
go func(srv *radigo.Server, uri string) {
|
||||
defer ra.wg.Done()
|
||||
utils.Logger.Info(fmt.Sprintf("<%s> Start listening for acct requests on <%s>", utils.RadiusAgent, uri))
|
||||
if err := srv.ListenAndServe(stopChan); err != nil {
|
||||
utils.Logger.Warning(fmt.Sprintf("<%s> error <%v>, on ListenAndServe <%s>",
|
||||
utils.RadiusAgent, err, uri))
|
||||
if strings.Contains(err.Error(), "address already in use") {
|
||||
return
|
||||
}
|
||||
errListen <- err
|
||||
}
|
||||
}(server, uri)
|
||||
}
|
||||
err = <-errListen
|
||||
return
|
||||
}
|
||||
|
||||
func (ra *RadiusAgent) Wait() { ra.wg.Wait() }
|
||||
|
||||
@@ -1040,9 +1040,13 @@ const CGRATES_CFG_JSON = `
|
||||
|
||||
"radius_agent": {
|
||||
"enabled": false, // enables the radius agent: <true|false>
|
||||
"listen_net": "udp", // network to listen on <udp|tcp>
|
||||
"listen_auth": "127.0.0.1:1812", // address where to listen for radius authentication requests <x.y.z.y:1234>
|
||||
"listen_acct": "127.0.0.1:1813", // address where to listen for radius accounting requests <x.y.z.y:1234>
|
||||
"listeners":[
|
||||
{
|
||||
"network": "udp", // network to listen on <udp|tcp>
|
||||
"auth_address": "127.0.0.1:1812", // address where to listen for radius authentication requests <x.y.z.y:1234>
|
||||
"acct_address": "127.0.0.1:1813" // address where to listen for radius accounting requests <x.y.z.y:1234>
|
||||
}
|
||||
],
|
||||
"client_secrets": { // hash containing secrets for clients connecting here <*default|$client_ip>
|
||||
"*default": "CGRateS.org"
|
||||
},
|
||||
|
||||
@@ -761,10 +761,14 @@ func TestDiameterAgentJsonCfg(t *testing.T) {
|
||||
|
||||
func TestRadiusAgentJsonCfg(t *testing.T) {
|
||||
eCfg := &RadiusAgentJsonCfg{
|
||||
Enabled: utils.BoolPointer(false),
|
||||
ListenNet: utils.StringPointer("udp"),
|
||||
ListenAuth: utils.StringPointer("127.0.0.1:1812"),
|
||||
ListenAcct: utils.StringPointer("127.0.0.1:1813"),
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Listeners: &[]*RadiusListenerJsonCfg{
|
||||
{
|
||||
Network: utils.StringPointer("udp"),
|
||||
AuthAddress: utils.StringPointer("127.0.0.1:1812"),
|
||||
AcctAddress: utils.StringPointer("127.0.0.1:1813"),
|
||||
},
|
||||
},
|
||||
ClientSecrets: map[string]string{
|
||||
utils.MetaDefault: "CGRateS.org",
|
||||
},
|
||||
|
||||
File diff suppressed because one or more lines are too long
125
config/radius.go
125
config/radius.go
@@ -19,20 +19,32 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package config
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
"github.com/cgrates/birpc/context"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
type RadiusListener struct {
|
||||
AuthAddr string
|
||||
AcctAddr string
|
||||
Network string // udp or tcp
|
||||
}
|
||||
|
||||
// AsMapInterface returns the config as a map[string]any.
|
||||
func (lstn *RadiusListener) AsMapInterface() map[string]any {
|
||||
return map[string]any{
|
||||
utils.AuthAddrCfg: lstn.AuthAddr,
|
||||
utils.AcctAddrCfg: lstn.AcctAddr,
|
||||
utils.NetworkCfg: lstn.Network,
|
||||
}
|
||||
}
|
||||
|
||||
// RadiusAgentCfg the config section that describes the Radius Agent
|
||||
type RadiusAgentCfg struct {
|
||||
Enabled bool
|
||||
ListenNet string // udp or tcp
|
||||
ListenAuth string
|
||||
ListenAcct string
|
||||
Listeners []RadiusListener
|
||||
ClientSecrets map[string]string
|
||||
ClientDictionaries map[string][]string
|
||||
SessionSConns []string
|
||||
@@ -50,34 +62,41 @@ func (ra *RadiusAgentCfg) Load(ctx *context.Context, jsnCfg ConfigDB, _ *CGRConf
|
||||
return ra.loadFromJSONCfg(jsnRACfg)
|
||||
}
|
||||
|
||||
func (ra *RadiusAgentCfg) loadFromJSONCfg(jsnCfg *RadiusAgentJsonCfg) (err error) {
|
||||
if jsnCfg == nil {
|
||||
func (ra *RadiusAgentCfg) loadFromJSONCfg(jc *RadiusAgentJsonCfg) (err error) {
|
||||
if jc == nil {
|
||||
return nil
|
||||
}
|
||||
if jsnCfg.Enabled != nil {
|
||||
ra.Enabled = *jsnCfg.Enabled
|
||||
if jc.Enabled != nil {
|
||||
ra.Enabled = *jc.Enabled
|
||||
}
|
||||
if jsnCfg.ListenNet != nil {
|
||||
ra.ListenNet = *jsnCfg.ListenNet
|
||||
if jc.Listeners != nil {
|
||||
ra.Listeners = make([]RadiusListener, 0, len(*jc.Listeners))
|
||||
for _, jl := range *jc.Listeners {
|
||||
var rl RadiusListener
|
||||
if jl.AuthAddress != nil {
|
||||
rl.AuthAddr = *jl.AuthAddress
|
||||
}
|
||||
if jl.AcctAddress != nil {
|
||||
rl.AcctAddr = *jl.AcctAddress
|
||||
}
|
||||
if jl.Network != nil {
|
||||
rl.Network = *jl.Network
|
||||
}
|
||||
ra.Listeners = append(ra.Listeners, rl)
|
||||
}
|
||||
}
|
||||
if jsnCfg.ListenAuth != nil {
|
||||
ra.ListenAuth = *jsnCfg.ListenAuth
|
||||
maps.Copy(ra.ClientSecrets, jc.ClientSecrets)
|
||||
maps.Copy(ra.ClientDictionaries, jc.ClientDictionaries)
|
||||
if jc.SessionSConns != nil {
|
||||
ra.SessionSConns = tagInternalConns(*jc.SessionSConns, utils.MetaSessionS)
|
||||
}
|
||||
if jsnCfg.ListenAcct != nil {
|
||||
ra.ListenAcct = *jsnCfg.ListenAcct
|
||||
if jc.StatSConns != nil {
|
||||
ra.StatSConns = tagInternalConns(*jc.StatSConns, utils.MetaStats)
|
||||
}
|
||||
maps.Copy(ra.ClientSecrets, jsnCfg.ClientSecrets)
|
||||
maps.Copy(ra.ClientDictionaries, jsnCfg.ClientDictionaries)
|
||||
if jsnCfg.SessionSConns != nil {
|
||||
ra.SessionSConns = tagInternalConns(*jsnCfg.SessionSConns, utils.MetaSessionS)
|
||||
if jc.ThresholdSConns != nil {
|
||||
ra.ThresholdSConns = tagInternalConns(*jc.ThresholdSConns, utils.MetaThresholds)
|
||||
}
|
||||
if jsnCfg.StatSConns != nil {
|
||||
ra.StatSConns = tagInternalConns(*jsnCfg.StatSConns, utils.MetaStats)
|
||||
}
|
||||
if jsnCfg.ThresholdSConns != nil {
|
||||
ra.ThresholdSConns = tagInternalConns(*jsnCfg.ThresholdSConns, utils.MetaThresholds)
|
||||
}
|
||||
ra.RequestProcessors, err = appendRequestProcessors(ra.RequestProcessors, jsnCfg.RequestProcessors)
|
||||
ra.RequestProcessors, err = appendRequestProcessors(ra.RequestProcessors, jc.RequestProcessors)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -87,11 +106,13 @@ func (ra RadiusAgentCfg) AsMapInterface() any {
|
||||
for i, item := range ra.RequestProcessors {
|
||||
requestProcessors[i] = item.AsMapInterface()
|
||||
}
|
||||
listeners := make([]map[string]any, len(ra.Listeners))
|
||||
for i, item := range ra.Listeners {
|
||||
listeners[i] = item.AsMapInterface()
|
||||
}
|
||||
mp := map[string]any{
|
||||
utils.EnabledCfg: ra.Enabled,
|
||||
utils.ListenNetCfg: ra.ListenNet,
|
||||
utils.ListenAuthCfg: ra.ListenAuth,
|
||||
utils.ListenAcctCfg: ra.ListenAcct,
|
||||
utils.ListenersCfg: listeners,
|
||||
utils.ClientSecretsCfg: maps.Clone(ra.ClientSecrets),
|
||||
utils.ClientDictionariesCfg: maps.Clone(ra.ClientDictionaries),
|
||||
utils.SessionSConnsCfg: stripInternalConns(ra.SessionSConns),
|
||||
@@ -109,9 +130,7 @@ func (ra RadiusAgentCfg) CloneSection() Section { return ra.Clone() }
|
||||
func (ra RadiusAgentCfg) Clone() *RadiusAgentCfg {
|
||||
clone := &RadiusAgentCfg{
|
||||
Enabled: ra.Enabled,
|
||||
ListenNet: ra.ListenNet,
|
||||
ListenAuth: ra.ListenAuth,
|
||||
ListenAcct: ra.ListenAcct,
|
||||
Listeners: slices.Clone(ra.Listeners),
|
||||
ClientSecrets: maps.Clone(ra.ClientSecrets),
|
||||
SessionSConns: slices.Clone(ra.SessionSConns),
|
||||
StatSConns: slices.Clone(ra.StatSConns),
|
||||
@@ -132,18 +151,22 @@ func (ra RadiusAgentCfg) Clone() *RadiusAgentCfg {
|
||||
return clone
|
||||
}
|
||||
|
||||
type RadiusListenerJsonCfg struct {
|
||||
Network *string `json:"network"`
|
||||
AuthAddress *string `json:"auth_address"`
|
||||
AcctAddress *string `json:"acct_address"`
|
||||
}
|
||||
|
||||
// Radius Agent configuration section
|
||||
type RadiusAgentJsonCfg struct {
|
||||
Enabled *bool `json:"enabled"`
|
||||
ListenNet *string `json:"listen_net"`
|
||||
ListenAuth *string `json:"listen_auth"`
|
||||
ListenAcct *string `json:"listen_acct"`
|
||||
ClientSecrets map[string]string `json:"client_secrets"`
|
||||
ClientDictionaries map[string][]string `json:"client_dictionaries"`
|
||||
SessionSConns *[]string `json:"sessions_conns"`
|
||||
StatSConns *[]string `json:"stats_conns"`
|
||||
ThresholdSConns *[]string `json:"thresholds_conns"`
|
||||
RequestProcessors *[]*ReqProcessorJsnCfg `json:"request_processors"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
Listeners *[]*RadiusListenerJsonCfg `json:"listeners"`
|
||||
ClientSecrets map[string]string `json:"client_secrets"`
|
||||
ClientDictionaries map[string][]string `json:"client_dictionaries"`
|
||||
SessionSConns *[]string `json:"sessions_conns"`
|
||||
StatSConns *[]string `json:"stats_conns"`
|
||||
ThresholdSConns *[]string `json:"thresholds_conns"`
|
||||
RequestProcessors *[]*ReqProcessorJsnCfg `json:"request_processors"`
|
||||
}
|
||||
|
||||
func diffRadiusAgentJsonCfg(d *RadiusAgentJsonCfg, v1, v2 *RadiusAgentCfg) *RadiusAgentJsonCfg {
|
||||
@@ -153,14 +176,16 @@ func diffRadiusAgentJsonCfg(d *RadiusAgentJsonCfg, v1, v2 *RadiusAgentCfg) *Radi
|
||||
if v1.Enabled != v2.Enabled {
|
||||
d.Enabled = utils.BoolPointer(v2.Enabled)
|
||||
}
|
||||
if v1.ListenNet != v2.ListenNet {
|
||||
d.ListenNet = utils.StringPointer(v2.ListenNet)
|
||||
}
|
||||
if v1.ListenAuth != v2.ListenAuth {
|
||||
d.ListenAuth = utils.StringPointer(v2.ListenAuth)
|
||||
}
|
||||
if v1.ListenAcct != v2.ListenAcct {
|
||||
d.ListenAcct = utils.StringPointer(v2.ListenAcct)
|
||||
if !slices.Equal(v1.Listeners, v2.Listeners) {
|
||||
listeners := make([]*RadiusListenerJsonCfg, len(v2.Listeners))
|
||||
for i, listener := range v2.Listeners {
|
||||
listeners[i] = &RadiusListenerJsonCfg{
|
||||
AuthAddress: utils.StringPointer(listener.AuthAddr),
|
||||
AcctAddress: utils.StringPointer(listener.AcctAddr),
|
||||
Network: utils.StringPointer(listener.Network),
|
||||
}
|
||||
}
|
||||
d.Listeners = &listeners
|
||||
}
|
||||
d.ClientSecrets = diffMapString(d.ClientSecrets, v1.ClientSecrets, v2.ClientSecrets)
|
||||
d.ClientDictionaries = diffMapStringSlice(d.ClientDictionaries, v1.ClientDictionaries, v2.ClientDictionaries)
|
||||
|
||||
@@ -28,10 +28,14 @@ import (
|
||||
|
||||
func TestRadiusAgentCfgloadFromJsonCfgCase1(t *testing.T) {
|
||||
cfgJSON := &RadiusAgentJsonCfg{
|
||||
Enabled: utils.BoolPointer(true),
|
||||
ListenNet: utils.StringPointer(utils.UDP),
|
||||
ListenAuth: utils.StringPointer("127.0.0.1:1812"),
|
||||
ListenAcct: utils.StringPointer("127.0.0.1:1813"),
|
||||
Enabled: utils.BoolPointer(true),
|
||||
Listeners: &[]*RadiusListenerJsonCfg{
|
||||
{
|
||||
Network: utils.StringPointer(utils.UDP),
|
||||
AuthAddress: utils.StringPointer("127.0.0.1:1812"),
|
||||
AcctAddress: utils.StringPointer("127.0.0.1:1813"),
|
||||
},
|
||||
},
|
||||
ClientSecrets: map[string]string{utils.MetaDefault: "CGRateS.org"},
|
||||
ClientDictionaries: map[string][]string{utils.MetaDefault: {"/usr/share/cgrates/radius/dict/"}},
|
||||
SessionSConns: &[]string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)},
|
||||
@@ -59,10 +63,14 @@ func TestRadiusAgentCfgloadFromJsonCfgCase1(t *testing.T) {
|
||||
},
|
||||
}
|
||||
expected := &RadiusAgentCfg{
|
||||
Enabled: true,
|
||||
ListenNet: "udp",
|
||||
ListenAuth: "127.0.0.1:1812",
|
||||
ListenAcct: "127.0.0.1:1813",
|
||||
Enabled: true,
|
||||
Listeners: []RadiusListener{
|
||||
{
|
||||
Network: utils.UDP,
|
||||
AuthAddr: "127.0.0.1:1812",
|
||||
AcctAddr: "127.0.0.1:1813",
|
||||
},
|
||||
},
|
||||
ClientSecrets: map[string]string{utils.MetaDefault: "CGRateS.org"},
|
||||
ClientDictionaries: map[string][]string{utils.MetaDefault: {"/usr/share/cgrates/radius/dict/"}},
|
||||
SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)},
|
||||
@@ -155,38 +163,46 @@ func TestRadiusAgentCfgloadFromJsonCfgCase3(t *testing.T) {
|
||||
|
||||
func TestRadiusAgentCfgAsMapInterface(t *testing.T) {
|
||||
cfgJSONStr := `{
|
||||
"radius_agent": {
|
||||
"enabled": true,
|
||||
"listen_auth": "127.0.0.1:1816",
|
||||
"listen_acct": "127.0.0.1:1892",
|
||||
|
||||
"client_dictionaries": {
|
||||
"*default": [
|
||||
"/usr/share/cgrates/"
|
||||
]
|
||||
},
|
||||
"sessions_conns": ["*birpc_internal", "*conn1","*conn2"],
|
||||
"stats_conns": ["*internal", "*conn1","*conn2"],
|
||||
"thresholds_conns": ["*internal", "*conn1","*conn2"],
|
||||
"request_processors": [
|
||||
{
|
||||
"id": "OutboundAUTHDryRun",
|
||||
"filters": ["*string:~*req.request_type:OutboundAUTH","*string:~*req.Msisdn:497700056231"],
|
||||
"tenant": "cgrates.org",
|
||||
"flags": ["*dryRun"],
|
||||
"request_fields":[],
|
||||
"reply_fields":[
|
||||
{"tag": "Allow", "path": "*rep.response.Allow", "type": "*constant",
|
||||
"value": "1", "mandatory": true},
|
||||
],
|
||||
},],
|
||||
},
|
||||
"radius_agent": {
|
||||
"enabled": true,
|
||||
"listeners":[
|
||||
{
|
||||
"network": "udp",
|
||||
"auth_address": "127.0.0.1:1816",
|
||||
"acct_address": "127.0.0.1:1892"
|
||||
}
|
||||
],
|
||||
"client_dictionaries": {
|
||||
"*default": [
|
||||
"/usr/share/cgrates/"
|
||||
]
|
||||
},
|
||||
"sessions_conns": ["*birpc_internal", "*conn1","*conn2"],
|
||||
"stats_conns": ["*internal", "*conn1","*conn2"],
|
||||
"thresholds_conns": ["*internal", "*conn1","*conn2"],
|
||||
"request_processors": [
|
||||
{
|
||||
"id": "OutboundAUTHDryRun",
|
||||
"filters": ["*string:~*req.request_type:OutboundAUTH","*string:~*req.Msisdn:497700056231"],
|
||||
"tenant": "cgrates.org",
|
||||
"flags": ["*dryRun"],
|
||||
"request_fields":[],
|
||||
"reply_fields":[
|
||||
{"tag": "Allow", "path": "*rep.response.Allow", "type": "*constant", "value": "1", "mandatory": true},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}`
|
||||
eMap := map[string]any{
|
||||
utils.EnabledCfg: true,
|
||||
utils.ListenNetCfg: "udp",
|
||||
utils.ListenAuthCfg: "127.0.0.1:1816",
|
||||
utils.ListenAcctCfg: "127.0.0.1:1892",
|
||||
utils.EnabledCfg: true,
|
||||
utils.ListenersCfg: []map[string]any{
|
||||
{
|
||||
utils.NetworkCfg: utils.UDP,
|
||||
utils.AuthAddrCfg: "127.0.0.1:1816",
|
||||
utils.AcctAddrCfg: "127.0.0.1:1892",
|
||||
},
|
||||
},
|
||||
utils.ClientSecretsCfg: map[string]string{
|
||||
utils.MetaDefault: "CGRateS.org",
|
||||
},
|
||||
@@ -222,10 +238,14 @@ func TestRadiusAgentCfgAsMapInterface1(t *testing.T) {
|
||||
"radius_agent": {},
|
||||
}`
|
||||
eMap := map[string]any{
|
||||
utils.EnabledCfg: false,
|
||||
utils.ListenNetCfg: "udp",
|
||||
utils.ListenAuthCfg: "127.0.0.1:1812",
|
||||
utils.ListenAcctCfg: "127.0.0.1:1813",
|
||||
utils.EnabledCfg: false,
|
||||
utils.ListenersCfg: []map[string]any{
|
||||
{
|
||||
utils.NetworkCfg: utils.UDP,
|
||||
utils.AuthAddrCfg: "127.0.0.1:1812",
|
||||
utils.AcctAddrCfg: "127.0.0.1:1813",
|
||||
},
|
||||
},
|
||||
utils.ClientSecretsCfg: map[string]string{
|
||||
utils.MetaDefault: "CGRateS.org",
|
||||
},
|
||||
@@ -246,10 +266,14 @@ func TestRadiusAgentCfgAsMapInterface1(t *testing.T) {
|
||||
|
||||
func TestRadiusAgentCfgClone(t *testing.T) {
|
||||
ban := &RadiusAgentCfg{
|
||||
Enabled: true,
|
||||
ListenNet: "udp",
|
||||
ListenAuth: "127.0.0.1:1812",
|
||||
ListenAcct: "127.0.0.1:1813",
|
||||
Enabled: true,
|
||||
Listeners: []RadiusListener{
|
||||
{
|
||||
Network: utils.UDP,
|
||||
AuthAddr: "127.0.0.1:1812",
|
||||
AcctAddr: "127.0.0.1:1813",
|
||||
},
|
||||
},
|
||||
ClientSecrets: map[string]string{utils.MetaDefault: "CGRateS.org"},
|
||||
ClientDictionaries: map[string][]string{utils.MetaDefault: {"/usr/share/cgrates/radius/dict/"}},
|
||||
SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"},
|
||||
@@ -296,10 +320,14 @@ func TestDiffRadiusAgentJsonCfg(t *testing.T) {
|
||||
var d *RadiusAgentJsonCfg
|
||||
|
||||
v1 := &RadiusAgentCfg{
|
||||
Enabled: false,
|
||||
ListenNet: "tcp",
|
||||
ListenAuth: "radius_auth",
|
||||
ListenAcct: "radius_account",
|
||||
Enabled: false,
|
||||
Listeners: []RadiusListener{
|
||||
{
|
||||
Network: utils.TCP,
|
||||
AuthAddr: "radius_auth",
|
||||
AcctAddr: "radius_account",
|
||||
},
|
||||
},
|
||||
ClientSecrets: map[string]string{},
|
||||
ClientDictionaries: map[string][]string{},
|
||||
SessionSConns: []string{"*localhost"},
|
||||
@@ -309,10 +337,14 @@ func TestDiffRadiusAgentJsonCfg(t *testing.T) {
|
||||
}
|
||||
|
||||
v2 := &RadiusAgentCfg{
|
||||
Enabled: true,
|
||||
ListenNet: "udp",
|
||||
ListenAuth: "radius_auth2",
|
||||
ListenAcct: "radius_account2",
|
||||
Enabled: true,
|
||||
Listeners: []RadiusListener{
|
||||
{
|
||||
Network: utils.UDP,
|
||||
AuthAddr: "radius_auth2",
|
||||
AcctAddr: "radius_account2",
|
||||
},
|
||||
},
|
||||
ClientSecrets: map[string]string{
|
||||
"radius_user": "radius_pass",
|
||||
},
|
||||
@@ -331,10 +363,14 @@ func TestDiffRadiusAgentJsonCfg(t *testing.T) {
|
||||
}
|
||||
|
||||
expected := &RadiusAgentJsonCfg{
|
||||
Enabled: utils.BoolPointer(true),
|
||||
ListenNet: utils.StringPointer("udp"),
|
||||
ListenAuth: utils.StringPointer("radius_auth2"),
|
||||
ListenAcct: utils.StringPointer("radius_account2"),
|
||||
Enabled: utils.BoolPointer(true),
|
||||
Listeners: &[]*RadiusListenerJsonCfg{
|
||||
{
|
||||
Network: utils.StringPointer(utils.UDP),
|
||||
AuthAddress: utils.StringPointer("radius_auth2"),
|
||||
AcctAddress: utils.StringPointer("radius_account2"),
|
||||
},
|
||||
},
|
||||
ClientSecrets: map[string]string{
|
||||
"radius_user": "radius_pass",
|
||||
},
|
||||
@@ -373,10 +409,14 @@ func TestDiffRadiusAgentJsonCfg(t *testing.T) {
|
||||
|
||||
func TestRadiusAgentCloneSection(t *testing.T) {
|
||||
rdagCfg := &RadiusAgentCfg{
|
||||
Enabled: true,
|
||||
ListenNet: "udp",
|
||||
ListenAuth: "radius_auth2",
|
||||
ListenAcct: "radius_account2",
|
||||
Enabled: true,
|
||||
Listeners: []RadiusListener{
|
||||
{
|
||||
Network: utils.UDP,
|
||||
AuthAddr: "radius_auth2",
|
||||
AcctAddr: "radius_account2",
|
||||
},
|
||||
},
|
||||
ClientSecrets: map[string]string{
|
||||
"radius_user": "radius_pass",
|
||||
},
|
||||
@@ -395,10 +435,14 @@ func TestRadiusAgentCloneSection(t *testing.T) {
|
||||
}
|
||||
|
||||
exp := &RadiusAgentCfg{
|
||||
Enabled: true,
|
||||
ListenNet: "udp",
|
||||
ListenAuth: "radius_auth2",
|
||||
ListenAcct: "radius_account2",
|
||||
Enabled: true,
|
||||
Listeners: []RadiusListener{
|
||||
{
|
||||
Network: utils.UDP,
|
||||
AuthAddr: "radius_auth2",
|
||||
AcctAddr: "radius_account2",
|
||||
},
|
||||
},
|
||||
ClientSecrets: map[string]string{
|
||||
"radius_user": "radius_pass",
|
||||
},
|
||||
|
||||
@@ -42,9 +42,6 @@ type RadiusAgent struct {
|
||||
cfg *config.CGRConfig
|
||||
stopChan chan struct{}
|
||||
rad *agents.RadiusAgent
|
||||
lnet string
|
||||
lauth string
|
||||
lacct string
|
||||
stateDeps *StateDependencies // channel subscriptions for state changes
|
||||
}
|
||||
|
||||
@@ -65,10 +62,6 @@ func (rad *RadiusAgent) Start(shutdown *utils.SyncedChan, registry *servmanager.
|
||||
rad.mu.Lock()
|
||||
defer rad.mu.Unlock()
|
||||
|
||||
rad.lnet = rad.cfg.RadiusAgentCfg().ListenNet
|
||||
rad.lauth = rad.cfg.RadiusAgentCfg().ListenAuth
|
||||
rad.lacct = rad.cfg.RadiusAgentCfg().ListenAcct
|
||||
|
||||
if rad.rad, err = agents.NewRadiusAgent(rad.cfg, fs.FilterS(), cms.ConnManager()); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -88,27 +81,21 @@ func (rad *RadiusAgent) listenAndServe(r *agents.RadiusAgent, shutdown *utils.Sy
|
||||
|
||||
// Reload handles the change of config
|
||||
func (rad *RadiusAgent) Reload(shutdown *utils.SyncedChan, registry *servmanager.ServiceRegistry) (err error) {
|
||||
if rad.lnet == rad.cfg.RadiusAgentCfg().ListenNet &&
|
||||
rad.lauth == rad.cfg.RadiusAgentCfg().ListenAuth &&
|
||||
rad.lacct == rad.cfg.RadiusAgentCfg().ListenAcct {
|
||||
return
|
||||
}
|
||||
|
||||
rad.shutdown()
|
||||
rad.Shutdown(registry)
|
||||
return rad.Start(shutdown, registry)
|
||||
}
|
||||
|
||||
// Shutdown stops the service
|
||||
func (rad *RadiusAgent) Shutdown(_ *servmanager.ServiceRegistry) (err error) {
|
||||
rad.shutdown()
|
||||
return // no shutdown for the momment
|
||||
}
|
||||
|
||||
func (rad *RadiusAgent) shutdown() {
|
||||
func (rad *RadiusAgent) Shutdown(_ *servmanager.ServiceRegistry) error {
|
||||
if rad.rad == nil {
|
||||
return nil
|
||||
}
|
||||
close(rad.stopChan)
|
||||
rad.rad.Wait()
|
||||
rad.mu.Lock()
|
||||
defer rad.mu.Unlock()
|
||||
close(rad.stopChan)
|
||||
rad.rad = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServiceName returns the service name
|
||||
|
||||
@@ -2258,8 +2258,8 @@ const (
|
||||
ReplyFieldsCfg = "reply_fields"
|
||||
|
||||
// RadiusAgentCfg
|
||||
ListenAuthCfg = "listen_auth"
|
||||
ListenAcctCfg = "listen_acct"
|
||||
AuthAddrCfg = "auth_address"
|
||||
AcctAddrCfg = "acct_address"
|
||||
ClientSecretsCfg = "client_secrets"
|
||||
ClientDictionariesCfg = "client_dictionaries"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user