Example #1
0
// NewSimpleRule creates a new Simple Rule
func NewSimpleRule(from, to string) SimpleRule {
	tpf := dns.StringToType[from]
	tpt := dns.StringToType[to]

	// ANY is both a type and class, ANY class rewritting is way more less frequent
	// so we default to ANY as a type.
	clf := dns.StringToClass[from]
	clt := dns.StringToClass[to]
	if from == "ANY" {
		clf = 0
		clt = 0
	}

	// It's only a type/class if uppercase is used.
	if from != strings.ToUpper(from) {
		tpf = 0
		clf = 0
		from = middleware.Name(from).Normalize()
	}
	if to != strings.ToUpper(to) {
		tpt = 0
		clt = 0
		to = middleware.Name(to).Normalize()
	}
	return SimpleRule{From: from, To: to, fromType: tpf, toType: tpt, fromClass: clf, toClass: clt}
}
Example #2
0
func (e Etcd) AAAA(zone string, state middleware.State, previousRecords []dns.RR) (records []dns.RR, debug []msg.Service, err error) {
	services, debug, err := e.records(state, false)
	if err != nil {
		return nil, debug, err
	}

	for _, serv := range services {
		ip := net.ParseIP(serv.Host)
		switch {
		case ip == nil:
			// Try to resolve as CNAME if it's not an IP, but only if we don't create loops.
			if middleware.Name(state.Name()).Matches(dns.Fqdn(serv.Host)) {
				// x CNAME x is a direct loop, don't add those
				continue
			}

			newRecord := serv.NewCNAME(state.QName(), serv.Host)
			if len(previousRecords) > 7 {
				// don't add it, and just continue
				continue
			}
			if isDuplicateCNAME(newRecord, previousRecords) {
				continue
			}

			state1 := copyState(state, serv.Host, state.QType())
			nextRecords, nextDebug, err := e.AAAA(zone, state1, append(previousRecords, newRecord))

			if err == nil {
				// Not only have we found something we should add the CNAME and the IP addresses.
				if len(nextRecords) > 0 {
					records = append(records, newRecord)
					records = append(records, nextRecords...)
					debug = append(debug, nextDebug...)
				}
				continue
			}
			// This means we can not complete the CNAME, try to look else where.
			target := newRecord.Target
			if dns.IsSubDomain(zone, target) {
				// We should already have found it
				continue
			}
			m1, e1 := e.Proxy.Lookup(state, target, state.QType())
			if e1 != nil {
				continue
			}
			// Len(m1.Answer) > 0 here is well?
			records = append(records, newRecord)
			records = append(records, m1.Answer...)
			continue
			// both here again
		case ip.To4() != nil:
			// nada?
		case ip.To4() == nil:
			records = append(records, serv.NewAAAA(state.QName(), ip.To16()))
		}
	}
	return records, debug, nil
}
Example #3
0
func (l Logger) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
	state := middleware.State{W: w, Req: r}
	for _, rule := range l.Rules {
		if middleware.Name(rule.NameScope).Matches(state.Name()) {
			responseRecorder := middleware.NewResponseRecorder(w)
			rcode, err := l.Next.ServeDNS(ctx, responseRecorder, r)

			if rcode > 0 {
				// There was an error up the chain, but no response has been written yet.
				// The error must be handled here so the log entry will record the response size.
				if l.ErrorFunc != nil {
					l.ErrorFunc(responseRecorder, r, rcode)
				} else {
					rc := middleware.RcodeToString(rcode)

					answer := new(dns.Msg)
					answer.SetRcode(r, rcode)
					state.SizeAndDo(answer)

					metrics.Report(state, metrics.Dropped, rc, answer.Len(), time.Now())
					w.WriteMsg(answer)
				}
				rcode = 0
			}
			rep := middleware.NewReplacer(r, responseRecorder, CommonLogEmptyValue)
			rule.Log.Println(rep.Replace(rule.Format))
			return rcode, err

		}
	}
	return l.Next.ServeDNS(ctx, w, r)
}
Example #4
0
func (k Kubernetes) A(zone string, state middleware.State, previousRecords []dns.RR) (records []dns.RR, err error) {
	services, err := k.records(state, false)
	if err != nil {
		return nil, err
	}

	for _, serv := range services {
		ip := net.ParseIP(serv.Host)
		switch {
		case ip == nil:
			// TODO(miek): lowercasing? Should lowercase in everything see #85
			if middleware.Name(state.Name()).Matches(dns.Fqdn(serv.Host)) {
				// x CNAME x is a direct loop, don't add those
				continue
			}

			newRecord := serv.NewCNAME(state.QName(), serv.Host)
			if len(previousRecords) > 7 {
				// don't add it, and just continue
				continue
			}
			if isDuplicateCNAME(newRecord, previousRecords) {
				continue
			}

			state1 := copyState(state, serv.Host, state.QType())
			nextRecords, err := k.A(zone, state1, append(previousRecords, newRecord))

			if err == nil {
				// Not only have we found something we should add the CNAME and the IP addresses.
				if len(nextRecords) > 0 {
					records = append(records, newRecord)
					records = append(records, nextRecords...)
				}
				continue
			}
			// This means we can not complete the CNAME, try to look else where.
			target := newRecord.Target
			if dns.IsSubDomain(zone, target) {
				// We should already have found it
				continue
			}
			m1, e1 := k.Proxy.Lookup(state, target, state.QType())
			if e1 != nil {
				continue
			}
			// Len(m1.Answer) > 0 here is well?
			records = append(records, newRecord)
			records = append(records, m1.Answer...)
			continue
		case ip.To4() != nil:
			records = append(records, serv.NewA(state.QName(), ip.To4()))
		case ip.To4() == nil:
			// nodata?
		}
	}
	return records, nil
}
Example #5
0
func (u *staticUpstream) IsAllowedPath(name string) bool {
	for _, ignoredSubDomain := range u.IgnoredSubDomains {
		if dns.Name(name) == dns.Name(u.From()) {
			return true
		}
		if middleware.Name(name).Matches(ignoredSubDomain + u.From()) {
			return false
		}
	}
	return true
}
Example #6
0
func TestCache(t *testing.T) {
	c, crr := newTestCache()

	for _, tc := range cacheTestCases {
		m := tc.in.Msg()
		m = cacheMsg(m, tc)
		do := tc.in.Do

		mt, _ := middleware.Classify(m)
		key := cacheKey(m, mt, do)
		crr.set(m, key, mt)

		name := middleware.Name(m.Question[0].Name).Normalize()
		qtype := m.Question[0].Qtype
		i, ok := c.get(name, qtype, do)
		if !ok && !m.Truncated {
			t.Errorf("Truncated message should not have been cached")
		}

		if ok {
			resp := i.toMsg(m)

			if !test.Header(t, tc.Case, resp) {
				t.Logf("%v\n", resp)
				continue
			}

			if !test.Section(t, tc.Case, test.Answer, resp.Answer) {
				t.Logf("%v\n", resp)
			}
			if !test.Section(t, tc.Case, test.Ns, resp.Ns) {
				t.Logf("%v\n", resp)

			}
			if !test.Section(t, tc.Case, test.Extra, resp.Extra) {
				t.Logf("%v\n", resp)
			}
		}
	}
}
Example #7
0
func (e Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
	state := middleware.State{W: w, Req: r}
	if state.QClass() != dns.ClassINET {
		return dns.RcodeServerFailure, fmt.Errorf("can only deal with ClassINET")
	}
	name := state.Name()
	if e.Debug {
		if debug := isDebug(name); debug != "" {
			e.debug = r.Question[0].Name
			state.Clear()
			state.Req.Question[0].Name = debug
		}
	}

	// We need to check stubzones first, because we may get a request for a zone we
	// are not auth. for *but* do have a stubzone forward for. If we do the stubzone
	// handler will handle the request.
	if e.Stubmap != nil && len(*e.Stubmap) > 0 {
		for zone := range *e.Stubmap {
			if middleware.Name(zone).Matches(name) {
				stub := Stub{Etcd: e, Zone: zone}
				return stub.ServeDNS(ctx, w, r)
			}
		}
	}

	zone := middleware.Zones(e.Zones).Matches(state.Name())
	if zone == "" {
		if e.Next == nil {
			return dns.RcodeServerFailure, nil
		}
		return e.Next.ServeDNS(ctx, w, r)
	}

	var (
		records, extra []dns.RR
		debug          []msg.Service
		err            error
	)
	switch state.Type() {
	case "A":
		records, debug, err = e.A(zone, state, nil)
	case "AAAA":
		records, debug, err = e.AAAA(zone, state, nil)
	case "TXT":
		records, debug, err = e.TXT(zone, state)
	case "CNAME":
		records, debug, err = e.CNAME(zone, state)
	case "PTR":
		records, debug, err = e.PTR(zone, state)
	case "MX":
		records, extra, debug, err = e.MX(zone, state)
	case "SRV":
		records, extra, debug, err = e.SRV(zone, state)
	case "SOA":
		records, debug, err = e.SOA(zone, state)
	case "NS":
		if state.Name() == zone {
			records, extra, debug, err = e.NS(zone, state)
			break
		}
		fallthrough
	default:
		// Do a fake A lookup, so we can distinguish between NODATA and NXDOMAIN
		_, debug, err = e.A(zone, state, nil)
	}

	if e.debug != "" {
		// Substitute this name with the original when we return the request.
		state.Clear()
		state.Req.Question[0].Name = e.debug
	}

	if isEtcdNameError(err) {
		return e.Err(zone, dns.RcodeNameError, state, debug, err)
	}
	if err != nil {
		return e.Err(zone, dns.RcodeServerFailure, state, debug, err)
	}

	if len(records) == 0 {
		return e.Err(zone, dns.RcodeSuccess, state, debug, err)
	}

	m := new(dns.Msg)
	m.SetReply(r)
	m.Authoritative, m.RecursionAvailable, m.Compress = true, true, true
	m.Answer = append(m.Answer, records...)
	m.Extra = append(m.Extra, extra...)
	if e.debug != "" {
		m.Extra = append(m.Extra, servicesToTxt(debug)...)
	}

	m = dedup(m)
	state.SizeAndDo(m)
	m, _ = state.Scrub(m)
	w.WriteMsg(m)
	return dns.RcodeSuccess, nil
}