mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
DNSAgent - basic ENUM implementation working with dryRun
This commit is contained in:
@@ -72,28 +72,6 @@ func (da *DNSAgent) ListenAndServe() 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) {
|
||||
fmt.Printf("got message: %+v\n", req)
|
||||
/*rply := new(dns.Msg)
|
||||
rply.SetReply(req)
|
||||
switch req.Question[0].Qtype {
|
||||
case dns.TypeA:
|
||||
rply.Authoritative = true
|
||||
if req.Question[0].Name == "cgrates.org." {
|
||||
rply.Answer = append(rply.Answer,
|
||||
&dns.A{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: req.Question[0].Name,
|
||||
Rrtype: dns.TypeA,
|
||||
Class: dns.ClassINET,
|
||||
Ttl: 60},
|
||||
A: net.ParseIP("195.201.167.179")},
|
||||
)
|
||||
}
|
||||
}
|
||||
rply.Rcode = dns.RcodeServerFailure
|
||||
w.WriteMsg(rply)
|
||||
*/
|
||||
|
||||
dnsDP := newDNSDataProvider(req, w)
|
||||
reqVars := make(map[string]interface{})
|
||||
reqVars[QueryType] = dns.TypeToString[req.Question[0].Qtype]
|
||||
@@ -112,10 +90,8 @@ func (da *DNSAgent) handleMessage(w dns.ResponseWriter, req *dns.Msg) {
|
||||
return
|
||||
}
|
||||
reqVars[E164Address] = e164
|
||||
utils.Logger.Info(fmt.Sprintf("reqVars: %+v", reqVars))
|
||||
}
|
||||
rplyNM := config.NewNavigableMap(nil) // share it among different processors
|
||||
|
||||
var processed bool
|
||||
var err error
|
||||
for _, reqProcessor := range da.cgrCfg.DNSAgentCfg().RequestProcessors {
|
||||
@@ -152,6 +128,20 @@ func (da *DNSAgent) handleMessage(w dns.ResponseWriter, req *dns.Msg) {
|
||||
dnsWriteMsg(w, rply)
|
||||
return
|
||||
}
|
||||
if err = updateDNSMsgFromNM(rply, rplyNM); err != nil {
|
||||
utils.Logger.Warning(
|
||||
fmt.Sprintf("<%s> error: %s updating answer: %s from NM %s",
|
||||
utils.DNSAgent, err.Error(), utils.ToJSON(rply), utils.ToJSON(rplyNM)))
|
||||
rply.Rcode = dns.RcodeServerFailure
|
||||
dnsWriteMsg(w, rply)
|
||||
}
|
||||
if err = dnsWriteMsg(w, rply); err != nil { // failed sending, most probably content issue
|
||||
rply = new(dns.Msg)
|
||||
rply.SetReply(req)
|
||||
rply.Rcode = dns.RcodeServerFailure
|
||||
dnsWriteMsg(w, rply)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (da *DNSAgent) processRequest(reqProcessor *config.RequestProcessor,
|
||||
|
||||
@@ -21,7 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package agents
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"path"
|
||||
@@ -43,7 +42,7 @@ var (
|
||||
|
||||
var sTestsDNS = []func(t *testing.T){
|
||||
testDNSitResetDB,
|
||||
testDNSitStartEngine,
|
||||
//testDNSitStartEngine,
|
||||
testDNSitApierRpcConn,
|
||||
testDNSitTPFromFolder,
|
||||
testDNSitClntConn,
|
||||
@@ -94,26 +93,13 @@ func testDNSitApierRpcConn(t *testing.T) {
|
||||
|
||||
// Load the tariff plan, creating accounts and their balances
|
||||
func testDNSitTPFromFolder(t *testing.T) {
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "oldtutorial")}
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")}
|
||||
var loadInst utils.LoadInstance
|
||||
if err := dnsRPC.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &loadInst); err != nil {
|
||||
if err := dnsRPC.Call(utils.ApierV2LoadTariffPlanFromFolder,
|
||||
attrs, &loadInst); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
//add a default charger
|
||||
chargerProfile := &engine.ChargerProfile{
|
||||
Tenant: "cgrates.org",
|
||||
ID: "Default",
|
||||
RunID: utils.MetaDefault,
|
||||
AttributeIDs: []string{"*none"},
|
||||
Weight: 20,
|
||||
}
|
||||
var result string
|
||||
if err := dnsRPC.Call("ApierV1.SetChargerProfile", chargerProfile, &result); err != nil {
|
||||
t.Error(err)
|
||||
} else if result != utils.OK {
|
||||
t.Error("Unexpected reply returned", result)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect DNS client to server
|
||||
@@ -125,7 +111,6 @@ func testDNSitClntConn(t *testing.T) {
|
||||
} else if dnsClnt == nil {
|
||||
t.Fatalf("conn is nil")
|
||||
}
|
||||
fmt.Printf("done connecting to %s", dnsCfg.DNSAgentCfg().Listen)
|
||||
}
|
||||
|
||||
func testDNSitClntNAPTRDryRun(t *testing.T) {
|
||||
@@ -140,6 +125,25 @@ func testDNSitClntNAPTRDryRun(t *testing.T) {
|
||||
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 != "^.*$" {
|
||||
t.Errorf("received: <%q>", answr.Regexp)
|
||||
}
|
||||
if answr.Replacement != "sip:1\\@172.16.1.10." {
|
||||
t.Errorf("received: <%q>", answr.Replacement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
|
||||
const (
|
||||
QueryType = "QueryType"
|
||||
E164Address = "E164"
|
||||
E164Address = "E164Address"
|
||||
)
|
||||
|
||||
// e164FromNAPTR extracts the E164 address out of a NAPTR name record
|
||||
@@ -129,6 +129,16 @@ func appendDNSAnswer(msg *dns.Msg) (err error) {
|
||||
Ttl: 60},
|
||||
},
|
||||
)
|
||||
case dns.TypeNAPTR:
|
||||
msg.Answer = append(msg.Answer,
|
||||
&dns.NAPTR{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: msg.Question[0].Name,
|
||||
Rrtype: msg.Question[0].Qtype,
|
||||
Class: dns.ClassINET,
|
||||
Ttl: 60},
|
||||
},
|
||||
)
|
||||
default:
|
||||
return fmt.Errorf("unsupported DNS type: <%v>", msg.Question[0].Qtype)
|
||||
}
|
||||
@@ -146,7 +156,7 @@ func updateDNSMsgFromNM(msg *dns.Msg, nm *config.NavigableMap) (err error) {
|
||||
continue
|
||||
}
|
||||
cfgItm := nmItms[0] // first item gives some config for the rest
|
||||
if cfgItm.Config.NewBranch {
|
||||
if len(msg.Answer) == 0 || cfgItm.Config.NewBranch {
|
||||
if err = appendDNSAnswer(msg); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -155,31 +165,68 @@ func updateDNSMsgFromNM(msg *dns.Msg, nm *config.NavigableMap) (err error) {
|
||||
return errors.New("empty path in config item")
|
||||
}
|
||||
switch cfgItm.Path[0] {
|
||||
case utils.MetaResponseCode:
|
||||
case utils.Rcode:
|
||||
var itm int64
|
||||
if itm, err = utils.IfaceAsInt64(cfgItm.Data); err != nil {
|
||||
return fmt.Errorf("item: <%s>, err: %s", cfgItm.Path[0], err.Error())
|
||||
}
|
||||
msg.Rcode = int(itm)
|
||||
continue
|
||||
case utils.MetaAnswer:
|
||||
lastAnswer := msg.Answer[len(msg.Answer)-1]
|
||||
switch msg.Question[0].Qtype {
|
||||
case dns.TypeA:
|
||||
var ip string
|
||||
if ip, err = utils.IfaceAsString(cfgItm.Data); err != nil {
|
||||
return
|
||||
}
|
||||
lastAnswer.(*dns.A).A = net.ParseIP(ip)
|
||||
case dns.TypeNAPTR:
|
||||
if rr, err := dns.NewRR(`IN NAPTR 100 10 "U" "E2U+sip" "!^.*$!sip:customer-service@example.com!" .`); err != nil {
|
||||
return err
|
||||
} else {
|
||||
lastAnswer = rr
|
||||
}
|
||||
case utils.Order:
|
||||
if msg.Question[0].Qtype != dns.TypeNAPTR {
|
||||
return fmt.Errorf("field <%s> only works with NAPTR", utils.Order)
|
||||
}
|
||||
|
||||
var itm int64
|
||||
if itm, err = utils.IfaceAsInt64(cfgItm.Data); err != nil {
|
||||
return fmt.Errorf("item: <%s>, err: %s", cfgItm.Path[0], err.Error())
|
||||
}
|
||||
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)
|
||||
}
|
||||
var itm int64
|
||||
if itm, err = utils.IfaceAsInt64(cfgItm.Data); err != nil {
|
||||
return fmt.Errorf("item: <%s>, err: %s", cfgItm.Path[0], err.Error())
|
||||
}
|
||||
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)
|
||||
}
|
||||
var itm string
|
||||
if itm, err = utils.IfaceAsString(cfgItm.Data); err != nil {
|
||||
return fmt.Errorf("item: <%s>, err: %s", cfgItm.Path[0], err.Error())
|
||||
}
|
||||
msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Flags = itm
|
||||
case utils.Service:
|
||||
if msg.Question[0].Qtype != dns.TypeNAPTR {
|
||||
return fmt.Errorf("field <%s> only works with NAPTR", utils.Service)
|
||||
}
|
||||
var itm string
|
||||
if itm, err = utils.IfaceAsString(cfgItm.Data); err != nil {
|
||||
return fmt.Errorf("item: <%s>, err: %s", cfgItm.Path[0], err.Error())
|
||||
}
|
||||
msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Service = itm
|
||||
case utils.Regexp:
|
||||
if msg.Question[0].Qtype != dns.TypeNAPTR {
|
||||
return fmt.Errorf("field <%s> only works with NAPTR", utils.Regexp)
|
||||
}
|
||||
var itm string
|
||||
if itm, err = utils.IfaceAsString(cfgItm.Data); err != nil {
|
||||
return fmt.Errorf("item: <%s>, err: %s", cfgItm.Path[0], err.Error())
|
||||
}
|
||||
msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Regexp = itm
|
||||
case utils.Replacement:
|
||||
if msg.Question[0].Qtype != dns.TypeNAPTR {
|
||||
return fmt.Errorf("field <%s> only works with NAPTR", utils.Replacement)
|
||||
}
|
||||
var rplc string
|
||||
if rplc, err = utils.IfaceAsString(cfgItm.Data); err != nil {
|
||||
return fmt.Errorf("item: <%s>, err: %s", cfgItm.Path[0], err.Error())
|
||||
}
|
||||
msg.Answer[len(msg.Answer)-1].(*dns.NAPTR).Replacement = rplc
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -11,10 +11,19 @@
|
||||
"db_password": "CGRateS.org",
|
||||
},
|
||||
|
||||
|
||||
"scheduler": {
|
||||
"enabled": true,
|
||||
"cdrs_conns": [
|
||||
{"address": "*internal"},
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
"sessions": {
|
||||
"enabled": true,
|
||||
"attributes_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"rals_conns": [
|
||||
{"address": "*internal"}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
|
||||
"diameter_agent": {
|
||||
"dns_agent": {
|
||||
"request_processors": [
|
||||
{
|
||||
"id": "dryrun1",
|
||||
@@ -10,6 +10,12 @@
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*constant", "value": "*sms"},
|
||||
],
|
||||
"reply_fields":[
|
||||
{"tag": "NAPTROrder", "field_id": "Order", "type": "*constant", "value": "100"},
|
||||
{"tag": "NAPTRPreference", "field_id": "Preference", "type": "*constant", "value": "10"},
|
||||
{"tag": "NAPTRFlags", "field_id": "Flags", "type": "*constant", "value": "U"},
|
||||
{"tag": "NAPTRService", "field_id": "Service", "type": "*constant", "value": "E2U+SIP"},
|
||||
{"tag": "NAPTRRegexp", "field_id": "Regexp", "type": "*constant", "value": "^.*$"},
|
||||
{"tag": "NAPTRReplacement", "field_id": "Replacement", "type": "*constant", "value": "sip:\\1@172.16.1.10."},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -571,9 +571,13 @@ const (
|
||||
MetaApiKey = "*api_key"
|
||||
UsageID = "UsageID"
|
||||
Status = "status"
|
||||
MetaResponseCode = "*response_code"
|
||||
MetaAnswer = "*answer"
|
||||
MetaTTL = "*ttl"
|
||||
Rcode = "Rcode"
|
||||
Replacement = "Replacement"
|
||||
Regexp = "Regexp"
|
||||
Order = "Order"
|
||||
Preference = "Preference"
|
||||
Flags = "Flags"
|
||||
Service = "Service"
|
||||
)
|
||||
|
||||
// Migrator Action
|
||||
|
||||
Reference in New Issue
Block a user