implemented lego HTTP endpoint
This commit is contained in:
parent
c7bac27a53
commit
fe7c207065
@ -33,3 +33,9 @@ blacklist:
|
|||||||
format: host
|
format: host
|
||||||
- url: https://blocklistproject.github.io/Lists/alt-version/ads-nl.txt
|
- url: https://blocklistproject.github.io/Lists/alt-version/ads-nl.txt
|
||||||
format: line
|
format: line
|
||||||
|
|
||||||
|
lego:
|
||||||
|
enable: true
|
||||||
|
address: :8080
|
||||||
|
username: lego
|
||||||
|
secret: "133742069ab"
|
20
coolDns.go
20
coolDns.go
@ -31,6 +31,7 @@ type config struct {
|
|||||||
Address string `yaml:"address"`
|
Address string `yaml:"address"`
|
||||||
Blacklist []configBlacklist `yaml:"blacklist"`
|
Blacklist []configBlacklist `yaml:"blacklist"`
|
||||||
TLS configTLS `yaml:"tls"`
|
TLS configTLS `yaml:"tls"`
|
||||||
|
Lego configLego `yaml:"lego"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type configForward struct {
|
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
|
// 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()
|
srv := dns.NewServeMux()
|
||||||
c := new(dns.Client)
|
c := new(dns.Client)
|
||||||
|
|
||||||
@ -184,6 +185,11 @@ func createServer(zones zoneMap, config config, aclList map[string]*net.IPNet, b
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if it is a ACME DNS-01 challange
|
||||||
|
if handleACMERequest(w, r, acmeList) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// find out what view to handle the request
|
// find out what view to handle the request
|
||||||
zoneIndex := -1
|
zoneIndex := -1
|
||||||
|
|
||||||
@ -215,6 +221,11 @@ func createServer(zones zoneMap, config config, aclList map[string]*net.IPNet, b
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if it is a ACME DNS-01 challange
|
||||||
|
if handleACMERequest(w, r, acmeList) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Check ACL rules
|
// Check ACL rules
|
||||||
if !checkACL(config.Forward.ACL, aclList, ip) {
|
if !checkACL(config.Forward.ACL, aclList, ip) {
|
||||||
rcodeRequest(w, r, dns.RcodeRefused)
|
rcodeRequest(w, r, dns.RcodeRefused)
|
||||||
@ -389,7 +400,12 @@ func main() {
|
|||||||
|
|
||||||
blacklist := loadBlacklist(config.Blacklist)
|
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)
|
listenAndServer(server, config.Address)
|
||||||
|
|
||||||
|
118
lego.go
Normal file
118
lego.go
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user