diff --git a/agents/librad.go b/agents/librad.go
new file mode 100644
index 000000000..6eb7007ba
--- /dev/null
+++ b/agents/librad.go
@@ -0,0 +1,41 @@
+/*
+Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
+Copyright (C) ITsysCOM GmbH
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package agents
+
+import (
+ "github.com/cgrates/cgrates/utils"
+ "github.com/cgrates/radigo"
+)
+
+/*
+Various RADIUS helpers here
+*/
+
+func radPassesFieldFilter(pkt *radigo.Packet, fieldFilter *utils.RSRField, processorVars map[string]string) (pass bool) {
+ if fieldFilter == nil {
+ return true
+ }
+ if val, hasIt := processorVars[fieldFilter.Id]; hasIt { // ProcessorVars have priority
+ if fieldFilter.FilterPasses(val) {
+ return true, 0
+ }
+ return false
+ }
+ return
+}
diff --git a/agents/librad_test.go b/agents/librad_test.go
new file mode 100644
index 000000000..8fee7742c
--- /dev/null
+++ b/agents/librad_test.go
@@ -0,0 +1,36 @@
+/*
+Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
+Copyright (C) ITsysCOM GmbH
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
+*/
+
+package agents
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/sessionmanager"
+ "github.com/cgrates/cgrates/utils"
+ "github.com/fiorix/go-diameter/diam"
+ "github.com/fiorix/go-diameter/diam/avp"
+ "github.com/fiorix/go-diameter/diam/datatype"
+ "github.com/fiorix/go-diameter/diam/dict"
+)
diff --git a/agents/radagent.go b/agents/radagent.go
index 374ded580..94d32cc23 100644
--- a/agents/radagent.go
+++ b/agents/radagent.go
@@ -35,9 +35,9 @@ func NewRadiusAgent(cgrCfg *config.CGRConfig, smg rpcclient.RpcClientConnection)
}
ra = &RadiusAgent{cgrCfg: cgrCfg, smg: smg}
ra.rsAuth = radigo.NewServer(cgrCfg.RadiusAgentCfg().ListenNet, cgrCfg.RadiusAgentCfg().ListenAuth, cgrCfg.RadiusAgentCfg().ClientSecrets, dicts,
- map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){radigo.AccessRequest: ra.handleAuth})
+ map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){radigo.AccessRequest: ra.handleAuth}, nil)
ra.rsAcct = radigo.NewServer(cgrCfg.RadiusAgentCfg().ListenNet, cgrCfg.RadiusAgentCfg().ListenAcct, cgrCfg.RadiusAgentCfg().ClientSecrets, dicts,
- map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){radigo.AccountingRequest: ra.handleAcct})
+ map[radigo.PacketCode]func(*radigo.Packet) (*radigo.Packet, error){radigo.AccountingRequest: ra.handleAcct}, nil)
return
}
@@ -59,12 +59,26 @@ func (ra *RadiusAgent) handleAuth(req *radigo.Packet) (rpl *radigo.Packet, err e
return
}
+// RadiusAgent handleAcct, received req: &{RWMutex:{w:{state:0 sema:0} writerSem:0 readerSem:0 readerCount:0 readerWait:0} dict:0xc4202e5840 secret:CGRateS.org Code:AccountingRequest Identifier:143 Authenticator:[67 77 204 122 189 209 219 22 9 176 15 228 24 246 183 7] AVPs:[0xc42023c230 0xc42023c2a0 0xc42023c310 0xc42023c460 0xc42023c4d0 0xc42023c540 0xc42023c850 0xc42023ce00 0xc42023d180 0xc42023d1f0 0xc42023d260]}
+// Identifier:144 Authenticator:[192 197 33 53 203 181 16 117 204 143 172 174 231 245 81 116] AVPs:[0xc42023d5e0 0xc42023d650 0xc42023d880 0xc42023d8f0 0xc42023da40 0xc42023db20 0xc42023dc70 0xc42023dd50 0xc42023ddc0 0xc42023de30 0xc42023dea0]}
func (ra *RadiusAgent) handleAcct(req *radigo.Packet) (rpl *radigo.Packet, err error) {
- utils.Logger.Debug(fmt.Sprintf("RadiusAgent handleAcct, received req: %+v", req))
+ req.SetAVPValues()
+ utils.Logger.Debug(fmt.Sprintf("Received request: %s", utils.ToJSON(req)))
rpl = req.Reply()
rpl.Code = radigo.AccountingResponse
- for _, avp := range req.AVPs {
- rpl.AVPs = append(rpl.AVPs, avp)
+ rpl.SetAVPValues()
+ return
+}
+
+func (ra *RadiusAgent) processRequest(req *radigo.Packet, reqProcessor *config.RARequestProcessor) (processed bool, err error) {
+ passesAllFilters := true
+ for _, fldFilter := range reqProcessor.RequestFilter {
+ if passes, _ := radPassesFieldFilter(req, fldFilter, nil); !passes {
+ passesAllFilters = false
+ }
+ }
+ if !passesAllFilters { // Not going with this processor further
+ return false, nil
}
return
}
diff --git a/data/conf/samples/radagent/cgrates.json b/data/conf/samples/radagent/cgrates.json
index ab571a016..cb7f38a01 100644
--- a/data/conf/samples/radagent/cgrates.json
+++ b/data/conf/samples/radagent/cgrates.json
@@ -1,8 +1,11 @@
{
// CGRateS Configuration file
//
-// Used for cgradmin
-// Starts rater, scheduler
+
+"general": {
+ "log_level": 7,
+},
+
"listen": {
"rpc_json": ":2012", // RPC JSON listening address
@@ -74,6 +77,36 @@
"radius_agent": {
"enabled": true,
+ "request_processors": [
+ {
+ "id": "KamailioAccountingStart",
+ "dry_run": false,
+ "request_filter": "Service-Type(Sip-Session);Sip-Method(Invite)",
+ "flags": [],
+ "continue_on_success": false,
+ "append_reply": true,
+ "request_fields":[
+ {"tag": "Account", "field_id": "Account", "type": "*composed", "value": "User-Name", "mandatory": true},
+ {"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "Called-Station-Id", "mandatory": true},
+ ],
+ "reply_fields":[],
+ },
+ {
+ "id": "KamailioAccountingStop",
+ "dry_run": false,
+ "request_filter": "Service-Type(Sip-Session);Sip-Method(Bye)",
+ "flags": [],
+ "continue_on_success": false,
+ "append_reply": true,
+ "request_fields":[
+ {"tag": "Account", "field_id": "Account", "type": "*composed", "value": "User-Name", "mandatory": true},
+ {"tag": "Destination", "field_id": "Destination", "type": "*composed", "value": "Called-Station-Id", "mandatory": true},
+ ],
+ "reply_fields":[],
+ },
+
+ ],
+
},
}
diff --git a/data/radius/dict/dictionary.kamailio b/data/radius/dict/dictionary.kamailio
new file mode 100644
index 000000000..2188030ca
--- /dev/null
+++ b/data/radius/dict/dictionary.kamailio
@@ -0,0 +1,86 @@
+#
+# $Id$
+#
+# SIP RADIUS attributes
+#
+# Proprietary indicates an attribute that hasn't
+# been standardized
+#
+#
+# NOTE: All standard (IANA registered) attributes are
+# defined in the default dictionary of the
+# radiusclient-ng library.
+#
+
+
+#### Attributes ###
+ATTRIBUTE Sip-Response-Code 102 integer
+ATTRIBUTE Sip-Method 101 integer
+ATTRIBUTE Sip-Response-Code 102 integer
+ATTRIBUTE Sip-CSeq 103 string
+ATTRIBUTE Sip-To-Tag 104 string
+ATTRIBUTE Sip-From-Tag 105 string
+ATTRIBUTE Sip-Branch-ID 106 string
+ATTRIBUTE Sip-Translated-Request-URI 107 string
+ATTRIBUTE Sip-Source-IP-Address 108 ipaddr
+ATTRIBUTE Sip-Source-Port 109 integer
+ATTRIBUTE Sip-User-ID 110 string
+ATTRIBUTE Sip-User-Realm 111 string
+ATTRIBUTE Sip-User-Nonce 112 string
+ATTRIBUTE Sip-User-Method 113 string
+ATTRIBUTE Sip-User-Digest-URI 114 string
+ATTRIBUTE Sip-User-Nonce-Count 115 string
+ATTRIBUTE Sip-User-QOP 116 string
+ATTRIBUTE Sip-User-Opaque 117 string
+ATTRIBUTE Sip-User-Response 118 string
+ATTRIBUTE Sip-User-CNonce 119 string
+ATTRIBUTE Sip-URI-User 208 string
+ATTRIBUTE Sip-Req-URI 210 string
+ATTRIBUTE Sip-CC 212 string
+ATTRIBUTE Sip-RPId 213 string
+ATTRIBUTE Digest-Response 206 string
+ATTRIBUTE Digest-Attributes 207 string
+ATTRIBUTE Digest-Realm 1063 string
+ATTRIBUTE Digest-Nonce 1064 string
+ATTRIBUTE Digest-Method 1065 string
+ATTRIBUTE Digest-URI 1066 string
+ATTRIBUTE Digest-QOP 1067 string
+ATTRIBUTE Digest-Algorithm 1068 string
+ATTRIBUTE Digest-Body-Digest 1069 string
+ATTRIBUTE Digest-CNonce 1070 string
+ATTRIBUTE Digest-Nonce-Count 1071 string
+ATTRIBUTE Digest-User-Name 1072 string
+
+ATTRIBUTE Sip-Uri-User 208 string # Proprietary, auth_radius
+ATTRIBUTE Sip-Group 211 string # Proprietary, group_radius
+ATTRIBUTE Sip-Rpid 213 string # Proprietary, auth_radius
+ATTRIBUTE SIP-AVP 225 string # Proprietary, avp_radius
+
+### Acct-Status-Type Values ###
+VALUE Acct-Status-Type Failed 15 # RFC2866, acc
+
+### Service-Type Values ###
+#VALUE Service-Type Call-Check 10 # RFC2865, uri_radius
+VALUE Service-Type Group-Check 12 # Proprietary, group_radius
+VALUE Service-Type Sip-Session 15 # Schulzrinne, acc, auth_radius
+VALUE Service-Type SIP-Caller-AVPs 30 # Proprietary, avp_radius
+VALUE Service-Type SIP-Callee-AVPs 31 # Proprietary, avp_radius
+
+### Sip-Method Values ###
+VALUE Sip-Method Undefined 0
+VALUE Sip-Method Invite 1
+VALUE Sip-Method Cancel 2
+VALUE Sip-Method Ack 4
+VALUE Sip-Method Bye 8
+VALUE Sip-Method Info 16
+VALUE Sip-Method Options 32
+VALUE Sip-Method Update 64
+VALUE Sip-Method Register 128
+VALUE Sip-Method Message 256
+VALUE Sip-Method Subscribe 512
+VALUE Sip-Method Notify 1024
+VALUE Sip-Method Prack 2048
+VALUE Sip-Method Refer 4096
+VALUE Sip-Method Other 8192
+
+
diff --git a/engine/storage_cdrs_it_test.go b/engine/storage_cdrs_it_test.go
index 72e05abd4..44363bd9d 100644
--- a/engine/storage_cdrs_it_test.go
+++ b/engine/storage_cdrs_it_test.go
@@ -32,7 +32,6 @@ import (
)
func TestITCDRsMySQL(t *testing.T) {
-
cfg, err := config.NewCGRConfigFromFolder(path.Join(*dataDir, "conf", "samples", "storage", "mysql"))
if err != nil {
t.Error(err)
@@ -49,7 +48,6 @@ func TestITCDRsMySQL(t *testing.T) {
}
func TestITCDRsPSQL(t *testing.T) {
-
cfg, err := config.NewCGRConfigFromFolder(path.Join(*dataDir, "conf", "samples", "storage", "postgres"))
if err != nil {
t.Error(err)