diff --git a/caddy.go b/caddy.go index c5ff88ca0..3d8a6139b 100644 --- a/caddy.go +++ b/caddy.go @@ -763,6 +763,35 @@ func IsLoopback(addr string) bool { strings.HasPrefix(host, "127.") } +// IsInternal returns true if the IP of addr +// belongs to a private network IP range. addr must only +// be an IP or an IP:port combination. +// Loopback addresses are considered false. +func IsInternal(addr string) bool { + private_networks := []string{ + "10.0.0.0/8", + "172.16.0.0/12", + "192.168.0.0/16", + "fc00::/7", + } + + host, _, err := net.SplitHostPort(addr) + if err != nil { + host = addr // happens if the addr is just a hostname + } + ip := net.ParseIP(host) + if ip == nil { + return false + } + for _, private_network := range private_networks { + _, ipnet, _ := net.ParseCIDR(private_network) + if ipnet.Contains(ip) { + return true + } + } + return false +} + // Upgrade re-launches the process, preserving the listeners // for a graceful restart. It does NOT load new configuration; // it only starts the process anew with a fresh binary. diff --git a/caddy_test.go b/caddy_test.go index 61bb553e3..2f86105b0 100644 --- a/caddy_test.go +++ b/caddy_test.go @@ -61,6 +61,65 @@ func TestIsLoopback(t *testing.T) { } } +func TestIsInternal(t *testing.T) { + for i, test := range []struct { + input string + expect bool + }{ + {"9.255.255.255", false}, + {"10.0.0.0", true}, + {"10.0.0.1", true}, + {"10.255.255.254", true}, + {"10.255.255.255", true}, + {"11.0.0.0", false}, + {"10.0.0.5:1234", true}, + {"11.0.0.5:1234", false}, + + {"172.15.255.255", false}, + {"172.16.0.0", true}, + {"172.16.0.1", true}, + {"172.31.255.254", true}, + {"172.31.255.255", true}, + {"172.32.0.0", false}, + {"172.16.0.1:1234", true}, + + {"192.167.255.255", false}, + {"192.168.0.0", true}, + {"192.168.0.1", true}, + {"192.168.255.254", true}, + {"192.168.255.255", true}, + {"192.169.0.0", false}, + {"192.168.0.1:1234", true}, + + {"fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", false}, + {"fc00::", true}, + {"fc00::1", true}, + {"fdff:ffff:ffff:ffff:ffff:ffff:ffff:fffe", true}, + {"fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", true}, + {"fe00::", false}, + {"fd12:3456:789a:1::1:1234", true}, + + {"example.com", false}, + {"localhost", false}, + {"localhost:1234", false}, + {"localhost:", false}, + {"127.0.0.1", false}, + {"127.0.0.1:443", false}, + {"127.0.1.5", false}, + {"12.7.0.1", false}, + {"[::1]", false}, + {"[::1]:1234", false}, + {"::1", false}, + {"::", false}, + {"[::]", false}, + {"local", false}, + } { + if got, want := IsInternal(test.input), test.expect; got != want { + t.Errorf("Test %d (%s): expected %v but was %v", i, test.input, want, got) + } + } +} + func TestListenerAddrEqual(t *testing.T) { ln1, err := net.Listen("tcp", "[::]:0") if err != nil { diff --git a/caddytls/client.go b/caddytls/client.go index 394c36882..deb94af7a 100644 --- a/caddytls/client.go +++ b/caddytls/client.go @@ -61,7 +61,7 @@ var newACMEClient = func(config *Config, allowPrompts bool) (*ACMEClient, error) if err != nil { return nil, err } - if u.Scheme != "https" && !caddy.IsLoopback(u.Host) && !strings.HasPrefix(u.Host, "10.") { + if u.Scheme != "https" && !caddy.IsLoopback(u.Host) && !caddy.IsInternal(u.Host) { return nil, fmt.Errorf("%s: insecure CA URL (HTTPS required)", caURL) }