mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
ips: add RADIUS IPAM integration test
This commit is contained in:
committed by
Dan Christian Bogos
parent
c4389a9ab6
commit
7845074db5
446
data/conf/samples/radius_ipam/acct.json
Normal file
446
data/conf/samples/radius_ipam/acct.json
Normal file
@@ -0,0 +1,446 @@
|
||||
{
|
||||
"radius_agent": {
|
||||
"request_processors": [
|
||||
{
|
||||
"id": "IPSAccountingStart",
|
||||
"filters": [
|
||||
"*string:~*req.Acct-Status-Type:Start"
|
||||
],
|
||||
"flags": [
|
||||
"*initiate",
|
||||
"*ips"
|
||||
],
|
||||
"request_fields": [
|
||||
{
|
||||
"tag": "Category",
|
||||
"path": "*cgreq.Category",
|
||||
"type": "*constant",
|
||||
"value": "ips"
|
||||
},
|
||||
{
|
||||
"tag": "RequestType",
|
||||
"path": "*cgreq.RequestType",
|
||||
"type": "*constant",
|
||||
"value": "*prepaid",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "OriginID",
|
||||
"path": "*opts.*originID",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Session-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "OriginHost",
|
||||
"path": "*cgreq.OriginHost",
|
||||
"type": "*variable",
|
||||
"value": "~*req.NAS-IP-Address",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Account",
|
||||
"path": "*cgreq.Account",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Subject",
|
||||
"path": "*cgreq.Subject",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Destination",
|
||||
"path": "*cgreq.Destination",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Called-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "SetupTime",
|
||||
"path": "*cgreq.SetupTime",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Event-Timestamp",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "AnswerTime",
|
||||
"path": "*cgreq.AnswerTime",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Event-Timestamp",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "IMSI",
|
||||
"path": "*cgreq.IMSI",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "APN",
|
||||
"path": "*cgreq.APN",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Called-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "CallingStationId",
|
||||
"path": "*cgreq.CallingStationId",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Calling-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "NAS-Identifier",
|
||||
"path": "*cgreq.NAS-Identifier",
|
||||
"type": "*variable",
|
||||
"value": "~*req.NAS-Identifier",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "ServiceType",
|
||||
"path": "*cgreq.ServiceType",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Service-Type",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "FramedProtocol",
|
||||
"path": "*cgreq.FramedProtocol",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Framed-Protocol",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "NASPortType",
|
||||
"path": "*cgreq.NASPortType",
|
||||
"type": "*variable",
|
||||
"value": "~*req.NAS-Port-Type",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "AcctAuthentic",
|
||||
"path": "*cgreq.AcctAuthentic",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Authentic",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "AcctDelayTime",
|
||||
"path": "*cgreq.AcctDelayTime",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Delay-Time",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "AllocatedIP",
|
||||
"path": "*cgreq.AllocatedIP",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Framed-IP-Address",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "SessionID",
|
||||
"path": "*vars.*sessionID",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Session-Id"
|
||||
},
|
||||
{
|
||||
"tag": "RemoteAddr",
|
||||
"path": "*cgreq.RemoteAddr",
|
||||
"type": "*variable",
|
||||
"value": "~*vars.RemoteHost:s/(.*):\\d+/${1}/"
|
||||
}
|
||||
],
|
||||
"reply_fields": [
|
||||
{
|
||||
"tag": "ProxyState",
|
||||
"path": "*rep.Proxy-State",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Proxy-State",
|
||||
"mandatory": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "IPSAccountingAlive",
|
||||
"filters": [
|
||||
"*string:~*req.Acct-Status-Type:Alive"
|
||||
],
|
||||
"flags": [
|
||||
"*update"
|
||||
],
|
||||
"request_fields": [
|
||||
{
|
||||
"tag": "Category",
|
||||
"path": "*cgreq.Category",
|
||||
"type": "*constant",
|
||||
"value": "ips"
|
||||
},
|
||||
{
|
||||
"tag": "RequestType",
|
||||
"path": "*cgreq.RequestType",
|
||||
"type": "*constant",
|
||||
"value": "*prepaid",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "OriginID",
|
||||
"path": "*opts.*originID",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Session-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Account",
|
||||
"path": "*cgreq.Account",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Subject",
|
||||
"path": "*cgreq.Subject",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Destination",
|
||||
"path": "*cgreq.Destination",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Called-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "SetupTime",
|
||||
"path": "*cgreq.SetupTime",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Event-Timestamp",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "IMSI",
|
||||
"path": "*cgreq.IMSI",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "APN",
|
||||
"path": "*cgreq.APN",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Called-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "CallingStationId",
|
||||
"path": "*cgreq.CallingStationId",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Calling-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "NAS-Identifier",
|
||||
"path": "*cgreq.NAS-Identifier",
|
||||
"type": "*variable",
|
||||
"value": "~*req.NAS-Identifier",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "ServiceType",
|
||||
"path": "*cgreq.ServiceType",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Service-Type",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "FramedProtocol",
|
||||
"path": "*cgreq.FramedProtocol",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Framed-Protocol",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "AcctInputOctets",
|
||||
"path": "*cgreq.AcctInputOctets",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Input-Octets",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "AcctOutputOctets",
|
||||
"path": "*cgreq.AcctOutputOctets",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Output-Octets",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "SessionID",
|
||||
"path": "*vars.*sessionID",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Session-Id"
|
||||
}
|
||||
],
|
||||
"reply_fields": [
|
||||
{
|
||||
"tag": "ProxyState",
|
||||
"path": "*rep.Proxy-State",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Proxy-State",
|
||||
"mandatory": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "IPSAccountingStop",
|
||||
"filters": [
|
||||
"*string:~*req.Acct-Status-Type:Stop"
|
||||
],
|
||||
"flags": [
|
||||
"*terminate",
|
||||
"*ips"
|
||||
],
|
||||
"request_fields": [
|
||||
{
|
||||
"tag": "Category",
|
||||
"path": "*cgreq.Category",
|
||||
"type": "*constant",
|
||||
"value": "ips"
|
||||
},
|
||||
{
|
||||
"tag": "RequestType",
|
||||
"path": "*cgreq.RequestType",
|
||||
"type": "*constant",
|
||||
"value": "*prepaid",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "OriginID",
|
||||
"path": "*opts.*originID",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Session-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Account",
|
||||
"path": "*cgreq.Account",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Subject",
|
||||
"path": "*cgreq.Subject",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Destination",
|
||||
"path": "*cgreq.Destination",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Called-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "SetupTime",
|
||||
"path": "*cgreq.SetupTime",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Event-Timestamp",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Usage",
|
||||
"path": "*cgreq.Usage",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Event-Timestamp",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "IMSI",
|
||||
"path": "*cgreq.IMSI",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "APN",
|
||||
"path": "*cgreq.APN",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Called-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "CallingStationId",
|
||||
"path": "*cgreq.CallingStationId",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Calling-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "NAS-Identifier",
|
||||
"path": "*cgreq.NAS-Identifier",
|
||||
"type": "*variable",
|
||||
"value": "~*req.NAS-Identifier",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "ServiceType",
|
||||
"path": "*cgreq.ServiceType",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Service-Type",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "FramedProtocol",
|
||||
"path": "*cgreq.FramedProtocol",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Framed-Protocol",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "AcctInputOctets",
|
||||
"path": "*cgreq.AcctInputOctets",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Input-Octets",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "AcctOutputOctets",
|
||||
"path": "*cgreq.AcctOutputOctets",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Output-Octets",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "AcctTerminateCause",
|
||||
"path": "*cgreq.AcctTerminateCause",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Terminate-Cause",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "SessionID",
|
||||
"path": "*vars.*sessionID",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Session-Id"
|
||||
}
|
||||
],
|
||||
"reply_fields": [
|
||||
{
|
||||
"tag": "ProxyState",
|
||||
"path": "*rep.Proxy-State",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Proxy-State",
|
||||
"mandatory": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
172
data/conf/samples/radius_ipam/auth.json
Normal file
172
data/conf/samples/radius_ipam/auth.json
Normal file
@@ -0,0 +1,172 @@
|
||||
{
|
||||
"radius_agent": {
|
||||
"request_processors": [
|
||||
{
|
||||
"id": "IPSAuthorization",
|
||||
"filters": [
|
||||
"*string:~*vars.*radReqType:*radAuth"
|
||||
],
|
||||
"flags": [
|
||||
"*authorize",
|
||||
"*ips",
|
||||
"*continue"
|
||||
],
|
||||
"request_fields": [
|
||||
{
|
||||
"tag": "Category",
|
||||
"path": "*cgreq.Category",
|
||||
"type": "*constant",
|
||||
"value": "ips"
|
||||
},
|
||||
{
|
||||
"tag": "RequestType",
|
||||
"path": "*cgreq.RequestType",
|
||||
"type": "*constant",
|
||||
"value": "*prepaid",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "OriginID",
|
||||
"path": "*opts.*originID",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Acct-Session-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Account",
|
||||
"path": "*cgreq.Account",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Subject",
|
||||
"path": "*cgreq.Subject",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "Destination",
|
||||
"path": "*cgreq.Destination",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Called-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "SetupTime",
|
||||
"path": "*cgreq.SetupTime",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Event-Timestamp",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "AnswerTime",
|
||||
"path": "*cgreq.AnswerTime",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Event-Timestamp",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "IMSI",
|
||||
"path": "*cgreq.IMSI",
|
||||
"type": "*variable",
|
||||
"value": "~*req.User-Name",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "APN",
|
||||
"path": "*cgreq.APN",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Called-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "CallingStationId",
|
||||
"path": "*cgreq.CallingStationId",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Calling-Station-Id",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "NAS-Identifier",
|
||||
"path": "*cgreq.NAS-Identifier",
|
||||
"type": "*variable",
|
||||
"value": "~*req.NAS-Identifier",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "FramedPool",
|
||||
"path": "*cgreq.FramedPool",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Framed-Pool",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "ServiceType",
|
||||
"path": "*cgreq.ServiceType",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Service-Type",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "FramedProtocol",
|
||||
"path": "*cgreq.FramedProtocol",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Framed-Protocol",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "NAS-IP",
|
||||
"path": "*cgreq.NAS-IP",
|
||||
"type": "*variable",
|
||||
"value": "~*req.NAS-IP-Address",
|
||||
"mandatory": true
|
||||
}
|
||||
],
|
||||
"reply_fields": [
|
||||
{
|
||||
"tag": "FramedIPAddress",
|
||||
"path": "*rep.Framed-IP-Address",
|
||||
"type": "*variable",
|
||||
"value": "~*cgrep.AllocatedIP.Address",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "FramedProtocol",
|
||||
"path": "*rep.Framed-Protocol",
|
||||
"type": "*constant",
|
||||
"value": "PPP",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "ServiceType",
|
||||
"path": "*rep.Service-Type",
|
||||
"type": "*constant",
|
||||
"value": "Framed",
|
||||
"mandatory": true
|
||||
},
|
||||
{
|
||||
"tag": "ReplyMessage",
|
||||
"path": "*rep.Reply-Message",
|
||||
"type": "*variable",
|
||||
"value": "Pool:;~*cgrep.AllocatedIP.PoolID; - ;~*cgrep.AllocatedIP.Message",
|
||||
},
|
||||
{
|
||||
"tag": "Class",
|
||||
"path": "*rep.Class",
|
||||
"type": "*variable",
|
||||
"value": "~*cgrep.AllocatedIP.ProfileID",
|
||||
},
|
||||
{
|
||||
"tag": "ProxyState",
|
||||
"path": "*rep.Proxy-State",
|
||||
"type": "*variable",
|
||||
"value": "~*req.Proxy-State",
|
||||
"mandatory": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
45
data/conf/samples/radius_ipam/cgrates.json
Normal file
45
data/conf/samples/radius_ipam/cgrates.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"sessions": {
|
||||
"enabled": true,
|
||||
"ips_conns": [
|
||||
"*localhost"
|
||||
],
|
||||
"opts": {
|
||||
"*ipsAuthorize": [
|
||||
{
|
||||
"Value": true
|
||||
}
|
||||
],
|
||||
"*ipsAllocate": [
|
||||
{
|
||||
"Value": true
|
||||
}
|
||||
],
|
||||
"*ipsRelease": [
|
||||
{
|
||||
"Value": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"ips": {
|
||||
"enabled": true,
|
||||
"store_interval": "-1"
|
||||
},
|
||||
"radius_agent": {
|
||||
"enabled": true,
|
||||
"sessions_conns": [
|
||||
"*bijson_localhost"
|
||||
],
|
||||
"listeners": [
|
||||
{
|
||||
"network": "udp",
|
||||
"auth_address": "127.0.0.1:1812",
|
||||
"acct_address": "127.0.0.1:1813"
|
||||
}
|
||||
]
|
||||
},
|
||||
"admins": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
362
general_tests/radius_ipam_it_test.go
Normal file
362
general_tests/radius_ipam_it_test.go
Normal file
@@ -0,0 +1,362 @@
|
||||
//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"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/birpc"
|
||||
"github.com/cgrates/birpc/context"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/radigo"
|
||||
)
|
||||
|
||||
func TestRadiusIPAM(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 Framed-Pool 88 string
|
||||
|
||||
VALUE Service-Type Framed 2
|
||||
VALUE Framed-Protocol PPP 1
|
||||
VALUE Framed-Protocol GPRS-PDP-Context 7
|
||||
VALUE NAS-Port-Type Virtual 5
|
||||
VALUE Acct-Status-Type Start 1
|
||||
VALUE Acct-Status-Type Stop 2
|
||||
VALUE Acct-Status-Type Alive 3
|
||||
VALUE Acct-Authentic RADIUS 1
|
||||
VALUE Acct-Terminate-Cause User-Request 1
|
||||
`
|
||||
|
||||
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_ipam"),
|
||||
ConfigJSON: fmt.Sprintf(`{
|
||||
"radius_agent": {
|
||||
"client_dictionaries": {
|
||||
"*default": [
|
||||
%q
|
||||
]
|
||||
}
|
||||
}
|
||||
}`, dictDir+"/"),
|
||||
DBCfg: engine.InternalDBCfg,
|
||||
Encoding: *utils.Encoding,
|
||||
// LogBuffer: &bytes.Buffer{},
|
||||
}
|
||||
// t.Cleanup(func() { fmt.Println(ng.LogBuffer) })
|
||||
client, cfg := ng.Run(t)
|
||||
|
||||
var replySet string
|
||||
if err := client.Call(context.Background(), utils.AdminSv1SetIPProfile,
|
||||
&utils.IPProfileWithAPIOpts{
|
||||
IPProfile: &utils.IPProfile{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "IPsAPI",
|
||||
FilterIDs: []string{"*string:~*req.Account:123456789012345"},
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
Weight: 15,
|
||||
},
|
||||
},
|
||||
TTL: -1,
|
||||
Stored: false,
|
||||
|
||||
// Pool selection logic:
|
||||
// POOL_A (10.100.0.1): weight 50, blocks (APN=internet.test.apn)
|
||||
// POOL_B (10.100.0.2): weight 30, gets removed
|
||||
// POOL_C (10.100.0.3): weight 100 should win
|
||||
Pools: []*utils.IPPool{
|
||||
{
|
||||
ID: "POOL_A",
|
||||
FilterIDs: []string{},
|
||||
Type: "*ipv4",
|
||||
Range: "10.100.0.1/32",
|
||||
Strategy: "*ascending",
|
||||
Message: "Pool A message",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
FilterIDs: []string{},
|
||||
Weight: 50,
|
||||
},
|
||||
},
|
||||
Blockers: utils.DynamicBlockers{
|
||||
{
|
||||
FilterIDs: []string{"*string:~*req.APN:internet.test.apn"},
|
||||
Blocker: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "POOL_B",
|
||||
FilterIDs: []string{},
|
||||
Type: "*ipv4",
|
||||
Range: "10.100.0.2/32",
|
||||
Strategy: "*ascending",
|
||||
Message: "Pool B message",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
FilterIDs: []string{},
|
||||
Weight: 30,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "POOL_C",
|
||||
FilterIDs: []string{},
|
||||
Type: "*ipv4",
|
||||
Range: "10.100.0.3/32",
|
||||
Strategy: "*ascending",
|
||||
Message: "Pool C message",
|
||||
Weights: utils.DynamicWeights{
|
||||
{
|
||||
FilterIDs: []string{"*string:~*req.APN:internet.test.apn"},
|
||||
Weight: 100,
|
||||
},
|
||||
{
|
||||
FilterIDs: []string{},
|
||||
Weight: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, &replySet); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
imsi := "123456789012345"
|
||||
msisdn := "987654321098765"
|
||||
apn := "internet.test.apn"
|
||||
|
||||
nasID := "test-nas-server-1"
|
||||
nasIP := "192.168.1.10"
|
||||
poolName := "test-pool-primary"
|
||||
|
||||
passwd := "CGRateSPassword1"
|
||||
currentTimestamp := fmt.Sprintf("%d", time.Now().Unix())
|
||||
|
||||
authSessionID := "auth-session-12345-67890"
|
||||
acctSessionID := "acct-session-abcdef-123456"
|
||||
|
||||
proxyAuth := "4829"
|
||||
proxyAcctStart := "4830"
|
||||
proxyAcctAlive := "4831"
|
||||
proxyAcctStop := "4832"
|
||||
|
||||
// Step 1: Access-Request (should not allocate)
|
||||
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
|
||||
clientAuth, err := radigo.NewClient(net, authAddr, secret, dictRad, 1, nil, utils.Logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
reply := sendRadReq(t, clientAuth, radigo.AccessRequest, 1,
|
||||
map[string]string{
|
||||
"User-Name": imsi,
|
||||
"Service-Type": "Framed",
|
||||
"Framed-Protocol": "GPRS-PDP-Context",
|
||||
"Called-Station-Id": apn,
|
||||
"Calling-Station-Id": msisdn,
|
||||
"NAS-Identifier": nasID,
|
||||
"Acct-Session-Id": authSessionID,
|
||||
"Framed-Pool": poolName,
|
||||
"User-Password": passwd,
|
||||
"Event-Timestamp": currentTimestamp,
|
||||
"NAS-IP-Address": nasIP,
|
||||
"Proxy-State": proxyAuth,
|
||||
},
|
||||
)
|
||||
checkAllocs(t, client, "IPsAPI")
|
||||
|
||||
// retrieve allocatedIP (to be used in Accounting-Request Start)
|
||||
var allocatedIP string
|
||||
for _, avp := range reply.AVPs {
|
||||
if avp.Number == 8 { // Framed-IP-Address
|
||||
if len(avp.RawValue) == 4 {
|
||||
allocatedIP = fmt.Sprintf("%d.%d.%d.%d",
|
||||
avp.RawValue[0], avp.RawValue[1],
|
||||
avp.RawValue[2], avp.RawValue[3])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if allocatedIP != "10.100.0.3" {
|
||||
t.Errorf("expected IP from POOL_C (10.100.0.3), got %s", allocatedIP)
|
||||
}
|
||||
|
||||
// Step 2: Accounting-Request Start (should allocate)
|
||||
acctAddr := cfg.RadiusAgentCfg().Listeners[0].AcctAddr
|
||||
clientAcct, err := radigo.NewClient(net, acctAddr, secret, dictRad, 1, nil, utils.Logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sendRadReq(t, clientAcct, radigo.AccountingRequest, 2,
|
||||
map[string]string{
|
||||
"User-Name": imsi,
|
||||
"Acct-Status-Type": "Start",
|
||||
"NAS-Identifier": "test-nas-server-2", // Different NAS for accounting
|
||||
"Called-Station-Id": apn,
|
||||
"Framed-Protocol": "GPRS-PDP-Context",
|
||||
"Service-Type": "Framed",
|
||||
"NAS-Port-Type": "Virtual",
|
||||
"Calling-Station-Id": msisdn,
|
||||
"Acct-Authentic": "RADIUS",
|
||||
"Acct-Delay-Time": "0",
|
||||
"Acct-Session-Id": acctSessionID,
|
||||
"Framed-IP-Address": allocatedIP,
|
||||
"NAS-IP-Address": "192.168.1.11", // Different NAS IP for accounting
|
||||
"Event-Timestamp": currentTimestamp,
|
||||
"Proxy-State": proxyAcctStart,
|
||||
},
|
||||
)
|
||||
checkAllocs(t, client, "IPsAPI", acctSessionID)
|
||||
|
||||
// Step 3: Accounting-Request Alive (should maintain allocation)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
aliveTimestamp := fmt.Sprintf("%d", time.Now().Unix())
|
||||
sendRadReq(t, clientAcct, radigo.AccountingRequest, 3,
|
||||
map[string]string{
|
||||
"User-Name": imsi,
|
||||
"Acct-Status-Type": "Alive",
|
||||
"Service-Type": "Framed",
|
||||
"Acct-Session-Id": acctSessionID,
|
||||
"Framed-Protocol": "GPRS-PDP-Context",
|
||||
"Called-Station-Id": apn,
|
||||
"Calling-Station-Id": msisdn,
|
||||
"NAS-Identifier": "test-nas-server-3",
|
||||
"Acct-Input-Octets": "1234567",
|
||||
"Acct-Output-Octets": "7654321",
|
||||
"NAS-IP-Address": "192.168.1.12",
|
||||
"Event-Timestamp": aliveTimestamp,
|
||||
"Proxy-State": proxyAcctAlive,
|
||||
},
|
||||
)
|
||||
checkAllocs(t, client, "IPsAPI", acctSessionID)
|
||||
|
||||
// Step 4: Accounting-Request Stop (should release)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
stopTimestamp := fmt.Sprintf("%d", time.Now().Unix())
|
||||
sendRadReq(t, clientAcct, radigo.AccountingRequest, 4,
|
||||
map[string]string{
|
||||
"User-Name": imsi,
|
||||
"Acct-Status-Type": "Stop",
|
||||
"Service-Type": "Framed",
|
||||
"Acct-Session-Id": acctSessionID,
|
||||
"Framed-Protocol": "GPRS-PDP-Context",
|
||||
"Called-Station-Id": apn,
|
||||
"Calling-Station-Id": msisdn,
|
||||
"NAS-Identifier": "test-nas-server-3",
|
||||
"Acct-Input-Octets": "9876543",
|
||||
"Acct-Output-Octets": "1234567",
|
||||
"Acct-Terminate-Cause": "User-Request",
|
||||
"NAS-IP-Address": "192.168.1.12",
|
||||
"Event-Timestamp": stopTimestamp,
|
||||
"Proxy-State": proxyAcctStop,
|
||||
},
|
||||
)
|
||||
checkAllocs(t, client, "IPsAPI")
|
||||
}
|
||||
|
||||
func sendRadReq(t *testing.T, client *radigo.Client, code radigo.PacketCode, id uint8, avps map[string]string) *radigo.Packet {
|
||||
t.Helper()
|
||||
req := client.NewRequest(code, id)
|
||||
|
||||
for attr, val := range avps {
|
||||
if err := req.AddAVPWithName(attr, val, ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if code == radigo.AccessRequest && attr == "User-Password" {
|
||||
secret := []byte("CGRateS.org")
|
||||
for i := len(req.AVPs) - 1; i >= 0; i-- {
|
||||
if req.AVPs[i].Name == "User-Password" {
|
||||
req.AVPs[i].RawValue = radigo.EncodeUserPassword([]byte(val), secret, req.Authenticator[:])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
replyPacket, err := client.SendRequest(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var failed bool
|
||||
switch code {
|
||||
case radigo.AccessRequest:
|
||||
failed = replyPacket.Code != radigo.AccessAccept
|
||||
case radigo.AccountingRequest:
|
||||
failed = replyPacket.Code != radigo.AccountingResponse
|
||||
}
|
||||
if failed {
|
||||
t.Errorf("unexpected reply received to %s: %+v", code.String(), utils.ToJSON(replyPacket))
|
||||
}
|
||||
|
||||
return replyPacket
|
||||
}
|
||||
|
||||
func checkAllocs(t *testing.T, client *birpc.Client, id string, wantAllocs ...string) {
|
||||
t.Helper()
|
||||
var allocs utils.IPAllocations
|
||||
if err := client.Call(context.Background(), utils.IPsV1GetIPAllocations,
|
||||
&utils.TenantIDWithAPIOpts{
|
||||
TenantID: &utils.TenantID{
|
||||
Tenant: "cgrates.org",
|
||||
ID: id,
|
||||
},
|
||||
}, &allocs); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(allocs.Allocations) != len(wantAllocs) {
|
||||
t.Errorf("%s unexpected result: %s", utils.IPsV1GetIPAllocations, utils.ToJSON(allocs))
|
||||
}
|
||||
|
||||
for _, allocID := range wantAllocs {
|
||||
if _, exists := allocs.Allocations[allocID]; !exists {
|
||||
t.Errorf("%s unexpected result: %s", utils.IPsV1GetIPAllocations, utils.ToJSON(allocs))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user