Skip to content

Commit

Permalink
Merge branch 'dev' of https://github.com/SagerNet/sing-tun into meta
Browse files Browse the repository at this point in the history
  • Loading branch information
wwqgtxx committed Apr 19, 2023
2 parents 2b6d71c + 510a181 commit d70abf4
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 49 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ require (
github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97
github.com/sagernet/sing v0.2.1
github.com/sagernet/sing v0.2.4-0.20230419150837-2b3a62786474
golang.org/x/net v0.8.0
golang.org/x/sys v0.6.0
golang.org/x/sys v0.7.0
)

require (
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.2.1 h1:r0STYeyfKBBtoAHsBtW1dQonxG+3Qidde7/1VAMhdn8=
github.com/sagernet/sing v0.2.1/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw=
github.com/sagernet/sing v0.2.4-0.20230419150837-2b3a62786474 h1:eSYMHrZvHo9hTKSAPTFaGsiafUss7FPhTDanXsNrfwE=
github.com/sagernet/sing v0.2.4-0.20230419150837-2b3a62786474/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
19 changes: 14 additions & 5 deletions gvisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"syscall"
"time"

"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/canceler"
E "github.com/sagernet/sing/common/exceptions"
Expand Down Expand Up @@ -42,6 +43,7 @@ type GVisor struct {
stack *stack.Stack
endpoint stack.LinkEndpoint
routeMapping *RouteMapping
udpForwarder *UDPForwarder
}

type GVisorTun interface {
Expand All @@ -57,7 +59,7 @@ func NewGVisor(
return nil, E.New("gVisor stack is unsupported on current platform")
}

return &GVisor{
gStack := &GVisor{
ctx: options.Context,
tun: gTun,
tunMtu: options.MTU,
Expand All @@ -66,8 +68,11 @@ func NewGVisor(
router: options.Router,
handler: options.Handler,
logger: options.Logger,
routeMapping: NewRouteMapping(options.UDPTimeout),
}, nil
}
if gStack.router != nil {
gStack.routeMapping = NewRouteMapping(options.UDPTimeout)
}
return gStack, nil
}

func (t *GVisor) Start() error {
Expand Down Expand Up @@ -253,7 +258,8 @@ func (t *GVisor) Start() error {
return udpForwarder.HandlePacket(id, buffer)
})
} else {
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, NewUDPForwarder(t.ctx, ipStack, t.handler, t.udpTimeout).HandlePacket)
t.udpForwarder = NewUDPForwarder(t.ctx, ipStack, t.handler, t.udpTimeout)
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, t.udpForwarder.HandlePacket)
}

t.stack = ipStack
Expand All @@ -267,5 +273,8 @@ func (t *GVisor) Close() error {
for _, endpoint := range t.stack.CleanupEndpoints() {
endpoint.Abort()
}
return nil
return common.Close(
common.PtrOrNil(t.routeMapping),
common.PtrOrNil(t.udpForwarder),
)
}
5 changes: 4 additions & 1 deletion lwip.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ func (l *LWIP) Close() error {
lwip.RegisterOutputFn(func(bytes []byte) (int, error) {
return 0, os.ErrClosed
})
return l.stack.Close()
return common.Close(
l.stack,
common.PtrOrNil(l.udpNat),
)
}

func (l *LWIP) Handle(conn net.Conn) error {
Expand Down
117 changes: 99 additions & 18 deletions monitor_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import (
"net"
"net/netip"
"os"
"runtime"
"strings"
"sync"
"syscall"
"time"

"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
Expand Down Expand Up @@ -85,32 +84,114 @@ func (m *defaultInterfaceMonitor) checkUpdate() error {
if err != nil {
return err
}
var defaultInterface *net.Interface
for _, rawRouteMessage := range routeMessages {
routeMessage := rawRouteMessage.(*route.RouteMessage)
if len(routeMessage.Addrs) <= unix.RTAX_NETMASK {
continue
}
destination, isIPv4Destination := routeMessage.Addrs[unix.RTAX_DST].(*route.Inet4Addr)
if !isIPv4Destination {
continue
}
if destination.IP != netip.IPv4Unspecified().As4() {
continue
}
mask, isIPv4Mask := routeMessage.Addrs[unix.RTAX_NETMASK].(*route.Inet4Addr)
if !isIPv4Mask {
continue
}
ones, _ := net.IPMask(mask.IP[:]).Size()
if ones != 0 {
continue
}
routeInterface, err := net.InterfaceByIndex(routeMessage.Index)
if err != nil {
return err
}
if runtime.GOOS == "ios" && strings.HasPrefix(routeInterface.Name, "utun") {
if routeMessage.Flags&unix.RTF_UP == 0 {
continue
}
if routeMessage.Flags&unix.RTF_GATEWAY == 0 {
continue
}
if routeMessage.Flags&unix.RTF_IFSCOPE != 0 {
continue
}
if common.Any(common.FilterIsInstance(routeMessage.Addrs, func(it route.Addr) (*route.Inet4Addr, bool) {
addr, loaded := it.(*route.Inet4Addr)
return addr, loaded
}), func(addr *route.Inet4Addr) bool {
return addr.IP == netip.IPv4Unspecified().As4()
}) {
oldInterface := m.defaultInterfaceName
oldIndex := m.defaultInterfaceIndex
defaultInterface = routeInterface
break
}
if defaultInterface == nil {
defaultInterface, err = getDefaultInterfaceBySocket()
if err != nil {
return err
}
}
oldInterface := m.defaultInterfaceName
oldIndex := m.defaultInterfaceIndex
m.defaultInterfaceIndex = defaultInterface.Index
m.defaultInterfaceName = defaultInterface.Name
if oldInterface == m.defaultInterfaceName && oldIndex == m.defaultInterfaceIndex {
return nil
}
m.emit(EventInterfaceUpdate)
return nil
}

m.defaultInterfaceIndex = routeMessage.Index
m.defaultInterfaceName = routeInterface.Name
if oldInterface == m.defaultInterfaceName && oldIndex == m.defaultInterfaceIndex {
return nil
func getDefaultInterfaceBySocket() (*net.Interface, error) {
socketFd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0)
if err != nil {
return nil, E.Cause(err, "create file descriptor")
}
defer unix.Close(socketFd)
go unix.Connect(socketFd, &unix.SockaddrInet4{
Addr: [4]byte{10, 255, 255, 255},
Port: 80,
})
result := make(chan netip.Addr, 1)
go func() {
for {
sockname, sockErr := unix.Getsockname(socketFd)
if sockErr != nil {
break
}
sockaddr, isInet4Sockaddr := sockname.(*unix.SockaddrInet4)
if !isInet4Sockaddr {
break
}
addr := netip.AddrFrom4(sockaddr.Addr)
if addr.IsUnspecified() {
time.Sleep(time.Millisecond)
continue
}
result <- addr
break
}
}()
var selectedAddr netip.Addr
select {
case selectedAddr = <-result:
case <-time.After(time.Second):
return nil, os.ErrDeadlineExceeded
}
interfaces, err := net.Interfaces()
if err != nil {
return nil, E.Cause(err, "net.Interfaces")
}
for _, netInterface := range interfaces {
interfaceAddrs, err := netInterface.Addrs()
if err != nil {
return nil, E.Cause(err, "net.Interfaces.Addrs")
}
for _, interfaceAddr := range interfaceAddrs {
ipNet, isIPNet := interfaceAddr.(*net.IPNet)
if !isIPNet {
continue
}
if ipNet.Contains(selectedAddr.AsSlice()) {
return &netInterface, nil
}
m.emit(EventInterfaceUpdate)
return nil
}
}
return ErrNoRoute
return nil, E.New("no interface found for address ", selectedAddr)
}
12 changes: 12 additions & 0 deletions route_mapping.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
package tun

import (
"context"
"net"

"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/cache"
)

type RouteMapping struct {
status *cache.LruCache[RouteSession, RouteAction]
cancel common.ContextCancelCauseFunc
}

func NewRouteMapping(maxAge int64) *RouteMapping {
ctx, cancel := common.ContextWithCancelCause(context.Background())
return &RouteMapping{
status: cache.New(
cache.WithContext[RouteSession, RouteAction](ctx),
cache.WithAge[RouteSession, RouteAction](maxAge),
cache.WithUpdateAgeOnGet[RouteSession, RouteAction](),
cache.WithEvict[RouteSession, RouteAction](func(key RouteSession, conn RouteAction) {
common.Close(conn)
}),
),
cancel: cancel,
}
}

Expand All @@ -30,3 +37,8 @@ func (m *RouteMapping) Lookup(session RouteSession, constructor func() RouteActi
}
return action
}

func (m *RouteMapping) Close() error {
m.cancel(net.ErrClosed)
return nil
}
17 changes: 11 additions & 6 deletions system.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ func NewSystem(options StackOptions) (Stack, error) {
inet4Prefixes: options.Inet4Address,
inet6Prefixes: options.Inet6Address,
underPlatform: options.UnderPlatform,
routeMapping: NewRouteMapping(options.UDPTimeout),
}
if stack.router != nil {
stack.routeMapping = NewRouteMapping(options.UDPTimeout)
}
if len(options.Inet4Address) > 0 {
if options.Inet4Address[0].Bits() == 32 {
Expand All @@ -89,6 +91,8 @@ func (s *System) Close() error {
return common.Close(
s.tcpListener,
s.tcpListener6,
s.udpNat,
common.PtrOrNil(s.routeMapping),
)
}

Expand All @@ -115,7 +119,7 @@ func (s *System) Start() error {
s.tcpPort6 = M.SocksaddrFromNet(tcpListener.Addr()).Port
go s.acceptLoop(tcpListener)
}
s.tcpNat = NewNat()
s.tcpNat = NewNat(s.ctx, time.Second*time.Duration(s.udpTimeout))
s.udpNat = udpnat.New[netip.AddrPort](s.udpTimeout, s.handler)
go s.tunLoop()
return nil
Expand Down Expand Up @@ -208,13 +212,14 @@ func (s *System) acceptLoop(listener net.Listener) {
}
}
go func() {
s.handler.NewConnection(s.ctx, conn, M.Metadata{
_ = s.handler.NewConnection(s.ctx, conn, M.Metadata{
Source: M.SocksaddrFromNetIP(session.Source),
Destination: destination,
})
conn.Close()
time.Sleep(time.Second)
s.tcpNat.Revoke(connPort, session)
if tcpConn, isTCPConn := conn.(*net.TCPConn); isTCPConn {
_ = tcpConn.SetLinger(0)
}
_ = conn.Close()
}()
}
}
Expand Down
Loading

0 comments on commit d70abf4

Please sign in to comment.