to_device

This commit is contained in:
Aaron Paterson 2025-12-05 00:05:19 -07:00
parent 4435af28d3
commit b3b711b2bc
3 changed files with 86 additions and 83 deletions

View file

@ -320,9 +320,9 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad
} }
} else { } else {
lnCfgVals = []bindOptions{{ lnCfgVals = []bindOptions{{
addresses: []string{""}, addresses: []string{""},
interfaces: nil, protocols: nil,
protocols: nil, to_device: false,
}} }}
} }
} }
@ -332,76 +332,79 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad
interfaces := map[string][]net.Addr{} interfaces := map[string][]net.Addr{}
for _, lnCfgVal := range lnCfgVals { for _, lnCfgVal := range lnCfgVals {
lnAddresses := make([]string, 0, len(lnCfgVal.addresses)) lnAddresses := make([]string, 0, len(lnCfgVal.addresses))
lnAddresses = append(lnAddresses, lnCfgVal.addresses...) for _, lnAddress := range lnCfgVal.addresses {
for _, lnIface := range lnCfgVal.interfaces { if lnCfgVal.to_device {
lnNetw, lnDevice, _, err := caddy.SplitNetworkAddress(lnIface) lnNetw, lnDevice, _, err := caddy.SplitNetworkAddress(lnAddress)
if err != nil {
return nil, fmt.Errorf("splitting listener interface: %v", err)
}
ifaceAddresses, ok := interfaces[lnDevice]
if !ok {
iface, err := net.InterfaceByName(lnDevice)
if err != nil { if err != nil {
return nil, fmt.Errorf("querying listener interface: %v: %v", lnDevice, err) return nil, fmt.Errorf("splitting listener interface: %v", err)
} }
if iface == nil {
return nil, fmt.Errorf("querying listener interface: %v", lnDevice)
}
ifaceAddresses, err := iface.Addrs()
if err != nil {
return nil, fmt.Errorf("querying listener interface addresses: %v: %v", lnDevice, err)
}
interfaces[lnDevice] = ifaceAddresses
}
lnIfaceAddresses := []string{} ifaceAddresses, ok := interfaces[lnDevice]
for _, ifaceAddress := range ifaceAddresses { if !ok {
if caddy.IsReservedNetwork(lnNetw) { iface, err := net.InterfaceByName(lnDevice)
var addrok, netwok bool if err != nil {
return nil, fmt.Errorf("querying listener interface: %v: %v", lnDevice, err)
var ip net.IP
switch ifaceAddressValue := ifaceAddress.(type) {
case *net.IPAddr:
ip, addrok, netwok = ifaceAddressValue.IP, true, true
case *net.IPNet:
ip, addrok, netwok = ifaceAddressValue.IP, true, true
case *net.TCPAddr:
ip, addrok, netwok = ifaceAddressValue.IP, true, caddy.IsTCPNetwork(lnNetw)
case *net.UDPAddr:
ip, addrok, netwok = ifaceAddressValue.IP, true, caddy.IsUDPNetwork(lnNetw)
} }
if iface == nil {
return nil, fmt.Errorf("querying listener interface: %v", lnDevice)
}
ifaceAddresses, err := iface.Addrs()
if err != nil {
return nil, fmt.Errorf("querying listener interface addresses: %v: %v", lnDevice, err)
}
interfaces[lnDevice] = ifaceAddresses
}
if addrok { lnIfaceAddresses := []string{}
if netwok { for _, ifaceAddress := range ifaceAddresses {
if caddy.IsIPv4Network(lnNetw) && len(ip) == net.IPv4len || caddy.IsIPv6Network(lnNetw) && len(ip) == net.IPv6len { if caddy.IsReservedNetwork(lnNetw) {
lnIfaceAddresses = append(lnIfaceAddresses, ip.String()) var addrok, netwok bool
var ip net.IP
switch ifaceAddressValue := ifaceAddress.(type) {
case *net.IPAddr:
ip, addrok, netwok = ifaceAddressValue.IP, true, true
case *net.IPNet:
ip, addrok, netwok = ifaceAddressValue.IP, true, true
case *net.TCPAddr:
ip, addrok, netwok = ifaceAddressValue.IP, true, caddy.IsTCPNetwork(lnNetw)
case *net.UDPAddr:
ip, addrok, netwok = ifaceAddressValue.IP, true, caddy.IsUDPNetwork(lnNetw)
}
if addrok {
if netwok {
if caddy.IsIPv4Network(lnNetw) && len(ip) == net.IPv4len || caddy.IsIPv6Network(lnNetw) && len(ip) == net.IPv6len {
lnIfaceAddresses = append(lnIfaceAddresses, ip.String())
}
} }
continue
} }
continue
}
var name string var name string
switch ifaceAddressValue := ifaceAddress.(type) { switch ifaceAddressValue := ifaceAddress.(type) {
case *net.UnixAddr: case *net.UnixAddr:
name, addrok, netwok = ifaceAddressValue.Name, true, caddy.IsUnixNetwork(lnNetw) name, addrok, netwok = ifaceAddressValue.Name, true, caddy.IsUnixNetwork(lnNetw)
}
if addrok {
if netwok {
lnIfaceAddresses = append(lnIfaceAddresses, name)
} }
continue
if addrok {
if netwok {
lnIfaceAddresses = append(lnIfaceAddresses, name)
}
continue
}
} else {
lnIfaceAddresses = append(lnIfaceAddresses, ifaceAddress.String())
} }
} else {
lnIfaceAddresses = append(lnIfaceAddresses, ifaceAddress.String())
} }
} if len(lnIfaceAddresses) == 0 {
if len(lnIfaceAddresses) == 0 { return nil, fmt.Errorf("no available listener interface addresses for network: %v: %v", lnDevice, lnNetw)
return nil, fmt.Errorf("no available listener interface addresses for network: %v: %v", lnDevice, lnNetw) }
} for _, lnIfaceAddress := range lnIfaceAddresses {
for _, lnIfaceAddress := range lnIfaceAddresses { lnAddresses = append(lnAddresses, caddy.JoinNetworkAddress(lnNetw, lnIfaceAddress, ""))
lnAddresses = append(lnAddresses, caddy.JoinNetworkAddress(lnNetw, lnIfaceAddress, "")) }
} else {
lnAddresses = append(lnAddresses, lnAddress)
} }
} }
for _, lnAddr := range lnAddresses { for _, lnAddr := range lnAddresses {
@ -426,9 +429,9 @@ func (st *ServerType) listenersForServerBlockAddress(sblock serverBlock, addr Ad
} }
type bindOptions struct { type bindOptions struct {
addresses []string addresses []string
interfaces []string protocols []string
protocols []string to_device bool
} }
// Address represents a site address. It contains // Address represents a site address. It contains

View file

@ -63,30 +63,30 @@ func init() {
// }] // }]
func parseBind(h Helper) ([]ConfigValue, error) { func parseBind(h Helper) ([]ConfigValue, error) {
h.Next() // consume directive name h.Next() // consume directive name
var addresses, interfaces, protocols []string var (
addresses, protocols []string
to_device bool
)
addresses = h.RemainingArgs() addresses = h.RemainingArgs()
for h.NextBlock(0) { for h.NextBlock(0) {
switch h.Val() { switch h.Val() {
case "interfaces":
interfaces = h.RemainingArgs()
if len(interfaces) == 0 {
return nil, h.Errf("interfaces requires one or more arguments")
}
case "protocols": case "protocols":
protocols = h.RemainingArgs() protocols = h.RemainingArgs()
if len(protocols) == 0 { if len(protocols) == 0 {
return nil, h.Errf("protocols requires one or more arguments") return nil, h.Errf("protocols requires one or more arguments")
} }
case "to_device":
to_device = true
default: default:
return nil, h.Errf("unknown subdirective: %s", h.Val()) return nil, h.Errf("unknown subdirective: %s", h.Val())
} }
} }
return []ConfigValue{{Class: "bind", Value: bindOptions{ return []ConfigValue{{Class: "bind", Value: bindOptions{
addresses: addresses, addresses: addresses,
interfaces: interfaces, protocols: protocols,
protocols: protocols, to_device: to_device,
}}}, nil }}}, nil
} }

View file

@ -307,7 +307,10 @@ func parseOptSingleString(d *caddyfile.Dispenser, _ any) (any, error) {
func parseOptDefaultBind(d *caddyfile.Dispenser, _ any) (any, error) { func parseOptDefaultBind(d *caddyfile.Dispenser, _ any) (any, error) {
d.Next() // consume option name d.Next() // consume option name
var addresses, interfaces, protocols []string var (
addresses, protocols []string
to_device bool
)
addresses = d.RemainingArgs() addresses = d.RemainingArgs()
if len(addresses) == 0 { if len(addresses) == 0 {
@ -316,25 +319,22 @@ func parseOptDefaultBind(d *caddyfile.Dispenser, _ any) (any, error) {
for d.NextBlock(0) { for d.NextBlock(0) {
switch d.Val() { switch d.Val() {
case "interfaces":
interfaces = d.RemainingArgs()
if len(interfaces) == 0 {
return nil, d.Errf("interfaces requires one or more arguments")
}
case "protocols": case "protocols":
protocols = d.RemainingArgs() protocols = d.RemainingArgs()
if len(protocols) == 0 { if len(protocols) == 0 {
return nil, d.Errf("protocols requires one or more arguments") return nil, d.Errf("protocols requires one or more arguments")
} }
case "to_device":
to_device = true
default: default:
return nil, d.Errf("unknown subdirective: %s", d.Val()) return nil, d.Errf("unknown subdirective: %s", d.Val())
} }
} }
return []ConfigValue{{Class: "bind", Value: bindOptions{ return []ConfigValue{{Class: "bind", Value: bindOptions{
addresses: addresses, addresses: addresses,
interfaces: interfaces, protocols: protocols,
protocols: protocols, to_device: to_device,
}}}, nil }}}, nil
} }