initial commit
This commit is contained in:
193
dns_update.go
Normal file
193
dns_update.go
Normal file
@@ -0,0 +1,193 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/miekg/dns"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DnsUpdate struct {
|
||||
Timeout int
|
||||
TSigKeyName string
|
||||
TSigKey string
|
||||
TSigAlgorithm string
|
||||
DnsHost string
|
||||
Zone string
|
||||
}
|
||||
|
||||
|
||||
func NewTestInstance() *DnsUpdate {
|
||||
return &DnsUpdate{
|
||||
DnsHost: "45.129.181.183:53",
|
||||
Timeout: 300,
|
||||
TSigKeyName: "ddns-key",
|
||||
TSigAlgorithm: dns.HmacSHA512,
|
||||
TSigKey: "rcDW6VdBFV8+LKH4JHXKRan0ZzoJBbbfeK6sL8VOSM60nt99Z/0jQbDp9PyF3q9TsmEBb0rTI2txySIH998Vfw==",
|
||||
Zone: "hub.voglfrei.net",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (d *DnsUpdate) createIp4Addr(host string, addr net.IP) *dns.A {
|
||||
|
||||
ip := addr.To4()
|
||||
if ip == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &dns.A{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: dns.Fqdn(host+"."+d.Zone),
|
||||
Rrtype: dns.TypeA,
|
||||
Class: dns.ClassINET,
|
||||
Ttl: uint32(d.Timeout),
|
||||
},
|
||||
A: ip,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DnsUpdate) createIp6Addr(host string, addr net.IP) *dns.AAAA {
|
||||
|
||||
ip := addr.To16()
|
||||
if ip == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &dns.AAAA{
|
||||
Hdr: dns.RR_Header{
|
||||
Name: dns.Fqdn(host+"."+d.Zone),
|
||||
Rrtype: dns.TypeAAAA,
|
||||
Class: dns.ClassINET,
|
||||
Ttl: uint32(d.Timeout),
|
||||
},
|
||||
AAAA: ip,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DnsUpdate) createRemovals(host string) []dns.RR {
|
||||
return []dns.RR{
|
||||
&dns.RR_Header{Name: dns.Fqdn(host+"."+d.Zone)},
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DnsUpdate) createInserts(host string, addr net.IP) []dns.RR {
|
||||
|
||||
var rr = make([]dns.RR,0)
|
||||
|
||||
if r := d.createIp4Addr(host, addr); r != nil {
|
||||
rr = append(rr, r)
|
||||
}
|
||||
|
||||
if r := d.createIp6Addr(host, addr); r != nil {
|
||||
rr = append(rr, r)
|
||||
}
|
||||
|
||||
return rr
|
||||
}
|
||||
func (d *DnsUpdate) exchange(msg *dns.Msg) (*dns.Msg, error) {
|
||||
var client = new(dns.Client)
|
||||
|
||||
timeout := time.Duration(d.Timeout * int(time.Second))
|
||||
client.DialTimeout = timeout
|
||||
client.ReadTimeout = timeout
|
||||
client.WriteTimeout = timeout
|
||||
client.TsigSecret = map[string]string {dns.Fqdn(d.TSigKeyName): d.TSigKey }
|
||||
|
||||
r, _, err := client.Exchange(msg, d.DnsHost)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r.Rcode == dns.RcodeSuccess {
|
||||
return r, nil
|
||||
} else {
|
||||
return nil, errors.New(dns.RcodeToString[r.Rcode])
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DnsUpdate) Remove(host string) error {
|
||||
var msg = new(dns.Msg)
|
||||
msg.SetUpdate(dns.Fqdn(d.Zone))
|
||||
msg.RemoveName(d.createRemovals(host))
|
||||
msg.SetTsig(dns.Fqdn(d.TSigKeyName), d.TSigAlgorithm, uint16(d.Timeout), time.Now().Unix())
|
||||
|
||||
_, err := d.exchange(msg)
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
func (d *DnsUpdate) Resolve(host string) ([]string, error) {
|
||||
var msg = new(dns.Msg)
|
||||
msg.SetQuestion(dns.Fqdn(host + "." + d.Zone), dns.TypeA)
|
||||
|
||||
r, err := d.exchange(msg)
|
||||
if err != nil {return nil, err}
|
||||
|
||||
hosts := make([]string, 0)
|
||||
for _, v := range r.Answer {
|
||||
if v.Header().Rrtype == dns.TypeA {
|
||||
hosts = append(hosts, v.(*dns.A).A.To4().String())
|
||||
} else if v.Header().Rrtype == dns.TypeAAAA {
|
||||
hosts = append(hosts, v.(*dns.AAAA).AAAA.To16().String())
|
||||
}
|
||||
}
|
||||
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
func (d *DnsUpdate) ExternalResolve(host string) ([]string, error ) {
|
||||
r := &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
d := net.Dialer{
|
||||
Timeout: time.Millisecond * time.Duration(10000),
|
||||
}
|
||||
return d.DialContext(ctx, "udp", "8.8.8.8:53")
|
||||
},
|
||||
}
|
||||
ip, err := r.LookupHost(context.Background(), host + "." + d.Zone)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (d *DnsUpdate) Update(host string, addrs ...string) error {
|
||||
var err error
|
||||
err = d.Remove(host)
|
||||
if err != nil {return err }
|
||||
|
||||
return d.AddMany(host, addrs...)
|
||||
}
|
||||
|
||||
func (d *DnsUpdate) AddMany(host string, addrs ...string) error {
|
||||
var err error
|
||||
|
||||
for _, v := range addrs {
|
||||
err = d.Add(host, v)
|
||||
if err != nil {return err }
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DnsUpdate) Add(host string, addr string) error {
|
||||
ip, err := net.ResolveIPAddr("ip", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var msg = new(dns.Msg)
|
||||
msg.SetUpdate(dns.Fqdn(d.Zone))
|
||||
msg.Insert(d.createInserts(host, ip.IP))
|
||||
msg.SetTsig(dns.Fqdn(d.TSigKeyName), d.TSigAlgorithm, uint16(d.Timeout), time.Now().Unix())
|
||||
|
||||
_, err = d.exchange(msg)
|
||||
return err
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user