diff --git a/agents/dnsagent.go b/agents/dnsagent.go index 1c8b0beab..01713ce06 100644 --- a/agents/dnsagent.go +++ b/agents/dnsagent.go @@ -85,24 +85,20 @@ func (da *DNSAgent) Reload() (err error) { func (da *DNSAgent) handleMessage(w dns.ResponseWriter, req *dns.Msg) { dnsDP := newDnsDP(req) - rply := new(dns.Msg) - rply.SetReply(req) - + rply := newDnsReply(req) rmtAddr := w.RemoteAddr().String() for _, q := range req.Question { if processed, err := da.handleQuestion(dnsDP, rply, &q, rmtAddr); err != nil || !processed { + rply := newDnsReply(req) rply.Rcode = dns.RcodeServerFailure - rply = new(dns.Msg) - rply.SetReply(req) dnsWriteMsg(w, rply) return } } if err := dnsWriteMsg(w, rply); err != nil { // failed sending, most probably content issue - rply = new(dns.Msg) - rply.SetReply(req) + rply := newDnsReply(req) rply.Rcode = dns.RcodeServerFailure dnsWriteMsg(w, rply) } diff --git a/agents/dnsagent_it_test.go b/agents/dnsagent_it_test.go index 0c9bb90cb..85c104572 100644 --- a/agents/dnsagent_it_test.go +++ b/agents/dnsagent_it_test.go @@ -51,6 +51,7 @@ var ( testDNSitClntNAPTRAttributes, testDNSitClntNAPTRSuppliers, testDNSitClntNAPTROpts, + testDNSitClntNAPTROptsWithAttributes, testDNSitStopEngine, } ) @@ -266,6 +267,53 @@ func testDNSitClntNAPTROpts(t *testing.T) { } } +func testDNSitClntNAPTROptsWithAttributes(t *testing.T) { + m := new(dns.Msg) + m.SetQuestion("7.6.9.4.7.1.7.1.5.6.8.9.5.e164.arpa.", dns.TypeNAPTR) + m.SetEdns0(4096, false) + m.IsEdns0().Option = append(m.IsEdns0().Option, &dns.EDNS0_ESU{Uri: "sip:cgrates@cgrates.org"}) + if err := dnsClnt.WriteMsg(m); err != nil { + t.Error(err) + } + rply, err := dnsClnt.ReadMsg() + if err != nil { + t.Error(err) + } else if len(rply.Answer) != 1 { + t.Fatalf("wrong number of records: %s", utils.ToIJSON(rply.Answer)) + } + if rply.Rcode != dns.RcodeSuccess { + t.Errorf("failed to get an valid answer\n%v", rply) + } + answr := rply.Answer[0].(*dns.NAPTR) + if answr.Order != 100 { + t.Errorf("received: <%q>", answr.Order) + } + if answr.Preference != 10 { + t.Errorf("received: <%q>", answr.Preference) + } + if answr.Flags != "U" { + t.Errorf("received: <%q>", answr.Flags) + } + if answr.Service != "E2U+SIP" { + t.Errorf("received: <%q>", answr.Service) + } + if answr.Regexp != "!^(.*)$!sip:1@172.16.1.10.!" { + t.Errorf("received: <%q>", answr.Regexp) + } + if answr.Replacement != "." { + t.Errorf("received: <%q>", answr.Replacement) + } + if opts := rply.IsEdns0(); opts == nil { + t.Error("recieved nil options") + } else if len(opts.Option) != 1 { + t.Errorf("recieved wrong number of options: %v", len(opts.Option)) + } else if ov, can := opts.Option[0].(*dns.EDNS0_ESU); !can { + t.Errorf("recieved wrong option type: %T", opts.Option[0]) + } else if expected := "sip:cgrates@e164.arpa"; ov.Uri != expected { + t.Errorf("Expected :<%q> , received: <%q>", expected, ov.Uri) + } +} + func testDNSitStopEngine(t *testing.T) { if err := engine.KillEngine(*waitRater); err != nil { t.Error(err) diff --git a/agents/libdns.go b/agents/libdns.go index dd773e544..8af2bbf09 100644 --- a/agents/libdns.go +++ b/agents/libdns.go @@ -35,6 +35,21 @@ const ( dnsOption = "Option" ) +func newDnsReply(req *dns.Msg) (rply *dns.Msg) { + rply = new(dns.Msg) + rply.SetReply(req) + if len(req.Question) > 0 { + rply.Question = make([]dns.Question, len(req.Question)) + for i, q := range req.Question { + rply.Question[i] = q + } + } + if opts := rply.IsEdns0(); opts != nil { + rply.SetEdns0(4096, false).IsEdns0().Option = opts.Option + } + 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 { diff --git a/data/conf/samples/dnsagent_mysql/opts.json b/data/conf/samples/dnsagent_mysql/opts.json index 057dc7e84..2da9770c6 100644 --- a/data/conf/samples/dnsagent_mysql/opts.json +++ b/data/conf/samples/dnsagent_mysql/opts.json @@ -20,6 +20,25 @@ {"tag": "Opts3", "path": "*rep.Option[0].Uri", "type": "*constant", "value": "sip:cgrates@cgrates.com"}, ], }, + { + "id": "OptsWithAttributes", + "filters": ["*string:~*vars.QueryType:NAPTR", "*string:~*vars.QueryName{*e164}:5986517174967"], + "flags": ["*event","*attributes"], + "request_fields":[ + {"tag": "Origin", "path": "*cgreq.Origin", "type": "*variable", "value": "~*req.Option[0].Uri{*sipuri_user}"}, + {"tag": "Domanin", "path": "*cgreq.Domanin", "type": "*variable", "value": "~*vars.QueryName{*e164Domain}"}, + {"tag": "NewSipURI", "path": "*cgreq.SipURI", "type": "*constant", "value": "*attributes"}, + ], + "reply_fields":[ + {"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": "."}, + {"tag": "Opts", "path": "*rep.Option.Uri", "type": "*variable", "value": "~*cgrep.Attributes[*raw].SipURI", "mandatory": true}, + ], + }, ], }, diff --git a/data/tariffplans/dnsagent/Attributes.csv b/data/tariffplans/dnsagent/Attributes.csv index 12f1c7d1e..007c8d5bc 100644 --- a/data/tariffplans/dnsagent/Attributes.csv +++ b/data/tariffplans/dnsagent/Attributes.csv @@ -1,3 +1,4 @@ #Tenant,ID,Contexts,FilterIDs,ActivationInterval,AttributeFilterIDs,Path,Type,Value,Blocker,Weight cgrates.org,ATTR_NAPTR_ADDR,*any,*string:~*req.E164Address:4986517174964,,,*req.NAPTRAddress,*constant,sip:\1@172.16.1.1.,false,20 +cgrates.org,ATTR_NAPTR_SIP_URI,*any,*string:~*req.Origin:cgrates,,,*req.SipURI,*variable,sip:cgrates@;~*req.Domanin,false,20 diff --git a/utils/dataconverter.go b/utils/dataconverter.go index 5af5f80d8..a954c9809 100644 --- a/utils/dataconverter.go +++ b/utils/dataconverter.go @@ -341,8 +341,7 @@ type SIPURIHostConverter struct{} // Convert implements DataConverter interface func (*SIPURIHostConverter) Convert(in interface{}) (out interface{}, err error) { - val := IfaceAsString(in) - return sipingo.HostFrom(val), nil + return sipingo.HostFrom(IfaceAsString(in)), nil } // SIPURIUserConverter will return the @@ -350,8 +349,7 @@ type SIPURIUserConverter struct{} // Convert implements DataConverter interface func (*SIPURIUserConverter) Convert(in interface{}) (out interface{}, err error) { - val := IfaceAsString(in) - return sipingo.UserFrom(val), nil + return sipingo.UserFrom(IfaceAsString(in)), nil } // SIPURIMethodConverter will return the @@ -359,8 +357,7 @@ type SIPURIMethodConverter struct{} // Convert implements DataConverter interface func (*SIPURIMethodConverter) Convert(in interface{}) (out interface{}, err error) { - val := IfaceAsString(in) - return sipingo.MethodFrom(val), nil + return sipingo.MethodFrom(IfaceAsString(in)), nil } func NewTimeStringConverter(params string) (hdlr DataConverter) {