diff --git a/src/config/config.go b/src/config/config.go index 767dc188..d81907f5 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -27,19 +27,25 @@ import ( // supply one of these structs to the Yggdrasil core when starting a node. type NodeConfig struct { sync.RWMutex `json:"-"` - Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tls://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."` - InterfacePeers map[string][]string `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ tls://a.b.c.d:e ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."` - Listen []string `comment:"Listen addresses for incoming connections. You will need to add\nlisteners in order to accept incoming peerings from non-local nodes.\nMulticast peer discovery will work regardless of any listeners set\nhere. Each listener should be specified in URI format as above, e.g.\ntls://0.0.0.0:0 or tls://[::]:0 to listen on all interfaces."` - AdminListen string `comment:"Listen address for admin connections. Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X. To disable\nthe admin socket, use the value \"none\" instead."` - MulticastInterfaces []string `comment:"Regular expressions for which interfaces multicast peer discovery\nshould be enabled on. If none specified, multicast peer discovery is\ndisabled. The default value is .* which uses all interfaces."` - AllowedPublicKeys []string `comment:"List of peer public keys to allow incoming peering connections\nfrom. If left empty/undefined then all connections will be allowed\nby default. This does not affect outgoing peerings, nor does it\naffect link-local peers discovered via multicast."` - PublicKey string `comment:"Your public key. Your peers may ask you for this to put\ninto their AllowedPublicKeys configuration."` - PrivateKey string `comment:"Your private key. DO NOT share this with anyone!"` - LinkLocalTCPPort uint16 `comment:"The port number to be used for the link-local TCP listeners for the\nconfigured MulticastInterfaces. This option does not affect listeners\nspecified in the Listen option. Unless you plan to firewall link-local\ntraffic, it is best to leave this as the default value of 0. This\noption cannot currently be changed by reloading config during runtime."` - IfName string `comment:"Local network interface name for TUN adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN."` - IfMTU uint64 `comment:"Maximum Transmission Unit (MTU) size for your local TUN interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."` - NodeInfoPrivacy bool `comment:"By default, nodeinfo contains some defaults including the platform,\narchitecture and Yggdrasil version. These can help when surveying\nthe network and diagnosing network routing problems. Enabling\nnodeinfo privacy prevents this, so that only items specified in\n\"NodeInfo\" are sent back if specified."` - NodeInfo map[string]interface{} `comment:"Optional node info. This must be a { \"key\": \"value\", ... } map\nor set as null. This is entirely optional but, if set, is visible\nto the whole network on request."` + Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tls://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."` + InterfacePeers map[string][]string `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ tls://a.b.c.d:e ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."` + Listen []string `comment:"Listen addresses for incoming connections. You will need to add\nlisteners in order to accept incoming peerings from non-local nodes.\nMulticast peer discovery will work regardless of any listeners set\nhere. Each listener should be specified in URI format as above, e.g.\ntls://0.0.0.0:0 or tls://[::]:0 to listen on all interfaces."` + AdminListen string `comment:"Listen address for admin connections. Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X. To disable\nthe admin socket, use the value \"none\" instead."` + MulticastInterfaces []MulticastInterfaceConfig `comment:"Regular expressions for which interfaces multicast peer discovery\nshould be enabled on. If none specified, multicast peer discovery is\ndisabled. The default value is .* which uses all interfaces."` + AllowedPublicKeys []string `comment:"List of peer public keys to allow incoming peering connections\nfrom. If left empty/undefined then all connections will be allowed\nby default. This does not affect outgoing peerings, nor does it\naffect link-local peers discovered via multicast."` + PublicKey string `comment:"Your public key. Your peers may ask you for this to put\ninto their AllowedPublicKeys configuration."` + PrivateKey string `comment:"Your private key. DO NOT share this with anyone!"` + LinkLocalTCPPort uint16 `comment:"The port number to be used for the link-local TCP listeners for the\nconfigured MulticastInterfaces. This option does not affect listeners\nspecified in the Listen option. Unless you plan to firewall link-local\ntraffic, it is best to leave this as the default value of 0. This\noption cannot currently be changed by reloading config during runtime."` + IfName string `comment:"Local network interface name for TUN adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN."` + IfMTU uint64 `comment:"Maximum Transmission Unit (MTU) size for your local TUN interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."` + NodeInfoPrivacy bool `comment:"By default, nodeinfo contains some defaults including the platform,\narchitecture and Yggdrasil version. These can help when surveying\nthe network and diagnosing network routing problems. Enabling\nnodeinfo privacy prevents this, so that only items specified in\n\"NodeInfo\" are sent back if specified."` + NodeInfo map[string]interface{} `comment:"Optional node info. This must be a { \"key\": \"value\", ... } map\nor set as null. This is entirely optional but, if set, is visible\nto the whole network on request."` +} + +type MulticastInterfaceConfig struct { + Regex string + Incoming bool + Outgoing bool } // NewSigningKeys replaces the signing keypair in the NodeConfig with a new diff --git a/src/defaults/defaults.go b/src/defaults/defaults.go index 238a36d7..7912fc76 100644 --- a/src/defaults/defaults.go +++ b/src/defaults/defaults.go @@ -2,6 +2,8 @@ package defaults import "github.com/yggdrasil-network/yggdrasil-go/src/config" +type MulticastInterfaceConfig = config.MulticastInterfaceConfig + // Defines which parameters are expected by default for configuration on a // specific platform. These values are populated in the relevant defaults_*.go // for the platform being targeted. They must be set. @@ -13,7 +15,7 @@ type platformDefaultParameters struct { DefaultConfigFile string // Multicast interfaces - DefaultMulticastInterfaces []string + DefaultMulticastInterfaces []MulticastInterfaceConfig // TUN/TAP MaximumIfMTU uint64 diff --git a/src/defaults/defaults_darwin.go b/src/defaults/defaults_darwin.go index 9fbe6d8e..a21539f7 100644 --- a/src/defaults/defaults_darwin.go +++ b/src/defaults/defaults_darwin.go @@ -13,9 +13,9 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "/etc/yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - "en.*", - "bridge.*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: "en.*", Incoming: true, Outgoing: true}, + {Regex: "bridge.*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_freebsd.go b/src/defaults/defaults_freebsd.go index a57be2fa..400ae29a 100644 --- a/src/defaults/defaults_freebsd.go +++ b/src/defaults/defaults_freebsd.go @@ -13,8 +13,8 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "/usr/local/etc/yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - ".*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: ".*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_linux.go b/src/defaults/defaults_linux.go index 5f3f12a8..ac678d85 100644 --- a/src/defaults/defaults_linux.go +++ b/src/defaults/defaults_linux.go @@ -13,8 +13,8 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "/etc/yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - ".*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: ".*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_openbsd.go b/src/defaults/defaults_openbsd.go index 6700eb8f..f3e2376c 100644 --- a/src/defaults/defaults_openbsd.go +++ b/src/defaults/defaults_openbsd.go @@ -13,8 +13,8 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "/etc/yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - ".*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: ".*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_other.go b/src/defaults/defaults_other.go index 3b035537..d23c2ef0 100644 --- a/src/defaults/defaults_other.go +++ b/src/defaults/defaults_other.go @@ -13,8 +13,8 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "/etc/yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - ".*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: ".*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/defaults/defaults_windows.go b/src/defaults/defaults_windows.go index 305a2ffe..1e918c3b 100644 --- a/src/defaults/defaults_windows.go +++ b/src/defaults/defaults_windows.go @@ -13,8 +13,8 @@ func GetDefaults() platformDefaultParameters { DefaultConfigFile: "C:\\Program Files\\Yggdrasil\\yggdrasil.conf", // Multicast interfaces - DefaultMulticastInterfaces: []string{ - ".*", + DefaultMulticastInterfaces: []MulticastInterfaceConfig{ + {Regex: ".*", Incoming: true, Outgoing: true}, }, // TUN/TAP diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 5d9f689c..aea4e079 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -38,8 +38,10 @@ type Multicast struct { } type interfaceInfo struct { - iface net.Interface - addrs []net.Addr + iface net.Interface + addrs []net.Addr + incoming bool + outgoing bool } type listenerInfo struct { @@ -136,18 +138,16 @@ func (m *Multicast) _stop() error { } func (m *Multicast) _updateInterfaces() { - interfaces := make(map[string]interfaceInfo) - intfs := m.getAllowedInterfaces() - for _, intf := range intfs { - addrs, err := intf.Addrs() + interfaces := m.getAllowedInterfaces() + for name, info := range interfaces { + addrs, err := info.iface.Addrs() if err != nil { - m.log.Warnf("Failed up get addresses for interface %s: %s", intf.Name, err) + m.log.Warnf("Failed up get addresses for interface %s: %s", name, err) + delete(interfaces, name) continue } - interfaces[intf.Name] = interfaceInfo{ - iface: intf, - addrs: addrs, - } + info.addrs = addrs + interfaces[name] = info } m._interfaces = interfaces } @@ -163,10 +163,10 @@ func (m *Multicast) Interfaces() map[string]net.Interface { } // getAllowedInterfaces returns the currently known/enabled multicast interfaces. -func (m *Multicast) getAllowedInterfaces() map[string]net.Interface { - interfaces := make(map[string]net.Interface) +func (m *Multicast) getAllowedInterfaces() map[string]interfaceInfo { + interfaces := make(map[string]interfaceInfo) // Get interface expressions from config - exprs := m.config.MulticastInterfaces + ifcfgs := m.config.MulticastInterfaces // Ask the system for network interfaces allifaces, err := net.Interfaces() if err != nil { @@ -188,15 +188,23 @@ func (m *Multicast) getAllowedInterfaces() map[string]net.Interface { // Ignore point-to-point interfaces continue } - for _, expr := range exprs { + for _, ifcfg := range ifcfgs { // Compile each regular expression - e, err := regexp.Compile(expr) + e, err := regexp.Compile(ifcfg.Regex) if err != nil { panic(err) } // Does the interface match the regular expression? Store it if so if e.MatchString(iface.Name) { - interfaces[iface.Name] = iface + if ifcfg.Incoming || ifcfg.Outgoing { + info := interfaceInfo{ + iface: iface, + incoming: ifcfg.Incoming, + outgoing: ifcfg.Outgoing, + } + interfaces[iface.Name] = info + } + break } } } @@ -272,8 +280,13 @@ func (m *Multicast) _announce() { if !addrIP.IsLinkLocalUnicast() { continue } - // Join the multicast group - _ = m.sock.JoinGroup(&iface, groupAddr) + if info.outgoing { + // Join the multicast group, so we can listen for advertisements to open outgoing connections + _ = m.sock.JoinGroup(&iface, groupAddr) + } + if !info.incoming { + break // Don't send multicast advertisements if we don't accept incoming connections + } // Try and see if we already have a TCP listener for this interface var info *listenerInfo if nfo, ok := m.listeners[iface.Name]; !ok || nfo.listener.Listener == nil { @@ -378,7 +391,7 @@ func (m *Multicast) listen() { phony.Block(m, func() { interfaces = m._interfaces }) - if _, ok := interfaces[from.Zone]; ok { + if info, ok := interfaces[from.Zone]; ok && info.outgoing { addr.Zone = "" pin := fmt.Sprintf("/?key=%s", hex.EncodeToString(key)) u, err := url.Parse("tls://" + addr.String() + pin)