mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Update client_da_addresses structure
Supports configuring transport (tcp/udp), host, port and flags (only *log for now).
This commit is contained in:
committed by
Dan Christian Bogos
parent
8dc3a9e28f
commit
ca6a9440f7
@@ -22,6 +22,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@@ -575,12 +576,13 @@ func (ra *RadiusAgent) sendRadDaReq(requestType radigo.PacketCode, requestTempla
|
||||
return 0, fmt.Errorf("could not set attributes: %w", err)
|
||||
}
|
||||
|
||||
remoteAddr, remoteHost, err := dmRemoteAddr(packet.RemoteAddr().String(),
|
||||
remoteAddr, remoteHost, err := daRequestAddress(packet.RemoteAddr().String(),
|
||||
ra.cgrCfg.RadiusAgentCfg().ClientDaAddresses)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("retrieving remote address failed: %w", err)
|
||||
}
|
||||
dynAuthClient, err := radigo.NewClient(utils.UDP, remoteAddr,
|
||||
clientOpts := ra.cgrCfg.RadiusAgentCfg().ClientDaAddresses[remoteHost]
|
||||
dynAuthClient, err := radigo.NewClient(clientOpts.Transport, remoteAddr,
|
||||
ra.dacCfg.secrets.GetSecret(remoteHost),
|
||||
ra.dacCfg.dicts.GetInstance(remoteHost),
|
||||
ra.cgrCfg.GeneralCfg().ConnectAttempts, nil, utils.Logger)
|
||||
@@ -591,6 +593,11 @@ func (ra *RadiusAgent) sendRadDaReq(requestType radigo.PacketCode, requestTempla
|
||||
if err = radAppendAttributes(dynAuthReq, agReq.radDAReq); err != nil {
|
||||
return 0, fmt.Errorf("could not append attributes to the request packet: %w", err)
|
||||
}
|
||||
if clientOpts.Flags.Has(utils.MetaLog) {
|
||||
utils.Logger.Info(
|
||||
fmt.Sprintf("<%s> LOG, sending %s for session with ID '%s' to '%s': %s",
|
||||
utils.RadiusAgent, requestType, sessionID, remoteAddr, utils.ToJSON(dynAuthReq)))
|
||||
}
|
||||
dynAuthReply, err := dynAuthClient.SendRequest(dynAuthReq)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to send request: %w", err)
|
||||
@@ -598,9 +605,9 @@ func (ra *RadiusAgent) sendRadDaReq(requestType radigo.PacketCode, requestTempla
|
||||
return dynAuthReply.Code, nil
|
||||
}
|
||||
|
||||
// dmRemoteAddr ranges over the client_da_addresses map and returns the address configured for a
|
||||
// daRequestAddress ranges over the client_da_addresses map and returns the address configured for a
|
||||
// specific client alongside the host.
|
||||
func dmRemoteAddr(remoteAddr string, dynAuthAddresses map[string]string) (string, string, error) {
|
||||
func daRequestAddress(remoteAddr string, dynAuthAddresses map[string]config.DAClientOpts) (string, string, error) {
|
||||
if len(dynAuthAddresses) == 0 {
|
||||
return "", "", utils.ErrNotFound
|
||||
}
|
||||
@@ -608,9 +615,10 @@ func dmRemoteAddr(remoteAddr string, dynAuthAddresses map[string]string) (string
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
for host, addr := range dynAuthAddresses {
|
||||
for host, opts := range dynAuthAddresses {
|
||||
if host == remoteHost {
|
||||
return addr, host, nil
|
||||
address := opts.Host + ":" + strconv.Itoa(opts.Port)
|
||||
return address, host, nil
|
||||
}
|
||||
}
|
||||
return "", "", utils.ErrNotFound
|
||||
|
||||
@@ -186,7 +186,7 @@ func TestRadiusCoADisconnect(t *testing.T) {
|
||||
var testRadClient testNAS
|
||||
secrets := radigo.NewSecrets(map[string]string{utils.MetaDefault: "CGRateS.org"})
|
||||
dicts := radigo.NewDictionaries(map[string]*radigo.Dictionary{utils.MetaDefault: dictRad})
|
||||
testRadClient.server = radigo.NewServer("udp", "127.0.0.1:3799", secrets, dicts,
|
||||
testRadClient.server = radigo.NewServer(utils.UDP, "127.0.0.1:3799", secrets, dicts,
|
||||
map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){
|
||||
radigo.DisconnectRequest: handleDisconnect,
|
||||
radigo.CoARequest: handleCoA,
|
||||
|
||||
@@ -695,27 +695,35 @@ const CGRATES_CFG_JSON = `
|
||||
|
||||
|
||||
"radius_agent": {
|
||||
"enabled": false, // enables the radius agent: <true|false>
|
||||
"enabled": false, // enables the radius agent: <true|false>
|
||||
"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>
|
||||
"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>
|
||||
"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": [ // key represents the client IP or catch-all <*default|$client_ip>
|
||||
"client_dictionaries": { // per client path towards directory holding additional dictionaries to load (extra to RFC)
|
||||
"*default": [ // key represents the client IP or catch-all <*default|$client_ip>
|
||||
"/usr/share/cgrates/radius/dict/",
|
||||
]
|
||||
},
|
||||
"client_da_addresses": {}, // list of clients supporting dynamic authorization
|
||||
"client_da_addresses": { // configuration for clients capable of handling Dynamic Authorization (CoA/DM) requests.
|
||||
// "nasIdentifier": { // identifier for the NAS, typically the host from the initial RADIUS packet.
|
||||
// "transport": "udp", // transport protocol for Dynamic Authorization requests, defaults to UDP.
|
||||
// "host": "", // optionally specify an alternative host for DA requests. Defaults to the NAS identifier if empty.
|
||||
// "port": 3799, // port for Dynamic Authorization requests, default is 3799.
|
||||
// "flags": [] // additional options, currently supports *log for logging DA requests before sending.
|
||||
// }
|
||||
},
|
||||
"requests_cache_key": "",
|
||||
"sessions_conns": ["*internal"],
|
||||
"dmr_template": "", // template used to build the Disconnect-Request packet
|
||||
"coa_template": "", // template used to build the CoA-Request packet
|
||||
"request_processors": [ // request processors to be applied to Radius messages
|
||||
"dmr_template": "", // template used to build the Disconnect-Request packet
|
||||
"coa_template": "", // template used to build the CoA-Request packet
|
||||
"request_processors": [ // request processors to be applied to Radius messages
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
@@ -1000,7 +1000,7 @@ func TestRadiusAgentJsonCfg(t *testing.T) {
|
||||
Request_processors: &[]*ReqProcessorJsnCfg{},
|
||||
Dmr_template: utils.StringPointer(""),
|
||||
Coa_template: utils.StringPointer(""),
|
||||
Client_da_addresses: map[string]string{},
|
||||
Client_da_addresses: map[string]DAClientOptsJson{},
|
||||
}
|
||||
dfCgrJSONCfg, err := NewCgrJsonCfgFromBytes([]byte(CGRATES_CFG_JSON))
|
||||
if err != nil {
|
||||
|
||||
@@ -532,13 +532,20 @@ type RadiListenerJsnCfg struct {
|
||||
Acct_Address *string
|
||||
}
|
||||
|
||||
type DAClientOptsJson struct {
|
||||
Transport *string
|
||||
Host *string
|
||||
Port *int
|
||||
Flags []string
|
||||
}
|
||||
|
||||
// Radius Agent configuration section
|
||||
type RadiusAgentJsonCfg struct {
|
||||
Enabled *bool
|
||||
Listeners *[]*RadiListenerJsnCfg
|
||||
Client_secrets *map[string]string
|
||||
Client_dictionaries *map[string][]string
|
||||
Client_da_addresses map[string]string
|
||||
Client_da_addresses map[string]DAClientOptsJson
|
||||
Sessions_conns *[]string
|
||||
Dmr_template *string
|
||||
Coa_template *string
|
||||
|
||||
@@ -34,7 +34,7 @@ type RadiusAgentCfg struct {
|
||||
Listeners []RadiusListener
|
||||
ClientSecrets map[string]string
|
||||
ClientDictionaries map[string][]string
|
||||
ClientDaAddresses map[string]string
|
||||
ClientDaAddresses map[string]DAClientOpts
|
||||
SessionSConns []string
|
||||
DMRTemplate string
|
||||
CoATemplate string
|
||||
@@ -82,10 +82,13 @@ func (ra *RadiusAgentCfg) loadFromJSONCfg(jsnCfg *RadiusAgentJsonCfg, separator
|
||||
}
|
||||
if len(jsnCfg.Client_da_addresses) != 0 {
|
||||
if ra.ClientDaAddresses == nil {
|
||||
ra.ClientDaAddresses = make(map[string]string)
|
||||
ra.ClientDaAddresses = make(map[string]DAClientOpts)
|
||||
}
|
||||
for k, v := range jsnCfg.Client_da_addresses {
|
||||
ra.ClientDaAddresses[k] = v
|
||||
ra.ClientDaAddresses = make(map[string]DAClientOpts, len(jsnCfg.Client_da_addresses))
|
||||
for hostKey, clientOpts := range jsnCfg.Client_da_addresses {
|
||||
cfg := DAClientOpts{}
|
||||
cfg.loadFromJSONCfg(clientOpts, hostKey)
|
||||
ra.ClientDaAddresses[hostKey] = cfg
|
||||
}
|
||||
}
|
||||
if jsnCfg.Sessions_conns != nil {
|
||||
@@ -177,9 +180,9 @@ func (ra *RadiusAgentCfg) AsMapInterface(separator string) (initialMP map[string
|
||||
}
|
||||
initialMP[utils.ClientDictionariesCfg] = clientDictionaries
|
||||
if len(ra.ClientDaAddresses) != 0 {
|
||||
clientDaAddresses := make(map[string]string)
|
||||
clientDaAddresses := make(map[string]any)
|
||||
for k, v := range ra.ClientDaAddresses {
|
||||
clientDaAddresses[k] = v
|
||||
clientDaAddresses[k] = v.AsMapInterface()
|
||||
}
|
||||
initialMP[utils.ClientDaAddressesCfg] = clientDaAddresses
|
||||
}
|
||||
@@ -213,9 +216,9 @@ func (ra RadiusAgentCfg) Clone() (cln *RadiusAgentCfg) {
|
||||
cln.ClientDictionaries[k] = v
|
||||
}
|
||||
if len(ra.ClientDaAddresses) != 0 {
|
||||
cln.ClientDaAddresses = make(map[string]string)
|
||||
cln.ClientDaAddresses = make(map[string]DAClientOpts, len(ra.ClientDaAddresses))
|
||||
for k, v := range ra.ClientDaAddresses {
|
||||
cln.ClientDaAddresses[k] = v
|
||||
cln.ClientDaAddresses[k] = *v.Clone()
|
||||
}
|
||||
}
|
||||
if ra.RequestProcessors != nil {
|
||||
@@ -226,3 +229,53 @@ func (ra RadiusAgentCfg) Clone() (cln *RadiusAgentCfg) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type DAClientOpts struct {
|
||||
Transport string // transport protocol for Dynamic Authorization requests <UDP|TCP>.
|
||||
Host string // alternative host for DA requests
|
||||
Port int // port for Dynamic Authorization requests
|
||||
Flags utils.FlagsWithParams // flags (only *log for now)
|
||||
}
|
||||
|
||||
func (cda *DAClientOpts) loadFromJSONCfg(jsnCfg DAClientOptsJson, defaultHost string) error {
|
||||
cda.Transport = utils.UDP
|
||||
if jsnCfg.Transport != nil {
|
||||
cda.Transport = *jsnCfg.Transport
|
||||
}
|
||||
cda.Host = defaultHost
|
||||
if jsnCfg.Host != nil {
|
||||
cda.Host = *jsnCfg.Host
|
||||
}
|
||||
cda.Port = 3799
|
||||
if jsnCfg.Port != nil {
|
||||
cda.Port = *jsnCfg.Port
|
||||
}
|
||||
if jsnCfg.Flags != nil {
|
||||
cda.Flags = utils.FlagsWithParamsFromSlice(jsnCfg.Flags)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cda *DAClientOpts) Clone() *DAClientOpts {
|
||||
cln := DAClientOpts{
|
||||
Transport: cda.Transport,
|
||||
Host: cda.Host,
|
||||
Port: cda.Port,
|
||||
}
|
||||
if cda.Flags != nil {
|
||||
cln.Flags = cda.Flags.Clone()
|
||||
}
|
||||
return &cln
|
||||
}
|
||||
|
||||
func (cda *DAClientOpts) AsMapInterface() map[string]any {
|
||||
mp := map[string]any{
|
||||
utils.TransportCfg: cda.Transport,
|
||||
utils.HostCfg: cda.Host,
|
||||
utils.PortCfg: cda.Port,
|
||||
}
|
||||
if len(cda.Flags) != 0 {
|
||||
mp[utils.FlagsCfg] = cda.Flags.SliceFlags()
|
||||
}
|
||||
return mp
|
||||
}
|
||||
|
||||
@@ -58,8 +58,13 @@
|
||||
"radius_agent": {
|
||||
"enabled": true,
|
||||
"sessions_conns": ["*bijson_localhost"],
|
||||
"client_da_addresses": {
|
||||
"127.0.0.1": ":3799"
|
||||
"client_da_addresses": {
|
||||
"127.0.0.1": {
|
||||
"transport": "udp",
|
||||
"host": "",
|
||||
"port": 3799,
|
||||
"flags": ["*log"]
|
||||
}
|
||||
},
|
||||
"listeners":[
|
||||
{
|
||||
@@ -78,3 +83,4 @@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2261,6 +2261,8 @@ const (
|
||||
ClientDaAddressesCfg = "client_da_addresses"
|
||||
DMRTemplateCfg = "dmr_template"
|
||||
CoATemplateCfg = "coa_template"
|
||||
HostCfg = "host"
|
||||
PortCfg = "port"
|
||||
|
||||
// AttributeSCfg
|
||||
IndexedSelectsCfg = "indexed_selects"
|
||||
|
||||
Reference in New Issue
Block a user