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")
}
Example #4
0
//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
}
Example #5
0
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!")
}
Example #6
0
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())
}
Example #7
0
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!")
}
Example #8
0
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)
}
Example #10
0
//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())
}
Example #11
0
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 "))
}
Example #12
0
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!")
}
Example #14
0
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")
}
Example #15
0
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
}
Example #16
0
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")
	}

}
Example #17
0
// 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)
	}
}
Example #18
0
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")
}
Example #19
0
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
}
Example #20
0
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
}
Example #21
0
// 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
}
Example #22
0
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 ")

}
Example #23
0
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"))
}
Example #24
0
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")
}
Example #25
0
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")
}
Example #26
0
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())

}