Commit 3a810c65 authored by zhsj's avatar zhsj Committed by Matt Holt

bind: support multiple values (#2128)

Signed-off-by: default avatarShengjing Zhu <i@zhsj.me>
parent 764c9ec9
...@@ -29,10 +29,17 @@ func init() { ...@@ -29,10 +29,17 @@ func init() {
func setupBind(c *caddy.Controller) error { func setupBind(c *caddy.Controller) error {
config := httpserver.GetConfig(c) config := httpserver.GetConfig(c)
for c.Next() { for c.Next() {
if !c.Args(&config.ListenHost) { args := c.RemainingArgs()
return c.ArgErr()
if len(args) == 0 {
return c.Errf("Expected at least one address")
}
for _, addr := range args {
config.ListenHosts = append(config.ListenHosts, addr)
} }
config.TLS.ListenHost = config.ListenHost // necessary for ACME challenges, see issue #309
config.TLS.ListenHost = config.ListenHosts[0] // necessary for ACME challenges, see issue #309
} }
return nil return nil
} }
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
package bind package bind
import ( import (
"reflect"
"testing" "testing"
"github.com/mholt/caddy" "github.com/mholt/caddy"
...@@ -22,17 +23,34 @@ import ( ...@@ -22,17 +23,34 @@ import (
) )
func TestSetupBind(t *testing.T) { func TestSetupBind(t *testing.T) {
c := caddy.NewTestController("http", `bind 1.2.3.4`) for _, testcase := range []struct {
Bind string
Hosts []string
TLSHost string
}{
{
Bind: "bind 1.2.3.4",
Hosts: []string{"1.2.3.4"},
TLSHost: "1.2.3.4",
},
{
Bind: "bind 1.2.3.4 5.6.7.8",
Hosts: []string{"1.2.3.4", "5.6.7.8"},
TLSHost: "1.2.3.4",
},
} {
c := caddy.NewTestController("http", testcase.Bind)
err := setupBind(c) err := setupBind(c)
if err != nil { if err != nil {
t.Fatalf("Expected no errors, but got: %v", err) t.Fatalf("Expected no errors, but got: %v", err)
} }
cfg := httpserver.GetConfig(c) cfg := httpserver.GetConfig(c)
if got, want := cfg.ListenHost, "1.2.3.4"; got != want { if got, want := cfg.ListenHosts, testcase.Hosts; !reflect.DeepEqual(got, want) {
t.Errorf("Expected the config's ListenHost to be %s, was %s", want, got) t.Errorf("Expected the config's ListenHost to be %s, was %s", want, got)
} }
if got, want := cfg.TLS.ListenHost, "1.2.3.4"; got != want { if got, want := cfg.TLS.ListenHost, testcase.TLSHost; got != want {
t.Errorf("Expected the TLS config's ListenHost to be %s, was %s", want, got) t.Errorf("Expected the TLS config's ListenHost to be %s, was %s", want, got)
} }
}
} }
...@@ -205,7 +205,7 @@ func redirPlaintextHost(cfg *SiteConfig) *SiteConfig { ...@@ -205,7 +205,7 @@ func redirPlaintextHost(cfg *SiteConfig) *SiteConfig {
return &SiteConfig{ return &SiteConfig{
Addr: Address{Original: addr, Host: host, Port: port}, Addr: Address{Original: addr, Host: host, Port: port},
ListenHost: cfg.ListenHost, ListenHosts: cfg.ListenHosts,
middleware: []Middleware{redirMiddleware}, middleware: []Middleware{redirMiddleware},
TLS: &caddytls.Config{AltHTTPPort: cfg.TLS.AltHTTPPort, AltTLSSNIPort: cfg.TLS.AltTLSSNIPort}, TLS: &caddytls.Config{AltHTTPPort: cfg.TLS.AltHTTPPort, AltTLSSNIPort: cfg.TLS.AltTLSSNIPort},
Timeouts: cfg.Timeouts, Timeouts: cfg.Timeouts,
......
...@@ -19,6 +19,7 @@ import ( ...@@ -19,6 +19,7 @@ import (
"net" "net"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"reflect"
"testing" "testing"
"github.com/mholt/caddy/caddytls" "github.com/mholt/caddy/caddytls"
...@@ -28,7 +29,7 @@ func TestRedirPlaintextHost(t *testing.T) { ...@@ -28,7 +29,7 @@ func TestRedirPlaintextHost(t *testing.T) {
for i, testcase := range []struct { for i, testcase := range []struct {
Host string // used for the site config Host string // used for the site config
Port string Port string
ListenHost string ListenHosts []string
RequestHost string // if different from Host RequestHost string // if different from Host
}{ }{
{ {
...@@ -44,12 +45,16 @@ func TestRedirPlaintextHost(t *testing.T) { ...@@ -44,12 +45,16 @@ func TestRedirPlaintextHost(t *testing.T) {
}, },
{ {
Host: "foohost", Host: "foohost",
ListenHost: "93.184.216.34", ListenHosts: []string{"93.184.216.34"},
}, },
{ {
Host: "foohost", Host: "foohost",
Port: "1234", Port: "1234",
ListenHost: "93.184.216.34", ListenHosts: []string{"93.184.216.34"},
},
{
Host: "foohost",
ListenHosts: []string{"127.0.0.1", "127.0.0.2"},
}, },
{ {
Host: "foohost", Host: "foohost",
...@@ -70,7 +75,7 @@ func TestRedirPlaintextHost(t *testing.T) { ...@@ -70,7 +75,7 @@ func TestRedirPlaintextHost(t *testing.T) {
Host: testcase.Host, Host: testcase.Host,
Port: testcase.Port, Port: testcase.Port,
}, },
ListenHost: testcase.ListenHost, ListenHosts: testcase.ListenHosts,
TLS: new(caddytls.Config), TLS: new(caddytls.Config),
}) })
...@@ -78,7 +83,7 @@ func TestRedirPlaintextHost(t *testing.T) { ...@@ -78,7 +83,7 @@ func TestRedirPlaintextHost(t *testing.T) {
if actual, expected := cfg.Addr.Host, testcase.Host; actual != expected { if actual, expected := cfg.Addr.Host, testcase.Host; actual != expected {
t.Errorf("Test %d: Expected redir config to have host %s but got %s", i, expected, actual) t.Errorf("Test %d: Expected redir config to have host %s but got %s", i, expected, actual)
} }
if actual, expected := cfg.ListenHost, testcase.ListenHost; actual != expected { if actual, expected := cfg.ListenHosts, testcase.ListenHosts; !reflect.DeepEqual(actual, expected) {
t.Errorf("Test %d: Expected redir config to have bindhost %s but got %s", i, expected, actual) t.Errorf("Test %d: Expected redir config to have bindhost %s but got %s", i, expected, actual)
} }
if actual, expected := cfg.Addr.Port, HTTPPort; actual != expected { if actual, expected := cfg.Addr.Port, HTTPPort; actual != expected {
......
...@@ -239,9 +239,18 @@ func (h *httpContext) MakeServers() ([]caddy.Server, error) { ...@@ -239,9 +239,18 @@ func (h *httpContext) MakeServers() ([]caddy.Server, error) {
// see if all the addresses (both sites and // see if all the addresses (both sites and
// listeners) are loopback to help us determine // listeners) are loopback to help us determine
// if this is a "production" instance or not // if this is a "production" instance or not
for _, listenHost := range cfg.ListenHosts {
if !atLeastOneSiteLooksLikeProduction { if !atLeastOneSiteLooksLikeProduction {
if !caddy.IsLoopback(cfg.Addr.Host) && if !caddy.IsLoopback(cfg.Addr.Host) &&
!caddy.IsLoopback(cfg.ListenHost) && !caddy.IsLoopback(listenHost) &&
(caddytls.QualifiesForManagedTLS(cfg) ||
caddytls.HostQualifies(cfg.Addr.Host)) {
atLeastOneSiteLooksLikeProduction = true
}
}
}
if !atLeastOneSiteLooksLikeProduction && len(cfg.ListenHosts) == 0 {
if !caddy.IsLoopback(cfg.Addr.Host) &&
(caddytls.QualifiesForManagedTLS(cfg) || (caddytls.QualifiesForManagedTLS(cfg) ||
caddytls.HostQualifies(cfg.Addr.Host)) { caddytls.HostQualifies(cfg.Addr.Host)) {
atLeastOneSiteLooksLikeProduction = true atLeastOneSiteLooksLikeProduction = true
...@@ -368,20 +377,31 @@ func groupSiteConfigsByListenAddr(configs []*SiteConfig) (map[string][]*SiteConf ...@@ -368,20 +377,31 @@ func groupSiteConfigsByListenAddr(configs []*SiteConfig) (map[string][]*SiteConf
for _, conf := range configs { for _, conf := range configs {
// We would add a special case here so that localhost addresses // We would add a special case here so that localhost addresses
// bind to 127.0.0.1 if conf.ListenHost is not already set, which // bind to 127.0.0.1 if conf.ListenHosts is not already set, which
// would prevent outsiders from even connecting; but that was problematic: // would prevent outsiders from even connecting; but that was problematic:
// https://caddy.community/t/wildcard-virtual-domains-with-wildcard-roots/221/5?u=matt // https://caddy.community/t/wildcard-virtual-domains-with-wildcard-roots/221/5?u=matt
if conf.Addr.Port == "" { if conf.Addr.Port == "" {
conf.Addr.Port = Port conf.Addr.Port = Port
} }
addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(conf.ListenHost, conf.Addr.Port))
if len(conf.ListenHosts) == 0 {
addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort("", conf.Addr.Port))
if err != nil { if err != nil {
return nil, err return nil, err
} }
addrstr := addr.String() addrstr := addr.String()
groups[addrstr] = append(groups[addrstr], conf) groups[addrstr] = append(groups[addrstr], conf)
} }
for _, host := range conf.ListenHosts {
addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(host, conf.Addr.Port))
if err != nil {
return nil, err
}
addrstr := addr.String()
groups[addrstr] = append(groups[addrstr], conf)
}
}
return groups, nil return groups, nil
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
package httpserver package httpserver
import ( import (
"reflect"
"strings" "strings"
"testing" "testing"
...@@ -347,3 +348,28 @@ func TestHideCaddyfile(t *testing.T) { ...@@ -347,3 +348,28 @@ func TestHideCaddyfile(t *testing.T) {
} }
t.Fatal("Caddyfile missing from HiddenFiles") t.Fatal("Caddyfile missing from HiddenFiles")
} }
func TestGroupSiteConfigsByListenAddr(t *testing.T) {
cfg := []*SiteConfig{
{
ListenHosts: []string{"127.0.0.1", "::1"},
},
{
Addr: Address{
Port: "80",
},
},
}
groups, err := groupSiteConfigsByListenAddr(cfg)
if err != nil {
t.Fatal("Failed to group SiteConfigs by listen address")
}
actual := []string{}
for k := range groups {
actual = append(actual, k)
}
expected := []string{"127.0.0.1:" + Port, "[::1]:" + Port, ":80"}
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Expected listen on %#v, but got %#v", expected, actual)
}
}
...@@ -419,7 +419,7 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error) ...@@ -419,7 +419,7 @@ func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error)
// we still check for ACME challenge if the vhost exists, // we still check for ACME challenge if the vhost exists,
// because we must apply its HTTP challenge config settings // because we must apply its HTTP challenge config settings
if caddytls.HTTPChallengeHandler(w, r, vhost.ListenHost) { if caddytls.HTTPChallengeHandler(w, r, vhost.ListenHosts[0]) {
return 0, nil return 0, nil
} }
......
...@@ -31,7 +31,7 @@ type SiteConfig struct { ...@@ -31,7 +31,7 @@ type SiteConfig struct {
// The hostname to bind listener to; // The hostname to bind listener to;
// defaults to Addr.Host // defaults to Addr.Host
ListenHost string ListenHosts []string
// TLS configuration // TLS configuration
TLS *caddytls.Config TLS *caddytls.Config
......
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