httpcaddyfile: Fix bind when IPv6 is specified with network (#4950)

* fix listening on IPv6 addresses: use net.JoinHostPort

Commit 1e18afb5c8 broke my caddy setup.
This commit fixes it.

* Refactor solution; simplify, add descriptive comment

* Move network to host, not copy

Co-authored-by: Matthew Holt <mholt@users.noreply.github.com>
This commit is contained in:
Michael Stapelberg 2022-09-15 16:03:24 +02:00 committed by GitHub
parent 62b0685375
commit a1ad20e472
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 24 additions and 12 deletions

View File

@ -36,12 +36,12 @@ import (
// server block that share the same address stay grouped together so the config
// isn't repeated unnecessarily. For example, this Caddyfile:
//
// example.com {
// bind 127.0.0.1
// }
// www.example.com, example.net/path, localhost:9999 {
// bind 127.0.0.1 1.2.3.4
// }
// example.com {
// bind 127.0.0.1
// }
// www.example.com, example.net/path, localhost:9999 {
// bind 127.0.0.1 1.2.3.4
// }
//
// has two server blocks to start with. But expressed in this Caddyfile are
// actually 4 listener addresses: 127.0.0.1:443, 1.2.3.4:443, 127.0.0.1:9999,
@ -219,7 +219,7 @@ func (st *ServerType) listenerAddrsForServerBlockKey(sblock serverBlock, key str
return nil, fmt.Errorf("[%s] scheme and port violate convention", key)
}
// the bind directive specifies hosts, but is optional
// the bind directive specifies hosts (and potentially network), but is optional
lnHosts := make([]string, 0, len(sblock.pile["bind"]))
for _, cfgVal := range sblock.pile["bind"] {
lnHosts = append(lnHosts, cfgVal.Value.([]string)...)
@ -234,11 +234,23 @@ func (st *ServerType) listenerAddrsForServerBlockKey(sblock serverBlock, key str
// use a map to prevent duplication
listeners := make(map[string]struct{})
for _, host := range lnHosts {
// host can have network + host (e.g. "tcp6/localhost") but
// will/should not have port information because this usually
// comes from the bind directive, so we append the port
addr, err := caddy.ParseNetworkAddress(host + ":" + lnPort)
for _, lnHost := range lnHosts {
// normally we would simply append the port,
// but if lnHost is IPv6, we need to ensure it
// is enclosed in [ ]; net.JoinHostPort does
// this for us, but lnHost might also have a
// network type in front (e.g. "tcp/") leading
// to "[tcp/::1]" which causes parsing failures
// later; what we need is "tcp/[::1]", so we have
// to split the network and host, then re-combine
network, host, ok := strings.Cut(lnHost, "/")
if !ok {
host = network
network = ""
}
host = strings.Trim(host, "[]") // IPv6
networkAddr := caddy.JoinNetworkAddress(network, host, lnPort)
addr, err := caddy.ParseNetworkAddress(networkAddr)
if err != nil {
return nil, fmt.Errorf("parsing network address: %v", err)
}