mirror of
https://github.com/netbirdio/netbird.git
synced 2024-11-22 08:03:30 +01:00
Add custom ice stdnet implementation (#754)
On Android, because of the hard SELinux policies can not list the interfaces of the ICE package. Without it can not generate a host type candidate. In this pull request, the list of interfaces comes via the Java interface.
This commit is contained in:
parent
a27fe4326c
commit
d1703479ff
2
.github/workflows/golang-test-linux.yml
vendored
2
.github/workflows/golang-test-linux.yml
vendored
@ -72,7 +72,7 @@ jobs:
|
|||||||
run: go test -c -o routemanager-testing.bin ./client/internal/routemanager/...
|
run: go test -c -o routemanager-testing.bin ./client/internal/routemanager/...
|
||||||
|
|
||||||
- name: Generate Engine Test bin
|
- name: Generate Engine Test bin
|
||||||
run: go test -c -o engine-testing.bin ./client/internal/*.go
|
run: go test -c -o engine-testing.bin ./client/internal
|
||||||
|
|
||||||
- name: Generate Peer Test bin
|
- name: Generate Peer Test bin
|
||||||
run: go test -c -o peer-testing.bin ./client/internal/peer/...
|
run: go test -c -o peer-testing.bin ./client/internal/peer/...
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/client/internal"
|
"github.com/netbirdio/netbird/client/internal"
|
||||||
"github.com/netbirdio/netbird/client/internal/peer"
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
|
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||||
"github.com/netbirdio/netbird/client/system"
|
"github.com/netbirdio/netbird/client/system"
|
||||||
"github.com/netbirdio/netbird/formatter"
|
"github.com/netbirdio/netbird/formatter"
|
||||||
"github.com/netbirdio/netbird/iface"
|
"github.com/netbirdio/netbird/iface"
|
||||||
@ -23,6 +24,11 @@ type TunAdapter interface {
|
|||||||
iface.TunAdapter
|
iface.TunAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IFaceDiscover export internal IFaceDiscover for mobile
|
||||||
|
type IFaceDiscover interface {
|
||||||
|
stdnet.IFaceDiscover
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
formatter.SetLogcatFormatter(log.StandardLogger())
|
formatter.SetLogcatFormatter(log.StandardLogger())
|
||||||
}
|
}
|
||||||
@ -31,6 +37,7 @@ func init() {
|
|||||||
type Client struct {
|
type Client struct {
|
||||||
cfgFile string
|
cfgFile string
|
||||||
tunAdapter iface.TunAdapter
|
tunAdapter iface.TunAdapter
|
||||||
|
iFaceDiscover IFaceDiscover
|
||||||
recorder *peer.Status
|
recorder *peer.Status
|
||||||
ctxCancel context.CancelFunc
|
ctxCancel context.CancelFunc
|
||||||
ctxCancelLock *sync.Mutex
|
ctxCancelLock *sync.Mutex
|
||||||
@ -38,7 +45,7 @@ type Client struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewClient instantiate a new Client
|
// NewClient instantiate a new Client
|
||||||
func NewClient(cfgFile, deviceName string, tunAdapter TunAdapter) *Client {
|
func NewClient(cfgFile, deviceName string, tunAdapter TunAdapter, iFaceDiscover IFaceDiscover) *Client {
|
||||||
lvl, _ := log.ParseLevel("trace")
|
lvl, _ := log.ParseLevel("trace")
|
||||||
log.SetLevel(lvl)
|
log.SetLevel(lvl)
|
||||||
|
|
||||||
@ -46,6 +53,7 @@ func NewClient(cfgFile, deviceName string, tunAdapter TunAdapter) *Client {
|
|||||||
cfgFile: cfgFile,
|
cfgFile: cfgFile,
|
||||||
deviceName: deviceName,
|
deviceName: deviceName,
|
||||||
tunAdapter: tunAdapter,
|
tunAdapter: tunAdapter,
|
||||||
|
iFaceDiscover: iFaceDiscover,
|
||||||
recorder: peer.NewRecorder(""),
|
recorder: peer.NewRecorder(""),
|
||||||
ctxCancelLock: &sync.Mutex{},
|
ctxCancelLock: &sync.Mutex{},
|
||||||
}
|
}
|
||||||
@ -77,7 +85,7 @@ func (c *Client) Run(urlOpener URLOpener) error {
|
|||||||
|
|
||||||
// todo do not throw error in case of cancelled context
|
// todo do not throw error in case of cancelled context
|
||||||
ctx = internal.CtxInitState(ctx)
|
ctx = internal.CtxInitState(ctx)
|
||||||
return internal.RunClient(ctx, cfg, c.recorder, c.tunAdapter)
|
return internal.RunClient(ctx, cfg, c.recorder, c.tunAdapter, c.iFaceDiscover)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the internal client and free the resources
|
// Stop the internal client and free the resources
|
||||||
|
@ -94,7 +94,7 @@ func runInForegroundMode(ctx context.Context, cmd *cobra.Command) error {
|
|||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
ctx, cancel = context.WithCancel(ctx)
|
ctx, cancel = context.WithCancel(ctx)
|
||||||
SetupCloseHandler(ctx, cancel)
|
SetupCloseHandler(ctx, cancel)
|
||||||
return internal.RunClient(ctx, config, peer.NewRecorder(config.ManagementURL.String()), nil)
|
return internal.RunClient(ctx, config, peer.NewRecorder(config.ManagementURL.String()), nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runInDaemonMode(ctx context.Context, cmd *cobra.Command) error {
|
func runInDaemonMode(ctx context.Context, cmd *cobra.Command) error {
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
gstatus "google.golang.org/grpc/status"
|
gstatus "google.golang.org/grpc/status"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/internal/peer"
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
|
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||||
"github.com/netbirdio/netbird/client/ssh"
|
"github.com/netbirdio/netbird/client/ssh"
|
||||||
"github.com/netbirdio/netbird/client/system"
|
"github.com/netbirdio/netbird/client/system"
|
||||||
"github.com/netbirdio/netbird/iface"
|
"github.com/netbirdio/netbird/iface"
|
||||||
@ -22,7 +23,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// RunClient with main logic.
|
// RunClient with main logic.
|
||||||
func RunClient(ctx context.Context, config *Config, statusRecorder *peer.Status, tunAdapter iface.TunAdapter) error {
|
func RunClient(ctx context.Context, config *Config, statusRecorder *peer.Status, tunAdapter iface.TunAdapter, iFaceDiscover stdnet.IFaceDiscover) error {
|
||||||
backOff := &backoff.ExponentialBackOff{
|
backOff := &backoff.ExponentialBackOff{
|
||||||
InitialInterval: time.Second,
|
InitialInterval: time.Second,
|
||||||
RandomizationFactor: 1,
|
RandomizationFactor: 1,
|
||||||
@ -146,7 +147,7 @@ func RunClient(ctx context.Context, config *Config, statusRecorder *peer.Status,
|
|||||||
|
|
||||||
peerConfig := loginResp.GetPeerConfig()
|
peerConfig := loginResp.GetPeerConfig()
|
||||||
|
|
||||||
engineConfig, err := createEngineConfig(myPrivateKey, config, peerConfig, tunAdapter)
|
engineConfig, err := createEngineConfig(myPrivateKey, config, peerConfig, tunAdapter, iFaceDiscover)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return wrapErr(err)
|
return wrapErr(err)
|
||||||
@ -193,12 +194,13 @@ func RunClient(ctx context.Context, config *Config, statusRecorder *peer.Status,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createEngineConfig converts configuration received from Management Service to EngineConfig
|
// createEngineConfig converts configuration received from Management Service to EngineConfig
|
||||||
func createEngineConfig(key wgtypes.Key, config *Config, peerConfig *mgmProto.PeerConfig, tunAdapter iface.TunAdapter) (*EngineConfig, error) {
|
func createEngineConfig(key wgtypes.Key, config *Config, peerConfig *mgmProto.PeerConfig, tunAdapter iface.TunAdapter, iFaceDiscover stdnet.IFaceDiscover) (*EngineConfig, error) {
|
||||||
|
|
||||||
engineConf := &EngineConfig{
|
engineConf := &EngineConfig{
|
||||||
WgIfaceName: config.WgIface,
|
WgIfaceName: config.WgIface,
|
||||||
WgAddr: peerConfig.Address,
|
WgAddr: peerConfig.Address,
|
||||||
TunAdapter: tunAdapter,
|
TunAdapter: tunAdapter,
|
||||||
|
IFaceDiscover: iFaceDiscover,
|
||||||
IFaceBlackList: config.IFaceBlackList,
|
IFaceBlackList: config.IFaceBlackList,
|
||||||
DisableIPv6Discovery: config.DisableIPv6Discovery,
|
DisableIPv6Discovery: config.DisableIPv6Discovery,
|
||||||
WgPrivateKey: key,
|
WgPrivateKey: key,
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/internal/peer"
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
"github.com/netbirdio/netbird/client/internal/proxy"
|
"github.com/netbirdio/netbird/client/internal/proxy"
|
||||||
"github.com/netbirdio/netbird/client/internal/routemanager"
|
"github.com/netbirdio/netbird/client/internal/routemanager"
|
||||||
|
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||||
nbssh "github.com/netbirdio/netbird/client/ssh"
|
nbssh "github.com/netbirdio/netbird/client/ssh"
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/iface"
|
"github.com/netbirdio/netbird/iface"
|
||||||
@ -49,6 +50,8 @@ type EngineConfig struct {
|
|||||||
// TunAdapter is option. It is necessary for mobile version.
|
// TunAdapter is option. It is necessary for mobile version.
|
||||||
TunAdapter iface.TunAdapter
|
TunAdapter iface.TunAdapter
|
||||||
|
|
||||||
|
IFaceDiscover stdnet.IFaceDiscover
|
||||||
|
|
||||||
// WgAddr is a Wireguard local address (Netbird Network IP)
|
// WgAddr is a Wireguard local address (Netbird Network IP)
|
||||||
WgAddr string
|
WgAddr string
|
||||||
|
|
||||||
@ -186,12 +189,22 @@ func (e *Engine) Start() error {
|
|||||||
networkName = "udp4"
|
networkName = "udp4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transportNet, err := e.newStdNet()
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("failed to create pion's stdnet: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
e.udpMuxConn, err = net.ListenUDP(networkName, &net.UDPAddr{Port: e.config.UDPMuxPort})
|
e.udpMuxConn, err = net.ListenUDP(networkName, &net.UDPAddr{Port: e.config.UDPMuxPort})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed listening on UDP port %d: [%s]", e.config.UDPMuxPort, err.Error())
|
log.Errorf("failed listening on UDP port %d: [%s]", e.config.UDPMuxPort, err.Error())
|
||||||
e.close()
|
e.close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
udpMuxParams := ice.UDPMuxParams{
|
||||||
|
UDPConn: e.udpMuxConn,
|
||||||
|
Net: transportNet,
|
||||||
|
}
|
||||||
|
e.udpMux = ice.NewUDPMuxDefault(udpMuxParams)
|
||||||
|
|
||||||
e.udpMuxConnSrflx, err = net.ListenUDP(networkName, &net.UDPAddr{Port: e.config.UDPMuxSrflxPort})
|
e.udpMuxConnSrflx, err = net.ListenUDP(networkName, &net.UDPAddr{Port: e.config.UDPMuxSrflxPort})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -199,9 +212,7 @@ func (e *Engine) Start() error {
|
|||||||
e.close()
|
e.close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
e.udpMuxSrflx = ice.NewUniversalUDPMuxDefault(ice.UniversalUDPMuxParams{UDPConn: e.udpMuxConnSrflx, Net: transportNet})
|
||||||
e.udpMux = ice.NewUDPMuxDefault(ice.UDPMuxParams{UDPConn: e.udpMuxConn})
|
|
||||||
e.udpMuxSrflx = ice.NewUniversalUDPMuxDefault(ice.UniversalUDPMuxParams{UDPConn: e.udpMuxConnSrflx})
|
|
||||||
|
|
||||||
err = e.wgInterface.Create()
|
err = e.wgInterface.Create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -813,7 +824,7 @@ func (e Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, er
|
|||||||
NATExternalIPs: e.parseNATExternalIPMappings(),
|
NATExternalIPs: e.parseNATExternalIPMappings(),
|
||||||
}
|
}
|
||||||
|
|
||||||
peerConn, err := peer.NewConn(config, e.statusRecorder)
|
peerConn, err := peer.NewConn(config, e.statusRecorder, e.config.TunAdapter, e.config.IFaceDiscover)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
11
client/internal/engine_stdnet.go
Normal file
11
client/internal/engine_stdnet.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
//go:build !android
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pion/transport/v2/stdnet"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *Engine) newStdNet() (*stdnet.Net, error) {
|
||||||
|
return stdnet.NewNet()
|
||||||
|
}
|
7
client/internal/engine_stdnet_android.go
Normal file
7
client/internal/engine_stdnet_android.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import "github.com/netbirdio/netbird/client/internal/stdnet"
|
||||||
|
|
||||||
|
func (e *Engine) newStdNet() (*stdnet.Net, error) {
|
||||||
|
return stdnet.NewNet(e.config.IFaceDiscover)
|
||||||
|
}
|
@ -9,15 +9,15 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pion/ice/v2"
|
"github.com/pion/ice/v2"
|
||||||
"github.com/pion/transport/v2/stdnet"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/internal/proxy"
|
"github.com/netbirdio/netbird/client/internal/proxy"
|
||||||
|
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||||
"github.com/netbirdio/netbird/iface"
|
"github.com/netbirdio/netbird/iface"
|
||||||
"github.com/netbirdio/netbird/version"
|
|
||||||
signal "github.com/netbirdio/netbird/signal/client"
|
signal "github.com/netbirdio/netbird/signal/client"
|
||||||
sProto "github.com/netbirdio/netbird/signal/proto"
|
sProto "github.com/netbirdio/netbird/signal/proto"
|
||||||
|
"github.com/netbirdio/netbird/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConnConfig is a peer Connection configuration
|
// ConnConfig is a peer Connection configuration
|
||||||
@ -93,6 +93,9 @@ type Conn struct {
|
|||||||
proxy proxy.Proxy
|
proxy proxy.Proxy
|
||||||
remoteModeCh chan ModeMessage
|
remoteModeCh chan ModeMessage
|
||||||
meta meta
|
meta meta
|
||||||
|
|
||||||
|
adapter iface.TunAdapter
|
||||||
|
iFaceDiscover stdnet.IFaceDiscover
|
||||||
}
|
}
|
||||||
|
|
||||||
// meta holds meta information about a connection
|
// meta holds meta information about a connection
|
||||||
@ -118,7 +121,7 @@ func (conn *Conn) UpdateConf(conf ConnConfig) {
|
|||||||
|
|
||||||
// NewConn creates a new not opened Conn to the remote peer.
|
// NewConn creates a new not opened Conn to the remote peer.
|
||||||
// To establish a connection run Conn.Open
|
// To establish a connection run Conn.Open
|
||||||
func NewConn(config ConnConfig, statusRecorder *Status) (*Conn, error) {
|
func NewConn(config ConnConfig, statusRecorder *Status, adapter iface.TunAdapter, iFaceDiscover stdnet.IFaceDiscover) (*Conn, error) {
|
||||||
return &Conn{
|
return &Conn{
|
||||||
config: config,
|
config: config,
|
||||||
mu: sync.Mutex{},
|
mu: sync.Mutex{},
|
||||||
@ -128,6 +131,8 @@ func NewConn(config ConnConfig, statusRecorder *Status) (*Conn, error) {
|
|||||||
remoteAnswerCh: make(chan OfferAnswer),
|
remoteAnswerCh: make(chan OfferAnswer),
|
||||||
statusRecorder: statusRecorder,
|
statusRecorder: statusRecorder,
|
||||||
remoteModeCh: make(chan ModeMessage, 1),
|
remoteModeCh: make(chan ModeMessage, 1),
|
||||||
|
adapter: adapter,
|
||||||
|
iFaceDiscover: iFaceDiscover,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +167,9 @@ func (conn *Conn) reCreateAgent() error {
|
|||||||
defer conn.mu.Unlock()
|
defer conn.mu.Unlock()
|
||||||
|
|
||||||
failedTimeout := 6 * time.Second
|
failedTimeout := 6 * time.Second
|
||||||
transportNet, err := stdnet.NewNet()
|
|
||||||
|
var err error
|
||||||
|
transportNet, err := conn.newStdNet()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("failed to create pion's stdnet: %s", err)
|
log.Warnf("failed to create pion's stdnet: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ func TestNewConn_interfaceFilter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestConn_GetKey(t *testing.T) {
|
func TestConn_GetKey(t *testing.T) {
|
||||||
conn, err := NewConn(connConf, nil)
|
conn, err := NewConn(connConf, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ func TestConn_GetKey(t *testing.T) {
|
|||||||
|
|
||||||
func TestConn_OnRemoteOffer(t *testing.T) {
|
func TestConn_OnRemoteOffer(t *testing.T) {
|
||||||
|
|
||||||
conn, err := NewConn(connConf, NewRecorder("https://mgm"))
|
conn, err := NewConn(connConf, NewRecorder("https://mgm"), nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ func TestConn_OnRemoteOffer(t *testing.T) {
|
|||||||
|
|
||||||
func TestConn_OnRemoteAnswer(t *testing.T) {
|
func TestConn_OnRemoteAnswer(t *testing.T) {
|
||||||
|
|
||||||
conn, err := NewConn(connConf, NewRecorder("https://mgm"))
|
conn, err := NewConn(connConf, NewRecorder("https://mgm"), nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -116,7 +116,7 @@ func TestConn_OnRemoteAnswer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
func TestConn_Status(t *testing.T) {
|
func TestConn_Status(t *testing.T) {
|
||||||
|
|
||||||
conn, err := NewConn(connConf, NewRecorder("https://mgm"))
|
conn, err := NewConn(connConf, NewRecorder("https://mgm"), nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -143,7 +143,7 @@ func TestConn_Status(t *testing.T) {
|
|||||||
|
|
||||||
func TestConn_Close(t *testing.T) {
|
func TestConn_Close(t *testing.T) {
|
||||||
|
|
||||||
conn, err := NewConn(connConf, NewRecorder("https://mgm"))
|
conn, err := NewConn(connConf, NewRecorder("https://mgm"), nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -411,7 +411,7 @@ func TestGetProxyWithMessageExchange(t *testing.T) {
|
|||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
g := errgroup.Group{}
|
g := errgroup.Group{}
|
||||||
conn, err := NewConn(connConf, nil)
|
conn, err := NewConn(connConf, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
11
client/internal/peer/stdnet.go
Normal file
11
client/internal/peer/stdnet.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
//go:build !android
|
||||||
|
|
||||||
|
package peer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pion/transport/v2/stdnet"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (conn *Conn) newStdNet() (*stdnet.Net, error) {
|
||||||
|
return stdnet.NewNet()
|
||||||
|
}
|
7
client/internal/peer/stdnet_android.go
Normal file
7
client/internal/peer/stdnet_android.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package peer
|
||||||
|
|
||||||
|
import "github.com/netbirdio/netbird/client/internal/stdnet"
|
||||||
|
|
||||||
|
func (conn *Conn) newStdNet() (*stdnet.Net, error) {
|
||||||
|
return stdnet.NewNet(conn.iFaceDiscover)
|
||||||
|
}
|
8
client/internal/stdnet/iface_discover.go
Normal file
8
client/internal/stdnet/iface_discover.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package stdnet
|
||||||
|
|
||||||
|
// IFaceDiscover provide an option for external services (mobile)
|
||||||
|
// to collect network interface information
|
||||||
|
type IFaceDiscover interface {
|
||||||
|
// IFaces return with the description of the interfaces
|
||||||
|
IFaces() (string, error)
|
||||||
|
}
|
137
client/internal/stdnet/stdnet.go
Normal file
137
client/internal/stdnet/stdnet.go
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
// Package stdnet is an extension of the pion's stdnet.
|
||||||
|
// With it the list of the interface can come from external source.
|
||||||
|
// More info: https://github.com/golang/go/issues/40569
|
||||||
|
package stdnet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pion/transport/v2"
|
||||||
|
"github.com/pion/transport/v2/stdnet"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Net is an implementation of the net.Net interface
|
||||||
|
// based on functions of the standard net package.
|
||||||
|
type Net struct {
|
||||||
|
stdnet.Net
|
||||||
|
interfaces []*transport.Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNet creates a new StdNet instance.
|
||||||
|
func NewNet(iFaceDiscover IFaceDiscover) (*Net, error) {
|
||||||
|
n := &Net{}
|
||||||
|
|
||||||
|
return n, n.UpdateInterfaces(iFaceDiscover)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateInterfaces updates the internal list of network interfaces
|
||||||
|
// and associated addresses.
|
||||||
|
func (n *Net) UpdateInterfaces(iFaceDiscover IFaceDiscover) error {
|
||||||
|
ifacesString, err := iFaceDiscover.IFaces()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
n.interfaces = parseInterfacesString(ifacesString)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interfaces returns a slice of interfaces which are available on the
|
||||||
|
// system
|
||||||
|
func (n *Net) Interfaces() ([]*transport.Interface, error) {
|
||||||
|
return n.interfaces, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceByIndex returns the interface specified by index.
|
||||||
|
//
|
||||||
|
// On Solaris, it returns one of the logical network interfaces
|
||||||
|
// sharing the logical data link; for more precision use
|
||||||
|
// InterfaceByName.
|
||||||
|
func (n *Net) InterfaceByIndex(index int) (*transport.Interface, error) {
|
||||||
|
for _, ifc := range n.interfaces {
|
||||||
|
if ifc.Index == index {
|
||||||
|
return ifc, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("%w: index=%d", transport.ErrInterfaceNotFound, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceByName returns the interface specified by name.
|
||||||
|
func (n *Net) InterfaceByName(name string) (*transport.Interface, error) {
|
||||||
|
for _, ifc := range n.interfaces {
|
||||||
|
if ifc.Name == name {
|
||||||
|
return ifc, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("%w: %s", transport.ErrInterfaceNotFound, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInterfacesString(interfaces string) []*transport.Interface {
|
||||||
|
ifs := []*transport.Interface{}
|
||||||
|
|
||||||
|
for _, iface := range strings.Split(interfaces, "\n") {
|
||||||
|
if strings.TrimSpace(iface) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := strings.Split(iface, "|")
|
||||||
|
if len(fields) != 2 {
|
||||||
|
log.Warnf("parseInterfacesString: unable to split %q", iface)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var name string
|
||||||
|
var index, mtu int
|
||||||
|
var up, broadcast, loopback, pointToPoint, multicast bool
|
||||||
|
_, err := fmt.Sscanf(fields[0], "%s %d %d %t %t %t %t %t",
|
||||||
|
&name, &index, &mtu, &up, &broadcast, &loopback, &pointToPoint, &multicast)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("parseInterfacesString: unable to parse %q: %v", iface, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newIf := net.Interface{
|
||||||
|
Name: name,
|
||||||
|
Index: index,
|
||||||
|
MTU: mtu,
|
||||||
|
}
|
||||||
|
if up {
|
||||||
|
newIf.Flags |= net.FlagUp
|
||||||
|
}
|
||||||
|
if broadcast {
|
||||||
|
newIf.Flags |= net.FlagBroadcast
|
||||||
|
}
|
||||||
|
if loopback {
|
||||||
|
newIf.Flags |= net.FlagLoopback
|
||||||
|
}
|
||||||
|
if pointToPoint {
|
||||||
|
newIf.Flags |= net.FlagPointToPoint
|
||||||
|
}
|
||||||
|
if multicast {
|
||||||
|
newIf.Flags |= net.FlagMulticast
|
||||||
|
}
|
||||||
|
|
||||||
|
ifc := transport.NewInterface(newIf)
|
||||||
|
|
||||||
|
addrs := strings.Trim(fields[1], " \n")
|
||||||
|
foundAddress := false
|
||||||
|
for _, addr := range strings.Split(addrs, " ") {
|
||||||
|
ip, ipNet, err := net.ParseCIDR(addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("%s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ipNet.IP = ip
|
||||||
|
ifc.AddAddress(ipNet)
|
||||||
|
foundAddress = true
|
||||||
|
}
|
||||||
|
if foundAddress {
|
||||||
|
ifs = append(ifs, ifc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ifs
|
||||||
|
}
|
52
client/internal/stdnet/stdnet_test.go
Normal file
52
client/internal/stdnet/stdnet_test.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package stdnet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_parseInterfacesString(t *testing.T) {
|
||||||
|
testData := []struct {
|
||||||
|
name string
|
||||||
|
index int
|
||||||
|
mtu int
|
||||||
|
up bool
|
||||||
|
broadcast bool
|
||||||
|
loopBack bool
|
||||||
|
pointToPoint bool
|
||||||
|
multicast bool
|
||||||
|
addr string
|
||||||
|
}{
|
||||||
|
{"wlan0", 30, 1500, true, true, false, false, true, "10.1.10.131/24"},
|
||||||
|
{"rmnet0", 30, 1500, true, true, false, false, true, "192.168.0.56/24"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var exampleString string
|
||||||
|
for _, d := range testData {
|
||||||
|
exampleString = fmt.Sprintf("%s\n%s %d %d %t %t %t %t %t | %s", exampleString,
|
||||||
|
d.name,
|
||||||
|
d.index,
|
||||||
|
d.mtu,
|
||||||
|
d.up,
|
||||||
|
d.broadcast,
|
||||||
|
d.loopBack,
|
||||||
|
d.pointToPoint,
|
||||||
|
d.multicast,
|
||||||
|
d.addr)
|
||||||
|
}
|
||||||
|
nets := parseInterfacesString(exampleString)
|
||||||
|
if len(nets) == 0 {
|
||||||
|
t.Fatalf("failed to parse interfaces")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, net := range nets {
|
||||||
|
if net.MTU != testData[i].mtu {
|
||||||
|
t.Errorf("invalid mtu: %d, expected: %d", net.MTU, testData[0].mtu)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if net.Interface.Name != testData[i].name {
|
||||||
|
t.Errorf("invalid interface name: %s, expected: %s", net.Interface.Name, testData[i].name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -102,7 +102,7 @@ func (s *Server) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if err := internal.RunClient(ctx, config, s.statusRecorder, nil); err != nil {
|
if err := internal.RunClient(ctx, config, s.statusRecorder, nil, nil); err != nil {
|
||||||
log.Errorf("init connections: %v", err)
|
log.Errorf("init connections: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -394,7 +394,7 @@ func (s *Server) Up(callerCtx context.Context, _ *proto.UpRequest) (*proto.UpRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if err := internal.RunClient(ctx, s.config, s.statusRecorder, nil); err != nil {
|
if err := internal.RunClient(ctx, s.config, s.statusRecorder, nil, nil); err != nil {
|
||||||
log.Errorf("run client connection: %v", err)
|
log.Errorf("run client connection: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user