func TestDNSUpstreamEncoding(t *testing.T) { var tmp [60]byte bad_domain := "www." + base32.StdEncoding.EncodeToString(tmp[:]) + "." if _, good := dns.IsDomainName(bad_domain); good { t.Errorf("Bad domain not detected: %v", bad_domain) } codec, err := NewDNSTransportUpstreamCodec("blahgeek.com") if err != nil { t.Fatalf("Unable to build codec: %v", err) } streamer := DNSTransportStream{codec: codec} for i := 0; i < 1500; i += 1 { var msg []byte for j := 0; j < i; j += 1 { msg = append(msg, byte(rand.Int()&0xff)) } var decoded_msg []byte upstreams := streamer.Encode(msg) for _, d := range upstreams { t.Logf("Encoded domain for msg length %v: %v", i, d) if _, good := dns.IsDomainName(d); !good { t.Errorf("Bad domain for msg length %v", i) } decoded_msg = streamer.Decode(d) } if bytes.Compare(decoded_msg, msg) != 0 { t.Errorf("Decoded msg != msg") } } }
func discoverDNS(domain string, port int) (servers []string, ttl time.Duration, err error) { r, _ := region() // all DNS queries must use the FQDN domain = "txt." + r + "." + dns.Fqdn(domain) if _, ok := dns.IsDomainName(domain); !ok { err = fmt.Errorf("invalid domain name: '%s' is not a domain name", domain) return } regionRecords, ttl, err := retryingFindTXT(domain) if err != nil { return } for _, az := range regionRecords { instances, _, er := retryingFindTXT("txt." + dns.Fqdn(az)) if er != nil { continue } for _, instance := range instances { // format the service URL servers = append(servers, fmt.Sprintf("http://%s:%d/eureka/v2", instance, port)) } } return }
// standardAddress parses an address string into a structured format with separate // host, and port portions, as well as the original input string. func standardAddress(str string) (address, error) { var err error // first check for scheme and strip it off input := str // separate host and port host, port, err := net.SplitHostPort(str) if err != nil { host, port, err = net.SplitHostPort(str + ":") // no error check here; return err at end of function } if len(host) > 255 { return address{}, fmt.Errorf("specified address is too long: %d > 255", len(host)) } _, d := dns.IsDomainName(host) if !d { return address{}, fmt.Errorf("host is not a valid domain: %s", host) } // see if we can set port based off scheme if port == "" { port = "53" } return address{Original: input, Host: strings.ToLower(dns.Fqdn(host)), Port: port}, err }
// update record func updateRecord(r dns.RR, q *dns.Question) { // record to update var rr dns.RR // IP of record var ip net.IP header := r.Header() if _, ok := dns.IsDomainName(header.Name); ok { if header.Class == dns.ClassANY && header.Rdlength == 0 { // Delete record deleteRecord(header.Name, header.Rrtype) } else { // Add record rheader := dns.RR_Header{ Name: header.Name, Rrtype: header.Rrtype, Class: dns.ClassINET, Ttl: header.Ttl, } // IPv4 only if a, ok := r.(*dns.A); ok { rrr, err := getRecord(header.Name, header.Rrtype) if err == nil { rr = rrr.(*dns.A) } else { rr = new(dns.A) } ip = a.A rr.(*dns.A).Hdr = rheader rr.(*dns.A).A = ip saveRecord(rr) } } } }
func getKey(domain string, rtype uint16) (r string, e error) { if *debug { Log.Printf("getKey: domain: %s, resource type: %d\n", domain, rtype) } if n, ok := dns.IsDomainName(domain); ok { labels := dns.SplitDomainName(domain) // Reverse domain, starting from top-level domain // eg. ".com.mkaczanowski.test " var tmp string for i := 0; i < int(math.Floor(float64(n/2))); i++ { tmp = labels[i] labels[i] = labels[n-1] labels[n-1] = tmp } reverseDomain := strings.Join(labels, ".") r = strings.Join([]string{reverseDomain, strconv.Itoa(int(rtype))}, "_") } else { e = errors.New("Invailid domain: " + domain) Log.Println(e.Error()) } return r, e }
// return formated key (domain_type) func formatKey(domain string, rtype uint16) (key string, err error) { domain = strings.ToLower(domain) if _, ok := dns.IsDomainName(domain); !ok { return "", errors.New(domain + " is not a valid domain") } key = domain + "_" + strconv.Itoa(int(rtype)) return }
func updateRecord(r dns.RR, q *dns.Question) { if *debug { Log.Printf("updateRecord: resource record: %+v, question: %+v\n", r, q) } var ( rr dns.RR name string rtype uint16 ttl uint32 ip net.IP ) header := r.Header() name = header.Name rtype = header.Rrtype ttl = header.Ttl if _, ok := dns.IsDomainName(name); ok { if header.Class == dns.ClassANY && header.Rdlength == 0 { // Delete record deleteRecord(name, rtype) } else { // Add record rheader := dns.RR_Header{ Name: name, Rrtype: rtype, Class: dns.ClassINET, Ttl: ttl, } if a, ok := r.(*dns.A); ok { rrr, err := getRecord(name, rtype) if err == nil { rr = rrr.(*dns.A) } else { rr = new(dns.A) } ip = a.A rr.(*dns.A).Hdr = rheader rr.(*dns.A).A = ip } else if a, ok := r.(*dns.AAAA); ok { rrr, err := getRecord(name, rtype) if err == nil { rr = rrr.(*dns.AAAA) } else { rr = new(dns.AAAA) } ip = a.AAAA rr.(*dns.AAAA).Hdr = rheader rr.(*dns.AAAA).AAAA = ip } storeRecord(rr) } } }
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()) }
// Preparation for Query A and CNAME / NS record. // param d : domain name to query // isEdns0 : either use edns0_subnet or not // return : // *MyError.Myerror // domain name server ip // domain name server port // *dns.OPT (for edns0_subnet) func preQuery(d, srcIP string) (*dns.OPT, *MyError.MyError) { if _, ok := dns.IsDomainName(d); !ok { // return "", "", nil, MyError.NewError(MyError.ERROR_PARAM, d+" is not a domain name!") } var o *dns.OPT if len(srcIP) > 0 { o = PackEdns0SubnetOPT(srcIP, DEFAULT_SOURCEMASK, DEFAULT_SOURCESCOPE) } else { o = nil } return o, nil }
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 HttpDispacherQueryServe(w http.ResponseWriter, r *http.Request) { url_path := r.URL.Path query_domain := r.URL.Query().Get("d") srcIP := r.URL.Query().Get("ip") if _, ok := dns.IsDomainName(query_domain); !ok { fmt.Fprintln(w, "Error domain name: ", query_domain) utils.ServerLogger.Info("error domain name : %s ", query_domain) return } if srcIP == "" { hp := strings.Split(r.RemoteAddr, ":") srcIP = hp[0] } utils.QueryLogger.Info("src ip: %s query_domain: %s url_path: %s", string(srcIP), query_domain, url_path) if x := net.ParseIP(srcIP); x == nil { w.WriteHeader(http.StatusForbidden) fmt.Fprint(w, srcIP) fmt.Fprintln(w, "src ip : "+srcIP+" is not correct") utils.ServerLogger.Warning("src ip : %s is not correct", srcIP) return } if config.InWhiteList(query_domain) { ok, re, e := query.GetARecord(query_domain, srcIP) if ok { w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) for _, ree := range re { if a, ok := ree.(*dns.A); ok { fmt.Fprintln(w, a.A.String()) utils.ServerLogger.Debug("query result: %s ", a.A.String()) } else { fmt.Fprintln(w, ree.String()) utils.ServerLogger.Debug("query result: %s ", ree.String()) } } } else if e != nil { fmt.Fprintln(w, e.Error()) utils.ServerLogger.Error("query domain: %s src_ip: %s %s", query_domain, srcIP, e.Error()) } else { fmt.Fprintln(w, "unkown error!\n") utils.ServerLogger.Error("query domain: %s src_ip: %s fail unkown error!", query_domain, srcIP) } } else { w.WriteHeader(http.StatusForbidden) fmt.Fprintln(w, "Query for domain: "+query_domain+" is not permited\n") utils.ServerLogger.Info("Query for domain: %s is not permited", query_domain) return } }
func NewDNSTransportUpstreamCodec(domain string) (*DNSTransportUpstreamCodec, error) { ret := DNSTransportUpstreamCodec{domain: domain + "."} var ok bool if ret.domain_label_count, ok = dns.IsDomainName(ret.domain); !ok { return nil, fmt.Errorf("Bad domain %d", domain) } name_len := 255 - len(ret.domain) name_len -= 9 // seq number (4 byte --base32--> 8byte) + '.' ret.max_len_per_name = name_len / 64 * DNS_UPSTREAM_MAX_LEN_PER_LABEL if tmp := name_len % 64; tmp > 9 { ret.max_len_per_name += (tmp - 1) / 8 * 5 } ret.header_codec = bitcodec.NewBitcodec(&DNSCodecHeader{}) return &ret, nil }
// Handler for DNS queries func query(w http.ResponseWriter, r *http.Request) { server := r.URL.Query().Get(":server") domain := dns.Fqdn(r.URL.Query().Get(":domain")) querytype := r.URL.Query().Get(":querytype") if domain, err := idna.ToASCII(domain); err == nil { // Valid domain name (ASCII or IDN) if _, isDomain := dns.IsDomainName(domain); isDomain { // Well-formed domain name if querytype, ok := dns.StringToType[strings.ToUpper(querytype)]; ok { // Valid DNS query type resolve(w, r, server, domain, querytype) } else { error(w, 400, 404, "Invalid DNS query type") } } else { error(w, 400, 402, "Input string is not a well-formed domain name") } } else { error(w, 400, 401, "Input string could not be parsed") } }
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 (dom Domain) addHandler(tld string) { fqdn := dom.Name if tld != "" { fqdn = dom.Name + "." + tld } FqdnParts, _ := dns.IsDomainName(fqdn) fmt.Printf("Adding: %v - %v nums\n", fqdn, FqdnParts) // Handle dns requests if it is really a fqdn if dns.IsFqdn(fqdn) { dns.HandleFunc(fqdn, func(w dns.ResponseWriter, req *dns.Msg) { m := new(dns.Msg) m.SetReply(req) m.Compress = true for i, q := range req.Question { fmt.Printf("Requested: %s, Type: %v\n", req.Question[i].Name, req.Question[i].Qtype) switch q.Qtype { case 1: fmt.Printf("Adding a record %v with ip %v", q.Name, dom.A.Ip) m.Answer = append(m.Answer, NewA(q.Name, dom.A.Ip, uint32(dom.A.Ttl))) case 15: fmt.Printf("Adding a record %v with ip %v", q.Name, dom.A.Ip) m.Answer = append(m.Answer, NewMX(q.Name, dom.Mx.Content, dom.Mx.Priority, uint32(dom.Mx.Ttl))) } } w.WriteMsg(m) }) } // add subdomains.. for _, d := range dom.Domains { d.addHandler(fqdn) } }
func dnsLookup(msg commands.Message, ret commands.MessageFunc) string { var lookupType, lookupAddr string if len(msg.Params) < 2 { return "Usage: .dns [A/AAAA/CNAME/PTR/TXT/SRV] [host]" } else if len(msg.Params) == 2 { lookupType = "A" lookupAddr = msg.Params[1] } else { lookupType = msg.Params[1] lookupAddr = msg.Params[2] } if strings.ToUpper(lookupType) == "PTR" { if addr, err := dns.ReverseAddr(lookupAddr); err == nil { return lookupHelper(msg, ret, dns.TypePTR, addr) } return "Invalid PTR address" } else if _, isdomain := dns.IsDomainName(lookupAddr); isdomain { if querytype, ok := dns.StringToType[strings.ToUpper(lookupType)]; ok { return lookupHelper(msg, ret, querytype, lookupAddr) } } return "" }
func validateStaticEntryFile(sef string) (StaticEntryConfig, error) { if len(sef) == 0 { return StaticEntryConfig{}, nil } if _, err := os.Stat(sef); os.IsNotExist(err) { return StaticEntryConfig{}, fmt.Errorf("StaticEntryFile not found: %s", sef) } conf, err := ParseStaticConfig(sef) for _, entry := range conf.Entries { switch entry.Type { case "A": ip := net.ParseIP(entry.Value) if ip == nil { return conf, fmt.Errorf("Invalid IP on StaticEntry: %q", entry.Value) } if !dns.IsFqdn(entry.Fqdn) { return conf, fmt.Errorf("Invalid FQDN: %s", entry.Fqdn) } break case "SRV": if _, ok := dns.IsDomainName(entry.Fqdn); !ok { return conf, fmt.Errorf("Invalid SRV FQDN: %s", entry.Fqdn) } if match, _ := regexp.MatchString(ValidHostPortRegex, entry.Value); !match { return conf, fmt.Errorf("Invalid (Host:Port) tuple: %s", entry.Value) } break default: return conf, fmt.Errorf("Unsupported Record Type: %s", entry.Type) } } return conf, err }
rr = &dns.TXT{header, []string{node.Value}} return }, dns.TypeCNAME: func(node *etcd.Node, header dns.RR_Header) (rr dns.RR, err error) { rr = &dns.CNAME{header, dns.Fqdn(node.Value)} return }, dns.TypeNS: func(node *etcd.Node, header dns.RR_Header) (rr dns.RR, err error) { rr = &dns.NS{header, dns.Fqdn(node.Value)} return }, dns.TypePTR: func(node *etcd.Node, header dns.RR_Header) (rr dns.RR, err error) { labels, ok := dns.IsDomainName(node.Value) if ok && labels > 0 { rr = &dns.PTR{header, dns.Fqdn(node.Value)} } else { err = &NodeConversionError{ Node: node, Message: fmt.Sprintf("Value '%s' isn't a valid domain name", node.Value), AttemptedType: dns.TypePTR} } return }, dns.TypeSRV: func(node *etcd.Node, header dns.RR_Header) (rr dns.RR, err error) { parts := strings.SplitN(node.Value, "\t", 4)
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") }