From 4645077dea4c0173042e4c21324945fffef73071 Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 12:03:47 -0700 Subject: [PATCH 01/16] read addresses from network interfaces --- caddyconfig/httpcaddyfile/addresses.go | 45 ++++++++++++++++++++++---- caddyconfig/httpcaddyfile/builtins.go | 21 ++++++++---- replacer_systemd.go | 11 ++++--- 3 files changed, 59 insertions(+), 18 deletions(-) diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go index 1121776d98f..7b661806fc5 100644 --- a/caddyconfig/httpcaddyfile/addresses.go +++ b/caddyconfig/httpcaddyfile/addresses.go @@ -307,21 +307,22 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad } // the bind directive specifies hosts (and potentially network), and the protocols to serve them with, but is optional - lnCfgVals := make([]addressesWithProtocols, 0, len(sblock.pile["bind"])) + lnCfgVals := make([]bindOptions, 0, len(sblock.pile["bind"])) for _, cfgVal := range sblock.pile["bind"] { - if val, ok := cfgVal.Value.(addressesWithProtocols); ok { + if val, ok := cfgVal.Value.(bindOptions); ok { lnCfgVals = append(lnCfgVals, val) } } if len(lnCfgVals) == 0 { if defaultBindValues, ok := options["default_bind"].([]ConfigValue); ok { for _, defaultBindValue := range defaultBindValues { - lnCfgVals = append(lnCfgVals, defaultBindValue.Value.(addressesWithProtocols)) + lnCfgVals = append(lnCfgVals, defaultBindValue.Value.(bindOptions)) } } else { - lnCfgVals = []addressesWithProtocols{{ - addresses: []string{""}, - protocols: nil, + lnCfgVals = []bindOptions{{ + addresses: []string{""}, + interfaces: nil, + protocols: nil, }} } } @@ -329,6 +330,32 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad // use a map to prevent duplication listeners := map[string]map[string]struct{}{} for _, lnCfgVal := range lnCfgVals { + addresses := []string{} + addresses = append(addresses, lnCfgVal.addresses...) + for _, lnIface := range lnCfgVal.interfaces { + lnNetw, lnDevice, _, err := caddy.SplitNetworkAddress(lnIface) + if err != nil { + return nil, fmt.Errorf("splitting listener interface: %v", err) + } + iface, err := net.InterfaceByName(lnDevice) + if err != nil || iface == nil { + return nil, fmt.Errorf("querying listener interface: %v", err) + } + ifaceAddrs, err := iface.Addrs() + if err != nil { + return nil, fmt.Errorf("querying listener interface addresses: %v", err) + } + for _, ifaceAddr := range ifaceAddrs { + switch ifaceAddrValue := ifaceAddr.(type) { + case *net.IPAddr: + addresses = append(addresses, caddy.JoinNetworkAddress(lnNetw, ifaceAddrValue.IP.String(), "")) + case *net.IPNet: + addresses = append(addresses, caddy.JoinNetworkAddress(lnNetw, ifaceAddrValue.IP.String(), "")) + default: + return nil, fmt.Errorf("reading listener interface address: %v", err) + } + } + } for _, lnAddr := range lnCfgVal.addresses { lnNetw, lnHost, _, err := caddy.SplitNetworkAddress(lnAddr) if err != nil { @@ -350,6 +377,12 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad return listeners, nil } +type bindOptions struct { + addresses []string + interfaces []string + protocols []string +} + // addressesWithProtocols associates a list of listen addresses // with a list of protocols to serve them with type addressesWithProtocols struct { diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go index 061aaa48b8d..717a51b1514 100644 --- a/caddyconfig/httpcaddyfile/builtins.go +++ b/caddyconfig/httpcaddyfile/builtins.go @@ -57,16 +57,22 @@ func init() { // parseBind parses the bind directive. Syntax: // -// bind [{ -// protocols [h1|h2|h2c|h3] [...] -// }] +// bind [{ +// interfaces +// protocols [h1|h2|h2c|h3] [...] +// }] func parseBind(h Helper) ([]ConfigValue, error) { h.Next() // consume directive name - var addresses, protocols []string + var addresses, interfaces, protocols []string addresses = h.RemainingArgs() for h.NextBlock(0) { switch h.Val() { + case "interfaces": + interfaces = h.RemainingArgs() + if len(interfaces) == 0 { + return nil, h.Errf("interfaces requires one or more arguments") + } case "protocols": protocols = h.RemainingArgs() if len(protocols) == 0 { @@ -77,9 +83,10 @@ func parseBind(h Helper) ([]ConfigValue, error) { } } - return []ConfigValue{{Class: "bind", Value: addressesWithProtocols{ - addresses: addresses, - protocols: protocols, + return []ConfigValue{{Class: "bind", Value: bindOptions{ + addresses: addresses, + interfaces: interfaces, + protocols: protocols, }}}, nil } diff --git a/replacer_systemd.go b/replacer_systemd.go index d810861f9b0..8ac2809e891 100644 --- a/replacer_systemd.go +++ b/replacer_systemd.go @@ -65,14 +65,15 @@ func sdListenFdsWithNames() (map[string][]uint, error) { } func getSdListenFd(nameToFiles map[string][]uint, host string) (uint, error) { - name, index, li := host, uint(0), strings.Index(host, ":") - if li >= 0 { - name = host[:li] - i, err := strconv.ParseUint(host[li+1:], 0, strconv.IntSize) + index := uint(0) + + name, offset, found := strings.Cut(host, ":") + if found { + off, err := strconv.ParseUint(offset, 0, strconv.IntSize) if err != nil { return 0, err } - index += uint(i) + index += uint(off) } files, ok := nameToFiles[name] From b091080ebe5b7f331dbf473bf8d2fa8093744a44 Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 12:09:33 -0700 Subject: [PATCH 02/16] addresses from copy --- caddyconfig/httpcaddyfile/addresses.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go index 7b661806fc5..c81f44ec46a 100644 --- a/caddyconfig/httpcaddyfile/addresses.go +++ b/caddyconfig/httpcaddyfile/addresses.go @@ -356,7 +356,7 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad } } } - for _, lnAddr := range lnCfgVal.addresses { + for _, lnAddr := range addresses { lnNetw, lnHost, _, err := caddy.SplitNetworkAddress(lnAddr) if err != nil { return nil, fmt.Errorf("splitting listener address: %v", err) From 9eb54beaeb5d3eb5717396b7630a4beb89ff489b Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 12:10:53 -0700 Subject: [PATCH 03/16] string in err --- caddyconfig/httpcaddyfile/addresses.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go index c81f44ec46a..dc547b5c118 100644 --- a/caddyconfig/httpcaddyfile/addresses.go +++ b/caddyconfig/httpcaddyfile/addresses.go @@ -352,7 +352,7 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad case *net.IPNet: addresses = append(addresses, caddy.JoinNetworkAddress(lnNetw, ifaceAddrValue.IP.String(), "")) default: - return nil, fmt.Errorf("reading listener interface address: %v", err) + return nil, fmt.Errorf("reading listener interface address: %v", ifaceAddr.String()) } } } From a6dbe6b54329e561822f1df03ac2721c8828ab98 Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 12:22:19 -0700 Subject: [PATCH 04/16] interface address memo --- caddyconfig/httpcaddyfile/addresses.go | 38 +++++++++++++++----------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go index dc547b5c118..067ee6716cb 100644 --- a/caddyconfig/httpcaddyfile/addresses.go +++ b/caddyconfig/httpcaddyfile/addresses.go @@ -328,6 +328,7 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad } // use a map to prevent duplication + interfaceAddress := map[string]string{} listeners := map[string]map[string]struct{}{} for _, lnCfgVal := range lnCfgVals { addresses := []string{} @@ -337,24 +338,29 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad if err != nil { return nil, fmt.Errorf("splitting listener interface: %v", err) } - iface, err := net.InterfaceByName(lnDevice) - if err != nil || iface == nil { - return nil, fmt.Errorf("querying listener interface: %v", err) - } - ifaceAddrs, err := iface.Addrs() - if err != nil { - return nil, fmt.Errorf("querying listener interface addresses: %v", err) - } - for _, ifaceAddr := range ifaceAddrs { - switch ifaceAddrValue := ifaceAddr.(type) { - case *net.IPAddr: - addresses = append(addresses, caddy.JoinNetworkAddress(lnNetw, ifaceAddrValue.IP.String(), "")) - case *net.IPNet: - addresses = append(addresses, caddy.JoinNetworkAddress(lnNetw, ifaceAddrValue.IP.String(), "")) - default: - return nil, fmt.Errorf("reading listener interface address: %v", ifaceAddr.String()) + + address, ok := interfaceAddress[lnDevice] + if !ok { + iface, err := net.InterfaceByName(lnDevice) + if err != nil || iface == nil { + return nil, fmt.Errorf("querying listener interface: %v", err) + } + ifaceAddrs, err := iface.Addrs() + if err != nil { + return nil, fmt.Errorf("querying listener interface addresses: %v", err) + } + for _, ifaceAddr := range ifaceAddrs { + switch ifaceAddrValue := ifaceAddr.(type) { + case *net.IPAddr: + address = caddy.JoinNetworkAddress(lnNetw, ifaceAddrValue.IP.String(), "") + case *net.IPNet: + address = caddy.JoinNetworkAddress(lnNetw, ifaceAddrValue.IP.String(), "") + default: + return nil, fmt.Errorf("reading listener interface address: %v", ifaceAddr.String()) + } } } + addresses = append(addresses, address) } for _, lnAddr := range addresses { lnNetw, lnHost, _, err := caddy.SplitNetworkAddress(lnAddr) From 5710bb6d11dec8ef921d5d9d0111ee23a57575f3 Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 16:34:14 -0700 Subject: [PATCH 05/16] check iface network --- caddyconfig/httpcaddyfile/addresses.go | 19 ++++++++++++++----- networks.go | 20 ++++++++++++++++++-- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go index 067ee6716cb..f6c80946e5e 100644 --- a/caddyconfig/httpcaddyfile/addresses.go +++ b/caddyconfig/httpcaddyfile/addresses.go @@ -328,7 +328,7 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad } // use a map to prevent duplication - interfaceAddress := map[string]string{} + interfaceAddresses := map[string][]string{} listeners := map[string]map[string]struct{}{} for _, lnCfgVal := range lnCfgVals { addresses := []string{} @@ -339,7 +339,7 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad return nil, fmt.Errorf("splitting listener interface: %v", err) } - address, ok := interfaceAddress[lnDevice] + ifaceAddresses, ok := interfaceAddresses[lnDevice] if !ok { iface, err := net.InterfaceByName(lnDevice) if err != nil || iface == nil { @@ -350,17 +350,26 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad return nil, fmt.Errorf("querying listener interface addresses: %v", err) } for _, ifaceAddr := range ifaceAddrs { + var ip net.IP switch ifaceAddrValue := ifaceAddr.(type) { case *net.IPAddr: - address = caddy.JoinNetworkAddress(lnNetw, ifaceAddrValue.IP.String(), "") + ip = ifaceAddrValue.IP case *net.IPNet: - address = caddy.JoinNetworkAddress(lnNetw, ifaceAddrValue.IP.String(), "") + ip = ifaceAddrValue.IP default: return nil, fmt.Errorf("reading listener interface address: %v", ifaceAddr.String()) } + + if len(ip) == 4 && caddy.IsIPv4Network(lnNetw) || len(ip) == 16 && caddy.IsIPv6Network(lnNetw) { + ifaceAddresses = append(ifaceAddresses,caddy.JoinNetworkAddress(lnNetw, ip.String(), "")) + } + } + if len(ifaceAddresses) == 0 { + return nil, fmt.Errorf("querying listener interface addresses for network: %v for %v", lnDevice, lnNetw) } + interfaceAddresses[lnDevice] = ifaceAddresses } - addresses = append(addresses, address) + addresses = append(addresses, ifaceAddresses...) } for _, lnAddr := range addresses { lnNetw, lnHost, _, err := caddy.SplitNetworkAddress(lnAddr) diff --git a/networks.go b/networks.go index edcdfa48811..e8a7111f2a8 100644 --- a/networks.go +++ b/networks.go @@ -28,6 +28,14 @@ func IsUnixNetwork(netw string) bool { return netw == "unix" || netw == "unixgram" || netw == "unixpacket" || netw == "unix+h2c" } +func IsTCPNetwork(netw string) bool { + return netw == "tcp" || netw == "tcp4" || netw == "tcp6" +} + +func IsUDPNetwork(netw string) bool { + return netw == "udp" || netw == "udp4" || netw == "udp6" +} + // IsIpNetwork returns true if the netw is an ip network. func IsIpNetwork(netw string) bool { return strings.HasPrefix(netw, "ip:") || strings.HasPrefix(netw, "ip4:") || strings.HasPrefix(netw, "ip6:") @@ -39,13 +47,21 @@ func IsFdNetwork(netw string) bool { } func IsReservedNetwork(network string) bool { - return network == "tcp" || network == "tcp4" || network == "tcp6" || - network == "udp" || network == "udp4" || network == "udp6" || + return IsTCPNetwork(network) || + IsUDPNetwork(network) || IsUnixNetwork(network) || IsIpNetwork(network) || IsFdNetwork(network) } +func IsIPv4Network(netw string) bool { + return netw == "tcp" || netw == "udp" || netw == "tcp4" || netw == "udp4" || strings.HasPrefix(netw, "ip:") || strings.HasPrefix(netw, "ip4:") +} + +func IsIPv6Network(netw string) bool { + return netw == "tcp" || netw == "udp" || netw == "tcp6" || netw == "udp6" || strings.HasPrefix(netw, "ip:") || strings.HasPrefix(netw, "ip6:") +} + // ListenerFunc is a function that can return a listener given a network and address. // The listeners must be capable of overlapping: with Caddy, new configs are loaded // before old ones are unloaded, so listeners may overlap briefly if the configs From 7500d162bf0af74c685e2b03235b657200aa6a27 Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 16:40:23 -0700 Subject: [PATCH 06/16] more errs --- caddyconfig/httpcaddyfile/addresses.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go index f6c80946e5e..3cfc9bacae2 100644 --- a/caddyconfig/httpcaddyfile/addresses.go +++ b/caddyconfig/httpcaddyfile/addresses.go @@ -342,12 +342,15 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad ifaceAddresses, ok := interfaceAddresses[lnDevice] if !ok { iface, err := net.InterfaceByName(lnDevice) - if err != nil || iface == nil { - return nil, fmt.Errorf("querying listener interface: %v", err) + if err != nil { + return nil, fmt.Errorf("querying listener interface: %v: %v", lnDevice, err) + } + if iface == nil { + return nil, fmt.Errorf("querying listener interface: %v", lnDevice) } ifaceAddrs, err := iface.Addrs() if err != nil { - return nil, fmt.Errorf("querying listener interface addresses: %v", err) + return nil, fmt.Errorf("querying listener interface addresses: %v: %v", lnDevice, err) } for _, ifaceAddr := range ifaceAddrs { var ip net.IP @@ -357,7 +360,7 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad case *net.IPNet: ip = ifaceAddrValue.IP default: - return nil, fmt.Errorf("reading listener interface address: %v", ifaceAddr.String()) + return nil, fmt.Errorf("reading listener interface address: %v: %v", lnDevice, ifaceAddr.String()) } if len(ip) == 4 && caddy.IsIPv4Network(lnNetw) || len(ip) == 16 && caddy.IsIPv6Network(lnNetw) { @@ -365,7 +368,7 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad } } if len(ifaceAddresses) == 0 { - return nil, fmt.Errorf("querying listener interface addresses for network: %v for %v", lnDevice, lnNetw) + return nil, fmt.Errorf("querying listener interface addresses for network: %v: %v", lnDevice, lnNetw) } interfaceAddresses[lnDevice] = ifaceAddresses } From a8b2bb6f542aee32623e61297dafdef7483d379e Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 16:42:48 -0700 Subject: [PATCH 07/16] gofumpt --- caddyconfig/httpcaddyfile/addresses.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go index 3cfc9bacae2..24c54c6381d 100644 --- a/caddyconfig/httpcaddyfile/addresses.go +++ b/caddyconfig/httpcaddyfile/addresses.go @@ -364,10 +364,10 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad } if len(ip) == 4 && caddy.IsIPv4Network(lnNetw) || len(ip) == 16 && caddy.IsIPv6Network(lnNetw) { - ifaceAddresses = append(ifaceAddresses,caddy.JoinNetworkAddress(lnNetw, ip.String(), "")) + ifaceAddresses = append(ifaceAddresses, caddy.JoinNetworkAddress(lnNetw, ip.String(), "")) } } - if len(ifaceAddresses) == 0 { + if len(ifaceAddresses) == 0 { return nil, fmt.Errorf("querying listener interface addresses for network: %v: %v", lnDevice, lnNetw) } interfaceAddresses[lnDevice] = ifaceAddresses From 319a7a0e75540af70f36f0a993163af0a9e2622a Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 17:19:14 -0700 Subject: [PATCH 08/16] ungofumpt --- caddyconfig/httpcaddyfile/builtins.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go index 717a51b1514..544943b0fad 100644 --- a/caddyconfig/httpcaddyfile/builtins.go +++ b/caddyconfig/httpcaddyfile/builtins.go @@ -57,10 +57,10 @@ func init() { // parseBind parses the bind directive. Syntax: // -// bind [{ -// interfaces -// protocols [h1|h2|h2c|h3] [...] -// }] +// bind [{ +// interfaces +// protocols [h1|h2|h2c|h3] [...] +// }] func parseBind(h Helper) ([]ConfigValue, error) { h.Next() // consume directive name var addresses, interfaces, protocols []string From 7da87c27811b36cce2d235580999957e292fc1e5 Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 17:19:31 -0700 Subject: [PATCH 09/16] ungofumpt --- caddyconfig/httpcaddyfile/builtins.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go index 544943b0fad..a0eb770470b 100644 --- a/caddyconfig/httpcaddyfile/builtins.go +++ b/caddyconfig/httpcaddyfile/builtins.go @@ -57,10 +57,10 @@ func init() { // parseBind parses the bind directive. Syntax: // -// bind [{ -// interfaces -// protocols [h1|h2|h2c|h3] [...] -// }] +// bind [{ +// interfaces +// protocols [h1|h2|h2c|h3] [...] +// }] func parseBind(h Helper) ([]ConfigValue, error) { h.Next() // consume directive name var addresses, interfaces, protocols []string From 2ce548d58a32338085c032ba6baa57e914090bb6 Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 17:55:05 -0700 Subject: [PATCH 10/16] tcp and udp na funcs --- listeners.go | 12 ++++++++++++ networks.go | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/listeners.go b/listeners.go index d8d567b5e5e..16e56b4e0f0 100644 --- a/listeners.go +++ b/listeners.go @@ -213,6 +213,18 @@ func (na NetworkAddress) IsUnixNetwork() bool { return IsUnixNetwork(na.Network) } +// IsTCPNetwork returns true if na.Network is +// tcp, tcp4, or tcp6. +func (na NetworkAddress) IsTCPNetwork() bool { + return IsTCPNetwork(na.Network) +} + +// IsUDPNetwork returns true if na.Network is +// udp, udp4, or udp6. +func (na NetworkAddress) IsUDPNetwork() bool { + return IsUDPNetwork(na.Network) +} + // IsIpNetwork returns true if na.Network starts with // ip: ip4: or ip6: func (na NetworkAddress) IsIpNetwork() bool { diff --git a/networks.go b/networks.go index e8a7111f2a8..b6222b75dc1 100644 --- a/networks.go +++ b/networks.go @@ -55,11 +55,11 @@ func IsReservedNetwork(network string) bool { } func IsIPv4Network(netw string) bool { - return netw == "tcp" || netw == "udp" || netw == "tcp4" || netw == "udp4" || strings.HasPrefix(netw, "ip:") || strings.HasPrefix(netw, "ip4:") + return netw == "tcp" || netw == "tcp4" || netw == "udp" || netw == "udp4" || strings.HasPrefix(netw, "ip:") || strings.HasPrefix(netw, "ip4:") } func IsIPv6Network(netw string) bool { - return netw == "tcp" || netw == "udp" || netw == "tcp6" || netw == "udp6" || strings.HasPrefix(netw, "ip:") || strings.HasPrefix(netw, "ip6:") + return netw == "tcp" || netw == "tcp6" || netw == "udp" || netw == "udp6" || strings.HasPrefix(netw, "ip:") || strings.HasPrefix(netw, "ip6:") } // ListenerFunc is a function that can return a listener given a network and address. From c11c2809a5c988d0d5b1bda682dce05a9fd5c8af Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 17:56:04 -0700 Subject: [PATCH 11/16] comments --- networks.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/networks.go b/networks.go index b6222b75dc1..642dfaf0f89 100644 --- a/networks.go +++ b/networks.go @@ -28,10 +28,12 @@ func IsUnixNetwork(netw string) bool { return netw == "unix" || netw == "unixgram" || netw == "unixpacket" || netw == "unix+h2c" } +// IsUnixNetwork returns true if the netw is a TCP network. func IsTCPNetwork(netw string) bool { return netw == "tcp" || netw == "tcp4" || netw == "tcp6" } +// IsUnixNetwork returns true if the netw is a UDP network. func IsUDPNetwork(netw string) bool { return netw == "udp" || netw == "udp4" || netw == "udp6" } From c72a6d3ae92ebfaf22bd38f6c9be99b0df46ef6f Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 17:57:15 -0700 Subject: [PATCH 12/16] order --- networks.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/networks.go b/networks.go index 642dfaf0f89..8580931ccc5 100644 --- a/networks.go +++ b/networks.go @@ -49,9 +49,9 @@ func IsFdNetwork(netw string) bool { } func IsReservedNetwork(network string) bool { - return IsTCPNetwork(network) || + return IsUnixNetwork(network) || + IsTCPNetwork(network) || IsUDPNetwork(network) || - IsUnixNetwork(network) || IsIpNetwork(network) || IsFdNetwork(network) } From c4ed4ba40d21cad9bd1412feb88df80990ca0cc1 Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 19:22:35 -0700 Subject: [PATCH 13/16] constants --- caddyconfig/httpcaddyfile/addresses.go | 2 +- listen.go | 6 +-- listen_unix.go | 9 ++-- listeners.go | 2 +- networks.go | 72 ++++++++++++++++++-------- 5 files changed, 58 insertions(+), 33 deletions(-) diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go index 24c54c6381d..d70efbea82d 100644 --- a/caddyconfig/httpcaddyfile/addresses.go +++ b/caddyconfig/httpcaddyfile/addresses.go @@ -363,7 +363,7 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad return nil, fmt.Errorf("reading listener interface address: %v: %v", lnDevice, ifaceAddr.String()) } - if len(ip) == 4 && caddy.IsIPv4Network(lnNetw) || len(ip) == 16 && caddy.IsIPv6Network(lnNetw) { + if len(ip) == net.IPv4len && caddy.IsIPv4Network(lnNetw) || len(ip) == net.IPv6len && caddy.IsIPv6Network(lnNetw) { ifaceAddresses = append(ifaceAddresses, caddy.JoinNetworkAddress(lnNetw, ip.String(), "")) } } diff --git a/listen.go b/listen.go index fba9c3a6ba6..c4600aa12b9 100644 --- a/listen.go +++ b/listen.go @@ -37,7 +37,7 @@ func reuseUnixSocket(_, _ string) (any, error) { func listenReusable(ctx context.Context, lnKey string, network, address string, config net.ListenConfig) (any, error) { var socketFile *os.File - fd := slices.Contains([]string{"fd", "fdgram"}, network) + fd := IsFdNetwork(network) if fd { socketFd, err := strconv.ParseUint(address, 0, strconv.IntSize) if err != nil { @@ -66,8 +66,8 @@ func listenReusable(ctx context.Context, lnKey string, network, address string, } } - datagram := slices.Contains([]string{"udp", "udp4", "udp6", "unixgram", "fdgram"}, network) - if datagram { + packet := IsPacketNetwork(network) + if packet { sharedPc, _, err := listenerPool.LoadOrNew(lnKey, func() (Destructor, error) { var ( pc net.PacketConn diff --git a/listen_unix.go b/listen_unix.go index d6ae0cb8ebb..856d0980ecf 100644 --- a/listen_unix.go +++ b/listen_unix.go @@ -27,7 +27,6 @@ import ( "io/fs" "net" "os" - "slices" "strconv" "sync" "sync/atomic" @@ -102,7 +101,7 @@ func listenReusable(ctx context.Context, lnKey string, network, address string, socketFile *os.File ) - fd := slices.Contains([]string{"fd", "fdgram"}, network) + fd := IsFdNetwork(network) if fd { socketFd, err := strconv.ParseUint(address, 0, strconv.IntSize) if err != nil { @@ -142,8 +141,8 @@ func listenReusable(ctx context.Context, lnKey string, network, address string, } } - datagram := slices.Contains([]string{"udp", "udp4", "udp6", "unixgram", "fdgram"}, network) - if datagram { + packet := IsPacketNetwork(network) + if packet { if fd { ln, err = net.FilePacketConn(socketFile) } else { @@ -161,7 +160,7 @@ func listenReusable(ctx context.Context, lnKey string, network, address string, listenerPool.LoadOrStore(lnKey, nil) } - if datagram { + if packet { if !fd { // TODO: Not 100% sure this is necessary, but we do this for net.UnixListener, so... if unix, ok := ln.(*net.UnixConn); ok { diff --git a/listeners.go b/listeners.go index 16e56b4e0f0..286a76599af 100644 --- a/listeners.go +++ b/listeners.go @@ -310,7 +310,7 @@ func (na NetworkAddress) port() string { // The output can be parsed by ParseNetworkAddress(). If the // address is a unix socket, any non-zero port will be dropped. func (na NetworkAddress) String() string { - if na.Network == "tcp" && (na.Host != "" || na.port() != "") { + if na.Network == TCP && (na.Host != "" || na.port() != "") { na.Network = "" // omit default network value for brevity } return JoinNetworkAddress(na.Network, na.Host, na.port()) diff --git a/networks.go b/networks.go index 8580931ccc5..cab873804de 100644 --- a/networks.go +++ b/networks.go @@ -23,29 +23,47 @@ import ( "go.uber.org/zap" ) +const ( + UNIX = "unix" + UNIX_H2C = "unix+h2c" + UNIXGRAM = "unixgram" + UNIXPACKET = "unixpacket" + TCP = "tcp" + TCP4 = "tcp4" + TCP6 = "tcp6" + UDP = "udp" + UDP4 = "udp4" + UDP6 = "udp6" + IP_ = "ip:" + IP4_ = "ip4:" + IP6_ = "ip6:" + FD = "fd" + FDGRAM = "fdgram" +) + // IsUnixNetwork returns true if the netw is a unix network. func IsUnixNetwork(netw string) bool { - return netw == "unix" || netw == "unixgram" || netw == "unixpacket" || netw == "unix+h2c" + return netw == UNIX || netw == UNIX_H2C || netw == UNIXGRAM || netw == UNIXPACKET } // IsUnixNetwork returns true if the netw is a TCP network. func IsTCPNetwork(netw string) bool { - return netw == "tcp" || netw == "tcp4" || netw == "tcp6" + return netw == TCP || netw == TCP4 || netw == TCP6 } // IsUnixNetwork returns true if the netw is a UDP network. func IsUDPNetwork(netw string) bool { - return netw == "udp" || netw == "udp4" || netw == "udp6" + return netw == UDP || netw == UDP4 || netw == UDP6 } // IsIpNetwork returns true if the netw is an ip network. func IsIpNetwork(netw string) bool { - return strings.HasPrefix(netw, "ip:") || strings.HasPrefix(netw, "ip4:") || strings.HasPrefix(netw, "ip6:") + return strings.HasPrefix(netw, IP_) || strings.HasPrefix(netw, IP4_) || strings.HasPrefix(netw, IP6_) } // IsFdNetwork returns true if the netw is a fd network. func IsFdNetwork(netw string) bool { - return netw == "fd" || netw == "fdgram" + return netw == FD || netw == FDGRAM } func IsReservedNetwork(network string) bool { @@ -57,11 +75,19 @@ func IsReservedNetwork(network string) bool { } func IsIPv4Network(netw string) bool { - return netw == "tcp" || netw == "tcp4" || netw == "udp" || netw == "udp4" || strings.HasPrefix(netw, "ip:") || strings.HasPrefix(netw, "ip4:") + return netw == TCP || netw == TCP4 || netw == UDP || netw == UDP4 || strings.HasPrefix(netw, IP_) || strings.HasPrefix(netw, IP4_) } func IsIPv6Network(netw string) bool { - return netw == "tcp" || netw == "tcp6" || netw == "udp" || netw == "udp6" || strings.HasPrefix(netw, "ip:") || strings.HasPrefix(netw, "ip6:") + return netw == TCP || netw == TCP6 || netw == UDP || netw == UDP6 || strings.HasPrefix(netw, IP_) || strings.HasPrefix(netw, IP6_) +} + +func IsStreamNetwork(netw string) bool { + return netw == UNIX || netw == UNIX_H2C || netw == UNIXPACKET || IsTCPNetwork(netw) || netw == FD +} + +func IsPacketNetwork(netw string) bool { + return netw == UNIXGRAM || IsUDPNetwork(netw) || IsIpNetwork(netw) || netw == FDGRAM } // ListenerFunc is a function that can return a listener given a network and address. @@ -132,22 +158,22 @@ func getHTTP3Plugin(originalNetwork string) (string, error) { func GetHTTP3Network(originalNetwork string) (string, error) { switch originalNetwork { - case "unixgram": - return "unixgram", nil - case "udp": - return "udp", nil - case "udp4": - return "udp4", nil - case "udp6": - return "udp6", nil - case "tcp": - return "udp", nil - case "tcp4": - return "udp4", nil - case "tcp6": - return "udp6", nil - case "fdgram": - return "fdgram", nil + case UNIXGRAM: + return UNIXGRAM, nil + case UDP: + return UDP, nil + case UDP4: + return UDP4, nil + case UDP6: + return UDP6, nil + case TCP: + return UDP, nil + case TCP4: + return UDP4, nil + case TCP6: + return UDP6, nil + case FDGRAM: + return FDGRAM, nil } return getHTTP3Plugin(originalNetwork) } From a6949c42f03a30695520c271631b7c02c014c89e Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Wed, 5 Nov 2025 23:13:32 -0700 Subject: [PATCH 14/16] rename arg --- replacer_systemd.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/replacer_systemd.go b/replacer_systemd.go index 8ac2809e891..281d356232a 100644 --- a/replacer_systemd.go +++ b/replacer_systemd.go @@ -64,10 +64,10 @@ func sdListenFdsWithNames() (map[string][]uint, error) { return nameToFiles, nil } -func getSdListenFd(nameToFiles map[string][]uint, host string) (uint, error) { +func getSdListenFd(nameToFiles map[string][]uint, nameOffset string) (uint, error) { index := uint(0) - name, offset, found := strings.Cut(host, ":") + name, offset, found := strings.Cut(nameOffset, ":") if found { off, err := strconv.ParseUint(offset, 0, strconv.IntSize) if err != nil { From 2b102e3ba3109b140c48cb9377a554e90dcb83a3 Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Thu, 6 Nov 2025 01:42:59 -0700 Subject: [PATCH 15/16] gofumpt --- replacer_systemd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/replacer_systemd.go b/replacer_systemd.go index 6f9b769134d..518ce365943 100644 --- a/replacer_systemd.go +++ b/replacer_systemd.go @@ -105,7 +105,7 @@ func (f systemdReplacementProvider) replace(key string) (any, bool) { } fd, err := getSdListenFd(initNameToFiles, key[len(systemdListenPrefix):]) if err != nil { - Log().Error("unable to process {" + key + "}", zap.Error(err)) + Log().Error("unable to process {"+key+"}", zap.Error(err)) return nil, false } return fd, true From f5f56ec17e77e3179cd7224175e8380a0184aaab Mon Sep 17 00:00:00 2001 From: Aaron Paterson Date: Thu, 6 Nov 2025 01:54:11 -0700 Subject: [PATCH 16/16] log when addr cannot be read --- caddyconfig/httpcaddyfile/addresses.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go index d70efbea82d..db122e6beee 100644 --- a/caddyconfig/httpcaddyfile/addresses.go +++ b/caddyconfig/httpcaddyfile/addresses.go @@ -29,6 +29,7 @@ import ( "github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/caddyserver/caddy/v2/modules/caddyhttp" + "go.uber.org/zap" ) // mapAddressToProtocolToServerBlocks returns a map of listener address to list of server @@ -360,7 +361,8 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad case *net.IPNet: ip = ifaceAddrValue.IP default: - return nil, fmt.Errorf("reading listener interface address: %v: %v", lnDevice, ifaceAddr.String()) + caddy.Log().Error("reading listener interface address", zap.String("device", lnDevice), zap.String("address", ifaceAddr.String())) + continue } if len(ip) == net.IPv4len && caddy.IsIPv4Network(lnNetw) || len(ip) == net.IPv6len && caddy.IsIPv6Network(lnNetw) {