Commit e17d43b5 authored by Matthew Holt's avatar Matthew Holt

Default host now empty string; default port now depends on host

Hosts which are eligible for automatic HTTPS have default port "https" but other hosts (wildcards, loopback, etc.) have the default port 2015. The default host of empty string should be more IPv6-compatible.
parent 580b50ea
...@@ -83,7 +83,7 @@ var ( ...@@ -83,7 +83,7 @@ var (
const ( const (
// DefaultHost is the default host. // DefaultHost is the default host.
DefaultHost = "0.0.0.0" DefaultHost = ""
// DefaultPort is the default port. // DefaultPort is the default port.
DefaultPort = "2015" DefaultPort = "2015"
// DefaultRoot is the default root folder. // DefaultRoot is the default root folder.
......
...@@ -331,22 +331,18 @@ func validDirective(d string) bool { ...@@ -331,22 +331,18 @@ func validDirective(d string) bool {
return false return false
} }
// NewDefault makes a default configuration, which
// is empty except for root, host, and port,
// which are essentials for serving the cwd.
func NewDefault() server.Config {
return server.Config{
Root: Root,
Host: Host,
Port: Port,
}
}
// DefaultInput returns the default Caddyfile input // DefaultInput returns the default Caddyfile input
// to use when it is otherwise empty or missing. // to use when it is otherwise empty or missing.
// It uses the default host and port (depends on
// host, e.g. localhost is 2015, otherwise https) and
// root.
func DefaultInput() CaddyfileInput { func DefaultInput() CaddyfileInput {
port := Port
if letsencrypt.HostQualifies(Host) {
port = "https"
}
return CaddyfileInput{ return CaddyfileInput{
Contents: []byte(fmt.Sprintf("%s:%s\nroot %s", Host, Port, Root)), Contents: []byte(fmt.Sprintf("%s:%s\nroot %s", Host, port, Root)),
} }
} }
......
...@@ -8,17 +8,26 @@ import ( ...@@ -8,17 +8,26 @@ import (
"github.com/mholt/caddy/server" "github.com/mholt/caddy/server"
) )
func TestNewDefault(t *testing.T) { func TestDefaultInput(t *testing.T) {
config := NewDefault() if actual, expected := string(DefaultInput().Body()), ":2015\nroot ."; actual != expected {
t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual)
}
// next few tests simulate user providing -host flag
if actual, expected := config.Root, DefaultRoot; actual != expected { Host = "not-localhost.com"
t.Errorf("Root was %s but expected %s", actual, expected) if actual, expected := string(DefaultInput().Body()), "not-localhost.com:https\nroot ."; actual != expected {
t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual)
} }
if actual, expected := config.Host, DefaultHost; actual != expected {
t.Errorf("Host was %s but expected %s", actual, expected) Host = "[::1]"
if actual, expected := string(DefaultInput().Body()), "[::1]:2015\nroot ."; actual != expected {
t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual)
} }
if actual, expected := config.Port, DefaultPort; actual != expected {
t.Errorf("Port was %s but expected %s", actual, expected) Host = "127.0.1.1"
if actual, expected := string(DefaultInput().Body()), "127.0.1.1:2015\nroot ."; actual != expected {
t.Errorf("Host=%s; Port=%s; Root=%s;\nEXPECTED: '%s'\n ACTUAL: '%s'", Host, Port, Root, expected, actual)
} }
} }
......
...@@ -166,17 +166,29 @@ func configQualifies(allConfigs []server.Config, cfgIndex int) bool { ...@@ -166,17 +166,29 @@ func configQualifies(allConfigs []server.Config, cfgIndex int) bool {
cfg.TLS.LetsEncryptEmail != "off" && cfg.TLS.LetsEncryptEmail != "off" &&
// obviously we get can't certs for loopback or internal hosts // obviously we get can't certs for loopback or internal hosts
cfg.Host != "localhost" && HostQualifies(cfg.Host) &&
cfg.Host != "" &&
cfg.Host != "0.0.0.0" &&
cfg.Host != "::1" &&
!strings.HasPrefix(cfg.Host, "127.") && // to use boulder on your own machine, add fake domain to hosts file
// not excluding 10.* and 192.168.* hosts for possibility of running internal Boulder instance
// make sure another HTTPS version of this config doesn't exist in the list already // make sure another HTTPS version of this config doesn't exist in the list already
!otherHostHasScheme(allConfigs, cfgIndex, "https") !otherHostHasScheme(allConfigs, cfgIndex, "https")
} }
// HostQualifies returns true if the hostname alone
// appears eligible for automatic HTTPS. For example,
// localhost, empty hostname, and wildcard hosts are
// not eligible because we cannot obtain certificates
// for those names.
func HostQualifies(hostname string) bool {
return hostname != "localhost" &&
strings.TrimSpace(hostname) != "" &&
hostname != "0.0.0.0" &&
hostname != "[::]" && // before parsing
hostname != "::" && // after parsing
hostname != "[::1]" && // before parsing
hostname != "::1" && // after parsing
!strings.HasPrefix(hostname, "127.") // to use boulder on your own machine, add fake domain to hosts file
// not excluding 10.* and 192.168.* hosts for possibility of running internal Boulder instance
}
// groupConfigsByEmail groups configs by user email address. The returned map is // groupConfigsByEmail groups configs by user email address. The returned map is
// a map of email address to the configs that are serviced under that account. // a map of email address to the configs that are serviced under that account.
// If an email address is not available for an eligible config, the user will be // If an email address is not available for an eligible config, the user will be
...@@ -273,12 +285,10 @@ func newClientPort(leEmail, port string) (*acme.Client, error) { ...@@ -273,12 +285,10 @@ func newClientPort(leEmail, port string) (*acme.Client, error) {
// obtainCertificates obtains certificates from the CA server for // obtainCertificates obtains certificates from the CA server for
// the configurations in serverConfigs using client. // the configurations in serverConfigs using client.
func obtainCertificates(client *acme.Client, serverConfigs []server.Config) ([]acme.CertificateResource, map[string]error) { func obtainCertificates(client *acme.Client, serverConfigs []server.Config) ([]acme.CertificateResource, map[string]error) {
// collect all the hostnames into one slice
var hosts []string var hosts []string
for _, cfg := range serverConfigs { for _, cfg := range serverConfigs {
hosts = append(hosts, cfg.Host) hosts = append(hosts, cfg.Host)
} }
return client.ObtainCertificates(hosts, true) return client.ObtainCertificates(hosts, true)
} }
......
...@@ -8,6 +8,34 @@ import ( ...@@ -8,6 +8,34 @@ import (
"github.com/mholt/caddy/server" "github.com/mholt/caddy/server"
) )
func TestHostQualifies(t *testing.T) {
for i, test := range []struct {
host string
expect bool
}{
{"localhost", false},
{"127.0.0.1", false},
{"127.0.1.5", false},
{"::1", false},
{"[::1]", false},
{"[::]", false},
{"::", false},
{"", false},
{" ", false},
{"0.0.0.0", false},
{"192.168.1.3", true},
{"10.0.2.1", true},
{"foobar.com", true},
} {
if HostQualifies(test.host) && !test.expect {
t.Errorf("Test %d: Expected '%s' to NOT qualify, but it did", i, test.host)
}
if !HostQualifies(test.host) && test.expect {
t.Errorf("Test %d: Expected '%s' to qualify, but it did NOT", i, test.host)
}
}
}
func TestRedirPlaintextHost(t *testing.T) { func TestRedirPlaintextHost(t *testing.T) {
cfg := redirPlaintextHost(server.Config{ cfg := redirPlaintextHost(server.Config{
Host: "example.com", Host: "example.com",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment