func GetAFromMySQLBackend(dst, srcIP string, regionTree *RegionTree) (bool, []dns.RR, uint16, *MyError.MyError) { domainId, e := RRMySQL.GetDomainIDFromMySQL(dst) if e != nil { //todo: //fmt.Println(utils.GetDebugLine(), "Error, GetDomainIDFromMySQL:", e) return false, nil, uint16(0), e } region, ee := RRMySQL.GetRegionWithIPFromMySQL(utils.Ip4ToInt32(utils.StrToIP(srcIP))) if ee != nil { //fmt.Println(utils.GetDebugLine(), "Error GetRegionWithIPFromMySQL:", ee) return false, nil, uint16(0), MyError.NewError(ee.ErrorNo, "GetRegionWithIPFromMySQL return "+ee.Error()) } RR, eee := RRMySQL.GetRRFromMySQL(uint32(domainId), region.IdRegion) if eee != nil && eee.ErrorNo == MyError.ERROR_NORESULT { //fmt.Println(utils.GetDebugLine(), "Error GetRRFromMySQL with DomainID:", domainId, // "RegionID:", region.IdRegion, eee) //fmt.Println(utils.GetDebugLine(), "Try to GetRRFromMySQL with Default Region") utils.ServerLogger.Debug("Try to GetRRFromMySQL with Default Region") RR, eee = RRMySQL.GetRRFromMySQL(uint32(domainId), uint32(0)) if eee != nil { //fmt.Println(utils.GetDebugLine(), "Error GetRRFromMySQL with DomainID:", domainId, // "RegionID:", 0, eee) return false, nil, uint16(0), MyError.NewError(eee.ErrorNo, "Error GetRRFromMySQL with DomainID:"+strconv.Itoa(domainId)+eee.Error()) } } else if eee != nil { utils.ServerLogger.Error(eee.Error()) return false, nil, uint16(0), eee } //fmt.Println(utils.GetDebugLine(), "GetRRFromMySQL Succ!:", RR) utils.ServerLogger.Debug("GetRRFromMySQL Succ!: ", RR) var R []dns.RR var rtype uint16 var reE *MyError.MyError hdr := dns.RR_Header{ Name: dst, Class: RR.RR.Class, Rrtype: RR.RR.RrType, Ttl: RR.RR.Ttl, } //fmt.Println(utils.GetDebugLine(), mr.RR) if RR.RR.RrType == dns.TypeA { for _, mr := range RR.RR.Target { rh := &dns.A{ Hdr: hdr, A: utils.StrToIP(mr), } R = append(R, dns.RR(rh)) } rtype = dns.TypeA // fmt.Println(utils.GetDebugLine(), "Get A RR from MySQL, requery dst:", dst) } else if RR.RR.RrType == dns.TypeCNAME { for _, mr := range RR.RR.Target { rh := &dns.CNAME{ Hdr: hdr, Target: mr, } R = append(R, dns.RR(rh)) } rtype = dns.TypeCNAME //fmt.Println(utils.GetDebugLine(), "Get CNAME RR from MySQL, requery dst:", dst) reE = MyError.NewError(MyError.ERROR_NOTVALID, "Got CNAME result for dst : "+dst+" with srcIP : "+srcIP) } if len(R) > 0 { //Add timer for auto refrech the RegionCache go func(dst, srcIP string, r dns.RR, regionTree *RegionTree) { //fmt.Println(utils.GetDebugLine(), " Refresh record after ", r.Header().Ttl-5, // " Second, dst: ", dst, " srcIP: ", srcIP, "add timer ") time.AfterFunc(time.Duration(r.Header().Ttl-5)*time.Second, func() { GetAFromMySQLBackend(dst, srcIP, regionTree) }) }(dst, srcIP, R[0], regionTree) go func(regionTree *RegionTree, R []dns.RR, srcIP string) { //fmt.Println(utils.GetDebugLine(), "GetAFromMySQLBackend: ", e) startIP, endIP := region.Region.StarIP, region.Region.EndIP cidrmask := utils.GetCIDRMaskWithUint32Range(startIP, endIP) //fmt.Println(utils.GetDebugLine(), " GetRegionWithIPFromMySQL with srcIP: ", // srcIP, " StartIP : ", startIP, "==", utils.Int32ToIP4(startIP).String(), // " EndIP: ", endIP, "==", utils.Int32ToIP4(endIP).String(), " cidrmask : ", cidrmask) // netaddr, mask := DefaultNetaddr, DefaultMask r, _ := NewRegion(R, startIP, cidrmask) regionTree.AddRegionToCache(r) //fmt.Println(utils.GetDebugLine(), "GetAFromMySQLBackend: ", r) // fmt.Println(regionTree.GetRegionFromCacheWithAddr(startIP, cidrmask)) }(regionTree, R, srcIP) return true, R, rtype, reE } return false, nil, uint16(0), MyError.NewError(MyError.ERROR_UNKNOWN, utils.GetDebugLine()+"Unknown Error ") }
func GetAFromDNSBackend( dst, srcIP string) (bool, []dns.RR, uint16, *MyError.MyError) { var reE *MyError.MyError = nil var rtype uint16 soa, e := GetSOARecord(dst) utils.ServerLogger.Debug("GetSOARecord return: ", soa, " error: ", e) if e != nil || len(soa.NS) <= 0 { //GetSOA failed , need log and return utils.ServerLogger.Error("GetSOARecord error: %s", e.Error()) return false, nil, dns.TypeNone, MyError.NewError(MyError.ERROR_UNKNOWN, "GetARecord func GetSOARecord failed: "+dst) } var ns_a []string //todo: is that soa.NS may nil ? for _, x := range soa.NS { ns_a = append(ns_a, x.Ns) } rr, edns_h, edns, e := QueryA(dst, srcIP, ns_a, query.NS_SERVER_PORT) //todo: ends_h ends need to be parsed and returned! utils.QueryLogger.Info("QueryA(): dst:", dst, "srcIP:", srcIP, "ns_a:", ns_a, " returned rr:", rr, "edns_h:", edns_h, "edns:", edns, "e:", e) if e == nil && rr != nil { var rr_i []dns.RR //todo:if you add both "A" and "CNAME" record to a domain name,this should be wrong! if a, ok := ParseA(rr, dst); ok { //rr is A record utils.ServerLogger.Debug("GetAFromDNSBackend : typeA record: ", a, " dns.TypeA: ", ok) for _, i := range a { rr_i = append(rr_i, dns.RR(i)) } //if A ,need parse edns client subnet // return true,rr_i,nil rtype = dns.TypeA } else if b, ok := ParseCNAME(rr, dst); ok { //rr is CNAME record //fmt.Println(utils.GetDebugLine(), "GetAFromDNSBackend: typeCNAME record: ", b, " dns.TypeCNAME: ", ok) utils.ServerLogger.Debug("GetAFromDNSBackend: typeCNAME record: ", b, " dns.TypeCNAME: ", ok) //todo: if you add more than one "CNAME" record to a domain name ,this should be wrong,only the first one will be used! //dst = b[0].Target for _, i := range b { rr_i = append(rr_i, dns.RR(i)) } rtype = dns.TypeCNAME reE = MyError.NewError(MyError.ERROR_NOTVALID, "Got CNAME result for dst : "+dst+" with srcIP : "+srcIP) //if CNAME need parse edns client subnet } else { //error return and retry //fmt.Println(utils.GetDebugLine(), "GetAFromDNSBackend: ", rr) utils.ServerLogger.Debug("GetAFromDNSBackend: ", rr) return false, nil, dns.TypeNone, MyError.NewError(MyError.ERROR_NORESULT, "Got error result, need retry for dst : "+dst+" with srcIP : "+srcIP) } utils.ServerLogger.Debug("Add A record to Region Cache: dst:", dst, "srcIP:", srcIP, "rr_i:", rr_i, "ends_h", edns_h, "edns:", edns) go AddAToRegionCache(dst, srcIP, rr_i, edns_h, edns) return true, rr_i, rtype, reE } return false, nil, dns.TypeNone, MyError.NewError(MyError.ERROR_UNKNOWN, utils.GetDebugLine()+"Unknown error") }
func TestMubitRadix(t *testing.T) { cidrNet := []string{ "10.0.0.2/8", "10.20.0.0/14", "10.21.0.0/16", "192.168.0.0/16", "192.168.2.0/24", "8.0.0.0/9", "8.8.8.0/24", "0.0.0.0/0", // "128.0.0.0/1", } ip2Find := []string{ "10.20.1.2", "10.22.1.2", "10.19.0.1", "10.21.0.1", "192.168.2.3", "10.22.0.5", "202.106.0.20", "172.16.3.133", "8.8.8.8", "8.8.7.1", } RadixTree := NewDomainRegionTree() for _, x := range cidrNet { i, n, e := net.ParseCIDR(x) if e != nil { t.Log(e.Error()) t.Fail() continue } a, m := utils.IpNetToInt32(n) RadixTree.AddRegionToCache(&Region{ NetworkAddr: a, NetworkMask: m, RR: []dns.RR{ dns.RR(&dns.A{ A: i, Hdr: dns.RR_Header{ Rrtype: 1, Class: 1, Ttl: 60, }, }), }, }) } // For default route RadixTree.AddRegionToCache(&Region{ NetworkAddr: DefaultRadixNetaddr, NetworkMask: DefaultRadixNetMask, RR: []dns.RR{ dns.RR(&dns.A{ A: utils.Int32ToIP4(DefaultRadixNetaddr), Hdr: dns.RR_Header{ Rrtype: 1, Class: 1, Ttl: 60, }, }), }, }) for _, i := range ip2Find { ii := utils.Ip4ToInt32(utils.StrToIP(i)) r, e := RadixTree.GetRegionFromCacheWithAddr(ii, DefaultRadixSearchMask) if e != nil { t.Log(e) t.Log(i) t.Fail() } else { t.Log(r) } } RadixTree.Radix32.Do(func(r1 *bitradix.Radix32, i int) { t.Log(r1.Key(), r1.Value, r1.Bits()) }) }