Custom DNS Server returns only TXT records

This small DNS server only returns one type of record, a TXT record,
meant to be a token assigned by a certificate authority (e.g. Let's
Encrypt) to verify domain ownership.

The TXT record will be updateable by an API endpoint on the webserver
(same executable as the DNS server), but I haven't yet written that
portion.

Drive-by: in our _other_ (main) sslip.io DNS server, I changed `break` →
`continue` in the main loop. Had we gotten a malformed UDP packet, we
would have exited, but now we continue to the next packet. Exiting is
not that big a deal—`monit` would have restarted the server—but moving
on to the next packet is a more robust approach.

[#6]
This commit is contained in:
Brian Cunnie
2021-01-09 10:32:24 -08:00
parent 404e9b2365
commit 0614f2b059
5 changed files with 103 additions and 4 deletions

View File

@@ -19,7 +19,7 @@ func main() {
_, addr, err := conn.ReadFromUDP(query) _, addr, err := conn.ReadFromUDP(query)
if err != nil { if err != nil {
log.Println(err.Error()) log.Println(err.Error())
break continue
} }
go func() { go func() {

View File

@@ -0,0 +1,5 @@
module github.com/cunnie/sslip.io/bosh-release/src/wildcard-dns-http-server
go 1.15
require golang.org/x/net v0.0.0-20201224014010-6772e930b67b

View File

@@ -0,0 +1,6 @@
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@@ -0,0 +1,90 @@
package main
import (
"log"
"net"
"sync"
"golang.org/x/net/dns/dnsmessage"
)
var txt = `Set this TXT record: curl -X POST http://localhost/update -d '{"txt":"Certificate Authority's validation token"}'`
func main() {
conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: 53})
if err != nil {
log.Fatal(err.Error())
}
var group sync.WaitGroup
group.Add(1)
go dnsServer(conn, &group)
group.Add(1)
go httpServer(&group)
group.Wait()
}
func dnsServer(conn *net.UDPConn, group *sync.WaitGroup) {
var query dnsmessage.Message
defer group.Done()
log.Println("I'm firing up the DNS server.")
queryRaw := make([]byte, 512)
for {
_, addr, err := conn.ReadFromUDP(queryRaw)
if err != nil {
log.Println(err.Error())
continue
}
err = query.Unpack(queryRaw)
if err != nil {
log.Println(err.Error())
continue
}
// Technically, there can be multiple questions in a DNS message; practically, there's only one
if len(query.Questions) != 1 {
log.Printf("I expected one question but got %d.\n", len(query.Questions))
continue
}
// We only return answers to TXT records, nothing else
if query.Questions[0].Type != dnsmessage.TypeTXT {
log.Println("I expected a question for a TypeTXT record but got a question for a " + query.Questions[0].Type.String() + " record.")
continue
}
reply := dnsmessage.Message{
Header: dnsmessage.Header{
ID: query.ID,
Response: true,
Authoritative: true,
RecursionDesired: query.RecursionDesired,
},
Questions: query.Questions,
Answers: []dnsmessage.Resource{
{
Header: dnsmessage.ResourceHeader{
Name: query.Questions[0].Name,
Type: dnsmessage.TypeTXT,
Class: dnsmessage.ClassINET,
},
Body: &dnsmessage.TXTResource{TXT: []string{txt}},
},
},
}
replyRaw, err := reply.Pack()
if err != nil {
log.Println(err.Error())
continue
}
_, err = conn.WriteToUDP(replyRaw, addr)
if err != nil {
log.Println(err.Error())
continue
}
log.Printf("%v.%d %s → \"%s\"\n", addr.IP, addr.Port, query.Questions[0].Type.String(), txt)
}
}
func httpServer(group *sync.WaitGroup) {
defer group.Done()
log.Println("I'm firing up the HTTP server.")
}

View File

@@ -91,8 +91,6 @@ docker run --rm -it \
Clean-up: Clean-up:
``` ```
gcloud compute firewall-rules delete sslip-io-allow-dns-http-ssh
gcloud compute firewall-rules delete sslip-io-allow-dns-http
gcloud compute firewall-rules delete sslip-io-allow-dns gcloud compute firewall-rules delete sslip-io-allow-dns
gcloud compute instances delete gcloud compute instances delete sslip
``` ```