Browse Source

Support for CNAME records and aliases

Ask Bjørn Hansen 13 years ago
parent
commit
9312930b31
3 changed files with 50 additions and 7 deletions
  1. 27 5
      config.go
  2. 14 2
      serve.go
  3. 9 0
      types.go

+ 27 - 5
config.go

@@ -123,9 +123,11 @@ func readZoneFile(zoneName, fileName string) (*Zone, error) {
 func setupZoneData(data map[string]interface{}, Zone *Zone) {
 
 	var recordTypes = map[string]uint16{
-		"a":    dns.TypeA,
-		"aaaa": dns.TypeAAAA,
-		"ns":   dns.TypeNS,
+		"a":     dns.TypeA,
+		"aaaa":  dns.TypeAAAA,
+		"ns":    dns.TypeNS,
+		"cname": dns.TypeCNAME,
+		"alias": dns.TypeMF,
 	}
 
 	for dk, dv := range data {
@@ -134,6 +136,7 @@ func setupZoneData(data map[string]interface{}, Zone *Zone) {
 
 		Zone.Labels[dk] = new(Label)
 		label := Zone.Labels[dk]
+		label.Label = dk
 
 		// BUG(ask) Read 'ttl' value in label data
 
@@ -146,13 +149,13 @@ func setupZoneData(data map[string]interface{}, Zone *Zone) {
 				continue
 			}
 
-			//log.Printf("rdata %s TYPE-R %T\n", rdata, rdata)
+			log.Printf("rdata %s TYPE-R %T\n", rdata, rdata)
 
 			records := make(map[string][]interface{})
 
 			switch rdata.(type) {
 			case map[string]interface{}:
-				// Handle map[ns2.example.net:<nil> ns1.example.net:<nil>]
+				// Handle NS map syntax, map[ns2.example.net:<nil> ns1.example.net:<nil>]
 				tmp := make([]interface{}, 0)
 				for rdata_k, rdata_v := range rdata.(map[string]interface{}) {
 					if rdata_v == nil {
@@ -161,6 +164,11 @@ func setupZoneData(data map[string]interface{}, Zone *Zone) {
 					tmp = append(tmp, []string{rdata_k, rdata_v.(string)})
 				}
 				records[rType] = tmp
+			case string:
+				// CNAME and alias
+				tmp := make([]interface{}, 1)
+				tmp[0] = rdata.(string)
+				records[rType] = tmp
 			default:
 				records[rType] = rdata.([]interface{})
 			}
@@ -185,6 +193,7 @@ func setupZoneData(data map[string]interface{}, Zone *Zone) {
 				h.Ttl = uint32(Zone.Options.Ttl)
 				h.Class = dns.ClassINET
 				h.Rrtype = dnsType
+				h.Name = label.Label + "." + Zone.Origin + "."
 
 				switch dnsType {
 				case dns.TypeA, dns.TypeAAAA:
@@ -217,6 +226,19 @@ func setupZoneData(data map[string]interface{}, Zone *Zone) {
 						}
 						record.RR = rr
 					}
+
+				case dns.TypeCNAME:
+					rec := records[rType][i]
+					rr := &dns.RR_CNAME{Hdr: h}
+					rr.Target = rec.(string)
+					record.RR = rr
+
+				case dns.TypeMF:
+					rec := records[rType][i]
+					rr := &dns.RR_MF{Hdr: h}
+					rr.Mf = rec.(string)
+					record.RR = rr
+
 				case dns.TypeNS:
 					rec := records[rType][i]
 					rr := &dns.RR_NS{Hdr: h}

+ 14 - 2
serve.go

@@ -40,13 +40,20 @@ func serve(w dns.ResponseWriter, req *dns.Msg, z *Zone) {
 	}
 	m.Authoritative = true
 
+	// TODO(ask) Fix the findLabels API to make this work better
+	if alias := z.findLabels(label, "", dns.TypeMF); alias != nil &&
+		alias.Records[dns.TypeMF] != nil {
+		// We found an alias record, so pretend the question was for that name instead
+		label = alias.firstRR(dns.TypeMF).(*dns.RR_MF).Mf
+	}
+
 	labels := z.findLabels(label, country, qtype)
 	if labels == nil {
 		// return NXDOMAIN
 		m.SetRcode(req, dns.RcodeNameError)
 		m.Authoritative = true
 
-		m.Ns = []dns.RR{z.Labels[""].Records[dns.TypeSOA][0].RR}
+		m.Ns = []dns.RR{z.SoaRR()}
 
 		w.Write(m)
 		return
@@ -67,7 +74,12 @@ func serve(w dns.ResponseWriter, req *dns.Msg, z *Zone) {
 	}
 
 	if len(m.Answer) == 0 {
-		m.Ns = append(m.Ns, z.Labels[""].Records[dns.TypeSOA][0].RR)
+
+		if cname := z.Labels[label].firstRR(dns.TypeCNAME); cname != nil {
+			m.Answer = append(m.Answer, cname)
+		} else {
+			m.Ns = append(m.Ns, z.SoaRR())
+		}
 	}
 
 	log.Println("Writing reply")

+ 9 - 0
types.go

@@ -42,6 +42,14 @@ type Zone struct {
 	Options   Options
 }
 
+func (l *Label) firstRR(dnsType uint16) dns.RR {
+	return l.Records[dnsType][0].RR
+}
+
+func (z *Zone) SoaRR() dns.RR {
+	return z.Labels[""].firstRR(dns.TypeSOA)
+}
+
 func (z *Zone) findLabels(s, cc string, qtype uint16) *Label {
 
 	selectors := []string{}
@@ -58,6 +66,7 @@ func (z *Zone) findLabels(s, cc string, qtype uint16) *Label {
 	for _, name := range selectors {
 		if label, ok := z.Labels[name]; ok {
 			// return the label if it has the right records
+			// TODO(ask) Should this also look for CNAME or aliases?
 			if label.Records[qtype] != nil {
 				return label
 			}