add multi instance support
This commit is contained in:
57
http.go
57
http.go
@@ -40,11 +40,16 @@ type (
|
||||
certPool *x509.CertPool
|
||||
debug bool
|
||||
m sync.RWMutex
|
||||
dns *PowerDNS
|
||||
dnsInstances []pdnsInstance
|
||||
nonceGen string
|
||||
certCache map[string]time.Time
|
||||
zoneProfiles map[string]*zoneProfile
|
||||
}
|
||||
pdnsInstance struct {
|
||||
dns *PowerDNS
|
||||
isDefault bool
|
||||
regexp []*regexp.Regexp
|
||||
}
|
||||
zoneProfile struct {
|
||||
Default bool
|
||||
NameServers []string
|
||||
@@ -73,7 +78,7 @@ func (e JSONRPCError) String() string {
|
||||
}
|
||||
|
||||
// NewHTTPServer initializes HTTPServer
|
||||
func NewHTTPServer(port, key, cert, crl, ca, pdnsServer, pdnsKey string, timeout, ttl int) *HTTPServer {
|
||||
func NewHTTPServer(port string, key string, cert string, crl string, ca string, instances []pdnsInstance) *HTTPServer {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
h := HTTPServer{
|
||||
Port: port,
|
||||
@@ -87,6 +92,7 @@ func NewHTTPServer(port, key, cert, crl, ca, pdnsServer, pdnsKey string, timeout
|
||||
pdnsAcls: []*PdnsACL{},
|
||||
certPool: x509.NewCertPool(),
|
||||
decodedCA: []*x509.Certificate{},
|
||||
dnsInstances: instances,
|
||||
}
|
||||
|
||||
rawCA, err := ioutil.ReadFile(ca)
|
||||
@@ -109,9 +115,6 @@ func NewHTTPServer(port, key, cert, crl, ca, pdnsServer, pdnsKey string, timeout
|
||||
h.certPool.AddCert(cert)
|
||||
h.decodedCA = append(h.decodedCA, cert)
|
||||
}
|
||||
if h.dns, err = NewClient(pdnsServer, pdnsKey, timeout, ttl); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if _, err := h.RefreshCRL(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -177,7 +180,9 @@ func (h *HTTPServer) unlock() {
|
||||
// Debug facilities
|
||||
func (h *HTTPServer) Debug() {
|
||||
h.debug = true
|
||||
h.dns.Debug()
|
||||
for _, d := range h.dnsInstances {
|
||||
d.dns.Debug()
|
||||
}
|
||||
}
|
||||
|
||||
// verifyNonce check that the once is valid and less than 10s old
|
||||
@@ -359,7 +364,7 @@ func (h *HTTPServer) jrpcDecodeQuery(body []byte) (JSONArray, []byte, []byte, bo
|
||||
b, message := clearsign.Decode(body)
|
||||
// this is not a valid PGP signed payload, meaning message is all we got
|
||||
if b == nil {
|
||||
jsonRPC, wasArray, err := ParsejsonRPCRequest(message, h.dns)
|
||||
jsonRPC, wasArray, err := ParsejsonRPCRequest(message, h)
|
||||
return jsonRPC, message, nil, wasArray, err
|
||||
}
|
||||
// this is a valid PGP signed payload, we can extract the real payload and
|
||||
@@ -375,7 +380,7 @@ func (h *HTTPServer) jrpcDecodeQuery(body []byte) (JSONArray, []byte, []byte, bo
|
||||
if err != nil {
|
||||
return JSONArray{}, message, signature, false, err
|
||||
}
|
||||
jsonRPC, wasArray, err := ParsejsonRPCRequest(message, h.dns)
|
||||
jsonRPC, wasArray, err := ParsejsonRPCRequest(message, h)
|
||||
return jsonRPC, message, signature, wasArray, err
|
||||
}
|
||||
|
||||
@@ -416,6 +421,27 @@ func (h *HTTPServer) jsonRPCServe(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, jsonRPC.Run(h, username, wasArray, r.Header.Get("PDNS-Output") == "plaintext"))
|
||||
}
|
||||
|
||||
// Find the right PDNS instance to use for a given query
|
||||
func (h *HTTPServer) findDNSInstance(query string) *PowerDNS {
|
||||
var d *PowerDNS
|
||||
|
||||
if len(h.dnsInstances) == 1 {
|
||||
return h.dnsInstances[0].dns
|
||||
}
|
||||
for _, i := range h.dnsInstances {
|
||||
if i.isDefault {
|
||||
d = i.dns
|
||||
}
|
||||
for _, re := range i.regexp {
|
||||
if !re.MatchString(query) {
|
||||
continue
|
||||
}
|
||||
return i.dns
|
||||
}
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// PowerDNS native API support. Add certificate support for auth
|
||||
func (h *HTTPServer) nativeAPIServe(w http.ResponseWriter, r *http.Request) {
|
||||
// Check if the user/server is allowed to perform the required action
|
||||
@@ -424,20 +450,29 @@ func (h *HTTPServer) nativeAPIServe(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, certError.Error(), 403)
|
||||
return
|
||||
}
|
||||
|
||||
// find the target PDNS instance based on the URL
|
||||
dns := h.findDNSInstance(r.RequestURI)
|
||||
|
||||
log.Println("[Native API] User", commonName, "requested", r.Method, "on", r.RequestURI)
|
||||
if !h.nativeValidAuth(strings.TrimPrefix(r.RequestURI, h.dns.apiURL+"/"), commonName, r.Method) {
|
||||
if !h.nativeValidAuth(strings.TrimPrefix(r.RequestURI, dns.apiURL+"/"), commonName, r.Method) {
|
||||
http.Error(w, "The user "+commonName+" is not authorized to perform this action", 403)
|
||||
log.Println("[Native API] User ", commonName, " was not authorized to perform the action")
|
||||
return
|
||||
}
|
||||
h.dns.Proxy(w, r)
|
||||
dns.Proxy(w, r)
|
||||
}
|
||||
|
||||
// GetZoneConfig returns a configuration for a new zone
|
||||
func (h *HTTPServer) GetZoneConfig(s string) (string, string, []string, JSONArray, bool, error) {
|
||||
valid := ""
|
||||
def := JSONArray{}
|
||||
|
||||
for zoneType, profile := range h.zoneProfiles {
|
||||
// if there is only one profile, it's the good one
|
||||
if len(h.zoneProfiles) == 1 {
|
||||
return zoneType, profile.SOA, profile.NameServers, def, profile.AutoInc, nil
|
||||
}
|
||||
for _, re := range profile.Regexp {
|
||||
if !re.MatchString(s) {
|
||||
continue
|
||||
@@ -557,7 +592,7 @@ func (h *HTTPServer) Run() {
|
||||
mux.HandleFunc("/stats/", h.nativeAPIServe)
|
||||
mux.HandleFunc("/style.css", h.nativeAPIServe)
|
||||
if _, err := os.Stat("./web"); err == nil && h.debug {
|
||||
h.dns.LogDebug("serving local files")
|
||||
h.dnsInstances[0].dns.LogDebug("serving local files")
|
||||
mux.Handle("/", http.FileServer(http.Dir("web")))
|
||||
} else {
|
||||
mux.Handle("/", http.FileServer(http.FS(serverRoot)))
|
||||
|
||||
Reference in New Issue
Block a user