Fix interface monitor for android
This commit is contained in:
@@ -29,3 +29,19 @@ func (i *iterator[T]) Next() T {
|
||||
func (i *iterator[T]) HasNext() bool {
|
||||
return len(i.values) > 0
|
||||
}
|
||||
|
||||
type abstractIterator[T any] interface {
|
||||
Next() T
|
||||
HasNext() bool
|
||||
}
|
||||
|
||||
func iteratorToArray[T any](iterator abstractIterator[T]) []T {
|
||||
if iterator == nil {
|
||||
return nil
|
||||
}
|
||||
var values []T
|
||||
for iterator.HasNext() {
|
||||
values = append(values, iterator.Next())
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
183
experimental/libbox/monitor.go
Normal file
183
experimental/libbox/monitor.go
Normal file
@@ -0,0 +1,183 @@
|
||||
package libbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
)
|
||||
|
||||
var (
|
||||
_ tun.DefaultInterfaceMonitor = (*platformDefaultInterfaceMonitor)(nil)
|
||||
_ InterfaceUpdateListener = (*platformDefaultInterfaceMonitor)(nil)
|
||||
)
|
||||
|
||||
type platformDefaultInterfaceMonitor struct {
|
||||
*platformInterfaceWrapper
|
||||
errorHandler E.Handler
|
||||
networkAddresses []networkAddress
|
||||
defaultInterfaceName string
|
||||
defaultInterfaceIndex int
|
||||
element *list.Element[tun.NetworkUpdateCallback]
|
||||
access sync.Mutex
|
||||
callbacks list.List[tun.DefaultInterfaceUpdateCallback]
|
||||
}
|
||||
|
||||
type networkAddress struct {
|
||||
interfaceName string
|
||||
interfaceIndex int
|
||||
addresses []netip.Prefix
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) Start() error {
|
||||
return m.iif.StartDefaultInterfaceMonitor(m)
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) Close() error {
|
||||
return m.iif.CloseDefaultInterfaceMonitor(m)
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) DefaultInterfaceName(destination netip.Addr) string {
|
||||
for _, address := range m.networkAddresses {
|
||||
for _, prefix := range address.addresses {
|
||||
if prefix.Contains(destination) {
|
||||
return address.interfaceName
|
||||
}
|
||||
}
|
||||
}
|
||||
return m.defaultInterfaceName
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) DefaultInterfaceIndex(destination netip.Addr) int {
|
||||
for _, address := range m.networkAddresses {
|
||||
for _, prefix := range address.addresses {
|
||||
if prefix.Contains(destination) {
|
||||
return address.interfaceIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
return m.defaultInterfaceIndex
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) OverrideAndroidVPN() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) AndroidVPNEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) RegisterCallback(callback tun.DefaultInterfaceUpdateCallback) *list.Element[tun.DefaultInterfaceUpdateCallback] {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
return m.callbacks.PushBack(callback)
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
m.callbacks.Remove(element)
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32) {
|
||||
var err error
|
||||
if m.iif.UsePlatformInterfaceGetter() {
|
||||
err = m.updateInterfacesPlatform()
|
||||
} else {
|
||||
err = m.updateInterfaces()
|
||||
}
|
||||
if err == nil {
|
||||
err = m.router.UpdateInterfaces()
|
||||
}
|
||||
if err != nil {
|
||||
m.errorHandler.NewError(context.Background(), E.Cause(err, "update interfaces"))
|
||||
}
|
||||
interfaceIndex := int(interfaceIndex32)
|
||||
if interfaceName == "" {
|
||||
for _, netIf := range m.networkAddresses {
|
||||
if netIf.interfaceIndex == interfaceIndex {
|
||||
interfaceName = netIf.interfaceName
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if interfaceIndex == -1 {
|
||||
for _, netIf := range m.networkAddresses {
|
||||
if netIf.interfaceName == interfaceName {
|
||||
interfaceIndex = netIf.interfaceIndex
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if interfaceName == "" {
|
||||
m.errorHandler.NewError(context.Background(), E.New("invalid interface name for ", interfaceIndex))
|
||||
return
|
||||
} else if interfaceIndex == -1 {
|
||||
m.errorHandler.NewError(context.Background(), E.New("invalid interface index for ", interfaceName))
|
||||
return
|
||||
}
|
||||
if m.defaultInterfaceName == interfaceName && m.defaultInterfaceIndex == interfaceIndex {
|
||||
return
|
||||
}
|
||||
m.defaultInterfaceName = interfaceName
|
||||
m.defaultInterfaceIndex = interfaceIndex
|
||||
m.access.Lock()
|
||||
callbacks := m.callbacks.Array()
|
||||
m.access.Unlock()
|
||||
for _, callback := range callbacks {
|
||||
err = callback(tun.EventInterfaceUpdate)
|
||||
if err != nil {
|
||||
m.errorHandler.NewError(context.Background(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) updateInterfaces() error {
|
||||
interfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var addresses []networkAddress
|
||||
for _, iif := range interfaces {
|
||||
var netAddresses []net.Addr
|
||||
netAddresses, err = iif.Addrs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var address networkAddress
|
||||
address.interfaceName = iif.Name
|
||||
address.interfaceIndex = iif.Index
|
||||
address.addresses = common.Map(common.FilterIsInstance(netAddresses, func(it net.Addr) (*net.IPNet, bool) {
|
||||
value, loaded := it.(*net.IPNet)
|
||||
return value, loaded
|
||||
}), func(it *net.IPNet) netip.Prefix {
|
||||
bits, _ := it.Mask.Size()
|
||||
return netip.PrefixFrom(M.AddrFromIP(it.IP), bits)
|
||||
})
|
||||
addresses = append(addresses, address)
|
||||
}
|
||||
m.networkAddresses = addresses
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) updateInterfacesPlatform() error {
|
||||
interfaces, err := m.Interfaces()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var addresses []networkAddress
|
||||
for _, iif := range interfaces {
|
||||
var address networkAddress
|
||||
address.interfaceName = iif.Name
|
||||
address.interfaceIndex = iif.Index
|
||||
// address.addresses = common.Map(iif.Addresses, netip.MustParsePrefix)
|
||||
addresses = append(addresses, address)
|
||||
}
|
||||
m.networkAddresses = addresses
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package libbox
|
||||
|
||||
import "github.com/sagernet/sing-box/option"
|
||||
import (
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
type PlatformInterface interface {
|
||||
AutoDetectInterfaceControl(fd int32) error
|
||||
@@ -10,6 +12,11 @@ type PlatformInterface interface {
|
||||
FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error)
|
||||
PackageNameByUid(uid int32) (string, error)
|
||||
UIDByPackageName(packageName string) (int32, error)
|
||||
UsePlatformDefaultInterfaceMonitor() bool
|
||||
StartDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
|
||||
CloseDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
|
||||
UsePlatformInterfaceGetter() bool
|
||||
GetInterfaces() (NetworkInterfaceIterator, error)
|
||||
}
|
||||
|
||||
type TunInterface interface {
|
||||
@@ -17,8 +24,19 @@ type TunInterface interface {
|
||||
Close() error
|
||||
}
|
||||
|
||||
type OnDemandRuleIterator interface {
|
||||
Next() OnDemandRule
|
||||
type InterfaceUpdateListener interface {
|
||||
UpdateDefaultInterface(interfaceName string, interfaceIndex int32)
|
||||
}
|
||||
|
||||
type NetworkInterface struct {
|
||||
Index int32
|
||||
MTU int32
|
||||
Name string
|
||||
Addresses StringIterator
|
||||
}
|
||||
|
||||
type NetworkInterfaceIterator interface {
|
||||
Next() *NetworkInterface
|
||||
HasNext() bool
|
||||
}
|
||||
|
||||
@@ -31,6 +49,11 @@ type OnDemandRule interface {
|
||||
ProbeURL() string
|
||||
}
|
||||
|
||||
type OnDemandRuleIterator interface {
|
||||
Next() OnDemandRule
|
||||
HasNext() bool
|
||||
}
|
||||
|
||||
type onDemandRule struct {
|
||||
option.OnDemandRule
|
||||
}
|
||||
|
||||
@@ -1,17 +1,33 @@
|
||||
package platform
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/netip"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/process"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Initialize(ctx context.Context, router adapter.Router) error
|
||||
AutoDetectInterfaceControl() control.Func
|
||||
OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error)
|
||||
UsePlatformDefaultInterfaceMonitor() bool
|
||||
CreateDefaultInterfaceMonitor(errorHandler E.Handler) tun.DefaultInterfaceMonitor
|
||||
UsePlatformInterfaceGetter() bool
|
||||
Interfaces() ([]NetworkInterface, error)
|
||||
process.Searcher
|
||||
io.Writer
|
||||
}
|
||||
|
||||
type NetworkInterface struct {
|
||||
Index int
|
||||
MTU int
|
||||
Name string
|
||||
Addresses []netip.Prefix
|
||||
}
|
||||
|
||||
@@ -6,11 +6,13 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/sagernet/sing-box"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/process"
|
||||
"github.com/sagernet/sing-box/experimental/libbox/internal/procfs"
|
||||
"github.com/sagernet/sing-box/experimental/libbox/platform"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
@@ -31,7 +33,7 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
|
||||
instance, err := box.New(box.Options{
|
||||
Context: ctx,
|
||||
Options: options,
|
||||
PlatformInterface: &platformInterfaceWrapper{platformInterface, platformInterface.UseProcFS()},
|
||||
PlatformInterface: &platformInterfaceWrapper{iif: platformInterface, useProcFS: platformInterface.UseProcFS()},
|
||||
})
|
||||
if err != nil {
|
||||
cancel()
|
||||
@@ -58,6 +60,12 @@ var _ platform.Interface = (*platformInterfaceWrapper)(nil)
|
||||
type platformInterfaceWrapper struct {
|
||||
iif PlatformInterface
|
||||
useProcFS bool
|
||||
router adapter.Router
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error {
|
||||
w.router = router
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
|
||||
@@ -122,3 +130,36 @@ func (w *platformInterfaceWrapper) FindProcessInfo(ctx context.Context, network
|
||||
packageName, _ := w.iif.PackageNameByUid(uid)
|
||||
return &process.Info{UserId: uid, PackageName: packageName}, nil
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) UsePlatformDefaultInterfaceMonitor() bool {
|
||||
return w.iif.UsePlatformDefaultInterfaceMonitor()
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) CreateDefaultInterfaceMonitor(errorHandler E.Handler) tun.DefaultInterfaceMonitor {
|
||||
return &platformDefaultInterfaceMonitor{
|
||||
platformInterfaceWrapper: w,
|
||||
errorHandler: errorHandler,
|
||||
defaultInterfaceIndex: -1,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) UsePlatformInterfaceGetter() bool {
|
||||
return w.iif.UsePlatformInterfaceGetter()
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) Interfaces() ([]platform.NetworkInterface, error) {
|
||||
interfaceIterator, err := w.iif.GetInterfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var interfaces []platform.NetworkInterface
|
||||
for _, netInterface := range iteratorToArray[*NetworkInterface](interfaceIterator) {
|
||||
interfaces = append(interfaces, platform.NetworkInterface{
|
||||
Index: int(netInterface.Index),
|
||||
MTU: int(netInterface.MTU),
|
||||
Name: netInterface.Name,
|
||||
Addresses: common.Map(iteratorToArray[string](netInterface.Addresses), netip.MustParsePrefix),
|
||||
})
|
||||
}
|
||||
return interfaces, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user