mirror of
https://github.com/joohoi/acme-dns.git
synced 2025-02-02 04:13:48 +07:00
Added config option to check for a header value for clinet IP
This commit is contained in:
parent
8c99346b01
commit
bf9eaf2f32
11
acmetxt.go
11
acmetxt.go
@ -57,6 +57,17 @@ func (a ACMETxt) allowedFrom(ip string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Go through list (most likely from headers) to check for the IP.
|
||||
// Reason for this is that some setups use reverse proxy in front of acme-dns
|
||||
func (a ACMETxt) allowedFromList(ips []string) bool {
|
||||
for _, v := range ips {
|
||||
if a.allowedFrom(v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func newACMETxt() ACMETxt {
|
||||
var a = ACMETxt{}
|
||||
password := generatePassword(40)
|
||||
|
12
api.go
12
api.go
@ -9,6 +9,7 @@ import (
|
||||
|
||||
// Serve is an authentication middlware function used to authenticate update requests
|
||||
func (a authMiddleware) Serve(ctx *iris.Context) {
|
||||
allowUpdate := false
|
||||
usernameStr := ctx.RequestHeader("X-Api-User")
|
||||
password := ctx.RequestHeader("X-Api-Key")
|
||||
postData := ACMETxt{}
|
||||
@ -23,7 +24,16 @@ func (a authMiddleware) Serve(ctx *iris.Context) {
|
||||
} else {
|
||||
if correctPassword(password, au.Password) {
|
||||
// Password ok
|
||||
if au.allowedFrom(ctx.RequestIP()) {
|
||||
|
||||
// Now test for the possibly limited ranges
|
||||
if DNSConf.API.UseHeader {
|
||||
ips := getIPListFromHeader(ctx.RequestHeader(DNSConf.API.HeaderName))
|
||||
allowUpdate = au.allowedFromList(ips)
|
||||
} else {
|
||||
allowUpdate = au.allowedFrom(ctx.RequestIP())
|
||||
}
|
||||
|
||||
if allowUpdate {
|
||||
// Update is allowed from remote addr
|
||||
if err := ctx.ReadJSON(&postData); err == nil {
|
||||
if au.Subdomain == postData.Subdomain {
|
||||
|
47
api_test.go
47
api_test.go
@ -19,6 +19,8 @@ func setupIris(t *testing.T, debug bool, noauth bool) *httpexpect.Expect {
|
||||
Port: "8080",
|
||||
TLS: "none",
|
||||
CorsOrigins: []string{"*"},
|
||||
UseHeader: false,
|
||||
HeaderName: "X-Forwarded-For",
|
||||
}
|
||||
var dnscfg = DNSConfig{
|
||||
API: httpapicfg,
|
||||
@ -206,3 +208,48 @@ func TestApiManyUpdateWithCredentials(t *testing.T) {
|
||||
Status(test.status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApiManyUpdateWithIpCheckHeaders(t *testing.T) {
|
||||
|
||||
updateJSON := map[string]interface{}{
|
||||
"subdomain": "",
|
||||
"txt": ""}
|
||||
|
||||
e := setupIris(t, false, false)
|
||||
// Use header checks from default header (X-Forwarded-For)
|
||||
DNSConf.API.UseHeader = true
|
||||
// User without defined CIDR masks
|
||||
newUser, err := DB.Register(cidrslice{})
|
||||
if err != nil {
|
||||
t.Errorf("Could not create new user, got error [%v]", err)
|
||||
}
|
||||
|
||||
newUserWithCIDR, err := DB.Register(cidrslice{"192.168.1.2/32", "invalid"})
|
||||
if err != nil {
|
||||
t.Errorf("Could not create new user with CIDR, got error [%v]", err)
|
||||
}
|
||||
|
||||
for _, test := range []struct {
|
||||
user ACMETxt
|
||||
headerValue string
|
||||
status int
|
||||
}{
|
||||
{newUser, "whatever goes", 200},
|
||||
{newUser, "10.0.0.1, 1.2.3.4 ,3.4.5.6", 200},
|
||||
{newUserWithCIDR, "127.0.0.1", 401},
|
||||
{newUserWithCIDR, "10.0.0.1, 10.0.0.2, 192.168.1.3", 401},
|
||||
{newUserWithCIDR, "10.1.1.1 ,192.168.1.2, 8.8.8.8", 200},
|
||||
} {
|
||||
updateJSON = map[string]interface{}{
|
||||
"subdomain": test.user.Subdomain,
|
||||
"txt": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}
|
||||
e.POST("/update").
|
||||
WithJSON(updateJSON).
|
||||
WithHeader("X-Api-User", test.user.Username.String()).
|
||||
WithHeader("X-Api-Key", test.user.Password).
|
||||
WithHeader("X-Forwarded-For", test.headerValue).
|
||||
Expect().
|
||||
Status(test.status)
|
||||
}
|
||||
DNSConf.API.UseHeader = false
|
||||
}
|
||||
|
@ -44,6 +44,10 @@ tls_cert_fullchain = "/etc/tls/example.org/fullchain.pem"
|
||||
corsorigins = [
|
||||
"*"
|
||||
]
|
||||
# use HTTP header to get the client ip
|
||||
use_header = false
|
||||
# header name to pull the ip address / list of ip addresses from
|
||||
header_name = "X-Forwarded-For"
|
||||
|
||||
[logconfig]
|
||||
# logging level: "error", "warning", "info" or "debug"
|
||||
|
@ -68,6 +68,8 @@ func setupConfig() {
|
||||
Port: "8080",
|
||||
TLS: "none",
|
||||
CorsOrigins: []string{"*"},
|
||||
UseHeader: false,
|
||||
HeaderName: "X-Forwarded-For",
|
||||
}
|
||||
|
||||
var dnscfg = DNSConfig{
|
||||
|
2
types.go
2
types.go
@ -56,6 +56,8 @@ type httpapi struct {
|
||||
TLSCertPrivkey string `toml:"tls_cert_privkey"`
|
||||
TLSCertFullchain string `toml:"tls_cert_fullchain"`
|
||||
CorsOrigins []string
|
||||
UseHeader bool `toml:"use_header"`
|
||||
HeaderName string `toml:"header_name"`
|
||||
}
|
||||
|
||||
// Logging config
|
||||
|
18
util.go
18
util.go
@ -2,12 +2,13 @@ package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"github.com/BurntSushi/toml"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/miekg/dns"
|
||||
"math/big"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func readConfig(fname string) DNSConfig {
|
||||
@ -68,3 +69,14 @@ func startDNS(listen string, proto string) *dns.Server {
|
||||
go server.ListenAndServe()
|
||||
return server
|
||||
}
|
||||
|
||||
func getIPListFromHeader(header string) []string {
|
||||
iplist := []string{}
|
||||
for _, v := range strings.Split(header, ",") {
|
||||
if len(v) > 0 {
|
||||
// Ignore empty values
|
||||
iplist = append(iplist, strings.TrimSpace(v))
|
||||
}
|
||||
}
|
||||
return iplist
|
||||
}
|
||||
|
24
util_test.go
24
util_test.go
@ -71,3 +71,27 @@ func TestReadConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetIPListFromHeader(t *testing.T) {
|
||||
for i, test := range []struct {
|
||||
input string
|
||||
output []string
|
||||
}{
|
||||
{"1.1.1.1, 2.2.2.2", []string{"1.1.1.1", "2.2.2.2"}},
|
||||
{" 1.1.1.1 , 2.2.2.2", []string{"1.1.1.1", "2.2.2.2"}},
|
||||
{",1.1.1.1 ,2.2.2.2", []string{"1.1.1.1", "2.2.2.2"}},
|
||||
} {
|
||||
res := getIPListFromHeader(test.input)
|
||||
if len(res) != len(test.output) {
|
||||
t.Errorf("Test %d: Expected [%d] items in return list, but got [%d]", i, len(test.output), len(res))
|
||||
} else {
|
||||
|
||||
for j, vv := range test.output {
|
||||
if res[j] != vv {
|
||||
t.Errorf("Test %d: Expected return value [%v] but got [%v]", j, test.output, res)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user