go-nsupdate/update.go

148 lines
2.8 KiB
Go
Raw Normal View History

package main
import (
"github.com/miekg/dns"
"time"
"fmt"
"net"
"log"
)
type Update struct {
zone string
name string
ttl int
tsig map[string]string
2016-06-19 11:46:23 -05:00
tsigAlgo TSIGAlgorithm
server string
timeout time.Duration
}
2016-06-19 11:46:23 -05:00
func (u *Update) Init(name string, zone string, server string) error {
2016-06-19 12:05:55 -05:00
if name == "" {
return fmt.Errorf("Missing name")
} else {
u.name = dns.Fqdn(name)
}
2016-06-19 12:05:55 -05:00
if zone == "" {
// guess
if labels := dns.Split(u.name); len(labels) > 1 {
u.zone = u.name[labels[1]:]
} else {
return fmt.Errorf("Missing zone")
}
2016-06-19 11:46:23 -05:00
} else {
2016-06-19 12:05:55 -05:00
u.zone = dns.Fqdn(zone)
}
if server == "" {
if server, err := discoverZoneServer(u.zone); err != nil {
return fmt.Errorf("Failed to discver server")
} else {
log.Printf("discover server=%v", server)
u.server = net.JoinHostPort(server, "53")
}
} else {
if _, _, err := net.SplitHostPort(server); err == nil {
u.server = server
} else {
u.server = net.JoinHostPort(server, "53")
}
}
return nil
}
2016-06-19 11:46:23 -05:00
func (u *Update) InitTSIG(name string, secret string, algo TSIGAlgorithm) {
u.tsig = map[string]string{dns.Fqdn(name): secret}
u.tsigAlgo = algo
}
2016-06-19 11:46:23 -05:00
func (u *Update) buildAddr(ip net.IP) dns.RR {
if ip4 := ip.To4(); ip4 != nil {
return &dns.A{
Hdr: dns.RR_Header{Name: u.name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: uint32(u.ttl)},
A: ip4,
}
}
2016-06-19 11:46:23 -05:00
if ip6 := ip.To16(); ip6 != nil {
return &dns.AAAA{
Hdr: dns.RR_Header{Name: u.name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: uint32(u.ttl)},
AAAA: ip6,
}
}
2016-06-19 11:46:23 -05:00
return nil
}
func (u *Update) buildAddrs(addrs *AddrSet) (rs []dns.RR) {
for _, ip := range addrs.addrs {
rs = append(rs, u.buildAddr(ip))
}
return rs
}
2016-06-19 11:46:23 -05:00
func (u *Update) buildMsg(addrs *AddrSet) *dns.Msg {
var msg = new(dns.Msg)
msg.SetUpdate(u.zone)
msg.RemoveName([]dns.RR{&dns.RR_Header{Name:u.name}})
2016-06-19 11:46:23 -05:00
msg.Insert(u.buildAddrs(addrs))
if u.tsig != nil {
for keyName, _ := range u.tsig {
2016-06-19 11:46:23 -05:00
msg.SetTsig(keyName, string(u.tsigAlgo), TSIG_FUDGE_SECONDS, time.Now().Unix())
}
}
return msg
}
func (u *Update) query(msg *dns.Msg) (*dns.Msg, error) {
var client = new(dns.Client)
client.DialTimeout = u.timeout
client.ReadTimeout = u.timeout
client.WriteTimeout = u.timeout
if u.tsig != nil {
client.TsigSecret = u.tsig
}
msg, _, err := client.Exchange(msg, u.server)
if err != nil {
return msg, fmt.Errorf("dns:Client.Exchange ... %v: %v", u.server, err)
}
if msg.Rcode == dns.RcodeSuccess {
return msg, nil
} else {
return msg, fmt.Errorf("rcode=%v", dns.RcodeToString[msg.Rcode])
}
}
2016-06-19 11:46:23 -05:00
func (u *Update) Update(addrs *AddrSet, verbose bool) error {
q := u.buildMsg(addrs)
if verbose {
log.Printf("query:\n%v", q)
}
r, err := u.query(q)
if err != nil {
return err
}
if verbose {
log.Printf("answer:\n%v", r)
}
return nil
}