mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 15:26:40 +00:00
Extend stdnet to have an interface filter
This commit is contained in:
@@ -166,7 +166,7 @@ func (e *Engine) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start creates a new Wireguard tunnel interface and listens to events from Signal and Management services
|
||||
// Start creates a new WireGuard tunnel interface and listens to events from Signal and Management services
|
||||
// Connections to remote peers are not established here.
|
||||
// However, they will be established once an event with a list of peers to connect to will be received from Management Service
|
||||
func (e *Engine) Start() error {
|
||||
@@ -184,10 +184,11 @@ func (e *Engine) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
/*transportNet, err := e.newStdNet()
|
||||
transportNet, err := e.newStdNet()
|
||||
if err != nil {
|
||||
log.Warnf("failed to create pion's stdnet: %s", err)
|
||||
}*/
|
||||
}
|
||||
fmt.Sprint(transportNet)
|
||||
|
||||
err = e.wgInterface.Create()
|
||||
if err != nil {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"github.com/pion/transport/v2/stdnet"
|
||||
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||
)
|
||||
|
||||
func (e *Engine) newStdNet() (*stdnet.Net, error) {
|
||||
return stdnet.NewNet()
|
||||
return stdnet.NewNet(nil, e.config.IFaceBlackList)
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ package internal
|
||||
import "github.com/netbirdio/netbird/client/internal/stdnet"
|
||||
|
||||
func (e *Engine) newStdNet() (*stdnet.Net, error) {
|
||||
return stdnet.NewNet(e.config.IFaceDiscover)
|
||||
return stdnet.NewNet(e.config.IFaceDiscover, e.config.IFaceBlackList)
|
||||
}
|
||||
|
||||
@@ -8,16 +8,14 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pion/ice/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/proxy"
|
||||
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||
"github.com/netbirdio/netbird/iface"
|
||||
signal "github.com/netbirdio/netbird/signal/client"
|
||||
sProto "github.com/netbirdio/netbird/signal/proto"
|
||||
"github.com/netbirdio/netbird/version"
|
||||
"github.com/pion/ice/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// ConnConfig is a peer Connection configuration
|
||||
@@ -136,32 +134,6 @@ func NewConn(config ConnConfig, statusRecorder *Status, adapter iface.TunAdapter
|
||||
}, nil
|
||||
}
|
||||
|
||||
// interfaceFilter is a function passed to ICE Agent to filter out not allowed interfaces
|
||||
// to avoid building tunnel over them
|
||||
func interfaceFilter(blackList []string) func(string) bool {
|
||||
|
||||
return func(iFace string) bool {
|
||||
for _, s := range blackList {
|
||||
if strings.HasPrefix(iFace, s) {
|
||||
log.Debugf("ignoring interface %s - it is not allowed", iFace)
|
||||
return false
|
||||
}
|
||||
}
|
||||
// look for unlisted WireGuard interfaces
|
||||
wg, err := wgctrl.New()
|
||||
if err != nil {
|
||||
log.Debugf("trying to create a wgctrl client failed with: %v", err)
|
||||
return true
|
||||
}
|
||||
defer func() {
|
||||
_ = wg.Close()
|
||||
}()
|
||||
|
||||
_, err = wg.Device(iFace)
|
||||
return err != nil
|
||||
}
|
||||
}
|
||||
|
||||
func (conn *Conn) reCreateAgent() error {
|
||||
conn.mu.Lock()
|
||||
defer conn.mu.Unlock()
|
||||
@@ -179,7 +151,7 @@ func (conn *Conn) reCreateAgent() error {
|
||||
Urls: conn.config.StunTurn,
|
||||
CandidateTypes: []ice.CandidateType{ice.CandidateTypeHost, ice.CandidateTypeServerReflexive},
|
||||
FailedTimeout: &failedTimeout,
|
||||
InterfaceFilter: interfaceFilter(conn.config.InterfaceBlackList),
|
||||
InterfaceFilter: stdnet.InterfaceFilter(conn.config.InterfaceBlackList),
|
||||
UDPMux: conn.config.UDPMux,
|
||||
UDPMuxSrflx: conn.config.UDPMuxSrflx,
|
||||
NAT1To1IPs: conn.config.NATExternalIPs,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -28,7 +29,7 @@ func TestNewConn_interfaceFilter(t *testing.T) {
|
||||
ignore := []string{iface.WgInterfaceDefault, "tun0", "zt", "ZeroTier", "utun", "wg", "ts",
|
||||
"Tailscale", "tailscale"}
|
||||
|
||||
filter := interfaceFilter(ignore)
|
||||
filter := stdnet.InterfaceFilter(ignore)
|
||||
|
||||
for _, s := range ignore {
|
||||
assert.Equal(t, filter(s), false)
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"github.com/pion/transport/v2/stdnet"
|
||||
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||
)
|
||||
|
||||
func (conn *Conn) newStdNet() (*stdnet.Net, error) {
|
||||
return stdnet.NewNet()
|
||||
return stdnet.NewNet(nil, conn.config.InterfaceBlackList)
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ package peer
|
||||
import "github.com/netbirdio/netbird/client/internal/stdnet"
|
||||
|
||||
func (conn *Conn) newStdNet() (*stdnet.Net, error) {
|
||||
return stdnet.NewNet(conn.iFaceDiscover)
|
||||
return stdnet.NewNet(conn.iFaceDiscover, e.config.IFaceBlackList)
|
||||
}
|
||||
|
||||
@@ -4,5 +4,6 @@ package stdnet
|
||||
// to collect network interface information
|
||||
type IFaceDiscover interface {
|
||||
// IFaces return with the description of the interfaces
|
||||
// todo refactor this to return []*transport.Interface instead to have it generic and independent from the platform
|
||||
IFaces() (string, error)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ package stdnet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
@@ -18,24 +19,78 @@ import (
|
||||
type Net struct {
|
||||
stdnet.Net
|
||||
interfaces []*transport.Interface
|
||||
// interfaceFilter should return true if the given interfaceName is allowed
|
||||
interfaceFilter func(interfaceName string) bool
|
||||
}
|
||||
|
||||
// NewNet creates a new StdNet instance.
|
||||
func NewNet(iFaceDiscover IFaceDiscover) (*Net, error) {
|
||||
n := &Net{}
|
||||
|
||||
// iFaceDiscover and disallowList can be nil.
|
||||
// iFaceDiscover
|
||||
func NewNet(iFaceDiscover IFaceDiscover, disallowList []string) (*Net, error) {
|
||||
n := &Net{interfaceFilter: InterfaceFilter(disallowList)}
|
||||
return n, n.UpdateInterfaces(iFaceDiscover)
|
||||
}
|
||||
|
||||
func (n *Net) filterInterfaces(interfaces []*transport.Interface) []*transport.Interface {
|
||||
if n.interfaceFilter == nil {
|
||||
return interfaces
|
||||
}
|
||||
result := []*transport.Interface{}
|
||||
for _, iface := range interfaces {
|
||||
if n.interfaceFilter(iface.Name) {
|
||||
result = append(result, iface)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// UpdateInterfaces updates the internal list of network interfaces
|
||||
// and associated addresses.
|
||||
// and associated addresses filtering them by name.
|
||||
// The interfaces are discovered by an external iFaceDiscover function or by a default discoverer if the external one
|
||||
// wasn't specified.
|
||||
func (n *Net) UpdateInterfaces(iFaceDiscover IFaceDiscover) error {
|
||||
ifacesString, err := iFaceDiscover.IFaces()
|
||||
discoveredInterfaces := []*transport.Interface{}
|
||||
var err error
|
||||
if iFaceDiscover != nil {
|
||||
interfacesString := ""
|
||||
interfacesString, err = iFaceDiscover.IFaces()
|
||||
discoveredInterfaces = parseInterfacesString(interfacesString)
|
||||
} else {
|
||||
// fallback to the default discovering if custom IFaceDiscover wasn't provided
|
||||
discoveredInterfaces, err = discoverInterfaces()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.interfaces = parseInterfacesString(ifacesString)
|
||||
return err
|
||||
|
||||
n.interfaces = n.filterInterfaces(discoveredInterfaces)
|
||||
return nil
|
||||
}
|
||||
|
||||
func discoverInterfaces() ([]*transport.Interface, error) {
|
||||
ifs := []*transport.Interface{}
|
||||
|
||||
oifs, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, oif := range oifs {
|
||||
ifc := transport.NewInterface(oif)
|
||||
|
||||
addrs, err := oif.Addrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
ifc.AddAddress(addr)
|
||||
}
|
||||
|
||||
ifs = append(ifs, ifc)
|
||||
}
|
||||
|
||||
return ifs, nil
|
||||
}
|
||||
|
||||
// Interfaces returns a slice of interfaces which are available on the
|
||||
@@ -135,3 +190,29 @@ func parseInterfacesString(interfaces string) []*transport.Interface {
|
||||
}
|
||||
return ifs
|
||||
}
|
||||
|
||||
// InterfaceFilter is a function passed to ICE Agent to filter out not allowed interfaces
|
||||
// to avoid building tunnel over them.
|
||||
func InterfaceFilter(disallowList []string) func(string) bool {
|
||||
|
||||
return func(iFace string) bool {
|
||||
for _, s := range disallowList {
|
||||
if strings.HasPrefix(iFace, s) {
|
||||
log.Debugf("ignoring interface %s - it is not allowed", iFace)
|
||||
return false
|
||||
}
|
||||
}
|
||||
// look for unlisted WireGuard interfaces
|
||||
wg, err := wgctrl.New()
|
||||
if err != nil {
|
||||
log.Debugf("trying to create a wgctrl client failed with: %v", err)
|
||||
return true
|
||||
}
|
||||
defer func() {
|
||||
_ = wg.Close()
|
||||
}()
|
||||
|
||||
_, err = wg.Device(iFace)
|
||||
return err != nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/pion/stun"
|
||||
"github.com/pion/transport/v2/stdnet"
|
||||
"github.com/pion/transport/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.zx2c4.com/wireguard/conn"
|
||||
"net"
|
||||
@@ -14,10 +14,23 @@ import (
|
||||
)
|
||||
|
||||
type ICEBind struct {
|
||||
// below fields, initialized on open
|
||||
sharedConn net.PacketConn
|
||||
udpMux *UniversalUDPMuxDefault
|
||||
|
||||
mu sync.Mutex // protects following fields
|
||||
// below are fields initialized on creation
|
||||
transportNet transport.Net
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// NewICEBind create a new instance of ICEBind with a given transportNet and an interfaceFilter function.
|
||||
// The interfaceFilter function is used to exclude interfaces from hole punching (the IPs of that interfaces won't be used as connection candidates)
|
||||
// The transportNet can be nil.
|
||||
func NewICEBind(transportNet transport.Net, interfaceFilter func(interfaceName string) bool) *ICEBind {
|
||||
return &ICEBind{
|
||||
transportNet: transportNet,
|
||||
mu: sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
func (b *ICEBind) GetICEMux() (*UniversalUDPMuxDefault, error) {
|
||||
@@ -44,11 +57,7 @@ func (b *ICEBind) Open(uport uint16) ([]conn.ReceiveFunc, uint16, error) {
|
||||
return nil, 0, err
|
||||
}
|
||||
b.sharedConn = ipv4Conn
|
||||
newNet, err := stdnet.NewNet()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
b.udpMux = NewUniversalUDPMuxDefault(UniversalUDPMuxParams{UDPConn: b.sharedConn, Net: newNet})
|
||||
b.udpMux = NewUniversalUDPMuxDefault(UniversalUDPMuxParams{UDPConn: b.sharedConn, Net: b.transportNet})
|
||||
|
||||
portAddr1, err := netip.ParseAddrPort(ipv4Conn.LocalAddr().String())
|
||||
if err != nil {
|
||||
|
||||
@@ -211,7 +211,6 @@ func (m *UDPMuxDefault) LocalAddr() net.Addr {
|
||||
|
||||
// GetListenAddresses returns the list of addresses that this mux is listening on
|
||||
func (m *UDPMuxDefault) GetListenAddresses() []net.Addr {
|
||||
log.Infof("---------------------------------")
|
||||
if len(m.localAddrsForUnspecified) > 0 {
|
||||
return m.localAddrsForUnspecified
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ type udpConn struct {
|
||||
}
|
||||
|
||||
func (m *UniversalUDPMuxDefault) GetListenAddresses() []net.Addr {
|
||||
log.Infof("================================")
|
||||
return []net.Addr{m.LocalAddr()}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user