package cooldns import ( "encoding/json" "log" "net/http" "github.com/miekg/dns" ) // See https://go-acme.github.io/lego/dns/httpreq/ type configLego struct { Enable bool `yaml:"enable"` Address string `yaml:"address"` Username string `yaml:"username"` Secret string `yaml:"secret"` } type legoPresent struct { Fqdn string `json:"fqdn"` Value string `json:"value"` } type legoMap map[string]string func startLEGOWebSever(config configLego) *legoMap { mux := http.NewServeMux() acmeMap := make(legoMap) mux.HandleFunc("/present", func(rw http.ResponseWriter, r *http.Request) { if !checkBasicAuth(r, config) { rw.WriteHeader(http.StatusUnauthorized) return } var presentData legoPresent err := json.NewDecoder(r.Body).Decode(&presentData) defer r.Body.Close() if err != nil { log.Printf("Failed to parse request for ACME: %s", err.Error()) } acmeMap[presentData.Fqdn] = presentData.Value rw.WriteHeader(http.StatusOK) }) mux.HandleFunc("/cleanup", func(rw http.ResponseWriter, r *http.Request) { if !checkBasicAuth(r, config) { rw.WriteHeader(http.StatusUnauthorized) return } for k := range acmeMap { delete(acmeMap, k) } rw.WriteHeader(http.StatusOK) }) go func() { if err := http.ListenAndServe(config.Address, mux); err != nil { log.Fatalf("Failed to start Webserver for LEGO: %s\n", err.Error()) } }() log.Printf("Startet webserver on %s", config.Address) return &acmeMap } func checkBasicAuth(r *http.Request, config configLego) bool { if config.Username != "" && config.Secret != "" { u, p, ok := r.BasicAuth() if !ok { return false } if u == config.Username && p == config.Secret { return true } log.Printf("Failed lego authentication") return false } return true } func handleACMERequest(w dns.ResponseWriter, r *dns.Msg, acmeMap *legoMap) bool { if len(r.Question) == 1 { if r.Question[0].Qtype == dns.TypeTXT && r.Question[0].Qclass == dns.ClassINET { if value, ok := (*acmeMap)[r.Question[0].Name]; ok { m := new(dns.Msg) m.SetReply(r) m.Answer = append(m.Answer, &dns.TXT{ Hdr: dns.RR_Header{ Name: r.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0, }, Txt: []string{value}, }) w.WriteMsg(m) return true } } } return false }