564 lines
16 KiB
Go
564 lines
16 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/julienschmidt/httprouter"
|
|
"github.com/miekg/dns"
|
|
|
|
"git.nemunai.re/srs/adlin/libadlin"
|
|
)
|
|
|
|
var (
|
|
ControlSocket = "[2a01:e0a:2b:2250::b]:53"
|
|
tsigName = "ddns."
|
|
tsigSecret = ""
|
|
)
|
|
|
|
func init() {
|
|
router.GET("/api/adomains/", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
return student.GetAssociatedDomains(), nil
|
|
}))
|
|
router.POST("/api/adomains/", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
ue := &struct {
|
|
Domain string `json:"domain"`
|
|
A string `json:"a"`
|
|
AAAA string `json:"aaaa"`
|
|
CNAME string `json:"cname,omitempty"`
|
|
}{}
|
|
|
|
if err := json.Unmarshal(body, &ue); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if ue.Domain != "" && ue.A == "" && ue.AAAA == "" && ue.CNAME == "" {
|
|
student.AssociatedDomain = nil
|
|
|
|
if _, err := student.Update(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return true, nil
|
|
} else if ue.CNAME != "" {
|
|
cname := dns.Fqdn(ue.CNAME)
|
|
student.AssociatedDomain = &cname
|
|
|
|
if _, err := student.Update(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return true, nil
|
|
} else {
|
|
var aaaa net.IP
|
|
if ue != nil && len(ue.AAAA) > 0 {
|
|
aaaa = net.ParseIP(ue.AAAA)
|
|
}
|
|
|
|
return true, AddAssociatedDomains(student, aaaa)
|
|
}
|
|
}))
|
|
router.GET("/api/adomains/:dn", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
return GetAssociatedDomain(student, ps.ByName("dn"))
|
|
}))
|
|
|
|
router.GET("/api/ddomains/", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
return []string{student.MyDelegatedDomain()}, nil
|
|
}))
|
|
router.POST("/api/ddomains/", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
ue := &struct {
|
|
NS string `json:"ns"`
|
|
}{}
|
|
|
|
if err := json.Unmarshal(body, &ue); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if ue.NS == "" {
|
|
student.DelegatedDomain = nil
|
|
|
|
if _, err := student.Update(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return true, nil
|
|
} else {
|
|
ns := dns.Fqdn(ue.NS)
|
|
student.DelegatedDomain = &ns
|
|
|
|
if _, err := student.Update(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
}))
|
|
router.GET("/api/ddomains/:dn/", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
return getRRDelegatedDomain(student, ps.ByName("dn"), "")
|
|
}))
|
|
router.GET("/api/ddomains/:dn/NS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
return getRRDelegatedDomain(student, ps.ByName("dn"), "NS")
|
|
}))
|
|
router.POST("/api/ddomains/:dn/NS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
var ue Entry
|
|
if err := json.Unmarshal(body, &ue); err != nil {
|
|
return nil, err
|
|
}
|
|
return true, AddNSDelegatedDomain(student, ps.ByName("dn"), ue.TTL, strings.Join(ue.Values, " "))
|
|
}))
|
|
router.PATCH("/api/ddomains/:dn/NS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
var ue Entry
|
|
if err := json.Unmarshal(body, &ue); err != nil {
|
|
return nil, err
|
|
}
|
|
return true, UpdateNSDelegatedDomain(student, ps.ByName("dn"), ue.TTL, ue.ValuesFrom, strings.Join(ue.Values, ""))
|
|
}))
|
|
router.DELETE("/api/ddomains/:dn/NS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
var ue Entry
|
|
if err := json.Unmarshal(body, &ue); err != nil {
|
|
return nil, err
|
|
}
|
|
return true, DeleteRRDelegatedDomain(student, ps.ByName("dn"), "NS", strings.Join(ue.Values, " "))
|
|
}))
|
|
router.GET("/api/ddomains/:dn/GLUE", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
return getRRDelegatedDomain(student, ps.ByName("dn"), "AAAA")
|
|
}))
|
|
router.POST("/api/ddomains/:dn/AAAA", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
var ue Entry
|
|
if err := json.Unmarshal(body, &ue); err != nil {
|
|
return nil, err
|
|
}
|
|
return true, AddGLUEDelegatedDomain(student, ps.ByName("dn"), ue.TTL, strings.Join(ue.Values, " "))
|
|
}))
|
|
router.PATCH("/api/ddomains/:dn/AAAA", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
var ue Entry
|
|
if err := json.Unmarshal(body, &ue); err != nil {
|
|
return nil, err
|
|
}
|
|
return true, UpdateGLUEDelegatedDomain(student, ps.ByName("dn"), ue.TTL, ue.ValuesFrom, strings.Join(ue.Values, " "))
|
|
}))
|
|
router.POST("/api/ddomains/:dn/GLUE", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
var ue Entry
|
|
if err := json.Unmarshal(body, &ue); err != nil {
|
|
return nil, err
|
|
}
|
|
return true, UpdateGLUEDelegatedDomain(student, ps.ByName("dn"), ue.TTL, ue.ValuesFrom, strings.Join(ue.Values, " "))
|
|
}))
|
|
router.DELETE("/api/ddomains/:dn/AAAA", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
var ue Entry
|
|
if err := json.Unmarshal(body, &ue); err != nil {
|
|
return nil, err
|
|
}
|
|
return true, DeleteRRDelegatedDomain(student, ps.ByName("dn"), "AAAA", strings.Join(ue.Values, " "))
|
|
}))
|
|
router.GET("/api/ddomains/:dn/DS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
return getRRDelegatedDomain(student, ps.ByName("dn"), "DS")
|
|
}))
|
|
router.POST("/api/ddomains/:dn/DS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
var ue Entry
|
|
if err := json.Unmarshal(body, &ue); err != nil {
|
|
return nil, err
|
|
}
|
|
return true, AddDSDelegatedDomain(student, ps.ByName("dn"), ue.TTL, strings.Join(ue.Values, " "))
|
|
}))
|
|
router.DELETE("/api/ddomains/:dn/DS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) {
|
|
var ue Entry
|
|
if err := json.Unmarshal(body, &ue); err != nil {
|
|
return nil, err
|
|
}
|
|
return true, DeleteRRDelegatedDomain(student, ps.ByName("dn"), "DS", strings.Join(ue.Values, " "))
|
|
}))
|
|
}
|
|
|
|
type Entry struct {
|
|
Domain string `json:"domain"`
|
|
TTL uint32 `json:"ttl"`
|
|
RR string `json:"rr"`
|
|
ValuesFrom string `json:"valuesfrom,omitempty"`
|
|
Values []string `json:"values"`
|
|
}
|
|
|
|
func parseZoneRead(globalDomain string, domain string) (rr []Entry, err error) {
|
|
t := new(dns.Transfer)
|
|
|
|
m := new(dns.Msg)
|
|
t.TsigSecret = map[string]string{tsigName: tsigSecret}
|
|
m.SetAxfr(globalDomain)
|
|
m.SetTsig(tsigName, dns.HmacSHA256, 300, time.Now().Unix())
|
|
|
|
c, err := t.In(m, ControlSocket)
|
|
if err != nil {
|
|
log.Println(globalDomain, err)
|
|
return nil, err
|
|
}
|
|
|
|
for {
|
|
response, ok := <-c
|
|
if !ok {
|
|
break
|
|
}
|
|
|
|
for _, r := range response.RR {
|
|
if strings.HasSuffix(r.Header().Name, domain) {
|
|
z := []string{}
|
|
if v, ok := r.(*dns.A); ok {
|
|
z = append(z, fmt.Sprintf("%s", v.A))
|
|
} else if v, ok := r.(*dns.AAAA); ok {
|
|
z = append(z, fmt.Sprintf("%s", v.AAAA))
|
|
} else if v, ok := r.(*dns.NS); ok {
|
|
z = append(z, fmt.Sprintf("%s", v.Ns))
|
|
} else if v, ok := r.(*dns.DS); ok {
|
|
z = append(z, fmt.Sprintf("%d", v.KeyTag), fmt.Sprintf("%d", v.Algorithm), fmt.Sprintf("%d", v.DigestType), fmt.Sprintf("%s", v.Digest))
|
|
}
|
|
rr = append(rr, Entry{r.Header().Name, r.Header().Ttl, dns.TypeToString[r.Header().Rrtype], "", z})
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func GetAssociatedDomain(student *adlin.Student, dn string) (rrs []Entry, err error) {
|
|
domains := student.GetAssociatedDomains()
|
|
found := false
|
|
for _, d := range domains {
|
|
if d == dn {
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
err = errors.New(fmt.Sprintf("Unable to find domain %q.", dn))
|
|
}
|
|
|
|
if entries, errr := parseZoneRead(adlin.AssociatedDomainSuffix, dn); err != nil {
|
|
return nil, errr
|
|
} else {
|
|
for _, e := range entries {
|
|
if e.RR != "RRSIG" && e.RR != "NSEC" && e.RR != "NSEC3" {
|
|
rrs = append(rrs, e)
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func delAssociatedDomains(student *adlin.Student, dn string) (err error) {
|
|
var adomains []Entry
|
|
adomains, err = GetAssociatedDomain(student, dn)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
m1 := new(dns.Msg)
|
|
m1.Id = dns.Id()
|
|
m1.Opcode = dns.OpcodeUpdate
|
|
m1.Question = make([]dns.Question, 1)
|
|
m1.Question[0] = dns.Question{Name: adlin.AssociatedDomainSuffix, Qtype: dns.TypeSOA, Qclass: dns.ClassINET}
|
|
|
|
var rrs []dns.RR
|
|
for _, domain := range adomains {
|
|
rr, errr := dns.NewRR(fmt.Sprintf("%s %s %s", domain.Domain, domain.RR, strings.Join(domain.Values, " ")))
|
|
if errr != nil {
|
|
return errr
|
|
}
|
|
|
|
rrs = append(rrs, rr)
|
|
}
|
|
|
|
m1.Remove(rrs)
|
|
|
|
c := new(dns.Client)
|
|
c.TsigSecret = map[string]string{tsigName: tsigSecret}
|
|
m1.SetTsig(tsigName, dns.HmacSHA256, 300, time.Now().Unix())
|
|
|
|
_, _, err = c.Exchange(m1, ControlSocket)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func AddAssociatedDomains(student *adlin.Student, aaaa net.IP) (err error) {
|
|
err = delAssociatedDomains(student, student.DefaultAssociatedDomain())
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if aaaa == nil {
|
|
aaaa = net.ParseIP(adlin.StudentIP(student.Id).String() + "1")
|
|
} else if !adlin.StudentNet(student.Id).Contains(aaaa) {
|
|
return errors.New("The associated IP has to be in your IP range.")
|
|
}
|
|
|
|
m2 := new(dns.Msg)
|
|
m2.Id = dns.Id()
|
|
m2.Opcode = dns.OpcodeUpdate
|
|
m2.Question = make([]dns.Question, 1)
|
|
m2.Question[0] = dns.Question{Name: adlin.AssociatedDomainSuffix, Qtype: dns.TypeSOA, Qclass: dns.ClassINET}
|
|
|
|
rrA := new(dns.A)
|
|
rrA.Hdr = dns.RR_Header{Name: student.DefaultAssociatedDomain(), Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 3600}
|
|
rrA.A = net.IPv4(82, 64, 31, 248)
|
|
m2.Insert([]dns.RR{rrA})
|
|
|
|
rrAAAA := new(dns.AAAA)
|
|
rrAAAA.Hdr = dns.RR_Header{Name: student.DefaultAssociatedDomain(), Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 3600}
|
|
rrAAAA.AAAA = aaaa
|
|
m2.Insert([]dns.RR{rrAAAA})
|
|
|
|
c := new(dns.Client)
|
|
c.TsigSecret = map[string]string{tsigName: tsigSecret}
|
|
m2.SetTsig(tsigName, dns.HmacSHA256, 300, time.Now().Unix())
|
|
|
|
_, _, err = c.Exchange(m2, ControlSocket)
|
|
return
|
|
}
|
|
|
|
func getRRDelegatedDomain(student *adlin.Student, dn string, rr string) (rrs []Entry, err error) {
|
|
domains := []string{student.MyDelegatedDomain()}
|
|
found := false
|
|
for _, d := range domains {
|
|
if d == dn {
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
err = errors.New(fmt.Sprintf("Unable to find domain %q.", dn))
|
|
}
|
|
|
|
if entries, errr := parseZoneRead(adlin.DelegatedDomainSuffix, dn); err != nil {
|
|
return nil, errr
|
|
} else {
|
|
for _, e := range entries {
|
|
if e.RR == rr && strings.HasSuffix(strings.TrimSuffix(e.Domain, "."), strings.TrimSuffix(dn, ".")) {
|
|
rrs = append(rrs, e)
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func AddNSDelegatedDomain(student *adlin.Student, dn string, ttl uint32, ns string) (err error) {
|
|
for _, d := range []string{student.MyDelegatedDomain()} {
|
|
m1 := new(dns.Msg)
|
|
m1.Id = dns.Id()
|
|
m1.Opcode = dns.OpcodeUpdate
|
|
m1.Question = make([]dns.Question, 1)
|
|
m1.Question[0] = dns.Question{Name: adlin.DelegatedDomainSuffix, Qtype: dns.TypeSOA, Qclass: dns.ClassINET}
|
|
|
|
rrNS := new(dns.NS)
|
|
rrNS.Hdr = dns.RR_Header{Name: d, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: ttl}
|
|
rrNS.Ns = ns
|
|
m1.Insert([]dns.RR{rrNS})
|
|
|
|
c := new(dns.Client)
|
|
c.TsigSecret = map[string]string{tsigName: tsigSecret}
|
|
m1.SetTsig(tsigName, dns.HmacSHA256, 300, time.Now().Unix())
|
|
|
|
_, _, err = c.Exchange(m1, ControlSocket)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func UpdateNSDelegatedDomain(student *adlin.Student, dn string, ttl uint32, oldns string, ns string) (err error) {
|
|
for _, d := range []string{student.MyDelegatedDomain()} {
|
|
m1 := new(dns.Msg)
|
|
m1.Id = dns.Id()
|
|
m1.Opcode = dns.OpcodeUpdate
|
|
m1.Question = make([]dns.Question, 1)
|
|
m1.Question[0] = dns.Question{Name: adlin.DelegatedDomainSuffix, Qtype: dns.TypeSOA, Qclass: dns.ClassINET}
|
|
|
|
rrOldNS := new(dns.NS)
|
|
rrOldNS.Hdr = dns.RR_Header{Name: d, Rrtype: dns.TypeNS, Class: dns.ClassINET}
|
|
rrOldNS.Ns = oldns
|
|
m1.Remove([]dns.RR{rrOldNS})
|
|
|
|
rrNS := new(dns.NS)
|
|
rrNS.Hdr = dns.RR_Header{Name: d, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: ttl}
|
|
rrNS.Ns = ns
|
|
m1.Insert([]dns.RR{rrNS})
|
|
|
|
c := new(dns.Client)
|
|
c.TsigSecret = map[string]string{tsigName: tsigSecret}
|
|
m1.SetTsig(tsigName, dns.HmacSHA256, 300, time.Now().Unix())
|
|
|
|
_, _, err = c.Exchange(m1, ControlSocket)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func AddGLUEDelegatedDomain(student *adlin.Student, dn string, ttl uint32, aaaa string) (err error) {
|
|
domains := []string{student.MyDelegatedDomain()}
|
|
found := false
|
|
for _, d := range domains {
|
|
if strings.HasSuffix(dn, d) {
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
err = errors.New(fmt.Sprintf("Unable to find domain %q in your whitelist.", dn))
|
|
return
|
|
}
|
|
|
|
m1 := new(dns.Msg)
|
|
m1.Id = dns.Id()
|
|
m1.Opcode = dns.OpcodeUpdate
|
|
m1.Question = make([]dns.Question, 1)
|
|
m1.Question[0] = dns.Question{Name: adlin.DelegatedDomainSuffix, Qtype: dns.TypeSOA, Qclass: dns.ClassINET}
|
|
|
|
var rr dns.RR
|
|
rr, err = dns.NewRR(fmt.Sprintf("%s %d IN AAAA %s", dn, ttl, aaaa))
|
|
if err != nil {
|
|
return
|
|
}
|
|
m1.Insert([]dns.RR{rr})
|
|
|
|
c := new(dns.Client)
|
|
c.TsigSecret = map[string]string{tsigName: tsigSecret}
|
|
m1.SetTsig(tsigName, dns.HmacSHA256, 300, time.Now().Unix())
|
|
|
|
_, _, err = c.Exchange(m1, ControlSocket)
|
|
|
|
return
|
|
}
|
|
|
|
func UpdateGLUEDelegatedDomain(student *adlin.Student, dn string, ttl uint32, oldaaaa string, aaaa string) (err error) {
|
|
domains := []string{student.MyDelegatedDomain()}
|
|
found := false
|
|
for _, d := range domains {
|
|
if strings.HasSuffix(dn, d) {
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
err = errors.New(fmt.Sprintf("Unable to find domain %q in your whitelist.", dn))
|
|
return
|
|
}
|
|
|
|
m1 := new(dns.Msg)
|
|
m1.Id = dns.Id()
|
|
m1.Opcode = dns.OpcodeUpdate
|
|
m1.Question = make([]dns.Question, 1)
|
|
m1.Question[0] = dns.Question{Name: adlin.DelegatedDomainSuffix, Qtype: dns.TypeSOA, Qclass: dns.ClassINET}
|
|
|
|
var rr dns.RR
|
|
|
|
rr, err = dns.NewRR(fmt.Sprintf("%s IN AAAA %s", dn, oldaaaa))
|
|
if err != nil {
|
|
return
|
|
}
|
|
m1.Remove([]dns.RR{rr})
|
|
|
|
rr, err = dns.NewRR(fmt.Sprintf("%s %d IN AAAA %s", dn, ttl, aaaa))
|
|
if err != nil {
|
|
return
|
|
}
|
|
m1.Insert([]dns.RR{rr})
|
|
|
|
c := new(dns.Client)
|
|
c.TsigSecret = map[string]string{tsigName: tsigSecret}
|
|
m1.SetTsig(tsigName, dns.HmacSHA256, 300, time.Now().Unix())
|
|
|
|
_, _, err = c.Exchange(m1, ControlSocket)
|
|
return
|
|
}
|
|
|
|
func AddDSDelegatedDomain(student *adlin.Student, dn string, ttl uint32, rdata string) (err error) {
|
|
domains := []string{student.MyDelegatedDomain()}
|
|
found := false
|
|
for _, d := range domains {
|
|
if dn == d {
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
err = errors.New(fmt.Sprintf("Unable to find domain %q in your whitelist.", dn))
|
|
return
|
|
}
|
|
|
|
var rr dns.RR
|
|
rr, err = dns.NewRR(fmt.Sprintf("%s IN DNSKEY %s", dn, rdata))
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
var dnskey dns.DNSKEY
|
|
if v, ok := rr.(*dns.DNSKEY); ok {
|
|
dnskey = *v
|
|
} else {
|
|
err = errors.New(fmt.Sprintf("This is not a valid DNSKEY record."))
|
|
return
|
|
}
|
|
|
|
m1 := new(dns.Msg)
|
|
m1.Id = dns.Id()
|
|
m1.Opcode = dns.OpcodeUpdate
|
|
m1.Question = make([]dns.Question, 1)
|
|
m1.Question[0] = dns.Question{Name: adlin.DelegatedDomainSuffix, Qtype: dns.TypeSOA, Qclass: dns.ClassINET}
|
|
|
|
var ds *dns.DS
|
|
ds = dnskey.ToDS(dns.SHA256)
|
|
if ds == nil {
|
|
err = errors.New(fmt.Sprintf("Unable to generate corresponding DS record, please check given data."))
|
|
return
|
|
}
|
|
m1.Insert([]dns.RR{ds})
|
|
|
|
c := new(dns.Client)
|
|
c.TsigSecret = map[string]string{tsigName: tsigSecret}
|
|
m1.SetTsig(tsigName, dns.HmacSHA256, 300, time.Now().Unix())
|
|
|
|
_, _, err = c.Exchange(m1, ControlSocket)
|
|
return
|
|
}
|
|
|
|
func DeleteRRDelegatedDomain(student *adlin.Student, dn string, rr string, values ...string) (err error) {
|
|
domains := []string{student.MyDelegatedDomain()}
|
|
found := false
|
|
for _, d := range domains {
|
|
if strings.HasSuffix(dn, d) {
|
|
found = true
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
err = errors.New(fmt.Sprintf("Unable to find domain %q in your whitelist.", dn))
|
|
return
|
|
}
|
|
|
|
m1 := new(dns.Msg)
|
|
m1.Id = dns.Id()
|
|
m1.Opcode = dns.OpcodeUpdate
|
|
m1.Question = make([]dns.Question, 1)
|
|
m1.Question[0] = dns.Question{Name: adlin.DelegatedDomainSuffix, Qtype: dns.TypeSOA, Qclass: dns.ClassINET}
|
|
|
|
rrr, errr := dns.NewRR(fmt.Sprintf("%s %s %s", dn, rr, strings.Join(values, " ")))
|
|
if errr != nil {
|
|
return errr
|
|
}
|
|
m1.Remove([]dns.RR{rrr})
|
|
|
|
c := new(dns.Client)
|
|
c.TsigSecret = map[string]string{tsigName: tsigSecret}
|
|
m1.SetTsig(tsigName, dns.HmacSHA256, 300, time.Now().Unix())
|
|
|
|
_, _, err = c.Exchange(m1, ControlSocket)
|
|
|
|
return
|
|
}
|