From 7a57b61da980aca29bae9a695babb29e44ff4f61 Mon Sep 17 00:00:00 2001 From: Badreddin Aboubakr Date: Mon, 1 Jul 2024 15:59:48 +0200 Subject: [PATCH] feat(mdns): allow specifying iface for mDNS --- cmd/serf/command/agent/command.go | 22 ++++++++++++++++++++-- cmd/serf/command/agent/config.go | 25 ++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/cmd/serf/command/agent/command.go b/cmd/serf/command/agent/command.go index dbbe860a7..9ebe8070c 100644 --- a/cmd/serf/command/agent/command.go +++ b/cmd/serf/command/agent/command.go @@ -88,6 +88,7 @@ func (c *Command) readConfig() *Config { "tag pair, specified as key=value") cmdFlags.StringVar(&cmdConfig.Discover, "discover", "", "mDNS discovery name") cmdFlags.StringVar(&cmdConfig.Interface, "iface", "", "interface to bind to") + cmdFlags.StringVar(&cmdConfig.MDNS.Interface, "mdns-iface", "", "interface to use for mDNS") cmdFlags.StringVar(&cmdConfig.TagsFile, "tags-file", "", "tag persistence file") cmdFlags.BoolVar(&cmdConfig.EnableSyslog, "syslog", false, "enable logging to syslog facility") @@ -176,6 +177,18 @@ func (c *Command) readConfig() *Config { return nil } + if config.MDNS.Interface != "" { + if config.Discover == "" { + c.Ui.Error("mDNS interface specified without enabling mDNS discovery") + return nil + } + + if _, err := net.InterfaceByName(config.MDNS.Interface); err != nil { + c.Ui.Error(fmt.Sprintf("Invalid mDNS network interface: %s", err)) + return nil + } + } + // Backward compatibility hack for 'Role' if config.Role != "" { c.Ui.Output("Deprecation warning: 'Role' has been replaced with 'Tags'") @@ -432,7 +445,9 @@ func (c *Command) startAgent(config *Config, agent *Agent, local := agent.Serf().Memberlist().LocalNode() // Get the bind interface if any - iface, _ := config.NetworkInterface() + iface, _ := config.MDNSNetworkInterface() + + c.logger.Printf("[INFO] agent: Starting mDNS listener on interface %s", iface.Name) _, err := NewAgentMDNS(agent, logOutput, config.ReplayOnJoin, config.NodeName, config.Discover, iface, local.Addr, int(local.Port)) @@ -734,7 +749,10 @@ Options: -bind if the interface is known but not the address. If both are provided, then Serf verifies that the interface has the bind address that is provided. This - flag also sets the multicast device used for -discover. + flag also sets the multicast device used for -discover, + if mdns-iface is not specified. + -mdns-iface Network interface to use for mDNS. If not provided, the + -iface value is used. -advertise=0.0.0.0 Address to advertise to the other cluster members -config-file=foo Path to a JSON file to read configuration from. This can be specified multiple times. diff --git a/cmd/serf/command/agent/config.go b/cmd/serf/command/agent/config.go index 49186c529..abf2460e6 100644 --- a/cmd/serf/command/agent/config.go +++ b/cmd/serf/command/agent/config.go @@ -45,6 +45,12 @@ func DefaultConfig() *Config { type dirEnts []os.FileInfo +type MDNSConfig struct { + // Interface is used to provide a binding interface to use for mDNS. + // if not set, iface will be used. + Interface string `mapstructure:"interface"` +} + // Config is the configuration that can be set for an Agent. Some of these // configurations are exposed as command-line flags to `serf agent`, whereas // many of the more advanced configurations can only be set by creating @@ -154,10 +160,12 @@ type Config struct { // allows Serf agents to join each other with zero configuration. Discover string `mapstructure:"discover"` + MDNS MDNSConfig `mapstructure:"mdns"` + // Interface is used to provide a binding interface to use. It can be // used instead of providing a bind address, as Serf will discover the // address of the provided interface. It is also used to set the multicast - // device used with `-discover`. + // device used with `-discover`, if `mdns-iface` is not set Interface string `mapstructure:"interface"` // ReconnectIntervalRaw is the string reconnect interval time. This interval @@ -292,6 +300,16 @@ func (c *Config) NetworkInterface() (*net.Interface, error) { return net.InterfaceByName(c.Interface) } +func (c *Config) MDNSNetworkInterface() (*net.Interface, error) { + if c.MDNS.Interface == "" && c.Interface == "" { + return nil, nil + } else if c.MDNS.Interface != "" { + return net.InterfaceByName(c.MDNS.Interface) + } else { + return net.InterfaceByName(c.Interface) + } +} + // DecodeConfig reads the configuration from the given reader in JSON // format and decodes it into a proper Config structure. func DecodeConfig(r io.Reader) (*Config, error) { @@ -436,6 +454,11 @@ func MergeConfig(a, b *Config) *Config { if b.Interface != "" { result.Interface = b.Interface } + + if b.MDNS.Interface != "" { + result.MDNS.Interface = b.MDNS.Interface + } + if b.ReconnectInterval != 0 { result.ReconnectInterval = b.ReconnectInterval }