@@ 35,6 35,8 @@ func parseQuery(m *dns.Msg, r *dns.Msg) {
handleNSRecord(&q, m, r)
case dns.TypeSOA:
handleSOARecord(&q, m, r)
+ case dns.TypeTXT:
+ handleTXTRecord(&q, m, r)
default:
m.SetRcode(r, dns.RcodeNotImplemented)
}
@@ 117,3 119,37 @@ func handleSOARecord(q *dns.Question, m *dns.Msg, r *dns.Msg) {
m.SetRcode(r, dns.RcodeNameError)
}
}
+
+func handleTXTRecord(q *dns.Question, m *dns.Msg, r *dns.Msg) {
+ qName := strings.ToLower(q.Name)
+
+ // NOTE: This handles only _acme-challenge queries
+ expectedPrefix := "_acme-challenge."
+ if !strings.HasPrefix(qName, expectedPrefix) {
+ m.SetRcode(r, dns.RcodeNameError)
+ return
+ }
+ qNameWithoutPrefix, ok := strings.CutPrefix(qName, expectedPrefix)
+ if !ok {
+ m.SetRcode(r, dns.RcodeFormatError)
+ return
+ }
+
+ var ddnsDomain string
+ if index := strings.IndexByte(qNameWithoutPrefix, '.'); index >= 0 {
+ ddnsDomain = qNameWithoutPrefix[:index]
+ } else {
+ m.SetRcode(r, dns.RcodeNameError)
+ return
+ }
+
+ txtRecord, err := db.FetchDomainAcmeChallenge(ddnsDomain)
+ if err != nil {
+ m.SetRcode(r, dns.RcodeNameError)
+ } else {
+ m.Answer = append(m.Answer, &dns.TXT{
+ Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0},
+ Txt: []string{txtRecord},
+ })
+ }
+}