func (c *Config) GenerateServeDNS(hostname string) func(dns.ResponseWriter, *dns.Msg) { if len(hostname) > 0 { if hostname[len(hostname)-1] != '.' { hostname += "." } } return func(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) m.Authoritative = true ip, err := c.GetOrLaunchInstance() if err != nil { // TODO: error handling log.Println("Error in GetOrLaunchInstance:", err) w.Close() return } rr := new(dns.A) rr.Hdr = dns.RR_Header{Name: hostname, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: uint32(c.MaxIdleTime.Seconds())} rr.A = ip m.Answer = []dns.RR{rr} w.WriteMsg(m) } }
func (s *DNSServer) handleARequest(r *dns.Msg, m *dns.Msg) { m.Answer = make([]dns.RR, 0, 2) query := r.Question[0].Name if query[len(query)-1] == '.' { query = query[:len(query)-1] } for service := range s.queryServices(query) { rr := new(dns.A) var ttl int if service.Ttl != -1 { ttl = service.Ttl } else { ttl = s.config.ttl } rr.Hdr = dns.RR_Header{ Name: r.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: uint32(ttl), } rr.A = service.Ip m.Answer = append(m.Answer, rr) } }
func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns.Msg, error) { addr := r.sb.ResolveName(name, ipType) if addr == nil { return nil, nil } log.Debugf("Lookup for %s: IP %v", name, addr) resp := new(dns.Msg) resp.SetReply(query) setCommonFlags(resp) if len(addr) > 1 { addr = shuffleAddr(addr) } if ipType == netutils.IPv4 { for _, ip := range addr { rr := new(dns.A) rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL} rr.A = ip resp.Answer = append(resp.Answer, rr) } } else { for _, ip := range addr { rr := new(dns.AAAA) rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: respTTL} rr.AAAA = ip resp.Answer = append(resp.Answer, rr) } } return resp, nil }
func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns.Msg, error) { addr, ipv6Miss := r.sb.ResolveName(name, ipType) if addr == nil && ipv6Miss { // Send a reply without any Answer sections log.Debugf("Lookup name %s present without IPv6 address", name) resp := createRespMsg(query) return resp, nil } if addr == nil { return nil, nil } log.Debugf("Lookup for %s: IP %v", name, addr) resp := createRespMsg(query) if len(addr) > 1 { addr = shuffleAddr(addr) } if ipType == types.IPv4 { for _, ip := range addr { rr := new(dns.A) rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL} rr.A = ip resp.Answer = append(resp.Answer, rr) } } else { for _, ip := range addr { rr := new(dns.AAAA) rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: respTTL} rr.AAAA = ip resp.Answer = append(resp.Answer, rr) } } return resp, nil }
func (r *resolver) handleSRVQuery(svc string, query *dns.Msg) (*dns.Msg, error) { srv, ip := r.backend.ResolveService(svc) if len(srv) == 0 { return nil, nil } if len(srv) != len(ip) { return nil, fmt.Errorf("invalid reply for SRV query %s", svc) } resp := createRespMsg(query) for i, r := range srv { rr := new(dns.SRV) rr.Hdr = dns.RR_Header{Name: svc, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: respTTL} rr.Port = r.Port rr.Target = r.Target resp.Answer = append(resp.Answer, rr) rr1 := new(dns.A) rr1.Hdr = dns.RR_Header{Name: r.Target, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL} rr1.A = ip[i] resp.Extra = append(resp.Extra, rr1) } return resp, nil }
func newRR(host string, addr net.IP) dns.RR { rr := new(dns.A) rr.Hdr = dns.RR_Header{ Name: host, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} rr.A = addr.To4() return rr }
// hijackResponse returns a modified version on the input dns.Msg with the A record modified // to point to our server func hijackResponse(r *dns.Msg) (m *dns.Msg) { m = new(dns.Msg) m.SetReply(r) m.Answer = make([]dns.RR, 1) rr := new(dns.A) rr.Hdr = dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 600} rr.A = net.ParseIP(config.EXTERNAL_ADDRESS) m.Answer[0] = rr return m }
func dnsAddressRecord(query *dns.Msg, name string, addrs []net.IP) *dns.Msg { resp := new(dns.Msg) resp.SetReply(query) for _, addr := range addrs { rr := new(dns.A) rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} rr.A = addr resp.Answer = append(resp.Answer, rr) } return resp }
func dnsHandler(w dns.ResponseWriter, r *dns.Msg) { defer w.Close() m := new(dns.Msg) m.SetReply(r) m.Compress = false for _, q := range r.Question { fmt.Printf("dns-srv: Query -- [%s] %s\n", q.Name, dns.TypeToString[q.Qtype]) switch q.Qtype { case dns.TypeA: record := new(dns.A) record.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0, } record.A = net.ParseIP("127.0.0.1") m.Answer = append(m.Answer, record) case dns.TypeMX: record := new(dns.MX) record.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 0, } record.Mx = "mail." + q.Name record.Preference = 10 m.Answer = append(m.Answer, record) } } w.WriteMsg(m) return }
func (s *server) AddressRecords(q dns.Question, name string) (records []dns.RR, err error) { results, err := s.hosts.FindHosts(name) if err != nil { return nil, err } for _, ip := range results { switch { case ip.To4() != nil && (q.Qtype == dns.TypeA || q.Qtype == dns.TypeANY): r := new(dns.A) r.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.config.HostsTtl} r.A = ip.To4() records = append(records, r) case ip.To4() == nil && (q.Qtype == dns.TypeAAAA || q.Qtype == dns.TypeANY): r := new(dns.AAAA) r.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.config.HostsTtl} r.AAAA = ip.To16() records = append(records, r) } } return records, nil }
func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error) { addr := r.sb.ResolveName(name) if addr == nil { return nil, nil } log.Debugf("Lookup for %s: IP %s", name, addr.String()) resp := new(dns.Msg) resp.SetReply(query) rr := new(dns.A) rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL} rr.A = addr resp.Answer = append(resp.Answer, rr) return resp, nil }
/* ---------------------------------------------------------------------------- FUNCTION Name: Serve Response Prototype: func serveResponse(w dns.ResponseWriter, r *dns.Msg) Developer: Andrew Burian Created On: 2015-09-24 Parameters: w dns.ResponseWriter the writer that will respond to the dns query r dns.Msg the dns query to respond to Return Values: (none) Description: Handles a single dns request by generating and writing a response to the provided writer. Also strips out the contained data and sends it over a channel Revisions: (none) ---------------------------------------------------------------------------- */ func serveResponse(w dns.ResponseWriter, r *dns.Msg) { // create a message to respond with respMsg := new(dns.Msg) // set this message to be a response to the first respMsg.SetReply(r) // create a new record to respond with respRec := new(dns.A) respRec.Hdr = dns.RR_Header{ Name: r.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} // 0 TTL to avoid caching // pseudo random IP rand_bytes := make([]byte, 4) rand.Read(rand_bytes) respRec.A = rand_bytes respMsg.Answer = append(respMsg.Answer, respRec) w.WriteMsg(respMsg) // now that the response has been handled // process the covert data // get the data from the query data := (strings.Split(r.Question[0].Name, "."))[0] // create the new message channel datachan := make(chan byte, len(data)) // send it to the main messages <- datachan // read all the bytes into the channel for _, b := range []byte(data) { datachan <- b } close(datachan) }
func route(w dns.ResponseWriter, req *dns.Msg) { if len(req.Question) != 1 { failWithRcode(w, req, dns.RcodeRefused) return } question := req.Question[0] qtype := question.Qtype if question.Qclass != dns.ClassINET { failWithRcode(w, req, dns.RcodeRefused) return } remoteIP := w.RemoteAddr().(*net.UDPAddr).IP m := new(dns.Msg) m.Id = req.Id switch qtype { case dns.TypeA: if remoteIP4 := remoteIP.To4(); remoteIP4 != nil { rr := new(dns.A) rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: question.Qtype, Class: dns.ClassINET, Ttl: 10} rr.A = remoteIP4 m.Answer = []dns.RR{rr} } case dns.TypeAAAA: if remoteIP16 := remoteIP.To16(); remoteIP16 != nil { rr := new(dns.AAAA) rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: question.Qtype, Class: dns.ClassINET, Ttl: 10} rr.AAAA = remoteIP16 m.Answer = []dns.RR{rr} } case dns.TypeTXT: rr := new(dns.TXT) rr.Hdr = dns.RR_Header{Name: question.Name, Rrtype: question.Qtype, Class: dns.ClassINET, Ttl: 10} rr.Txt = []string{fmt.Sprintf("Resolver IP: %v", remoteIP.String())} m.Answer = []dns.RR{rr} } m.Question = req.Question m.Response = true m.Authoritative = true w.WriteMsg(m) }
func (s *SenseDNS) fillWithData(pairs api.KVPairs, network string) { zs := s.dnsServer.zones zs.Lock() defer zs.Unlock() key := s.dnsServer.getNetDomain(network) zs.store[key] = make(map[dns.RR_Header][]dns.RR) for _, value := range pairs { path := strings.Split(value.Key, "/") hostname := fmt.Sprintf("%s.%s.%s", path[3], network, s.dnsServer.networkTLD) ip := string(value.Value) rr := new(dns.A) rr.A = net.ParseIP(ip) rr.Hdr = dns.RR_Header{Name: dns.Fqdn(hostname), Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 3600} key2 := dns.RR_Header{Name: dns.Fqdn(rr.Header().Name), Rrtype: rr.Header().Rrtype, Class: rr.Header().Class} zs.store[key][key2] = append(zs.store[key][key2], rr) } if log.Level == logrus.DebugLevel { s.dnsServer.printRoutingTable() } }
func parseValue(t uint16, value string, h dns.RR_Header) dns.RR { switch t { case dns.TypeA: a := new(dns.A) a.Hdr = h a.A, _ = parseA(value) return a case dns.TypeAAAA: aaaa := new(dns.AAAA) aaaa.Hdr = h aaaa.AAAA, _ = parseAAAA(value) return aaaa case dns.TypeSRV: srv := new(dns.SRV) srv.Hdr = h srv.Priority, srv.Weight, srv.Port, srv.Target, _ = parseSRV(value) return srv } return nil }
func (s *DNSServer) makeServiceA(n string, service *Service) dns.RR { rr := new(dns.A) var ttl int if service.Ttl != -1 { ttl = service.Ttl } else { ttl = s.config.ttl } rr.Hdr = dns.RR_Header{ Name: n, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: uint32(ttl), } rr.A = service.Ip return rr }
func handleRequest(w dns.ResponseWriter, r *dns.Msg) { q := r.Question[0] info := fmt.Sprintf("Question: Type=%s Class=%s Name=%s", dns.TypeToString[q.Qtype], dns.ClassToString[q.Qclass], q.Name) if q.Qtype == dns.TypeA && q.Qclass == dns.ClassINET { m := new(dns.Msg) m.SetReply(r) a := new(dns.A) a.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 600} a.A = resolveIP m.Answer = []dns.RR{a} w.WriteMsg(m) log.Printf("%s (RESOLVED)\n", info) } else { m := new(dns.Msg) m.SetReply(r) m.Rcode = dns.RcodeNameError // NXDOMAIN w.WriteMsg(m) log.Printf("%s (NXDOMAIN)\n", info) } }
func (c *config) flattenCNAME(in *dns.CNAME) ([]dns.RR, error) { // TODO: cache CNAME lookups h := in.Header() answers := []dns.RR{} m := new(dns.Msg) m.SetQuestion(in.Target, dns.TypeA) m.RecursionDesired = true d := new(dns.Client) record, _, err := d.Exchange(m, c.resolver) // TODO: try multiple resolvers if err != nil { return nil, err } if record == nil || record.Rcode == dns.RcodeNameError || record.Rcode != dns.RcodeSuccess { return nil, fmt.Errorf("Record error code %s: %s", record.Rcode, err.Error()) } for _, a := range record.Answer { if r, ok := a.(*dns.A); ok { out := new(dns.A) out.Hdr = dns.RR_Header{Name: h.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 300} out.A = r.A answers = append(answers, out) } } return answers, nil }
func (s *server) AddressRecords(q dns.Question) (records []dns.RR, err error) { name := strings.ToLower(q.Name) if name == "master."+s.config.Domain || name == s.config.Domain { for _, m := range s.client.GetCluster() { u, e := url.Parse(m) if e != nil { continue } h, _, e := net.SplitHostPort(u.Host) if e != nil { continue } ip := net.ParseIP(h) switch { case ip.To4() != nil && q.Qtype == dns.TypeA: records = append(records, &dns.A{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.Ttl}, A: ip.To4()}) case ip.To4() == nil && q.Qtype == dns.TypeAAAA: records = append(records, &dns.AAAA{Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.Ttl}, AAAA: ip.To16()}) } } return } r, err := s.client.Get(path(name), false, true) if err != nil { println(err.Error()) return nil, err } var serv *Service if !r.Node.Dir { // single element if err := json.Unmarshal([]byte(r.Node.Value), &serv); err != nil { log.Printf("error: Failure to parse value: %q", err) return nil, err } ip := net.ParseIP(serv.Host) ttl := uint32(r.Node.TTL) if ttl == 0 { ttl = s.Ttl } switch { case ip == nil: case ip.To4() != nil && q.Qtype == dns.TypeA: a := new(dns.A) a.Hdr = dns.RR_Header{Name: q.Name, Rrtype: q.Qtype, Class: dns.ClassINET, Ttl: ttl} a.A = ip.To4() records = append(records, a) case ip.To4() == nil && q.Qtype == dns.TypeAAAA: aaaa := new(dns.AAAA) aaaa.Hdr = dns.RR_Header{Name: q.Name, Rrtype: q.Qtype, Class: dns.ClassINET, Ttl: ttl} aaaa.AAAA = ip.To16() records = append(records, aaaa) } return records, nil } for _, serv := range s.loopNodes(&r.Node.Nodes) { ip := net.ParseIP(serv.Host) switch { case ip == nil: case ip.To4() != nil && q.Qtype == dns.TypeA: a := new(dns.A) a.Hdr = dns.RR_Header{Name: q.Name, Rrtype: q.Qtype, Class: dns.ClassINET, Ttl: uint32(r.Node.TTL)} a.A = ip.To4() records = append(records, a) case ip.To4() == nil && q.Qtype == dns.TypeAAAA: aaaa := new(dns.AAAA) aaaa.Hdr = dns.RR_Header{Name: q.Name, Rrtype: q.Qtype, Class: dns.ClassINET, Ttl: uint32(r.Node.TTL)} aaaa.AAAA = ip.To16() records = append(records, aaaa) } } if s.config.RoundRobin { switch l := len(records); l { case 2: if dns.Id()%2 == 0 { records[0], records[1] = records[1], records[0] } default: // Do a minimum of l swap, maximum of 4l swaps for j := 0; j < l*(int(dns.Id())%4+1); j++ { q := int(dns.Id()) % l p := int(dns.Id()) % l if q == p { p = (p + 1) % l } records[q], records[p] = records[p], records[q] } } } return records, nil }
// updateDNS updates the current slices of dns.RR so incoming requests get a // fast answer func updateDNS(s *dnsseeder) { var rr4std, rr4non, rr6std, rr6non []dns.RR s.mtx.RLock() // loop over each dns recprd type we need for t := range []int{dnsV4Std, dnsV4Non, dnsV6Std, dnsV6Non} { // FIXME above needs to be convertwd into one scan of theList if possible numRR := 0 for _, nd := range s.theList { // when we reach max exit if numRR >= 25 { break } if nd.status != statusCG { continue } if t == dnsV4Std || t == dnsV4Non { if t == dnsV4Std && nd.dnsType == dnsV4Std { r := new(dns.A) r.Hdr = dns.RR_Header{Name: s.dnsHost + ".", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.ttl} r.A = nd.na.IP rr4std = append(rr4std, r) numRR++ } // if the node is using a non standard port then add the encoded port info to DNS if t == dnsV4Non && nd.dnsType == dnsV4Non { r := new(dns.A) r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.ttl} r.A = nd.na.IP rr4non = append(rr4non, r) numRR++ r = new(dns.A) r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.ttl} r.A = nd.nonstdIP rr4non = append(rr4non, r) numRR++ } } if t == dnsV6Std || t == dnsV6Non { if t == dnsV6Std && nd.dnsType == dnsV6Std { r := new(dns.AAAA) r.Hdr = dns.RR_Header{Name: s.dnsHost + ".", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.ttl} r.AAAA = nd.na.IP rr6std = append(rr6std, r) numRR++ } // if the node is using a non standard port then add the encoded port info to DNS if t == dnsV6Non && nd.dnsType == dnsV6Non { r := new(dns.AAAA) r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.ttl} r.AAAA = nd.na.IP rr6non = append(rr6non, r) numRR++ r = new(dns.AAAA) r.Hdr = dns.RR_Header{Name: "nonstd." + s.dnsHost + ".", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.ttl} r.AAAA = nd.nonstdIP rr6non = append(rr6non, r) numRR++ } } } } s.mtx.RUnlock() config.dnsmtx.Lock() // update the map holding the details for this seeder for t := range []int{dnsV4Std, dnsV4Non, dnsV6Std, dnsV6Non} { switch t { case dnsV4Std: config.dns[s.dnsHost+".A"] = rr4std case dnsV4Non: config.dns["nonstd."+s.dnsHost+".A"] = rr4non case dnsV6Std: config.dns[s.dnsHost+".AAAA"] = rr6std case dnsV6Non: config.dns["nonstd."+s.dnsHost+".AAAA"] = rr6non } } config.dnsmtx.Unlock() if config.stats { s.counts.mtx.RLock() log.Printf("%s - DNS available: v4std: %v v4non: %v v6std: %v v6non: %v\n", s.name, len(rr4std), len(rr4non), len(rr6std), len(rr6non)) log.Printf("%s - DNS counts: v4std: %v v4non: %v v6std: %v v6non: %v total: %v\n", s.name, s.counts.DNSCounts[dnsV4Std], s.counts.DNSCounts[dnsV4Non], s.counts.DNSCounts[dnsV6Std], s.counts.DNSCounts[dnsV6Non], s.counts.DNSCounts[dnsV4Std]+s.counts.DNSCounts[dnsV4Non]+s.counts.DNSCounts[dnsV6Std]+s.counts.DNSCounts[dnsV6Non]) s.counts.mtx.RUnlock() } }
func handleDnsRequest(w dns.ResponseWriter, req *dns.Msg) { r := new(dns.Msg) r.SetReply(req) r.Authoritative = true if len(req.Question) > 1 || req.Rcode != dns.OpcodeQuery { r.SetRcode(req, dns.RcodeNotImplemented) } if len(req.Question) == 0 { r.SetRcode(req, dns.RcodeFormatError) } if r.Rcode != dns.RcodeSuccess { w.WriteMsg(r) dnsReportChan <- 1 return } q := req.Question[0] log.Debug("dns server: question=%v type=%v remote_host=%v", q.Name, q.Qtype, w.RemoteAddr()) switch q.Qtype { case dns.TypeA: h, _ := randomHost() if h == "" || !isIPv4(h) { if *f_randomhosts { h = randomIPv4Addr() } else { // return NXDOMAIN r.SetRcode(req, dns.RcodeNameError) break } } resp := new(dns.A) resp.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: ttl, } resp.A = net.ParseIP(h) r.Answer = append(r.Answer, resp) case dns.TypeAAAA: h, _ := randomHost() if h == "" || !isIPv6(h) { if *f_randomhosts { h = randomIPv6Addr() } else { // return NXDOMAIN r.SetRcode(req, dns.RcodeNameError) break } } resp := new(dns.AAAA) resp.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: ttl, } resp.AAAA = net.ParseIP(h) r.Answer = append(r.Answer, resp) case dns.TypeCNAME: resp := new(dns.CNAME) resp.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: ttl, } resp.Target = fmt.Sprintf("cname.%s", q.Name) r.Answer = append(r.Answer, resp) case dns.TypeMX: resp := new(dns.MX) resp.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: ttl, } resp.Mx = fmt.Sprintf("mx.%s", q.Name) r.Answer = append(r.Answer, resp) case dns.TypeSOA: resp := new(dns.SOA) resp.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: ttl, } resp.Ns = fmt.Sprintf("ns.%s", q.Name) resp.Mbox = fmt.Sprintf("admin-%s", q.Name) r.Answer = append(r.Answer, resp) } w.WriteMsg(r) dnsReportChan <- 1 }
func (ts *testSrv) dnsHandler(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) m.Compress = false // Normally this test DNS server will return 127.0.0.1 for everything. // However, in some situations (for instance Docker), it's useful to return a // different hardcoded host. You can do so by setting the FAKE_DNS environment // variable. fakeDNS := os.Getenv("FAKE_DNS") if fakeDNS == "" { fakeDNS = "127.0.0.1" } for _, q := range r.Question { fmt.Printf("dns-srv: Query -- [%s] %s\n", q.Name, dns.TypeToString[q.Qtype]) switch q.Qtype { case dns.TypeA: record := new(dns.A) record.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0, } record.A = net.ParseIP(fakeDNS) m.Answer = append(m.Answer, record) case dns.TypeMX: record := new(dns.MX) record.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 0, } record.Mx = "mail." + q.Name record.Preference = 10 m.Answer = append(m.Answer, record) case dns.TypeTXT: ts.mu.RLock() value, present := ts.txtRecords[q.Name] ts.mu.RUnlock() if !present { continue } record := new(dns.TXT) record.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0, } record.Txt = []string{value} m.Answer = append(m.Answer, record) case dns.TypeCAA: if q.Name == "bad-caa-reserved.com." || q.Name == "good-caa-reserved.com." { record := new(dns.CAA) record.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeCAA, Class: dns.ClassINET, Ttl: 0, } record.Tag = "issue" if q.Name == "bad-caa-reserved.com." { record.Value = "sad-hacker-ca.invalid" } else if q.Name == "good-caa-reserved.com." { record.Value = "happy-hacker-ca.invalid" } m.Answer = append(m.Answer, record) } } } auth := new(dns.SOA) auth.Hdr = dns.RR_Header{Name: "boulder.invalid.", Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: 0} auth.Ns = "ns.boulder.invalid." auth.Mbox = "master.boulder.invalid." auth.Serial = 1 auth.Refresh = 1 auth.Retry = 1 auth.Expire = 1 auth.Minttl = 1 m.Ns = append(m.Ns, auth) w.WriteMsg(m) return }
func proxyServe(w dns.ResponseWriter, req *dns.Msg) { var ( key string m *dns.Msg err error tried bool data []byte id uint16 query []string questions []dns.Question used string ) defer func() { if err := recover(); err != nil { fmt.Println(err) } }() if req.MsgHdr.Response == true { return } query = make([]string, len(req.Question)) for i, q := range req.Question { if q.Qtype != dns.TypeAAAA || *ipv6 { questions = append(questions, q) } query[i] = fmt.Sprintf("(%s %s %s)", q.Name, dns.ClassToString[q.Qclass], dns.TypeToString[q.Qtype]) } if len(questions) == 0 { return } //check local map dom := req.Question[0].Name domain := dom[0 : len(dom)-1] v, ok := localMap[domain] if ok { tm := new(dns.Msg) tm.Id = req.Id tm.Answer = make([]dns.RR, 1) dom := req.Question[0].Name trr := new(dns.A) trr.Hdr = dns.RR_Header{Name: dom, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 5} trr.A = net.ParseIP(v) tm.Answer[0] = trr err = w.WriteMsg(tm) if DEBUG > 0 { log.Printf("hosts:%v ip:%v\n", domain, v) } goto end } req.Question = questions id = req.Id req.Id = 0 key = toMd5(req.String()) req.Id = id if ENCACHE { if reply, ok := conn.Get(key); ok { data, _ = reply.([]byte) } if data != nil && len(data) > 0 { m = &dns.Msg{} m.Unpack(data) m.Id = id err = w.WriteMsg(m) if DEBUG > 0 { log.Printf("id:%5d cache: HIT %v\n", id, query) } goto end } else { if DEBUG > 0 { log.Printf("id: %5d cache: MISS %v\n", id, query) } } } for i, parts := range DNS { dns := parts[0] proto := parts[1] tried = i > 0 if DEBUG > 0 { if tried { log.Printf("id: 5%d try: %v %s %s\n", id, query, dns, proto) } else { log.Printf("id: 5%d resolve: %v %s %s\n", id, query, dns, proto) } } client := clientUDP if proto == "tcp" { client = clientTCP } m, _, err = client.Exchange(req, dns) if err == nil && len(m.Answer) > 0 { used = dns break } } if err == nil { if DEBUG > 0 { if tried { if len(m.Answer) == 0 { log.Printf("id: %5d failed: %v\n", id, query) } else { log.Printf("id: %5d bingo: %v %s\n", id, query, used) } } } data, err = m.Pack() if err == nil { _, err = w.Write(data) if err == nil { if ENCACHE { m.Id = 0 data, _ = m.Pack() ttl := 0 if len(m.Answer) > 0 { ttl = int(m.Answer[0].Header().Ttl) if ttl < 0 { ttl = 0 } } conn.Set(key, data, time.Second*time.Duration(ttl)) m.Id = id if DEBUG > 0 { log.Printf("id: %5d cache: CACHED %v TTL %v\n", id, query, ttl) } } } } } end: if DEBUG > 1 { fmt.Println(req) if m != nil { fmt.Println(m) } } if err != nil { log.Printf("id: %5d error: %v %s\n", id, query, err) } if DEBUG > 1 { fmt.Println("======================================") } }
// TODO(axw) define an error for "no answer" func (s *jujuNameServer) answer(q dns.Question) (dns.RR, error) { if q.Qtype != dns.TypeA { return nil, nil } var envName string entityName := strings.ToLower(strings.TrimSuffix(q.Name, "."+zone)) if i := strings.IndexRune(entityName, '.'); i >= 0 { envName = entityName[i+1:] entityName = entityName[:i] } else { var err error envName, err = envcmd.GetDefaultEnvironment() if err != nil { return nil, err } } // TODO(axw) cache API connection api, err := s.openAPI(envName) if err != nil { return nil, err } defer api.Close() client := api.Client() // If the entity name parses as a tag, extract the ID. This enables // us to address "unit-mysql-0", where we couldn't otherwise, since // slashes are not allowed in domain names. Similarly for container // machines (e.g. to address "0/lxc/0", pass "machine-0-lxc-0"). if tag, err := names.ParseTag(entityName); err == nil { entityName = tag.Id() } var addr string if names.IsValidService(entityName) { status, err := client.Status([]string{entityName}) if err != nil { return nil, err } service := status.Services[entityName] addresses := make([]string, 0, len(service.Units)) for _, unit := range service.Units { if unit.PublicAddress == "" { continue } if includeLost || unit.UnitAgent.Status != "lost" { addresses = append(addresses, unit.PublicAddress) } } // Might be nice to have additional info in TXT? if len(addresses) == 0 { return nil, nil } addr = addresses[rand.Intn(len(addresses))] } else { // Assume it's a machine or unit name. addr, err = client.PublicAddress(entityName) if err != nil { return nil, err } } ip := net.ParseIP(addr) if ip != nil { rr := new(dns.A) rr.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0, } rr.A = ip return rr, nil } else { rr := new(dns.CNAME) rr.Hdr = dns.RR_Header{ Name: q.Name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 0, } rr.Target = addr + "." return rr, nil } }