func newRR(q dns.Question, i instance) dns.RR { hdr := dns.RR_Header{ Name: q.Name, Rrtype: q.Qtype, Class: dns.ClassINET, Ttl: defaultTTL, } switch q.Qtype { case dns.TypeA: return &dns.A{ Hdr: hdr, A: i.ip, } case dns.TypeSRV: return &dns.SRV{ Hdr: hdr, Priority: 0, Weight: 0, Port: i.port, Target: dns.Fqdn(i.host), } case dns.TypeNS: return &dns.NS{ Hdr: hdr, Ns: dns.Fqdn(i.host), } default: panic("unreachable") } }
func (v *Value) RRs(out []dns.RR, suffix, apexSuffix string) ([]dns.RR, error) { il := len(out) suffix = dns.Fqdn(suffix) apexSuffix = dns.Fqdn(apexSuffix) out, _ = v.appendNSs(out, suffix, apexSuffix) if len(v.NS) == 0 { out, _ = v.appendTranslate(out, suffix, apexSuffix) if !v.HasTranslate { out, _ = v.appendAlias(out, suffix, apexSuffix) if !v.HasAlias { out, _ = v.appendIPs(out, suffix, apexSuffix) out, _ = v.appendIP6s(out, suffix, apexSuffix) out, _ = v.appendTXTs(out, suffix, apexSuffix) out, _ = v.appendMXs(out, suffix, apexSuffix) out, _ = v.appendSRVs(out, suffix, apexSuffix) out, _ = v.appendTLSA(out, suffix, apexSuffix) } } } out, _ = v.appendDSs(out, suffix, apexSuffix) xout := out[il:] for i := range xout { h := xout[i].Header() if rrtypeHasPrefix(h.Rrtype) { h.Name += suffix } else { h.Name = suffix } } return out, nil }
func (r *RFC2136Provider) Init(rootDomainName string) error { var host, port, keyName, secret string if host = os.Getenv("RFC2136_HOST"); len(host) == 0 { return fmt.Errorf("RFC2136_HOST is not set") } if port = os.Getenv("RFC2136_PORT"); len(port) == 0 { return fmt.Errorf("RFC2136_PORT is not set") } if keyName = os.Getenv("RFC2136_TSIG_KEYNAME"); len(keyName) == 0 { return fmt.Errorf("RFC2136_TSIG_KEYNAME is not set") } if secret = os.Getenv("RFC2136_TSIG_SECRET"); len(secret) == 0 { return fmt.Errorf("RFC2136_TSIG_SECRET is not set") } r.nameserver = net.JoinHostPort(host, port) r.zoneName = dns.Fqdn(rootDomainName) r.tsigKeyName = dns.Fqdn(keyName) r.tsigSecret = secret logrus.Infof("Configured %s with zone '%s' and nameserver '%s'", r.GetName(), r.zoneName, r.nameserver) return nil }
func addresses(conf *dns.ClientConfig, c *dns.Client, name string) []string { m4 := new(dns.Msg) m4.SetQuestion(dns.Fqdn(os.Args[1]), dns.TypeA) m6 := new(dns.Msg) m6.SetQuestion(dns.Fqdn(os.Args[1]), dns.TypeAAAA) addr := make(chan []string) defer close(addr) c.Do(m4, conf.Servers[0]+":"+conf.Port, addr, qhandler) c.Do(m6, conf.Servers[0]+":"+conf.Port, addr, qhandler) var ips []string i := 2 // two outstanding queries forever: for { select { case ip := <-addr: ips = append(ips, ip...) i-- if i == 0 { break forever } } } return ips }
func VerifyTargetHandler(w http.ResponseWriter, req *http.Request) { if !checkAuth(req, authuser, authpassword) { UnauthorizedResponse(w) return } hostname1 := dns.Fqdn(mux.Vars(req)["hostname1"]) hostname2 := dns.Fqdn(mux.Vars(req)["hostname2"]) nocache := req.URL.Query().Get("nocache") != "" target_alias := req.URL.Query().Get("target_alias") if target_alias != "" { target_alias = dns.Fqdn(target_alias) } vr, err := VerifyTarget(hostname1, hostname2, target_alias, nocache) if err != nil { w.WriteHeader(500) json.NewEncoder(w).Encode(vr.Error) return } json.NewEncoder(w).Encode(vr) return }
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 }
func (c *Client) lookupIPs(host string) (ips []net.IP, err error) { m := new(dns.Msg) for _, resolver := range c.Resolvers { m.SetQuestion(dns.Fqdn(host), dns.TypeA) if in, err := dns.Exchange(m, resolver); err == nil { for _, rr := range in.Answer { if a, ok := rr.(*dns.A); ok { ips = append(ips, a.A) } } } else { log.Debug(err) } m.SetQuestion(dns.Fqdn(host), dns.TypeAAAA) if in, err := dns.Exchange(m, resolver); err == nil { for _, rr := range in.Answer { if aaaa, ok := rr.(*dns.AAAA); ok { ips = append(ips, aaaa.AAAA) } } } else { log.Debug(err) } } if len(ips) != 0 { return ips, nil } return net.LookupIP(host) }
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) } }
// Get IP addresses related to the given local hostname func (m *mdns) Resolve(host string) []net.IP { results := make(chan dns.RR) m.queries <- &query{ questions: []dns.Question{ dns.Question{dns.Fqdn(host), dns.TypeA, dns.ClassINET}, dns.Question{dns.Fqdn(host), dns.TypeAAAA, dns.ClassINET}, }, results: results, } ipset := map[string]net.IP{} ips := []net.IP{} for rr := range results { var ip net.IP switch rr := rr.(type) { case *dns.A: ip = rr.A case *dns.AAAA: ip = make([]byte, 16) copy(ip, rr.AAAA[:]) default: continue } if _, ok := ipset[ip.String()]; !ok { ipset[ip.String()] = ip ips = append(ips, ip) } } return ips }
func (s *Service) UpdateAlias(zone string, ttl uint32, from, to *Device) error { for _, r := range from.Aliases { if to.HasAlias(r) { continue } fmt.Printf("EXTRA ALIAS: %s\n", r) cname := &dns.CNAME{ Hdr: dns.RR_Header{Name: dns.Fqdn(r), Rrtype: dns.TypeCNAME, Class: dns.ClassINET}, Target: dns.Fqdn(to.Name), } fmt.Println(cname) if err := s.RemoveRRset(zone, []dns.RR{cname}); err != nil { return err } } for _, r := range to.Aliases { if from.HasAlias(r) { continue } fmt.Printf("MISSING ALIAS: %s\n", r) cname := &dns.CNAME{ Hdr: dns.RR_Header{Name: dns.Fqdn(r), Rrtype: dns.TypeCNAME, Class: dns.ClassINET}, Target: dns.Fqdn(from.Name), } fmt.Println(cname) if err := s.RemoveRRset(zone, []dns.RR{cname}); err != nil { return err } if err := s.Insert(zone, []dns.RR{cname}); err != nil { return err } } return nil }
// Dynamically remove a full set of RR records stored in DNS func (s *Service) RemoveName(zone string, rr []dns.RR) error { m := new(dns.Msg) m.SetUpdate(zone) m.SetTsig(dns.Fqdn(s.Key), dns.HmacMD5, 300, time.Now().Unix()) m.RemoveName(rr) h, err := s.ServerPort() if err != nil { return err } c := new(dns.Client) c.TsigSecret = map[string]string{dns.Fqdn(s.Key): s.Secret} r, _, err := c.Exchange(m, h) if err != nil { return err } if r.Rcode != dns.RcodeSuccess { return errors.New(fmt.Sprintf("invalid exchange answer")) } return nil }
func (answers *Answers) Addresses(clientIp string, fqdn string, cnameParents []dns.RR, depth int) (records []dns.RR, ok bool) { fqdn = dns.Fqdn(fqdn) log.WithFields(log.Fields{"fqdn": fqdn, "client": clientIp, "depth": depth}).Debug("Trying to resolve addresses") // Limit recursing for non-obvious loops if len(cnameParents) >= 10 { log.WithFields(log.Fields{"fqdn": fqdn, "client": clientIp}).Warn("Followed CNAME too many times ", cnameParents) return nil, false } // Look for a CNAME entry result, ok := answers.Matching(dns.TypeCNAME, clientIp, fqdn) if ok && len(result) > 0 { cname := result[0].(*dns.CNAME) log.WithFields(log.Fields{"fqdn": fqdn, "client": clientIp}).Debug("Matched CNAME ", cname.Target) // Stop obvious loops if dns.Fqdn(cname.Target) == fqdn { log.WithFields(log.Fields{"fqdn": fqdn, "client": clientIp}).Warn("CNAME is a loop ", cname.Target) return nil, false } // Recurse to find the eventual A for this CNAME children, ok := answers.Addresses(clientIp, dns.Fqdn(cname.Target), append(cnameParents, cname), depth+1) if ok && len(children) > 0 { log.WithFields(log.Fields{"fqdn": fqdn, "target": cname.Target, "client": clientIp}).Debug("Resolved CNAME ", children) records = append(records, cname) records = append(records, children...) return records, true } } // Look for an A entry result, ok = answers.Matching(dns.TypeA, clientIp, fqdn) if ok && len(result) > 0 { log.WithFields(log.Fields{"fqdn": fqdn, "client": clientIp}).Debug("Matched A ", result) shuffle(&result) return result, true } // Try the default section of the config if clientIp != DEFAULT_KEY { return answers.Addresses(DEFAULT_KEY, fqdn, cnameParents, depth+1) } // When resolving CNAMES, check recursive server if len(cnameParents) > 0 { log.WithFields(log.Fields{"fqdn": fqdn, "client": clientIp}).Debug("Trying recursive servers") r := new(dns.Msg) r.SetQuestion(fqdn, dns.TypeA) msg, err := ResolveTryAll(r, answers.Recursers(clientIp)) if err == nil { return msg.Answer, true } } log.WithFields(log.Fields{"fqdn": fqdn, "client": clientIp}).Debug("Did not match anything") return nil, false }
func lookupHost(host string, config *dns.ClientConfig) (addrs []string, err error) { if utilNet.IsValidIpv4(host) || utilNet.IsValidIpv6(host) { return []string{host}, nil } if host == "localhost" { return []string{"127.0.0.1", "::1"}, nil } c := new(dns.Client) c.DialTimeout = DialTimeout c.ReadTimeout = ReadTimeout c.WriteTimeout = WriteTimeout m := new(dns.Msg) m.SetQuestion(dns.Fqdn(host), dns.TypeA) var r *dns.Msg for i := 0; i < len(config.Servers); i++ { r, _, err = c.Exchange(m, config.Servers[i]+":"+config.Port) if err != nil { continue } err = nil } if err != nil { return nil, e.Forward(err) } if r.Rcode != dns.RcodeSuccess { return nil, e.New("can't resolve %v", host) } addrs = make([]string, 0, 10) for _, a := range r.Answer { if addr, ok := a.(*dns.A); ok { addrs = append(addrs, addr.A.String()) } } m.SetQuestion(dns.Fqdn(host), dns.TypeAAAA) for i := 0; i < len(config.Servers); i++ { r, _, err = c.Exchange(m, config.Servers[0]+":"+config.Port) if err != nil { continue } err = nil } if err != nil { return nil, e.Forward(err) } if r.Rcode != dns.RcodeSuccess { return nil, e.New("no success") } for _, a := range r.Answer { if addr, ok := a.(*dns.AAAA); ok { addrs = append(addrs, addr.AAAA.String()) } } return }
//todo: complete this func func InWhiteList(d string) bool { d = dns.Fqdn(d) for _, x := range RC.Domains { if d == dns.Fqdn(x) { return true } } return false }
// dnsCNAME returns a DNS CNAME record struct func dnsCNAME(src, dest string) *dns.CNAME { return &dns.CNAME{ Hdr: dns.RR_Header{ Name: dns.Fqdn(src), Rrtype: dns.TypeCNAME, Class: dns.ClassINET, }, Target: dns.Fqdn(dest), } }
func setDefaults(config *Config) error { if config.ReadTimeout == 0 { config.ReadTimeout = 2 * time.Second } if config.DnsAddr == "" { config.DnsAddr = "127.0.0.1:53" } if config.Domain == "" { config.Domain = "skydns.local." } if config.Hostmaster == "" { config.Hostmaster = "hostmaster." + config.Domain } // People probably don't know that SOA's email addresses cannot // contain @-signs, replace them with dots config.Hostmaster = dns.Fqdn(strings.Replace(config.Hostmaster, "@", ".", -1)) if config.MinTtl == 0 { config.MinTtl = 60 } if config.Ttl == 0 { config.Ttl = 3600 } if config.Priority == 0 { config.Priority = 10 } if len(config.Nameservers) == 0 { c, err := dns.ClientConfigFromFile("/etc/resolv.conf") if err != nil { return err } for _, s := range c.Servers { config.Nameservers = append(config.Nameservers, net.JoinHostPort(s, c.Port)) } } config.Domain = dns.Fqdn(strings.ToLower(config.Domain)) config.DomainLabels = dns.CountLabel(config.Domain) if config.DNSSEC != "" { // For some reason the + are replaces by spaces in etcd. Re-replace them keyfile := strings.Replace(config.DNSSEC, " ", "+", -1) k, p, err := ParseKeyFile(keyfile) if err != nil { return err } if k.Header().Name != dns.Fqdn(config.Domain) { return fmt.Errorf("ownername of DNSKEY must match SkyDNS domain") } k.Header().Ttl = config.Ttl config.PubKey = k config.KeyTag = k.KeyTag() config.PrivKey = p config.ClosestEncloser, config.DenyWildcard = newNSEC3CEandWildcard(config.Domain, config.Domain, config.MinTtl) } return nil }
// Deal with the zone options func configZONE(w dns.ResponseWriter, req *dns.Msg, t *dns.TXT, c *Config) error { sx := strings.Split(t.Txt[0], " ") if len(sx) == 0 { return nil } switch strings.ToUpper(sx[0]) { case "READ": if len(sx) != 3 { return nil } logPrintf("config READ %s %s\n", dns.Fqdn(sx[1]), sx[2]) if e := c.ReadZoneFile(dns.Fqdn(sx[1]), sx[2]); e != nil { logPrintf("failed to read %s: %s\n", sx[2], e.Error()) return e } logPrintf("config added: READ %s %s\n", dns.Fqdn(sx[1]), sx[2]) noerr(w, req) case "READXFR": if len(sx) != 3 { return nil } logPrintf("config READXFR %s %s\n", dns.Fqdn(sx[1]), sx[2]) if e := c.ReadZoneXfr(dns.Fqdn(sx[1]), sx[2]); e != nil { logPrintf("failed to axfr %s: %s\n", sx[2], e.Error()) return e } logPrintf("config added: READXFR %s %s\n", dns.Fqdn(sx[1]), sx[2]) noerr(w, req) case "DROP": if len(sx) != 2 { return nil } logPrintf("config DROP %s\n", dns.Fqdn(sx[1])) if e := c.DropZone(dns.Fqdn(sx[1])); e != nil { logPrintf("Failed to drop %s: %s\n", dns.Fqdn(sx[1]), e.Error()) return e } logPrintf("config dropped: DROP %s\n", dns.Fqdn(sx[1])) noerr(w, req) case "LIST": logPrintf("config LIST\n") m := new(dns.Msg) m.SetReply(req) // Add the zones to the additional section for zone, _ := range c.Zones { a, _ := dns.NewRR("ZONE. TXT \"" + zone + "\"") m.Extra = append(m.Extra, a) } m.SetTsig(userFromTsig(req), dns.HmacMD5, 300, time.Now().Unix()) w.WriteMsg(m) } return nil }
func IsLocalMysqlBackend(d string) bool { d = dns.Fqdn(d) if !RC.MySQLEnabled { return false } for _, x := range RC.MySQLConf.DomainsInMySQL { if d == dns.Fqdn(x) { return true } } return false }
func (r *dnsResolver) findReverse(address string) (hosts []string) { r.hostMutex.RLock() defer r.hostMutex.RUnlock() address = strings.ToLower(dns.Fqdn(address)) for _, entry := range r.hosts { if r, _ := dns.ReverseAddr(entry.Address.String()); address == r && len(entry.Names) > 0 { hosts = append(hosts, dns.Fqdn(entry.Names[0])) } } return }
func TestProtocolHandler(t *testing.T) { var ( answers = rand.Intn(12) + 3 want = answers / 2 testHandler = dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) { res := &dns.Msg{} for i := 0; i < answers; i++ { rr := &dns.A{ Hdr: dns.RR_Header{ Name: r.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 5, }, A: net.ParseIP(fmt.Sprintf("1.2.3.%d", i)), } res.Answer = append(res.Answer, rr) } err := w.WriteMsg(res) if err != nil { t.Fatalf("write response failed: %s", err) } }) ) w := &testWriter{ remoteAddr: &net.UDPAddr{}, } m := &dns.Msg{} m.SetQuestion(dns.Fqdn("app.glimpse.io"), dns.TypeA) protocolHandler(want, testHandler).ServeDNS(w, m) if have := len(w.msg.Answer); want != have { t.Errorf("want %d answers, have %d", want, have) } e := &errorWriter{w} errorHandler := dns.HandlerFunc(func(w dns.ResponseWriter, req *dns.Msg) { err := w.WriteMsg(&dns.Msg{}) if err == nil { t.Fatalf("want WriteMsg() to fail with errorWriter") } }) m = &dns.Msg{} m.SetQuestion(dns.Fqdn("app.glimpse.io"), dns.TypeA) protocolHandler(42, errorHandler).ServeDNS(e, m) }
// Newserver returns a new server. // TODO(miek): multiple ectdAddrs func NewServer(domain, dnsAddr string, nameservers []string, etcdAddr string) *server { s := &server{ domain: dns.Fqdn(strings.ToLower(domain)), domainLabels: dns.CountLabel(dns.Fqdn(domain)), DnsAddr: dnsAddr, client: etcd.NewClient([]string{etcdAddr}), dnsHandler: dns.NewServeMux(), waiter: new(sync.WaitGroup), nameservers: nameservers, } // DNS s.dnsHandler.Handle(".", s) return s }
func setDefaults(config *Config) error { if config.ReadTimeout == 0 { config.ReadTimeout = 2 * time.Second } if config.DnsAddr == "" { config.DnsAddr = "127.0.0.1:53" } if config.Domain == "" { config.Domain = "skydns.local" } if config.MinTtl == 0 { config.MinTtl = 60 } if config.Ttl == 0 { config.Ttl = 3600 } if config.Priority == 0 { config.Priority = 10 } if len(config.Nameservers) == 0 { c, err := dns.ClientConfigFromFile("/etc/resolv.conf") if err != nil { return err } for _, s := range c.Servers { config.Nameservers = append(config.Nameservers, net.JoinHostPort(s, c.Port)) } } config.Domain = dns.Fqdn(strings.ToLower(config.Domain)) config.DomainLabels = dns.CountLabel(config.Domain) if config.DNSSEC != "" { // For some reason the + are replaces by spaces in etcd. Re-replace them keyfile := strings.Replace(config.DNSSEC, " ", "+", -1) k, p, err := ParseKeyFile(keyfile) if err != nil { return err } if k.Header().Name != dns.Fqdn(config.Domain) { return fmt.Errorf("ownername of DNSKEY must match SkyDNS domain") } k.Header().Ttl = config.Ttl config.PubKey = k config.KeyTag = k.KeyTag() config.PrivKey = p } return nil }
func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error) { parts := []string{} if strings.HasSuffix(ptr, ptrIPv4domain) { parts = strings.Split(ptr, ptrIPv4domain) } else if strings.HasSuffix(ptr, ptrIPv6domain) { parts = strings.Split(ptr, ptrIPv6domain) } else { return nil, fmt.Errorf("invalid PTR query, %v", ptr) } host := r.backend.ResolveIP(parts[0]) if len(host) == 0 { return nil, nil } logrus.Debugf("Lookup for IP %s: name %s", parts[0], host) fqdn := dns.Fqdn(host) resp := new(dns.Msg) resp.SetReply(query) setCommonFlags(resp) rr := new(dns.PTR) rr.Hdr = dns.RR_Header{Name: ptr, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: respTTL} rr.Ptr = fqdn resp.Answer = append(resp.Answer, rr) return resp, nil }
// 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 }
/* Get a domain's IPs from a specific name server. Parameters: domain the domain you want to query nameserver name server's IP address port 53 in general net tcp or udp timeout in seconds, can be omitted Here's an example: r, e := ARecords("www.example.com", "8.8.8.8", 53, "tcp") if e != nil { fmt.Println(e) } else { fmt.Println(r) } */ func ARecords(domain, nameserver string, port uint16, net string, timeout ...uint8) ([]string, error) { var result []string if net != "tcp" && net != "udp" { return result, errors.New("The parameter 'net' should only be 'tcp' or 'udp'.") } msg := new(mdns.Msg) msg.SetQuestion(mdns.Fqdn(domain), mdns.TypeA) var client *mdns.Client if len(timeout) > 0 { tm := time.Duration(timeout[0]) * time.Second client = &mdns.Client{Net: net, DialTimeout: tm, ReadTimeout: tm, WriteTimeout: tm} } else { client = &mdns.Client{Net: net} } r, _, err := client.Exchange(msg, fmt.Sprintf("%s:%d", nameserver, port)) if err != nil { return result, err } for _, i := range r.Answer { if t, ok := i.(*mdns.A); ok { result = append(result, t.A.String()) } } return result, nil }
func (d *DNSServer) handleRecursive(client *dns.Client, defaultMaxResponseSize int) func(dns.ResponseWriter, *dns.Msg) { return func(w dns.ResponseWriter, req *dns.Msg) { d.ns.debugf("recursive request: %+v", *req) // Resolve unqualified names locally if len(req.Question) == 1 && req.Question[0].Qtype == dns.TypeA { hostname := dns.Fqdn(req.Question[0].Name) if strings.Count(hostname, ".") == 1 { d.handleLocal(defaultMaxResponseSize)(w, req) return } } for _, server := range d.upstream.Servers { reqCopy := req.Copy() reqCopy.Id = dns.Id() response, _, err := client.Exchange(reqCopy, fmt.Sprintf("%s:%s", server, d.upstream.Port)) if err != nil || response == nil { d.ns.debugf("error trying %s: %v", server, err) continue } d.ns.debugf("response: %+v", response) response.Id = req.Id if err := w.WriteMsg(response); err != nil { d.ns.infof("error responding: %v", err) } return } d.errorResponse(req, dns.RcodeServerFailure, w) } }
// Look in .../dns/stub/<domain>/xx for msg.Services. Loop through them // extract <domain> and add them as forwarders (ip:port-combos) for // the stub zones. Only numeric (i.e. IP address) hosts are used. func (s *server) UpdateStubZones() { stubmap := make(map[string][]string) services, err := s.backend.Records("stub.dns."+s.config.Domain, false, net.IP{}) if err != nil { logf("stub zone update failed: %s", err) return } for _, serv := range services { if serv.Port == 0 { serv.Port = 53 } ip := net.ParseIP(serv.Host) if ip == nil { logf("stub zone non-address %s seen for: %s", serv.Key, serv.Host) continue } domain := msg.Domain(serv.Key) // Chop of left most label, because that is used as the nameserver place holder // and drop the right most labels that belong to localDomain. labels := dns.SplitDomainName(domain) domain = dns.Fqdn(strings.Join(labels[1:len(labels)-dns.CountLabel(s.config.localDomain)], ".")) // If the remaining name equals s.config.LocalDomain we ignore it. if domain == s.config.localDomain { logf("not adding stub zone for my own domain") continue } stubmap[domain] = append(stubmap[domain], net.JoinHostPort(serv.Host, strconv.Itoa(serv.Port))) } s.config.stub = &stubmap }
func (self *TrivialDnsServer) redirectQuery(w dns.ResponseWriter, r *dns.Msg, newName string) { self.Count("redirected_requests") if !strings.HasSuffix(newName, ".") { newName = newName + "." } newR := new(dns.Msg) newR.SetQuestion(dns.Fqdn(newName), dns.TypeA) if response, _, err := self.exchangeWithUpstream(newR); err == nil { ip := self.getSingleSimpleAnswer(response) if ip == nil { debug("%s redirect to %s yielded no answer", w.RemoteAddr(), newName) self.Count("redirected_nowhere") self.refuse(w, r) return } self.Count("redirected_successively") self.respondSuccessively(w, r, *ip) } else { self.Count("upstream_errors") self.refuse(w, r) log.Printf("%s: error: %s", w.RemoteAddr(), err) } }
func (e Etcd) AAAA(zone string, state middleware.State, previousRecords []dns.RR) (records []dns.RR, debug []msg.Service, err error) { services, debug, err := e.records(state, false) if err != nil { return nil, debug, err } for _, serv := range services { ip := net.ParseIP(serv.Host) switch { case ip == nil: // Try to resolve as CNAME if it's not an IP, but only if we don't create loops. if middleware.Name(state.Name()).Matches(dns.Fqdn(serv.Host)) { // x CNAME x is a direct loop, don't add those continue } newRecord := serv.NewCNAME(state.QName(), serv.Host) if len(previousRecords) > 7 { // don't add it, and just continue continue } if isDuplicateCNAME(newRecord, previousRecords) { continue } state1 := copyState(state, serv.Host, state.QType()) nextRecords, nextDebug, err := e.AAAA(zone, state1, append(previousRecords, newRecord)) if err == nil { // Not only have we found something we should add the CNAME and the IP addresses. if len(nextRecords) > 0 { records = append(records, newRecord) records = append(records, nextRecords...) debug = append(debug, nextDebug...) } continue } // This means we can not complete the CNAME, try to look else where. target := newRecord.Target if dns.IsSubDomain(zone, target) { // We should already have found it continue } m1, e1 := e.Proxy.Lookup(state, target, state.QType()) if e1 != nil { continue } // Len(m1.Answer) > 0 here is well? records = append(records, newRecord) records = append(records, m1.Answer...) continue // both here again case ip.To4() != nil: // nada? case ip.To4() == nil: records = append(records, serv.NewAAAA(state.QName(), ip.To16())) } } return records, debug, nil }
// handlePtr is used to handle "reverse" DNS queries func (d *DNSServer) handlePtr(resp dns.ResponseWriter, req *dns.Msg) { q := req.Question[0] defer func(s time.Time) { d.logger.Printf("[DEBUG] dns: request for %v (%v) from client %s (%s)", q, time.Now().Sub(s), resp.RemoteAddr().String(), resp.RemoteAddr().Network()) }(time.Now()) // Setup the message response m := new(dns.Msg) m.SetReply(req) m.Authoritative = true m.RecursionAvailable = (len(d.recursors) > 0) // Only add the SOA if requested if req.Question[0].Qtype == dns.TypeSOA { d.addSOA(d.domain, m) } datacenter := d.agent.config.Datacenter // Get the QName without the domain suffix qName := strings.ToLower(dns.Fqdn(req.Question[0].Name)) args := structs.DCSpecificRequest{ Datacenter: datacenter, QueryOptions: structs.QueryOptions{ Token: d.agent.config.ACLToken, AllowStale: d.config.AllowStale, }, } var out structs.IndexedNodes // TODO: Replace ListNodes with an internal RPC that can do the filter // server side to avoid transferring the entire node list. if err := d.agent.RPC("Catalog.ListNodes", &args, &out); err == nil { for _, n := range out.Nodes { arpa, _ := dns.ReverseAddr(n.Address) if arpa == qName { ptr := &dns.PTR{ Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0}, Ptr: fmt.Sprintf("%s.node.%s.%s", n.Node, datacenter, d.domain), } m.Answer = append(m.Answer, ptr) break } } } // nothing found locally, recurse if len(m.Answer) == 0 { d.handleRecurse(resp, req) return } // Write out the complete response if err := resp.WriteMsg(m); err != nil { d.logger.Printf("[WARN] dns: failed to respond: %v", err) } }