mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Update Radius
This commit is contained in:
committed by
Dan Christian Bogos
parent
ebaf5791b3
commit
a386f98990
@@ -151,6 +151,23 @@ func (aReq *AgentRequest) ParseField(
|
||||
case utils.META_COMPOSED:
|
||||
out = aReq.composedField(cfgFld.Value)
|
||||
isString = true
|
||||
case utils.META_USAGE_DIFFERENCE:
|
||||
if len(cfgFld.Value) != 2 {
|
||||
return nil, fmt.Errorf("invalid arguments <%s>", utils.ToJSON(cfgFld.Value))
|
||||
} else {
|
||||
strVal1, err := aReq.FieldAsString(strings.Split(cfgFld.Value[0].Id, utils.NestingSep))
|
||||
strVal2, err := aReq.FieldAsString(strings.Split(cfgFld.Value[1].Id, utils.NestingSep))
|
||||
tEnd, err := utils.ParseTimeDetectLayout(strVal1, cfgFld.Timezone)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tStart, err := utils.ParseTimeDetectLayout(strVal2, cfgFld.Timezone)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
out = tEnd.Sub(tStart).String()
|
||||
}
|
||||
isString = true
|
||||
}
|
||||
if isString { // format the string additionally with fmtFieldWidth
|
||||
out, err = utils.FmtFieldWidth(cfgFld.Tag, out.(string), cfgFld.Width,
|
||||
@@ -172,17 +189,18 @@ func (ar *AgentRequest) composedField(outTpl utils.RSRFields) (outVal string) {
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
valStr, err := ar.FieldAsString(strings.Split(rsrTpl.Id, utils.NestingSep))
|
||||
if err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> %s",
|
||||
utils.HTTPAgent, err.Error()))
|
||||
fmt.Sprintf("<%s> %s FieldAsString %s",
|
||||
utils.AgentRequest, err.Error(), rsrTpl.Id))
|
||||
continue
|
||||
}
|
||||
if parsed, err := rsrTpl.Parse(valStr); err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> %s",
|
||||
utils.HTTPAgent, err.Error()))
|
||||
fmt.Sprintf("<%s> %s Parse ",
|
||||
utils.AgentRequest, err.Error(), valStr))
|
||||
} else {
|
||||
outVal += parsed
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
package agents
|
||||
|
||||
/*
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
@@ -121,8 +120,6 @@ func TestAgReqAsNavigableMap(t *testing.T) {
|
||||
if mpOut, err := agReq.AsNavigableMap(tplFlds); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eMp, mpOut) {
|
||||
t.Errorf("expecting: %+v, received: %+v",
|
||||
eMp.AsMapStringInterface(), mpOut.AsMapStringInterface())
|
||||
t.Errorf("expecting: %+v, received: %+v", eMp, mpOut)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
147
agents/libdmt.go
147
agents/libdmt.go
@@ -64,6 +64,153 @@ var (
|
||||
ErrDiameterRatingFailed = errors.New("Diameter rating failed")
|
||||
)
|
||||
|
||||
// processorVars will hold various variables using during request processing
|
||||
// here so we can define methods on it
|
||||
type processorVars map[string]interface{}
|
||||
|
||||
// hasSubsystems will return true on single subsystem being present in processorVars
|
||||
func (pv processorVars) hasSubsystems() (has bool) {
|
||||
for _, k := range []string{utils.MetaAccounts, utils.MetaResources,
|
||||
utils.MetaSuppliers, utils.MetaAttributes} {
|
||||
if _, has = pv[k]; has {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (pv processorVars) hasVar(k string) (has bool) {
|
||||
_, has = pv[k]
|
||||
return
|
||||
}
|
||||
|
||||
// valAsInterface returns the string value for fldName
|
||||
func (pv processorVars) valAsInterface(fldPath string) (val interface{}, err error) {
|
||||
fldName := fldPath
|
||||
if strings.HasPrefix(fldPath, utils.MetaCGRReply) {
|
||||
fldName = utils.MetaCGRReply
|
||||
}
|
||||
if !pv.hasVar(fldName) {
|
||||
err = errors.New("not found")
|
||||
return
|
||||
}
|
||||
return engine.NewNavigableMap(pv).FieldAsInterface(strings.Split(fldPath, utils.HIERARCHY_SEP))
|
||||
}
|
||||
|
||||
// valAsString returns the string value for fldName
|
||||
// returns empty if fldName not found
|
||||
func (pv processorVars) valAsString(fldPath string) (val string, err error) {
|
||||
fldName := fldPath
|
||||
if strings.HasPrefix(fldPath, utils.MetaCGRReply) {
|
||||
fldName = utils.MetaCGRReply
|
||||
}
|
||||
if !pv.hasVar(fldName) {
|
||||
return "", utils.ErrNotFoundNoCaps
|
||||
}
|
||||
return engine.NewNavigableMap(pv).FieldAsString(strings.Split(fldPath, utils.HIERARCHY_SEP))
|
||||
}
|
||||
|
||||
// asV1AuthorizeArgs returns the arguments needed by SessionSv1.AuthorizeEvent
|
||||
func (pv processorVars) asV1AuthorizeArgs(cgrEv *utils.CGREvent) (args *sessions.V1AuthorizeArgs) {
|
||||
args = &sessions.V1AuthorizeArgs{ // defaults
|
||||
GetMaxUsage: true,
|
||||
CGREvent: *cgrEv,
|
||||
}
|
||||
if !pv.hasSubsystems() {
|
||||
return
|
||||
}
|
||||
if !pv.hasVar(utils.MetaAccounts) {
|
||||
args.GetMaxUsage = false
|
||||
}
|
||||
if pv.hasVar(utils.MetaResources) {
|
||||
args.AuthorizeResources = true
|
||||
}
|
||||
if pv.hasVar(utils.MetaSuppliers) {
|
||||
args.GetSuppliers = true
|
||||
}
|
||||
if pv.hasVar(utils.MetaAttributes) {
|
||||
args.GetAttributes = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// asV1InitSessionArgs returns the arguments used in SessionSv1.InitSession
|
||||
func (pv processorVars) asV1InitSessionArgs(cgrEv *utils.CGREvent) (args *sessions.V1InitSessionArgs) {
|
||||
args = &sessions.V1InitSessionArgs{ // defaults
|
||||
InitSession: true,
|
||||
CGREvent: *cgrEv,
|
||||
}
|
||||
if !pv.hasSubsystems() {
|
||||
return
|
||||
}
|
||||
if !pv.hasVar(utils.MetaAccounts) {
|
||||
args.InitSession = false
|
||||
}
|
||||
if pv.hasVar(utils.MetaResources) {
|
||||
args.AllocateResources = true
|
||||
}
|
||||
if pv.hasVar(utils.MetaAttributes) {
|
||||
args.GetAttributes = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// asV1UpdateSessionArgs returns the arguments used in SessionSv1.InitSession
|
||||
func (pv processorVars) asV1UpdateSessionArgs(cgrEv *utils.CGREvent) (args *sessions.V1UpdateSessionArgs) {
|
||||
args = &sessions.V1UpdateSessionArgs{ // defaults
|
||||
UpdateSession: true,
|
||||
CGREvent: *cgrEv,
|
||||
}
|
||||
if !pv.hasSubsystems() {
|
||||
return
|
||||
}
|
||||
if !pv.hasVar(utils.MetaAccounts) {
|
||||
args.UpdateSession = false
|
||||
}
|
||||
if pv.hasVar(utils.MetaAttributes) {
|
||||
args.GetAttributes = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// asV1TerminateSessionArgs returns the arguments used in SMGv1.TerminateSession
|
||||
func (pv processorVars) asV1TerminateSessionArgs(cgrEv *utils.CGREvent) (args *sessions.V1TerminateSessionArgs) {
|
||||
args = &sessions.V1TerminateSessionArgs{ // defaults
|
||||
TerminateSession: true,
|
||||
CGREvent: *cgrEv,
|
||||
}
|
||||
if !pv.hasSubsystems() {
|
||||
return
|
||||
}
|
||||
if !pv.hasVar(utils.MetaAccounts) {
|
||||
args.TerminateSession = false
|
||||
}
|
||||
if pv.hasVar(utils.MetaResources) {
|
||||
args.ReleaseResources = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (pv processorVars) asV1ProcessEventArgs(cgrEv *utils.CGREvent) (args *sessions.V1ProcessEventArgs) {
|
||||
args = &sessions.V1ProcessEventArgs{ // defaults
|
||||
Debit: true,
|
||||
CGREvent: *cgrEv,
|
||||
}
|
||||
if !pv.hasSubsystems() {
|
||||
return
|
||||
}
|
||||
if !pv.hasVar(utils.MetaAccounts) {
|
||||
args.Debit = false
|
||||
}
|
||||
if pv.hasVar(utils.MetaResources) {
|
||||
args.AllocateResources = true
|
||||
}
|
||||
if pv.hasVar(utils.MetaAttributes) {
|
||||
args.GetAttributes = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func loadDictionaries(dictsDir, componentId string) error {
|
||||
fi, err := os.Stat(dictsDir)
|
||||
if err != nil {
|
||||
|
||||
@@ -19,15 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package agents
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/sessions"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/radigo"
|
||||
)
|
||||
@@ -47,7 +43,7 @@ func attrVendorFromPath(path string) (attrName, vendorName string) {
|
||||
// radComposedFieldValue extracts the field value out of RADIUS packet
|
||||
// procVars have priority over packet variables
|
||||
func radComposedFieldValue(pkt *radigo.Packet,
|
||||
procVars processorVars, outTpl utils.RSRFields) (outVal string) {
|
||||
agReq *AgentRequest, outTpl utils.RSRFields) (outVal string) {
|
||||
for _, rsrTpl := range outTpl {
|
||||
if rsrTpl.IsStatic() {
|
||||
if parsed, err := rsrTpl.Parse(""); err != nil {
|
||||
@@ -59,13 +55,11 @@ func radComposedFieldValue(pkt *radigo.Packet,
|
||||
}
|
||||
continue
|
||||
}
|
||||
if val, err := procVars.valAsString(rsrTpl.Id); err != nil {
|
||||
if err.Error() != "not found" {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> %s",
|
||||
utils.RadiusAgent, err.Error()))
|
||||
continue
|
||||
}
|
||||
if val, err := agReq.FieldAsString(strings.Split(rsrTpl.Id, utils.NestingSep)); err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> %s",
|
||||
utils.RadiusAgent, err.Error()))
|
||||
continue
|
||||
} else {
|
||||
if parsed, err := rsrTpl.Parse(val); err != nil {
|
||||
utils.Logger.Warning(
|
||||
@@ -90,41 +84,8 @@ func radComposedFieldValue(pkt *radigo.Packet,
|
||||
return outVal
|
||||
}
|
||||
|
||||
// radMetaHandler handles *handler type in configuration fields
|
||||
func radMetaHandler(pkt *radigo.Packet, procVars processorVars,
|
||||
cfgFld *config.CfgCdrField, roundingDecimals int) (outVal string, err error) {
|
||||
handlerArgs := strings.Split(
|
||||
radComposedFieldValue(pkt, procVars, cfgFld.Value), utils.HandlerArgSep)
|
||||
switch cfgFld.HandlerId {
|
||||
case MetaUsageDifference: // expects tEnd|tStart in the composed val
|
||||
if len(handlerArgs) != 2 {
|
||||
return "", errors.New("unexpected number of arguments")
|
||||
}
|
||||
tEnd, err := utils.ParseTimeDetectLayout(handlerArgs[0], cfgFld.Timezone)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tStart, err := utils.ParseTimeDetectLayout(handlerArgs[1], cfgFld.Timezone)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return tEnd.Sub(tStart).String(), nil
|
||||
case utils.MetaDurationSeconds:
|
||||
if len(handlerArgs) != 1 {
|
||||
return "", errors.New("unexpected number of arguments")
|
||||
}
|
||||
val, err := utils.ParseDurationWithNanosecs(handlerArgs[0])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strconv.FormatInt(int64(utils.Round(val.Seconds(),
|
||||
roundingDecimals, utils.ROUNDING_MIDDLE)), 10), nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// radFieldOutVal formats the field value retrieved from RADIUS packet
|
||||
func radFieldOutVal(pkt *radigo.Packet, processorVars processorVars,
|
||||
func radFieldOutVal(pkt *radigo.Packet, agReq *AgentRequest,
|
||||
cfgFld *config.CfgCdrField) (outVal string, err error) {
|
||||
// different output based on cgrFld.Type
|
||||
switch cfgFld.Type {
|
||||
@@ -134,12 +95,7 @@ func radFieldOutVal(pkt *radigo.Packet, processorVars processorVars,
|
||||
case utils.META_CONSTANT:
|
||||
outVal = cfgFld.Value.Id()
|
||||
case utils.META_COMPOSED:
|
||||
outVal = radComposedFieldValue(pkt, processorVars, cfgFld.Value)
|
||||
case utils.META_HANDLER:
|
||||
if outVal, err = radMetaHandler(pkt, processorVars, cfgFld,
|
||||
config.CgrConfig().RoundingDecimals); err != nil {
|
||||
return "", err
|
||||
}
|
||||
outVal = radComposedFieldValue(pkt, agReq, cfgFld.Value)
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported configuration field type: <%s>", cfgFld.Type)
|
||||
}
|
||||
@@ -150,20 +106,10 @@ func radFieldOutVal(pkt *radigo.Packet, processorVars processorVars,
|
||||
}
|
||||
|
||||
// radReplyAppendAttributes appends attributes to a RADIUS reply based on predefined template
|
||||
func radReplyAppendAttributes(reply *radigo.Packet, procVars map[string]interface{},
|
||||
func radReplyAppendAttributes(reply *radigo.Packet, agReq *AgentRequest,
|
||||
cfgFlds []*config.CfgCdrField) (err error) {
|
||||
for _, cfgFld := range cfgFlds {
|
||||
passedAllFilters := true
|
||||
for _, fldFilter := range cfgFld.FieldFilter {
|
||||
if !radPassesFieldFilter(reply, procVars, fldFilter) {
|
||||
passedAllFilters = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !passedAllFilters {
|
||||
continue
|
||||
}
|
||||
fmtOut, err := radFieldOutVal(reply, procVars, cfgFld)
|
||||
fmtOut, err := radFieldOutVal(reply, agReq, cfgFld)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -191,12 +137,15 @@ func NewCGRReply(rply engine.NavigableMapper,
|
||||
return engine.NewNavigableMap(map[string]interface{}{
|
||||
utils.Error: errRply.Error()}), nil
|
||||
}
|
||||
mp, err = rply.AsNavigableMap(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
mp = engine.NewNavigableMap(nil)
|
||||
if rply != nil {
|
||||
mp, err = rply.AsNavigableMap(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
mp.Set([]string{utils.Error}, "", false) // enforce empty error
|
||||
return mp, nil
|
||||
return
|
||||
}
|
||||
|
||||
// newRADataProvider constructs a DataProvider
|
||||
@@ -215,7 +164,7 @@ type radiusDP struct {
|
||||
// String is part of engine.DataProvider interface
|
||||
// when called, it will display the already parsed values out of cache
|
||||
func (pk *radiusDP) String() string {
|
||||
return ""
|
||||
return utils.ToJSON(pk)
|
||||
}
|
||||
|
||||
// FieldAsInterface is part of engine.DataProvider interface
|
||||
@@ -228,6 +177,9 @@ func (pk *radiusDP) FieldAsInterface(fldPath []string) (data interface{}, err er
|
||||
return
|
||||
}
|
||||
err = nil // cancel previous err
|
||||
if len(pk.req.AttributesWithName(fldPath[0], "")) != 0 {
|
||||
data = pk.req.AttributesWithName(fldPath[0], "")[0].GetStringValue()
|
||||
}
|
||||
pk.cache.Set(fldPath, data, false)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/sessions"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/radigo"
|
||||
)
|
||||
@@ -91,47 +90,6 @@ func TestAttrVendorFromPath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRadPassesFieldFilter(t *testing.T) {
|
||||
pkt := radigo.NewPacket(radigo.AccountingRequest, 1, dictRad, coder, "CGRateS.org")
|
||||
if err := pkt.AddAVPWithName("User-Name", "flopsy", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("Cisco-NAS-Port", "CGR1", "Cisco"); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !radPassesFieldFilter(pkt, nil, nil) {
|
||||
t.Error("not passing empty filter")
|
||||
}
|
||||
if !radPassesFieldFilter(pkt, nil,
|
||||
utils.NewRSRFieldMustCompile("User-Name(flopsy)")) {
|
||||
t.Error("not passing valid filter")
|
||||
}
|
||||
if radPassesFieldFilter(pkt, nil,
|
||||
utils.NewRSRFieldMustCompile("User-Name(notmatching)")) {
|
||||
t.Error("passing invalid filter value")
|
||||
}
|
||||
if !radPassesFieldFilter(pkt, nil,
|
||||
utils.NewRSRFieldMustCompile("Cisco>Cisco-NAS-Port(CGR1)")) {
|
||||
t.Error("not passing valid filter")
|
||||
}
|
||||
if radPassesFieldFilter(pkt, nil,
|
||||
utils.NewRSRFieldMustCompile("Cisco>Cisco-NAS-Port(notmatching)")) {
|
||||
t.Error("passing invalid filter value")
|
||||
}
|
||||
if !radPassesFieldFilter(pkt, processorVars{MetaRadReqType: MetaRadAuth},
|
||||
utils.NewRSRFieldMustCompile(fmt.Sprintf("%s(%s)", MetaRadReqType, MetaRadAuth))) {
|
||||
t.Error("not passing valid filter")
|
||||
}
|
||||
if radPassesFieldFilter(pkt, processorVars{MetaRadReqType: MetaRadAcctStart},
|
||||
utils.NewRSRFieldMustCompile(fmt.Sprintf("%s(%s)", MetaRadReqType, MetaRadAuth))) {
|
||||
t.Error("passing invalid filter")
|
||||
}
|
||||
if radPassesFieldFilter(pkt, nil,
|
||||
utils.NewRSRFieldMustCompile("UnknownField(notmatching)")) {
|
||||
t.Error("passing invalid filter value")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRadComposedFieldValue(t *testing.T) {
|
||||
pkt := radigo.NewPacket(radigo.AccountingRequest, 1, dictRad, coder, "CGRateS.org")
|
||||
if err := pkt.AddAVPWithName("User-Name", "flopsy", ""); err != nil {
|
||||
@@ -140,10 +98,13 @@ func TestRadComposedFieldValue(t *testing.T) {
|
||||
if err := pkt.AddAVPWithName("Cisco-NAS-Port", "CGR1", "Cisco"); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
eOut := fmt.Sprintf("%s|flopsy|CGR1", MetaRadAcctStart)
|
||||
if out := radComposedFieldValue(pkt, processorVars{MetaRadReqType: MetaRadAcctStart},
|
||||
utils.ParseRSRFieldsMustCompile(fmt.Sprintf("%s;^|;User-Name;^|;Cisco>Cisco-NAS-Port",
|
||||
MetaRadReqType), utils.INFIELD_SEP)); out != eOut {
|
||||
agReq := newAgentRequest(nil, nil, "cgrates.org", nil)
|
||||
agReq.Vars.Set([]string{MetaRadReqType}, MetaRadAcctStart, false)
|
||||
agReq.Vars.Set([]string{"Cisco"}, "CGR1", false)
|
||||
agReq.Vars.Set([]string{"User-Name"}, "flopsy", false)
|
||||
eOut := "*radAcctStart|flopsy|CGR1"
|
||||
if out := radComposedFieldValue(pkt, agReq,
|
||||
utils.ParseRSRFieldsMustCompile("*vars.*radReqType;^|;*vars.User-Name;^|;*vars.Cisco", utils.INFIELD_SEP)); out != eOut {
|
||||
t.Errorf("Expecting: <%s>, received: <%s>", eOut, out)
|
||||
}
|
||||
}
|
||||
@@ -157,263 +118,33 @@ func TestRadFieldOutVal(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
eOut := fmt.Sprintf("%s|flopsy|CGR1", MetaRadAcctStart)
|
||||
agReq := newAgentRequest(nil, nil, "cgrates.org", nil)
|
||||
agReq.Vars.Set([]string{MetaRadReqType}, MetaRadAcctStart, false)
|
||||
agReq.Vars.Set([]string{"Cisco"}, "CGR1", false)
|
||||
agReq.Vars.Set([]string{"User-Name"}, "flopsy", false)
|
||||
//processorVars{MetaRadReqType: MetaRadAcctStart}
|
||||
cfgFld := &config.CfgCdrField{Tag: "ComposedTest", Type: utils.META_COMPOSED, FieldId: utils.Destination,
|
||||
Value: utils.ParseRSRFieldsMustCompile(fmt.Sprintf("%s;^|;User-Name;^|;Cisco>Cisco-NAS-Port", MetaRadReqType), utils.INFIELD_SEP), Mandatory: true}
|
||||
if outVal, err := radFieldOutVal(pkt, processorVars{MetaRadReqType: MetaRadAcctStart}, cfgFld); err != nil {
|
||||
Value: utils.ParseRSRFieldsMustCompile("*vars.*radReqType;^|;*vars.User-Name;^|;*vars.Cisco", utils.INFIELD_SEP), Mandatory: true}
|
||||
if outVal, err := radFieldOutVal(pkt, agReq, cfgFld); err != nil {
|
||||
t.Error(err)
|
||||
} else if outVal != eOut {
|
||||
t.Errorf("Expecting: <%s>, received: <%s>", eOut, outVal)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRadReqAsCGREvent(t *testing.T) {
|
||||
pkt := radigo.NewPacket(radigo.AccountingRequest, 1, dictRad, coder, "CGRateS.org")
|
||||
// Sample minimal packet sent by Kamailio
|
||||
if err := pkt.AddAVPWithName("Acct-Status-Type", "2", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("Service-Type", "15", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("Sip-Response-Code", "200", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("Sip-Method", "8", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("Event-Timestamp", "1497106119", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("Sip-From-Tag", "75c2f57b", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("Sip-To-Tag", "51585361", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("Acct-Session-Id", "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("User-Name", "1001", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("Called-Station-Id", "1002", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("Ascend-User-Acct-Time", "1497106115", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("NAS-Port-Id", "5060", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("Acct-Delay-Time", "0", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := pkt.AddAVPWithName("NAS-IP-Address", "127.0.0.1", ""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
cfgFlds := []*config.CfgCdrField{
|
||||
&config.CfgCdrField{Tag: "TOR", FieldId: utils.ToR, Type: utils.META_CONSTANT,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.VOICE, utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "OriginID", FieldId: utils.OriginID, Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("Acct-Session-Id;^-;Sip-From-Tag;^-;Sip-To-Tag", utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "OriginHost", FieldId: utils.OriginHost, Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("NAS-IP-Address", utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "RequestType", FieldId: utils.RequestType, Type: utils.META_CONSTANT,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.META_PREPAID, utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "Direction", FieldId: utils.Direction, Type: utils.META_CONSTANT,
|
||||
Value: utils.ParseRSRFieldsMustCompile(utils.OUT, utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "Tenant", FieldId: utils.Tenant, Type: utils.META_CONSTANT,
|
||||
Value: utils.ParseRSRFieldsMustCompile("cgrates.org", utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "Category", FieldId: utils.Category, Type: utils.META_CONSTANT,
|
||||
Value: utils.ParseRSRFieldsMustCompile("call", utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "Account", FieldId: utils.Account, Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("User-Name", utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "Destination", FieldId: utils.Destination, Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("Called-Station-Id", utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "SetupTime", FieldId: utils.SetupTime, Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("Ascend-User-Acct-Time", utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "AnswerTime", FieldId: utils.AnswerTime, Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("Ascend-User-Acct-Time", utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "Usage", FieldId: utils.Usage, Type: utils.META_HANDLER, HandlerId: MetaUsageDifference,
|
||||
Value: utils.ParseRSRFieldsMustCompile("Event-Timestamp;^|;Ascend-User-Acct-Time", utils.INFIELD_SEP)},
|
||||
}
|
||||
eOut := &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: utils.UUIDSha1Prefix(),
|
||||
Time: utils.TimePointer(time.Now()),
|
||||
Event: map[string]interface{}{
|
||||
utils.Account: "1001",
|
||||
utils.AnswerTime: "1497106115",
|
||||
utils.Category: "call",
|
||||
utils.Destination: "1002",
|
||||
utils.Direction: utils.META_OUT,
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-75c2f57b-51585361",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.SetupTime: "1497106115",
|
||||
utils.Tenant: "cgrates.org",
|
||||
utils.ToR: "*voice",
|
||||
utils.Usage: "4s",
|
||||
},
|
||||
}
|
||||
if outVal, err := radReqAsCGREvent(pkt, processorVars{MetaRadReqType: MetaRadAcctStart}, nil, cfgFlds); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(outVal.Tenant, eOut.Tenant) {
|
||||
t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(eOut.Tenant), utils.ToJSON(outVal.Tenant))
|
||||
} else if !reflect.DeepEqual(outVal.Event, eOut.Event) {
|
||||
t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(eOut.Event), utils.ToJSON(outVal.Event))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPVAsV1AuthorizeArgs(t *testing.T) {
|
||||
cgrEv := &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: utils.UUIDSha1Prefix(),
|
||||
Time: utils.TimePointer(time.Now()),
|
||||
Event: map[string]interface{}{
|
||||
utils.Account: "1001",
|
||||
utils.AnswerTime: "1497106115",
|
||||
utils.Category: "call",
|
||||
utils.Destination: "1002",
|
||||
utils.Direction: utils.META_OUT,
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-75c2f57b-51585361",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.SetupTime: "1497106115",
|
||||
utils.Tenant: "cgrates.org",
|
||||
utils.ToR: "*voice",
|
||||
utils.Usage: "4s",
|
||||
},
|
||||
}
|
||||
expected := &sessions.V1AuthorizeArgs{
|
||||
GetMaxUsage: true,
|
||||
CGREvent: *cgrEv,
|
||||
}
|
||||
outVal := processorVars{MetaRadReqType: MetaRadAcctStart}.asV1AuthorizeArgs(cgrEv)
|
||||
if !reflect.DeepEqual(expected, outVal) {
|
||||
t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(expected), utils.ToJSON(outVal))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPVAsV1InitSessionArgs(t *testing.T) {
|
||||
cgrEv := &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: utils.UUIDSha1Prefix(),
|
||||
Time: utils.TimePointer(time.Now()),
|
||||
Event: map[string]interface{}{
|
||||
utils.Account: "1001",
|
||||
utils.AnswerTime: "1497106115",
|
||||
utils.Category: "call",
|
||||
utils.Destination: "1002",
|
||||
utils.Direction: utils.META_OUT,
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-75c2f57b-51585361",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.SetupTime: "1497106115",
|
||||
utils.Tenant: "cgrates.org",
|
||||
utils.ToR: "*voice",
|
||||
utils.Usage: "4s",
|
||||
},
|
||||
}
|
||||
expected := &sessions.V1InitSessionArgs{
|
||||
InitSession: true,
|
||||
CGREvent: *cgrEv,
|
||||
}
|
||||
outVal := processorVars{MetaRadReqType: MetaRadAcctStart}.asV1InitSessionArgs(cgrEv)
|
||||
if !reflect.DeepEqual(expected, outVal) {
|
||||
t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(expected), utils.ToJSON(outVal))
|
||||
}
|
||||
eInitArgs := &sessions.V1InitSessionArgs{
|
||||
InitSession: false,
|
||||
AllocateResources: true,
|
||||
GetAttributes: true,
|
||||
CGREvent: *cgrEv,
|
||||
}
|
||||
initArgs := processorVars{MetaRadReqType: MetaRadAcctStart, utils.MetaResources: true,
|
||||
utils.MetaAttributes: true}.asV1InitSessionArgs(cgrEv)
|
||||
if !reflect.DeepEqual(eInitArgs, initArgs) {
|
||||
t.Errorf("expecting: %+v, received: %+v", eInitArgs, initArgs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPVAsV1UpdateSessionArgs(t *testing.T) {
|
||||
cgrEv := &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: utils.UUIDSha1Prefix(),
|
||||
Time: utils.TimePointer(time.Now()),
|
||||
Event: map[string]interface{}{
|
||||
utils.Account: "1001",
|
||||
utils.AnswerTime: "1497106115",
|
||||
utils.Category: "call",
|
||||
utils.Destination: "1002",
|
||||
utils.Direction: utils.META_OUT,
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-75c2f57b-51585361",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.SetupTime: "1497106115",
|
||||
utils.Tenant: "cgrates.org",
|
||||
utils.ToR: "*voice",
|
||||
utils.Usage: "4s",
|
||||
},
|
||||
}
|
||||
expected := &sessions.V1UpdateSessionArgs{
|
||||
UpdateSession: true,
|
||||
CGREvent: *cgrEv,
|
||||
}
|
||||
outVal := processorVars{MetaRadReqType: MetaRadAcctStart}.asV1UpdateSessionArgs(cgrEv)
|
||||
if !reflect.DeepEqual(expected, outVal) {
|
||||
t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(expected), utils.ToJSON(outVal))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPVAsTerminateSessionArgs(t *testing.T) {
|
||||
cgrEv := &utils.CGREvent{
|
||||
Tenant: "cgrates.org",
|
||||
ID: utils.UUIDSha1Prefix(),
|
||||
Time: utils.TimePointer(time.Now()),
|
||||
Event: map[string]interface{}{
|
||||
utils.Account: "1001",
|
||||
utils.AnswerTime: "1497106115",
|
||||
utils.Category: "call",
|
||||
utils.Destination: "1002",
|
||||
utils.Direction: utils.META_OUT,
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-75c2f57b-51585361",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.SetupTime: "1497106115",
|
||||
utils.Tenant: "cgrates.org",
|
||||
utils.ToR: "*voice",
|
||||
utils.Usage: "4s",
|
||||
},
|
||||
}
|
||||
expected := &sessions.V1TerminateSessionArgs{
|
||||
TerminateSession: true,
|
||||
CGREvent: *cgrEv,
|
||||
}
|
||||
outVal := processorVars{MetaRadReqType: MetaRadAcctStart}.asV1TerminateSessionArgs(cgrEv)
|
||||
if !reflect.DeepEqual(expected, outVal) {
|
||||
t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(expected), utils.ToJSON(outVal))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRadReplyAppendAttributes(t *testing.T) {
|
||||
rply := radigo.NewPacket(radigo.AccessRequest, 2, dictRad, coder, "CGRateS.org").Reply()
|
||||
rplyFlds := []*config.CfgCdrField{
|
||||
&config.CfgCdrField{Tag: "ReplyCode", FieldId: MetaRadReplyCode, Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("*cgrReply>Attributes>RadReply", utils.INFIELD_SEP)},
|
||||
Value: utils.ParseRSRFieldsMustCompile("*cgrReply.Attributes.RadReply", utils.INFIELD_SEP)},
|
||||
&config.CfgCdrField{Tag: "Acct-Session-Time", FieldId: "Acct-Session-Time", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("*cgrReply>MaxUsage{*duration_seconds}", utils.INFIELD_SEP)},
|
||||
Value: utils.ParseRSRFieldsMustCompile("*cgrReply.MaxUsage{*duration_seconds}", utils.INFIELD_SEP)},
|
||||
}
|
||||
procVars := make(processorVars)
|
||||
procVars[utils.MetaCGRReply] = map[string]interface{}{
|
||||
utils.CapAttributes: map[string]interface{}{
|
||||
"RadReply": "AccessAccept",
|
||||
utils.Account: "1001",
|
||||
},
|
||||
utils.CapMaxUsage: time.Duration(time.Hour),
|
||||
}
|
||||
if err := radReplyAppendAttributes(rply, procVars, rplyFlds); err != nil {
|
||||
agReq := newAgentRequest(nil, nil, "cgrates.org", nil)
|
||||
agReq.CGRReply.Set([]string{utils.CapMaxUsage}, time.Duration(time.Hour), false)
|
||||
agReq.CGRReply.Set([]string{utils.CapAttributes, "RadReply"}, "AccessAccept", false)
|
||||
agReq.CGRReply.Set([]string{utils.CapAttributes, utils.Account}, "1001", false)
|
||||
if err := radReplyAppendAttributes(rply, agReq, rplyFlds); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if rply.Code != radigo.AccessAccept {
|
||||
|
||||
@@ -19,8 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package agents
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
@@ -88,6 +88,7 @@ func (ra *RadiusAgent) handleAuth(req *radigo.Packet) (rpl *radigo.Packet, err e
|
||||
return
|
||||
}
|
||||
agReq := newAgentRequest(dcdr, ra.tenantCfg, ra.cgrCfg.DefaultTenant, ra.filterS)
|
||||
agReq.Vars.Set([]string{MetaRadReqType}, utils.StringToInterface(MetaRadAuth), true)
|
||||
rpl = req.Reply()
|
||||
rpl.Code = radigo.AccessAccept
|
||||
var processed bool
|
||||
@@ -101,12 +102,12 @@ func (ra *RadiusAgent) handleAuth(req *radigo.Packet) (rpl *radigo.Packet, err e
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> error: <%s> ignoring request: %s, process vars: %+v",
|
||||
utils.RadiusAgent, err.Error(), utils.ToJSON(req), procVars))
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> error: <%s> ignoring request: %s, agentRequest: %+v",
|
||||
utils.RadiusAgent, err.Error(), utils.ToJSON(req), utils.ToJSON(agReq)))
|
||||
return nil, nil
|
||||
} else if !processed {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> no request processor enabled, ignoring request %s, process vars: %+v",
|
||||
utils.RadiusAgent, utils.ToJSON(req), procVars))
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> no request processor enabled, ignoring request %s, agentRequest: %+v",
|
||||
utils.RadiusAgent, utils.ToJSON(req), utils.ToJSON(agReq)))
|
||||
return nil, nil
|
||||
}
|
||||
return
|
||||
@@ -115,24 +116,21 @@ func (ra *RadiusAgent) handleAuth(req *radigo.Packet) (rpl *radigo.Packet, err e
|
||||
// handleAcct handles RADIUS Accounting request
|
||||
// supports: Acct-Status-Type = Start, Interim-Update, Stop
|
||||
func (ra *RadiusAgent) handleAcct(req *radigo.Packet) (rpl *radigo.Packet, err error) {
|
||||
req.SetAVPValues() // populate string values in AVPs
|
||||
procVars := make(processorVars)
|
||||
if avps := req.AttributesWithName("Acct-Status-Type", ""); len(avps) != 0 { // populate accounting type
|
||||
switch avps[0].GetStringValue() { // first AVP found will give out the type of accounting
|
||||
case RadAcctStart:
|
||||
procVars[MetaRadReqType] = MetaRadAcctStart
|
||||
case RadAcctInterimUpdate:
|
||||
procVars[MetaRadReqType] = MetaRadAcctUpdate
|
||||
case RadAcctStop:
|
||||
procVars[MetaRadReqType] = MetaRadAcctStop
|
||||
}
|
||||
req.SetAVPValues() // populate string values in AVPs
|
||||
dcdr, err := newRADataProvider(req) // dcdr will provide information from request
|
||||
if err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> error creating decoder: %s",
|
||||
utils.RadiusAgent, err.Error()))
|
||||
return
|
||||
}
|
||||
agReq := newAgentRequest(dcdr, ra.tenantCfg, ra.cgrCfg.DefaultTenant, ra.filterS)
|
||||
rpl = req.Reply()
|
||||
rpl.Code = radigo.AccountingResponse
|
||||
var processed bool
|
||||
for _, reqProcessor := range ra.cgrCfg.RadiusAgentCfg().RequestProcessors {
|
||||
var lclProcessed bool
|
||||
if lclProcessed, err = ra.processRequest(reqProcessor, req, procVars, rpl); lclProcessed {
|
||||
if lclProcessed, err = ra.processRequest(reqProcessor, agReq, rpl); lclProcessed {
|
||||
processed = lclProcessed
|
||||
}
|
||||
if err != nil || (lclProcessed && !reqProcessor.ContinueOnSuccess) {
|
||||
@@ -140,12 +138,12 @@ func (ra *RadiusAgent) handleAcct(req *radigo.Packet) (rpl *radigo.Packet, err e
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> error: <%s> ignoring request: %s, process vars: %+v",
|
||||
utils.RadiusAgent, err.Error(), utils.ToJSON(req), procVars))
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> error: <%s> ignoring request: %s, agentRequest: %+v",
|
||||
utils.RadiusAgent, err.Error(), utils.ToJSON(req), utils.ToJSON(agReq)))
|
||||
return nil, nil
|
||||
} else if !processed {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> no request processor enabled, ignoring request %s, process vars: %+v",
|
||||
utils.RadiusAgent, utils.ToJSON(req), procVars))
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> no request processor enabled, ignoring request %s, agentRequest: %+v",
|
||||
utils.RadiusAgent, utils.ToJSON(req), utils.ToJSON(agReq)))
|
||||
return nil, nil
|
||||
}
|
||||
return
|
||||
@@ -178,7 +176,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
|
||||
case utils.MetaDryRun:
|
||||
utils.Logger.Info(
|
||||
fmt.Sprintf("<%s> DRY_RUN, processorID: %s, CGREvent: %s",
|
||||
utils.HTTPAgent, reqProcessor.Id, utils.ToJSON(cgrEv)))
|
||||
utils.RadiusAgent, reqProcessor.Id, utils.ToJSON(cgrEv)))
|
||||
case utils.MetaAuth:
|
||||
authArgs := sessions.NewV1AuthorizeArgs(
|
||||
reqProcessor.Flags.HasKey(utils.MetaAttributes),
|
||||
@@ -191,7 +189,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
|
||||
reqProcessor.Flags.HasKey(utils.MetaSuppliersEventCost),
|
||||
*cgrEv)
|
||||
var authReply sessions.V1AuthorizeReply
|
||||
err = ha.sessionS.Call(utils.SessionSv1AuthorizeEvent,
|
||||
err = ra.sessionS.Call(utils.SessionSv1AuthorizeEvent,
|
||||
authArgs, &authReply)
|
||||
if agReq.CGRReply, err = NewCGRReply(&authReply, err); err != nil {
|
||||
return
|
||||
@@ -204,7 +202,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
|
||||
reqProcessor.Flags.HasKey(utils.MetaThresholds),
|
||||
reqProcessor.Flags.HasKey(utils.MetaStats), *cgrEv)
|
||||
var initReply sessions.V1InitSessionReply
|
||||
err = ha.sessionS.Call(utils.SessionSv1InitiateSession,
|
||||
err = ra.sessionS.Call(utils.SessionSv1InitiateSession,
|
||||
initArgs, &initReply)
|
||||
if agReq.CGRReply, err = NewCGRReply(&initReply, err); err != nil {
|
||||
return
|
||||
@@ -214,7 +212,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
|
||||
reqProcessor.Flags.HasKey(utils.MetaAttributes),
|
||||
reqProcessor.Flags.HasKey(utils.MetaAccounts), *cgrEv)
|
||||
var updateReply sessions.V1UpdateSessionReply
|
||||
err = ha.sessionS.Call(utils.SessionSv1UpdateSession,
|
||||
err = ra.sessionS.Call(utils.SessionSv1UpdateSession,
|
||||
updateArgs, &updateReply)
|
||||
if agReq.CGRReply, err = NewCGRReply(&updateReply, err); err != nil {
|
||||
return
|
||||
@@ -226,7 +224,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
|
||||
reqProcessor.Flags.HasKey(utils.MetaThresholds),
|
||||
reqProcessor.Flags.HasKey(utils.MetaStats), *cgrEv)
|
||||
var tRply string
|
||||
err = ha.sessionS.Call(utils.SessionSv1TerminateSession,
|
||||
err = ra.sessionS.Call(utils.SessionSv1TerminateSession,
|
||||
terminateArgs, &tRply)
|
||||
if agReq.CGRReply, err = NewCGRReply(nil, err); err != nil {
|
||||
return
|
||||
@@ -237,7 +235,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
|
||||
reqProcessor.Flags.HasKey(utils.MetaAccounts),
|
||||
reqProcessor.Flags.HasKey(utils.MetaAttributes), *cgrEv)
|
||||
var eventRply sessions.V1ProcessEventReply
|
||||
err = ha.sessionS.Call(utils.SessionSv1ProcessEvent,
|
||||
err = ra.sessionS.Call(utils.SessionSv1ProcessEvent,
|
||||
evArgs, &eventRply)
|
||||
if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
|
||||
cgrEv.Event[utils.Usage] = 0 // avoid further debits
|
||||
@@ -251,7 +249,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
|
||||
// separate request so we can capture the Terminate/Event also here
|
||||
if reqProcessor.Flags.HasKey(utils.MetaCDRs) {
|
||||
var rplyCDRs string
|
||||
if err = ha.sessionS.Call(utils.SessionSv1ProcessCDR,
|
||||
if err = ra.sessionS.Call(utils.SessionSv1ProcessCDR,
|
||||
*cgrEv, &rplyCDRs); err != nil {
|
||||
agReq.CGRReply.Set([]string{utils.Error}, err.Error(), false)
|
||||
}
|
||||
@@ -261,11 +259,13 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
|
||||
} else {
|
||||
agReq.Reply.Merge(nM)
|
||||
}
|
||||
//update rply *radigo.Packet
|
||||
if err := radReplyAppendAttributes(rply, agReq, reqProcessor.ReplyFields); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if reqType == utils.MetaDryRun {
|
||||
utils.Logger.Info(
|
||||
fmt.Sprintf("<%s> DRY_RUN, HTTP reply: %s",
|
||||
utils.HTTPAgent, utils.ToJSON(rply)))
|
||||
fmt.Sprintf("<%s> DRY_RUN, Radius reply: %s",
|
||||
utils.RadiusAgent, utils.ToJSON(rply)))
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ func TestRAitAcctStart(t *testing.T) {
|
||||
}
|
||||
// Make sure the sessin is managed by SMG
|
||||
var aSessions []*sessions.ActiveSession
|
||||
if err := raRPC.Call("SMGenericV1.GetActiveSessions",
|
||||
if err := raRPC.Call(utils.SessionSv1GetActiveSessions,
|
||||
map[string]string{utils.RunID: utils.META_DEFAULT,
|
||||
utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-51585361-75c2f57b"},
|
||||
&aSessions); err != nil {
|
||||
@@ -279,7 +279,7 @@ func TestRAitAcctStop(t *testing.T) {
|
||||
t.Errorf("Unexpected CDR CostSource received for CDR: %v", cdrs[0])
|
||||
}
|
||||
if cdrs[0].Cost != 0.01 {
|
||||
t.Errorf("Unexpected CDR Cost received for CDR: %v", cdrs[0])
|
||||
t.Errorf("Unexpected CDR Cost received for CDR: %v", cdrs[0].Cost)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ func startRadiusAgent(internalSMGChan chan rpcclient.RpcClientConnection, exitCh
|
||||
return
|
||||
}
|
||||
}
|
||||
ra, err := agents.NewRadiusAgent(cfg, smgConn)
|
||||
ra, err := agents.NewRadiusAgent(cfg, filterS, smgConn)
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<RadiusAgent> error: <%s>", err.Error()))
|
||||
exitChan <- true
|
||||
|
||||
@@ -29,18 +29,6 @@
|
||||
|
||||
"rals": {
|
||||
"enabled": true,
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"pubsubs_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"users_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"aliases_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"scheduler": {
|
||||
@@ -52,26 +40,6 @@
|
||||
"rals_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
},
|
||||
|
||||
"cdrstats": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"pubsubs": {
|
||||
"enabled": true, // starts PubSub service: <true|false>.
|
||||
},
|
||||
|
||||
"aliases": {
|
||||
"enabled": true, // starts Aliases service: <true|false>.
|
||||
},
|
||||
|
||||
"users": {
|
||||
"enabled": true,
|
||||
"indexes": ["SubscriberId"],
|
||||
},
|
||||
|
||||
"resources": {
|
||||
@@ -88,6 +56,18 @@
|
||||
|
||||
"sessions": {
|
||||
"enabled": true,
|
||||
"attributes_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"cdrs_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"rals_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"resources_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"debit_interval": "10s",
|
||||
},
|
||||
|
||||
@@ -99,70 +79,73 @@
|
||||
"request_processors": [
|
||||
{
|
||||
"id": "KamailioAuth",
|
||||
"filters": ["*string:*request.request_type:*radAuth"],
|
||||
"flags": ["*dryrun"],
|
||||
"filters": ["*string:*vars.*radReqType:*radAuth"],
|
||||
"flags": ["*auth", "*accounts",],
|
||||
"continue_on_success": false,
|
||||
"request_fields":[
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*constant",
|
||||
"value": "*prepaid", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed",
|
||||
"value": "Acct-Session-Id;^-;Sip-From-Tag", "mandatory": true},
|
||||
"value": "*request.Acct-Session-Id;^-;*request.Sip-From-Tag", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed",
|
||||
"value": "User-Name", "mandatory": true},
|
||||
"value": "*request.User-Name", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed",
|
||||
"value": "Called-Station-Id", "mandatory": true},
|
||||
"value": "*request.Called-Station-Id", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed",
|
||||
"value": "Event-Timestamp", "mandatory": true},
|
||||
"value": "*request.Event-Timestamp", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed",
|
||||
"value": "Event-Timestamp", "mandatory": true},
|
||||
"value": "*request.Event-Timestamp", "mandatory": true},
|
||||
],
|
||||
"reply_fields":[
|
||||
{"tag": "MaxUsage", "field_id": "SIP-AVP", "type": "*composed",
|
||||
"value": "^session_max_time#;*cgrReply>MaxUsage{*duration_seconds}", "mandatory": true},
|
||||
"value": "^session_max_time#;*cgrReply.MaxUsage{*duration_seconds}", "mandatory": true},
|
||||
],
|
||||
},
|
||||
{
|
||||
"id": "KamailioAccountingStart",
|
||||
"filters": ["*string:*request.request_type:*radAcctStart"],
|
||||
"flags": ["*dryrun"],
|
||||
"filters": ["*string:*request.Acct-Status-Type:Start"],
|
||||
"flags": ["*initiate","*attributes","*resources","*accounts"],
|
||||
"continue_on_success": false,
|
||||
"request_fields":[
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*constant",
|
||||
"value": "*prepaid", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed",
|
||||
"value": "Acct-Session-Id;^-;Sip-From-Tag;^-;Sip-To-Tag", "mandatory": true},
|
||||
"value": "*request.Acct-Session-Id;^-;*request.Sip-From-Tag;^-;*request.Sip-To-Tag", "mandatory": true},
|
||||
{"tag": "OriginHost", "field_id": "OriginHost", "type": "*composed",
|
||||
"value": "NAS-IP-Address", "mandatory": true},
|
||||
"value": "*request.NAS-IP-Address", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed",
|
||||
"value": "User-Name", "mandatory": true},
|
||||
"value": "*request.User-Name", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed",
|
||||
"value": "Called-Station-Id", "mandatory": true},
|
||||
"value": "*request.Called-Station-Id", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed",
|
||||
"value": "Ascend-User-Acct-Time", "mandatory": true},
|
||||
"value": "*request.Ascend-User-Acct-Time", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed",
|
||||
"value": "Ascend-User-Acct-Time", "mandatory": true},
|
||||
"value": "*request.Ascend-User-Acct-Time", "mandatory": true},
|
||||
],
|
||||
"reply_fields":[],
|
||||
},
|
||||
{
|
||||
"id": "KamailioAccountingStop",
|
||||
"filters": ["*string:*request.request_type:*radAcctStop"],
|
||||
"flags": ["*dryrun"],
|
||||
"filters": ["*string:*request.Acct-Status-Type:Stop"],
|
||||
"flags": ["*terminate","*resources","*accounts","*cdrs"],
|
||||
"continue_on_success": false,
|
||||
"request_fields":[
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*constant",
|
||||
"value": "*prepaid", "mandatory": true},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed",
|
||||
"value": "Acct-Session-Id;^-;Sip-From-Tag;^-;Sip-To-Tag", "mandatory": true},
|
||||
"value": "*request.Acct-Session-Id;^-;*request.Sip-From-Tag;^-;*request.Sip-To-Tag", "mandatory": true},
|
||||
{"tag": "OriginHost", "field_id": "OriginHost", "type": "*composed",
|
||||
"value": "NAS-IP-Address", "mandatory": true},
|
||||
"value": "*request.NAS-IP-Address", "mandatory": true},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*composed",
|
||||
"value": "User-Name", "mandatory": true},
|
||||
"value": "*request.User-Name", "mandatory": true},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed",
|
||||
"value": "Called-Station-Id", "mandatory": true},
|
||||
"value": "*request.Called-Station-Id", "mandatory": true},
|
||||
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed",
|
||||
"value": "Ascend-User-Acct-Time", "mandatory": true},
|
||||
"value": "*request.Ascend-User-Acct-Time", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed",
|
||||
"value": "Ascend-User-Acct-Time", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*handler", "handler_id": "*usage_difference",
|
||||
"value": "Event-Timestamp;^|;Ascend-User-Acct-Time", "mandatory": true},
|
||||
"value": "*request.Ascend-User-Acct-Time", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*usage_difference",
|
||||
"value": "*request.Event-Timestamp;*request.Ascend-User-Acct-Time", "mandatory": true},
|
||||
],
|
||||
"reply_fields":[],
|
||||
},
|
||||
|
||||
@@ -1902,6 +1902,7 @@ func (smg *SMGeneric) BiRPCv1TerminateSession(clnt rpcclient.RpcClientConnection
|
||||
if !args.TerminateSession && !args.ReleaseResources {
|
||||
return utils.NewErrMandatoryIeMissing("subsystems")
|
||||
}
|
||||
//
|
||||
if args.CGREvent.Tenant == "" {
|
||||
args.CGREvent.Tenant = smg.cgrCfg.DefaultTenant
|
||||
}
|
||||
|
||||
@@ -323,6 +323,7 @@ const (
|
||||
TRIGGER_BALANCE_EXPIRED = "*balance_expired"
|
||||
HIERARCHY_SEP = ">"
|
||||
META_COMPOSED = "*composed"
|
||||
META_USAGE_DIFFERENCE = "*usage_difference"
|
||||
MetaString = "*string"
|
||||
NegativePrefix = "!"
|
||||
MatchStartPrefix = "^"
|
||||
@@ -523,6 +524,7 @@ const (
|
||||
MetaDryRun = "*dryrun"
|
||||
Event = "Event"
|
||||
EmptyString = ""
|
||||
AgentRequest = "AgentRequest"
|
||||
)
|
||||
|
||||
// Migrator Action
|
||||
|
||||
Reference in New Issue
Block a user