Example #1
0
// lookupNameservers returns the authoritative nameservers for the given fqdn.
func lookupNameservers(fqdn string) ([]string, error) {
	var authoritativeNss []string

	r, err := dnsQuery(fqdn, dns.TypeNS, recursiveNameserver, true)
	if err != nil {
		return nil, err
	}

	for _, rr := range r.Answer {
		if ns, ok := rr.(*dns.NS); ok {
			authoritativeNss = append(authoritativeNss, strings.ToLower(ns.Ns))
		}
	}

	if len(authoritativeNss) > 0 {
		return authoritativeNss, nil
	}

	// Strip of the left most label to get the parent domain.
	offset, _ := dns.NextLabel(fqdn, 0)
	next := fqdn[offset:]
	if dns.CountLabel(next) < 2 {
		return nil, fmt.Errorf("Could not determine authoritative nameservers")
	}

	return lookupNameservers(next)
}
Example #2
0
// needFromPunycode returns true for strings that require punycode decoding.
func needFromPunycode(s string) bool {
	if s == "." {
		return false
	}

	off := 0
	end := false
	pl := len(_PREFIX)
	sl := len(s)

	// If s starts with _PREFIX.
	if sl > pl && s[off:off+pl] == _PREFIX {
		return true
	}

	for {
		// Find the part after the next ".".
		off, end = dns.NextLabel(s, off)
		if end {
			return false
		}
		// If this parts starts with _PREFIX.
		if sl-off > pl && s[off:off+pl] == _PREFIX {
			return true
		}
	}
}
Example #3
0
// ClosestEncloser returns the closest encloser for rr.
func (z *Zone) ClosestEncloser(qname string, qtype uint16) string {
	// tree/tree.go does not store a parent *Node pointer, so we can't
	// just follow up the tree. TODO(miek): fix.
	offset, end := dns.NextLabel(qname, 0)
	for !end {
		elem, _ := z.Tree.Search(qname, qtype)
		if elem != nil {
			return elem.Name()
		}
		qname = qname[offset:]

		offset, end = dns.NextLabel(qname, offset)
	}

	return z.Apex.SOA.Header().Name
}
Example #4
0
func (zs *ZoneStore) match(q string, t uint16) (*Zone, string) {
	zs.RLock()
	defer zs.RUnlock()
	var zone *Zone
	var name string
	b := make([]byte, len(q)) // worst case, one label of length q
	off := 0
	end := false
	for {
		l := len(q[off:])
		for i := 0; i < l; i++ {
			b[i] = q[off+i]
			if b[i] >= 'A' && b[i] <= 'Z' {
				b[i] |= ('a' - 'A')
			}
		}
		if z, ok := zs.store[string(b[:l])]; ok { // 'causes garbage, might want to change the map key
			if t != dns.TypeDS {
				return &z, string(b[:l])
			}
			// Continue for DS to see if we have a parent too, if so delegate to the parent
			zone = &z
			name = string(b[:l])
		}
		off, end = dns.NextLabel(q, off)
		if end {
			break
		}
	}
	return zone, name
}
Example #5
0
// NewMX returns a new MX record based on the Service.
func (s *Service) NewMX(name string) *dns.MX {
	host := dns.Fqdn(s.Host)

	offset, end := 0, false
	for i := 0; i < s.TargetStrip; i++ {
		offset, end = dns.NextLabel(host, offset)
	}
	if end {
		// We overshot the name, use the orignal one.
		offset = 0
	}
	host = host[offset:]

	return &dns.MX{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: s.Ttl},
		Preference: uint16(s.Priority), Mx: host}
}
Example #6
0
// NewSRV returns a new SRV record based on the Service.
func (s *Service) NewSRV(name string, weight uint16) *dns.SRV {
	host := dns.Fqdn(s.Host)

	offset, end := 0, false
	for i := 0; i < s.TargetStrip; i++ {
		offset, end = dns.NextLabel(host, offset)
	}
	if end {
		// We overshot the name, use the orignal one.
		offset = 0
	}
	host = host[offset:]

	return &dns.SRV{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: s.Ttl},
		Priority: uint16(s.Priority), Weight: weight, Port: uint16(s.Port), Target: host}
}
Example #7
0
// targetStrip strips "targetstrip" labels from the left side of the fully qualified name.
func targetStrip(name string, targetStrip int) string {
	if targetStrip == 0 {
		return name
	}

	offset, end := 0, false
	for i := 0; i < targetStrip; i++ {
		offset, end = dns.NextLabel(name, offset)
	}
	if end {
		// We overshot the name, use the orignal one.
		offset = 0
	}
	name = name[offset:]
	return name
}
Example #8
0
// ServeDNS is the entry point for every request to the address that s
// is bound to. It acts as a multiplexer for the requests zonename as
// defined in the request so that the correct zone
// (configuration and middleware stack) will handle the request.
func (s *Server) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
	defer func() {
		// In case the user doesn't enable error middleware, we still
		// need to make sure that we stay alive up here
		if rec := recover(); rec != nil {
			DefaultErrorFunc(w, r, dns.RcodeServerFailure)
		}
	}()

	if m, err := middleware.Edns0Version(r); err != nil { // Wrong EDNS version, return at once.
		rc := middleware.RcodeToString(dns.RcodeBadVers)
		state := middleware.State{W: w, Req: r}

		metrics.Report(state, metrics.Dropped, rc, m.Len(), time.Now())
		w.WriteMsg(m)
		return
	}

	// Execute the optional request callback if it exists
	if s.ReqCallback != nil && s.ReqCallback(w, r) {
		return
	}

	q := r.Question[0].Name
	b := make([]byte, len(q))
	off, end := 0, false
	ctx := context.Background()

	for {
		l := len(q[off:])
		for i := 0; i < l; i++ {
			b[i] = q[off+i]
			// normalize the name for the lookup
			if b[i] >= 'A' && b[i] <= 'Z' {
				b[i] |= ('a' - 'A')
			}
		}

		if h, ok := s.zones[string(b[:l])]; ok {
			if r.Question[0].Qtype != dns.TypeDS {
				rcode, _ := h.stack.ServeDNS(ctx, w, r)
				if RcodeNoClientWrite(rcode) {
					DefaultErrorFunc(w, r, rcode)
				}
				return
			}
		}
		off, end = dns.NextLabel(q, off)
		if end {
			break
		}
	}
	// Wildcard match, if we have found nothing try the root zone as a last resort.
	if h, ok := s.zones["."]; ok {
		rcode, _ := h.stack.ServeDNS(ctx, w, r)
		if RcodeNoClientWrite(rcode) {
			DefaultErrorFunc(w, r, rcode)
		}
		return
	}

	// Still here? Error out with REFUSED and some logging
	remoteHost := w.RemoteAddr().String()
	DefaultErrorFunc(w, r, dns.RcodeRefused)
	log.Printf("[INFO] \"%s %s %s\" - No such zone at %s (Remote: %s)", dns.Type(r.Question[0].Qtype), dns.Class(r.Question[0].Qclass), q, s.Addr, remoteHost)
}