Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6628e7d1b1 | ||
|
|
775acdc3b7 | ||
|
|
3fe0cd13db | ||
|
|
31f5c13494 | ||
|
|
52c15164b5 | ||
|
|
647e962311 | ||
|
|
d97b0f06d6 | ||
|
|
5400abd7f7 | ||
|
|
e71911f94d | ||
|
|
3a6fedf64a | ||
|
|
42a84746a9 | ||
|
|
7f3af59109 | ||
|
|
8ccd51404e | ||
|
|
7bd004f141 | ||
|
|
d44e0c68d4 | ||
|
|
bc23daa800 | ||
|
|
e6c219a61e | ||
|
|
ddc824fb9c | ||
|
|
e229d7041e |
@@ -69,6 +69,7 @@ func (r *autoRedirect) Start() error {
|
||||
r.androidSu = true
|
||||
for _, suPath := range []string{
|
||||
"su",
|
||||
"/product/bin/su",
|
||||
"/system/bin/su",
|
||||
} {
|
||||
r.suPath, err = exec.LookPath(suPath)
|
||||
|
||||
@@ -4,6 +4,7 @@ package tun
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/nftables"
|
||||
"github.com/sagernet/nftables/binaryutil"
|
||||
@@ -182,6 +183,25 @@ func (r *autoRedirect) setupNFTables() error {
|
||||
},
|
||||
},
|
||||
})
|
||||
nft.AddRule(&nftables.Rule{
|
||||
Table: table,
|
||||
Chain: chainPreRoutingUDP,
|
||||
Exprs: []expr.Any{
|
||||
&expr.Meta{
|
||||
Key: expr.MetaKeyIIFNAME,
|
||||
Register: 1,
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: nftablesIfname(r.tunOptions.Name),
|
||||
},
|
||||
&expr.Counter{},
|
||||
&expr.Verdict{
|
||||
Kind: expr.VerdictReturn,
|
||||
},
|
||||
},
|
||||
})
|
||||
nft.AddRule(&nftables.Rule{
|
||||
Table: table,
|
||||
Chain: chainPreRoutingUDP,
|
||||
@@ -269,6 +289,10 @@ func (r *autoRedirect) setupNFTables() error {
|
||||
|
||||
// TODO; test is this works
|
||||
func (r *autoRedirect) nftablesUpdateLocalAddressSet() error {
|
||||
err := r.interfaceFinder.Update()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newLocalAddresses := common.FlatMap(r.interfaceFinder.Interfaces(), func(it control.Interface) []netip.Prefix {
|
||||
return common.Filter(it.Addresses, func(prefix netip.Prefix) bool {
|
||||
return it.Name == "lo" || prefix.Addr().IsGlobalUnicast()
|
||||
@@ -277,6 +301,11 @@ func (r *autoRedirect) nftablesUpdateLocalAddressSet() error {
|
||||
if slices.Equal(newLocalAddresses, r.localAddresses) {
|
||||
return nil
|
||||
}
|
||||
if r.logger != nil {
|
||||
r.logger.Debug("updating local address set to [", strings.Join(common.Map(newLocalAddresses, func(it netip.Prefix) string {
|
||||
return it.String()
|
||||
}), ", ")+"]")
|
||||
}
|
||||
nft, err := nftables.New()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -74,12 +74,11 @@ func (r *autoRedirect) nftablesCreateLocalAddressSets(
|
||||
localAddresses4 := common.Filter(localAddresses, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is4()
|
||||
})
|
||||
updateAddresses4 := common.Filter(localAddresses, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is4()
|
||||
})
|
||||
var update bool
|
||||
if len(lastAddresses) != 0 {
|
||||
if !slices.Equal(localAddresses4, updateAddresses4) {
|
||||
if !slices.Equal(localAddresses4, common.Filter(lastAddresses, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is4()
|
||||
})) {
|
||||
update = true
|
||||
}
|
||||
}
|
||||
@@ -94,19 +93,14 @@ func (r *autoRedirect) nftablesCreateLocalAddressSets(
|
||||
localAddresses6 := common.Filter(localAddresses, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is6()
|
||||
})
|
||||
updateAddresses6 := common.Filter(localAddresses, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is6()
|
||||
})
|
||||
var update bool
|
||||
if len(lastAddresses) != 0 {
|
||||
if !slices.Equal(localAddresses6, updateAddresses6) {
|
||||
if !slices.Equal(localAddresses6, common.Filter(lastAddresses, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is6()
|
||||
})) {
|
||||
update = true
|
||||
}
|
||||
}
|
||||
localAddresses6 = common.Filter(localAddresses6, func(it netip.Prefix) bool {
|
||||
address := it.Addr()
|
||||
return address.IsLoopback() || address.IsGlobalUnicast() && !address.IsPrivate()
|
||||
})
|
||||
if len(lastAddresses) == 0 || update {
|
||||
_, err := nftablesCreateIPSet(nft, table, 6, "inet6_local_address_set", nftables.TableFamilyIPv6, nil, localAddresses6, false, update)
|
||||
if err != nil {
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/buffer"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
gHdr "github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
@@ -169,7 +172,7 @@ func (m *Mixed) batchLoopDarwin(darwinTUN DarwinTUN) {
|
||||
for {
|
||||
buffers, err := darwinTUN.BatchRead()
|
||||
if err != nil {
|
||||
if E.IsClosed(err) {
|
||||
if E.IsClosed(err) || errors.Is(err, syscall.EBADF) {
|
||||
return
|
||||
}
|
||||
m.logger.Error(E.Cause(err, "batch read packet"))
|
||||
|
||||
@@ -267,7 +267,7 @@ func (s *System) batchLoopDarwin(darwinTUN DarwinTUN) {
|
||||
for {
|
||||
buffers, err := darwinTUN.BatchRead()
|
||||
if err != nil {
|
||||
if E.IsClosed(err) {
|
||||
if E.IsClosed(err) || errors.Is(err, syscall.EBADF) {
|
||||
return
|
||||
}
|
||||
s.logger.Error(E.Cause(err, "batch read packet"))
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
)
|
||||
|
||||
type TCPNat struct {
|
||||
timeout time.Duration
|
||||
portIndex uint16
|
||||
portAccess sync.RWMutex
|
||||
addrAccess sync.RWMutex
|
||||
@@ -19,6 +20,7 @@ type TCPNat struct {
|
||||
}
|
||||
|
||||
type TCPSession struct {
|
||||
sync.Mutex
|
||||
Source netip.AddrPort
|
||||
Destination netip.AddrPort
|
||||
LastActive time.Time
|
||||
@@ -26,38 +28,41 @@ type TCPSession struct {
|
||||
|
||||
func NewNat(ctx context.Context, timeout time.Duration) *TCPNat {
|
||||
natMap := &TCPNat{
|
||||
timeout: timeout,
|
||||
portIndex: 10000,
|
||||
addrMap: make(map[netip.AddrPort]uint16),
|
||||
portMap: make(map[uint16]*TCPSession),
|
||||
}
|
||||
go natMap.loopCheckTimeout(ctx, timeout)
|
||||
go natMap.loopCheckTimeout(ctx)
|
||||
return natMap
|
||||
}
|
||||
|
||||
func (n *TCPNat) loopCheckTimeout(ctx context.Context, timeout time.Duration) {
|
||||
ticker := time.NewTicker(timeout)
|
||||
func (n *TCPNat) loopCheckTimeout(ctx context.Context) {
|
||||
ticker := time.NewTicker(n.timeout)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
n.checkTimeout(timeout)
|
||||
n.checkTimeout()
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *TCPNat) checkTimeout(timeout time.Duration) {
|
||||
func (n *TCPNat) checkTimeout() {
|
||||
now := time.Now()
|
||||
n.portAccess.Lock()
|
||||
defer n.portAccess.Unlock()
|
||||
n.addrAccess.Lock()
|
||||
defer n.addrAccess.Unlock()
|
||||
for natPort, session := range n.portMap {
|
||||
if now.Sub(session.LastActive) > timeout {
|
||||
session.Lock()
|
||||
if now.Sub(session.LastActive) > n.timeout {
|
||||
delete(n.addrMap, session.Source)
|
||||
delete(n.portMap, natPort)
|
||||
}
|
||||
session.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +71,11 @@ func (n *TCPNat) LookupBack(port uint16) *TCPSession {
|
||||
session := n.portMap[port]
|
||||
n.portAccess.RUnlock()
|
||||
if session != nil {
|
||||
session.LastActive = time.Now()
|
||||
session.Lock()
|
||||
if time.Since(session.LastActive) > time.Second {
|
||||
session.LastActive = time.Now()
|
||||
}
|
||||
session.Unlock()
|
||||
}
|
||||
return session
|
||||
}
|
||||
|
||||
72
tun.go
72
tun.go
@@ -52,44 +52,46 @@ type DarwinTUN interface {
|
||||
}
|
||||
|
||||
const (
|
||||
DefaultIPRoute2TableIndex = 2022
|
||||
DefaultIPRoute2RuleIndex = 9000
|
||||
DefaultIPRoute2TableIndex = 2022
|
||||
DefaultIPRoute2RuleIndex = 9000
|
||||
DefaultIPRoute2AutoRedirectFallbackRuleIndex = 32768
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Name string
|
||||
Inet4Address []netip.Prefix
|
||||
Inet6Address []netip.Prefix
|
||||
MTU uint32
|
||||
GSO bool
|
||||
AutoRoute bool
|
||||
InterfaceScope bool
|
||||
Inet4Gateway netip.Addr
|
||||
Inet6Gateway netip.Addr
|
||||
DNSServers []netip.Addr
|
||||
IPRoute2TableIndex int
|
||||
IPRoute2RuleIndex int
|
||||
AutoRedirectMarkMode bool
|
||||
AutoRedirectInputMark uint32
|
||||
AutoRedirectOutputMark uint32
|
||||
Inet4LoopbackAddress []netip.Addr
|
||||
Inet6LoopbackAddress []netip.Addr
|
||||
StrictRoute bool
|
||||
Inet4RouteAddress []netip.Prefix
|
||||
Inet6RouteAddress []netip.Prefix
|
||||
Inet4RouteExcludeAddress []netip.Prefix
|
||||
Inet6RouteExcludeAddress []netip.Prefix
|
||||
IncludeInterface []string
|
||||
ExcludeInterface []string
|
||||
IncludeUID []ranges.Range[uint32]
|
||||
ExcludeUID []ranges.Range[uint32]
|
||||
IncludeAndroidUser []int
|
||||
IncludePackage []string
|
||||
ExcludePackage []string
|
||||
InterfaceFinder control.InterfaceFinder
|
||||
InterfaceMonitor DefaultInterfaceMonitor
|
||||
FileDescriptor int
|
||||
Logger logger.Logger
|
||||
Name string
|
||||
Inet4Address []netip.Prefix
|
||||
Inet6Address []netip.Prefix
|
||||
MTU uint32
|
||||
GSO bool
|
||||
AutoRoute bool
|
||||
InterfaceScope bool
|
||||
Inet4Gateway netip.Addr
|
||||
Inet6Gateway netip.Addr
|
||||
DNSServers []netip.Addr
|
||||
IPRoute2TableIndex int
|
||||
IPRoute2RuleIndex int
|
||||
IPRoute2AutoRedirectFallbackRuleIndex int
|
||||
AutoRedirectMarkMode bool
|
||||
AutoRedirectInputMark uint32
|
||||
AutoRedirectOutputMark uint32
|
||||
Inet4LoopbackAddress []netip.Addr
|
||||
Inet6LoopbackAddress []netip.Addr
|
||||
StrictRoute bool
|
||||
Inet4RouteAddress []netip.Prefix
|
||||
Inet6RouteAddress []netip.Prefix
|
||||
Inet4RouteExcludeAddress []netip.Prefix
|
||||
Inet6RouteExcludeAddress []netip.Prefix
|
||||
IncludeInterface []string
|
||||
ExcludeInterface []string
|
||||
IncludeUID []ranges.Range[uint32]
|
||||
ExcludeUID []ranges.Range[uint32]
|
||||
IncludeAndroidUser []int
|
||||
IncludePackage []string
|
||||
ExcludePackage []string
|
||||
InterfaceFinder control.InterfaceFinder
|
||||
InterfaceMonitor DefaultInterfaceMonitor
|
||||
FileDescriptor int
|
||||
Logger logger.Logger
|
||||
|
||||
// No work for TCP, do not use.
|
||||
_TXChecksumOffload bool
|
||||
|
||||
@@ -152,7 +152,10 @@ func (t *NativeTun) Start() error {
|
||||
|
||||
func (t *NativeTun) Close() error {
|
||||
defer flushDNSCache()
|
||||
return E.Errors(t.unsetRoutes(), t.tunFile.Close())
|
||||
t.stopFd.Stop()
|
||||
err := E.Errors(t.unsetRoutes(), t.tunFile.Close())
|
||||
t.stopFd.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *NativeTun) Read(p []byte) (n int, err error) {
|
||||
@@ -347,6 +350,9 @@ func (t *NativeTun) BatchRead() ([]*buf.Buffer, error) {
|
||||
t.buffers = t.buffers[:0]
|
||||
return nil, errno
|
||||
}
|
||||
if n < 0 {
|
||||
return nil, os.ErrClosed
|
||||
}
|
||||
if n < 1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
68
tun_linux.go
68
tun_linux.go
@@ -17,7 +17,6 @@ import (
|
||||
"github.com/sagernet/sing-tun/internal/gtcpip/checksum"
|
||||
"github.com/sagernet/sing-tun/internal/gtcpip/header"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/rw"
|
||||
@@ -40,6 +39,7 @@ type NativeTun struct {
|
||||
writeAccess sync.Mutex
|
||||
vnetHdr bool
|
||||
writeBuffer []byte
|
||||
vnetHdrWriteBuf []byte
|
||||
gsoToWrite []int
|
||||
tcpGROTable *tcpGROTable
|
||||
udpGroAccess sync.Mutex
|
||||
@@ -130,7 +130,7 @@ func (t *NativeTun) configure(tunLink netlink.Link) error {
|
||||
for _, address := range t.options.Inet4Address {
|
||||
addr4, _ := netlink.ParseAddr(address.String())
|
||||
err = netlink.AddrAdd(tunLink, addr4)
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, unix.EEXIST) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ func (t *NativeTun) configure(tunLink netlink.Link) error {
|
||||
for _, address := range t.options.Inet6Address {
|
||||
addr6, _ := netlink.ParseAddr(address.String())
|
||||
err = netlink.AddrAdd(tunLink, addr6)
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, unix.EEXIST) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -148,7 +148,9 @@ func (t *NativeTun) configure(tunLink netlink.Link) error {
|
||||
if t.options.GSO {
|
||||
err = t.enableGSO()
|
||||
if err != nil {
|
||||
t.options.Logger.Warn(err)
|
||||
if t.options.Logger != nil {
|
||||
t.options.Logger.Warn(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +275,9 @@ func (t *NativeTun) Start() error {
|
||||
if err != nil {
|
||||
t.gro.disableTCPGRO()
|
||||
t.gro.disableUDPGRO()
|
||||
t.options.Logger.Warn(E.Cause(err, "disabled TUN TCP & UDP GRO due to GRO probe error"))
|
||||
if t.options.Logger != nil {
|
||||
t.options.Logger.Warn(E.Cause(err, "disabled TUN TCP & UDP GRO due to GRO probe error"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,6 +319,8 @@ func (t *NativeTun) Close() error {
|
||||
if t.interfaceCallback != nil {
|
||||
t.options.InterfaceMonitor.UnregisterCallback(t.interfaceCallback)
|
||||
}
|
||||
t.unsetSearchDomainForSystemdResolved()
|
||||
t.unsetAddresses()
|
||||
return E.Errors(t.unsetRoute(), t.unsetRules(), common.Close(common.PtrOrNil(t.tunFile)))
|
||||
}
|
||||
|
||||
@@ -382,10 +388,7 @@ func handleVirtioRead(in []byte, bufs [][]byte, sizes []int, offset int) (int, e
|
||||
|
||||
func (t *NativeTun) Write(p []byte) (n int, err error) {
|
||||
if t.vnetHdr {
|
||||
buffer := buf.Get(virtioNetHdrLen + len(p))
|
||||
copy(buffer[virtioNetHdrLen:], p)
|
||||
_, err = t.BatchWrite([][]byte{buffer}, virtioNetHdrLen)
|
||||
buf.Put(buffer)
|
||||
_, err = t.BatchWrite([][]byte{p}, virtioNetHdrLen)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -616,6 +619,22 @@ func (t *NativeTun) rules() []*netlink.Rule {
|
||||
it.Family = unix.AF_INET6
|
||||
rules = append(rules, it)
|
||||
}
|
||||
// Fallback rules after system default rules (32766: main, 32767: default)
|
||||
// Only reached when main and default tables have no route
|
||||
if p4 {
|
||||
it = netlink.NewRule()
|
||||
it.Priority = t.options.IPRoute2AutoRedirectFallbackRuleIndex
|
||||
it.Table = t.options.IPRoute2TableIndex
|
||||
it.Family = unix.AF_INET
|
||||
rules = append(rules, it)
|
||||
}
|
||||
if p6 {
|
||||
it = netlink.NewRule()
|
||||
it.Priority = t.options.IPRoute2AutoRedirectFallbackRuleIndex
|
||||
it.Table = t.options.IPRoute2TableIndex
|
||||
it.Family = unix.AF_INET6
|
||||
rules = append(rules, it)
|
||||
}
|
||||
return rules
|
||||
}
|
||||
|
||||
@@ -989,7 +1008,7 @@ func (t *NativeTun) unsetRules() error {
|
||||
for _, rule := range ruleList {
|
||||
ruleStart := t.options.IPRoute2RuleIndex
|
||||
ruleEnd := ruleStart + 10
|
||||
if rule.Priority >= ruleStart && rule.Priority <= ruleEnd {
|
||||
if rule.Priority >= ruleStart && rule.Priority <= ruleEnd || (t.options.AutoRedirectMarkMode && rule.Priority == t.options.IPRoute2AutoRedirectFallbackRuleIndex) {
|
||||
ruleToDel := netlink.NewRule()
|
||||
ruleToDel.Family = rule.Family
|
||||
ruleToDel.Priority = rule.Priority
|
||||
@@ -1003,6 +1022,24 @@ func (t *NativeTun) unsetRules() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *NativeTun) unsetAddresses() {
|
||||
if t.options.FileDescriptor > 0 {
|
||||
return
|
||||
}
|
||||
tunLink, err := netlink.LinkByName(t.options.Name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, address := range t.options.Inet4Address {
|
||||
addr, _ := netlink.ParseAddr(address.String())
|
||||
_ = netlink.AddrDel(tunLink, addr)
|
||||
}
|
||||
for _, address := range t.options.Inet6Address {
|
||||
addr, _ := netlink.ParseAddr(address.String())
|
||||
_ = netlink.AddrDel(tunLink, addr)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *NativeTun) resetRules() error {
|
||||
t.unsetRules()
|
||||
return t.setRules()
|
||||
@@ -1046,3 +1083,14 @@ func (t *NativeTun) setSearchDomainForSystemdResolved() {
|
||||
_ = shell.Exec(ctlPath, append([]string{"dns", t.options.Name}, common.Map(dnsServer, netip.Addr.String)...)...).Run()
|
||||
}()
|
||||
}
|
||||
|
||||
func (t *NativeTun) unsetSearchDomainForSystemdResolved() {
|
||||
if t.options.EXP_DisableDNSHijack {
|
||||
return
|
||||
}
|
||||
ctlPath, err := exec.LookPath("resolvectl")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = shell.Exec(ctlPath, "revert", t.options.Name).Run()
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/rawfile"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/link/fdbased"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
@@ -18,6 +20,37 @@ var _ GVisorTun = (*NativeTun)(nil)
|
||||
|
||||
func (t *NativeTun) WritePacket(pkt *stack.PacketBuffer) (int, error) {
|
||||
iovecs := t.iovecsOutputDefault
|
||||
if t.vnetHdr {
|
||||
if t.vnetHdrWriteBuf == nil {
|
||||
t.vnetHdrWriteBuf = make([]byte, virtioNetHdrLen)
|
||||
}
|
||||
vnetHdr := virtioNetHdr{}
|
||||
if pkt.GSOOptions.Type != stack.GSONone {
|
||||
vnetHdr.hdrLen = uint16(pkt.HeaderSize())
|
||||
if pkt.GSOOptions.NeedsCsum {
|
||||
vnetHdr.flags = unix.VIRTIO_NET_HDR_F_NEEDS_CSUM
|
||||
vnetHdr.csumStart = pkt.GSOOptions.L3HdrLen
|
||||
vnetHdr.csumOffset = pkt.GSOOptions.CsumOffset
|
||||
}
|
||||
if uint16(pkt.Data().Size()) > pkt.GSOOptions.MSS {
|
||||
switch pkt.GSOOptions.Type {
|
||||
case stack.GSOTCPv4:
|
||||
vnetHdr.gsoType = unix.VIRTIO_NET_HDR_GSO_TCPV4
|
||||
case stack.GSOTCPv6:
|
||||
vnetHdr.gsoType = unix.VIRTIO_NET_HDR_GSO_TCPV6
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown gso type: %v", pkt.GSOOptions.Type))
|
||||
}
|
||||
vnetHdr.gsoSize = pkt.GSOOptions.MSS
|
||||
}
|
||||
}
|
||||
if err := vnetHdr.encode(t.vnetHdrWriteBuf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
iovec := unix.Iovec{Base: &t.vnetHdrWriteBuf[0]}
|
||||
iovec.SetLen(virtioNetHdrLen)
|
||||
iovecs = append(iovecs, iovec)
|
||||
}
|
||||
var dataLen int
|
||||
for _, packetSlice := range pkt.AsSlices() {
|
||||
dataLen += len(packetSlice)
|
||||
|
||||
@@ -181,6 +181,13 @@ func (t *NativeTun) Start() error {
|
||||
return err
|
||||
}
|
||||
if t.options.StrictRoute {
|
||||
major, _, _ := windows.RtlGetNtVersionNumbers()
|
||||
if major < 10 {
|
||||
if t.options.Logger != nil {
|
||||
t.options.Logger.Warn("strict routing is not supported on Windows versions below 10")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var engine uintptr
|
||||
session := &winsys.FWPM_SESSION0{Flags: winsys.FWPM_SESSION_FLAG_DYNAMIC}
|
||||
err := winsys.FwpmEngineOpen0(nil, winsys.RPC_C_AUTHN_DEFAULT, nil, session, unsafe.Pointer(&engine))
|
||||
@@ -395,15 +402,16 @@ retry:
|
||||
|
||||
func (t *NativeTun) ReadPacket() ([]byte, func(), error) {
|
||||
t.running.Add(1)
|
||||
defer t.running.Done()
|
||||
retry:
|
||||
if t.close.Load() == 1 {
|
||||
t.running.Done()
|
||||
return nil, nil, os.ErrClosed
|
||||
}
|
||||
start := nanotime()
|
||||
shouldSpin := t.rate.current.Load() >= spinloopRateThreshold && uint64(start-t.rate.nextStartTime.Load()) <= rateMeasurementGranularity*2
|
||||
for {
|
||||
if t.close.Load() == 1 {
|
||||
t.running.Done()
|
||||
return nil, nil, os.ErrClosed
|
||||
}
|
||||
packet, err := t.session.ReceivePacket()
|
||||
@@ -411,7 +419,10 @@ retry:
|
||||
case nil:
|
||||
packetSize := len(packet)
|
||||
t.rate.update(uint64(packetSize))
|
||||
return packet, func() { t.session.ReleaseReceivePacket(packet) }, nil
|
||||
return packet, func() {
|
||||
t.session.ReleaseReceivePacket(packet)
|
||||
t.running.Done()
|
||||
}, nil
|
||||
case windows.ERROR_NO_MORE_ITEMS:
|
||||
if !shouldSpin || uint64(nanotime()-start) >= spinloopDuration {
|
||||
windows.WaitForSingleObject(t.readWait, windows.INFINITE)
|
||||
@@ -420,10 +431,13 @@ retry:
|
||||
procyield(1)
|
||||
continue
|
||||
case windows.ERROR_HANDLE_EOF:
|
||||
t.running.Done()
|
||||
return nil, nil, os.ErrClosed
|
||||
case windows.ERROR_INVALID_DATA:
|
||||
t.running.Done()
|
||||
return nil, nil, errors.New("send ring corrupt")
|
||||
}
|
||||
t.running.Done()
|
||||
return nil, nil, fmt.Errorf("read failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user