split up modules

This commit is contained in:
Tero Marttila 2016-06-19 19:46:23 +03:00
parent adab1510c9
commit 9026b24cc1
5 changed files with 137 additions and 120 deletions

54
addr.go
View File

@ -2,28 +2,56 @@ package main
import ( import (
"net" "net"
"github.com/miekg/dns" "github.com/vishvananda/netlink"
"fmt"
"log"
) )
type Addr struct { type AddrSet struct {
IP net.IP addrs map[string]net.IP
} }
func (addr Addr) buildRR(name string, ttl int) dns.RR { func (as *AddrSet) ScanInterface(iface string, family Family) error {
if ip4 := addr.IP.To4(); ip4 != nil { link, err := netlink.LinkByName(iface)
return &dns.A{ if err != nil {
Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: uint32(ttl)}, return fmt.Errorf("netlink.LinkByName %v: %v", iface, err)
A: ip4,
}
} }
if ip6 := addr.IP.To16(); ip6 != nil { addrList, err := netlink.AddrList(link, int(family))
return &dns.AAAA{ if err != nil {
Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: uint32(ttl)}, return fmt.Errorf("netlink.AddrList %v: %v", link, err)
AAAA: ip6,
} }
// set
as.addrs = make(map[string]net.IP)
for _, addr := range addrList {
as.applyLinkAddr(link, addr)
} }
return nil return nil
} }
func (as *AddrSet) applyLinkAddr(link netlink.Link, addr netlink.Addr) {
linkUp := link.Attrs().Flags & net.FlagUp != 0
if addr.Scope >= int(netlink.SCOPE_LINK) {
return
}
as.applyAddr(addr.IP, linkUp)
}
// Update state for address
func (as *AddrSet) applyAddr(ip net.IP, up bool) {
if up {
log.Printf("update: up %v", ip)
as.addrs[ip.String()] = ip
} else {
log.Printf("update: down %v", ip)
delete(as.addrs, ip.String())
}
}

26
dns.go Normal file
View File

@ -0,0 +1,26 @@
package main
import (
"github.com/miekg/dns"
"fmt"
)
const TSIG_FUDGE_SECONDS = 300
type TSIGAlgorithm string
func (t *TSIGAlgorithm) UnmarshalFlag(value string) error {
switch (value) {
case "hmac-md5", "md5":
*t = dns.HmacMD5
case "hmac-sha1", "sha1":
*t = dns.HmacSHA1
case "hmac-sha256", "sha256":
*t = dns.HmacSHA256
case "hmac-sha512", "sha512":
*t = dns.HmacSHA512
default:
return fmt.Errorf("Invalid --tsig-algorithm=%v", value)
}
return nil
}

63
main.go
View File

@ -2,51 +2,11 @@ package main
import ( import (
"github.com/jessevdk/go-flags" "github.com/jessevdk/go-flags"
"github.com/vishvananda/netlink"
"github.com/miekg/dns"
"net"
"fmt"
"log" "log"
"os" "os"
"time" "time"
) )
// zero value is unspec=all
type Family int
func (f *Family) UnmarshalFlag(value string) error {
switch (value) {
case "inet", "ipv4":
*f = netlink.FAMILY_V4
case "inet6", "ipv6":
*f = netlink.FAMILY_V6
default:
return fmt.Errorf("Invalid --family=%v", value)
}
return nil
}
const TSIG_FUDGE_SECONDS = 300
type TSIGAlgorithm string
func (t *TSIGAlgorithm) UnmarshalFlag(value string) error {
switch (value) {
case "hmac-md5", "md5":
*t = dns.HmacMD5
case "hmac-sha1", "sha1":
*t = dns.HmacSHA1
case "hmac-sha256", "sha256":
*t = dns.HmacSHA256
case "hmac-sha512", "sha512":
*t = dns.HmacSHA512
default:
return fmt.Errorf("Invalid --tsig-algorithm=%v", value)
}
return nil
}
type Options struct { type Options struct {
Verbose bool `long:"verbose" short:"v"` Verbose bool `long:"verbose" short:"v"`
@ -75,33 +35,32 @@ func main() {
os.Exit(1) os.Exit(1)
} }
var update = &Update{ var update = Update{
zone: dns.Fqdn(options.Zone),
name: dns.Fqdn(options.Name),
ttl: options.TTL, ttl: options.TTL,
timeout: options.Timeout, timeout: options.Timeout,
} }
if _, _, err := net.SplitHostPort(options.Server); err == nil { if err := update.Init(options.Name, options.Zone, options.Server); err != nil {
update.server = options.Server log.Fatalf("init: %v", err)
} else {
update.server = net.JoinHostPort(options.Server, "53")
} }
if options.TSIGName != "" { if options.TSIGName != "" {
log.Printf("using TSIG: %v (algo=%v)", options.TSIGName, options.TSIGAlgorithm) log.Printf("using TSIG: %v (algo=%v)", options.TSIGName, options.TSIGAlgorithm)
update.initTSIG(dns.Fqdn(options.TSIGName), options.TSIGSecret, string(options.TSIGAlgorithm)) update.InitTSIG(options.TSIGName, options.TSIGSecret, options.TSIGAlgorithm)
} }
// run // addrs
var addrs = new(AddrSet)
if options.Interface == "" { if options.Interface == "" {
} else if err := update.scan(options.Interface, int(options.InterfaceFamily)); err != nil { } else if err := addrs.ScanInterface(options.Interface, options.InterfaceFamily); err != nil {
log.Fatalf("scan: %v", err) log.Fatalf("addrs scan: %v", err)
} }
if err := update.update(options.Verbose); err != nil { // update
if err := update.Update(addrs, options.Verbose); err != nil {
log.Fatalf("update: %v", err) log.Fatalf("update: %v", err)
} }
} }

24
netlink.go Normal file
View File

@ -0,0 +1,24 @@
package main
import (
"github.com/vishvananda/netlink"
"fmt"
)
// zero value is unspec=all
type Family int
func (f *Family) UnmarshalFlag(value string) error {
switch (value) {
case "inet", "ipv4":
*f = netlink.FAMILY_V4
case "inet6", "ipv6":
*f = netlink.FAMILY_V6
default:
return fmt.Errorf("Invalid --family=%v", value)
}
return nil
}

View File

@ -1,7 +1,6 @@
package main package main
import ( import (
"github.com/vishvananda/netlink"
"github.com/miekg/dns" "github.com/miekg/dns"
"time" "time"
"fmt" "fmt"
@ -15,83 +14,64 @@ type Update struct {
ttl int ttl int
tsig map[string]string tsig map[string]string
tsigAlgo string tsigAlgo TSIGAlgorithm
server string server string
timeout time.Duration timeout time.Duration
link netlink.Link
addrs map[string]Addr
} }
func (u *Update) initTSIG(name string, secret string, algo string) { func (u *Update) Init(name string, zone string, server string) error {
u.tsig = map[string]string{name: secret} u.name = dns.Fqdn(name)
u.tsigAlgo = algo u.zone = dns.Fqdn(zone)
}
// Update state for link if _, _, err := net.SplitHostPort(server); err == nil {
func (u *Update) scan(iface string, family int) error { u.server = server
link, err := netlink.LinkByName(iface) } else {
if err != nil { u.server = net.JoinHostPort(server, "53")
return fmt.Errorf("netlink.LinkByName %v: %v", iface, err)
}
addrs, err := netlink.AddrList(link, family)
if err != nil {
return fmt.Errorf("netlink.AddrList %v: %v", link, err)
}
// set
u.addrs = make(map[string]Addr)
for _, addr := range addrs {
u.applyLinkAddr(link, addr)
} }
return nil return nil
} }
func (u *Update) applyLinkAddr(link netlink.Link, addr netlink.Addr) { func (u *Update) InitTSIG(name string, secret string, algo TSIGAlgorithm) {
linkUp := link.Attrs().Flags & net.FlagUp != 0 u.tsig = map[string]string{dns.Fqdn(name): secret}
u.tsigAlgo = algo
if addr.Scope >= int(netlink.SCOPE_LINK) {
return
}
u.apply(addr.IP, linkUp)
} }
// Update state for address func (u *Update) buildAddr(ip net.IP) dns.RR {
func (u *Update) apply(ip net.IP, up bool) { if ip4 := ip.To4(); ip4 != nil {
if up { return &dns.A{
log.Printf("update: up %v", ip) Hdr: dns.RR_Header{Name: u.name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: uint32(u.ttl)},
A: ip4,
u.addrs[ip.String()] = Addr{IP: ip} }
} else {
log.Printf("update: down %v", ip)
delete(u.addrs, ip.String())
} }
}
func (u *Update) buildRR() (rs []dns.RR) { if ip6 := ip.To16(); ip6 != nil {
for _, addr := range u.addrs { return &dns.AAAA{
rs = append(rs, addr.buildRR(u.name, u.ttl)) Hdr: dns.RR_Header{Name: u.name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: uint32(u.ttl)},
AAAA: ip6,
}
}
return nil
}
func (u *Update) buildAddrs(addrs *AddrSet) (rs []dns.RR) {
for _, ip := range addrs.addrs {
rs = append(rs, u.buildAddr(ip))
} }
return rs return rs
} }
func (u *Update) buildMsg() *dns.Msg { func (u *Update) buildMsg(addrs *AddrSet) *dns.Msg {
var msg = new(dns.Msg) var msg = new(dns.Msg)
msg.SetUpdate(u.zone) msg.SetUpdate(u.zone)
msg.RemoveName([]dns.RR{&dns.RR_Header{Name:u.name}}) msg.RemoveName([]dns.RR{&dns.RR_Header{Name:u.name}})
msg.Insert(u.buildRR()) msg.Insert(u.buildAddrs(addrs))
if u.tsig != nil { if u.tsig != nil {
for keyName, _ := range u.tsig { for keyName, _ := range u.tsig {
msg.SetTsig(keyName, u.tsigAlgo, TSIG_FUDGE_SECONDS, time.Now().Unix()) msg.SetTsig(keyName, string(u.tsigAlgo), TSIG_FUDGE_SECONDS, time.Now().Unix())
} }
} }
@ -122,8 +102,8 @@ func (u *Update) query(msg *dns.Msg) (*dns.Msg, error) {
} }
} }
func (u *Update) update(verbose bool) error { func (u *Update) Update(addrs *AddrSet, verbose bool) error {
q := u.buildMsg() q := u.buildMsg(addrs)
if verbose { if verbose {
log.Printf("query:\n%v", q) log.Printf("query:\n%v", q)