ns-controller: do not use cname aliases
diff --git a/core/ns-controller/controllers/zone.go b/core/ns-controller/controllers/zone.go
index 41fb98f..4969771 100644
--- a/core/ns-controller/controllers/zone.go
+++ b/core/ns-controller/controllers/zone.go
@@ -3,14 +3,17 @@
 import (
 	"fmt"
 	"io"
+	"net"
 	"strings"
+	"sync"
 	"time"
 
 	"github.com/miekg/dns"
 )
 
 type ZoneFile struct {
-	rrs []dns.RR
+	lock sync.Locker
+	rrs  []dns.RR
 }
 
 func NewZoneFile(r io.Reader) (*ZoneFile, error) {
@@ -27,10 +30,12 @@
 			break
 		}
 	}
-	return &ZoneFile{rrs}, nil
+	return &ZoneFile{&sync.Mutex{}, rrs}, nil
 }
 
 func (z *ZoneFile) DeleteTxtRecord(name, value string) {
+	z.lock.Lock()
+	defer z.lock.Unlock()
 	for i, rr := range z.rrs {
 		if txt, ok := rr.(*dns.TXT); ok {
 			if txt.Hdr.Name == name && strings.Join(txt.Txt, "") == value {
@@ -40,7 +45,21 @@
 	}
 }
 
+func (z *ZoneFile) DeleteRecordsFor(name string) {
+	z.lock.Lock()
+	defer z.lock.Unlock()
+	rrs := make([]dns.RR, 0)
+	for _, rr := range z.rrs {
+		if rr.Header().Name != name {
+			rrs = append(rrs, rr)
+		}
+	}
+	z.rrs = rrs
+}
+
 func (z *ZoneFile) CreateOrReplaceTxtRecord(name, value string) {
+	z.lock.Lock()
+	defer z.lock.Unlock()
 	for i, rr := range z.rrs {
 		if txt, ok := rr.(*dns.TXT); ok {
 			if txt.Hdr.Name == name && strings.Join(txt.Txt, "") == value {
@@ -62,7 +81,23 @@
 	})
 }
 
+func (z *ZoneFile) CreateARecord(name, value string) {
+	z.lock.Lock()
+	defer z.lock.Unlock()
+	z.rrs = append(z.rrs, &dns.A{
+		Hdr: dns.RR_Header{
+			Name:   name,
+			Rrtype: dns.TypeA,
+			Class:  dns.ClassINET,
+			Ttl:    300,
+		},
+		A: net.ParseIP(value),
+	})
+}
+
 func (z *ZoneFile) Write(w io.Writer) error {
+	z.lock.Lock()
+	defer z.lock.Unlock()
 	for _, rr := range z.rrs {
 		if soa, ok := rr.(*dns.SOA); ok {
 			soa.Serial = NowUnix()