Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a
github.com/sagernet/nftables v0.3.0-beta.4
github.com/sagernet/sing v0.5.0-alpha.11.0.20240625144910-6bd878184516
github.com/sagernet/sing v0.5.0-beta.2.0.20240922141512-c63546470b53
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
golang.org/x/net v0.26.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
github.com/sagernet/sing v0.5.0-alpha.11.0.20240625144910-6bd878184516 h1:C5NYqSEQC2CcILDFhT31iZe5Kp5hFNEtdS9mnNWyW5c=
github.com/sagernet/sing v0.5.0-alpha.11.0.20240625144910-6bd878184516/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.5.0-beta.2.0.20240922141512-c63546470b53 h1:skd2mM7USFsPTmyaPnnJJVrGWIMGv8PdzVyoKQPdqpU=
github.com/sagernet/sing v0.5.0-beta.2.0.20240922141512-c63546470b53/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
Expand Down
2 changes: 2 additions & 0 deletions monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tun
import (
"net/netip"

"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/x/list"
)
Expand Down Expand Up @@ -40,6 +41,7 @@ type DefaultInterfaceMonitor interface {
}

type DefaultInterfaceMonitorOptions struct {
InterfaceFinder control.InterfaceFinder
OverrideAndroidVPN bool
UnderNetworkExtension bool
}
2 changes: 1 addition & 1 deletion monitor_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func (m *defaultInterfaceMonitor) checkUpdate() error {
defaultInterface *net.Interface
err error
)
if m.options.UnderNetworkExtension {
if m.underNetworkExtension {
defaultInterface, err = getDefaultInterfaceBySocket()
if err != nil {
return err
Expand Down
69 changes: 18 additions & 51 deletions monitor_shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ package tun

import (
"errors"
"net"
"net/netip"
"sync"
"time"

"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/control"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/x/list"
)

Expand All @@ -37,8 +35,9 @@ func (m *networkUpdateMonitor) emit() {
}

type defaultInterfaceMonitor struct {
options DefaultInterfaceMonitorOptions
networkAddresses []networkAddress
interfaceFinder control.InterfaceFinder
overrideAndroidVPN bool
underNetworkExtension bool
defaultInterfaceName string
defaultInterfaceIndex int
androidVPNEnabled bool
Expand All @@ -51,15 +50,11 @@ type defaultInterfaceMonitor struct {
logger logger.Logger
}

type networkAddress struct {
interfaceName string
interfaceIndex int
addresses []netip.Prefix
}

func NewDefaultInterfaceMonitor(networkMonitor NetworkUpdateMonitor, logger logger.Logger, options DefaultInterfaceMonitorOptions) (DefaultInterfaceMonitor, error) {
return &defaultInterfaceMonitor{
options: options,
interfaceFinder: options.InterfaceFinder,
overrideAndroidVPN: options.OverrideAndroidVPN,
underNetworkExtension: options.UnderNetworkExtension,
networkMonitor: networkMonitor,
defaultInterfaceIndex: -1,
logger: logger,
Expand All @@ -81,7 +76,7 @@ func (m *defaultInterfaceMonitor) delayCheckUpdate() {
}

func (m *defaultInterfaceMonitor) postCheckUpdate() {
err := m.updateInterfaces()
err := m.interfaceFinder.Update()
if err != nil {
m.logger.Error("update interfaces: ", err)
}
Expand All @@ -100,34 +95,6 @@ func (m *defaultInterfaceMonitor) postCheckUpdate() {
}
}

func (m *defaultInterfaceMonitor) 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 *defaultInterfaceMonitor) Close() error {
if m.element != nil {
m.networkMonitor.UnregisterCallback(m.element)
Expand All @@ -136,40 +103,40 @@ func (m *defaultInterfaceMonitor) Close() error {
}

func (m *defaultInterfaceMonitor) DefaultInterfaceName(destination netip.Addr) string {
for _, address := range m.networkAddresses {
for _, prefix := range address.addresses {
for _, address := range m.interfaceFinder.Interfaces() {
for _, prefix := range address.Addresses {
if prefix.Contains(destination) {
return address.interfaceName
return address.Name
}
}
}
return m.defaultInterfaceName
}

func (m *defaultInterfaceMonitor) DefaultInterfaceIndex(destination netip.Addr) int {
for _, address := range m.networkAddresses {
for _, prefix := range address.addresses {
for _, address := range m.interfaceFinder.Interfaces() {
for _, prefix := range address.Addresses {
if prefix.Contains(destination) {
return address.interfaceIndex
return address.Index
}
}
}
return m.defaultInterfaceIndex
}

func (m *defaultInterfaceMonitor) DefaultInterface(destination netip.Addr) (string, int) {
for _, address := range m.networkAddresses {
for _, prefix := range address.addresses {
for _, address := range m.interfaceFinder.Interfaces() {
for _, prefix := range address.Addresses {
if prefix.Contains(destination) {
return address.interfaceName, address.interfaceIndex
return address.Name, address.Index
}
}
}
return m.defaultInterfaceName, m.defaultInterfaceIndex
}

func (m *defaultInterfaceMonitor) OverrideAndroidVPN() bool {
return m.options.OverrideAndroidVPN
return m.overrideAndroidVPN
}

func (m *defaultInterfaceMonitor) AndroidVPNEnabled() bool {
Expand Down
21 changes: 8 additions & 13 deletions tun_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net"
"net/netip"
"os"
"runtime"
"sync"
"time"
"unsafe"
Expand Down Expand Up @@ -350,7 +351,7 @@ retry:
if t.close.Load() == 1 {
return nil, nil, os.ErrClosed
}
start := nanotime()
start := time.Now().UnixNano()
shouldSpin := t.rate.current.Load() >= spinloopRateThreshold && uint64(start-t.rate.nextStartTime.Load()) <= rateMeasurementGranularity*2
for {
if t.close.Load() == 1 {
Expand All @@ -363,11 +364,11 @@ retry:
t.rate.update(uint64(packetSize))
return packet, func() { t.session.ReleaseReceivePacket(packet) }, nil
case windows.ERROR_NO_MORE_ITEMS:
if !shouldSpin || uint64(nanotime()-start) >= spinloopDuration {
if !shouldSpin || uint64(time.Now().UnixNano()-start) >= spinloopDuration {
windows.WaitForSingleObject(t.readWait, windows.INFINITE)
goto retry
}
procyield(1)
runtime.Gosched()
continue
case windows.ERROR_HANDLE_EOF:
return nil, nil, os.ErrClosed
Expand All @@ -385,7 +386,7 @@ retry:
if t.close.Load() == 1 {
return os.ErrClosed
}
start := nanotime()
start := time.Now().UnixNano()
shouldSpin := t.rate.current.Load() >= spinloopRateThreshold && uint64(start-t.rate.nextStartTime.Load()) <= rateMeasurementGranularity*2
for {
if t.close.Load() == 1 {
Expand All @@ -400,11 +401,11 @@ retry:
t.rate.update(uint64(packetSize))
return nil
case windows.ERROR_NO_MORE_ITEMS:
if !shouldSpin || uint64(nanotime()-start) >= spinloopDuration {
if !shouldSpin || uint64(time.Now().UnixNano()-start) >= spinloopDuration {
windows.WaitForSingleObject(t.readWait, windows.INFINITE)
goto retry
}
procyield(1)
runtime.Gosched()
continue
case windows.ERROR_HANDLE_EOF:
return os.ErrClosed
Expand Down Expand Up @@ -497,12 +498,6 @@ func generateGUIDByDeviceName(name string) *windows.GUID {
return (*windows.GUID)(unsafe.Pointer(&sum[0]))
}

//go:linkname procyield runtime.procyield
func procyield(cycles uint32)

//go:linkname nanotime runtime.nanotime
func nanotime() int64

type rateJuggler struct {
current atomic.Uint64
nextByteCount atomic.Uint64
Expand All @@ -511,7 +506,7 @@ type rateJuggler struct {
}

func (rate *rateJuggler) update(packetLen uint64) {
now := nanotime()
now := time.Now().UnixNano()
total := rate.nextByteCount.Add(packetLen)
period := uint64(now - rate.nextStartTime.Load())
if period >= rateMeasurementGranularity {
Expand Down