feature/sz/master-slave-compatible #1
@ -10,6 +10,7 @@ type AcmednsDB interface {
|
|||||||
Register(cidrslice Cidrslice) (ACMETxt, error)
|
Register(cidrslice Cidrslice) (ACMETxt, error)
|
||||||
GetByUsername(uuid.UUID) (ACMETxt, error)
|
GetByUsername(uuid.UUID) (ACMETxt, error)
|
||||||
GetTXTForDomain(string) ([]string, error)
|
GetTXTForDomain(string) ([]string, error)
|
||||||
|
GetTXTForAllDomains() ([]TXTRecord, error)
|
||||||
Update(ACMETxtPost) error
|
Update(ACMETxtPost) error
|
||||||
GetBackend() *sql.DB
|
GetBackend() *sql.DB
|
||||||
SetBackend(*sql.DB)
|
SetBackend(*sql.DB)
|
||||||
@ -23,4 +24,8 @@ type AcmednsNS interface {
|
|||||||
ParseRecords()
|
ParseRecords()
|
||||||
BumpSerial() error
|
BumpSerial() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TXTRecord struct {
|
||||||
|
Subdomain string
|
||||||
|
Value string
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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())
|
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) {
|
func (d *acmednsdb) GetTXTForDomain(domain string) ([]string, error) {
|
||||||
d.Mutex.Lock()
|
d.Mutex.Lock()
|
||||||
defer d.Mutex.Unlock()
|
defer d.Mutex.Unlock()
|
||||||
|
|||||||
@ -2,12 +2,48 @@ package nameserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (n *Nameserver) handleRequest(w dns.ResponseWriter, r *dns.Msg) {
|
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 := new(dns.Msg)
|
||||||
m.SetReply(r)
|
m.SetReply(r)
|
||||||
// handle edns0
|
// handle edns0
|
||||||
@ -161,3 +197,77 @@ func (n *Nameserver) getRecord(name string, qtype uint16) ([]dns.RR, error) {
|
|||||||
}
|
}
|
||||||
return rr, nil
|
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)
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user