mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 08:16:39 +00: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:
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user