feature/sz/master-slave-compatible #1

Open
simon wants to merge 2 commits from feature/sz/master-slave-compatible into master
3 changed files with 159 additions and 0 deletions
Showing only changes of commit b2701161cb - Show all commits

View File

@ -10,6 +10,7 @@ type AcmednsDB interface {
Register(cidrslice Cidrslice) (ACMETxt, error)
GetByUsername(uuid.UUID) (ACMETxt, error)
GetTXTForDomain(string) ([]string, error)
GetTXTForAllDomains() ([]TXTRecord, error)
Update(ACMETxtPost) error
GetBackend() *sql.DB
SetBackend(*sql.DB)
@ -23,4 +24,8 @@ type AcmednsNS interface {
ParseRecords()
BumpSerial() error
}
type TXTRecord struct {
Subdomain string
Value string
}

View File

@ -263,6 +263,50 @@ func (d *acmednsdb) GetByUsername(u uuid.UUID) (acmedns.ACMETxt, error) {
return acmedns.ACMETxt{}, fmt.Errorf("user not found: %s", u.String())
}
func (d *acmednsdb) GetTXTForAllDomains() ([]acmedns.TXTRecord, error) {
d.Mutex.Lock()
defer d.Mutex.Unlock()
var txts []acmedns.TXTRecord
getSQL := `
SELECT Subdomain, Value FROM txt
`
if d.Config.Database.Engine == "sqlite" {
getSQL = getSQLiteStmt(getSQL)
}
sm, err := d.DB.Prepare(getSQL)
if err != nil {
return txts, err
}
defer sm.Close()
rows, err := sm.Query()
if err != nil {
return txts, err
}
defer rows.Close()
for rows.Next() {
var subdomain string
var value string
err = rows.Scan(&subdomain, &value)
if err != nil {
return txts, err
}
d.Logger.Debugw("GetTXTForAllDomains() TXT Record:", subdomain, value)
txts = append(txts, acmedns.TXTRecord{
Subdomain: subdomain,
Value: value,
})
}
return txts, nil
}
func (d *acmednsdb) GetTXTForDomain(domain string) ([]string, error) {
d.Mutex.Lock()
defer d.Mutex.Unlock()

View File

@ -2,12 +2,48 @@ package nameserver
import (
"fmt"
"net"
"strings"
"github.com/miekg/dns"
)
func (n *Nameserver) handleRequest(w dns.ResponseWriter, r *dns.Msg) {
if len(r.Question) == 1 {
q := r.Question[0]
if q.Qtype == dns.TypeAXFR || q.Qtype == dns.TypeIXFR { // Get remote IP
remoteIP, _, err := net.SplitHostPort(w.RemoteAddr().String())
if err != nil {
n.Logger.Errorw("Failed to parse remote address", "err", err)
m := new(dns.Msg)
m.SetReply(r)
m.Rcode = dns.RcodeRefused
_ = w.WriteMsg(m)
return
}
// Check if remote IP is in slave list
allowed := false
for _, slave := range n.Config.General.SlaveHosts {
if remoteIP == slave {
allowed = true
break
}
}
if !allowed {
n.Logger.Warnw("AXFR/IXFR request denied", "remote", remoteIP)
m := new(dns.Msg)
m.SetReply(r)
m.Rcode = dns.RcodeRefused
_ = w.WriteMsg(m)
return
}
n.handleAXFR(w, r)
return
}
}
m := new(dns.Msg)
m.SetReply(r)
// handle edns0
@ -161,3 +197,77 @@ func (n *Nameserver) getRecord(name string, qtype uint16) ([]dns.RR, error) {
}
return rr, nil
}
func (n *Nameserver) handleAXFR(w dns.ResponseWriter, r *dns.Msg) {
if len(r.Question) == 0 {
return
}
zone := dns.Fqdn(r.Question[0].Name)
records, ok := n.Domains[zone]
if !ok {
m := new(dns.Msg)
m.SetRcode(r, dns.RcodeNameError)
_ = w.WriteMsg(m)
return
}
// AXFR muss über Transfer laufen
tr := new(dns.Transfer)
c := make(chan *dns.Envelope)
go func() {
defer close(c)
var rr []dns.RR
// Start SOA
rr = append(rr, n.SOA)
// NS
rr = append(rr, records.NS...)
// Andere Records
// rr = append(rr, filterSOA(records.Records)...)
rr = append(rr, records.Records...)
// TXT Records nur für diese Zone!
txtRecords, err := n.DB.GetTXTForAllDomains()
if err == nil {
for _, rec := range txtRecords {
if rec.Value == "" {
continue
}
fqdn := dns.Fqdn(rec.Subdomain + "." + zone)
txtRR := &dns.TXT{
Hdr: dns.RR_Header{
Name: fqdn,
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: 1,
},
Txt: []string{rec.Value},
}
rr = append(rr, txtRR)
n.Logger.Debugw("handleAXFR TXT Record", "subdomain", rec.Subdomain, "value", rec.Value, "fqdn", fqdn)
rr = append(rr, txtRR)
}
} else {
n.Logger.Errorw("Failed to get TXT records for AXFR", "error", err)
}
// End SOA
rr = append(rr, n.SOA)
c <- &dns.Envelope{RR: rr}
}()
_ = tr.Out(w, r, c)
}