Пример #1
0
// Sign signs a message m, it takes care of negative or nodata responses as
// well by synthesising NSEC3 records. It will also cache the signatures, using
// a hash of the signed data as a key.
// We also fake the origin TTL in the signature, because we don't want to
// throw away signatures when services decide to have longer TTL. So we just
// set the origTTL to 60.
// TODO(miek): revisit origTTL
func (s *server) Sign(m *dns.Msg, bufsize uint16) {
	now := time.Now().UTC()
	incep := uint32(now.Add(-3 * time.Hour).Unix())     // 2+1 hours, be sure to catch daylight saving time and such
	expir := uint32(now.Add(7 * 24 * time.Hour).Unix()) // sign for a week

	defer func() {
		promCacheSize.WithLabelValues("signature").Set(float64(s.scache.Size()))
	}()

	for _, r := range rrSets(m.Answer) {
		if r[0].Header().Rrtype == dns.TypeRRSIG {
			continue
		}
		if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) {
			continue
		}
		if sig, err := s.signSet(r, now, incep, expir); err == nil {
			m.Answer = append(m.Answer, sig)
		}
	}
	for _, r := range rrSets(m.Ns) {
		if r[0].Header().Rrtype == dns.TypeRRSIG {
			continue
		}
		if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) {
			continue
		}
		if sig, err := s.signSet(r, now, incep, expir); err == nil {
			m.Ns = append(m.Ns, sig)
		}
	}
	for _, r := range rrSets(m.Extra) {
		if r[0].Header().Rrtype == dns.TypeRRSIG || r[0].Header().Rrtype == dns.TypeOPT {
			continue
		}
		if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) {
			continue
		}
		if sig, err := s.signSet(r, now, incep, expir); err == nil {
			m.Extra = append(m.Extra, sig)
		}
	}
	if bufsize >= 512 || bufsize <= 4096 {
		// TCP here?
		promErrorCount.WithLabelValues("truncated").Inc()
		m.Truncated = m.Len() > int(bufsize)
	}
	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	o.SetDo()
	o.SetUDPSize(4096) // TODO(miek): echo client
	m.Extra = append(m.Extra, o)
	return
}
Пример #2
0
func (c Case) Msg() *dns.Msg {
	m := new(dns.Msg)
	m.SetQuestion(dns.Fqdn(c.Qname), c.Qtype)
	if c.Do {
		o := new(dns.OPT)
		o.Hdr.Name = "."
		o.Hdr.Rrtype = dns.TypeOPT
		o.SetDo()
		o.SetUDPSize(4096)
		m.Extra = []dns.RR{o}
	}
	return m
}
Пример #3
0
func optToMapStr(rrOPT *mkdns.OPT) common.MapStr {
	optMapStr := common.MapStr{
		"do":        rrOPT.Do(), // true if DNSSEC
		"version":   strconv.FormatUint(uint64(rrOPT.Version()), 10),
		"udp_size":  rrOPT.UDPSize(),
		"ext_rcode": dnsResponseCodeToString(rrOPT.ExtendedRcode()),
	}
	for _, o := range rrOPT.Option {
		switch o.(type) {
		case *mkdns.EDNS0_DAU:
			optMapStr["dau"] = o.String()
		case *mkdns.EDNS0_DHU:
			optMapStr["dhu"] = o.String()
		case *mkdns.EDNS0_EXPIRE:
			optMapStr["local"] = o.String()
		case *mkdns.EDNS0_LLQ:
			optMapStr["llq"] = o.String()
		case *mkdns.EDNS0_LOCAL:
			optMapStr["local"] = o.String()
		case *mkdns.EDNS0_N3U:
			optMapStr["n3u"] = o.String()
		case *mkdns.EDNS0_NSID:
			optMapStr["nsid"] = o.String()
		case *mkdns.EDNS0_SUBNET:
			var draft string
			if o.(*mkdns.EDNS0_SUBNET).DraftOption {
				draft = " draft"
			}
			optMapStr["subnet"] = o.String() + draft
		case *mkdns.EDNS0_UL:
			optMapStr["ul"] = o.String()
		}
	}
	return optMapStr
}
Пример #4
0
// Sign signs a message m, it takes care of negative or nodata responses as
// well by synthesising NSEC3 records. It will also cache the signatures, using
// a hash of the signed data as a key.
// We also fake the origin TTL in the signature, because we don't want to
// throw away signatures when services decide to have longer TTL. So we just
// set the origTTL to 60.
// TODO(miek): revisit origTTL
func (s *server) Sign(m *dns.Msg, bufsize uint16) {
	now := time.Now().UTC()
	incep := uint32(now.Add(-3 * time.Hour).Unix())     // 2+1 hours, be sure to catch daylight saving time and such
	expir := uint32(now.Add(7 * 24 * time.Hour).Unix()) // sign for a week

	for _, r := range rrSets(m.Answer) {
		if r[0].Header().Rrtype == dns.TypeRRSIG {
			continue
		}
		if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) {
			continue
		}
		if sig, err := s.signSet(r, now, incep, expir); err == nil {
			m.Answer = append(m.Answer, sig)
		}
	}
	for _, r := range rrSets(m.Ns) {
		if r[0].Header().Rrtype == dns.TypeRRSIG {
			continue
		}
		if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) {
			continue
		}
		if sig, err := s.signSet(r, now, incep, expir); err == nil {
			m.Ns = append(m.Ns, sig)
		}
	}
	for _, r := range rrSets(m.Extra) {
		if r[0].Header().Rrtype == dns.TypeRRSIG || r[0].Header().Rrtype == dns.TypeOPT {
			continue
		}
		if !dns.IsSubDomain(s.config.Domain, r[0].Header().Name) {
			continue
		}
		if sig, err := s.signSet(r, now, incep, expir); err == nil {
			m.Extra = append(m.Extra, sig)
		}
	}

	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	o.SetDo()
	o.SetUDPSize(4096) // TODO(miek): echo client
	m.Extra = append(m.Extra, o)
	return
}
Пример #5
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
}
Пример #6
0
func exchangeSubnet(c *C, name string, dnstype uint16, ip string) *dns.Msg {
	msg := new(dns.Msg)

	msg.SetQuestion(name, dnstype)

	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	e := new(dns.EDNS0_SUBNET)
	e.Code = dns.EDNS0SUBNET
	e.SourceScope = 0
	e.Address = net.ParseIP(ip)
	e.Family = 1 // IP4
	e.SourceNetmask = net.IPv4len * 8
	o.Option = append(o.Option, e)
	msg.Extra = append(msg.Extra, o)

	c.Log("msg", msg)

	return dorequest(c, msg)
}
Пример #7
0
func resolve(server string, domain string, clientIp *string) ([]dns.RR, error) {
	// queryType
	var qtype uint16
	qtype = dns.TypeA

	// dnsServer
	if !strings.HasSuffix(server, ":53") {
		server += ":53"
	}

	domain = dns.Fqdn(domain)

	msg := new(dns.Msg)
	msg.SetQuestion(domain, qtype)
	msg.RecursionDesired = true

	if *clientIP != "" {
		opt := new(dns.OPT)
		opt.Hdr.Name = "."
		opt.Hdr.Rrtype = dns.TypeOPT
		e := new(dns.EDNS0_SUBNET)
		e.Code = dns.EDNS0SUBNET
		e.Family = 1 // ipv4
		e.SourceNetmask = 32
		e.SourceScope = 0
		e.Address = net.ParseIP(*clientIP).To4()
		opt.Option = append(opt.Option, e)
		msg.Extra = []dns.RR{opt}
	}

	client := &dns.Client{
		DialTimeout:  5 * time.Second,
		ReadTimeout:  20 * time.Second,
		WriteTimeout: 20 * time.Second,
	}

	resp, rtt, err := client.Exchange(msg, server)
	return resp.Answer, err
}
Пример #8
0
func OPT(bufsize int, do bool) *dns.OPT {
	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	o.SetVersion(0)
	o.SetUDPSize(uint16(bufsize))
	if do {
		o.SetDo()
	}
	return o
}
Пример #9
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")
}
Пример #10
0
import (
	"net"
	"strconv"
	"strings"

	"github.com/miekg/dns"
	"github.com/skynetservices/skydns/msg"
)

const ednsStubCode = dns.EDNS0LOCALSTART + 10

// ednsStub is the EDNS0 record we add to stub queries. Queries which have this record are
// not forwarded again.
var ednsStub = func() *dns.OPT {
	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	e := new(dns.EDNS0_LOCAL)
	e.Code = ednsStubCode
	e.Data = []byte{1}
	o.Option = append(o.Option, e)
	return o
}()

// 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)
Пример #11
0
// sign signs a message m, it takes care of negative or nodata responses as
// well by synthesising NSEC3 records. It will also cache the signatures, using
// a hash of the signed data as a key.
// We also fake the origin TTL in the signature, because we don't want to
// throw away signatures when services decide to have longer TTL. So we just
// set the origTTL to 60.
func (s *server) sign(m *dns.Msg, bufsize uint16) {
	now := time.Now().UTC()
	incep := uint32(now.Add(-2 * time.Hour).Unix())     // 2 hours, be sure to catch daylight saving time and such
	expir := uint32(now.Add(7 * 24 * time.Hour).Unix()) // sign for a week

	// TODO(miek): repeating this two times?
	for _, r := range rrSets(m.Answer) {
		if r[0].Header().Rrtype == dns.TypeRRSIG {
			continue
		}
		key := cache.key(r)
		if s := cache.search(key); s != nil {
			if s.ValidityPeriod(now.Add(-24 * time.Hour)) {
				m.Answer = append(m.Answer, s)
				continue
			}
			cache.remove(key)
		}
		sig, err, shared := inflight.Do(key, func() (*dns.RRSIG, error) {
			sig1 := s.NewRRSIG(incep, expir)
			if r[0].Header().Rrtype == dns.TypeNSEC3 {
				sig1.OrigTtl = s.config.MinTtl
				sig1.Header().Ttl = s.config.MinTtl
			}
			e := sig1.Sign(s.config.PrivKey, r)
			if e != nil {
				log.Printf("failed to sign: %s\n", e.Error())
			}
			return sig1, e
		})
		if err != nil {
			continue
		}
		if !shared {
			// is it possible to miss this, due the the c.dups > 0 in Do()? TODO(miek)
			cache.insert(key, sig)
		}
		m.Answer = append(m.Answer, dns.Copy(sig).(*dns.RRSIG))
	}
	for _, r := range rrSets(m.Ns) {
		if r[0].Header().Rrtype == dns.TypeRRSIG {
			continue
		}
		key := cache.key(r)
		if s := cache.search(key); s != nil {
			if s.ValidityPeriod(now.Add(-24 * time.Hour)) {
				m.Ns = append(m.Ns, s)
				continue
			}
			cache.remove(key)
		}
		sig, err, shared := inflight.Do(key, func() (*dns.RRSIG, error) {
			sig1 := s.NewRRSIG(incep, expir)
			if r[0].Header().Rrtype == dns.TypeNSEC3 {
				sig1.OrigTtl = s.config.MinTtl
				sig1.Header().Ttl = s.config.MinTtl
			}
			e := sig1.Sign(s.config.PrivKey, r)
			if e != nil {
				log.Printf("failed to sign: %s\n", e.Error())
			}
			return sig1, e
		})
		if err != nil {
			continue
		}
		if !shared {
			// is it possible to miss this, due the the c.dups > 0 in Do()? TODO(miek)
			cache.insert(key, sig)
		}
		m.Ns = append(m.Ns, dns.Copy(sig).(*dns.RRSIG))
	}
	// TODO(miek): Forget the additional section for now
	if bufsize >= 512 || bufsize <= 4096 {
		m.Truncated = m.Len() > int(bufsize)
	}
	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	o.SetDo()
	o.SetUDPSize(4096)
	m.Extra = append(m.Extra, o)
	return
}
Пример #12
0
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())
	}
}
Пример #13
0
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")
	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 as trust anchor")
	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, multiple queries are asked over the same connection")
	nsid := flag.Bool("nsid", false, "set edns nsid option")
	client := flag.String("client", "", "set edns client-subnet option")
	clientdraftcode := flag.Bool("clientdraft", false, "set edns client-subnet option using the draft option code")
	opcode := flag.String("opcode", "query", "set opcode to query|update|notify")
	rcode := flag.String("rcode", "success", "set rcode to noerror|formerr|nxdomain|servfail|...")
	//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()
	}

	var (
		qtype  []uint16
		qclass []uint16
		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 = append(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 = append(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 = append(qtype, uint16(i))
				continue Flags
			}
		}
		// If it starts with CLASSxxx it is unknown class
		if strings.HasPrefix(flag.Arg(i), "CLASS") {
			i, e := strconv.Atoi(string([]byte(flag.Arg(i))[5:]))
			if e == nil {
				qclass = append(qclass, uint16(i))
				continue Flags
			}
		}
		// Anything else is a qname
		qname = append(qname, flag.Arg(i))
	}
	if len(qname) == 0 {
		qname = []string{"."}
		if len(qtype) == 0 {
			qtype = append(qtype, dns.TypeNS)
		}
	}
	if len(qtype) == 0 {
		qtype = append(qtype, dns.TypeA)
	}
	if len(qclass) == 0 {
		qclass = append(qclass, dns.ClassINET)
	}

	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)
	t := new(dns.Transfer)
	c.Net = "udp"
	if *four {
		c.Net = "udp4"
	}
	if *six {
		c.Net = "udp6"
	}
	if *tcp {
		c.Net = "tcp"
		if *four {
			c.Net = "tcp4"
		}
		if *six {
			c.Net = "tcp6"
		}
	}

	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)
	m.Opcode = dns.OpcodeQuery
	if op, ok := dns.StringToOpcode[strings.ToUpper(*opcode)]; ok {
		m.Opcode = op
	}
	m.Rcode = dns.RcodeSuccess
	if rc, ok := dns.StringToRcode[strings.ToUpper(*rcode)]; ok {
		m.Rcode = rc
	}

	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
			if *clientdraftcode {
				e.DraftOption = true
			}
			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)
	}
	if *tcp {
		co := new(dns.Conn)
		tcp := "tcp"
		if *six {
			tcp = "tcp6"
		}
		var err error
		if co.Conn, err = net.DialTimeout(tcp, nameserver, 2*time.Second); err != nil {
			fmt.Fprintf(os.Stderr, "Dialing "+nameserver+" failed: "+err.Error()+"\n")
			return
		}
		defer co.Close()
		qt := dns.TypeA
		qc := uint16(dns.ClassINET)
		for i, v := range qname {
			if i < len(qtype) {
				qt = qtype[i]
			}
			if i < len(qclass) {
				qc = qclass[i]
			}
			m.Question[0] = dns.Question{dns.Fqdn(v), qt, qc}
			m.Id = dns.Id()
			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}
					t.TsigSecret = map[string]string{name: secret}
				} else {
					fmt.Fprintf(os.Stderr, ";; TSIG key data error\n")
					continue
				}
			}
			co.SetReadDeadline(time.Now().Add(2 * time.Second))
			co.SetWriteDeadline(time.Now().Add(2 * time.Second))

			if *query {
				fmt.Printf("%s", m.String())
				fmt.Printf("\n;; size: %d bytes\n\n", m.Len())
			}
			then := time.Now()
			if e := co.WriteMsg(m); e != nil {
				fmt.Fprintf(os.Stderr, ";; %s\n", e.Error())
				continue
			}
			r, e := co.ReadMsg()
			if e != nil {
				fmt.Fprintf(os.Stderr, ";; %s\n", e.Error())
				continue
			}
			rtt := time.Since(then)
			if r.Id != m.Id {
				fmt.Fprintf(os.Stderr, "Id mismatch\n")
				continue
			}

			if *check {
				sigCheck(r, nameserver, true)
				denialCheck(r)
				fmt.Println()
			}
			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, tcp, r.Len())
		}
		return
	}

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

Query:
	for i, v := range qname {
		if i < len(qtype) {
			qt = qtype[i]
		}
		if i < len(qclass) {
			qc = qclass[i]
		}
		m.Question[0] = dns.Question{dns.Fqdn(v), qt, qc}
		m.Id = dns.Id()
		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}
				t.TsigSecret = map[string]string{name: secret}
			} else {
				fmt.Fprintf(os.Stderr, "TSIG key data error\n")
				continue
			}
		}
		if *query {
			fmt.Printf("%s", m.String())
			fmt.Printf("\n;; size: %d bytes\n\n", m.Len())
		}
		if qt == dns.TypeAXFR || qt == dns.TypeIXFR {
			env, err := t.In(m, nameserver)
			if err != nil {
				fmt.Printf(";; %s\n", err.Error())
				continue
			}
			envelope := 0
			record := 0
			for e := range env {
				if e.Error != nil {
					fmt.Printf(";; %s\n", e.Error.Error())
					continue Query
				}
				for _, r := range e.RR {
					fmt.Printf("%s\n", r)
				}
				record += len(e.RR)
				envelope++
			}
			fmt.Printf("\n;; xfr size: %d records (envelopes %d)\n", record, envelope)
			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 !*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)
			denialCheck(r)
			fmt.Println()
		}
		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())
	}
}
Пример #14
0
// addStubEdns0 adds our special option to the message's OPT record.
func addStubEdns0(m *dns.Msg) *dns.Msg {
	option := m.IsEdns0()
	// Add a custom EDNS0 option to the packet, so we can detect loops when 2 stubs are forwarding to each other.
	if option != nil {
		option.Option = append(option.Option, &dns.EDNS0_LOCAL{Code: ednsStubCode, Data: []byte{1}})
		return m
	}

	m.Extra = append(m.Extra, ednsStub)
	return m
}

const (
	ednsStubCode = dns.EDNS0LOCALSTART + 10
	stubDomain   = "stub.dns"
)

var ednsStub = func() *dns.OPT {
	o := new(dns.OPT)
	o.Hdr.Name = "."
	o.Hdr.Rrtype = dns.TypeOPT
	o.SetUDPSize(4096)

	e := new(dns.EDNS0_LOCAL)
	e.Code = ednsStubCode
	e.Data = []byte{1}
	o.Option = append(o.Option, e)
	return o
}()
Пример #15
0
func findA(ednsModel *EDNSModel) string {

	var domain_a string

	var server string
	if len(ednsModel.NS) != 0 {
		server = ednsModel.NS[0]
	} else if len(ednsModel.SOA) != 0 {
		server = ednsModel.SOA[0]
	} else {
		server = OPEN_DNS_SERVER
	}
	if dns.IsFqdn(server) {
		server = server[0 : len(server)-1]
	}
	if !strings.HasSuffix(server, ":53") {
		server += ":53"
	}

	domain := dns.Fqdn(ednsModel.CName[len(ednsModel.CName)-1])
	msg := new(dns.Msg)
	msg.SetQuestion(domain, dns.TypeA)
	msg.RecursionDesired = true

	if ednsModel.ClientIP != "" {

		opt := new(dns.OPT)
		opt.Hdr.Name = "."
		opt.Hdr.Rrtype = dns.TypeOPT

		e := new(dns.EDNS0_SUBNET)
		e.Code = dns.EDNS0SUBNET
		e.Family = 1 // ipv4
		e.SourceNetmask = 32
		e.SourceScope = 0
		e.Address = net.ParseIP(ednsModel.ClientIP).To4()

		opt.Option = append(opt.Option, e)
		msg.Extra = []dns.RR{opt}
	}

	client := &dns.Client{
		DialTimeout:  5 * time.Second,
		ReadTimeout:  20 * time.Second,
		WriteTimeout: 20 * time.Second,
	}

	resp, rtt, err := client.Exchange(msg, server)
	//	fmt.Println(resp.Answer)

	if err != nil {
		fmt.Println(rtt, err) // 记录日志  rtt是查询耗时
		return ""
	}

	for i := len(resp.Answer) - 1; i >= 0; i-- {
		switch resp.Answer[i].Header().Rrtype {
		case dns.TypeA:
			temp_a := resp.Answer[i].(*dns.A)
			domain_a += fmt.Sprint(temp_a.A, ":", temp_a.Hdr.Ttl, ",")
			break
		case dns.TypeCNAME:
			temp_cname := resp.Answer[i].(*dns.CNAME)
			ednsModel.CName = append(ednsModel.CName, temp_cname.Target)
			break
		}
	}

	return domain_a
}