Updated DNSAgent

This commit is contained in:
Trial97
2021-09-29 17:55:57 +03:00
committed by Dan Christian Bogos
parent dce8636c30
commit ec539b5994
26 changed files with 1123 additions and 953 deletions

View File

@@ -221,6 +221,18 @@ func testDiamItResetAllDB(t *testing.T) {
if err := engine.InitStorDb(allCfg); err != nil {
t.Fatal(err)
}
cfgPath2 := path.Join(*dataDir, "conf", "samples", "dispatchers", "all2")
allCfg2, err := config.NewCGRConfigFromPath(cfgPath2)
if err != nil {
t.Fatal(err)
}
if err := engine.InitDataDb(allCfg2); err != nil {
t.Fatal(err)
}
if err := engine.InitStorDb(allCfg2); err != nil {
t.Fatal(err)
}
}
// Remove data in both rating and accounting db

View File

@@ -267,14 +267,17 @@ func (da *DiameterAgent) handleMessage(c diam.Conn, m *diam.Message) {
var processed bool
for _, reqProcessor := range da.cgrCfg.DiameterAgentCfg().RequestProcessors {
var lclProcessed bool
lclProcessed, err = da.processRequest(
lclProcessed, err = processRequest(
reqProcessor,
NewAgentRequest(
diamDP, reqVars, cgrRplyNM, rply, opts,
reqProcessor.Tenant, da.cgrCfg.GeneralCfg().DefaultTenant,
utils.FirstNonEmpty(reqProcessor.Timezone,
da.cgrCfg.GeneralCfg().DefaultTimezone),
da.filterS, nil))
da.filterS, nil),
utils.DiameterAgent, da.connMgr,
da.cgrCfg.DiameterAgentCfg().SessionSConns,
da, da.filterS)
if lclProcessed {
processed = lclProcessed
}
@@ -309,180 +312,6 @@ func (da *DiameterAgent) handleMessage(c diam.Conn, m *diam.Message) {
writeOnConn(c, a)
}
func (da *DiameterAgent) processRequest(reqProcessor *config.RequestProcessor,
agReq *AgentRequest) (processed bool, err error) {
if pass, err := da.filterS.Pass(agReq.Tenant,
reqProcessor.Filters, agReq); err != nil || !pass {
return pass, err
}
if err = agReq.SetFields(reqProcessor.RequestFields); err != nil {
return
}
cgrEv := utils.NMAsCGREvent(agReq.CGRRequest, agReq.Tenant, utils.NestingSep, agReq.Opts)
var reqType string
for _, typ := range []string{
utils.MetaDryRun, utils.MetaAuthorize,
utils.MetaInitiate, utils.MetaUpdate,
utils.MetaTerminate, utils.MetaMessage,
utils.MetaCDRs, utils.MetaEvent, utils.MetaNone} {
if reqProcessor.Flags.Has(typ) { // request type is identified through flags
reqType = typ
break
}
}
var cgrArgs utils.Paginator
if reqType == utils.MetaAuthorize || reqType == utils.MetaMessage || reqType == utils.MetaEvent {
if cgrArgs, err = utils.GetRoutePaginatorFromOpts(cgrEv.APIOpts); err != nil {
utils.Logger.Warning(fmt.Sprintf("<%s> args extraction failed because <%s>",
utils.DiameterAgent, err.Error()))
err = nil // reset the error and continue the processing
}
}
if reqProcessor.Flags.Has(utils.MetaLog) {
utils.Logger.Info(
fmt.Sprintf("<%s> LOG, processorID: %s, diameter message: %s",
utils.DiameterAgent, reqProcessor.ID, agReq.Request.String()))
}
switch reqType {
default:
return false, fmt.Errorf("unknown request type: <%s>", reqType)
case utils.MetaNone: // do nothing on CGRateS side
case utils.MetaDryRun:
utils.Logger.Info(
fmt.Sprintf("<%s> DRY_RUN, processorID: %s, DiameterMessage: %s",
utils.DiameterAgent, reqProcessor.ID, agReq.Request.String()))
case utils.MetaAuthorize:
authArgs := sessions.NewV1AuthorizeArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaRoutes),
reqProcessor.Flags.Has(utils.MetaRoutesIgnoreErrors),
reqProcessor.Flags.Has(utils.MetaRoutesEventCost),
cgrEv, cgrArgs,
reqProcessor.Flags.Has(utils.MetaFD),
reqProcessor.Flags.ParamValue(utils.MetaRoutesMaxCost),
)
rply := new(sessions.V1AuthorizeReply)
err = da.connMgr.Call(da.cgrCfg.DiameterAgentCfg().SessionSConns, da, utils.SessionSv1AuthorizeEvent,
authArgs, rply)
rply.SetMaxUsageNeeded(authArgs.GetMaxUsage)
agReq.setCGRReply(rply, err)
case utils.MetaInitiate:
initArgs := sessions.NewV1InitSessionArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
rply := new(sessions.V1InitSessionReply)
err = da.connMgr.Call(da.cgrCfg.DiameterAgentCfg().SessionSConns, da, utils.SessionSv1InitiateSession,
initArgs, rply)
rply.SetMaxUsageNeeded(initArgs.InitSession)
agReq.setCGRReply(rply, err)
case utils.MetaUpdate:
updateArgs := sessions.NewV1UpdateSessionArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.Has(utils.MetaAccounts),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
rply := new(sessions.V1UpdateSessionReply)
rply.SetMaxUsageNeeded(updateArgs.UpdateSession)
err = da.connMgr.Call(da.cgrCfg.DiameterAgentCfg().SessionSConns, da, utils.SessionSv1UpdateSession,
updateArgs, rply)
agReq.setCGRReply(rply, err)
case utils.MetaTerminate:
terminateArgs := sessions.NewV1TerminateSessionArgs(
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
var rply string
err = da.connMgr.Call(da.cgrCfg.DiameterAgentCfg().SessionSConns, da, utils.SessionSv1TerminateSession,
terminateArgs, &rply)
agReq.setCGRReply(nil, err)
case utils.MetaMessage:
msgArgs := sessions.NewV1ProcessMessageArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaRoutes),
reqProcessor.Flags.Has(utils.MetaRoutesIgnoreErrors),
reqProcessor.Flags.Has(utils.MetaRoutesEventCost),
cgrEv, cgrArgs,
reqProcessor.Flags.Has(utils.MetaFD),
reqProcessor.Flags.ParamValue(utils.MetaRoutesMaxCost),
)
rply := new(sessions.V1ProcessMessageReply)
err = da.connMgr.Call(da.cgrCfg.DiameterAgentCfg().SessionSConns, da, utils.SessionSv1ProcessMessage,
msgArgs, rply)
if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
cgrEv.Event[utils.Usage] = 0 // avoid further debits
} else if msgArgs.Debit {
cgrEv.Event[utils.Usage] = rply.MaxUsage // make sure the CDR reflects the debit
}
rply.SetMaxUsageNeeded(msgArgs.Debit)
agReq.setCGRReply(rply, err)
case utils.MetaEvent:
evArgs := &sessions.V1ProcessEventArgs{
Flags: reqProcessor.Flags.SliceFlags(),
Paginator: cgrArgs,
CGREvent: cgrEv,
}
rply := new(sessions.V1ProcessEventReply)
err = da.connMgr.Call(da.cgrCfg.DiameterAgentCfg().SessionSConns, da, utils.SessionSv1ProcessEvent,
evArgs, rply)
if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
cgrEv.Event[utils.Usage] = 0 // avoid further debits
} else if needsMaxUsage(reqProcessor.Flags[utils.MetaRALs]) {
cgrEv.Event[utils.Usage] = rply.MaxUsage // make sure the CDR reflects the debit
}
agReq.setCGRReply(rply, err)
case utils.MetaCDRs: // allow CDR processing
}
// separate request so we can capture the Terminate/Event also here
if reqProcessor.Flags.GetBool(utils.MetaCDRs) &&
!reqProcessor.Flags.Has(utils.MetaDryRun) {
var rplyCDRs string
if err = da.connMgr.Call(da.cgrCfg.DiameterAgentCfg().SessionSConns, da, utils.SessionSv1ProcessCDR,
cgrEv, &rplyCDRs); err != nil {
agReq.CGRReply.Map[utils.Error] = utils.NewLeafNode(err.Error())
}
}
if err = agReq.SetFields(reqProcessor.ReplyFields); err != nil {
return
}
if reqProcessor.Flags.Has(utils.MetaLog) {
utils.Logger.Info(
fmt.Sprintf("<%s> LOG, Diameter reply: %s",
utils.DiameterAgent, agReq.Reply))
}
if reqType == utils.MetaDryRun {
utils.Logger.Info(
fmt.Sprintf("<%s> DRY_RUN, Diameter reply: %s",
utils.DiameterAgent, agReq.Reply))
}
return true, nil
}
// Call implements rpcclient.ClientConnector interface
func (da *DiameterAgent) Call(serviceMethod string, args interface{}, reply interface{}) error {
return utils.RPCCall(da, serviceMethod, args, reply)

View File

@@ -458,7 +458,7 @@ func TestProcessRequest(t *testing.T) {
filterS: filters,
connMgr: connMgr,
}
pr, err := da.processRequest(reqProcessor, agReq)
pr, err := processRequest(reqProcessor, agReq, utils.DiameterAgent, connMgr, da.cgrCfg.DiameterAgentCfg().SessionSConns, da, da.filterS)
if err != nil {
t.Error(err)
} else if !pr {
@@ -475,7 +475,7 @@ func TestProcessRequest(t *testing.T) {
reqProcessor.Tenant, config.CgrConfig().GeneralCfg().DefaultTenant,
config.CgrConfig().GeneralCfg().DefaultTimezone, filters, nil)
pr, err = da.processRequest(reqProcessor, agReq)
pr, err = processRequest(reqProcessor, agReq, utils.DiameterAgent, connMgr, da.cgrCfg.DiameterAgentCfg().SessionSConns, da, da.filterS)
if err != nil {
t.Error(err)
} else if !pr {
@@ -492,7 +492,7 @@ func TestProcessRequest(t *testing.T) {
reqProcessor.Tenant, config.CgrConfig().GeneralCfg().DefaultTenant,
config.CgrConfig().GeneralCfg().DefaultTimezone, filters, nil)
pr, err = da.processRequest(reqProcessor, agReq)
pr, err = processRequest(reqProcessor, agReq, utils.DiameterAgent, connMgr, da.cgrCfg.DiameterAgentCfg().SessionSConns, da, da.filterS)
if err != nil {
t.Error(err)
} else if !pr {
@@ -515,7 +515,7 @@ func TestProcessRequest(t *testing.T) {
reqProcessor.Tenant, config.CgrConfig().GeneralCfg().DefaultTenant,
config.CgrConfig().GeneralCfg().DefaultTimezone, filters, nil)
pr, err = da.processRequest(reqProcessor, agReq)
pr, err = processRequest(reqProcessor, agReq, utils.DiameterAgent, connMgr, da.cgrCfg.DiameterAgentCfg().SessionSConns, da, da.filterS)
if err != nil {
t.Error(err)
} else if !pr {
@@ -532,7 +532,7 @@ func TestProcessRequest(t *testing.T) {
reqProcessor.Tenant, config.CgrConfig().GeneralCfg().DefaultTenant,
config.CgrConfig().GeneralCfg().DefaultTimezone, filters, nil)
pr, err = da.processRequest(reqProcessor, agReq)
pr, err = processRequest(reqProcessor, agReq, utils.DiameterAgent, connMgr, da.cgrCfg.DiameterAgentCfg().SessionSConns, da, da.filterS)
if err != nil {
t.Error(err)
} else if !pr {

View File

@@ -25,7 +25,6 @@ import (
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/sessions"
"github.com/cgrates/cgrates/utils"
"github.com/miekg/dns"
)
@@ -47,27 +46,23 @@ type DNSAgent struct {
}
// initDNSServer instantiates the DNS server
func (da *DNSAgent) initDNSServer() (err error) {
handler := dns.HandlerFunc(func(w dns.ResponseWriter, m *dns.Msg) {
go da.handleMessage(w, m)
})
func (da *DNSAgent) initDNSServer() (_ error) {
da.server = &dns.Server{
Addr: da.cgrCfg.DNSAgentCfg().Listen,
Net: da.cgrCfg.DNSAgentCfg().ListenNet,
Handler: dns.HandlerFunc(func(w dns.ResponseWriter, m *dns.Msg) {
go da.handleMessage(w, m)
}),
}
if strings.HasSuffix(da.cgrCfg.DNSAgentCfg().ListenNet, utils.TLSNoCaps) {
cert, err := tls.LoadX509KeyPair(da.cgrCfg.TLSCfg().ServerCerificate, da.cgrCfg.TLSCfg().ServerKey)
if err != nil {
return err
}
config := tls.Config{
da.server.Net = "tcp-tls"
da.server.TLSConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
}
da.server = &dns.Server{
Addr: da.cgrCfg.DNSAgentCfg().Listen,
Net: "tcp-tls",
TLSConfig: &config,
Handler: handler,
}
} else {
da.server = &dns.Server{Addr: da.cgrCfg.DNSAgentCfg().Listen, Net: da.cgrCfg.DNSAgentCfg().ListenNet, Handler: handler}
}
return
}
@@ -88,7 +83,7 @@ func (da *DNSAgent) Reload() (err error) {
// handleMessage is the entry point of all DNS requests
// requests are reaching here asynchronously
func (da *DNSAgent) handleMessage(w dns.ResponseWriter, req *dns.Msg) {
dnsDP := newDNSDataProvider(req, w)
dnsDP := newDnsDP(req)
reqVars := &utils.DataNode{
Type: utils.NMMapType,
Map: map[string]*utils.DataNode{
@@ -99,20 +94,8 @@ func (da *DNSAgent) handleMessage(w dns.ResponseWriter, req *dns.Msg) {
rply := new(dns.Msg)
rply.SetReply(req)
// message preprocesing
switch req.Question[0].Qtype {
case dns.TypeNAPTR:
if req.Question[0].Qtype == dns.TypeNAPTR {
reqVars.Map[QueryName] = utils.NewLeafNode(req.Question[0].Name)
e164, err := e164FromNAPTR(req.Question[0].Name)
if err != nil {
utils.Logger.Warning(
fmt.Sprintf("<%s> decoding NAPTR query: <%s>, err: %s",
utils.DNSAgent, req.Question[0].Name, err.Error()))
rply.Rcode = dns.RcodeServerFailure
dnsWriteMsg(w, rply)
return
}
reqVars.Map[E164Address] = utils.NewLeafNode(e164)
reqVars.Map[DomainName] = utils.NewLeafNode(domainNameFromNAPTR(req.Question[0].Name))
}
cgrRplyNM := &utils.DataNode{Type: utils.NMMapType, Map: make(map[string]*utils.DataNode)}
rplyNM := utils.NewOrderedNavigableMap() // share it among different processors
@@ -121,7 +104,7 @@ func (da *DNSAgent) handleMessage(w dns.ResponseWriter, req *dns.Msg) {
var err error
for _, reqProcessor := range da.cgrCfg.DNSAgentCfg().RequestProcessors {
var lclProcessed bool
lclProcessed, err = da.processRequest(
lclProcessed, err = processRequest(
reqProcessor,
NewAgentRequest(
dnsDP, reqVars, cgrRplyNM, rplyNM,
@@ -129,7 +112,10 @@ func (da *DNSAgent) handleMessage(w dns.ResponseWriter, req *dns.Msg) {
da.cgrCfg.GeneralCfg().DefaultTenant,
utils.FirstNonEmpty(da.cgrCfg.DNSAgentCfg().Timezone,
da.cgrCfg.GeneralCfg().DefaultTimezone),
da.fltrS, nil))
da.fltrS, nil),
utils.DNSAgent, da.connMgr,
da.cgrCfg.DNSAgentCfg().SessionSConns,
nil, da.fltrS)
if lclProcessed {
processed = lclProcessed
}
@@ -169,186 +155,6 @@ func (da *DNSAgent) handleMessage(w dns.ResponseWriter, req *dns.Msg) {
}
}
func (da *DNSAgent) processRequest(reqProcessor *config.RequestProcessor,
agReq *AgentRequest) (processed bool, err error) {
if pass, err := da.fltrS.Pass(agReq.Tenant,
reqProcessor.Filters, agReq); err != nil || !pass {
return pass, err
}
if err = agReq.SetFields(reqProcessor.RequestFields); err != nil {
return
}
cgrEv := utils.NMAsCGREvent(agReq.CGRRequest, agReq.Tenant, utils.NestingSep, agReq.Opts)
var reqType string
for _, typ := range []string{
utils.MetaDryRun, utils.MetaAuthorize,
utils.MetaInitiate, utils.MetaUpdate,
utils.MetaTerminate, utils.MetaMessage,
utils.MetaCDRs, utils.MetaEvent, utils.MetaNone} {
if reqProcessor.Flags.Has(typ) { // request type is identified through flags
reqType = typ
break
}
}
var cgrArgs utils.Paginator
if reqType == utils.MetaAuthorize ||
reqType == utils.MetaMessage ||
reqType == utils.MetaEvent {
if cgrArgs, err = utils.GetRoutePaginatorFromOpts(cgrEv.APIOpts); err != nil {
utils.Logger.Warning(fmt.Sprintf("<%s> args extraction failed because <%s>",
utils.DNSAgent, err.Error()))
err = nil // reset the error and continue the processing
}
}
if reqProcessor.Flags.Has(utils.MetaLog) {
utils.Logger.Info(
fmt.Sprintf("<%s> LOG, processorID: <%s>, message: %s",
utils.DNSAgent, reqProcessor.ID, agReq.Request.String()))
}
switch reqType {
default:
return false, fmt.Errorf("unknown request type: <%s>", reqType)
case utils.MetaNone: // do nothing on CGRateS side
case utils.MetaDryRun:
utils.Logger.Info(
fmt.Sprintf("<%s> DRY_RUN, processorID: %s, CGREvent: %s",
utils.DNSAgent, reqProcessor.ID, utils.ToJSON(cgrEv)))
case utils.MetaAuthorize:
authArgs := sessions.NewV1AuthorizeArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaRoutes),
reqProcessor.Flags.Has(utils.MetaRoutesIgnoreErrors),
reqProcessor.Flags.Has(utils.MetaRoutesEventCost),
cgrEv, cgrArgs, reqProcessor.Flags.Has(utils.MetaFD),
reqProcessor.Flags.ParamValue(utils.MetaRoutesMaxCost),
)
rply := new(sessions.V1AuthorizeReply)
err = da.connMgr.Call(da.cgrCfg.DNSAgentCfg().SessionSConns, nil,
utils.SessionSv1AuthorizeEvent,
authArgs, rply)
rply.SetMaxUsageNeeded(authArgs.GetMaxUsage)
agReq.setCGRReply(rply, err)
case utils.MetaInitiate:
initArgs := sessions.NewV1InitSessionArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
rply := new(sessions.V1InitSessionReply)
err = da.connMgr.Call(da.cgrCfg.DNSAgentCfg().SessionSConns, nil,
utils.SessionSv1InitiateSession,
initArgs, rply)
rply.SetMaxUsageNeeded(initArgs.InitSession)
agReq.setCGRReply(rply, err)
case utils.MetaUpdate:
updateArgs := sessions.NewV1UpdateSessionArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.Has(utils.MetaAccounts),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
rply := new(sessions.V1UpdateSessionReply)
err = da.connMgr.Call(da.cgrCfg.DNSAgentCfg().SessionSConns, nil,
utils.SessionSv1UpdateSession,
updateArgs, rply)
rply.SetMaxUsageNeeded(updateArgs.UpdateSession)
agReq.setCGRReply(rply, err)
case utils.MetaTerminate:
terminateArgs := sessions.NewV1TerminateSessionArgs(
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
var rply string
err = da.connMgr.Call(da.cgrCfg.DNSAgentCfg().SessionSConns, nil,
utils.SessionSv1TerminateSession,
terminateArgs, &rply)
agReq.setCGRReply(nil, err)
case utils.MetaMessage:
evArgs := sessions.NewV1ProcessMessageArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaRoutes),
reqProcessor.Flags.Has(utils.MetaRoutesIgnoreErrors),
reqProcessor.Flags.Has(utils.MetaRoutesEventCost),
cgrEv, cgrArgs, reqProcessor.Flags.Has(utils.MetaFD),
reqProcessor.Flags.ParamValue(utils.MetaRoutesMaxCost),
)
rply := new(sessions.V1ProcessMessageReply) // need it so rpcclient can clone
err = da.connMgr.Call(da.cgrCfg.DNSAgentCfg().SessionSConns, nil,
utils.SessionSv1ProcessMessage,
evArgs, rply)
if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
cgrEv.Event[utils.Usage] = 0 // avoid further debits
} else if evArgs.Debit {
cgrEv.Event[utils.Usage] = rply.MaxUsage // make sure the CDR reflects the debit
}
rply.SetMaxUsageNeeded(evArgs.Debit)
agReq.setCGRReply(rply, err)
case utils.MetaEvent:
evArgs := &sessions.V1ProcessEventArgs{
Flags: reqProcessor.Flags.SliceFlags(),
CGREvent: cgrEv,
Paginator: cgrArgs,
}
rply := new(sessions.V1ProcessEventReply)
err = da.connMgr.Call(da.cgrCfg.DNSAgentCfg().SessionSConns, nil,
utils.SessionSv1ProcessEvent,
evArgs, rply)
if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
cgrEv.Event[utils.Usage] = 0 // avoid further debits
} else if needsMaxUsage(reqProcessor.Flags[utils.MetaRALs]) {
cgrEv.Event[utils.Usage] = rply.MaxUsage // make sure the CDR reflects the debit
}
agReq.setCGRReply(rply, err)
case utils.MetaCDRs: // allow CDR processing
}
// separate request so we can capture the Terminate/Event also here
if reqProcessor.Flags.GetBool(utils.MetaCDRs) &&
!reqProcessor.Flags.Has(utils.MetaDryRun) {
var rplyCDRs string
if err = da.connMgr.Call(da.cgrCfg.DNSAgentCfg().SessionSConns, nil,
utils.SessionSv1ProcessCDR,
cgrEv, &rplyCDRs); err != nil {
agReq.CGRReply.Map[utils.Error] = utils.NewLeafNode(err.Error())
}
}
if err := agReq.SetFields(reqProcessor.ReplyFields); err != nil {
return false, err
}
if reqProcessor.Flags.Has(utils.MetaLog) {
utils.Logger.Info(
fmt.Sprintf("<%s> LOG, reply: %s",
utils.DNSAgent, agReq.Reply))
}
if reqType == utils.MetaDryRun {
utils.Logger.Info(
fmt.Sprintf("<%s> DRY_RUN, reply: %s",
utils.DNSAgent, agReq.Reply))
}
return true, nil
}
// Shutdown stops the DNS server
func (da *DNSAgent) Shutdown() error {
return da.server.Shutdown()

View File

@@ -24,7 +24,6 @@ import (
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/sessions"
"github.com/cgrates/cgrates/utils"
)
@@ -73,7 +72,9 @@ func (ha *HTTPAgent) ServeHTTP(w http.ResponseWriter, req *http.Request) {
utils.FirstNonEmpty(reqProcessor.Timezone,
config.CgrConfig().GeneralCfg().DefaultTimezone),
ha.filterS, nil)
lclProcessed, err := ha.processRequest(reqProcessor, agReq)
lclProcessed, err := processRequest(reqProcessor, agReq,
utils.HTTPAgent, ha.connMgr, ha.sessionConns,
nil, agReq.filterS)
if err != nil {
utils.Logger.Warning(
fmt.Sprintf("<%s> error: %s processing request: %s",
@@ -101,177 +102,3 @@ func (ha *HTTPAgent) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
}
// processRequest represents one processor processing the request
func (ha *HTTPAgent) processRequest(reqProcessor *config.RequestProcessor,
agReq *AgentRequest) (processed bool, err error) {
if pass, err := ha.filterS.Pass(agReq.Tenant,
reqProcessor.Filters, agReq); err != nil || !pass {
return pass, err
}
if err = agReq.SetFields(reqProcessor.RequestFields); err != nil {
return
}
cgrEv := utils.NMAsCGREvent(agReq.CGRRequest, agReq.Tenant, utils.NestingSep, agReq.Opts)
var reqType string
for _, typ := range []string{
utils.MetaDryRun, utils.MetaAuthorize,
utils.MetaInitiate, utils.MetaUpdate,
utils.MetaTerminate, utils.MetaMessage,
utils.MetaCDRs, utils.MetaEvent, utils.MetaEmpty} {
if reqProcessor.Flags.Has(typ) { // request type is identified through flags
reqType = typ
break
}
}
var cgrArgs utils.Paginator
if reqType == utils.MetaAuthorize ||
reqType == utils.MetaMessage ||
reqType == utils.MetaEvent {
if cgrArgs, err = utils.GetRoutePaginatorFromOpts(cgrEv.APIOpts); err != nil {
utils.Logger.Warning(fmt.Sprintf("<%s> args extraction failed because <%s>",
utils.HTTPAgent, err.Error()))
err = nil // reset the error and continue the processing
}
}
if reqProcessor.Flags.Has(utils.MetaLog) {
utils.Logger.Info(
fmt.Sprintf("<%s> LOG, processorID: %s, http message: %s",
utils.HTTPAgent, reqProcessor.ID, agReq.Request.String()))
}
switch reqType {
default:
return false, fmt.Errorf("unknown request type: <%s>", reqType)
case utils.MetaNone: // do nothing on CGRateS side
case utils.MetaDryRun:
utils.Logger.Info(
fmt.Sprintf("<%s> DRY_RUN, processorID: %s, CGREvent: %s",
utils.HTTPAgent, reqProcessor.ID, utils.ToJSON(cgrEv)))
case utils.MetaAuthorize:
authArgs := sessions.NewV1AuthorizeArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaRoutes),
reqProcessor.Flags.Has(utils.MetaRoutesIgnoreErrors),
reqProcessor.Flags.Has(utils.MetaRoutesEventCost),
cgrEv, cgrArgs, reqProcessor.Flags.Has(utils.MetaFD),
reqProcessor.Flags.ParamValue(utils.MetaRoutesMaxCost),
)
rply := new(sessions.V1AuthorizeReply)
err = ha.connMgr.Call(ha.sessionConns, nil, utils.SessionSv1AuthorizeEvent,
authArgs, rply)
rply.SetMaxUsageNeeded(authArgs.GetMaxUsage)
agReq.setCGRReply(rply, err)
case utils.MetaInitiate:
initArgs := sessions.NewV1InitSessionArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
rply := new(sessions.V1InitSessionReply)
err = ha.connMgr.Call(ha.sessionConns, nil, utils.SessionSv1InitiateSession,
initArgs, rply)
rply.SetMaxUsageNeeded(initArgs.InitSession)
agReq.setCGRReply(rply, err)
case utils.MetaUpdate:
updateArgs := sessions.NewV1UpdateSessionArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.Has(utils.MetaAccounts),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
rply := new(sessions.V1UpdateSessionReply)
err = ha.connMgr.Call(ha.sessionConns, nil, utils.SessionSv1UpdateSession,
updateArgs, rply)
rply.SetMaxUsageNeeded(updateArgs.UpdateSession)
agReq.setCGRReply(rply, err)
case utils.MetaTerminate:
terminateArgs := sessions.NewV1TerminateSessionArgs(
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
var rply string
err = ha.connMgr.Call(ha.sessionConns, nil, utils.SessionSv1TerminateSession,
terminateArgs, &rply)
agReq.setCGRReply(nil, err)
case utils.MetaMessage:
evArgs := sessions.NewV1ProcessMessageArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaRoutes),
reqProcessor.Flags.Has(utils.MetaRoutesIgnoreErrors),
reqProcessor.Flags.Has(utils.MetaRoutesEventCost),
cgrEv, cgrArgs, reqProcessor.Flags.Has(utils.MetaFD),
reqProcessor.Flags.ParamValue(utils.MetaRoutesMaxCost),
)
rply := new(sessions.V1ProcessMessageReply)
err = ha.connMgr.Call(ha.sessionConns, nil, utils.SessionSv1ProcessMessage,
evArgs, rply)
if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
cgrEv.Event[utils.Usage] = 0 // avoid further debits
} else if evArgs.Debit {
cgrEv.Event[utils.Usage] = rply.MaxUsage // make sure the CDR reflects the debit
}
rply.SetMaxUsageNeeded(evArgs.Debit)
agReq.setCGRReply(nil, err)
case utils.MetaEvent:
evArgs := &sessions.V1ProcessEventArgs{
Flags: reqProcessor.Flags.SliceFlags(),
CGREvent: cgrEv,
Paginator: cgrArgs,
}
rply := new(sessions.V1ProcessEventReply)
err = ha.connMgr.Call(ha.sessionConns, nil, utils.SessionSv1ProcessEvent,
evArgs, rply)
if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
cgrEv.Event[utils.Usage] = 0 // avoid further debits
} else if needsMaxUsage(reqProcessor.Flags[utils.MetaRALs]) {
cgrEv.Event[utils.Usage] = rply.MaxUsage // make sure the CDR reflects the debit
}
agReq.setCGRReply(rply, err)
case utils.MetaCDRs: // allow CDR processing
}
// separate request so we can capture the Terminate/Event also here
if reqProcessor.Flags.GetBool(utils.MetaCDRs) &&
!reqProcessor.Flags.Has(utils.MetaDryRun) {
var rplyCDRs string
if err = ha.connMgr.Call(ha.sessionConns, nil, utils.SessionSv1ProcessCDR,
cgrEv, &rplyCDRs); err != nil {
agReq.CGRReply.Map[utils.Error] = utils.NewLeafNode(err.Error())
}
}
if err := agReq.SetFields(reqProcessor.ReplyFields); err != nil {
return false, err
}
if reqProcessor.Flags.Has(utils.MetaLog) {
utils.Logger.Info(
fmt.Sprintf("<%s> LOG, HTTP reply: %s",
utils.HTTPAgent, agReq.Reply))
}
if reqType == utils.MetaDryRun {
utils.Logger.Info(
fmt.Sprintf("<%s> DRY_RUN, HTTP reply: %s",
utils.HTTPAgent, agReq.Reply))
}
return true, nil
}

204
agents/libagents.go Normal file
View File

@@ -0,0 +1,204 @@
/*
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 agents
import (
"fmt"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/sessions"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/rpcclient"
)
func processRequest(reqProcessor *config.RequestProcessor, agReq *AgentRequest,
agentName string, connMgr *engine.ConnManager, sessionsConns []string,
aConn rpcclient.BiRPCConector, filterS *engine.FilterS) (processed bool, err error) {
if pass, err := filterS.Pass(agReq.Tenant,
reqProcessor.Filters, agReq); err != nil || !pass {
return pass, err
}
if err = agReq.SetFields(reqProcessor.RequestFields); err != nil {
return
}
cgrEv := utils.NMAsCGREvent(agReq.CGRRequest, agReq.Tenant, utils.NestingSep, agReq.Opts)
var reqType string
for _, typ := range []string{
utils.MetaDryRun, utils.MetaAuthorize,
utils.MetaInitiate, utils.MetaUpdate,
utils.MetaTerminate, utils.MetaMessage,
utils.MetaCDRs, utils.MetaEvent, utils.MetaNone} {
if reqProcessor.Flags.Has(typ) { // request type is identified through flags
reqType = typ
break
}
}
var cgrArgs utils.Paginator
if reqType == utils.MetaAuthorize || reqType == utils.MetaMessage || reqType == utils.MetaEvent {
if cgrArgs, err = utils.GetRoutePaginatorFromOpts(cgrEv.APIOpts); err != nil {
utils.Logger.Warning(fmt.Sprintf("<%s> args extraction failed because <%s>",
agentName, err.Error()))
err = nil // reset the error and continue the processing
}
}
if reqProcessor.Flags.Has(utils.MetaLog) {
utils.Logger.Info(
fmt.Sprintf("<%s> LOG, processorID: %s, diameter message: %s",
agentName, reqProcessor.ID, agReq.Request.String()))
}
switch reqType {
default:
return false, fmt.Errorf("unknown request type: <%s>", reqType)
case utils.MetaNone: // do nothing on CGRateS side
case utils.MetaDryRun:
utils.Logger.Info(
fmt.Sprintf("<%s> DRY_RUN, processorID: %s, DiameterMessage: %s",
agentName, reqProcessor.ID, agReq.Request.String()))
case utils.MetaAuthorize:
authArgs := sessions.NewV1AuthorizeArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaRoutes),
reqProcessor.Flags.Has(utils.MetaRoutesIgnoreErrors),
reqProcessor.Flags.Has(utils.MetaRoutesEventCost),
cgrEv, cgrArgs,
reqProcessor.Flags.Has(utils.MetaFD),
reqProcessor.Flags.ParamValue(utils.MetaRoutesMaxCost),
)
rply := new(sessions.V1AuthorizeReply)
err = connMgr.Call(sessionsConns, aConn, utils.SessionSv1AuthorizeEvent,
authArgs, rply)
rply.SetMaxUsageNeeded(authArgs.GetMaxUsage)
agReq.setCGRReply(rply, err)
case utils.MetaInitiate:
initArgs := sessions.NewV1InitSessionArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
rply := new(sessions.V1InitSessionReply)
err = connMgr.Call(sessionsConns, aConn, utils.SessionSv1InitiateSession,
initArgs, rply)
rply.SetMaxUsageNeeded(initArgs.InitSession)
agReq.setCGRReply(rply, err)
case utils.MetaUpdate:
updateArgs := sessions.NewV1UpdateSessionArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.Has(utils.MetaAccounts),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
rply := new(sessions.V1UpdateSessionReply)
rply.SetMaxUsageNeeded(updateArgs.UpdateSession)
err = connMgr.Call(sessionsConns, aConn, utils.SessionSv1UpdateSession,
updateArgs, rply)
agReq.setCGRReply(rply, err)
case utils.MetaTerminate:
terminateArgs := sessions.NewV1TerminateSessionArgs(
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
cgrEv, reqProcessor.Flags.Has(utils.MetaFD))
var rply string
err = connMgr.Call(sessionsConns, aConn, utils.SessionSv1TerminateSession,
terminateArgs, &rply)
agReq.setCGRReply(nil, err)
case utils.MetaMessage:
msgArgs := sessions.NewV1ProcessMessageArgs(
reqProcessor.Flags.GetBool(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats, utils.MetaIDs),
reqProcessor.Flags.GetBool(utils.MetaResources),
reqProcessor.Flags.Has(utils.MetaAccounts),
reqProcessor.Flags.GetBool(utils.MetaRoutes),
reqProcessor.Flags.Has(utils.MetaRoutesIgnoreErrors),
reqProcessor.Flags.Has(utils.MetaRoutesEventCost),
cgrEv, cgrArgs,
reqProcessor.Flags.Has(utils.MetaFD),
reqProcessor.Flags.ParamValue(utils.MetaRoutesMaxCost),
)
rply := new(sessions.V1ProcessMessageReply)
err = connMgr.Call(sessionsConns, aConn, utils.SessionSv1ProcessMessage,
msgArgs, rply)
if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
cgrEv.Event[utils.Usage] = 0 // avoid further debits
} else if msgArgs.Debit {
cgrEv.Event[utils.Usage] = rply.MaxUsage // make sure the CDR reflects the debit
}
rply.SetMaxUsageNeeded(msgArgs.Debit)
agReq.setCGRReply(rply, err)
case utils.MetaEvent:
evArgs := &sessions.V1ProcessEventArgs{
Flags: reqProcessor.Flags.SliceFlags(),
Paginator: cgrArgs,
CGREvent: cgrEv,
}
rply := new(sessions.V1ProcessEventReply)
err = connMgr.Call(sessionsConns, aConn, utils.SessionSv1ProcessEvent,
evArgs, rply)
if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
cgrEv.Event[utils.Usage] = 0 // avoid further debits
} else if needsMaxUsage(reqProcessor.Flags[utils.MetaRALs]) {
cgrEv.Event[utils.Usage] = rply.MaxUsage // make sure the CDR reflects the debit
}
agReq.setCGRReply(rply, err)
case utils.MetaCDRs: // allow CDR processing
}
// separate request so we can capture the Terminate/Event also here
if reqProcessor.Flags.GetBool(utils.MetaCDRs) &&
!reqProcessor.Flags.Has(utils.MetaDryRun) {
var rplyCDRs string
if err = connMgr.Call(sessionsConns, aConn, utils.SessionSv1ProcessCDR,
cgrEv, &rplyCDRs); err != nil {
agReq.CGRReply.Map[utils.Error] = utils.NewLeafNode(err.Error())
}
}
if err = agReq.SetFields(reqProcessor.ReplyFields); err != nil {
return
}
if reqProcessor.Flags.Has(utils.MetaLog) {
utils.Logger.Info(
fmt.Sprintf("<%s> LOG, Diameter reply: %s",
agentName, agReq.Reply))
}
if reqType == utils.MetaDryRun {
utils.Logger.Info(
fmt.Sprintf("<%s> DRY_RUN, Diameter reply: %s",
agentName, agReq.Reply))
}
return true, nil
}

View File

@@ -19,93 +19,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package agents
import (
"errors"
"fmt"
"net"
"strconv"
"strings"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
"github.com/miekg/dns"
)
const (
QueryType = "QueryType"
E164Address = "E164Address"
QueryName = "QueryName"
DomainName = "DomainName"
QueryType = "QueryType"
QueryName = "QueryName"
dnsOption = "Option"
)
// e164FromNAPTR extracts the E164 address out of a NAPTR name record
func e164FromNAPTR(name string) (e164 string, err error) {
i := strings.Index(name, ".e164.")
if i == -1 {
return "", errors.New("unknown format")
}
e164 = utils.ReverseString(
strings.Replace(name[:i], ".", "", -1))
return
}
// domainNameFromNAPTR extracts the domain part out of a NAPTR name record
func domainNameFromNAPTR(name string) (dName string) {
i := strings.Index(name, ".e164.")
if i == -1 {
dName = name
} else {
dName = name[i:]
}
return strings.Trim(dName, ".")
}
// newDADataProvider constructs a DataProvider for a diameter message
func newDNSDataProvider(req *dns.Msg,
w dns.ResponseWriter) utils.DataProvider {
return &dnsDP{req: req, w: w,
cache: utils.MapStorage{}}
}
// dnsDP implements engien.DataProvider, serving as dns.Msg decoder
// cache is used to cache queries within the message
type dnsDP struct {
req *dns.Msg
w dns.ResponseWriter
cache utils.MapStorage
}
// String is part of utils.DataProvider interface
// when called, it will display the already parsed values out of cache
func (dP *dnsDP) String() string {
return utils.ToJSON(dP.req)
}
// FieldAsString is part of utils.DataProvider interface
func (dP *dnsDP) FieldAsString(fldPath []string) (data string, err error) {
var valIface interface{}
valIface, err = dP.FieldAsInterface(fldPath)
if err != nil {
return
}
return utils.IfaceAsString(valIface), nil
}
// FieldAsInterface is part of utils.DataProvider interface
func (dP *dnsDP) FieldAsInterface(fldPath []string) (data interface{}, err error) {
if data, err = dP.cache.FieldAsInterface(fldPath); err != nil {
if err != utils.ErrNotFound { // item found in cache
return nil, err
}
err = nil // cancel previous err
} else {
return // data was found in cache
}
data = ""
// Return Question[0] by default
if len(dP.req.Question) != 0 {
data = dP.req.Question[0]
}
dP.cache.Set(fldPath, data)
return
}
// dnsWriteErr writes the error with code back to the client
func dnsWriteMsg(w dns.ResponseWriter, msg *dns.Msg) (err error) {
if err = w.WriteMsg(msg); err != nil {
@@ -145,73 +74,643 @@ func appendDNSAnswer(msg *dns.Msg) (err error) {
return
}
// updateDNSMsgFromNM will update DNS message with values from NavigableMap
func newDnsDP(req *dns.Msg) utils.DataProvider {
var opts interface{}
if o := req.IsEdns0(); o != nil {
opts = o
}
return &dnsDP{
req: config.NewObjectDP(req),
opts: config.NewObjectDP(opts),
}
}
type dnsDP struct {
req utils.DataProvider
opts utils.DataProvider
}
func (dp dnsDP) String() string { return dp.req.String() }
func (dp dnsDP) FieldAsInterface(fldPath []string) (interface{}, error) {
if len(fldPath) != 0 && fldPath[0] == dnsOption {
return dp.opts.FieldAsInterface(fldPath[1:])
}
return dp.req.FieldAsInterface(fldPath)
}
func (dp dnsDP) FieldAsString(fldPath []string) (string, error) {
valIface, err := dp.FieldAsInterface(fldPath)
if err != nil {
return "", err
}
return utils.IfaceAsString(valIface), nil
}
func updateDNSMsgFromNM(msg *dns.Msg, nm *utils.OrderedNavigableMap) (err error) {
msgFields := make(utils.StringSet) // work around to NMap issue
for el := nm.GetFirstElement(); el != nil; el = el.Next() {
path := el.Value
cfgItm, _ := nm.Field(path)
// path = path[:len(path)-1] // no need to remove the last index here as this uses only the first level
apnd := len(msg.Answer) == 0
if msgFields.Has(path[0]) { // force append if the same path was already used
apnd = true
}
if apnd {
if err = appendDNSAnswer(msg); err != nil {
return
itm, _ := nm.Field(path)
switch path[0] { // go for each posible field
case utils.Id:
var vItm int64
if vItm, err = utils.IfaceAsTInt64(itm.Data); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
}
msgFields = make(utils.StringSet) // reset the fields inside since we have a new message
}
itmData := cfgItm.Data
switch path[0] {
msg.Id = uint16(vItm)
case utils.Response:
var vItm bool
if vItm, err = utils.IfaceAsBool(itm.Data); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
}
msg.Response = vItm
case utils.Opcode:
var vItm int64
if vItm, err = utils.IfaceAsTInt64(itm.Data); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
}
msg.Opcode = int(vItm)
case utils.Authoritative:
var vItm bool
if vItm, err = utils.IfaceAsBool(itm.Data); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
}
msg.Authoritative = vItm
case utils.Truncated:
var vItm bool
if vItm, err = utils.IfaceAsBool(itm.Data); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
}
msg.Truncated = vItm
case utils.RecursionDesired:
var vItm bool
if vItm, err = utils.IfaceAsBool(itm.Data); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
}
msg.RecursionDesired = vItm
case utils.RecursionAvailable:
var vItm bool
if vItm, err = utils.IfaceAsBool(itm.Data); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
}
msg.RecursionAvailable = vItm
case utils.Zero:
var vItm bool
if vItm, err = utils.IfaceAsBool(itm.Data); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
}
msg.Zero = vItm
case utils.AuthenticatedData:
var vItm bool
if vItm, err = utils.IfaceAsBool(itm.Data); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
}
msg.AuthenticatedData = vItm
case utils.CheckingDisabled:
var vItm bool
if vItm, err = utils.IfaceAsBool(itm.Data); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
}
msg.CheckingDisabled = vItm
case utils.Rcode:
var itm int64
if itm, err = utils.IfaceAsInt64(itmData); err != nil {
var vItm int64
if vItm, err = utils.IfaceAsTInt64(itm.Data); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
}
msg.Rcode = int(itm)
case utils.Order:
if msg.Question[0].Qtype != dns.TypeNAPTR {
return fmt.Errorf("field <%s> only works with NAPTR", utils.Order)
msg.Rcode = int(vItm)
case utils.Question:
if msg.Question, err = updateDnsQuestions(msg.Question, path[1:len(path)-1], itm.Data, itm.NewBranch); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[:len(path)-1], err.Error())
}
var itm int64
if itm, err = utils.IfaceAsInt64(itmData); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
case utils.Answer:
newBranch := itm.NewBranch ||
len(msg.Answer) == 0 ||
msgFields.Has(path[0])
if newBranch { // force append if the same path was already used
msgFields = make(utils.StringSet) // reset the fields inside since we have a new message
msgFields.Add(strings.Join(path, ".")) // detect new branch
}
msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Order = uint16(itm)
case utils.Preference:
if msg.Question[0].Qtype != dns.TypeNAPTR {
return fmt.Errorf("field <%s> only works with NAPTR", utils.Preference)
if msg.Answer, err = updateDnsAnswer(msg.Answer, msg.Question[0].Qtype, msg.Question[0].Name, path[1:len(path)-1], itm.Data, newBranch); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[:len(path)-1], err.Error())
}
var itm int64
if itm, err = utils.IfaceAsInt64(itmData); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[0], err.Error())
case utils.Ns: //ToDO
case utils.Extra: //ToDO
case dnsOption:
opts := msg.IsEdns0()
if opts == nil {
opts = msg.SetEdns0(4096, false).IsEdns0()
}
msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Preference = uint16(itm)
case utils.Flags:
if msg.Question[0].Qtype != dns.TypeNAPTR {
return fmt.Errorf("field <%s> only works with NAPTR", utils.Flags)
if opts.Option, err = updateDnsOption(opts.Option, path[1:len(path)-1], itm.Data, itm.NewBranch); err != nil {
return fmt.Errorf("item: <%s>, err: %s", path[:len(path)-1], err.Error())
}
msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Flags = utils.IfaceAsString(itmData)
case utils.Service:
if msg.Question[0].Qtype != dns.TypeNAPTR {
return fmt.Errorf("field <%s> only works with NAPTR", utils.Service)
}
msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Service = utils.IfaceAsString(itmData)
case utils.Regexp:
if msg.Question[0].Qtype != dns.TypeNAPTR {
return fmt.Errorf("field <%s> only works with NAPTR", utils.Regexp)
}
msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Regexp = utils.IfaceAsString(itmData)
case utils.Replacement:
if msg.Question[0].Qtype != dns.TypeNAPTR {
return fmt.Errorf("field <%s> only works with NAPTR", utils.Replacement)
}
msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Replacement = utils.IfaceAsString(itmData)
default:
}
msgFields.Add(path[0]) // detect new branch
}
return
}
// updateDnsQuestion
func updateDnsQuestions(q []dns.Question, path []string, value interface{}, newBranch bool) (_ []dns.Question, err error) {
var idx int
var field string
switch len(path) {
case 1: // only the field so update the last one
if newBranch || len(q) == 0 {
q = append(q, dns.Question{})
}
idx = len(q) - 1
field = path[0]
case 2: // the index is specified
if idx, err = strconv.Atoi(path[0]); err != nil {
return
}
if lq := len(q); idx > lq {
err = utils.ErrWrongPath
return
} else if lq == idx {
q = append(q, dns.Question{})
}
field = path[1]
default:
err = utils.ErrWrongPath
return
}
switch field {
case utils.Name:
q[idx].Name = utils.IfaceAsString(value)
case utils.Qtype:
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
q[idx].Qtype = uint16(vItm)
case utils.Qclass:
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
q[idx].Qclass = uint16(vItm)
default:
err = utils.ErrWrongPath
return
}
return q, nil
}
func updateDnsOption(q []dns.EDNS0, path []string, value interface{}, newBranch bool) (_ []dns.EDNS0, err error) {
var idx int
var field string
switch len(path) {
case 1: // only the field so update the last one
field = path[0]
if newBranch ||
len(q) == 0 {
var o dns.EDNS0
if o, err = createDnsOption(field, value); err != nil {
return
}
return append(q, o), nil
}
idx = len(q) - 1
case 2: // the index is specified
field = path[1]
if idx, err = strconv.Atoi(path[0]); err != nil {
return
}
if lq := len(q); idx > lq {
err = utils.ErrWrongPath
return
} else if lq == idx {
var o dns.EDNS0
if o, err = createDnsOption(field, value); err != nil {
return
}
return append(q, o), nil
}
default:
err = utils.ErrWrongPath
return
}
switch v := q[idx].(type) {
case *dns.EDNS0_NSID:
if field != "Nsid" {
err = utils.ErrWrongPath
return
}
v.Nsid = utils.IfaceAsString(value)
case *dns.EDNS0_SUBNET:
switch field {
case "Family":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Family = uint16(vItm)
case "SourceNetmask":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.SourceNetmask = uint8(vItm)
case "SourceScope":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.SourceScope = uint8(vItm)
case "Address":
v.Address = net.ParseIP(utils.IfaceAsString(value))
default:
err = utils.ErrWrongPath
return
}
case *dns.EDNS0_COOKIE:
if field != "Cookie" {
err = utils.ErrWrongPath
return
}
v.Cookie = utils.IfaceAsString(value)
case *dns.EDNS0_UL:
switch field {
case "Lease":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Lease = uint32(vItm)
case "KeyLease":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.KeyLease = uint32(vItm)
default:
err = utils.ErrWrongPath
return
}
case *dns.EDNS0_LLQ:
switch field {
case "Version":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Version = uint16(vItm)
case "Opcode":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Opcode = uint16(vItm)
case "Error":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Error = uint16(vItm)
case "Id":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Id = uint64(vItm)
case "LeaseLife":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.LeaseLife = uint32(vItm)
default:
err = utils.ErrWrongPath
return
}
case *dns.EDNS0_DAU:
if field != "DAU" {
err = utils.ErrWrongPath
return
}
v.AlgCode = []uint8(utils.IfaceAsString(value))
case *dns.EDNS0_DHU:
if field != "DHU" {
err = utils.ErrWrongPath
return
}
v.AlgCode = []uint8(utils.IfaceAsString(value))
case *dns.EDNS0_N3U:
if field != "N3U" {
err = utils.ErrWrongPath
return
}
v.AlgCode = []uint8(utils.IfaceAsString(value))
case *dns.EDNS0_EXPIRE:
if field != "Expire" {
err = utils.ErrWrongPath
return
}
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Expire = uint32(vItm)
case *dns.EDNS0_TCP_KEEPALIVE:
switch field {
case "Length": //
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Length = uint16(vItm)
case "Timeout": //
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Timeout = uint16(vItm)
default:
err = utils.ErrWrongPath
return
}
case *dns.EDNS0_PADDING:
if field != "Padding" {
err = utils.ErrWrongPath
return
}
v.Padding = []byte(utils.IfaceAsString(value))
case *dns.EDNS0_EDE:
switch field {
case "InfoCode":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.InfoCode = uint16(vItm)
case "ExtraText":
v.ExtraText = utils.IfaceAsString(value)
default:
err = utils.ErrWrongPath
return
}
case *dns.EDNS0_ESU:
if field != "Uri" {
err = utils.ErrWrongPath
return
}
v.Uri = utils.IfaceAsString(value)
case *dns.EDNS0_LOCAL: // if already there you can change data
if field != "Data" {
err = utils.ErrWrongPath
return
}
v.Data = []byte(utils.IfaceAsString(value))
case nil:
err = fmt.Errorf("unsuported dns option type <%T>", v)
default:
err = fmt.Errorf("unsuported dns option type <%T>", v)
}
return q, err
}
func createDnsOption(field string, value interface{}) (o dns.EDNS0, err error) {
switch field {
case "Nsid": // EDNS0_NSID
o = &dns.EDNS0_NSID{Nsid: utils.IfaceAsString(value)}
case "Family": // EDNS0_SUBNET
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_SUBNET{Family: uint16(vItm)}
case "SourceNetmask": // EDNS0_SUBNET
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_SUBNET{SourceNetmask: uint8(vItm)}
case "SourceScope": // EDNS0_SUBNET
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_SUBNET{SourceScope: uint8(vItm)}
case "Address": // EDNS0_SUBNET
o = &dns.EDNS0_SUBNET{Address: net.ParseIP(utils.IfaceAsString(value))}
case "Cookie": // EDNS0_COOKIE
o = &dns.EDNS0_COOKIE{Cookie: utils.IfaceAsString(value)}
case "Lease": // EDNS0_UL
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_UL{Lease: uint32(vItm)}
case "KeyLease": // EDNS0_UL
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_UL{KeyLease: uint32(vItm)}
case "Version": // EDNS0_LLQ
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_LLQ{Version: uint16(vItm)}
case "Opcode": // EDNS0_LLQ
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_LLQ{Opcode: uint16(vItm)}
case "Error": // EDNS0_LLQ
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_LLQ{Error: uint16(vItm)}
case "Id": // EDNS0_LLQ
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_LLQ{Id: uint64(vItm)}
case "LeaseLife": // EDNS0_LLQ
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_LLQ{LeaseLife: uint32(vItm)}
case "DAU": // EDNS0_DAU
o = &dns.EDNS0_DAU{AlgCode: []uint8(utils.IfaceAsString(value))}
case "DHU": // EDNS0_DHU
o = &dns.EDNS0_DHU{AlgCode: []uint8(utils.IfaceAsString(value))}
case "N3U": // EDNS0_N3U
o = &dns.EDNS0_N3U{AlgCode: []uint8(utils.IfaceAsString(value))}
case "Expire": // EDNS0_EXPIRE
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_EXPIRE{Expire: uint32(vItm)}
case "Length": // EDNS0_TCP_KEEPALIVE
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_TCP_KEEPALIVE{Length: uint16(vItm)}
case "Timeout": // EDNS0_TCP_KEEPALIVE
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_TCP_KEEPALIVE{Timeout: uint16(vItm)}
case "Padding": // EDNS0_PADDING
o = &dns.EDNS0_PADDING{Padding: []byte(utils.IfaceAsString(value))}
case "InfoCode": // EDNS0_EDE
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
o = &dns.EDNS0_EDE{InfoCode: uint16(vItm)}
case "ExtraText": // EDNS0_EDE
o = &dns.EDNS0_EDE{ExtraText: utils.IfaceAsString(value)}
case "Uri": // EDNS0_ESU
o = &dns.EDNS0_ESU{Uri: utils.IfaceAsString(value)}
default:
err = fmt.Errorf("can not create option from field <%q>", field)
}
return
}
func updateDnsAnswer(q []dns.RR, qType uint16, qName string, path []string, value interface{}, newBranch bool) (_ []dns.RR, err error) {
var idx int
switch len(path) {
case 1: // only the field so update the last one
if newBranch || len(q) == 0 {
var a dns.RR
if a, err = newDNSAnswer(qType, qName); err != nil {
return
}
q = append(q, a)
}
idx = len(q) - 1
case 2: // the index is specified
if idx, err = strconv.Atoi(path[0]); err != nil {
return
}
if lq := len(q); idx > lq {
err = utils.ErrWrongPath
return
} else if lq == idx {
var a dns.RR
if a, err = newDNSAnswer(qType, qName); err != nil {
return
}
q = append(q, a)
}
path = path[1:]
default:
err = utils.ErrWrongPath
return
}
switch v := q[idx].(type) {
case *dns.NAPTR:
err = updateDnsNAPTRAnswer(v, path, value)
case nil:
err = fmt.Errorf("unsuported dns option type <%T>", v)
default:
err = fmt.Errorf("unsuported dns option type <%T>", v)
}
return q, err
}
// appendDNSAnswer will append the right answer payload to the message
func newDNSAnswer(qType uint16, qName string) (a dns.RR, err error) {
hdr := dns.RR_Header{
Name: qName,
Rrtype: qType,
Class: dns.ClassINET,
Ttl: 60,
}
switch qType {
case dns.TypeA:
a = &dns.A{Hdr: hdr}
case dns.TypeNAPTR:
a = &dns.NAPTR{Hdr: hdr}
default:
err = fmt.Errorf("unsupported DNS type: <%v>", qType)
}
return
}
func updateDnsNAPTRAnswer(v *dns.NAPTR, path []string, value interface{}) (err error) {
if len(path) < 1 ||
(path[0] != "Hdr" && len(path) != 1) ||
(path[0] == "Hdr" && len(path) != 2) {
return utils.ErrWrongPath
}
switch path[0] {
case "Hdr":
return updateDnsRRHeader(&v.Hdr, path[1:], value)
case "Order":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Order = uint16(vItm)
case "Preference":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Preference = uint16(vItm)
case "Flags":
v.Flags = utils.IfaceAsString(value)
case "Service":
v.Service = utils.IfaceAsString(value)
case "Regexp":
v.Regexp = utils.IfaceAsString(value)
case "Replacement":
v.Replacement = utils.IfaceAsString(value)
default:
return utils.ErrWrongPath
}
return
}
func updateDnsRRHeader(v *dns.RR_Header, path []string, value interface{}) (err error) {
if len(path) != 1 {
return utils.ErrWrongPath
}
switch path[0] {
case "Name":
v.Name = utils.IfaceAsString(value)
case "Rrtype":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Rrtype = uint16(vItm)
case "Class":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Class = uint16(vItm)
case "Ttl":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Ttl = uint32(vItm)
case "Rdlength":
var vItm int64
if vItm, err = utils.IfaceAsTInt64(value); err != nil {
return
}
v.Rdlength = uint16(vItm)
default:
return utils.ErrWrongPath
}
return
}

View File

@@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package agents
import (
"reflect"
"strings"
"testing"
@@ -27,26 +26,6 @@ import (
"github.com/miekg/dns"
)
func TestE164FromNAPTR(t *testing.T) {
if e164, err := e164FromNAPTR("8.7.6.5.4.3.2.1.0.1.6.e164.arpa."); err != nil {
t.Error(err)
} else if e164 != "61012345678" {
t.Errorf("received: <%s>", e164)
}
}
func TestDomainNameFromNAPTR(t *testing.T) {
if dName := domainNameFromNAPTR("8.7.6.5.4.3.2.1.0.1.6.e164.arpa."); dName != "e164.arpa" {
t.Errorf("received: <%s>", dName)
}
if dName := domainNameFromNAPTR("8.7.6.5.4.3.2.1.0.1.6.e164.itsyscom.com."); dName != "e164.itsyscom.com" {
t.Errorf("received: <%s>", dName)
}
if dName := domainNameFromNAPTR("8.7.6.5.4.3.2.1.0.1.6.itsyscom.com."); dName != "8.7.6.5.4.3.2.1.0.1.6.itsyscom.com" {
t.Errorf("received: <%s>", dName)
}
}
func TestAppendDNSAnswerTypeNAPTR(t *testing.T) {
m := new(dns.Msg)
m.SetQuestion("3.6.9.4.7.1.7.1.5.6.8.9.4.e164.arpa.", dns.TypeNAPTR)
@@ -93,84 +72,6 @@ func TestAppendDNSAnswerUnexpectedType(t *testing.T) {
}
}
func TestDNSDPFieldAsInterface(t *testing.T) {
m := new(dns.Msg)
m.SetQuestion("3.6.9.4.7.1.7.1.5.6.8.9.4.e164.arpa.", dns.TypeNAPTR)
dp := newDNSDataProvider(m, nil)
expected := m.Question[0]
if data, err := dp.FieldAsInterface([]string{"test"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(data, expected) {
t.Errorf("expecting: <%+v>, received: <%+v>", expected, data)
}
}
func TestDNSDPFieldAsInterfaceEmptyPath(t *testing.T) {
m := new(dns.Msg)
m.SetQuestion("3.6.9.4.7.1.7.1.5.6.8.9.4.e164.arpa.", dns.TypeNAPTR)
dp := newDNSDataProvider(m, nil)
if _, err := dp.FieldAsInterface([]string{}); err == nil ||
err.Error() != "empty field path" {
t.Error(err)
}
}
func TestDNSDPFieldAsInterfaceFromCache(t *testing.T) {
m := new(dns.Msg)
m.SetQuestion("3.6.9.4.7.1.7.1.5.6.8.9.4.e164.arpa.", dns.TypeNAPTR)
dp := newDNSDataProvider(m, nil)
expected := m.Question[0]
if data, err := dp.FieldAsInterface([]string{"test"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(data, expected) {
t.Errorf("expecting: <%+v>, received: <%+v>", expected, data)
}
if data, err := dp.FieldAsInterface([]string{"test"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(data, expected) {
t.Errorf("expecting: <%+v>, received: <%+v>", expected, data)
}
}
func TestDNSDPFieldAsString(t *testing.T) {
m := new(dns.Msg)
m.SetQuestion("3.6.9.4.7.1.7.1.5.6.8.9.4.e164.arpa.", dns.TypeNAPTR)
dp := newDNSDataProvider(m, nil)
expected := utils.ToJSON(m.Question[0])
if data, err := dp.FieldAsString([]string{"test"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(data, expected) {
t.Errorf("expecting: <%+v>, received: <%+v>", expected, data)
}
}
func TestDNSDPFieldAsStringEmptyPath(t *testing.T) {
m := new(dns.Msg)
m.SetQuestion("3.6.9.4.7.1.7.1.5.6.8.9.4.e164.arpa.", dns.TypeNAPTR)
dp := newDNSDataProvider(m, nil)
if _, err := dp.FieldAsString([]string{}); err == nil ||
err.Error() != "empty field path" {
t.Error(err)
}
}
func TestDNSDPFieldAsStringFromCache(t *testing.T) {
m := new(dns.Msg)
m.SetQuestion("3.6.9.4.7.1.7.1.5.6.8.9.4.e164.arpa.", dns.TypeNAPTR)
dp := newDNSDataProvider(m, nil)
expected := utils.ToJSON(m.Question[0])
if data, err := dp.FieldAsString([]string{"test"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(data, expected) {
t.Errorf("expecting: <%+v>, received: <%+v>", expected, data)
}
if data, err := dp.FieldAsString([]string{"test"}); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(data, expected) {
t.Errorf("expecting: <%+v>, received: <%+v>", expected, data)
}
}
func TestUpdateDNSMsgFromNM(t *testing.T) {
m := new(dns.Msg)
m.SetQuestion("3.6.9.4.7.1.7.1.5.6.8.9.4.e164.arpa.", dns.TypeNAPTR)
@@ -206,7 +107,7 @@ func TestUpdateDNSMsgFromNM(t *testing.T) {
}
nM = utils.NewOrderedNavigableMap()
path = []string{utils.Order}
path = []string{utils.Answer, utils.Order}
itm = &utils.DataNode{Type: utils.NMDataType, Value: &utils.DataLeaf{
Data: "RandomValue",
}}
@@ -215,12 +116,12 @@ func TestUpdateDNSMsgFromNM(t *testing.T) {
PathSlice: path,
}, []*utils.DataNode{itm})
if err := updateDNSMsgFromNM(m, nM); err == nil ||
err.Error() != `item: <Order>, err: strconv.ParseInt: parsing "RandomValue": invalid syntax` {
err.Error() != `item: <[Answer Order]>, err: strconv.ParseInt: parsing "RandomValue": invalid syntax` {
t.Error(err)
}
nM = utils.NewOrderedNavigableMap()
path = []string{utils.Preference}
path = []string{utils.Answer, utils.Preference}
itm = &utils.DataNode{Type: utils.NMDataType, Value: &utils.DataLeaf{
Data: "RandomValue",
}}
@@ -229,14 +130,14 @@ func TestUpdateDNSMsgFromNM(t *testing.T) {
PathSlice: path,
}, []*utils.DataNode{itm})
if err := updateDNSMsgFromNM(m, nM); err == nil ||
err.Error() != `item: <Preference>, err: strconv.ParseInt: parsing "RandomValue": invalid syntax` {
err.Error() != `item: <[Answer Preference]>, err: strconv.ParseInt: parsing "RandomValue": invalid syntax` {
t.Error(err)
}
m = new(dns.Msg)
m.SetQuestion("3.6.9.4.7.1.7.1.5.6.8.9.4.e164.arpa.", dns.TypeA)
nM = utils.NewOrderedNavigableMap()
path = []string{utils.Order}
path = []string{utils.Answer, utils.Order}
itm = &utils.DataNode{Type: utils.NMDataType, Value: &utils.DataLeaf{
Data: 10,
}}
@@ -245,12 +146,12 @@ func TestUpdateDNSMsgFromNM(t *testing.T) {
PathSlice: path,
}, []*utils.DataNode{itm})
if err := updateDNSMsgFromNM(m, nM); err == nil ||
err.Error() != `field <Order> only works with NAPTR` {
err.Error() != `item: <[Answer Order]>, err: unsuported dns option type <*dns.A>` {
t.Error(err)
}
nM = utils.NewOrderedNavigableMap()
path = []string{utils.Preference}
path = []string{utils.Answer, utils.Preference}
itm = &utils.DataNode{Type: utils.NMDataType, Value: &utils.DataLeaf{
Data: 10,
}}
@@ -259,12 +160,12 @@ func TestUpdateDNSMsgFromNM(t *testing.T) {
PathSlice: path,
}, []*utils.DataNode{itm})
if err := updateDNSMsgFromNM(m, nM); err == nil ||
err.Error() != `field <Preference> only works with NAPTR` {
err.Error() != `item: <[Answer Preference]>, err: unsuported dns option type <*dns.A>` {
t.Error(err)
}
nM = utils.NewOrderedNavigableMap()
path = []string{utils.Flags}
path = []string{utils.Answer, utils.Flags}
itm = &utils.DataNode{Type: utils.NMDataType, Value: &utils.DataLeaf{
Data: 10,
}}
@@ -273,12 +174,12 @@ func TestUpdateDNSMsgFromNM(t *testing.T) {
PathSlice: path,
}, []*utils.DataNode{itm})
if err := updateDNSMsgFromNM(m, nM); err == nil ||
err.Error() != `field <Flags> only works with NAPTR` {
err.Error() != `item: <[Answer Flags]>, err: unsuported dns option type <*dns.A>` {
t.Error(err)
}
nM = utils.NewOrderedNavigableMap()
path = []string{utils.Service}
path = []string{utils.Answer, utils.Service}
itm = &utils.DataNode{Type: utils.NMDataType, Value: &utils.DataLeaf{
Data: 10,
}}
@@ -287,12 +188,12 @@ func TestUpdateDNSMsgFromNM(t *testing.T) {
PathSlice: path,
}, []*utils.DataNode{itm})
if err := updateDNSMsgFromNM(m, nM); err == nil ||
err.Error() != `field <Service> only works with NAPTR` {
err.Error() != `item: <[Answer Service]>, err: unsuported dns option type <*dns.A>` {
t.Error(err)
}
nM = utils.NewOrderedNavigableMap()
path = []string{utils.Regexp}
path = []string{utils.Answer, utils.Regexp}
itm = &utils.DataNode{Type: utils.NMDataType, Value: &utils.DataLeaf{
Data: 10,
}}
@@ -301,12 +202,12 @@ func TestUpdateDNSMsgFromNM(t *testing.T) {
PathSlice: path,
}, []*utils.DataNode{itm})
if err := updateDNSMsgFromNM(m, nM); err == nil ||
err.Error() != `field <Regexp> only works with NAPTR` {
err.Error() != `item: <[Answer Regexp]>, err: unsuported dns option type <*dns.A>` {
t.Error(err)
}
nM = utils.NewOrderedNavigableMap()
path = []string{utils.Replacement}
path = []string{utils.Answer, utils.Replacement}
itm = &utils.DataNode{Type: utils.NMDataType, Value: &utils.DataLeaf{
Data: 10,
}}
@@ -315,7 +216,7 @@ func TestUpdateDNSMsgFromNM(t *testing.T) {
PathSlice: path,
}, []*utils.DataNode{itm})
if err := updateDNSMsgFromNM(m, nM); err == nil ||
err.Error() != `field <Replacement> only works with NAPTR` {
err.Error() != `item: <[Answer Replacement]>, err: unsuported dns option type <*dns.A>` {
t.Error(err)
}

View File

@@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package agents
import (
"bytes"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/radigo"
)
@@ -112,9 +114,7 @@ func radauthReq(flags utils.FlagsWithParams, req *radigo.Packet, aReq *AgentRequ
if len(userPassAvps) == 0 {
return false, utils.NewErrMandatoryIeMissing(UserPasswordAVP)
}
if userPassAvps[0].StringValue != pass {
return false, nil
}
return userPassAvps[0].StringValue == pass, nil
case flags.Has(utils.MetaCHAP):
chapAVPs := req.AttributesWithName(CHAPPasswordAVP, utils.EmptyString)
if len(chapAVPs) == 0 {
@@ -131,34 +131,25 @@ func radauthReq(flags utils.FlagsWithParams, req *radigo.Packet, aReq *AgentRequ
if len(msResponse) == 0 {
return false, utils.NewErrMandatoryIeMissing(MSCHAPResponseAVP)
}
vsaMSResponde := msResponse[0].Value.(*radigo.VSA)
vsaMSChallange := msChallenge[0].Value.(*radigo.VSA)
vsaMSResponde := msResponse[0].Value.(*radigo.VSA).RawValue
vsaMSChallange := msChallenge[0].Value.(*radigo.VSA).RawValue
userName := req.AttributesWithName("User-Name", utils.EmptyString)[0].StringValue
passwordFromAttributes := pass
if len(vsaMSChallange.RawValue) != 16 || len(vsaMSResponde.RawValue) != 50 {
if len(vsaMSChallange) != 16 || len(vsaMSResponde) != 50 {
return false, nil
}
ident := vsaMSResponde.RawValue[0]
peerChallenge := vsaMSResponde.RawValue[2:18]
peerResponse := vsaMSResponde.RawValue[26:50]
ntResponse, err := radigo.GenerateNTResponse(vsaMSChallange.RawValue,
peerChallenge, userName, passwordFromAttributes)
if err != nil {
ident := vsaMSResponde[0]
peerChallenge := vsaMSResponde[2:18]
peerResponse := vsaMSResponde[26:50]
ntResponse, err := radigo.GenerateNTResponse(vsaMSChallange,
peerChallenge, userName, pass)
if err != nil || !bytes.Equal(ntResponse, peerResponse) {
return false, err
}
if len(ntResponse) != len(peerResponse) {
return false, nil
}
for i := range ntResponse {
if ntResponse[i] != peerResponse[i] {
return false, nil
}
}
authenticatorResponse, err := radigo.GenerateAuthenticatorResponse(vsaMSChallange.RawValue, peerChallenge,
ntResponse, userName, passwordFromAttributes)
authenticatorResponse, err := radigo.GenerateAuthenticatorResponse(vsaMSChallange, peerChallenge,
ntResponse, userName, pass)
if err != nil {
return false, err
}
@@ -167,9 +158,9 @@ func radauthReq(flags utils.FlagsWithParams, req *radigo.Packet, aReq *AgentRequ
copy(success[1:], authenticatorResponse)
// this AVP need to be added to be verified on the client side
rpl.AddAVPWithName(MSCHAP2SuccessAVP, string(success), MicrosoftVendor)
return true, nil
default:
return false, utils.NewErrMandatoryIeMissing(utils.Flags)
}
return true, nil
}

View File

@@ -26,12 +26,11 @@ import (
)
// NewObjectDP constructs a utils.DataProvider
func NewObjectDP(obj interface{}) (dP utils.DataProvider) {
dP = &ObjectDP{
func NewObjectDP(obj interface{}) utils.DataProvider {
return &ObjectDP{
obj: obj,
cache: make(map[string]interface{}),
}
return
}
// ObjectDP implements the DataProvider for any interface{}
@@ -119,8 +118,7 @@ func (objDP *ObjectDP) FieldAsInterface(fldPath []string) (data interface{}, err
// FieldAsString is part of engine.utils.DataProvider interface
func (objDP *ObjectDP) FieldAsString(fldPath []string) (data string, err error) {
var valIface interface{}
valIface, err = objDP.FieldAsInterface(fldPath)
if err != nil {
if valIface, err = objDP.FieldAsInterface(fldPath); err != nil {
return
}
return utils.IfaceAsString(valIface), nil

View File

@@ -4,7 +4,7 @@
"request_processors": [
{
"id": "NAPTRAttributes",
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*vars.E164Address:4986517174964"],
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*req.Question[0].Name{*e164}:4986517174964"],
"flags": ["*authorize", "*attributes","*log"],
"request_fields":[
{"tag": "E164Address", "path": "*cgreq.E164Address",
@@ -13,15 +13,15 @@
"type": "*constant", "value": "*attributes"}
],
"reply_fields":[
{"tag": "NAPTROrder", "path": "*rep.Order",
{"tag": "NAPTROrder", "path": "*rep.Answer.Order",
"type": "*constant", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference",
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference",
"type": "*constant", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags",
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags",
"type": "*constant", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service",
{"tag": "NAPTRService", "path": "*rep.Answer.Service",
"type": "*constant", "value": "E2U+SIP"},
{"tag": "NAPTRRegex", "path": "*rep.Regexp",
{"tag": "NAPTRRegex", "path": "*rep.Answer.Regexp",
"type": "*variable", "value": "~*cgrep.Attributes.NAPTRAddress"},
],
},

View File

@@ -4,18 +4,18 @@
"request_processors": [
{
"id": "DryRunNAPTR",
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*vars.E164Address:4986517174963"],
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*req.Question[0].Name{*e164}:4986517174963"],
"flags": ["*dryrun","*log"],
"request_fields":[
{"tag": "ToR", "path": "*cgreq.ToR", "type": "*constant", "value": "*sms"},
],
"reply_fields":[
{"tag": "NAPTROrder", "path": "*rep.Order", "type": "*constant", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference", "type": "*constant", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags", "type": "*constant", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service", "type": "*constant", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Regexp", "type": "*constant", "value": "!^(.*)$!sip:\\1@172.16.1.10.!"},
{"tag": "NAPTRReplacement", "path": "*rep.Replacement", "type": "*constant", "value": "."},
{"tag": "NAPTROrder", "path": "*rep.Answer.Order", "type": "*constant", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference", "type": "*constant", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags", "type": "*constant", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Answer.Service", "type": "*constant", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Answer.Regexp", "type": "*constant", "value": "!^(.*)$!sip:\\1@172.16.1.10.!"},
{"tag": "NAPTRReplacement", "path": "*rep.Answer.Replacement", "type": "*constant", "value": "."},
],
},
],

View File

@@ -5,7 +5,7 @@
{
"id": "NAPTRRoutesQuery",
"filters": ["*string:~*vars.QueryType:NAPTR",
"*string:~*vars.E164Address:4986517174965"],
"*string:~*req.Question[0].Name{*e164}:4986517174965"],
"flags": ["*message", "*routes","*continue"],
"request_fields":[
{"tag": "ToR", "path": "*cgreq.Account", "type": "*constant", "value": "1001"}, // so we can match the supplier profile
@@ -18,44 +18,44 @@
{
"id": "NAPTRSuppliersOneSupplier",
"filters": ["*string:~*vars.QueryType:NAPTR",
"*string:~*vars.E164Address:4986517174965",
"*string:~*req.Question[0].Name{*e164}:4986517174965",
"*gte:~*cgrep.RouteProfiles.Length:1",
"*gte:~*cgrep.RouteProfiles[0].Routes.Length:1"],
"flags": ["*none","*continue"], // do not send request to CGRateS
"reply_fields":[
{"tag": "NAPTROrder", "path": "*rep.Order",
{"tag": "NAPTROrder", "path": "*rep.Answer.Order",
"type": "*group", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference",
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference",
"type": "*group", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags",
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags",
"type": "*group", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service",
{"tag": "NAPTRService", "path": "*rep.Answer.Service",
"type": "*group", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Regexp", "type": "*group",
{"tag": "NAPTRRegexp", "path": "*rep.Answer.Regexp", "type": "*group",
"value": "~*cgrep.RouteProfiles[0].Routes[0].RouteParameters"},
{"tag": "NAPTRReplacement", "path": "*rep.Replacement",
{"tag": "NAPTRReplacement", "path": "*rep.Answer.Replacement",
"type": "*group", "value": "."},
],
},
{
"id": "NAPTRSuppliersTwoSuppliers",
"filters": ["*string:~*vars.QueryType:NAPTR",
"*string:~*vars.E164Address:4986517174965",
"*string:~*req.Question[0].Name{*e164}:4986517174965",
"*gte:~*cgrep.RouteProfiles.Length:1",
"*gte:~*cgrep.RouteProfiles[0].Routes.Length:2"],
"flags": ["*none","*continue"],
"reply_fields":[
{"tag": "NAPTROrder", "type": "*group", "new_branch": true,
"path": "*rep.Order", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference",
"path": "*rep.Answer.Order", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference",
"type": "*group", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags",
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags",
"type": "*group", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service",
{"tag": "NAPTRService", "path": "*rep.Answer.Service",
"type": "*group", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Regexp", "type": "*group",
{"tag": "NAPTRRegexp", "path": "*rep.Answer.Regexp", "type": "*group",
"value": "~*cgrep.RouteProfiles[0].Routes[1].RouteParameters"},
{"tag": "NAPTRReplacement", "path": "*rep.Replacement",
{"tag": "NAPTRReplacement", "path": "*rep.Answer.Replacement",
"type": "*group", "value": "."},
],
},

View File

@@ -4,7 +4,7 @@
"request_processors": [
{
"id": "NAPTRAttributes",
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*vars.E164Address:4986517174964"],
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*req.Question[0].Name{*e164}:4986517174964"],
"flags": ["*authorize", "*attributes","*log"],
"request_fields":[
{"tag": "E164Address", "path": "*cgreq.E164Address",
@@ -13,15 +13,15 @@
"type": "*constant", "value": "*attributes"}
],
"reply_fields":[
{"tag": "NAPTROrder", "path": "*rep.Order",
{"tag": "NAPTROrder", "path": "*rep.Answer.Order",
"type": "*constant", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference",
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference",
"type": "*constant", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags",
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags",
"type": "*constant", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service",
{"tag": "NAPTRService", "path": "*rep.Answer.Service",
"type": "*constant", "value": "E2U+SIP"},
{"tag": "NAPTRRegex", "path": "*rep.Regexp",
{"tag": "NAPTRRegex", "path": "*rep.Answer.Regexp",
"type": "*variable", "value": "~*cgrep.Attributes.NAPTRAddress"},
],
},

View File

@@ -4,18 +4,18 @@
"request_processors": [
{
"id": "DryRunNAPTR",
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*vars.E164Address:4986517174963"],
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*req.Question[0].Name{*e164}:4986517174963"],
"flags": ["*dryrun","*log"],
"request_fields":[
{"tag": "ToR", "path": "*cgreq.ToR", "type": "*constant", "value": "*sms"},
],
"reply_fields":[
{"tag": "NAPTROrder", "path": "*rep.Order", "type": "*constant", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference", "type": "*constant", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags", "type": "*constant", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service", "type": "*constant", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Regexp", "type": "*constant", "value": "!^(.*)$!sip:\\1@172.16.1.10.!"},
{"tag": "NAPTRReplacement", "path": "*rep.Replacement", "type": "*constant", "value": "."},
{"tag": "NAPTROrder", "path": "*rep.Answer.Order", "type": "*constant", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference", "type": "*constant", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags", "type": "*constant", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Answer.Service", "type": "*constant", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Answer.Regexp", "type": "*constant", "value": "!^(.*)$!sip:\\1@172.16.1.10.!"},
{"tag": "NAPTRReplacement", "path": "*rep.Answer.Replacement", "type": "*constant", "value": "."},
],
},
],

View File

@@ -5,7 +5,7 @@
{
"id": "NAPTRRoutesQuery",
"filters": ["*string:~*vars.QueryType:NAPTR",
"*string:~*vars.E164Address:4986517174965"],
"*string:~*req.Question[0].Name{*e164}:4986517174965"],
"flags": ["*message", "*routes","*continue"],
"request_fields":[
{"tag": "ToR", "path": "*cgreq.Account", "type": "*constant", "value": "1001"}, // so we can match the supplier profile
@@ -18,44 +18,44 @@
{
"id": "NAPTRSuppliersOneSupplier",
"filters": ["*string:~*vars.QueryType:NAPTR",
"*string:~*vars.E164Address:4986517174965",
"*string:~*req.Question[0].Name{*e164}:4986517174965",
"*gte:~*cgrep.RouteProfiles.Length:1",
"*gte:~*cgrep.RouteProfiles[0].Routes.Length:1"],
"flags": ["*none","*continue"], // do not send request to CGRateS
"reply_fields":[
{"tag": "NAPTROrder", "path": "*rep.Order",
{"tag": "NAPTROrder", "path": "*rep.Answer.Order",
"type": "*group", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference",
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference",
"type": "*group", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags",
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags",
"type": "*group", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service",
{"tag": "NAPTRService", "path": "*rep.Answer.Service",
"type": "*group", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Regexp", "type": "*group",
{"tag": "NAPTRRegexp", "path": "*rep.Answer.Regexp", "type": "*group",
"value": "~*cgrep.RouteProfiles[0].Routes[0].RouteParameters"},
{"tag": "NAPTRReplacement", "path": "*rep.Replacement",
{"tag": "NAPTRReplacement", "path": "*rep.Answer.Replacement",
"type": "*group", "value": "."},
],
},
{
"id": "NAPTRSuppliersTwoSuppliers",
"filters": ["*string:~*vars.QueryType:NAPTR",
"*string:~*vars.E164Address:4986517174965",
"*string:~*req.Question[0].Name{*e164}:4986517174965",
"*gte:~*cgrep.RouteProfiles.Length:1",
"*gte:~*cgrep.RouteProfiles[0].Routes.Length:1"],
"flags": ["*none","*continue"],
"reply_fields":[
{"tag": "NAPTROrder", "type": "*group", "new_branch": true,
"path": "*rep.Order", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference",
"path": "*rep.Answer.Order", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference",
"type": "*group", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags",
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags",
"type": "*group", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service",
{"tag": "NAPTRService", "path": "*rep.Answer.Service",
"type": "*group", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Regexp", "type": "*group",
{"tag": "NAPTRRegexp", "path": "*rep.Answer.Regexp", "type": "*group",
"value": "~*cgrep.RouteProfiles[0].Routes[1].RouteParameters"},
{"tag": "NAPTRReplacement", "path": "*rep.Replacement",
{"tag": "NAPTRReplacement", "path": "*rep.Answer.Replacement",
"type": "*group", "value": "."},
],
},

View File

@@ -4,7 +4,7 @@
"request_processors": [
{
"id": "NAPTRAttributes",
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*vars.E164Address:4986517174964"],
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*req.Question[0].Name{*e164}:4986517174964"],
"flags": ["*authorize", "*attributes","*log"],
"request_fields":[
{"tag": "E164Address", "path": "*cgreq.E164Address",
@@ -13,15 +13,15 @@
"type": "*constant", "value": "*attributes"}
],
"reply_fields":[
{"tag": "NAPTROrder", "path": "*rep.Order",
{"tag": "NAPTROrder", "path": "*rep.Answer.Order",
"type": "*constant", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference",
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference",
"type": "*constant", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags",
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags",
"type": "*constant", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service",
{"tag": "NAPTRService", "path": "*rep.Answer.Service",
"type": "*constant", "value": "E2U+SIP"},
{"tag": "NAPTRRegex", "path": "*rep.Regexp",
{"tag": "NAPTRRegex", "path": "*rep.Answer.Regexp",
"type": "*variable", "value": "~*cgrep.Attributes.NAPTRAddress"},
],
},

View File

@@ -4,18 +4,18 @@
"request_processors": [
{
"id": "DryRunNAPTR",
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*vars.E164Address:4986517174963"],
"filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*req.Question[0].Name{*e164}:4986517174963"],
"flags": ["*dryrun","*log"],
"request_fields":[
{"tag": "ToR", "path": "*cgreq.ToR", "type": "*constant", "value": "*sms"},
{"tag": "ToR", "path": "*cgreq.Order", "type": "*variable", "value": "~*req.Question[0].Name"},
],
"reply_fields":[
{"tag": "NAPTROrder", "path": "*rep.Order", "type": "*constant", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference", "type": "*constant", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags", "type": "*constant", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service", "type": "*constant", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Regexp", "type": "*constant", "value": "!^(.*)$!sip:\\1@172.16.1.10.!"},
{"tag": "NAPTRReplacement", "path": "*rep.Replacement", "type": "*constant", "value": "."},
{"tag": "NAPTROrder", "path": "*rep.Answer.Order", "type": "*constant", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference", "type": "*constant", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags", "type": "*constant", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Answer.Service", "type": "*constant", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Answer.Regexp", "type": "*constant", "value": "!^(.*)$!sip:\\1@172.16.1.10.!"},
{"tag": "NAPTRReplacement", "path": "*rep.Answer.Replacement", "type": "*constant", "value": "."},
],
},
],

View File

@@ -5,7 +5,7 @@
{
"id": "NAPTRRoutesQuery",
"filters": ["*string:~*vars.QueryType:NAPTR",
"*string:~*vars.E164Address:4986517174965"],
"*string:~*req.Question[0].Name{*e164}:4986517174965"],
"flags": ["*message", "*routes","*continue"],
"request_fields":[
{"tag": "ToR", "path": "*cgreq.Account", "type": "*constant", "value": "1001"}, // so we can match the supplier profile
@@ -18,44 +18,44 @@
{
"id": "NAPTRSuppliersOneSupplier",
"filters": ["*string:~*vars.QueryType:NAPTR",
"*string:~*vars.E164Address:4986517174965",
"*string:~*req.Question[0].Name{*e164}:4986517174965",
"*gte:~*cgrep.RouteProfiles.Length:1",
"*gte:~*cgrep.RouteProfiles[0].Routes.Length:1"],
"flags": ["*none","*continue"], // do not send request to CGRateS
"reply_fields":[
{"tag": "NAPTROrder", "path": "*rep.Order",
{"tag": "NAPTROrder", "path": "*rep.Answer.Order",
"type": "*group", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference",
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference",
"type": "*group", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags",
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags",
"type": "*group", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service",
{"tag": "NAPTRService", "path": "*rep.Answer.Service",
"type": "*group", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Regexp", "type": "*group",
{"tag": "NAPTRRegexp", "path": "*rep.Answer.Regexp", "type": "*group",
"value": "~*cgrep.RouteProfiles[0].Routes[0].RouteParameters"},
{"tag": "NAPTRReplacement", "path": "*rep.Replacement",
{"tag": "NAPTRReplacement", "path": "*rep.Answer.Replacement",
"type": "*group", "value": "."},
],
},
{
"id": "NAPTRSuppliersTwoSuppliers",
"filters": ["*string:~*vars.QueryType:NAPTR",
"*string:~*vars.E164Address:4986517174965",
"*string:~*req.Question[0].Name{*e164}:4986517174965",
"*gte:~*cgrep.RouteProfiles.Length:1",
"*gte:~*cgrep.RouteProfiles[0].Routes.Length:2"],
"flags": ["*none","*continue"],
"reply_fields":[
{"tag": "NAPTROrder", "type": "*group", "new_branch": true,
"path": "*rep.Order", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Preference",
"path": "*rep.Answer.Order", "value": "100"},
{"tag": "NAPTRPreference", "path": "*rep.Answer.Preference",
"type": "*group", "value": "10"},
{"tag": "NAPTRFlags", "path": "*rep.Flags",
{"tag": "NAPTRFlags", "path": "*rep.Answer.Flags",
"type": "*group", "value": "U"},
{"tag": "NAPTRService", "path": "*rep.Service",
{"tag": "NAPTRService", "path": "*rep.Answer.Service",
"type": "*group", "value": "E2U+SIP"},
{"tag": "NAPTRRegexp", "path": "*rep.Regexp", "type": "*group",
{"tag": "NAPTRRegexp", "path": "*rep.Answer.Regexp", "type": "*group",
"value": "~*cgrep.RouteProfiles[0].Routes[1].RouteParameters"},
{"tag": "NAPTRReplacement", "path": "*rep.Replacement",
{"tag": "NAPTRReplacement", "path": "*rep.Answer.Replacement",
"type": "*group", "value": "."},
],
},

View File

@@ -430,7 +430,7 @@ func (acc *Account) debitCreditBalance(cd *CallDescriptor, count bool, dryRun bo
moneyBalanceChecker = false
for _, balance := range usefulMoneyBalances {
partCC, debitErr := balance.debit(cd, balance.account,
usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0,false)
usefulMoneyBalances, count, dryRun, len(cc.Timespans) == 0, false)
if debitErr != nil {
return nil, debitErr
}

12
go.mod
View File

@@ -8,7 +8,7 @@ go 1.16
require (
cloud.google.com/go v0.75.0 // indirect
github.com/Azure/go-amqp v0.13.1
github.com/Azure/go-amqp v0.15.0
github.com/RoaringBitmap/roaring v0.5.5 // indirect
github.com/antchfx/xmlquery v1.3.3
github.com/antchfx/xpath v1.1.11 // indirect
@@ -41,7 +41,7 @@ require (
github.com/lib/pq v1.8.0 // indirect
github.com/mattn/go-runewidth v0.0.10 // indirect
github.com/mediocregopher/radix/v3 v3.7.0
github.com/miekg/dns v1.1.35
github.com/miekg/dns v1.1.44-0.20210927135021-1630ffe2ca11
github.com/mitchellh/mapstructure v1.4.0
github.com/nats-io/nats-server/v2 v2.2.6 // indirect
github.com/nats-io/nats.go v1.11.0
@@ -56,11 +56,11 @@ require (
github.com/xdg/stringprep v1.0.1-0.20180714160509-73f8eece6fdc // indirect
go.mongodb.org/mongo-driver v1.4.4
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
golang.org/x/mod v0.5.1 // indirect
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect
golang.org/x/sys v0.0.0-20210112091331-59c308dcf3cc // indirect
golang.org/x/text v0.3.5 // indirect
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
golang.org/x/tools v0.1.6 // indirect
google.golang.org/api v0.36.0
google.golang.org/genproto v0.0.0-20210111234610-22ae2b108f89 // indirect
google.golang.org/grpc v1.34.1 // indirect

48
go.sum
View File

@@ -36,6 +36,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-amqp v0.13.1 h1:dXnEJ89Hf7wMkcBbLqvocZlM4a3uiX9uCxJIvU77+Oo=
github.com/Azure/go-amqp v0.13.1/go.mod h1:qj+o8xPCz9tMSbQ83Vp8boHahuRDl5mkNHyt1xlxUTs=
github.com/Azure/go-amqp v0.15.0 h1:YcB++F5msgyl8htdsjjlhK132YFca31FBPB7lObE/p0=
github.com/Azure/go-amqp v0.15.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
@@ -218,7 +220,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
@@ -237,8 +238,8 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -384,8 +385,8 @@ github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRR
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mediocregopher/radix/v3 v3.7.0 h1:SM9zJdme5pYGEVvh1HttjBjDmIaNBDKy+oDCv5w81Wo=
github.com/mediocregopher/radix/v3 v3.7.0/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.44-0.20210927135021-1630ffe2ca11 h1:x/LgmprhSZSR5CV8wFas/6sMT2U70LGgKog/P0Oe+jA=
github.com/miekg/dns v1.1.44-0.20210927135021-1630ffe2ca11/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0=
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -409,10 +410,6 @@ github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nyaruka/phonenumbers v1.0.60 h1:nnAcNwmZflhegiImm6MkvjlRRyoaSw1ox/jGPAewWTg=
github.com/nyaruka/phonenumbers v1.0.60/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U=
github.com/nyaruka/phonenumbers v1.0.70 h1:AecpfeQ8/qWKzkZM2NZZEoq5B+qAuH9MUmHK397U7CQ=
github.com/nyaruka/phonenumbers v1.0.70/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U=
github.com/nyaruka/phonenumbers v1.0.71 h1:itkCGhxkQkHrJ6OyZSApdjQVlPmrWs88MF283pPvbFU=
github.com/nyaruka/phonenumbers v1.0.71/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -508,6 +505,8 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
@@ -577,6 +576,9 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -591,7 +593,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -613,8 +614,12 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167 h1:eDd+TJqbgfXruGQ5sJRU7tEtp/58OAx4+Ayjxg4SM+4=
golang.org/x/net v0.0.0-20210924151903-3ad01bbaa167/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -634,8 +639,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -657,7 +662,6 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -680,8 +684,13 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112091331-59c308dcf3cc h1:y0Og6AYdwus7SIAnKnDxjc4gJetRiYEWOx4AKbOeyEI=
golang.org/x/sys v0.0.0-20210112091331-59c308dcf3cc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -689,8 +698,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -724,7 +733,6 @@ golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -751,6 +759,9 @@ golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6 h1:SIasE1FVIQOWz2GEAHFOmoW7xchJcqlucjSULTL0Ag4=
golang.org/x/tools v0.1.6/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -847,7 +858,6 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=

View File

@@ -172,6 +172,7 @@ cgrates (0.11.0~dev) UNRELEASED; urgency=medium
* [CacheS] Updated LoadCache and ReloadCache APIs
* [EEs] Added *log exporter
* [AttributeS] Added profile_runs to control how many times a profile is proccessed for an event
* [DNSAgent] Updated Msg handling from templates
-- DanB <danb@cgrates.org> Wed, 19 Feb 2020 13:25:52 +0200

View File

@@ -696,6 +696,8 @@ const (
MetaSIPURIMethod = "*sipuri_method"
MetaSIPURIHost = "*sipuri_host"
MetaSIPURIUser = "*sipuri_user"
E164DomainConverter = "*e164Domain"
E164Converter = "*e164"
MetaReload = "*reload"
MetaLoad = "*load"
MetaFloat64 = "*float64"
@@ -713,7 +715,6 @@ const (
DNSAgent = "DNSAgent"
TLSNoCaps = "tls"
UsageID = "UsageID"
Rcode = "Rcode"
Replacement = "Replacement"
Regexp = "Regexp"
Order = "Order"
@@ -853,6 +854,26 @@ const (
BalanceIDs = "BalanceIDs"
MetaCostIncrement = "*costIncrement"
Length = "Length"
// dns
Rcode = "Rcode"
Id = "Id"
Response = "Response"
Opcode = "Opcode"
Authoritative = "Authoritative"
Truncated = "Truncated"
RecursionDesired = "RecursionDesired"
RecursionAvailable = "RecursionAvailable"
Zero = "Zero"
AuthenticatedData = "AuthenticatedData"
CheckingDisabled = "CheckingDisabled"
Question = "Question"
Answer = "Answer"
Ns = "Ns"
Extra = "Extra"
Name = "Name"
Qtype = "Qtype"
Qclass = "Qclass"
)
// Migrator Action

View File

@@ -21,6 +21,7 @@ package utils
import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"math/rand"
"net"
@@ -94,6 +95,10 @@ func NewDataConverter(params string) (conv DataConverter, err error) {
return new(SliceConverter), nil
case params == MetaFloat64:
return new(Float64Converter), nil
case params == E164DomainConverter:
return new(e164DomainConverter), nil
case params == E164Converter:
return new(e164Converter), nil
case strings.HasPrefix(params, MetaLibPhoneNumber):
if len(params) == len(MetaLibPhoneNumber) {
return NewPhoneNumberConverter(EmptyString)
@@ -547,3 +552,27 @@ type Float64Converter struct{}
func (Float64Converter) Convert(in interface{}) (interface{}, error) {
return IfaceAsFloat64(in)
}
// e164DomainConverter extracts the domain part out of a NAPTR name record
type e164DomainConverter struct{}
func (e164DomainConverter) Convert(in interface{}) (interface{}, error) {
name := IfaceAsString(in)
if i := strings.Index(name, ".e164."); i != -1 {
name = name[i:]
}
return strings.Trim(name, "."), nil
}
// e164Converter extracts the E164 address out of a NAPTR name record
type e164Converter struct{}
func (e164Converter) Convert(in interface{}) (interface{}, error) {
name := IfaceAsString(in)
i := strings.Index(name, ".e164.")
if i == -1 {
return nil, errors.New("unknown format")
}
return ReverseString(
strings.Replace(name[:i], ".", "", -1)), nil
}

View File

@@ -1181,3 +1181,45 @@ func TestSliceConverter(t *testing.T) {
t.Errorf("Expecting: %+v, received: %+v", expected, rcv)
}
}
func TestE164FromNAPTRConverter(t *testing.T) {
exp := new(e164Converter)
cnv, err := NewDataConverter(E164Converter)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(exp, cnv) {
t.Errorf("Expecting: %+v, received: %+v", exp, cnv)
}
if e164, err := cnv.Convert("8.7.6.5.4.3.2.1.0.1.6.e164.arpa."); err != nil {
t.Error(err)
} else if e164 != "61012345678" {
t.Errorf("received: <%s>", e164)
}
}
func TestDomainNameFromNAPTRConverter(t *testing.T) {
exp := new(e164DomainConverter)
cnv, err := NewDataConverter(E164DomainConverter)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(exp, cnv) {
t.Errorf("Expecting: %+v, received: %+v", exp, cnv)
}
if dName, err := cnv.Convert("8.7.6.5.4.3.2.1.0.1.6.e164.arpa."); err != nil {
t.Fatal(err)
} else if dName != "e164.arpa" {
t.Errorf("received: <%s>", dName)
}
if dName, err := cnv.Convert("8.7.6.5.4.3.2.1.0.1.6.e164.itsyscom.com."); err != nil {
t.Fatal(err)
} else if dName != "e164.itsyscom.com" {
t.Errorf("received: <%s>", dName)
}
if dName, err := cnv.Convert("8.7.6.5.4.3.2.1.0.1.6.itsyscom.com."); err != nil {
t.Fatal(err)
} else if dName != "8.7.6.5.4.3.2.1.0.1.6.itsyscom.com" {
t.Errorf("received: <%s>", dName)
}
}