implemented lego HTTP endpoint

This commit is contained in:
Niklas 2021-01-08 16:08:57 +01:00
parent c7bac27a53
commit fe7c207065
3 changed files with 142 additions and 2 deletions

View File

@ -33,3 +33,9 @@ blacklist:
format: host
- url: https://blocklistproject.github.io/Lists/alt-version/ads-nl.txt
format: line
lego:
enable: true
address: :8080
username: lego
secret: "133742069ab"

View File

@ -31,6 +31,7 @@ type config struct {
Address string `yaml:"address"`
Blacklist []configBlacklist `yaml:"blacklist"`
TLS configTLS `yaml:"tls"`
Lego configLego `yaml:"lego"`
}
type configForward struct {
@ -168,7 +169,7 @@ func createACLList(config []configACL) (map[string]*net.IPNet, error) {
}
// createServer creates a new serve mux. Adds all the logic to handle the request
func createServer(zones zoneMap, config config, aclList map[string]*net.IPNet, blacklist map[string]bool) *dns.ServeMux {
func createServer(zones zoneMap, config config, aclList map[string]*net.IPNet, blacklist map[string]bool, acmeList *legoMap) *dns.ServeMux {
srv := dns.NewServeMux()
c := new(dns.Client)
@ -184,6 +185,11 @@ func createServer(zones zoneMap, config config, aclList map[string]*net.IPNet, b
return
}
// Check if it is a ACME DNS-01 challange
if handleACMERequest(w, r, acmeList) {
return
}
// find out what view to handle the request
zoneIndex := -1
@ -215,6 +221,11 @@ func createServer(zones zoneMap, config config, aclList map[string]*net.IPNet, b
return
}
// Check if it is a ACME DNS-01 challange
if handleACMERequest(w, r, acmeList) {
return
}
// Check ACL rules
if !checkACL(config.Forward.ACL, aclList, ip) {
rcodeRequest(w, r, dns.RcodeRefused)
@ -389,7 +400,12 @@ func main() {
blacklist := loadBlacklist(config.Blacklist)
server := createServer(zones, *config, aclList, blacklist)
var acmeMap *legoMap
if config.Lego.Enable {
acmeMap = startLEGOWebSever(config.Lego)
}
server := createServer(zones, *config, aclList, blacklist, acmeMap)
listenAndServer(server, config.Address)

118
lego.go Normal file
View File

@ -0,0 +1,118 @@
package main
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
}