Example #1
0
// Construct a response for a single DNS request.
func (ds *DjdnsServer) Handle(query *dns.Msg) (*dns.Msg, error) {
	response := new(dns.Msg)
	response.MsgHdr.Id = query.MsgHdr.Id
	response.Question = query.Question
	if len(query.Question) > 0 {
		// Ignore secondary questions
		question := query.Question[0]
		records, err := ds.GetRecords(question.Name)
		if err != nil {
			return nil, err
		}
		response.Answer = make([]dns.RR, len(records))
		for i, record := range records {
			answer, err := record.ToDns()
			if err != nil {
				return nil, err
			}
			response.Answer[i] = answer
		}
		response.Ns = make([]dns.RR, 0)
		response.Extra = make([]dns.RR, 0)
	}

	return response, nil
}
func RenewDnsMsg(m *dns.Msg) {
	m.Extra = nil
	m.Answer = nil
	m.AuthenticatedData = false
	m.CheckingDisabled = false
	m.Question = nil
}
Example #3
0
File: chaos.go Project: polvi/dns
func main() {
	if len(os.Args) != 2 {
		fmt.Printf("%s NAMESERVER\n", os.Args[0])
		os.Exit(1)
	}
	conf, _ := dns.ClientConfigFromFile("/etc/resolv.conf")

	m := new(dns.Msg)
	m.Question = make([]dns.Question, 1)
	c := new(dns.Client)

	addr := addresses(conf, c, os.Args[1])
	if len(addr) == 0 {
		fmt.Printf("No address found for %s\n", os.Args[1])
		os.Exit(1)
	}
	for _, a := range addr {
		m.Question[0] = dns.Question{"version.bind.", dns.TypeTXT, dns.ClassCHAOS}
		in, rtt, _ := c.ExchangeRtt(m, a)
		if in != nil && len(in.Answer) > 0 {
			fmt.Printf("(time %.3d µs) %v\n", rtt/1e3, in.Answer[0])
		}
		m.Question[0] = dns.Question{"hostname.bind.", dns.TypeTXT, dns.ClassCHAOS}
		in, rtt, _ = c.ExchangeRtt(m, a)
		if in != nil && len(in.Answer) > 0 {
			fmt.Printf("(time %.3d µs) %v\n", rtt/1e3, in.Answer[0])
		}
	}
}
Example #4
0
// Performs the actual query by service name (browse) or service instance name (lookup),
// start response listeners goroutines and loops over the entries channel.
func (c *client) query(params *LookupParams) error {
	var serviceName, serviceInstanceName string
	serviceName = fmt.Sprintf("%s.%s.", trimDot(params.Service), trimDot(params.Domain))
	if params.Instance != "" {
		serviceInstanceName = fmt.Sprintf("%s.%s", params.Instance, serviceName)
	}

	// send the query
	m := new(dns.Msg)
	if serviceInstanceName != "" {
		m.Question = []dns.Question{
			dns.Question{serviceInstanceName, dns.TypeSRV, dns.ClassINET},
			dns.Question{serviceInstanceName, dns.TypeTXT, dns.ClassINET},
		}
		m.RecursionDesired = false
	} else {
		m.SetQuestion(serviceName, dns.TypePTR)
		m.RecursionDesired = false
	}
	if err := c.sendQuery(m); err != nil {
		return err
	}

	return nil
}
func (self *DnsResolver) lookupHost(host string, triesLeft int) ([]net.IP, error) {
	m1 := new(dns.Msg)
	m1.Id = dns.Id()
	m1.RecursionDesired = true
	m1.Question = make([]dns.Question, 1)
	m1.Question[0] = dns.Question{dns.Fqdn(host), dns.TypeA, dns.ClassINET}
	in, err := dns.Exchange(m1, self.Servers[self.r.Intn(len(self.Servers))])

	result := []net.IP{}

	if err != nil {
		if strings.HasSuffix(err.Error(), "i/o timeout") && triesLeft > 0 {
			triesLeft -= 1
			return self.lookupHost(host, triesLeft)
		} else {
			return result, err
		}
	}

	if in != nil && in.Rcode != dns.RcodeSuccess {
		return result, errors.New(dns.RcodeToString[in.Rcode])
	}

	for _, record := range in.Answer {
		if t, ok := record.(*dns.A); ok {
			result = append(result, t.A)
		}
	}
	return result, err
}
Example #6
0
func newMsg(host string, qClass uint16) *dns.Msg {
	m1 := new(dns.Msg)
	m1.Id = dns.Id()
	m1.RecursionDesired = true
	m1.Question = make([]dns.Question, 1)
	m1.Question[0] = dns.Question{host, qClass, dns.ClassINET}
	return m1
}
Example #7
0
func localQuery(mychan chan DNSreply, qname string, qtype uint16) {
	var result DNSreply
	var trials uint
	result.qname = qname
	result.qtype = qtype
	result.r = nil
	result.err = errors.New("No name server to answer the question")
	localm := new(dns.Msg)
	localm.Id = dns.Id()
	localm.RecursionDesired = true
	localm.Question = make([]dns.Question, 1)
	localm.SetEdns0(EDNSBUFFERSIZE, false) // Even if no EDNS requested, see #9 May be we should retry without it if timeout?
	localc := new(dns.Client)
	localc.ReadTimeout = timeout
	localm.Question[0] = dns.Question{qname, qtype, dns.ClassINET}
Tests:
	for trials = 0; trials < uint(*maxTrials); trials++ {
	Resolvers:
		for serverIndex := range conf.Servers {
			server := conf.Servers[serverIndex]
			result.nameserver = server
			// Brackets around the server address are necessary for IPv6 name servers
			r, rtt, err := localc.Exchange(localm, "["+server+"]:"+conf.Port) // Do not use net.JoinHostPort, see https://github.com/bortzmeyer/check-soa/commit/3e4edb13855d8c4016768796b2892aa83eda1933#commitcomment-2355543
			if r == nil {
				result.r = nil
				result.err = err
				if strings.Contains(err.Error(), "timeout") {
					// Try another resolver
					break Resolvers
				} else { // We give in
					break Tests
				}
			} else {
				result.rtt = rtt
				if r.Rcode == dns.RcodeSuccess {
					// TODO: as a result, NODATA (NOERROR/ANSWER=0) are silently ignored (try "foo", for instance, the name exists but no IP address)
					// TODO: for rcodes like SERVFAIL, trying another resolver could make sense
					result.r = r
					result.err = nil
					break Tests
				} else {
					// All the other codes are errors. Yes, it may
					// happens that one resolver returns REFUSED
					// and the others work but we do not handle
					// this case. TODO: delete the resolver from
					// the list and try another one
					result.r = r
					result.err = errors.New(dns.RcodeToString[r.Rcode])
					break Tests
				}
			}
		}
	}
	if *debug {
		fmt.Printf("DEBUG: end of DNS request \"%s\" / %d\n", qname, qtype)
	}
	mychan <- result
}
Example #8
0
func prepareFailureMsg(req *dns.Msg) *dns.Msg {
	failMsg := new(dns.Msg)
	failMsg.Id = req.Id
	failMsg.Response = true
	failMsg.Authoritative = true
	failMsg.Question = req.Question
	failMsg.Rcode = dns.RcodeNameError
	return failMsg
}
Example #9
0
// DNS requests go to this function
func dnsHandle(w dns.ResponseWriter, r *dns.Msg) {
	name := r.Question[0].Name
	if !namePattern.MatchString(name) {
		kilog.Debug("%v does not match pattern, forwarding", name)
		dnsForward(w, r)
		return
	}
	// otherwise
	kilog.Debug("%v matches pattern, handling", name)
	dnsLock.Lock()
	defer dnsLock.Unlock()
	// check in table first
	fakeIP, ok := nameToIP[name]
	if !ok {
		// place in table
		var nwIP string
		for {
			haha := ipAlloc().String()
			_, exists := ipToName[haha]
			if exists {
				continue
			}
			nwIP = haha
			break
		}
		fakeIP = nwIP
		nameToIP[name] = fakeIP
		ipToName[fakeIP] = name
		// remove in 30 minutes
		go func() {
			time.Sleep(time.Minute * 30)
			dnsLock.Lock()
			defer dnsLock.Unlock()
			delete(nameToIP, name)
			delete(ipToName, fakeIP)
		}()
	}
	// return the fake IP to the user
	resp := new(dns.A)
	resp.Hdr.Name = name
	resp.Hdr.Ttl = 1 // very short
	resp.Hdr.Class = dns.ClassINET
	resp.Hdr.Rrtype = dns.TypeA
	resp.A = net.ParseIP(fakeIP)

	towrite := new(dns.Msg)
	towrite.Id = r.Id
	towrite.RecursionAvailable = true
	towrite.RecursionDesired = true
	towrite.Response = true
	towrite.Question = r.Question
	towrite.Answer = make([]dns.RR, 1)
	towrite.Answer[0] = resp
	w.WriteMsg(towrite)
	kilog.Debug("returning mapping %v -> %v", name, fakeIP)
}
Example #10
0
func (d *DnsDomain) Test() bool {
	if !(*Domain)(d).Test() {
		return false
	}

	fqdn := d.Name
	if strings.HasPrefix(fqdn, "*.") {
		fqdn = "a" + fqdn[1:]
	}
	if !strings.HasSuffix(fqdn, ".") {
		fqdn = fqdn + "."
	}

	any_ok := false

	d.DNS = make([]*DnsRecords, 0, len(DNS_servers))
	for name, addr := range DNS_servers {
		records := new(DnsRecords)
		records.Server = name
		records.NS = addr
		d.DNS = append(d.DNS, records)

		req := new(dns.Msg)
		req.Id = dns.Id()
		req.RecursionDesired = true
		req.Question = []dns.Question{
			dns.Question{fqdn, dns.TypeA, dns.ClassINET},
		}

		resp, err := dns_client.Exchange(req, addr)
		if err != nil {
			records.Status = 900
			records.Message = err.Error()
			continue
		}

		records.IPs = make([]string, 0, len(resp.Answer))
		for _, rr := range resp.Answer {
			switch a := rr.(type) {
			case *dns.RR_A:
				records.IPs = append(records.IPs, a.A.String())
			}
		}

		if len(records.IPs) > 0 {
			any_ok = true
		} else {
			records.Status = 900
			records.Message = "No records"
		}
	}

	return any_ok
}
Example #11
0
func prepareAnswerMsg(req *dns.Msg, answers []dns.RR) *dns.Msg {
	answerMsg := new(dns.Msg)
	answerMsg.Id = req.Id
	answerMsg.Response = true
	answerMsg.Authoritative = true
	answerMsg.Question = req.Question
	answerMsg.Answer = answers
	answerMsg.Rcode = dns.RcodeSuccess
	answerMsg.Extra = []dns.RR{}
	return answerMsg
}
Example #12
0
func TestServeDNSOverrideIPv6(t *testing.T) {
	t.Parallel()
	const hostname = "foo.com."
	var a App
	a.Overrides.Store(Overrides{hostname: net.ParseIP("1.2.3.4")})
	req := new(dns.Msg)
	req.Opcode = dns.OpcodeQuery
	req.Question = []dns.Question{{Name: hostname, Qtype: qtypeIPv6}}
	var w fDNSResponseWriter
	a.ServeDNS(&w, req)
	ensure.DeepEqual(t, len(w.msg.Answer), 0)
}
Example #13
0
func findSoaNs(domain string) (string, string, string) {

	var cname string
	var soa string
	var ns string

	add := func(c, s, n string) {
		cname += c
		soa += s
		ns += n
		return
	}

	cname += domain + ","
	m1 := new(dns.Msg)
	m1.Id = dns.Id()
	m1.RecursionDesired = true
	m1.Question = make([]dns.Question, 1)
	m1.Question[0] = dns.Question{domain, dns.TypeSOA, dns.ClassINET}
	in, _ := dns.Exchange(m1, (cf.Servers[1] + ":53"))
	rrList := [...][]dns.RR{in.Answer, in.Ns, in.Extra}

	for _, rr := range rrList {
		for i := len(rr) - 1; i >= 0; i-- {
			switch rr[i].Header().Rrtype {
			case dns.TypeCNAME:
				temp_cname := rr[i].(*dns.CNAME)
				add(findSoaNs(temp_cname.Target))
				//				fmt.Println(  "temp_cname:" , temp_cname )
				return cname, soa, ns
				break
			case dns.TypeNS:
				temp_ns := rr[i].(*dns.NS)
				ns += temp_ns.Ns + "," // + "|" +  fmt.Sprint( temp_ns.Hdr.Ttl ) + ","
				//				fmt.Println(  "temp_ns:" , temp_ns )
				break
			case dns.TypeSOA:
				temp_soa := rr[i].(*dns.SOA)
				soa += temp_soa.Ns + "," // + "|" + fmt.Sprint( temp_soa.Hdr.Ttl ) + ","
				//				fmt.Println( "temp_soa:" , temp_soa )
				break
			}
		}
	}

	return cname, soa, ns
}
Example #14
0
func (this *UDPNameServer) BuildQueryA(domain string, id uint16) *alloc.Buffer {
	buffer := alloc.NewBuffer()
	msg := new(dns.Msg)
	msg.Id = id
	msg.RecursionDesired = true
	msg.Question = []dns.Question{
		dns.Question{
			Name:   dns.Fqdn(domain),
			Qtype:  dns.TypeA,
			Qclass: dns.ClassINET,
		}}

	writtenBuffer, _ := msg.PackBuffer(buffer.Value)
	buffer.Slice(0, len(writtenBuffer))

	return buffer
}
Example #15
0
func fakeMsg(dom string, rrHeader uint16, proto string, serverPort int) (*dns.Msg, error) {
	qc := uint16(dns.ClassINET)

	c := new(dns.Client)
	c.Net = proto

	m := new(dns.Msg)
	m.Question = make([]dns.Question, 1)
	m.Question[0] = dns.Question{
		Name:   dns.Fqdn(dom),
		Qtype:  rrHeader,
		Qclass: qc,
	}
	m.RecursionDesired = true
	in, _, err := c.Exchange(m, "127.0.0.1:"+strconv.Itoa(serverPort))
	return in, err

}
Example #16
0
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)
}
Example #17
0
func (s *server) HealthCheck() {
	c := new(dns.Client)
	c.Net = "tcp"

	m := new(dns.Msg)
	m.Question = make([]dns.Question, 1)
	m.Question[0] = dns.Question{HealthQuery, dns.TypeTXT, dns.ClassCHAOS}

	// doing this in the loop is not the best idea
	for _, serv := range s.router.Servers() {
		if !check(c, m, serv) {
			// do it again
			if !check(c, m, serv) {
				log.Printf("healthcheck failed for %s", serv)
				s.router.RemoveServer(serv)
			}
		}
	}
}
Example #18
0
/*
 * makeMessage() - construct DNS message structure
 */
func makeMessage(c *Context, qname, qtype, qclass string, ext Extension) *dns.Msg {

	m := new(dns.Msg)
	m.Id = dns.Id()

	if c.restype == RESOLUTION_STUB {
		m.RecursionDesired = true
	} else {
		m.RecursionDesired = false
	}

	if c.adflag {
		m.AuthenticatedData = true
	}

	if c.cdflag {
		m.CheckingDisabled = true
	}

	if ext["dnssec_return_status"] || ext["dnssec_return_only_secure"] || ext["dnssec_return_validation_chain"] {
		opt := new(dns.OPT)
		opt.Hdr.Name = "."
		opt.Hdr.Rrtype = dns.TypeOPT
		opt.SetDo()
		m.Extra = append(m.Extra, opt)
	}

	m.Question = make([]dns.Question, 1)
	qtype_int, ok := dns.StringToType[strings.ToUpper(qtype)]
	if !ok {
		fmt.Printf("%s: Unrecognized query type.\n", qtype)
		return nil
	}
	qclass_int, ok := dns.StringToClass[strings.ToUpper(qclass)]
	if !ok {
		fmt.Printf("%s: Unrecognized query class.\n", qclass)
		return nil
	}
	m.Question[0] = dns.Question{qname, qtype_int, qclass_int}

	return m
}
Example #19
0
func main() {
	if len(os.Args) != 2 {
		fmt.Printf("%s NAME\n", os.Args[0])
		os.Exit(1)
	}
	name := os.Args[1]
	conf, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
	client := new(dns.Client)
	message := new(dns.Msg)
	message.Question = make([]dns.Question, 1)
	message.Question[0] = dns.Question{BASE, dns.TypeTXT, dns.ClassINET}
	message.SetEdns0(4096, true)
	message.RecursionDesired = true
	reply, _, err := client.Exchange(message, conf.Servers[0]+":"+conf.Port)
	if err != nil {
		fmt.Printf("Cannot get info for %s: %s\n", BASE, err)
		os.Exit(1)
	}
	if reply.Rcode != dns.RcodeSuccess {
		fmt.Printf("Bad answer from the resolver: %v\n", reply.Rcode)
		os.Exit(1)
	}
	if len(reply.Answer) == 0 {
		fmt.Printf("Zero answer for %s\n", BASE)
		os.Exit(1)
	}
	toReporter := make(chan instanceQuery)
	urls := 0
	for _, rr := range reply.Answer {
		switch rr.(type) {
		case *dns.TXT:
			url := rr.(*dns.TXT).Txt[0]
			urls++
			go queryOne(toReporter, url, name)
		}
		// Otherwise, ignore it. Probably a DNSSEC signature
	}
	fromReporter := make(chan string)
	go reporter(toReporter, fromReporter, urls)
	<-fromReporter

}
Example #20
0
func (v *UDPNameServer) BuildQueryA(domain string, id uint16) *buf.Buffer {

	msg := new(dns.Msg)
	msg.Id = id
	msg.RecursionDesired = true
	msg.Question = []dns.Question{
		{
			Name:   dns.Fqdn(domain),
			Qtype:  dns.TypeA,
			Qclass: dns.ClassINET,
		}}

	buffer := buf.New()
	buffer.AppendSupplier(func(b []byte) (int, error) {
		writtenBuffer, err := msg.PackBuffer(b)
		return len(writtenBuffer), err
	})

	return buffer
}
Example #21
0
func TestServeDNSForwardNonOverrideQuery(t *testing.T) {
	t.Parallel()
	const ns = "a"
	res := new(dns.Msg)
	a := App{
		Nameservers: []string{ns},
		dnsUDPclient: fDNSClient{
			exchange: func(m *dns.Msg, a string) (*dns.Msg, time.Duration, error) {
				ensure.DeepEqual(t, a, ns)
				return res, time.Minute, nil
			},
		},
	}
	a.Overrides.Store(Overrides{})
	req := new(dns.Msg)
	req.Opcode = dns.OpcodeQuery
	req.Question = []dns.Question{{Name: "foo.com."}}
	var w fDNSResponseWriter
	a.ServeDNS(&w, req)
	ensure.DeepEqual(t, w.msg, res)
}
Example #22
0
// Edns0Version checks the EDNS version in the request. If error
// is nil everything is OK and we can invoke the middleware. If non-nil, the
// returned Msg is valid to be returned to the client (and should). For some
// reason this response should not contain a question RR in the question section.
func Edns0Version(req *dns.Msg) (*dns.Msg, error) {
	opt := req.IsEdns0()
	if opt == nil {
		return nil, nil
	}
	if opt.Version() == 0 {
		return nil, nil
	}
	m := new(dns.Msg)
	m.SetReply(req)
	// zero out question section, wtf.
	m.Question = nil

	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	o.SetVersion(0)
	o.SetExtendedRcode(dns.RcodeBadVers)
	m.Extra = []dns.RR{o}

	return m, errors.New("EDNS0 BADVERS")
}
Example #23
0
func query(dom string) {
	nameserver := "127.0.0.1:8053"

	qt := dns.TypeA
	qc := uint16(dns.ClassINET)

	c := new(dns.Client)
	c.Net = "udp"

	m := new(dns.Msg)
	m.Question = make([]dns.Question, 1)
	m.Question[0] = dns.Question{
		Name:   dns.Fqdn(dom),
		Qtype:  qt,
		Qclass: qc,
	}

	_, _, err := c.Exchange(m, nameserver)
	if err != nil {
		fmt.Println(err)
	}
}
Example #24
0
// Get a single metric from dnsmasq. Returns the numeric value of the
// metric.
func (mc *metricsClient) getSingleMetric(name string) (int64, error) {
	msg := new(dns.Msg)
	msg.Id = dns.Id()
	msg.RecursionDesired = false
	msg.Question = make([]dns.Question, 1)
	msg.Question[0] = dns.Question{
		Name:   name,
		Qtype:  dns.TypeTXT,
		Qclass: dns.ClassCHAOS,
	}

	in, _, err := mc.dnsClient.Exchange(msg, mc.addrPort)
	if err != nil {
		return 0, err
	}

	if len(in.Answer) != 1 {
		return 0, fmt.Errorf("Invalid number of Answer records for %s: %d",
			name, len(in.Answer))
	}

	if t, ok := in.Answer[0].(*dns.TXT); ok {
		glog.V(4).Infof("Got valid TXT response %+v for %s", t, name)
		if len(t.Txt) != 1 {
			return 0, fmt.Errorf("Invalid number of TXT records for %s: %d",
				name, len(t.Txt))
		}

		value, err := strconv.ParseInt(t.Txt[0], 10, 64)
		if err != nil {
			return 0, err
		}

		return value, nil
	}

	return 0, fmt.Errorf("missing txt record for %s", name)
}
Example #25
0
func (r Resolver) ResolveA(addr string) (net.IP, bool) {
	// log.Println("Looking up A for " + addr)

	m1 := new(dns.Msg)
	m1.Id = dns.Id()
	m1.RecursionDesired = true
	m1.Question = make([]dns.Question, 1)
	m1.Question[0] = dns.Question{addr, dns.TypeA, dns.ClassINET}

	c := new(dns.Client)
	in, _, err := c.Exchange(m1, "10.1.3.254:53")
	if err != nil {
		log.Println("Failed on c.Exchange call: " + err.Error())
		return nil, false
	}

	if a, ok := in.Answer[0].(*dns.A); ok {
		// log.Println("I found an answer for " + addr)
		return a.A, true
	}
	// log.Println("Nothing found for " + addr)
	return nil, false
}
Example #26
0
func TestServeDNSOverrideIPv4(t *testing.T) {
	t.Parallel()
	const hostname = "foo.com."
	ip := net.ParseIP("1.2.3.4")
	var a App
	a.Overrides.Store(Overrides{hostname: ip})
	req := new(dns.Msg)
	req.Opcode = dns.OpcodeQuery
	req.Question = []dns.Question{{Name: hostname, Qtype: qtypeIPv4}}
	var w fDNSResponseWriter
	a.ServeDNS(&w, req)
	ensure.DeepEqual(t, w.msg.Answer, []dns.RR{
		&dns.A{
			A: ip,
			Hdr: dns.RR_Header{
				Name:     hostname,
				Rrtype:   1,
				Class:    1,
				Ttl:      100,
				Rdlength: 4,
			},
		},
	})
}
Example #27
0
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 { // supposed responses sent to us are bogus
		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
	}

	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: %5d try: %v %s %s\n", id, query, dns, proto)
			} else {
				log.Printf("id: %5d 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("====================================================")
	}
}
Example #28
0
File: q.go Project: raybejjani/dns
func main() {
	short = flag.Bool("short", false, "abbreviate long DNSSEC records")
	dnssec := flag.Bool("dnssec", false, "request DNSSEC records")
	query := flag.Bool("question", false, "show question")
	check := flag.Bool("check", false, "check internal DNSSEC consistency")
	raw := flag.Bool("raw", false, "do not strip 'http://' from the qname")
	six := flag.Bool("6", false, "use IPv6 only")
	four := flag.Bool("4", false, "use IPv4 only")
	anchor := flag.String("anchor", "", "use the DNSKEY in this file for interal DNSSEC consistency")
	tsig := flag.String("tsig", "", "request tsig with key: [hmac:]name:key")
	port := flag.Int("port", 53, "port number to use")
	aa := flag.Bool("aa", false, "set AA flag in query")
	ad := flag.Bool("ad", false, "set AD flag in query")
	cd := flag.Bool("cd", false, "set CD flag in query")
	rd := flag.Bool("rd", true, "set RD flag in query")
	fallback := flag.Bool("fallback", false, "fallback to 4096 bytes bufsize and after that TCP")
	tcp := flag.Bool("tcp", false, "TCP mode")
	nsid := flag.Bool("nsid", false, "set edns nsid option")
	client := flag.String("client", "", "set edns client-subnet option")
	//serial := flag.Int("serial", 0, "perform an IXFR with this serial")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [options] [@server] [qtype] [qclass] [name ...]\n", os.Args[0])
		flag.PrintDefaults()
	}

	qtype := uint16(0)
	qclass := uint16(dns.ClassINET)
	var qname []string

	flag.Parse()
	if *anchor != "" {
		f, err := os.Open(*anchor)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failure to open %s: %s\n", *anchor, err.Error())
		}
		r, err := dns.ReadRR(f, *anchor)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failure to read an RR from %s: %s\n", *anchor, err.Error())
		}
		if k, ok := r.(*dns.DNSKEY); !ok {
			fmt.Fprintf(os.Stderr, "No DNSKEY read from %s\n", *anchor)
		} else {
			dnskey = k
		}
	}

	var nameserver string

Flags:
	for i := 0; i < flag.NArg(); i++ {
		// If it starts with @ it is a nameserver
		if flag.Arg(i)[0] == '@' {
			nameserver = flag.Arg(i)
			continue Flags
		}
		// First class, then type, to make ANY queries possible
		// And if it looks like type, it is a type
		if k, ok := dns.StringToType[strings.ToUpper(flag.Arg(i))]; ok {
			qtype = k
			continue Flags
		}
		// If it looks like a class, it is a class
		if k, ok := dns.StringToClass[strings.ToUpper(flag.Arg(i))]; ok {
			qclass = k
			continue Flags
		}
		// If it starts with TYPExxx it is unknown rr
		if strings.HasPrefix(flag.Arg(i), "TYPE") {
			i, e := strconv.Atoi(string([]byte(flag.Arg(i))[4:]))
			if e == nil {
				qtype = uint16(i)
				continue Flags
			}
		}

		// Anything else is a qname
		qname = append(qname, flag.Arg(i))
	}
	if len(qname) == 0 {
		qname = make([]string, 1)
		qname[0] = "."
		qtype = dns.TypeNS
	}
	if qtype == 0 {
		qtype = dns.TypeA
	}

	if len(nameserver) == 0 {
		conf, err := dns.ClientConfigFromFile("/etc/resolv.conf")
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(2)
		}
		nameserver = "@" + conf.Servers[0]
	}

	nameserver = string([]byte(nameserver)[1:]) // chop off @
	// if the nameserver is from /etc/resolv.conf the [ and ] are already
	// added, thereby breaking net.ParseIP. Check for this and don't
	// fully qualify such a name
	if nameserver[0] == '[' && nameserver[len(nameserver)-1] == ']' {
		nameserver = nameserver[1 : len(nameserver)-1]
	}
	if i := net.ParseIP(nameserver); i != nil {
		nameserver = net.JoinHostPort(nameserver, strconv.Itoa(*port))
	} else {
		nameserver = dns.Fqdn(nameserver) + ":" + strconv.Itoa(*port)
	}
	c := new(dns.Client)
	if *tcp {
		c.Net = "tcp"
		if *four {
			c.Net = "tcp4"
		}
		if *six {
			c.Net = "tcp6"
		}
	} else {
		c.Net = "udp"
		if *four {
			c.Net = "udp4"
		}
		if *six {
			c.Net = "udp6"
		}
	}

	m := new(dns.Msg)
	m.MsgHdr.Authoritative = *aa
	m.MsgHdr.AuthenticatedData = *ad
	m.MsgHdr.CheckingDisabled = *cd
	m.MsgHdr.RecursionDesired = *rd
	m.Question = make([]dns.Question, 1)

	if *dnssec || *nsid || *client != "" {
		o := new(dns.OPT)
		o.Hdr.Name = "."
		o.Hdr.Rrtype = dns.TypeOPT
		if *dnssec {
			o.SetDo()
			o.SetUDPSize(dns.DefaultMsgSize)
		}
		if *nsid {
			e := new(dns.EDNS0_NSID)
			e.Code = dns.EDNS0NSID
			o.Option = append(o.Option, e)
			// NSD will not return nsid when the udp message size is too small
			o.SetUDPSize(dns.DefaultMsgSize)
		}
		if *client != "" {
			e := new(dns.EDNS0_SUBNET)
			e.Code = dns.EDNS0SUBNET
			e.SourceScope = 0
			e.Address = net.ParseIP(*client)
			if e.Address == nil {
				fmt.Fprintf(os.Stderr, "Failure to parse IP address: %s\n", *client)
				return
			}
			e.Family = 1 // IP4
			e.SourceNetmask = net.IPv4len * 8
			if e.Address.To4() == nil {
				e.Family = 2 // IP6
				e.SourceNetmask = net.IPv6len * 8
			}
			o.Option = append(o.Option, e)
		}
		m.Extra = append(m.Extra, o)
	}

	for _, v := range qname {
		if !*raw && strings.HasPrefix(v, "http://") {
			v = v[7:]
			if v[len(v)-1] == '/' {
				v = v[:len(v)-1]
			}
		}

		m.Question[0] = dns.Question{dns.Fqdn(v), qtype, qclass}
		m.Id = dns.Id()
		// Add tsig
		if *tsig != "" {
			if algo, name, secret, ok := tsigKeyParse(*tsig); ok {
				m.SetTsig(name, algo, 300, time.Now().Unix())
				c.TsigSecret = map[string]string{name: secret}
			} else {
				fmt.Fprintf(os.Stderr, "TSIG key data error\n")
				return
			}
		}
		if *query {
			fmt.Printf("%s", m.String())
			fmt.Printf("\n;; size: %d bytes\n\n", m.Len())
		}
		if qtype == dns.TypeAXFR {
			c.Net = "tcp"
			doXfr(c, m, nameserver)
			continue
		}
		if qtype == dns.TypeIXFR {
			doXfr(c, m, nameserver)
			continue
		}
		r, rtt, e := c.Exchange(m, nameserver)
	Redo:
		if e != nil {
			fmt.Printf(";; %s\n", e.Error())
			continue
		}
		if r.Id != m.Id {
			fmt.Fprintf(os.Stderr, "Id mismatch\n")
			return
		}
		if r.MsgHdr.Truncated && *fallback {
			if c.Net != "tcp" {
				if !*dnssec {
					fmt.Printf(";; Truncated, trying %d bytes bufsize\n", dns.DefaultMsgSize)
					o := new(dns.OPT)
					o.Hdr.Name = "."
					o.Hdr.Rrtype = dns.TypeOPT
					o.SetUDPSize(dns.DefaultMsgSize)
					m.Extra = append(m.Extra, o)
					r, rtt, e = c.Exchange(m, nameserver)
					*dnssec = true
					goto Redo
				} else {
					// First EDNS, then TCP
					fmt.Printf(";; Truncated, trying TCP\n")
					c.Net = "tcp"
					r, rtt, e = c.Exchange(m, nameserver)
					goto Redo
				}
			}
		}
		if r.MsgHdr.Truncated && !*fallback {
			fmt.Printf(";; Truncated\n")
		}
		if *check {
			sigCheck(r, nameserver, *tcp)
		}
		if *short {
			r = shortMsg(r)
		}

		fmt.Printf("%v", r)
		fmt.Printf("\n;; query time: %.3d µs, server: %s(%s), size: %d bytes\n", rtt/1e3, nameserver, c.Net, r.Len())
	}
}
Example #29
0
func TestRecursiveCompress(t *testing.T) {
	const (
		hostname = "foo.example."
		maxSize  = 512
	)

	// Construct a response that is >512 when uncompressed, <512 when compressed
	response := dns.Msg{}
	response.Authoritative = true
	response.Answer = []dns.RR{}
	header := dns.RR_Header{
		Name:   hostname,
		Rrtype: dns.TypeA,
		Class:  dns.ClassINET,
		Ttl:    10,
	}
	for response.Len() <= maxSize {
		ip := address.Address(rand.Uint32()).IP4()
		response.Answer = append(response.Answer, &dns.A{Hdr: header, A: ip})
	}
	response.Compress = true
	require.True(t, response.Len() <= maxSize)

	// A dns server that returns the above response
	var gotRequest = make(chan struct{}, 1)
	handleRecursive := func(w dns.ResponseWriter, req *dns.Msg) {
		gotRequest <- struct{}{}
		require.Equal(t, req.Question[0].Name, hostname)
		response.SetReply(req)
		err := w.WriteMsg(&response)
		require.Nil(t, err)
	}
	mux := dns.NewServeMux()
	mux.HandleFunc(topDomain, handleRecursive)
	udpListener, err := net.ListenPacket("udp", "0.0.0.0:0")
	require.Nil(t, err)
	udpServer := &dns.Server{PacketConn: udpListener, Handler: mux}
	udpServerPort := udpListener.LocalAddr().(*net.UDPAddr).Port
	go udpServer.ActivateAndServe()
	defer udpServer.Shutdown()

	// The weavedns server, pointed at the above server
	dnsserver, _, udpPort, _ := startServer(t, &dns.ClientConfig{
		Servers:  []string{"127.0.0.1"},
		Port:     strconv.Itoa(udpServerPort),
		Ndots:    1,
		Timeout:  5,
		Attempts: 2,
	})
	defer dnsserver.Stop()

	// Now do lookup, check its what we expected.
	// NB this doesn't really test golang's resolver behaves correctly, as I can't see
	// a way to point golangs resolver at a specific hosts.
	req := new(dns.Msg)
	req.Id = dns.Id()
	req.RecursionDesired = true
	req.Question = make([]dns.Question, 1)
	req.Question[0] = dns.Question{
		Name:   hostname,
		Qtype:  dns.TypeA,
		Qclass: dns.ClassINET,
	}
	c := new(dns.Client)
	res, _, err := c.Exchange(req, fmt.Sprintf("127.0.0.1:%d", udpPort))
	require.Nil(t, err)
	require.True(t, len(gotRequest) > 0)
	require.True(t, res.Len() > maxSize)
}
Example #30
0
func route(w dns.ResponseWriter, req *dns.Msg) {
	keyP, err := getKey(req)
	if err != nil {
		failWithRcode(w, req, dns.RcodeRefused)
		return
	}
	if handleSpecialNames(w, req) {
		return
	}
	maxPayloadSize := getMaxPayloadSize(req)
	var resp *dns.Msg
	cacheValP, _ := cache.Get(*keyP)
	if cacheValP != nil {
		cacheVal := cacheValP.(CacheVal)
		remaining := -time.Since(cacheVal.ValidUntil)
		if remaining > 0 {
			resp = cacheVal.Response.Copy()
			resp.Id = req.Id
			resp.Question = req.Question
		}
	}
	if *debug {
		question := req.Question[0]
		cachedStr := ""
		if resp != nil {
			cachedStr = " (cached)"
		}
		log.Printf("%v\t%v %v%v\n", w.RemoteAddr(), question.Name, dns.TypeToString[question.Qtype], cachedStr)
	}
	if resp == nil {
		slipValue := atomic.LoadUint32(&slip)
		if slipValue > 0 && slipValue%2 == 0 {
			atomic.CompareAndSwapUint32(&slip, slipValue, slipValue+1)
			if slipValue%4 == 0 {
				sendTruncated(w, req.MsgHdr)
			} else {
				w.Close()
			}
			return
		}
	}
	if resp == nil {
		resp, err = resolve(req, keyP.DNSSEC)
		if err == nil {
			validUntil := time.Now().Add(getMinTTL(resp))
			cache.Add(*keyP, CacheVal{ValidUntil: validUntil, Response: resp})
		} else {
			if cacheValP == nil {
				w.Close()
				return
			}
			cacheVal := cacheValP.(CacheVal)
			resp = cacheVal.Response.Copy()
			resp.Id = req.Id
			resp.Question = req.Question
		}
	}
	packed, _ := resp.Pack()
	packedLen := len(packed)
	if uint16(packedLen) > maxPayloadSize {
		sendTruncated(w, resp.MsgHdr)
	} else {
		w.WriteMsg(resp)
	}
}