Port StatusServer support to master

This commit is contained in:
armirveliaj
2025-07-25 10:39:31 -04:00
committed by Dan Christian Bogos
parent b4de0dc84c
commit 2fd7730b45
3 changed files with 275 additions and 0 deletions

View File

@@ -39,6 +39,8 @@ import (
const (
MetaRadReqType = "*radReqType"
MetaRadAuth = "*radAuth"
MetaRadAccount = "*radAccount"
MetaRadReqCode = "*radReqCode"
MetaRadReplyCode = "*radReplyCode"
UserPasswordAVP = "User-Password"
CHAPPasswordAVP = "CHAP-Password"
@@ -87,11 +89,13 @@ func NewRadiusAgent(cgrCfg *config.CGRConfig, filterS *engine.FilterS, connMgr *
radAgent.rsAuth[net+"://"+authAddr] = radigo.NewServer(net, authAddr, secrets, dicts,
map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){
radigo.AccessRequest: radAgent.handleAuth,
radigo.StatusServer: radAgent.handleAuth,
}, nil, utils.Logger)
acctAddr := radAgentCfg.Listeners[i].AcctAddr
radAgent.rsAcct[net+"://"+acctAddr] = radigo.NewServer(net, acctAddr, secrets, dicts,
map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){
radigo.AccountingRequest: radAgent.handleAcct,
radigo.StatusServer: radAgent.handleAcct,
}, nil, utils.Logger)
}
return radAgent, nil
@@ -157,6 +161,7 @@ func (ra *RadiusAgent) handleAuth(reqPacket *radigo.Packet) (*radigo.Packet, err
Type: utils.NMMapType,
Map: map[string]*utils.DataNode{
utils.RemoteHost: utils.NewLeafNode(reqPacket.RemoteAddr().String()),
MetaRadReqCode: utils.NewLeafNode(reqPacket.Code.String()),
},
}
radDP := newRADataProvider(reqPacket)
@@ -218,6 +223,8 @@ func (ra *RadiusAgent) handleAcct(reqPacket *radigo.Packet) (*radigo.Packet, err
Type: utils.NMMapType,
Map: map[string]*utils.DataNode{
utils.RemoteHost: utils.NewLeafNode(remoteAddr),
MetaRadReqType: utils.NewLeafNode(MetaRadAccount),
MetaRadReqCode: utils.NewLeafNode(reqPacket.Code.String()),
},
}

View File

@@ -0,0 +1,78 @@
{
"general": {
"log_level": 7
},
"data_db": {
"db_type": "*internal"
},
"stor_db": {
"db_type": "*internal"
},
"rals": {
"enabled": true
},
"schedulers": {
"enabled": true
},
"cdrs": {
"enabled": true,
"rals_conns": ["*internal"]
},
"resources": {
"enabled": true,
"store_interval": "-1"
},
"attributes": {
"enabled": true
},
"routes": {
"enabled": true
},
"chargers": {
"enabled": true
},
"sessions": {
"enabled": true,
"attributes_conns": ["*localhost"],
"cdrs_conns": ["*localhost"],
"rals_conns": ["*localhost"],
"resources_conns": ["*localhost"],
"chargers_conns": ["*internal"],
"debit_interval": "10s"
},
"radius_agent": {
"enabled": true,
"sessions_conns": ["*localhost"],
"listeners": [
{
"network": "udp",
"auth_address": "127.0.0.1:1812",
"acct_address": "127.0.0.1:1813"
}
],
"request_processors": [
{
"id": "Status",
"filters": [
"*string:~*vars.*radReqCode:StatusServer"
],
"flags": [
"*none", "*log"
],
"reply_fields": [
{
"tag": "ReplyMessage",
"path": "*rep.Reply-Message",
"type": "*constant",
"mandatory": true,
"value": "OK"
}
]
}
]
},
"apiers": {
"enabled": true,
"scheduler_conns": ["*internal"]
}
}

View File

@@ -0,0 +1,190 @@
//go:build integration
// +build integration
/*
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 <http://www.gnu.org/licenses/>
*/
package general_tests
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/radigo"
)
func TestRadiusStat(t *testing.T) {
switch *utils.DBType {
case utils.MetaInternal:
case utils.MetaMySQL, utils.MetaMongo, utils.MetaPostgres:
t.SkipNow()
default:
t.Fatal("unsupported dbtype value")
}
var testRadiusDict = `
ATTRIBUTE Message-Authenticator 80 octets
ATTRIBUTE User-Name 1 string
ATTRIBUTE User-Password 2 string
ATTRIBUTE CHAP-Password 3 string
ATTRIBUTE NAS-IP-Address 4 ipaddr
ATTRIBUTE NAS-Port 5 integer
ATTRIBUTE Service-Type 6 integer
ATTRIBUTE Framed-Protocol 7 integer
ATTRIBUTE Framed-IP-Address 8 ipaddr
ATTRIBUTE Framed-IP-Netmask 9 ipaddr
ATTRIBUTE Framed-Routing 10 integer
ATTRIBUTE Filter-Id 11 string
ATTRIBUTE Framed-MTU 12 integer
ATTRIBUTE Framed-Compression 13 integer
ATTRIBUTE Login-IP-Host 14 ipaddr
ATTRIBUTE Login-Service 15 integer
ATTRIBUTE Login-TCP-Port 16 integer
ATTRIBUTE Reply-Message 18 string
ATTRIBUTE Callback-Number 19 string
ATTRIBUTE Callback-Id 20 string
ATTRIBUTE Framed-Route 22 string
ATTRIBUTE Framed-IPX-Network 23 ipaddr
ATTRIBUTE State 24 string
ATTRIBUTE Class 25 string
ATTRIBUTE Vendor-Specific 26 string
ATTRIBUTE Session-Timeout 27 integer
ATTRIBUTE Idle-Timeout 28 integer
ATTRIBUTE Termination-Action 29 integer
ATTRIBUTE Called-Station-Id 30 string
ATTRIBUTE Calling-Station-Id 31 string
ATTRIBUTE NAS-Identifier 32 string
ATTRIBUTE Proxy-State 33 string
ATTRIBUTE Login-LAT-Service 34 string
ATTRIBUTE Login-LAT-Node 35 string
ATTRIBUTE Login-LAT-Group 36 string
ATTRIBUTE Framed-AppleTalk-Link 37 integer
ATTRIBUTE Framed-AppleTalk-Network 38 integer
ATTRIBUTE Framed-AppleTalk-Zone 39 string
ATTRIBUTE Acct-Status-Type 40 integer
ATTRIBUTE Acct-Delay-Time 41 integer
ATTRIBUTE Acct-Input-Octets 42 integer
ATTRIBUTE Acct-Output-Octets 43 integer
ATTRIBUTE Acct-Session-Id 44 string
ATTRIBUTE Acct-Authentic 45 integer
ATTRIBUTE Acct-Session-Time 46 integer
ATTRIBUTE Acct-Input-Packets 47 integer
ATTRIBUTE Acct-Output-Packets 48 integer
ATTRIBUTE Acct-Terminate-Cause 49 integer
ATTRIBUTE Acct-Multi-Session-Id 50 string
ATTRIBUTE Acct-Link-Count 51 integer
ATTRIBUTE Acct-Input-Gigawords 52 integer
ATTRIBUTE Acct-Output-Gigawords 53 integer
ATTRIBUTE Event-Timestamp 55 integer
ATTRIBUTE Egress-VLANID 56 string
ATTRIBUTE Ingress-Filters 57 integer
ATTRIBUTE Egress-VLAN-Name 58 string
ATTRIBUTE User-Priority-Table 59 string
ATTRIBUTE CHAP-Challenge 60 string
ATTRIBUTE NAS-Port-Type 61 integer
ATTRIBUTE Port-Limit 62 integer
ATTRIBUTE Login-LAT-Port 63 integer
`
dictDir := t.TempDir()
dictPath := filepath.Join(dictDir, "dictionary.test")
if err := os.WriteFile(dictPath, []byte(testRadiusDict), 0644); err != nil {
t.Fatal(err)
}
ng := engine.TestEngine{
ConfigPath: filepath.Join(*utils.DataDir, "conf", "samples", "radius_status"),
ConfigJSON: fmt.Sprintf(`{
"radius_agent": {
"client_dictionaries": {
"*default": [
%q
]
}
}
}`, dictDir+"/"),
DBCfg: engine.InternalDBCfg,
}
_, cfg := ng.Run(t)
dictRad := radigo.RFC2865Dictionary()
dictRad.ParseFromReader(strings.NewReader(testRadiusDict))
secret := cfg.RadiusAgentCfg().ClientSecrets[utils.MetaDefault]
net := cfg.RadiusAgentCfg().Listeners[0].Network
authAddr := cfg.RadiusAgentCfg().Listeners[0].AuthAddr
acctAddr := cfg.RadiusAgentCfg().Listeners[0].AcctAddr
clientAuth, err := radigo.NewClient(net, authAddr, secret, dictRad, 1, nil, utils.Logger)
if err != nil {
t.Fatal(err)
}
req := clientAuth.NewRequest(radigo.StatusServer, 71)
if err := req.AddAVPWithName("NAS-Identifier", "Status Check 1806. Are you alive?", ""); err != nil {
t.Fatal(err)
}
if err := req.AddAVPWithName("Message-Authenticator", "A7kLm29qXtP4vWcE0uYdRgHsJnFbZxQ3", ""); err != nil {
t.Fatal(err)
}
replyPacket, err := clientAuth.SendRequest(req)
if err != nil {
t.Fatal(err)
}
if len(replyPacket.AVPs) > 1 {
t.Errorf("Expected 1 AVP, received %v AVPS", len(replyPacket.AVPs))
}
if replyPacket.AVPs[0].Number != 18 {
t.Errorf("Expected 18 , received %v", replyPacket.AVPs[0].Number)
}
clientAcct, err := radigo.NewClient(net, acctAddr, secret, dictRad, 1, nil, utils.Logger)
if err != nil {
t.Fatal(err)
}
req = clientAcct.NewRequest(radigo.StatusServer, 71)
if err := req.AddAVPWithName("NAS-Identifier", "Status Check 1806. Are you alive?", ""); err != nil {
t.Fatal(err)
}
if err := req.AddAVPWithName("Message-Authenticator", "A7kLm29qXtP4vWcE0uYdRgHsJnFbZxQ3", ""); err != nil {
t.Fatal(err)
}
replyPacket, err = clientAcct.SendRequest(req)
if err != nil {
t.Fatal(err)
}
if len(replyPacket.AVPs) > 1 {
t.Errorf("Expected 1 AVP, received %v AVPS", len(replyPacket.AVPs))
}
if replyPacket.AVPs[0].Number != 18 {
t.Errorf("Expected 18 , received %v", replyPacket.AVPs[0].Number)
}
}