package dns import ( "github.com/miekg/dns" "code.crute.me/mcrute/go_ddns_manager/bind" ) type DNSClient struct { Server string } type DNSTransaction struct { zone *bind.Zone key *bind.Key msg *dns.Msg } func (t *DNSTransaction) Upsert(rrs ...RR) *DNSTransaction { t.RemoveAll(rrs...).Insert(rrs...) return t } func (t *DNSTransaction) Insert(rrs ...RR) *DNSTransaction { t.msg.Insert(toRRSet(t.zone, rrs...)) return t } func (t *DNSTransaction) Remove(rrs ...RR) *DNSTransaction { t.msg.Remove(toRRSet(t.zone, rrs...)) return t } func (t *DNSTransaction) RemoveAll(rrs ...RR) *DNSTransaction { t.msg.RemoveRRset(toRRSet(t.zone, rrs...)) return t } func (c *DNSClient) AXFR(zone *bind.Zone) (chan *dns.Envelope, error) { k := zone.Keys()[0] t := &dns.Transfer{TsigSecret: k.AsMap()} // Always uses tcp m := &dns.Msg{} m.SetAxfr(zone.Name) k.Sign(m) return t.In(m, c.Server) } func (c *DNSClient) StartUpdate(zone *bind.Zone) *DNSTransaction { m := &dns.Msg{} m.SetUpdate(zone.Name) return &DNSTransaction{ zone: zone, key: zone.Keys()[0], msg: m, } } func (c *DNSClient) SendUpdate(t *DNSTransaction) error { udp := &dns.Client{Net: "udp", TsigSecret: t.key.AsMap()} tcp := &dns.Client{Net: "tcp", TsigSecret: t.key.AsMap()} t.msg.SetEdns0(4096, false) t.key.Sign(t.msg) in, _, err := udp.Exchange(t.msg, c.Server) if in != nil && in.Truncated { // If the TCP request succeeds, the err will reset to nil in, _, err = tcp.Exchange(t.msg, c.Server) } if err != nil { return err } return nil }