DNSAgent configuration options within .json

This commit is contained in:
DanB
2019-04-05 18:50:21 +02:00
parent 81d145587d
commit a9eee5b6c6
8 changed files with 262 additions and 6 deletions

View File

@@ -17,3 +17,57 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package agents
import (
"fmt"
"strings"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/rpcclient"
"github.com/miekg/dns"
)
// NewDNSAgent is the constructor for DNSAgent
func NewDNSAgent(cgrCfg *config.CGRConfig, fltrS *engine.FilterS,
sS rpcclient.RpcClientConnection) (da *DNSAgent, err error) {
da = &DNSAgent{cgrCfg: cgrCfg, fltrS: fltrS, sS: sS}
return
}
// DNSAgent translates DNS requests towards CGRateS infrastructure
type DNSAgent struct {
cgrCfg *config.CGRConfig // loaded CGRateS configuration
fltrS *engine.FilterS // connection towards FilterS
sS rpcclient.RpcClientConnection // connection towards CGR-SessionS component
}
// ListenAndServe will run the DNS handler doing also the connection to listen address
func (da *DNSAgent) ListenAndServe() error {
if strings.HasSuffix(da.cgrCfg.DNSAgentCfg().ListenNet, utils.TLSNoCaps) {
return dns.ListenAndServeTLS(
da.cgrCfg.DNSAgentCfg().Listen,
da.cgrCfg.TlsCfg().ServerCerificate,
da.cgrCfg.TlsCfg().ServerKey,
dns.HandlerFunc(
func(w ResponseWriter, m *Msg) {
go da.handleMessage(w, m)
}),
)
}
return dns.ListenAndServe(
da.cgrCfg.DNSAgentCfg().Listen,
da.cgrCfg.DNSAgentCfg().ListenNet,
dns.HandlerFunc(
func(w ResponseWriter, m *Msg) {
go da.handleMessage(w, m)
}),
)
}
// handleMessage is the entry point of all DNS requests
// requests are reaching here asynchronously
func (da *DNSAgent) handleMessage(w ResponseWriter, m *dns.Msg) {
fmt.Printf("got message: %+v\n", m)
}

View File

@@ -152,6 +152,7 @@ func NewDefaultCGRConfig() (*CGRConfig, error) {
cfg.asteriskAgentCfg = new(AsteriskAgentCfg)
cfg.diameterAgentCfg = new(DiameterAgentCfg)
cfg.radiusAgentCfg = new(RadiusAgentCfg)
cfg.dnsAgentCfg = new(DNSAgentCfg)
cfg.attributeSCfg = new(AttributeSCfg)
cfg.chargerSCfg = new(ChargerSCfg)
cfg.resourceSCfg = new(ResourceSConfig)
@@ -324,6 +325,7 @@ type CGRConfig struct {
asteriskAgentCfg *AsteriskAgentCfg // AsteriskAgent config
diameterAgentCfg *DiameterAgentCfg // DiameterAgent config
radiusAgentCfg *RadiusAgentCfg // RadiusAgent config
dnsAgentCfg *DNSAgentCfg // DNSAgent config
attributeSCfg *AttributeSCfg // AttributeS config
chargerSCfg *ChargerSCfg // ChargerS config
resourceSCfg *ResourceSConfig // ResourceS config
@@ -605,6 +607,13 @@ func (self *CGRConfig) checkConfigSanity() error {
}
}
}
if self.dnsAgentCfg.Enabled && !self.sessionSCfg.Enabled {
for _, sSConn := range self.dnsAgentCfg.SessionSConns {
if sSConn.Address == utils.MetaInternal {
return fmt.Errorf("%s not enabled but referenced by %s", utils.SessionS, utils.DNSAgent)
}
}
}
// HTTPAgent checks
for _, httpAgentCfg := range self.httpAgentCfg {
// httpAgent checks
@@ -840,6 +849,14 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) {
return err
}
jsnDNSCfg, err := jsnCfg.DNSAgentJsonCfg()
if err != nil {
return err
}
if err := self.dnsAgentCfg.loadFromJsonCfg(jsnDNSCfg, self.generalCfg.RsrSepatarot); err != nil {
return err
}
jsnHttpAgntCfg, err := jsnCfg.HttpAgentJsonCfg()
if err != nil {
return err
@@ -1050,6 +1067,10 @@ func (self *CGRConfig) RadiusAgentCfg() *RadiusAgentCfg {
return self.radiusAgentCfg
}
func (self *CGRConfig) DNSAgentCfg() *DNSAgentCfg {
return self.dnsAgentCfg
}
func (cfg *CGRConfig) AttributeSCfg() *AttributeSCfg {
return cfg.attributeSCfg
}

View File

@@ -453,6 +453,19 @@ const CGRATES_CFG_JSON = `
],
"dns_agent": {
"enabled": false, // enables the DNS agent: <true|false>
"listen_net": "udp", // network to listen on <udp|tcp|tcp-tls>
"listen": "127.0.0.1:53", // address where to listen for DNS requests <x.y.z.y:1234>
"sessions_conns": [ // connections to SessionS for session management and CDR posting
{"address": "*internal"}
],
"timezone": "", // timezone of the events if not specified <UTC|Local|$IANA_TZ_DB>
"request_processors": [ // request processors to be applied to DNS messages
],
},
"attributes": { // AttributeS config
"enabled": false, // starts attribute service: <true|false>.
"indexed_selects":true, // enable profile matching exclusively on indexes

View File

@@ -66,6 +66,7 @@ const (
TlsCfgJson = "tls"
AnalyzerCfgJson = "analyzers"
Apier = "apier"
DNSAgentJson = "dns_agent"
)
// Loads the json config out of io.Reader, eg other sources than file, maybe over http
@@ -320,6 +321,16 @@ func (self CgrJsonCfg) HttpAgentJsonCfg() (*[]*HttpAgentJsonCfg, error) {
return &httpAgnt, nil
}
func (self CgrJsonCfg) DNSAgentJsonCfg() (da *DNSAgentJsonCfg, err error) {
rawCfg, hasKey := self[DNSAgentJson]
if !hasKey {
return
}
da = new(DNSAgentJsonCfg)
err = json.Unmarshal(*rawCfg, da)
return
}
func (cgrJsn CgrJsonCfg) AttributeServJsonCfg() (*AttributeSJsonCfg, error) {
rawCfg, hasKey := cgrJsn[ATTRIBUTE_JSN]
if !hasKey {

View File

@@ -737,6 +737,26 @@ func TestHttpAgentJsonCfg(t *testing.T) {
}
}
func TestDNSAgentJsonCfg(t *testing.T) {
eCfg := &DNSAgentJsonCfg{
Enabled: utils.BoolPointer(false),
Listen_net: utils.StringPointer("udp"),
Listen: utils.StringPointer("127.0.0.1:53"),
Sessions_conns: &[]*HaPoolJsonCfg{
{
Address: utils.StringPointer(utils.MetaInternal),
}},
Timezone: utils.StringPointer(""),
Request_processors: &[]*ReqProcessorJsnCfg{},
}
if cfg, err := dfCgrJsonCfg.DNSAgentJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
rcv := *cfg.Request_processors
t.Errorf("Received: %+v", rcv)
}
}
func TestDfAttributeServJsonCfg(t *testing.T) {
eCfg := &AttributeSJsonCfg{
Enabled: utils.BoolPointer(false),

122
config/dnsagntcfg.go Normal file
View File

@@ -0,0 +1,122 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package config
import (
"github.com/cgrates/cgrates/utils"
)
type DNSAgentCfg struct {
Enabled bool
ListenNet string // udp or tcp
Listen string
SessionSConns []*RemoteHost
Timezone string
RequestProcessors []*RequestProcessor
}
func (da *DNSAgentCfg) loadFromJsonCfg(jsnCfg *DNSAgentJsonCfg, sep string) (err error) {
if jsnCfg == nil {
return nil
}
if jsnCfg.Enabled != nil {
da.Enabled = *jsnCfg.Enabled
}
if jsnCfg.Listen_net != nil {
da.ListenNet = *jsnCfg.Listen_net
}
if jsnCfg.Listen != nil {
da.Listen = *jsnCfg.Listen
}
if jsnCfg.Sessions_conns != nil {
da.SessionSConns = make([]*RemoteHost, len(*jsnCfg.Sessions_conns))
for idx, jsnHaCfg := range *jsnCfg.Sessions_conns {
da.SessionSConns[idx] = NewDfltRemoteHost()
da.SessionSConns[idx].loadFromJsonCfg(jsnHaCfg)
}
}
if jsnCfg.Request_processors != nil {
for _, reqProcJsn := range *jsnCfg.Request_processors {
rp := new(RequestProcessor)
var haveID bool
for _, rpSet := range da.RequestProcessors {
if reqProcJsn.ID != nil && rpSet.ID == *reqProcJsn.ID {
rp = rpSet // Will load data into the one set
haveID = true
break
}
}
if err := rp.loadFromJsonCfg(reqProcJsn, sep); err != nil {
return nil
}
if !haveID {
da.RequestProcessors = append(da.RequestProcessors, rp)
}
}
}
return nil
}
// One request processor configuration
type RequestProcessor struct {
ID string
Tenant RSRParsers
Filters []string
Flags utils.StringMap
ContinueOnSuccess bool
RequestFields []*FCTemplate
ReplyFields []*FCTemplate
}
func (rp *RequestProcessor) loadFromJsonCfg(jsnCfg *ReqProcessorJsnCfg, sep string) (err error) {
if jsnCfg == nil {
return nil
}
if jsnCfg.ID != nil {
rp.ID = *jsnCfg.ID
}
if jsnCfg.Filters != nil {
rp.Filters = make([]string, len(*jsnCfg.Filters))
for i, fltr := range *jsnCfg.Filters {
rp.Filters[i] = fltr
}
}
if jsnCfg.Flags != nil {
rp.Flags = utils.StringMapFromSlice(*jsnCfg.Flags)
}
if jsnCfg.Continue_on_success != nil {
rp.ContinueOnSuccess = *jsnCfg.Continue_on_success
}
if jsnCfg.Tenant != nil {
if rp.Tenant, err = NewRSRParsers(*jsnCfg.Tenant, true, sep); err != nil {
return err
}
}
if jsnCfg.Request_fields != nil {
if rp.RequestFields, err = FCTemplatesFromFCTemplatesJsonCfg(*jsnCfg.Request_fields, sep); err != nil {
return
}
}
if jsnCfg.Reply_fields != nil {
if rp.ReplyFields, err = FCTemplatesFromFCTemplatesJsonCfg(*jsnCfg.Reply_fields, sep); err != nil {
return
}
}
return nil
}

View File

@@ -360,7 +360,6 @@ type RadiusAgentJsonCfg struct {
Client_secrets *map[string]string
Client_dictionaries *map[string]string
Sessions_conns *[]*HaPoolJsonCfg
Tenant *string
Timezone *string
Request_processors *[]*RAReqProcessorJsnCfg
}
@@ -397,11 +396,25 @@ type HttpAgentProcessorJsnCfg struct {
Reply_fields *[]*FcTemplateJsonCfg
}
// History server config section
type HistServJsonCfg struct {
Enabled *bool
History_dir *string
Save_interval *string
// DNSAgentJsonCfg
type DNSAgentJsonCfg struct {
Enabled *bool
Listen *string
Listen_net *string
Sessions_conns *[]*HaPoolJsonCfg
Timezone *string
Request_processors *[]*ReqProcessorJsnCfg
}
type ReqProcessorJsnCfg struct {
ID *string
Filters *[]string
Tenant *string
Timezone *string
Flags *[]string
Continue_on_success *bool
Request_fields *[]*FcTemplateJsonCfg
Reply_fields *[]*FcTemplateJsonCfg
}
// Attribute service config section

View File

@@ -562,6 +562,8 @@ const (
MetaRemove = "*remove"
MetaClear = "*clear"
LoadIDs = "load_ids"
DNSAgent = "DNSAgent"
TLSNoCaps = "tls"
)
// Migrator Action