Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
851494e
networks.go with sd and sdgram
MayCXC Oct 31, 2025
8725ffe
update tests
MayCXC Nov 1, 2025
659e308
gofmt
MayCXC Nov 1, 2025
c87d9c3
use caddy package
MayCXC Nov 1, 2025
4c36962
fix nosystemd build
MayCXC Nov 1, 2025
e5c4b04
gofumpt
MayCXC Nov 1, 2025
dfe2fe2
fix unix+h2c
MayCXC Nov 1, 2025
ac84e68
separate listeners_test target
MayCXC Nov 1, 2025
be04286
deprecate caddyhttp.RegisterNetworkHTTP3
MayCXC Nov 1, 2025
909d949
Merge branch 'master' into sd-sdgram-networks
MayCXC Nov 1, 2025
5ba3608
getSdFd
MayCXC Nov 1, 2025
cf35e36
Merge branch 'sd-sdgram-networks' of github.com:MayCXC/caddy into sd-…
MayCXC Nov 1, 2025
b5ccaea
Merge branch 'caddyserver:master' into iface-ifacegram-networks
MayCXC Nov 1, 2025
03be031
Merge branch 'sd-sdgram-networks' into iface-ifacegram-networks
MayCXC Nov 1, 2025
b596cdd
abandon for switch to placeholders
MayCXC Nov 4, 2025
72119bd
rm
MayCXC Nov 4, 2025
e755ff9
systemd.listen placeholder
MayCXC Nov 4, 2025
ea28788
editor did not save
MayCXC Nov 4, 2025
c7d4af6
Merge branch 'master' into systemd-placeholders
MayCXC Nov 4, 2025
3b5ca2d
no const on array
MayCXC Nov 4, 2025
9524b38
remove provider len test
MayCXC Nov 4, 2025
ee76e7a
lint
MayCXC Nov 4, 2025
7c8c765
lock not needed in init
MayCXC Nov 4, 2025
4645077
read addresses from network interfaces
MayCXC Nov 5, 2025
b091080
addresses from copy
MayCXC Nov 5, 2025
9eb54be
string in err
MayCXC Nov 5, 2025
a6dbe6b
interface address memo
MayCXC Nov 5, 2025
5710bb6
check iface network
MayCXC Nov 5, 2025
7500d16
more errs
MayCXC Nov 5, 2025
a8b2bb6
gofumpt
MayCXC Nov 5, 2025
319a7a0
ungofumpt
MayCXC Nov 6, 2025
7da87c2
ungofumpt
MayCXC Nov 6, 2025
2ce548d
tcp and udp na funcs
MayCXC Nov 6, 2025
c11c280
comments
MayCXC Nov 6, 2025
c72a6d3
order
MayCXC Nov 6, 2025
c4ed4ba
constants
MayCXC Nov 6, 2025
a6949c4
rename arg
MayCXC Nov 6, 2025
f537870
cherrypick networks
MayCXC Nov 6, 2025
ccd4a16
merge systemd-placeholders
MayCXC Nov 6, 2025
1472a12
unused import
MayCXC Nov 6, 2025
ea6b230
Merge branch 'systemd-placeholders' into bind-interfaces
MayCXC Nov 6, 2025
01ae560
cherrypick again
MayCXC Nov 6, 2025
d2c9b46
Merge branch 'systemd-placeholders' into bind-interfaces
MayCXC Nov 6, 2025
4a20224
errors
MayCXC Nov 6, 2025
a6eaddc
better message
MayCXC Nov 6, 2025
ca80f6f
Merge branch 'systemd-placeholders' into bind-interfaces
MayCXC Nov 6, 2025
2b102e3
gofumpt
MayCXC Nov 6, 2025
834b7fe
gofumpt
MayCXC Nov 6, 2025
4b4bfa0
Merge branch 'systemd-placeholders' into bind-interfaces
MayCXC Nov 6, 2025
f5f56ec
log when addr cannot be read
MayCXC Nov 6, 2025
a96dfbb
cast to config values to bindOptions
MayCXC Nov 6, 2025
d1423a7
remove newline
MayCXC Nov 6, 2025
2e5e31d
more newlines?
MayCXC Nov 6, 2025
1fcaf50
remove one newline?
MayCXC Nov 6, 2025
5717418
Revert "log when addr cannot be read"
MayCXC Nov 6, 2025
97f5b2a
unrevert
MayCXC Nov 6, 2025
33b3027
import order?
MayCXC Nov 6, 2025
8cc72d2
gci write
MayCXC Nov 6, 2025
2f56d9c
update default_bind
MayCXC Nov 6, 2025
9ad426b
golangci-lint fmt
MayCXC Nov 6, 2025
1bf58bc
remove old opts
MayCXC Nov 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 58 additions & 12 deletions caddyconfig/httpcaddyfile/addresses.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"unicode"

"github.com/caddyserver/certmagic"
"go.uber.org/zap"

"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
Expand Down Expand Up @@ -307,29 +308,75 @@ 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,
}}
}
}

// use a map to prevent duplication
interfaceAddresses := map[string][]string{}
listeners := map[string]map[string]struct{}{}
for _, lnCfgVal := range lnCfgVals {
for _, lnAddr := range lnCfgVal.addresses {
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)
}

ifaceAddresses, ok := interfaceAddresses[lnDevice]
if !ok {
iface, err := net.InterfaceByName(lnDevice)
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: %v", lnDevice, err)
}
for _, ifaceAddr := range ifaceAddrs {
var ip net.IP
switch ifaceAddrValue := ifaceAddr.(type) {
case *net.IPAddr:
ip = ifaceAddrValue.IP
case *net.IPNet:
ip = ifaceAddrValue.IP
default:
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) {
ifaceAddresses = append(ifaceAddresses, caddy.JoinNetworkAddress(lnNetw, ip.String(), ""))
}
}
if len(ifaceAddresses) == 0 {
return nil, fmt.Errorf("querying listener interface addresses for network: %v: %v", lnDevice, lnNetw)
}
interfaceAddresses[lnDevice] = ifaceAddresses
}
addresses = append(addresses, ifaceAddresses...)
}
for _, lnAddr := range addresses {
lnNetw, lnHost, _, err := caddy.SplitNetworkAddress(lnAddr)
if err != nil {
return nil, fmt.Errorf("splitting listener address: %v", err)
Expand All @@ -350,11 +397,10 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad
return listeners, nil
}

// addressesWithProtocols associates a list of listen addresses
// with a list of protocols to serve them with
type addressesWithProtocols struct {
addresses []string
protocols []string
type bindOptions struct {
addresses []string
interfaces []string
protocols []string
}

// Address represents a site address. It contains
Expand Down
21 changes: 14 additions & 7 deletions caddyconfig/httpcaddyfile/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,22 @@ func init() {

// parseBind parses the bind directive. Syntax:
//
// bind <addresses...> [{
// protocols [h1|h2|h2c|h3] [...]
// }]
// bind <addresses...> [{
// interfaces <devices...>
// 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 {
Expand All @@ -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
}

Expand Down
15 changes: 10 additions & 5 deletions caddyconfig/httpcaddyfile/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,7 @@ func parseOptSingleString(d *caddyfile.Dispenser, _ any) (any, error) {

func parseOptDefaultBind(d *caddyfile.Dispenser, _ any) (any, error) {
d.Next() // consume option name

var addresses, protocols []string
var addresses, interfaces, protocols []string
addresses = d.RemainingArgs()

if len(addresses) == 0 {
Expand All @@ -317,6 +316,11 @@ func parseOptDefaultBind(d *caddyfile.Dispenser, _ any) (any, error) {

for d.NextBlock(0) {
switch d.Val() {
case "interfaces":
interfaces = d.RemainingArgs()
if len(interfaces) == 0 {
return nil, d.Errf("interfaces requires one or more arguments")
}
case "protocols":
protocols = d.RemainingArgs()
if len(protocols) == 0 {
Expand All @@ -327,9 +331,10 @@ func parseOptDefaultBind(d *caddyfile.Dispenser, _ any) (any, error) {
}
}

return []ConfigValue{{Class: "bind", Value: addressesWithProtocols{
addresses: addresses,
protocols: protocols,
return []ConfigValue{{Class: "bind", Value: bindOptions{
addresses: addresses,
interfaces: interfaces,
protocols: protocols,
}}}, nil
}

Expand Down
4 changes: 2 additions & 2 deletions caddyconfig/httpcaddyfile/tlsapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ func (st ServerType) buildTLSApp(
if acmeIssuer.Challenges.BindHost == "" {
// only binding to one host is supported
var bindHost string
if asserted, ok := cfgVal.Value.(addressesWithProtocols); ok && len(asserted.addresses) > 0 {
if asserted, ok := cfgVal.Value.(bindOptions); ok && len(asserted.addresses) > 0 {
bindHost = asserted.addresses[0]
}
acmeIssuer.Challenges.BindHost = bindHost
Expand Down Expand Up @@ -613,7 +613,7 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]any) e
// In Linux the same call will error with EADDRINUSE whenever the listener for the automation policy is opened
if acmeIssuer.Challenges == nil || (acmeIssuer.Challenges.DNS == nil && acmeIssuer.Challenges.BindHost == "") {
if defBinds, ok := globalDefaultBind.([]ConfigValue); ok && len(defBinds) > 0 {
if abp, ok := defBinds[0].Value.(addressesWithProtocols); ok && len(abp.addresses) > 0 {
if abp, ok := defBinds[0].Value.(bindOptions); ok && len(abp.addresses) > 0 {
if acmeIssuer.Challenges == nil {
acmeIssuer.Challenges = new(caddytls.ChallengesConfig)
}
Expand Down
7 changes: 3 additions & 4 deletions listen.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"fmt"
"net"
"os"
"slices"
"strconv"
"sync"
"sync/atomic"
Expand All @@ -37,7 +36,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 {
Expand Down Expand Up @@ -66,8 +65,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
Expand Down
9 changes: 4 additions & 5 deletions listen_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"io/fs"
"net"
"os"
"slices"
"strconv"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
Loading
Loading