diff --git a/agents/radagent.go b/agents/radagent.go index 27c1a9450..1d4fcdc43 100644 --- a/agents/radagent.go +++ b/agents/radagent.go @@ -20,6 +20,8 @@ package agents import ( "fmt" + "strings" + "sync" "github.com/cgrates/birpc/context" "github.com/cgrates/cgrates/config" @@ -55,23 +57,35 @@ func NewRadiusAgent(cgrCfg *config.CGRConfig, filterS *engine.FilterS, dicts := radigo.NewDictionaries(dts) ra = &RadiusAgent{cgrCfg: cgrCfg, filterS: filterS, connMgr: connMgr} secrets := radigo.NewSecrets(cgrCfg.RadiusAgentCfg().ClientSecrets) - ra.rsAuth = radigo.NewServer(cgrCfg.RadiusAgentCfg().ListenNet, - cgrCfg.RadiusAgentCfg().ListenAuth, secrets, dicts, - map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){ - radigo.AccessRequest: ra.handleAuth}, nil) - ra.rsAcct = radigo.NewServer(cgrCfg.RadiusAgentCfg().ListenNet, - cgrCfg.RadiusAgentCfg().ListenAcct, secrets, dicts, - map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){ - radigo.AccountingRequest: ra.handleAcct}, nil) + ra.rsAuth = make(map[string]*radigo.Server, len(ra.cgrCfg.RadiusAgentCfg().Listeners)) + for i := range ra.cgrCfg.RadiusAgentCfg().Listeners { + net := cgrCfg.RadiusAgentCfg().Listeners[i].Network + addr := cgrCfg.RadiusAgentCfg().Listeners[i].AuthAddr + ra.rsAuth[net+"://"+addr] = radigo.NewServer(net, + addr, secrets, dicts, + map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){ + radigo.AccessRequest: ra.handleAuth}, nil) + } + ra.rsAcct = make(map[string]*radigo.Server, len(ra.cgrCfg.RadiusAgentCfg().Listeners)) + for i := range ra.cgrCfg.RadiusAgentCfg().Listeners { + net := cgrCfg.RadiusAgentCfg().Listeners[i].Network + addr := cgrCfg.RadiusAgentCfg().Listeners[i].AcctAddr + ra.rsAcct[net+"://"+addr] = radigo.NewServer(net, + addr, secrets, dicts, + map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){ + radigo.AccountingRequest: ra.handleAcct}, nil) + } return } type RadiusAgent struct { + sync.RWMutex cgrCfg *config.CGRConfig // reference for future config reloads connMgr *engine.ConnManager filterS *engine.FilterS - rsAuth *radigo.Server - rsAcct *radigo.Server + rsAuth map[string]*radigo.Server + rsAcct map[string]*radigo.Server + sync.WaitGroup } // handleAuth handles RADIUS Authorization request @@ -343,18 +357,37 @@ func (ra *RadiusAgent) processRequest(req *radigo.Packet, reqProcessor *config.R func (ra *RadiusAgent) ListenAndServe(stopChan <-chan struct{}) (err error) { errListen := make(chan error, 2) - go func() { - utils.Logger.Info(fmt.Sprintf("<%s> Start listening for auth requests on <%s>", utils.RadiusAgent, ra.cgrCfg.RadiusAgentCfg().ListenAuth)) - if err := ra.rsAuth.ListenAndServe(stopChan); err != nil { - errListen <- err - } - }() - go func() { - utils.Logger.Info(fmt.Sprintf("<%s> Start listening for acct req on <%s>", utils.RadiusAgent, ra.cgrCfg.RadiusAgentCfg().ListenAcct)) - if err := ra.rsAcct.ListenAndServe(stopChan); err != nil { - errListen <- err - } - }() + for uri, server := range ra.rsAuth { + ra.Add(1) + go func(srv *radigo.Server, uri string) { + defer ra.Done() + utils.Logger.Info(fmt.Sprintf("<%s> Start listening for auth requests on <%s>", utils.RadiusAgent, uri)) + if err := srv.ListenAndServe(stopChan); err != nil { + utils.Logger.Warning(fmt.Sprintf("<%s> error <%v>, on ListenAndServe <%s>", + utils.RadiusAgent, err, uri)) + if strings.Contains(err.Error(), "address already in use") { + return + } + errListen <- err + } + }(server, uri) + } + for uri, server := range ra.rsAcct { + ra.Add(1) + go func(srv *radigo.Server, uri string) { + defer ra.Done() + utils.Logger.Info(fmt.Sprintf("<%s> Start listening for acct requests on <%s>", utils.RadiusAgent, uri)) + if err := srv.ListenAndServe(stopChan); err != nil { + utils.Logger.Warning(fmt.Sprintf("<%s> error <%v>, on ListenAndServe <%s>", + utils.RadiusAgent, err, uri)) + if strings.Contains(err.Error(), "address already in use") { + return + } + errListen <- err + } + }(server, uri) + } + err = <-errListen return } diff --git a/agents/radagent_it_test.go b/agents/radagent_it_test.go index 4b0429ae5..722043642 100644 --- a/agents/radagent_it_test.go +++ b/agents/radagent_it_test.go @@ -53,16 +53,27 @@ var ( testRAitApierRpcConn, testRAitTPFromFolder, testRAitAuthPAPSuccess, + testRAitAuthPAPSuccessTCP, testRAitAuthPAPFail, + testRAitAuthPAPFailTCP, testRAitMandatoryFail, + testRAitMandatoryFailTCP, testRAitWithVendor, + testRAitWithVendorTCP, testRAitAuthCHAPSuccess, + testRAitAuthCHAPSuccessTCP, testRAitAuthCHAPFail, + testRAitAuthCHAPFailTCP, testRAitAuthMSCHAPV2Success, + testRAitAuthMSCHAPV2SuccessTCP, testRAitAuthMSCHAPV2Fail, + testRAitAuthMSCHAPV2FailTCP, testRAitChallenge, + testRAitChallengeTCP, testRAitChallengeResponse, + testRAitChallengeResponseTCP, testRAitAcctStart, + testRAitAcctStartTCP, testRAitAcctStop, testRAitStopCgrEngine, } @@ -245,6 +256,50 @@ func testRAitAuthPAPSuccess(t *testing.T) { t.Errorf("Received: %s", string(reply.AVPs[0].RawValue)) } } +func testRAitAuthPAPSuccessTCP(t *testing.T) { + if raAuthClnt, err = radigo.NewClient("tcp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { + t.Fatal(err) + } + authReq := raAuthClnt.NewRequest(radigo.AccessRequest, 1) // emulates Kamailio packet out of radius_load_caller_avps() + if err := authReq.AddAVPWithName("User-Name", "1001", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("User-Password", "CGRateSPassword1", ""); err != nil { + t.Error(err) + } + // encode the password as required so we can decode it properly + authReq.AVPs[1].RawValue = radigo.EncodeUserPassword([]byte("CGRateSPassword1"), []byte("CGRateS.org"), authReq.Authenticator[:]) + if err := authReq.AddAVPWithName("Service-Type", "SIP-Caller-AVPs", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Called-Station-Id", "1002", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Acct-Session-Id", "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Sip-From-Tag", "51585361", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("NAS-IP-Address", "127.0.0.1", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Event-Timestamp", "1497106115", ""); err != nil { + t.Error(err) + } + reply, err := raAuthClnt.SendRequest(authReq) + if err != nil { + t.Fatal(err) + } + if reply.Code != radigo.AccessAccept { + t.Errorf("Received reply: %+v", utils.ToJSON(reply)) + } + if len(reply.AVPs) != 1 { // make sure max duration is received + t.Errorf("Received AVPs: %+v", utils.ToJSON(reply.AVPs)) + } else if !bytes.Equal([]byte("session_max_time#10800"), reply.AVPs[0].RawValue) { + t.Errorf("Received: %s", string(reply.AVPs[0].RawValue)) + } +} func testRAitAuthPAPFail(t *testing.T) { if raAuthClnt, err = radigo.NewClient("udp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { @@ -291,6 +346,51 @@ func testRAitAuthPAPFail(t *testing.T) { } } +func testRAitAuthPAPFailTCP(t *testing.T) { + if raAuthClnt, err = radigo.NewClient("tcp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { + t.Fatal(err) + } + authReq := raAuthClnt.NewRequest(radigo.AccessRequest, 1) // emulates Kamailio packet out of radius_load_caller_avps() + if err := authReq.AddAVPWithName("User-Name", "1001", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("User-Password", "CGRateSPassword2", ""); err != nil { + t.Error(err) + } + // encode the password as required so we can decode it properly + authReq.AVPs[1].RawValue = radigo.EncodeUserPassword([]byte("CGRateSPassword2"), []byte("CGRateS.org"), authReq.Authenticator[:]) + if err := authReq.AddAVPWithName("Service-Type", "SIP-Caller-AVPs", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Called-Station-Id", "1002", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Acct-Session-Id", "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Sip-From-Tag", "51585361", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("NAS-IP-Address", "127.0.0.1", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Event-Timestamp", "1497106115", ""); err != nil { + t.Error(err) + } + reply, err := raAuthClnt.SendRequest(authReq) + if err != nil { + t.Fatal(err) + } + if reply.Code != radigo.AccessReject { + t.Errorf("Received reply: %+v", reply) + } + if len(reply.AVPs) != 1 { // make sure max duration is received + t.Errorf("Received AVPs: %+v", reply.AVPs) + } else if utils.RadauthFailed != string(reply.AVPs[0].RawValue) { + t.Errorf("Received: %s", string(reply.AVPs[0].RawValue)) + } +} + func testRAitMandatoryFail(t *testing.T) { if raAuthClnt, err = radigo.NewClient("udp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { t.Fatal(err) @@ -318,6 +418,33 @@ func testRAitMandatoryFail(t *testing.T) { } } +func testRAitMandatoryFailTCP(t *testing.T) { + if raAuthClnt, err = radigo.NewClient("tcp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { + t.Fatal(err) + } + authReq := raAuthClnt.NewRequest(radigo.AccessRequest, 1) + if err := authReq.AddAVPWithName("User-Name", "10011", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("User-Password", "CGRateSPassword3", ""); err != nil { + t.Error(err) + } + authReq.AVPs[1].RawValue = radigo.EncodeUserPassword([]byte("CGRateSPassword3"), []byte("CGRateS.org"), authReq.Authenticator[:]) + reply, err := raAuthClnt.SendRequest(authReq) + if err != nil { + t.Fatal(err) + } + if reply.Code != radigo.AccessReject { + t.Errorf("Received reply: %+v", reply) + } + exp := "ATTRIBUTES_ERROR:" + utils.MandatoryIEMissingCaps + ": [RadReplyMessage]" + if len(reply.AVPs) != 1 { + t.Errorf("Received AVPs: %+v", reply.AVPs) + } else if exp != string(reply.AVPs[0].RawValue) { + t.Errorf("Expected <%+v>, Received: <%+v>", exp, string(reply.AVPs[0].RawValue)) + } +} + func testRAitWithVendor(t *testing.T) { if raAuthClnt, err = radigo.NewClient("udp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { t.Fatal(err) @@ -349,6 +476,37 @@ func testRAitWithVendor(t *testing.T) { } } +func testRAitWithVendorTCP(t *testing.T) { + if raAuthClnt, err = radigo.NewClient("tcp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { + t.Fatal(err) + } + authReq := raAuthClnt.NewRequest(radigo.AccessRequest, 1) + if err := authReq.AddAVPWithName("User-Name", "10012", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("User-Password", "CGRateSPassword3", ""); err != nil { + t.Error(err) + } + authReq.AVPs[1].RawValue = radigo.EncodeUserPassword([]byte("CGRateSPassword3"), []byte("CGRateS.org"), authReq.Authenticator[:]) + reply, err := raAuthClnt.SendRequest(authReq) + if err != nil { + t.Fatal(err) + } + + if reply.Code != radigo.AccessAccept { + t.Errorf("Received reply: %+v", reply) + } + if len(reply.AVPs) != 3 { + t.Errorf("Received AVPs: %+v", reply.AVPs) + } else if string(reply.AVPs[0].RawValue) != "\x00\x00\x00\x00*\bClass1" { + t.Errorf("Expected <%+q>, Received: <%+q>", "\x00\x00\x00\x00*\bClass1", string(reply.AVPs[0].RawValue)) + } else if string(reply.AVPs[1].RawValue) != "\x00\x00\x00\x00*\bClass2" { + t.Errorf("Expected <%q>, Received: <%q>", "\x00\x00\x00\x00*\bClass2", string(reply.AVPs[1].RawValue)) + } else if string(reply.AVPs[2].RawValue) != "\x00\x00\x00\x00*\bClass3" { + t.Errorf("Expected <%q>, Received: <%q>", "\x00\x00\x00\x00*\bClass3", string(reply.AVPs[2].RawValue)) + } +} + func testRAitAuthCHAPSuccess(t *testing.T) { if raAuthClnt, err = radigo.NewClient("udp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { t.Fatal(err) @@ -393,6 +551,50 @@ func testRAitAuthCHAPSuccess(t *testing.T) { } } +func testRAitAuthCHAPSuccessTCP(t *testing.T) { + if raAuthClnt, err = radigo.NewClient("tcp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { + t.Fatal(err) + } + authReq := raAuthClnt.NewRequest(radigo.AccessRequest, 1) // emulates Kamailio packet out of radius_load_caller_avps() + if err := authReq.AddAVPWithName("User-Name", "1001", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("CHAP-Password", "CGRateSPassword1", ""); err != nil { + t.Error(err) + } + authReq.AVPs[1].RawValue = radigo.EncodeCHAPPassword([]byte("CGRateSPassword1"), authReq.Authenticator[:]) + if err := authReq.AddAVPWithName("Service-Type", "SIP-Caller-AVPs", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Called-Station-Id", "1002", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Acct-Session-Id", "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Sip-From-Tag", "51585362", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("NAS-IP-Address", "127.0.0.1", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Event-Timestamp", "1497106115", ""); err != nil { + t.Error(err) + } + reply, err := raAuthClnt.SendRequest(authReq) + if err != nil { + t.Fatal(err) + } + if reply.Code != radigo.AccessAccept { + t.Errorf("Received reply: %+v", utils.ToJSON(reply)) + } + if len(reply.AVPs) != 1 { // make sure max duration is received + t.Errorf("Received AVPs: %+v", utils.ToJSON(reply.AVPs)) + } else if !bytes.Equal([]byte("session_max_time#10800"), reply.AVPs[0].RawValue) { + t.Errorf("Received: %s", string(reply.AVPs[0].RawValue)) + } +} + func testRAitAuthCHAPFail(t *testing.T) { if raAuthClnt, err = radigo.NewClient("udp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { t.Fatal(err) @@ -437,6 +639,50 @@ func testRAitAuthCHAPFail(t *testing.T) { } } +func testRAitAuthCHAPFailTCP(t *testing.T) { + if raAuthClnt, err = radigo.NewClient("tcp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { + t.Fatal(err) + } + authReq := raAuthClnt.NewRequest(radigo.AccessRequest, 1) // emulates Kamailio packet out of radius_load_caller_avps() + if err := authReq.AddAVPWithName("User-Name", "1001", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("CHAP-Password", "CGRateSPassword2", ""); err != nil { + t.Error(err) + } + authReq.AVPs[1].RawValue = radigo.EncodeCHAPPassword([]byte("CGRateSPassword2"), authReq.Authenticator[:]) + if err := authReq.AddAVPWithName("Service-Type", "SIP-Caller-AVPs", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Called-Station-Id", "1002", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Acct-Session-Id", "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Sip-From-Tag", "51585362", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("NAS-IP-Address", "127.0.0.1", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Event-Timestamp", "1497106115", ""); err != nil { + t.Error(err) + } + reply, err := raAuthClnt.SendRequest(authReq) + if err != nil { + t.Fatal(err) + } + if reply.Code != radigo.AccessReject { + t.Errorf("Received reply: %+v", reply) + } + if len(reply.AVPs) != 1 { // make sure max duration is received + t.Errorf("Received AVPs: %+v", reply.AVPs) + } else if utils.RadauthFailed != string(reply.AVPs[0].RawValue) { + t.Errorf("Received: %s", string(reply.AVPs[0].RawValue)) + } +} + func testRAitAuthMSCHAPV2Success(t *testing.T) { for _, dictPath := range raCfg.RadiusAgentCfg().ClientDictionaries { if dictRad, err = radigo.NewDictionaryFromFoldersWithRFC2865(dictPath); err != nil { @@ -501,6 +747,70 @@ func testRAitAuthMSCHAPV2Success(t *testing.T) { } +func testRAitAuthMSCHAPV2SuccessTCP(t *testing.T) { + for _, dictPath := range raCfg.RadiusAgentCfg().ClientDictionaries { + if dictRad, err = radigo.NewDictionaryFromFoldersWithRFC2865(dictPath); err != nil { + return + } + } + if raAuthClnt, err = radigo.NewClient("tcp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { + t.Fatal(err) + } + authReq := raAuthClnt.NewRequest(radigo.AccessRequest, 1) // emulates Kamailio packet out of radius_load_caller_avps() + if err := authReq.AddAVPWithName("User-Name", "1001", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("MS-CHAP-Challenge", string(authReq.Authenticator[:]), "Microsoft"); err != nil { + t.Error(err) + } + + respVal, err := radigo.GenerateClientMSCHAPResponse(authReq.Authenticator, "1001", "CGRateSPassword1") + if err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("MS-CHAP-Response", string(respVal), "Microsoft"); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Service-Type", "SIP-Caller-AVPs", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Called-Station-Id", "1002", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Acct-Session-Id", "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Sip-From-Tag", "51585363", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("NAS-IP-Address", "127.0.0.1", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Event-Timestamp", "1497106115", ""); err != nil { + t.Error(err) + } + reply, err := raAuthClnt.SendRequest(authReq) + if err != nil { + t.Fatal(err) + } + if reply.Code != radigo.AccessAccept { + t.Errorf("Received reply: %+v", utils.ToJSON(reply)) + } + if len(reply.AVPs) != 2 { // make sure max duration is received + t.Errorf("Received AVPs: %+v", utils.ToJSON(reply.AVPs)) + } else { + for _, avp := range reply.AVPs { + if avp.Number == 26 && len(avp.RawValue) != 49 { + t.Errorf("Unexpected lenght of MS-CHAP2-Success AVP: %+v", len(avp.RawValue)) + } + if avp.Number == 225 && !bytes.Equal([]byte("session_max_time#10800"), reply.AVPs[1].RawValue) { + t.Errorf("Received: %s", string(reply.AVPs[0].RawValue)) + } + } + } + +} + func testRAitAuthMSCHAPV2Fail(t *testing.T) { for _, dictPath := range raCfg.RadiusAgentCfg().ClientDictionaries { if dictRad, err = radigo.NewDictionaryFromFoldersWithRFC2865(dictPath); err != nil { @@ -556,6 +866,61 @@ func testRAitAuthMSCHAPV2Fail(t *testing.T) { } } +func testRAitAuthMSCHAPV2FailTCP(t *testing.T) { + for _, dictPath := range raCfg.RadiusAgentCfg().ClientDictionaries { + if dictRad, err = radigo.NewDictionaryFromFoldersWithRFC2865(dictPath); err != nil { + return + } + } + if raAuthClnt, err = radigo.NewClient("tcp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { + t.Fatal(err) + } + authReq := raAuthClnt.NewRequest(radigo.AccessRequest, 1) // emulates Kamailio packet out of radius_load_caller_avps() + if err := authReq.AddAVPWithName("User-Name", "1001", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("MS-CHAP-Challenge", string(authReq.Authenticator[:]), "Microsoft"); err != nil { + t.Error(err) + } + respVal, err := radigo.GenerateClientMSCHAPResponse(authReq.Authenticator, "1001", "CGRateSPassword2") + if err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("MS-CHAP-Response", string(respVal), "Microsoft"); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Service-Type", "SIP-Caller-AVPs", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Called-Station-Id", "1002", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Acct-Session-Id", "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Sip-From-Tag", "51585363", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("NAS-IP-Address", "127.0.0.1", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Event-Timestamp", "1497106115", ""); err != nil { + t.Error(err) + } + reply, err := raAuthClnt.SendRequest(authReq) + if err != nil { + t.Fatal(err) + } + if reply.Code != radigo.AccessReject { + t.Errorf("Received reply: %+v", reply) + } + if len(reply.AVPs) != 1 { // make sure max duration is received + t.Errorf("Received AVPs: %+v", reply.AVPs) + } else if utils.RadauthFailed != string(reply.AVPs[0].RawValue) { + t.Errorf("Received: %s", string(reply.AVPs[0].RawValue)) + } +} + func testRAitChallenge(t *testing.T) { if raAuthClnt, err = radigo.NewClient("udp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { t.Fatal(err) @@ -596,6 +961,46 @@ func testRAitChallenge(t *testing.T) { } } +func testRAitChallengeTCP(t *testing.T) { + if raAuthClnt, err = radigo.NewClient("tcp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { + t.Fatal(err) + } + authReq := raAuthClnt.NewRequest(radigo.AccessRequest, 1) // emulates Kamailio packet out of radius_load_caller_avps() + if err := authReq.AddAVPWithName("User-Name", "1001", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Service-Type", "SIP-Caller-AVPs", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Called-Station-Id", "1002", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Acct-Session-Id", "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Sip-From-Tag", "12345678", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("NAS-IP-Address", "127.0.0.1", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Event-Timestamp", "1497106115", ""); err != nil { + t.Error(err) + } + reply, err := raAuthClnt.SendRequest(authReq) + if err != nil { + t.Fatal(err) + } + if reply.Code != radigo.AccessChallenge { + t.Errorf("Received reply: %+v", utils.ToJSON(reply)) + } + if len(reply.AVPs) != 1 { // make sure the client receive the message + t.Errorf("Received AVPs: %+v", utils.ToJSON(reply.AVPs)) + } else if !bytes.Equal([]byte("Missing User-Password"), reply.AVPs[0].RawValue) { + t.Errorf("Received: %s", string(reply.AVPs[0].RawValue)) + } +} + func testRAitChallengeResponse(t *testing.T) { if raAuthClnt, err = radigo.NewClient("udp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { t.Fatal(err) @@ -641,6 +1046,51 @@ func testRAitChallengeResponse(t *testing.T) { } } +func testRAitChallengeResponseTCP(t *testing.T) { + if raAuthClnt, err = radigo.NewClient("tcp", "127.0.0.1:1812", "CGRateS.org", dictRad, 1, nil); err != nil { + t.Fatal(err) + } + authReq := raAuthClnt.NewRequest(radigo.AccessRequest, 1) // emulates Kamailio packet out of radius_load_caller_avps() + if err := authReq.AddAVPWithName("User-Name", "1001", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("User-Password", "CGRateSPassword1", ""); err != nil { + t.Error(err) + } + // encode the password as required so we can decode it properly + authReq.AVPs[1].RawValue = radigo.EncodeUserPassword([]byte("CGRateSPassword1"), []byte("CGRateS.org"), authReq.Authenticator[:]) + if err := authReq.AddAVPWithName("Service-Type", "SIP-Caller-AVPs", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Called-Station-Id", "1002", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Acct-Session-Id", "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Sip-From-Tag", "12345678", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("NAS-IP-Address", "127.0.0.1", ""); err != nil { + t.Error(err) + } + if err := authReq.AddAVPWithName("Event-Timestamp", "1497106115", ""); err != nil { + t.Error(err) + } + reply, err := raAuthClnt.SendRequest(authReq) + if err != nil { + t.Fatal(err) + } + if reply.Code != radigo.AccessAccept { + t.Errorf("Received reply: %+v", utils.ToJSON(reply)) + } + if len(reply.AVPs) != 1 { // make sure max duration is received + t.Errorf("Received AVPs: %+v", utils.ToJSON(reply.AVPs)) + } else if !bytes.Equal([]byte("session_max_time#10800"), reply.AVPs[0].RawValue) { + t.Errorf("Received: %s", string(reply.AVPs[0].RawValue)) + } +} + func testRAitAcctStart(t *testing.T) { if raAcctClnt, err = radigo.NewClient("udp", "127.0.0.1:1813", "CGRateS.org", dictRad, 1, nil); err != nil { t.Fatal(err) @@ -720,6 +1170,85 @@ func testRAitAcctStart(t *testing.T) { } } +func testRAitAcctStartTCP(t *testing.T) { + if raAcctClnt, err = radigo.NewClient("tcp", "127.0.0.1:1813", "CGRateS.org", dictRad, 1, nil); err != nil { + t.Fatal(err) + } + req := raAcctClnt.NewRequest(radigo.AccountingRequest, 2) // emulates Kamailio packet for accounting start + if err := req.AddAVPWithName("Acct-Status-Type", "Start", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("Service-Type", "Sip-Session", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("Sip-Response-Code", "200", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("Sip-Method", "Invite", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("Event-Timestamp", "1497106115", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("Sip-From-Tag", "51585361", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("Sip-To-Tag", "75c2f57b", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("Acct-Session-Id", "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("User-Name", "1001", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("Called-Station-Id", "1002", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("Ascend-User-Acct-Time", "1497106115", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("NAS-Port", "5060", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("Acct-Delay-Time", "0", ""); err != nil { + t.Error(err) + } + if err := req.AddAVPWithName("NAS-IP-Address", "127.0.0.1", ""); err != nil { + t.Error(err) + } + reply, err := raAcctClnt.SendRequest(req) + if err != nil { + t.Error(err) + } + if reply.Code != radigo.AccountingResponse { + t.Errorf("Received reply: %+v", reply) + } + if len(reply.AVPs) != 0 { // we don't expect AVPs to be populated + t.Errorf("Received AVPs: %+v", reply.AVPs) + } + // Make sure the sessin is managed by SMG + time.Sleep(10 * time.Millisecond) + expUsage := 10 * time.Second + if isDispatcherActive { // no debit interval set on dispatched session + expUsage = 3 * time.Hour + } + var aSessions []*sessions.ExternalSession + if err := raRPC.Call(context.Background(), utils.SessionSv1GetActiveSessions, + utils.SessionFilter{ + Filters: []string{ + fmt.Sprintf("*string:~*req.%s:%s", utils.RunID, utils.MetaDefault), + fmt.Sprintf("*string:~*req.%s:%s", utils.OriginID, "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-51585361-75c2f57b"), + }, + }, &aSessions); err != nil { + t.Error(err) + } else if len(aSessions) != 1 { + t.Errorf("Unexpected number of sessions received: %+v", aSessions) + } else if aSessions[0].Usage != expUsage { + t.Errorf("Expecting %v, received usage: %v\nAnd Session: %s ", expUsage, aSessions[0].Usage, utils.ToJSON(aSessions)) + } +} + func testRAitAcctStop(t *testing.T) { req := raAcctClnt.NewRequest(radigo.AccountingRequest, 3) // emulates Kamailio packet for accounting start if err := req.AddAVPWithName("Acct-Status-Type", "Stop", ""); err != nil { diff --git a/config/config_defaults.go b/config/config_defaults.go index 21fa63d5a..63386d13f 100644 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -715,9 +715,13 @@ const CGRATES_CFG_JSON = ` "radius_agent": { "enabled": false, // enables the radius agent: - "listen_net": "udp", // network to listen on - "listen_auth": "127.0.0.1:1812", // address where to listen for radius authentication requests - "listen_acct": "127.0.0.1:1813", // address where to listen for radius accounting requests + "listeners":[ + { + "network": "udp", // network to listen on + "auth_address": "127.0.0.1:1812", // address where to listen for radius authentication requests + "acct_address": "127.0.0.1:1813" // address where to listen for radius accounting requests + } + ], "client_secrets": { // hash containing secrets for clients connecting here <*default|$client_ip> "*default": "CGRateS.org" }, @@ -742,7 +746,7 @@ const CGRATES_CFG_JSON = ` "listeners":[ { "address": "127.0.0.1:53", // address where to listen for DNS requests - "network": "udp" // network to listen on + "network": "udp" // network to listen on } ], "sessions_conns": ["*internal"], diff --git a/config/config_it_test.go b/config/config_it_test.go index e1a0f4176..d3076a5f0 100644 --- a/config/config_it_test.go +++ b/config/config_it_test.go @@ -683,7 +683,7 @@ func testCGRConfigReloadDNSAgent(t *testing.T) { } expAttr := &DNSAgentCfg{ Enabled: true, - Listeners: []Listener{ + Listeners: []DnsListener{ { Address: ":2053", Network: "udp", diff --git a/config/config_json_test.go b/config/config_json_test.go index 74b32f2a3..335d9a90b 100644 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -975,10 +975,14 @@ func TestDiameterAgentJsonCfg(t *testing.T) { func TestRadiusAgentJsonCfg(t *testing.T) { eCfg := &RadiusAgentJsonCfg{ - Enabled: utils.BoolPointer(false), - Listen_net: utils.StringPointer("udp"), - Listen_auth: utils.StringPointer("127.0.0.1:1812"), - Listen_acct: utils.StringPointer("127.0.0.1:1813"), + Enabled: utils.BoolPointer(false), + Listeners: &[]*RadiListenerJsnCfg{ + { + Network: utils.StringPointer(utils.UDP), + Auth_Address: utils.StringPointer("127.0.0.1:1812"), + Acct_Address: utils.StringPointer("127.0.0.1:1813"), + }, + }, Client_secrets: utils.MapStringStringPointer(map[string]string{ utils.MetaDefault: "CGRateS.org", }), @@ -996,7 +1000,7 @@ func TestRadiusAgentJsonCfg(t *testing.T) { t.Error(err) } else if !reflect.DeepEqual(eCfg, cfg) { rcv := *cfg.Request_processors - t.Errorf("Received: %+v", rcv) + t.Errorf("Expected <%+v>, \nReceived: \n<%+v>", eCfg.Request_processors, rcv) } } @@ -1016,7 +1020,7 @@ func TestHttpAgentJsonCfg(t *testing.T) { func TestDNSAgentJsonCfg(t *testing.T) { eCfg := &DNSAgentJsonCfg{ Enabled: utils.BoolPointer(false), - Listeners: &[]*ListenerJsnCfg{ + Listeners: &[]*DnsListenerJsnCfg{ { Network: utils.StringPointer("udp"), Address: utils.StringPointer("127.0.0.1:53"), diff --git a/config/config_test.go b/config/config_test.go index b656a7bbd..420806b31 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -914,17 +914,21 @@ func TestCgrCfgJSONDefaultsHTTP(t *testing.T) { func TestRadiusAgentCfg(t *testing.T) { testRA := &RadiusAgentCfg{ - Enabled: false, - ListenNet: "udp", - ListenAuth: "127.0.0.1:1812", - ListenAcct: "127.0.0.1:1813", + Enabled: false, + Listeners: []RadiusListener{ + { + Network: utils.UDP, + AuthAddr: "127.0.0.1:1812", + AcctAddr: "127.0.0.1:1813", + }, + }, ClientSecrets: map[string]string{utils.MetaDefault: "CGRateS.org"}, ClientDictionaries: map[string][]string{utils.MetaDefault: {"/usr/share/cgrates/radius/dict/"}}, SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)}, RequestProcessors: nil, } if !reflect.DeepEqual(cgrCfg.radiusAgentCfg, testRA) { - t.Errorf("expecting: %+v, received: %+v", cgrCfg.radiusAgentCfg, testRA) + t.Errorf("expecting: %+v, received: %+v", testRA, cgrCfg.radiusAgentCfg) } } @@ -1340,10 +1344,14 @@ func TestLoadDiameterAgentCfgError(t *testing.T) { func TestLoadRadiusAgentCfgError(t *testing.T) { cfgJSONStr := `{ "radius_agent": { - "listen_auth": 1, + "listeners":[ + { + "auth_address": 1 + } + ], }, }` - expected := "json: cannot unmarshal number into Go struct field RadiusAgentJsonCfg.Listen_auth of type string" + expected := "json: cannot unmarshal number into Go struct field RadiListenerJsnCfg.Listeners.Auth_Address of type string" cgrConfig := NewDefaultCGRConfig() if err != nil { t.Error(err) @@ -1365,7 +1373,7 @@ func TestLoadDNSAgentCfgError(t *testing.T) { ], }, }` - expected := "json: cannot unmarshal number into Go struct field ListenerJsnCfg.Listeners.Address of type string" + expected := "json: cannot unmarshal number into Go struct field DnsListenerJsnCfg.Listeners.Address of type string" cgrConfig := NewDefaultCGRConfig() if err != nil { t.Error(err) @@ -1915,10 +1923,14 @@ func TestDiameterAgentConfig(t *testing.T) { func TestRadiusAgentConfig(t *testing.T) { expected := &RadiusAgentCfg{ - Enabled: false, - ListenNet: "udp", - ListenAuth: "127.0.0.1:1812", - ListenAcct: "127.0.0.1:1813", + Enabled: false, + Listeners: []RadiusListener{ + { + Network: utils.UDP, + AuthAddr: "127.0.0.1:1812", + AcctAddr: "127.0.0.1:1813", + }, + }, ClientSecrets: map[string]string{utils.MetaDefault: "CGRateS.org"}, ClientDictionaries: map[string][]string{utils.MetaDefault: {"/usr/share/cgrates/radius/dict/"}}, SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)}, @@ -1937,7 +1949,7 @@ func TestRadiusAgentConfig(t *testing.T) { func TestDNSAgentConfig(t *testing.T) { expected := &DNSAgentCfg{ Enabled: false, - Listeners: []Listener{ + Listeners: []DnsListener{ { Address: "127.0.0.1:53", Network: "udp", @@ -2341,21 +2353,19 @@ func TestERSConfig(t *testing.T) { SessionSConns: []string{"*internal:*sessions"}, Readers: []*EventReaderCfg{ { - ID: utils.MetaDefault, - Type: utils.MetaNone, - RunDelay: 0, - ConcurrentReqs: 1024, - SourcePath: "/var/spool/cgrates/ers/in", - ProcessedPath: "/var/spool/cgrates/ers/out", - Tenant: nil, - Timezone: utils.EmptyString, - Filters: []string{}, - Flags: utils.FlagsWithParams{}, - Fields: nil, - CacheDumpFields: make([]*FCTemplate, 0), - PartialCommitFields: make([]*FCTemplate, 0), - Reconnects: -1, - MaxReconnectInterval: 5 * time.Minute, + ID: utils.MetaDefault, + Type: utils.MetaNone, + RunDelay: 0, + ConcurrentReqs: 1024, + SourcePath: "/var/spool/cgrates/ers/in", + ProcessedPath: "/var/spool/cgrates/ers/out", + Tenant: nil, + Timezone: utils.EmptyString, + Filters: []string{}, + Flags: utils.FlagsWithParams{}, + Fields: nil, + CacheDumpFields: make([]*FCTemplate, 0), + PartialCommitFields: make([]*FCTemplate, 0), Opts: &EventReaderOpts{ CSV: &CSVROpts{ FieldSeparator: utils.StringPointer(utils.FieldsSep), @@ -4023,10 +4033,14 @@ func TestV1GetConfigRadiusAgent(t *testing.T) { var reply map[string]any expected := map[string]any{ RA_JSN: map[string]any{ - utils.EnabledCfg: false, - utils.ListenNetCfg: "udp", - utils.ListenAuthCfg: "127.0.0.1:1812", - utils.ListenAcctCfg: "127.0.0.1:1813", + utils.EnabledCfg: false, + utils.ListenersCfg: []map[string]any{ + { + utils.NetworkCfg: utils.UDP, + utils.AuthAddrCfg: "127.0.0.1:1812", + utils.AcctAddrCfg: "127.0.0.1:1813", + }, + }, utils.ClientSecretsCfg: map[string]string{ utils.MetaDefault: "CGRateS.org", }, @@ -4960,7 +4974,7 @@ func TestV1GetConfigAsJSONADiameterAgent(t *testing.T) { func TestV1GetConfigAsJSONARadiusAgent(t *testing.T) { var reply string - expected := `{"radius_agent":{"client_dictionaries":{"*default":["/usr/share/cgrates/radius/dict/"]},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listen_acct":"127.0.0.1:1813","listen_auth":"127.0.0.1:1812","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"]}}` + expected := `{"radius_agent":{"client_dictionaries":{"*default":["/usr/share/cgrates/radius/dict/"]},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listeners":[{"acct_address":"127.0.0.1:1813","auth_address":"127.0.0.1:1812","network":"udp"}],"request_processors":[],"sessions_conns":["*internal"]}}` cfgCgr := NewDefaultCGRConfig() if err := cfgCgr.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Section: RA_JSN}, &reply); err != nil { t.Error(err) @@ -5318,7 +5332,7 @@ func TestV1GetConfigAsJSONAllConfig(t *testing.T) { }` var reply string cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSON) - expected := `{"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","enabled":false,"index_type":"*scorch","ttl":"24h0m0s"},"apiban":{"keys":[]},"apiers":{"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false,"scheduler_conns":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"max_reconnect_interval":"0s","password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*birpc_internal"]},"attributes":{"any_context":true,"apiers_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*processRuns":1,"*profileIDs":[],"*profileIgnoreFilters":false,"*profileRuns":0},"prefix_indexed_fields":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*diameter_messages":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_loads":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_routes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatchers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*event_charges":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*sentrypeer":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":true,"ttl":"24h0m0s"},"*shared_groups":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"remote_conns":[],"replication_conns":[]},"cdrs":{"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":[],"rals_conns":[],"scheduler_conns":[],"session_cost_retries":5,"stats_conns":[],"store_cdrs":true,"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false},"diameter_agent":{"asr_template":"","concurrent_requests":-1,"dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*birpc_internal"],"synced_conn_requests":false,"vendor_id":0},"dispatchers":{"any_subsystem":true,"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"prevent_loop":false,"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listeners":[{"address":"127.0.0.1:53","network":"udp"}],"request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"ers":{"enabled":false,"partial_cache_ttl":"1s","readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"id":"*default","max_reconnect_interval":"5m0s","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime"},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","reconnects":-1,"run_delay":"0","source_path":"/var/spool/cgrates/ers/in","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"]},"filters":{"apiers_conns":[],"resources_conns":[],"stats_conns":[]},"freeswitch_agent":{"create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","max_reconnect_interval":"0s","password":"ClueCon","reconnects":5}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_parallel_conns":100,"max_reconnect_interval":"0","node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0s","forceAttemptHttp2":true,"idleConnTimeout":"1m30s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0s","skipTlsVerify":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","max_reconnect_interval":"0s","reconnects":5}],"sessions_conns":["*birpc_internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","scheduler_conns":["*localhost"],"tpid":""},"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","flags":null,"type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"ConnectAttempts","tag":"ConnectAttempts","type":"*variable","value":"~*req.4"},{"path":"Reconnects","tag":"Reconnects","type":"*variable","value":"~*req.5"},{"path":"MaxReconnectInterval","tag":"MaxReconnectInterval","type":"*variable","value":"~*req.6"},{"path":"ConnectTimeout","tag":"ConnectTimeout","type":"*variable","value":"~*req.7"},{"path":"ReplyTimeout","tag":"ReplyTimeout","type":"*variable","value":"~*req.8"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.9"},{"path":"ClientKey","tag":"ClientKey","type":"*variable","value":"~*req.10"},{"path":"ClientCertificate","tag":"ClientCertificate","type":"*variable","value":"~*req.11"},{"path":"CaCertificate","tag":"CaCertificate","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherHosts.csv","flags":null,"type":"*dispatcher_hosts"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lockfile_path":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"mailer":{"auth_password":"CGRateS.org","auth_user":"cgrates","from_address":"cgr-mailer@localhost.localdomain","server":"localhost"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"mongoQueryTimeout":"0s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"*redis","out_datadb_user":"cgrates","out_stordb_host":"127.0.0.1","out_stordb_name":"cgrates","out_stordb_opts":{"mongoQueryTimeout":"0s","mysqlDSNParams":null,"mysqlLocation":"","pgSSLMode":"","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":0,"sqlMaxOpenConns":0},"out_stordb_password":"","out_stordb_port":"3306","out_stordb_type":"*mysql","out_stordb_user":"cgrates","users_filters":null},"radius_agent":{"client_dictionaries":{"*default":["/usr/share/cgrates/radius/dict/"]},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listen_acct":"127.0.0.1:1813","listen_auth":"127.0.0.1:1812","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"enabled":false,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"stats_conns":[],"thresholds_conns":[]},"registrarc":{"dispatchers":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]},"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*units":1,"*usageID":""},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"attributes_conns":[],"default_ratio":1,"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*context":"*routes","*ignoreErrors":false,"*maxCost":""},"prefix_indexed_fields":[],"rals_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*bijson_localhost":{"conns":[{"address":"127.0.0.1:2014","transport":"*birpc_json"}],"poolSize":0,"strategy":"*first"},"*birpc_internal":{"conns":[{"address":"*birpc_internal","transport":""}],"poolSize":0,"strategy":"*first"},"*internal":{"conns":[{"address":"*internal","transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"address":"127.0.0.1:2012","transport":"*json"}],"poolSize":0,"strategy":"*first"}},"schedulers":{"cdrs_conns":[],"dynaprepaid_actionplans":[],"enabled":false,"filters":[],"stats_conns":[],"thresholds_conns":[]},"sentrypeer":{"Audience":"https://sentrypeer.com/api","ClientID":"","ClientSecret":"","GrantType":"client_credentials","IpUrl":"https://sentrypeer.com/api/ip-addresses","NumberUrl":"https://sentrypeer.com/api/phone-numbers","TokenURL":"https://authz.sentrypeer.com/oauth/token"},"sessions":{"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":1,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stale_chan_max_extra_usage":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":1000000000,"sessions_conns":["*internal"],"timezone":""},"stats":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"CGRateS.org","db_port":3306,"db_type":"*mysql","db_user":"cgrates","items":{"*cdrs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*session_costs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_account_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_attributes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_chargers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destination_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_routes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_stats":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoQueryTimeout":"10s","mysqlDSNParams":{},"mysqlLocation":"Local","pgSSLMode":"disable","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":10,"sqlMaxOpenConns":100},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*req.CGRID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*cdrLog":[{"mandatory":true,"path":"*cdr.ToR","tag":"ToR","type":"*variable","value":"~*req.BalanceType"},{"mandatory":true,"path":"*cdr.OriginHost","tag":"OriginHost","type":"*constant","value":"127.0.0.1"},{"mandatory":true,"path":"*cdr.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"mandatory":true,"path":"*cdr.Tenant","tag":"Tenant","type":"*variable","value":"~*req.Tenant"},{"mandatory":true,"path":"*cdr.Account","tag":"Account","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Subject","tag":"Subject","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Cost","tag":"Cost","type":"*variable","value":"~*req.Cost"},{"mandatory":true,"path":"*cdr.Source","tag":"Source","type":"*constant","value":"*cdrLog"},{"mandatory":true,"path":"*cdr.Usage","tag":"Usage","type":"*constant","value":"1"},{"mandatory":true,"path":"*cdr.RunID","tag":"RunID","type":"*variable","value":"~*req.ActionType"},{"mandatory":true,"path":"*cdr.SetupTime","tag":"SetupTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.AnswerTime","tag":"AnswerTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.PreRated","tag":"PreRated","type":"*constant","value":"true"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4}}` + expected := `{"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","enabled":false,"index_type":"*scorch","ttl":"24h0m0s"},"apiban":{"keys":[]},"apiers":{"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false,"scheduler_conns":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"max_reconnect_interval":"0s","password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*birpc_internal"]},"attributes":{"any_context":true,"apiers_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*processRuns":1,"*profileIDs":[],"*profileIgnoreFilters":false,"*profileRuns":0},"prefix_indexed_fields":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*diameter_messages":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_loads":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_routes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatchers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*event_charges":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*sentrypeer":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":true,"ttl":"24h0m0s"},"*shared_groups":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"remote_conns":[],"replication_conns":[]},"cdrs":{"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":[],"rals_conns":[],"scheduler_conns":[],"session_cost_retries":5,"stats_conns":[],"store_cdrs":true,"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false},"diameter_agent":{"asr_template":"","concurrent_requests":-1,"dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*birpc_internal"],"synced_conn_requests":false,"vendor_id":0},"dispatchers":{"any_subsystem":true,"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"prevent_loop":false,"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listeners":[{"address":"127.0.0.1:53","network":"udp"}],"request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"ers":{"enabled":false,"partial_cache_ttl":"1s","readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"id":"*default","max_reconnect_interval":"5m0s","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime"},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","reconnects":-1,"run_delay":"0","source_path":"/var/spool/cgrates/ers/in","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"]},"filters":{"apiers_conns":[],"resources_conns":[],"stats_conns":[]},"freeswitch_agent":{"create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","max_reconnect_interval":"0s","password":"ClueCon","reconnects":5}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_parallel_conns":100,"max_reconnect_interval":"0","node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0s","forceAttemptHttp2":true,"idleConnTimeout":"1m30s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0s","skipTlsVerify":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","max_reconnect_interval":"0s","reconnects":5}],"sessions_conns":["*birpc_internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","scheduler_conns":["*localhost"],"tpid":""},"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","flags":null,"type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"ConnectAttempts","tag":"ConnectAttempts","type":"*variable","value":"~*req.4"},{"path":"Reconnects","tag":"Reconnects","type":"*variable","value":"~*req.5"},{"path":"MaxReconnectInterval","tag":"MaxReconnectInterval","type":"*variable","value":"~*req.6"},{"path":"ConnectTimeout","tag":"ConnectTimeout","type":"*variable","value":"~*req.7"},{"path":"ReplyTimeout","tag":"ReplyTimeout","type":"*variable","value":"~*req.8"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.9"},{"path":"ClientKey","tag":"ClientKey","type":"*variable","value":"~*req.10"},{"path":"ClientCertificate","tag":"ClientCertificate","type":"*variable","value":"~*req.11"},{"path":"CaCertificate","tag":"CaCertificate","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherHosts.csv","flags":null,"type":"*dispatcher_hosts"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lockfile_path":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"mailer":{"auth_password":"CGRateS.org","auth_user":"cgrates","from_address":"cgr-mailer@localhost.localdomain","server":"localhost"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"mongoQueryTimeout":"0s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"*redis","out_datadb_user":"cgrates","out_stordb_host":"127.0.0.1","out_stordb_name":"cgrates","out_stordb_opts":{"mongoQueryTimeout":"0s","mysqlDSNParams":null,"mysqlLocation":"","pgSSLMode":"","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":0,"sqlMaxOpenConns":0},"out_stordb_password":"","out_stordb_port":"3306","out_stordb_type":"*mysql","out_stordb_user":"cgrates","users_filters":null},"radius_agent":{"client_dictionaries":{"*default":["/usr/share/cgrates/radius/dict/"]},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listeners":[{"acct_address":"127.0.0.1:1813","auth_address":"127.0.0.1:1812","network":"udp"}],"request_processors":[],"sessions_conns":["*internal"]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"enabled":false,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"stats_conns":[],"thresholds_conns":[]},"registrarc":{"dispatchers":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]},"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*units":1,"*usageID":""},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"attributes_conns":[],"default_ratio":1,"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*context":"*routes","*ignoreErrors":false,"*maxCost":""},"prefix_indexed_fields":[],"rals_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*bijson_localhost":{"conns":[{"address":"127.0.0.1:2014","transport":"*birpc_json"}],"poolSize":0,"strategy":"*first"},"*birpc_internal":{"conns":[{"address":"*birpc_internal","transport":""}],"poolSize":0,"strategy":"*first"},"*internal":{"conns":[{"address":"*internal","transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"address":"127.0.0.1:2012","transport":"*json"}],"poolSize":0,"strategy":"*first"}},"schedulers":{"cdrs_conns":[],"dynaprepaid_actionplans":[],"enabled":false,"filters":[],"stats_conns":[],"thresholds_conns":[]},"sentrypeer":{"Audience":"https://sentrypeer.com/api","ClientID":"","ClientSecret":"","GrantType":"client_credentials","IpUrl":"https://sentrypeer.com/api/ip-addresses","NumberUrl":"https://sentrypeer.com/api/phone-numbers","TokenURL":"https://authz.sentrypeer.com/oauth/token"},"sessions":{"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":1,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stale_chan_max_extra_usage":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":1000000000,"sessions_conns":["*internal"],"timezone":""},"stats":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"CGRateS.org","db_port":3306,"db_type":"*mysql","db_user":"cgrates","items":{"*cdrs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*session_costs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_account_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_attributes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_chargers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destination_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_routes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_stats":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoQueryTimeout":"10s","mysqlDSNParams":{},"mysqlLocation":"Local","pgSSLMode":"disable","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":10,"sqlMaxOpenConns":100},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*req.CGRID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*cdrLog":[{"mandatory":true,"path":"*cdr.ToR","tag":"ToR","type":"*variable","value":"~*req.BalanceType"},{"mandatory":true,"path":"*cdr.OriginHost","tag":"OriginHost","type":"*constant","value":"127.0.0.1"},{"mandatory":true,"path":"*cdr.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"mandatory":true,"path":"*cdr.Tenant","tag":"Tenant","type":"*variable","value":"~*req.Tenant"},{"mandatory":true,"path":"*cdr.Account","tag":"Account","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Subject","tag":"Subject","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Cost","tag":"Cost","type":"*variable","value":"~*req.Cost"},{"mandatory":true,"path":"*cdr.Source","tag":"Source","type":"*constant","value":"*cdrLog"},{"mandatory":true,"path":"*cdr.Usage","tag":"Usage","type":"*constant","value":"1"},{"mandatory":true,"path":"*cdr.RunID","tag":"RunID","type":"*variable","value":"~*req.ActionType"},{"mandatory":true,"path":"*cdr.SetupTime","tag":"SetupTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.AnswerTime","tag":"AnswerTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.PreRated","tag":"PreRated","type":"*constant","value":"true"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4}}` if err != nil { t.Fatal(err) } @@ -5366,18 +5380,16 @@ func TestCgrCdfEventReader(t *testing.T) { SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)}, Readers: []*EventReaderCfg{ { - ID: utils.MetaDefault, - Type: utils.MetaNone, - RunDelay: 0, - ConcurrentReqs: 1024, - SourcePath: "/var/spool/cgrates/ers/in", - ProcessedPath: "/var/spool/cgrates/ers/out", - Tenant: nil, - Timezone: utils.EmptyString, - Filters: []string{}, - Flags: utils.FlagsWithParams{}, - Reconnects: -1, - MaxReconnectInterval: 5 * time.Minute, + ID: utils.MetaDefault, + Type: utils.MetaNone, + RunDelay: 0, + ConcurrentReqs: 1024, + SourcePath: "/var/spool/cgrates/ers/in", + ProcessedPath: "/var/spool/cgrates/ers/out", + Tenant: nil, + Timezone: utils.EmptyString, + Filters: []string{}, + Flags: utils.FlagsWithParams{}, Fields: []*FCTemplate{ {Tag: utils.ToR, Path: utils.MetaCgreq + utils.NestingSep + utils.ToR, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.2", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339}, @@ -5479,18 +5491,16 @@ func TestCgrCdfEventExporter(t *testing.T) { func TestCgrCfgEventReaderDefault(t *testing.T) { eCfg := &EventReaderCfg{ - ID: utils.MetaDefault, - Type: utils.MetaNone, - RunDelay: 0, - ConcurrentReqs: 1024, - SourcePath: "/var/spool/cgrates/ers/in", - ProcessedPath: "/var/spool/cgrates/ers/out", - Tenant: nil, - Timezone: utils.EmptyString, - Filters: []string{}, - Flags: utils.FlagsWithParams{}, - Reconnects: -1, - MaxReconnectInterval: 5 * time.Minute, + ID: utils.MetaDefault, + Type: utils.MetaNone, + RunDelay: 0, + ConcurrentReqs: 1024, + SourcePath: "/var/spool/cgrates/ers/in", + ProcessedPath: "/var/spool/cgrates/ers/out", + Tenant: nil, + Timezone: utils.EmptyString, + Filters: []string{}, + Flags: utils.FlagsWithParams{}, Fields: []*FCTemplate{ {Tag: utils.ToR, Path: utils.MetaCgreq + utils.NestingSep + utils.ToR, Type: utils.MetaVariable, Value: NewRSRParsersMustCompile("~*req.2", utils.InfieldSep), Mandatory: true, Layout: time.RFC3339}, diff --git a/config/dnsagentcfg_test.go b/config/dnsagentcfg_test.go index fee11bd47..91a1fd261 100644 --- a/config/dnsagentcfg_test.go +++ b/config/dnsagentcfg_test.go @@ -27,7 +27,7 @@ import ( func TestDNSAgentCfgloadFromJsonCfg(t *testing.T) { jsnCfg := &DNSAgentJsonCfg{ Enabled: utils.BoolPointer(true), - Listeners: &[]*ListenerJsnCfg{ + Listeners: &[]*DnsListenerJsnCfg{ { Address: utils.StringPointer("127.0.0.1:2053"), Network: utils.StringPointer("udp"), @@ -51,7 +51,7 @@ func TestDNSAgentCfgloadFromJsonCfg(t *testing.T) { } expected := &DNSAgentCfg{ Enabled: true, - Listeners: []Listener{ + Listeners: []DnsListener{ { Address: "127.0.0.1:2053", Network: "udp", @@ -324,7 +324,7 @@ func TestRequestProcessorClone(t *testing.T) { func TestDNSAgentCfgClone(t *testing.T) { ban := &DNSAgentCfg{ Enabled: true, - Listeners: []Listener{ + Listeners: []DnsListener{ { Address: "127.0.0.1:2053", Network: "udp", diff --git a/config/dnsagntcfg.go b/config/dnsagntcfg.go index c8c88f026..1cf7873a2 100644 --- a/config/dnsagntcfg.go +++ b/config/dnsagntcfg.go @@ -22,7 +22,7 @@ import ( "github.com/cgrates/cgrates/utils" ) -type Listener struct { +type DnsListener struct { Address string Network string // udp or tcp } @@ -30,7 +30,7 @@ type Listener struct { // DNSAgentCfg the config section that describes the DNS Agent type DNSAgentCfg struct { Enabled bool - Listeners []Listener + Listeners []DnsListener SessionSConns []string Timezone string RequestProcessors []*RequestProcessor @@ -45,9 +45,9 @@ func (da *DNSAgentCfg) loadFromJSONCfg(jsnCfg *DNSAgentJsonCfg, sep string) (err } if jsnCfg.Listeners != nil { - da.Listeners = make([]Listener, 0, len(*jsnCfg.Listeners)) + da.Listeners = make([]DnsListener, 0, len(*jsnCfg.Listeners)) for _, listnr := range *jsnCfg.Listeners { - var ls Listener + var ls DnsListener if listnr.Address != nil { ls.Address = *listnr.Address } @@ -93,7 +93,7 @@ func (da *DNSAgentCfg) loadFromJSONCfg(jsnCfg *DNSAgentJsonCfg, sep string) (err } // AsMapInterface returns the config as a map[string]any -func (lstn *Listener) AsMapInterface(separator string) map[string]any { +func (lstn *DnsListener) AsMapInterface(separator string) map[string]any { return map[string]any{ utils.AddressCfg: lstn.Address, utils.NetworkCfg: lstn.Network, @@ -142,7 +142,7 @@ func (da DNSAgentCfg) Clone() (cln *DNSAgentCfg) { } if da.Listeners != nil { - cln.Listeners = make([]Listener, len(da.Listeners)) + cln.Listeners = make([]DnsListener, len(da.Listeners)) copy(cln.Listeners, da.Listeners) } diff --git a/config/libconfig_json.go b/config/libconfig_json.go index 14d26b336..73ede4ba3 100644 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -539,12 +539,16 @@ type DiameterAgentJsonCfg struct { Request_processors *[]*ReqProcessorJsnCfg } +type RadiListenerJsnCfg struct { + Network *string + Auth_Address *string + Acct_Address *string +} + // Radius Agent configuration section type RadiusAgentJsonCfg struct { Enabled *bool - Listen_net *string - Listen_auth *string - Listen_acct *string + Listeners *[]*RadiListenerJsnCfg Client_secrets *map[string]string Client_dictionaries *map[string][]string Sessions_conns *[]string @@ -562,7 +566,7 @@ type HttpAgentJsonCfg struct { Request_processors *[]*ReqProcessorJsnCfg } -type ListenerJsnCfg struct { +type DnsListenerJsnCfg struct { Address *string Network *string } @@ -570,7 +574,7 @@ type ListenerJsnCfg struct { // DNSAgentJsonCfg type DNSAgentJsonCfg struct { Enabled *bool - Listeners *[]*ListenerJsnCfg + Listeners *[]*DnsListenerJsnCfg Sessions_conns *[]string Timezone *string Request_processors *[]*ReqProcessorJsnCfg diff --git a/config/radiuscfg.go b/config/radiuscfg.go index 6e4d26823..4e5224140 100644 --- a/config/radiuscfg.go +++ b/config/radiuscfg.go @@ -22,12 +22,16 @@ import ( "github.com/cgrates/cgrates/utils" ) +type RadiusListener struct { + AuthAddr string + AcctAddr string + Network string // udp or tcp +} + // RadiusAgentCfg the config section that describes the Radius Agent type RadiusAgentCfg struct { Enabled bool - ListenNet string // udp or tcp - ListenAuth string - ListenAcct string + Listeners []RadiusListener ClientSecrets map[string]string ClientDictionaries map[string][]string SessionSConns []string @@ -41,14 +45,21 @@ func (ra *RadiusAgentCfg) loadFromJSONCfg(jsnCfg *RadiusAgentJsonCfg, separator if jsnCfg.Enabled != nil { ra.Enabled = *jsnCfg.Enabled } - if jsnCfg.Listen_net != nil { - ra.ListenNet = *jsnCfg.Listen_net - } - if jsnCfg.Listen_auth != nil { - ra.ListenAuth = *jsnCfg.Listen_auth - } - if jsnCfg.Listen_acct != nil { - ra.ListenAcct = *jsnCfg.Listen_acct + if jsnCfg.Listeners != nil { + ra.Listeners = make([]RadiusListener, 0, len(*jsnCfg.Listeners)) + for _, listnr := range *jsnCfg.Listeners { + var ls RadiusListener + if listnr.Auth_Address != nil { + ls.AuthAddr = *listnr.Auth_Address + } + if listnr.Acct_Address != nil { + ls.AcctAddr = *listnr.Acct_Address + } + if listnr.Network != nil { + ls.Network = *listnr.Network + } + ra.Listeners = append(ra.Listeners, ls) + } } if jsnCfg.Client_secrets != nil { if ra.ClientSecrets == nil { @@ -98,15 +109,28 @@ func (ra *RadiusAgentCfg) loadFromJSONCfg(jsnCfg *RadiusAgentJsonCfg, separator return } +// AsMapInterface returns the config as a map[string]any +func (lstn *RadiusListener) AsMapInterface(separator string) map[string]any { + return map[string]any{ + utils.AuthAddrCfg: lstn.AuthAddr, + utils.AcctAddrCfg: lstn.AcctAddr, + utils.NetworkCfg: lstn.Network, + } + +} + // AsMapInterface returns the config as a map[string]any func (ra *RadiusAgentCfg) AsMapInterface(separator string) (initialMP map[string]any) { initialMP = map[string]any{ - utils.EnabledCfg: ra.Enabled, - utils.ListenNetCfg: ra.ListenNet, - utils.ListenAuthCfg: ra.ListenAuth, - utils.ListenAcctCfg: ra.ListenAcct, + utils.EnabledCfg: ra.Enabled, } + listeners := make([]map[string]any, len(ra.Listeners)) + for i, item := range ra.Listeners { + listeners[i] = item.AsMapInterface(separator) + } + initialMP[utils.ListenersCfg] = listeners + requestProcessors := make([]map[string]any, len(ra.RequestProcessors)) for i, item := range ra.RequestProcessors { requestProcessors[i] = item.AsMapInterface(separator) @@ -140,12 +164,16 @@ func (ra *RadiusAgentCfg) AsMapInterface(separator string) (initialMP map[string func (ra RadiusAgentCfg) Clone() (cln *RadiusAgentCfg) { cln = &RadiusAgentCfg{ Enabled: ra.Enabled, - ListenNet: ra.ListenNet, - ListenAuth: ra.ListenAuth, - ListenAcct: ra.ListenAcct, + Listeners: ra.Listeners, ClientSecrets: make(map[string]string), ClientDictionaries: make(map[string][]string), } + + if ra.Listeners != nil { + cln.Listeners = make([]RadiusListener, len(ra.Listeners)) + copy(cln.Listeners, ra.Listeners) + } + if ra.SessionSConns != nil { cln.SessionSConns = make([]string, len(ra.SessionSConns)) copy(cln.SessionSConns, ra.SessionSConns) diff --git a/config/radiuscfg_test.go b/config/radiuscfg_test.go index 33659c287..1f5f491e4 100644 --- a/config/radiuscfg_test.go +++ b/config/radiuscfg_test.go @@ -28,10 +28,14 @@ import ( func TestRadiusAgentCfgloadFromJsonCfgCase1(t *testing.T) { cfgJSON := &RadiusAgentJsonCfg{ - Enabled: utils.BoolPointer(true), - Listen_net: utils.StringPointer(utils.UDP), - Listen_auth: utils.StringPointer("127.0.0.1:1812"), - Listen_acct: utils.StringPointer("127.0.0.1:1813"), + Enabled: utils.BoolPointer(true), + Listeners: &[]*RadiListenerJsnCfg{ + { + Network: utils.StringPointer(utils.UDP), + Auth_Address: utils.StringPointer("127.0.0.1:1812"), + Acct_Address: utils.StringPointer("127.0.0.1:1813"), + }, + }, Client_secrets: &map[string]string{utils.MetaDefault: "CGRateS.org"}, Client_dictionaries: &map[string][]string{utils.MetaDefault: {"/usr/share/cgrates/radius/dict/"}}, Sessions_conns: &[]string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)}, @@ -57,10 +61,14 @@ func TestRadiusAgentCfgloadFromJsonCfgCase1(t *testing.T) { }, } expected := &RadiusAgentCfg{ - Enabled: true, - ListenNet: "udp", - ListenAuth: "127.0.0.1:1812", - ListenAcct: "127.0.0.1:1813", + Enabled: true, + Listeners: []RadiusListener{ + { + Network: utils.UDP, + AuthAddr: "127.0.0.1:1812", + AcctAddr: "127.0.0.1:1813", + }, + }, ClientSecrets: map[string]string{utils.MetaDefault: "CGRateS.org"}, ClientDictionaries: map[string][]string{utils.MetaDefault: {"/usr/share/cgrates/radius/dict/"}}, SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)}, @@ -148,10 +156,13 @@ func TestRadiusAgentCfgloadFromJsonCfgCase3(t *testing.T) { func TestRadiusAgentCfgAsMapInterface(t *testing.T) { cfgJSONStr := `{ "radius_agent": { - "enabled": true, - "listen_auth": "127.0.0.1:1816", - "listen_acct": "127.0.0.1:1892", - + "enabled": true, + "listeners":[ + { + "auth_address": "127.0.0.1:1816", + "acct_address": "127.0.0.1:1892" + } + ], "client_dictionaries": { "*default": [ "/usr/share/cgrates/", @@ -173,10 +184,14 @@ func TestRadiusAgentCfgAsMapInterface(t *testing.T) { }, }` eMap := map[string]any{ - utils.EnabledCfg: true, - utils.ListenNetCfg: "udp", - utils.ListenAuthCfg: "127.0.0.1:1816", - utils.ListenAcctCfg: "127.0.0.1:1892", + utils.EnabledCfg: true, + utils.ListenersCfg: []map[string]any{ + { + utils.NetworkCfg: utils.EmptyString, + utils.AuthAddrCfg: "127.0.0.1:1816", + utils.AcctAddrCfg: "127.0.0.1:1892", + }, + }, utils.ClientSecretsCfg: map[string]string{ utils.MetaDefault: "CGRateS.org", }, @@ -210,10 +225,14 @@ func TestRadiusAgentCfgAsMapInterface1(t *testing.T) { "radius_agent": {}, }` eMap := map[string]any{ - utils.EnabledCfg: false, - utils.ListenNetCfg: "udp", - utils.ListenAuthCfg: "127.0.0.1:1812", - utils.ListenAcctCfg: "127.0.0.1:1813", + utils.EnabledCfg: false, + utils.ListenersCfg: []map[string]any{ + { + utils.NetworkCfg: utils.UDP, + utils.AuthAddrCfg: "127.0.0.1:1812", + utils.AcctAddrCfg: "127.0.0.1:1813", + }, + }, utils.ClientSecretsCfg: map[string]string{ utils.MetaDefault: "CGRateS.org", }, @@ -232,10 +251,14 @@ func TestRadiusAgentCfgAsMapInterface1(t *testing.T) { func TestRadiusAgentCfgClone(t *testing.T) { ban := &RadiusAgentCfg{ - Enabled: true, - ListenNet: "udp", - ListenAuth: "127.0.0.1:1812", - ListenAcct: "127.0.0.1:1813", + Enabled: true, + Listeners: []RadiusListener{ + { + Network: utils.UDP, + AuthAddr: "127.0.0.1:1812", + AcctAddr: "127.0.0.1:1813", + }, + }, ClientSecrets: map[string]string{utils.MetaDefault: "CGRateS.org"}, ClientDictionaries: map[string][]string{utils.MetaDefault: {"/usr/share/cgrates/radius/dict/"}}, SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"}, diff --git a/data/conf/cgrates/cgrates.json b/data/conf/cgrates/cgrates.json index 5bf643e57..0c380c141 100644 --- a/data/conf/cgrates/cgrates.json +++ b/data/conf/cgrates/cgrates.json @@ -646,9 +646,13 @@ // "radius_agent": { // "enabled": false, // enables the radius agent: -// "listen_net": "udp", // network to listen on -// "listen_auth": "127.0.0.1:1812", // address where to listen for radius authentication requests -// "listen_acct": "127.0.0.1:1813", // address where to listen for radius accounting requests +// "listeners":[ +// { +// "network": "udp", // network to listen on +// "auth_address": "127.0.0.1:1812", // address where to listen for radius authentication requests +// "acct_address": "127.0.0.1:1813" // address where to listen for radius accounting requests +// } +// ], // "client_secrets": { // hash containing secrets for clients connecting here <*default|$client_ip> // "*default": "CGRateS.org" // }, @@ -669,8 +673,12 @@ // "dns_agent": { // "enabled": false, // enables the DNS agent: -// "listen": "127.0.0.1:53", // address where to listen for DNS requests -// "listen_net": "udp", // network to listen on +// "listeners":[ +// { +// "address": "127.0.0.1:53", // address where to listen for DNS requests +// "network": "udp" // network to listen on +// } +// ], // "sessions_conns": ["*internal"], // "timezone": "", // timezone of the events if not specified // "request_processors": [ // request processors to be applied to DNS messages diff --git a/data/conf/samples/dispatchers/radagent/cgrates.json b/data/conf/samples/dispatchers/radagent/cgrates.json index 138ce03c1..4107763d1 100644 --- a/data/conf/samples/dispatchers/radagent/cgrates.json +++ b/data/conf/samples/dispatchers/radagent/cgrates.json @@ -54,6 +54,18 @@ "radius_agent": { "enabled": true, "sessions_conns": ["*localhost"], + "listeners":[ + { + "network": "udp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + { + "network": "tcp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + ], }, "apiers": { diff --git a/data/conf/samples/radagent_internal/accounting.json b/data/conf/samples/radagent_internal/accounting.json index b6dd99a4f..0d4831a54 100644 --- a/data/conf/samples/radagent_internal/accounting.json +++ b/data/conf/samples/radagent_internal/accounting.json @@ -61,4 +61,4 @@ ], }, -}, \ No newline at end of file +}, diff --git a/data/conf/samples/radagent_internal/authchallenge.json b/data/conf/samples/radagent_internal/authchallenge.json index f6d006747..9b89d6614 100644 --- a/data/conf/samples/radagent_internal/authchallenge.json +++ b/data/conf/samples/radagent_internal/authchallenge.json @@ -59,4 +59,4 @@ }, ], } -} \ No newline at end of file +} diff --git a/data/conf/samples/radagent_internal/authchap.json b/data/conf/samples/radagent_internal/authchap.json index 39193305d..dbdf1fda3 100644 --- a/data/conf/samples/radagent_internal/authchap.json +++ b/data/conf/samples/radagent_internal/authchap.json @@ -48,4 +48,4 @@ }, ], } -} \ No newline at end of file +} diff --git a/data/conf/samples/radagent_internal/authmschapv2.json b/data/conf/samples/radagent_internal/authmschapv2.json index 23ee13dc8..cddb47cf8 100644 --- a/data/conf/samples/radagent_internal/authmschapv2.json +++ b/data/conf/samples/radagent_internal/authmschapv2.json @@ -48,4 +48,4 @@ ], } -} \ No newline at end of file +} diff --git a/data/conf/samples/radagent_internal/authpapauth.json b/data/conf/samples/radagent_internal/authpapauth.json index 5910e8614..788cf4ddd 100644 --- a/data/conf/samples/radagent_internal/authpapauth.json +++ b/data/conf/samples/radagent_internal/authpapauth.json @@ -48,4 +48,4 @@ }, ], } -} \ No newline at end of file +} diff --git a/data/conf/samples/radagent_internal/authvendorwblock.json b/data/conf/samples/radagent_internal/authvendorwblock.json index 9eeb3e7a2..c825e7724 100644 --- a/data/conf/samples/radagent_internal/authvendorwblock.json +++ b/data/conf/samples/radagent_internal/authvendorwblock.json @@ -78,4 +78,4 @@ } ] } -} \ No newline at end of file +} diff --git a/data/conf/samples/radagent_internal/cgrates.json b/data/conf/samples/radagent_internal/cgrates.json index 583af9fd8..287e82923 100644 --- a/data/conf/samples/radagent_internal/cgrates.json +++ b/data/conf/samples/radagent_internal/cgrates.json @@ -66,6 +66,18 @@ "radius_agent": { "enabled": true, "sessions_conns": ["*localhost"], + "listeners":[ + { + "network": "udp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + { + "network": "tcp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + ], }, diff --git a/data/conf/samples/radagent_internal_gob/cgrates.json b/data/conf/samples/radagent_internal_gob/cgrates.json index 9c37f224c..c9a81f6a5 100644 --- a/data/conf/samples/radagent_internal_gob/cgrates.json +++ b/data/conf/samples/radagent_internal_gob/cgrates.json @@ -74,6 +74,18 @@ "radius_agent": { "enabled": true, "sessions_conns": ["conn1"], + "listeners":[ + { + "network": "udp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + { + "network": "tcp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + ], }, diff --git a/data/conf/samples/radagent_mongo/cgrates.json b/data/conf/samples/radagent_mongo/cgrates.json index c6b968ff5..8f0e3a898 100644 --- a/data/conf/samples/radagent_mongo/cgrates.json +++ b/data/conf/samples/radagent_mongo/cgrates.json @@ -69,6 +69,18 @@ "radius_agent": { "enabled": true, "sessions_conns": ["*localhost"], + "listeners":[ + { + "network": "udp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + { + "network": "tcp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + ], }, diff --git a/data/conf/samples/radagent_mongo_gob/cgrates.json b/data/conf/samples/radagent_mongo_gob/cgrates.json index 87c878090..80de55aaa 100644 --- a/data/conf/samples/radagent_mongo_gob/cgrates.json +++ b/data/conf/samples/radagent_mongo_gob/cgrates.json @@ -77,6 +77,18 @@ "radius_agent": { "enabled": true, "sessions_conns": ["conn1"], + "listeners":[ + { + "network": "udp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + { + "network": "tcp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + ], }, diff --git a/data/conf/samples/radagent_mysql/cgrates.json b/data/conf/samples/radagent_mysql/cgrates.json index ebc611298..28644de5b 100644 --- a/data/conf/samples/radagent_mysql/cgrates.json +++ b/data/conf/samples/radagent_mysql/cgrates.json @@ -65,6 +65,18 @@ "radius_agent": { "enabled": true, "sessions_conns": ["*localhost"], + "listeners":[ + { + "network": "udp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + { + "network": "tcp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + ], }, diff --git a/data/conf/samples/radagent_mysql_gob/cgrates.json b/data/conf/samples/radagent_mysql_gob/cgrates.json index 2ad3043b5..c2f1cbeae 100644 --- a/data/conf/samples/radagent_mysql_gob/cgrates.json +++ b/data/conf/samples/radagent_mysql_gob/cgrates.json @@ -72,6 +72,18 @@ "radius_agent": { "enabled": true, "sessions_conns": ["conn1"], + "listeners":[ + { + "network": "udp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + { + "network": "tcp", + "auth_address": "127.0.0.1:1812", + "acct_address": "127.0.0.1:1813" + }, + ], }, diff --git a/services/dnsagent_it_test.go b/services/dnsagent_it_test.go index 5b7832b69..2c27be81f 100644 --- a/services/dnsagent_it_test.go +++ b/services/dnsagent_it_test.go @@ -42,7 +42,7 @@ func TestDNSAgentStartReloadShut(t *testing.T) { cfg.SessionSCfg().Enabled = true cfg.SessionSCfg().ListenBijson = "" cfg.DNSAgentCfg().Enabled = true - cfg.DNSAgentCfg().Listeners = []config.Listener{ + cfg.DNSAgentCfg().Listeners = []config.DnsListener{ { Network: "udp", Address: ":2055", diff --git a/services/radiusagent.go b/services/radiusagent.go index 6f0f73550..7e2ecd854 100644 --- a/services/radiusagent.go +++ b/services/radiusagent.go @@ -53,10 +53,6 @@ type RadiusAgent struct { rad *agents.RadiusAgent connMgr *engine.ConnManager srvDep map[string]*sync.WaitGroup - - lnet string - lauth string - lacct string } // Start should handle the sercive start @@ -71,10 +67,6 @@ func (rad *RadiusAgent) Start() (err error) { rad.Lock() defer rad.Unlock() - rad.lnet = rad.cfg.RadiusAgentCfg().ListenNet - rad.lauth = rad.cfg.RadiusAgentCfg().ListenAuth - rad.lacct = rad.cfg.RadiusAgentCfg().ListenAcct - if rad.rad, err = agents.NewRadiusAgent(rad.cfg, filterS, rad.connMgr); err != nil { utils.Logger.Err(fmt.Sprintf("<%s> error: <%s>", utils.RadiusAgent, err.Error())) return @@ -96,27 +88,21 @@ func (rad *RadiusAgent) listenAndServe(r *agents.RadiusAgent) (err error) { // Reload handles the change of config func (rad *RadiusAgent) Reload() (err error) { - if rad.lnet == rad.cfg.RadiusAgentCfg().ListenNet && - rad.lauth == rad.cfg.RadiusAgentCfg().ListenAuth && - rad.lacct == rad.cfg.RadiusAgentCfg().ListenAcct { - return - } - - rad.shutdown() + rad.Shutdown() return rad.Start() } // Shutdown stops the service func (rad *RadiusAgent) Shutdown() (err error) { - rad.shutdown() - return // no shutdown for the momment -} - -func (rad *RadiusAgent) shutdown() { - rad.Lock() + if rad.rad == nil { + return + } close(rad.stopChan) + rad.rad.Wait() + rad.rad.Lock() + defer rad.rad.Unlock() rad.rad = nil - rad.Unlock() + return // no shutdown for the momment } // IsRunning returns if the service is running diff --git a/services/radiusagent_it_test.go b/services/radiusagent_it_test.go index 1e6f2024b..9cb83df6c 100644 --- a/services/radiusagent_it_test.go +++ b/services/radiusagent_it_test.go @@ -37,7 +37,64 @@ import ( "github.com/cgrates/cgrates/utils" ) -func TestRadiusAgentReload(t *testing.T) { +func TestRadiusAgentReloadStartShut(t *testing.T) { + cfg := config.NewDefaultCGRConfig() + cfg.SessionSCfg().Enabled = true + cfg.SessionSCfg().ListenBijson = "" + cfg.RadiusAgentCfg().Enabled = true + cfg.RadiusAgentCfg().Listeners = []config.RadiusListener{ + { + Network: "udp", + AuthAddr: ":1812", + AcctAddr: ":1813", + }, + { + Network: "tcp", + AuthAddr: ":1822", + AcctAddr: ":1823", + }, + } + utils.Logger, _ = utils.Newlogger(utils.MetaSysLog, cfg.GeneralCfg().NodeID) + utils.Logger.SetLogLevel(7) + filterSChan := make(chan *engine.FilterS, 1) + filterSChan <- nil + shdChan := utils.NewSyncedChan() + srvDep := map[string]*sync.WaitGroup{utils.DataDB: new(sync.WaitGroup)} + srv := NewRadiusAgent(cfg, filterSChan, shdChan, nil, srvDep) + shdWg := new(sync.WaitGroup) + srvMngr := servmanager.NewServiceManager(cfg, shdChan, shdWg, nil) + engine.NewConnManager(cfg, nil) + db := NewDataDBService(cfg, nil, srvDep) + server := cores.NewServer(nil) + anz := NewAnalyzerService(cfg, server, filterSChan, shdChan, make(chan birpc.ClientConnector, 1), srvDep) + sS := NewSessionService(cfg, db, server, make(chan birpc.ClientConnector, 1), + shdChan, nil, anz, srvDep) + srvMngr.AddServices(srv, sS, + NewLoaderService(cfg, db, filterSChan, server, make(chan birpc.ClientConnector, 1), nil, anz, srvDep), db) + runtime.Gosched() + time.Sleep(10 * time.Millisecond) //need to switch to gorutine + if err := srv.Shutdown(); err != nil { + t.Error(err) + } + time.Sleep(10 * time.Millisecond) + if err := srv.Start(); err != nil { + t.Error(err) + } + time.Sleep(10 * time.Millisecond) + if err := srv.Reload(); err != nil { + t.Error(err) + } + time.Sleep(10 * time.Millisecond) + if err := srv.Shutdown(); err != nil { + t.Error(err) + } + time.Sleep(10 * time.Millisecond) + if srv.IsRunning() { + t.Errorf("service is still running") + } +} + +func TestRadiusAgentReload1(t *testing.T) { cfg := config.NewDefaultCGRConfig() cfg.SessionSCfg().Enabled = true @@ -87,12 +144,11 @@ func TestRadiusAgentReload(t *testing.T) { } else if reply != utils.OK { t.Fatalf("Expecting OK ,received %s", reply) } - time.Sleep(10 * time.Millisecond) //need to switch to gorutine runtime.Gosched() + time.Sleep(10 * time.Millisecond) //need to switch to gorutine if !srv.IsRunning() { t.Fatalf("Expected service to be running") } - runtime.Gosched() err = srv.Start() if err == nil || err != utils.ErrServiceAlreadyRunning { t.Fatalf("\nExpecting <%+v>,\n Received <%+v>", utils.ErrServiceAlreadyRunning, err) @@ -175,23 +231,17 @@ func TestRadiusAgentReload2(t *testing.T) { if err != nil { t.Fatalf("\nExpecting ,\n Received <%+v>", err) } - castSrv, canCastSrv := srv.(*RadiusAgent) - if !canCastSrv { - t.Fatalf("cannot cast") - } - err = srv.Reload() if err != nil { t.Fatalf("\nExpecting ,\n Received <%+v>", err) } - castSrv.lnet = "test_string" err = srv.Reload() if err != nil { t.Fatalf("\nExpecting ,\n Received <%+v>", err) } cfg.RadiusAgentCfg().Enabled = false cfg.GetReloadChan(config.RA_JSN) <- struct{}{} - time.Sleep(10 * time.Millisecond) + time.Sleep(100 * time.Millisecond) if srv.IsRunning() { t.Fatalf("Expected service to be down") } @@ -226,7 +276,7 @@ func TestRadiusAgentReload4(t *testing.T) { cfg := config.NewDefaultCGRConfig() cfg.SessionSCfg().Enabled = true cfg.RadiusAgentCfg().Enabled = true - cfg.RadiusAgentCfg().ListenNet = "test" + cfg.RadiusAgentCfg().Listeners[0].Network = "test" utils.Logger, _ = utils.Newlogger(utils.MetaSysLog, cfg.GeneralCfg().NodeID) utils.Logger.SetLogLevel(7) filterSChan := make(chan *engine.FilterS, 1) diff --git a/utils/consts.go b/utils/consts.go index 0cb5df8f5..92e54dd52 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -2217,8 +2217,8 @@ const ( ReplyFieldsCfg = "reply_fields" // RadiusAgentCfg - ListenAuthCfg = "listen_auth" - ListenAcctCfg = "listen_acct" + AuthAddrCfg = "auth_address" + AcctAddrCfg = "acct_address" ClientSecretsCfg = "client_secrets" ClientDictionariesCfg = "client_dictionaries"