func ParseSOA(d string, r []dns.RR) (*dns.SOA, []*dns.NS, *MyError.MyError) { var soa *dns.SOA var ns_a []*dns.NS for _, v := range r { vh := v.Header() if vh.Name == dns.Fqdn(d) || dns.IsSubDomain(vh.Name, dns.Fqdn(d)) { switch vh.Rrtype { case dns.TypeSOA: if vv, ok := v.(*dns.SOA); ok { //fmt.Print(utils.GetDebugLine(), "ParseSOA: ", vv) soa = vv utils.ServerLogger.Debug("ParseSOA: %v", vv) } case dns.TypeNS: if vv, ok := v.(*dns.NS); ok { ns_a = append(ns_a, vv) } default: //fmt.Println(utils.GetDebugLine(), " PasreSOA: error unexpect: ", v) utils.ServerLogger.Error("ParseSOA: error unexpect %v", v) } } else { //fmt.Print(utils.GetDebugLine(), "ParseSOA 258 ") //fmt.Println(utils.GetDebugLine(), vh.Name+" not match "+d) utils.ServerLogger.Debug("%s not match %s", vh.Name, d) return nil, nil, MyError.NewError(MyError.ERROR_NOTVALID, d+" has no SOA record,try parent") } } if soa != nil { return soa, ns_a, nil } else { return nil, nil, MyError.NewError(MyError.ERROR_NORESULT, "No SOA record for domain "+d) } }
func (D *RR_MySQL) GetRegionWithIPFromMySQL(ip uint32) (*MySQLRegion, *MyError.MyError) { if e := D.DB.Ping(); e != nil { if ok := InitMySQL(RC_MySQLConf); ok != true { return nil, MyError.NewError(MyError.ERROR_UNKNOWN, "Connect MySQL Error") } } sqlstring := "Select idRegion, StartIP, EndIP, NetAddr, NetMask From " + RegionTable + " Where ? >= StartIP and ? <= EndIP" var idRegion, StartIP, EndIP, NetAddr, NetMask uint32 ee := D.DB.QueryRow(sqlstring, ip, ip).Scan(&idRegion, &StartIP, &EndIP, &NetAddr, &NetMask) switch { case ee == sql.ErrNoRows: utils.QueryLogger.Error(ee.Error()) return nil, MyError.NewError(MyError.ERROR_NOTFOUND, "Not found for Region for IP: "+strconv.Itoa(int(ip))) case ee != nil: utils.QueryLogger.Error(ee.Error()) return nil, MyError.NewError(MyError.ERROR_UNKNOWN, ee.Error()) default: utils.QueryLogger.Debug("GetRegionWithIPFromMySQL: ", " idRegion: ", idRegion, " StartIP: ", StartIP, " EndIP: ", EndIP, " NetAddr: ", NetAddr, " NetMask: ", NetMask, " srcIP: ", utils.Int32ToIP4(ip).String()) return &MySQLRegion{ IdRegion: idRegion, Region: &RegionNew{ StarIP: StartIP, EndIP: EndIP, NetAddr: NetAddr, NetMask: NetMask}, }, nil } return nil, MyError.NewError(MyError.ERROR_UNKNOWN, "Unknown error!") }
func GenerateParentDomain(d string) (string, *MyError.MyError) { x := dns.SplitDomainName(d) if cap(x) > 1 { // fmt.Println(x) return strings.Join(x[1:], "."), nil } else { return d, MyError.NewError(MyError.ERROR_NORESULT, d+" has no subdomain") } return d, MyError.NewError(MyError.ERROR_UNKNOWN, d+" unknown error") }
//Parse ip(uint32) and mask(int) to *net.IPNe func Int32ToIpNet(ip uint32, mask int) (*net.IPNet, *MyError.MyError) { if mask < 0 || mask > 32 { return nil, MyError.NewError(MyError.ERROR_NOTVALID, "invalid mask error, param: "+strconv.Itoa(mask)) } ipaddr := Int32ToIP4(ip) cidr := strings.Join([]string{ipaddr.String(), strconv.Itoa(mask)}, "/") _, ipnet, ok := net.ParseCIDR(cidr) if ok != nil { return nil, MyError.NewError(MyError.ERROR_NOTVALID, "ParseCIDR error, param: "+cidr) } return ipnet, nil }
func (ST *DomainSOATree) GetDomainSOANodeFromCache(dsn *DomainSOANode) (*DomainSOANode, *MyError.MyError) { ST.RWMutex.RLock() defer ST.RWMutex.RUnlock() if dt := ST.LLRB.Get(dsn); dt != nil { if dsn_r, ok := dt.(*DomainSOANode); ok { return dsn_r, nil } else { return nil, MyError.NewError(MyError.ERROR_TYPE, "ERROR_TYPE") } } else { return nil, MyError.NewError(MyError.ERROR_NOTFOUND, "Not found soa record from DomainSOACache via domainname "+dsn.SOAKey) } return nil, MyError.NewError(MyError.ERROR_UNKNOWN, "Unknown Error!") }
func (DT *DomainRRTree) GetDomainNodeFromCache(d *Domain) (*DomainNode, *MyError.MyError) { DT.RWMutex.RLock() defer DT.RWMutex.RUnlock() dr := DT.LLRB.Get(d) if dr != nil { if drr, ok := dr.(*DomainNode); ok { return drr, nil } else { return nil, MyError.NewError(MyError.ERROR_TYPE, "Got error result because of the type of return value is "+reflect.TypeOf(dr).String()) } } else { return nil, MyError.NewError(MyError.ERROR_NOTFOUND, "Not found DomainNode from DomainRRCache for param: "+reflect.ValueOf(d.DomainName).String()) } return nil, MyError.NewError(MyError.ERROR_UNKNOWN, "SearchDomainNode got param: "+reflect.ValueOf(d).String()) }
func GetAFromCache(dst, srcIP string) (*DomainNode, []dns.RR, *MyError.MyError) { dn, e := DomainRRCache.GetDomainNodeFromCacheWithName(dst) if e == nil && dn != nil && dn.DomainRegionTree != nil { //Get DomainNode succ, r, e := dn.DomainRegionTree.GetRegionFromCacheWithAddr( utils.Ip4ToInt32(net.ParseIP(srcIP)), DefaultRadixSearchMask) if e == nil && len(r.RR) > 0 { if r.RrType == dns.TypeA { utils.ServerLogger.Debug("GetAFromCache: Goooot A ", dst, srcIP, r.RR) return dn, r.RR, nil } else if r.RrType == dns.TypeCNAME { utils.ServerLogger.Debug("GetAFromCache: Goooot CNAME ", dst, srcIP, r.RR) return dn, r.RR, MyError.NewError(MyError.ERROR_CNAME, "Get CNAME From,Requery A for "+r.RR[0].(*dns.CNAME).Target) } } return dn, nil, MyError.NewError(MyError.ERROR_NOTFOUND, "Not found R in cache, dst :"+dst+" srcIP "+srcIP) // return } else if e == nil && dn != nil && dn.DomainRegionTree == nil { // Get domainNode in cache tree,but no RR in region tree,need query with NS // if RegionTree is nil, init RegionTree First ok, e := dn.InitRegionTree() if e != nil { utils.ServerLogger.Error("InitRegionTree fail %s", e.Error()) } // //fmt.Println("RegionTree is nil ,Init it: "+reflect.ValueOf(ok).String(), e) utils.ServerLogger.Debug("RegionTree is nil ,Init it: %s ", reflect.ValueOf(ok).String()) return dn, nil, MyError.NewError(MyError.ERROR_NORESULT, "Get domainNode in cache tree,but no RR in region tree,need query with NS, dst : "+dst+" srcIP "+srcIP) } else { // e != nil // RegionTree is not nil if e != nil { if e.ErrorNo != MyError.ERROR_NOTFOUND { //fmt.Println("Found unexpected error, need return !") utils.ServerLogger.Info("Not found, need return :", "error :", e, "dn:", dn) //os.Exit(2) } else { utils.ServerLogger.Critical("Found unexpected error, need return !", "error :", e, "dn:", dn) } } return nil, nil, e } return nil, nil, MyError.NewError(MyError.ERROR_UNKNOWN, "Unknown error!") }
func (RT *RegionTree) GetRegionFromCacheWithAddr(addr uint32, mask int) (*Region, *MyError.MyError) { RT.RWMutex.RLock() defer RT.RWMutex.RUnlock() if r := RT.Radix32.Find(addr, mask); r != nil && r.Value != nil { //fmt.Println(utils.GetDebugLine(), "GetRegionFromCacheWithAddr : ", r, addr, reflect.TypeOf(addr), mask, reflect.TypeOf(mask)) utils.ServerLogger.Debug("GetRegionFromCacheWithAddr: ", r, addr, reflect.TypeOf(addr), mask, reflect.TypeOf(mask)) if rr, ok := r.Value.(*Region); ok { return rr, nil } else { return nil, MyError.NewError(MyError.ERROR_NOTVALID, "Found result but not valid,need check !") } } else if addr != DefaultRadixNetaddr && mask != DefaultRadixNetMask { return RT.GetRegionFromCacheWithAddr(DefaultRadixNetaddr, DefaultRadixNetMask) } return nil, MyError.NewError(MyError.ERROR_NOTFOUND, "Not found search region "+string(addr)+":"+string(mask)) }
func GetIPinfoWithString(ip string) (Ipinfo, *MyError.MyError) { if ipdb := Il_open(DBFile); ipdb > 0 { defer Il_close(ipdb) nip := NewIp(ip) defer DeleteIp(nip) ipinfo := NewIpinfo() // defer DeleteIpinfo(ipinfo) "Can not delete ip info within this func! n := Il_search(nip, ipinfo, ipdb) if n > 0 { return ipinfo, nil } } else { return nil, MyError.NewError(MyError.ERROR_UNKNOWN, "Open ipdb file error :"+DBFile) } return nil, MyError.NewError(MyError.ERROR_NORESULT, "Can not get ipinfo with ip :"+ip) }
//ParseEdnsIPNet, Parse ends data to *net.IPNet func ParseEdnsIPNet(ip net.IP, mask uint8, family uint16) (*net.IPNet, *MyError.MyError) { cidr := strings.Join([]string{ip.String(), strconv.Itoa(int(mask))}, "/") _, ipnet, e := net.ParseCIDR(cidr) if e == nil { return ipnet, nil } return nil, MyError.NewError(MyError.ERROR_NOTVALID, e.Error()) }
func (a *Domain) Less(b llrb.Item) bool { if x, ok := b.(*DomainNode); ok { return a.DomainName < x.DomainName } else if y, ok := b.(*Domain); ok { return a.DomainName < y.DomainName } panic(MyError.NewError(MyError.ERROR_PARAM, "Param error of b ")) }
func (DT *DomainRRTree) GetDomainNodeFromCacheWithName(d string) (*DomainNode, *MyError.MyError) { if _, ok := dns.IsDomainName(d); ok { dn := &Domain{ DomainName: dns.Fqdn(d), } return DT.GetDomainNodeFromCache(dn) } return nil, MyError.NewError(MyError.ERROR_PARAM, "Eorror param: "+reflect.ValueOf(d).String()) }
func (D *RR_MySQL) GetDomainIDFromMySQL(d string) (int, *MyError.MyError) { if e := D.DB.Ping(); e != nil { if ok := InitMySQL(RC_MySQLConf); ok != true { return 0, MyError.NewError(MyError.ERROR_UNKNOWN, "Connect MySQL Error") } } sql_string := "Select idDomainName From " + DomainTable + " Where DomainName=?" var idDomainName int e := D.DB.QueryRow(sql_string, dns.Fqdn(d)).Scan(&idDomainName) switch { case e == sql.ErrNoRows: return 0, MyError.NewError(MyError.ERROR_NOTFOUND, "Not found record for DomainName:"+d) case e != nil: return -1, MyError.NewError(MyError.ERROR_UNKNOWN, e.Error()) default: // if id,e := strconv.Atoi(idDomainName); e== nil{ return idDomainName, nil // } } return -1, MyError.NewError(MyError.ERROR_UNKNOWN, "Unknown Error!") }
func (DT *DomainRRTree) UpdateDomainNode(d *DomainNode) (bool, *MyError.MyError) { if _, ok := dns.IsDomainName(d.DomainName); ok { if dt, err := DT.GetDomainNodeFromCache(&d.Domain); dt != nil && err == nil { d.DomainRegionTree = dt.DomainRegionTree DT.RWMutex.Lock() r := DT.LLRB.ReplaceOrInsert(d) DT.RWMutex.Unlock() if r != nil { return true, nil } else { //Exception:see source code of "LLRB.ReplaceOrInsert" return true, MyError.NewError(MyError.ERROR_UNKNOWN, "Update error, but inserted") } } else { return false, MyError.NewError(MyError.ERROR_NOTFOUND, "DomainRRTree does not has "+reflect.ValueOf(d).String()+" or it has "+reflect.ValueOf(dt).String()) } } else { return false, MyError.NewError(MyError.ERROR_PARAM, " Param d "+reflect.ValueOf(d).String()+" is not valid Domain instance") } return false, MyError.NewError(MyError.ERROR_UNKNOWN, "UpdateDomainNode return unknown error") }
func NewDomainNode(d string, soakey string, t uint32) (*DomainNode, *MyError.MyError) { if _, ok := dns.IsDomainName(d); !ok { return nil, MyError.NewError(MyError.ERROR_PARAM, d+" is not valid domain name") } return &DomainNode{ Domain: Domain{ DomainName: dns.Fqdn(d), SOAKey: soakey, TTL: t, }, DomainRegionTree: NewDomainRegionTree(), }, nil }
func (RT *RegionTree) DelRegionFromCache(r *Region) (bool, *MyError.MyError) { if rnode, e := RT.GetRegionFromCache(r); rnode != nil && e == nil { RT.RWMutex.Lock() RT.Radix32.Remove(r.NetworkAddr, r.NetworkMask) RT.RWMutex.Unlock() //fmt.Println(utils.GetDebugLine(), "Remove Region from RegionCache "+string(r.NetworkAddr)+":"+string(r.NetworkMask)) utils.ServerLogger.Debug("Remove Region from RegionCache %s : %s", string(r.NetworkAddr), string(r.NetworkMask)) return true, nil } else { return true, MyError.NewError(MyError.ERROR_NOTFOUND, "Not found Region from RegionCache") } }
// General Query for dns upstream query // param: t string ["tcp"|"udp] // queryType uint16 dns.QueryType func DoQuery( domainName string, domainResolverIP []string, domainResolverPort string, queryType uint16, queryOpt *dns.OPT, t string) (*dns.Msg, *MyError.MyError) { c := ClientPool.Get().(*dns.Client) defer func(c *dns.Client) { go func() { RenewDnsClient(c) ClientPool.Put(c) }() }(c) c.Net = t // m := &dns.Msg{} m := DnsMsgPool.Get().(*dns.Msg) defer func(m *dns.Msg) { go func() { RenewDnsMsg(m) DnsMsgPool.Put(m) }() }(m) m.AuthenticatedData = true m.RecursionDesired = true // m.Truncated= false m.SetQuestion(dns.Fqdn(domainName), queryType) if queryOpt != nil { m.Extra = append(m.Extra, queryOpt) } var x = make(chan *dns.Msg) var closesig = make(chan struct{}) for _, ds := range domainResolverIP { go func(c *dns.Client, m *dns.Msg, ds, dp string, queryType uint16, closesig chan struct{}) { select { case x <- doQuery(*c, *m, ds, domainResolverPort, queryType, closesig): default: } }(c, m, ds, domainResolverPort, queryType, closesig) } if r := <-x; r != nil { close(closesig) return r, nil } else { return nil, MyError.NewError(MyError.ERROR_UNKNOWN, "Query failed "+domainName) } }
func GetSOARecord(d string) (*DomainSOANode, *MyError.MyError) { var soa *DomainSOANode dn, e := DomainRRCache.GetDomainNodeFromCacheWithName(d) if e == nil && dn != nil { dsoa_key := dn.SOAKey soa, e = DomainSOACache.GetDomainSOANodeFromCacheWithDomainName(dsoa_key) utils.ServerLogger.Debug("GetDomainSOANodeFromCacheWithDomainName: key: %s soa %v", dsoa_key, soa) if e == nil && soa != nil { return soa, nil } else { // error == nil bug soa record also == nil utils.ServerLogger.Critical("GetSOARecord->GetDomainSOANodeFromCacheWithDomainName unknown error") } } soa_t, ns, e := QuerySOA(d) // Need to store DomainSOANode and DomainNOde both if e == nil && soa_t != nil && ns != nil { soa = NewDomainSOANode(soa_t, ns) go func(d string, soa *DomainSOANode) { //TODO: get StoreDomainSOANode return values _, e := DomainSOACache.StoreDomainSOANodeToCache(soa) if e != nil { utils.ServerLogger.Error("DomainSOACache.StoreDomainSOANodeToCache return error :", e, " param :", soa) } else { utils.ServerLogger.Debug("DomainSOACache.StoreDomainSOANodeToCache return OK", soa) } rrnode, _ := NewDomainNode(d, soa.SOAKey, soa.SOA.Expire) _, e = DomainRRCache.StoreDomainNodeToCache(rrnode) if e != nil { utils.ServerLogger.Error("DomainRRCache.StoreDomainNodeToCache return error :", e, " param :", rrnode) } else { utils.ServerLogger.Debug("DomainRRCache.StoreDomainNodeToCache return ok", rrnode) } }(d, soa) return soa, nil } // QuerySOA fail return nil, MyError.NewError(MyError.ERROR_UNKNOWN, "Finally GetSOARecord failed") }
func QueryNS(d string) ([]*dns.NS, *MyError.MyError) { // ds, dp, _, e := preQuery(d, false) cf, _ := dns.ClientConfigFromFile("/etc/resolv.conf") e := &MyError.MyError{} r := &dns.Msg{} // for c := 0; (c < 3) && cap(r.Answer) < 1; c++ { r, e = DoQuery(d, cf.Servers, cf.Port, dns.TypeNS, nil, "udp") if (e == nil) && (cap(r.Answer) > 0) { b, ns_a := ParseNS(r.Answer) if b != false { return ns_a, nil } else { return nil, MyError.NewError(MyError.ERROR_NORESULT, "ParseNS() has no result returned") } // } } return nil, e }
func NewRegion(r []dns.RR, networkAddr uint32, networkMask int) (*Region, *MyError.MyError) { if len(r) < 1 { return nil, MyError.NewError(MyError.ERROR_PARAM, "cap of r ([]dns.RR) can not be less than 1 ") } else { //fmt.Println(utils.GetDebugLine(), "NewRegion: ", // " r: ", r, " networkAddr: ", networkAddr, " networkMask: ", networkMask) utils.ServerLogger.Debug("NewRegion: r: ", r, " networkAddr: ", networkAddr, " networkMask: ", networkMask) } dr := &Region{ NetworkAddr: networkAddr, NetworkMask: networkMask, // IpStart: ipStart, // IpEnd: ipEnd, RR: r, RrType: r[0].Header().Rrtype, TTL: r[0].Header().Ttl, UpdateTime: time.Now(), } return dr, nil }
// Query func QueryCNAME(d, srcIP string, ds []string, dp string) ([]*dns.CNAME, *dns.RR_Header, *dns.EDNS0_SUBNET, *MyError.MyError) { o, e := preQuery(d, srcIP) r, e := DoQuery(d, ds, dp, dns.TypeCNAME, o, UDP) if e != nil { return nil, nil, nil, e } //fmt.Println(utils.GetDebugLine(), r) //fmt.Println(utils.GetDebugLine(), e) cname_a, ok := ParseCNAME(r.Answer, d) if ok != true { return nil, nil, nil, MyError.NewError(MyError.ERROR_NORESULT, "No CNAME record returned") } utils.ServerLogger.Debug("QueryCNAME domain: %s srcip: %s result: %v", d, srcIP, cname_a) var edns_header *dns.RR_Header var edns *dns.EDNS0_SUBNET if len(srcIP) > 0 { if x := r.IsEdns0(); x != nil { edns_header, edns = parseEdns0subnet(x) } } return cname_a, edns_header, edns, nil }
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 (DS *DomainSOANode) Less(b llrb.Item) bool { if x, ok := b.(*DomainSOANode); ok { return DS.SOAKey < x.SOAKey } panic(MyError.NewError(MyError.ERROR_PARAM, "Param b "+reflect.ValueOf(b).String()+" is not valid DomainSOANode or String")) }
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 QuerySOA(d string) (*dns.SOA, []*dns.NS, *MyError.MyError) { //fmt.Println(utils.GetDebugLine(), " QuerySOA: ", d) utils.ServerLogger.Debug(" QuerySOA domain: %s ", d) if _, ok := dns.IsDomainName(d); !ok { return nil, nil, MyError.NewError(MyError.ERROR_PARAM, d+" is not a domain name") } cf, el := dns.ClientConfigFromFile("/etc/resolv.conf") if el != nil { return nil, nil, MyError.NewError(MyError.ERROR_UNKNOWN, "Get dns config from file /etc/resolv.conf failed") } var soa *dns.SOA var ns_a []*dns.NS for c := 0; (soa == nil) && (c < 3); c++ { soa, ns_a = nil, nil r, e := DoQuery(d, cf.Servers, cf.Port, dns.TypeSOA, nil, UDP) // fmt.Println(r) if e != nil { utils.QueryLogger.Error("QeurySOA got error : "+e.Error()+ ". Param: %s , %v, %s, %v ", d, cf.Servers, cf.Port, dns.TypeSOA) continue } else { var rr []dns.RR if r.Answer != nil { rr = append(rr, r.Answer...) } if r.Ns != nil { rr = append(rr, r.Ns...) } soa, ns_a, e = ParseSOA(d, rr) if e != nil { switch e.ErrorNo { case MyError.ERROR_SUBDOMAIN, MyError.ERROR_NOTVALID: utils.ServerLogger.Error("ERROR_NOTVALID: %s", e.Error()) var ee *MyError.MyError d, ee = GenerateParentDomain(d) if ee != nil { if ee.ErrorNo == MyError.ERROR_NORESULT { // fmt.Println(ee) // continue } return nil, nil, MyError.NewError(MyError.ERROR_NORESULT, d+" has no SOA record "+" because of "+ee.Error()) } continue case MyError.ERROR_NORESULT: // c++ //fmt.Println(utils.GetDebugLine(), e) utils.ServerLogger.Error("ERROR_NORESULT: %s", e.Error()) //fmt.Println("+++++++++++++++++++++++++++++++++++") continue default: // c++ utils.ServerLogger.Error("ERROR_DEFAULT: %s", e.Error()) //fmt.Println(utils.GetDebugLine(), ".....................") //fmt.Println(utils.GetDebugLine(), e) continue // return nil, nil, e } } else { if cap(ns_a) < 1 { //fmt.Println(utils.GetDebugLine(), "QuerySOA: line 223: cap(ns_a)<1, need QueryNS ", soa.Hdr.Name) utils.ServerLogger.Debug("QuerySOA: cap(ns_a)<1, need QueryNS: %s", soa.Hdr.Name) ns_a, e = QueryNS(soa.Hdr.Name) if e != nil { //TODO: do some log } } // fmt.Println("============xxxxxx================") //fmt.Println(utils.GetDebugLine(), "QuerySOA: soa record ", soa, " ns_a: ", ns_a) utils.ServerLogger.Debug("QuerySOA: soa record %v ns_a: %v", soa, ns_a) return soa, ns_a, nil } } } return nil, nil, MyError.NewError(MyError.ERROR_UNKNOWN, d+" QuerySOA faild with unknow error") }
func GetARecord(d string, srcIP string) (bool, []dns.RR, *MyError.MyError) { var Regiontree *RegionTree var bigloopflag bool = false // big loop flag var c = 0 //big loop count //Can't loop for CNAME chain than bigger than CNAME_CHAIN_LENGTH for dst := d; (bigloopflag == false) && (c < CNAME_CHAIN_LENGTH); c++ { utils.ServerLogger.Debug("Trying GetARecord : %s srcIP: %s", dst, srcIP) dn, RR, e := GetAFromCache(dst, srcIP) utils.ServerLogger.Debug("GetAFromCache return: ", dn, RR, e) if e == nil { // All is right and especilly RR is A record return true, RR, nil } else { //Return Cname record if (e.ErrorNo == MyError.ERROR_CNAME) && (dn != nil) && (RR != nil) { if dst_cname, ok := RR[0].(*dns.CNAME); ok { dst = dst_cname.Target continue } else { utils.ServerLogger.Error("dn:", dn, "RR:", RR, "e:", e) } } else { // hava domain node ,but region node is nil,need queryA utils.ServerLogger.Error("error get dn:", dn, "RR:", RR, "e:", e, "need query A from dns/mysql backend") } } utils.ServerLogger.Info("Need to get dst from backend: ", dst, " srcIP: ", srcIP) //fmt.Println(utils.GetDebugLine(), "++++++++++++++++++++++++++++++++++++++++++++++") if config.IsLocalMysqlBackend(dst) { //fmt.Println(utils.GetDebugLine(), "**********************************************") //need pass dn to GetAFromMySQLBackend, to fill th dn.RegionTree node ok, RR, rtype, ee := GetAFromMySQLBackend(dst, srcIP, Regiontree) //fmt.Println(utils.GetDebugLine(), " Debug: GetAFromMySQLBackend: return ", ok, // " RR: ", RR, " error: ", ee) utils.ServerLogger.Debug("GetAFromMySQLBackend: return ", ok, RR, rtype, ee) if !ok { //fmt.Println(utils.GetDebugLine(), "Error: GetAFromMySQL error : ", ee) utils.ServerLogger.Error("Error: GetAFromMySQL error : ", ee) } else if rtype == dns.TypeA { //fmt.Println(utils.GetDebugLine(), "Info: Got A record, : ", RR) utils.ServerLogger.Debug("Got A record: ", RR) return true, RR, nil } else if rtype == dns.TypeCNAME { //fmt.Println(utils.GetDebugLine(), "Info: Got CNAME record, ReGet dst : ", dst, RR) utils.ServerLogger.Debug("Got CNAME record, ReGet dst: ", dst, RR) dst = RR[0].(*dns.CNAME).Target continue } } else { //fmt.Println(utils.GetDebugLine(), "Info: Got dst: ", dst, " srcIP: ", srcIP, " soa.NS: ", soa.NS) ok, rr_i, rtype, ee := GetAFromDNSBackend(dst, srcIP) //go func() { // AddAToCache() //}() if ok && rtype == dns.TypeA { return true, rr_i, nil } else if ok && rtype == dns.TypeCNAME { dst = rr_i[0].(*dns.CNAME).Target continue } else if !ok && rr_i == nil && ee != nil && ee.ErrorNo == MyError.ERROR_NORESULT { continue } else { return false, nil, MyError.NewError(MyError.ERROR_UNKNOWN, "Unknown error") } } } //fmt.Println(utils.GetDebugLine(), "GetARecord: ", Regiontree) return false, nil, MyError.NewError(MyError.ERROR_UNKNOWN, "Unknown error") }
func (D *RR_MySQL) GetRRFromMySQL(domainId, regionId uint32) (*MySQLRR, *MyError.MyError) { if e := D.DB.Ping(); e != nil { if ok := InitMySQL(RC_MySQLConf); ok != true { return nil, MyError.NewError(MyError.ERROR_UNKNOWN, "Connect MySQL Error") } } sqlstring := "Select idRRTable, Rrtype, Class, Ttl, Target From " + RRTable + " where idDomainName = ? and idRegion = ?" rows, e := D.DB.Query(sqlstring, domainId, regionId) if e == nil { var MyRR *MySQLRR var rtype_tmp uint16 var isHybird bool = false //if both hava dns.TypeA and dns.TypeCNAME, isHybird is true ,else false var uu []uint32 var u, v uint32 // u is for idRRTable, v is for Ttl var w, x uint16 // w is for Rrtype(5 for dns.TypdCNAME and 1 for dns.TypeA), var zz []string // for Target(s) var z string var rows_count int for rows.Next() { rows_count++ e := rows.Scan(&u, &w, &x, &v, &z) if e == nil { utils.QueryLogger.Debug(" got row : %v,%v,%v,%v,%v ", u, w, x, v, z) if (rtype_tmp != uint16(0)) && (rtype_tmp != w) { isHybird = true rtype_tmp = w utils.QueryLogger.Debug(" got row: %v,%v,%v,%v,%v,%v,%v", rtype_tmp, w, u, x, v, z, isHybird) //rtype is not same as previous one } else { uu = append(uu, u) zz = append(zz, z) } } else { utils.QueryLogger.Error(" rows.Scan error %s ,%v", e.Error(), rows.Err()) return nil, MyError.NewError(MyError.ERROR_NOTVALID, e.Error()+rows.Err().Error()) } } if rows_count > 0 { utils.QueryLogger.Debug("get uu: %v, zz: %v", uu, zz) if isHybird { utils.QueryLogger.Info("Both TypeA and TypeCNAME for domain: " + strconv.Itoa(int(domainId)) + " and Regionid :" + strconv.Itoa(int(regionId)) + ", that's not good !") MyRR = nil } else { MyRR = &MySQLRR{ idRR: uu, RR: &RRNew{ RrType: w, Class: x, Target: zz, }, } return MyRR, nil } } else { return nil, MyError.NewError(MyError.ERROR_NORESULT, "No Result for domainId : "+strconv.Itoa(int(domainId))+" RegionID: "+strconv.Itoa(int(regionId))) } } utils.QueryLogger.Error("MySQL query error: %v", e) return nil, MyError.NewError(MyError.ERROR_UNKNOWN, e.Error()) }