Compare commits
6 Commits
v0.8.0-bet
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0329538ecd | ||
|
|
caaf8469e0 | ||
|
|
c81ce6d358 | ||
|
|
90ea7a0b69 | ||
|
|
6ee3db839d | ||
|
|
1fb8456021 |
12
go.mod
12
go.mod
@@ -6,25 +6,25 @@ require (
|
||||
github.com/florianl/go-nfqueue/v2 v2.0.2
|
||||
github.com/go-ole/go-ole v1.3.0
|
||||
github.com/google/btree v1.1.3
|
||||
github.com/mdlayher/netlink v1.7.2
|
||||
github.com/mdlayher/netlink v1.9.0
|
||||
github.com/sagernet/fswatch v0.1.1
|
||||
github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a
|
||||
github.com/sagernet/nftables v0.3.0-beta.4
|
||||
github.com/sagernet/sing v0.8.0-beta.2
|
||||
github.com/sagernet/sing v0.8.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
|
||||
golang.org/x/net v0.43.0
|
||||
golang.org/x/sys v0.35.0
|
||||
golang.org/x/net v0.50.0
|
||||
golang.org/x/sys v0.41.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
|
||||
12
go.sum
12
go.sum
@@ -10,12 +10,18 @@ github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/netlink v1.9.0 h1:G8+GLq2x3v4D4MVIqDdNUhTUC7TKiCy/6MDkmItfKco=
|
||||
github.com/mdlayher/netlink v1.9.0/go.mod h1:YBnl5BXsCoRuwBjKKlZ+aYmEoq0r12FDA/3JC+94KDg=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
||||
@@ -28,6 +34,8 @@ github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNen
|
||||
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
|
||||
github.com/sagernet/sing v0.8.0-beta.2 h1:3khO2eE5LMylD/v47+pnVMtFzl6lBY2v/b/V+79qpsE=
|
||||
github.com/sagernet/sing v0.8.0-beta.2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.8.0 h1:OwLEwbcYfZHvu4olZVljxxC1XRicBqJ1HfiFr6F2WEE=
|
||||
github.com/sagernet/sing v0.8.0/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
@@ -38,11 +46,15 @@ golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0J
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
|
||||
@@ -19,29 +19,31 @@ import (
|
||||
)
|
||||
|
||||
type autoRedirect struct {
|
||||
tunOptions *Options
|
||||
ctx context.Context
|
||||
handler Handler
|
||||
logger logger.Logger
|
||||
tableName string
|
||||
networkMonitor NetworkUpdateMonitor
|
||||
networkListener *list.Element[NetworkUpdateCallback]
|
||||
interfaceFinder control.InterfaceFinder
|
||||
localAddresses []netip.Prefix
|
||||
customRedirectPortFunc func() int
|
||||
customRedirectPort int
|
||||
redirectServer *redirectServer
|
||||
enableIPv4 bool
|
||||
enableIPv6 bool
|
||||
iptablesPath string
|
||||
ip6tablesPath string
|
||||
useNFTables bool
|
||||
androidSu bool
|
||||
suPath string
|
||||
routeAddressSet *[]*netipx.IPSet
|
||||
routeExcludeAddressSet *[]*netipx.IPSet
|
||||
nfqueueHandler *nfqueueHandler
|
||||
nfqueueEnabled bool
|
||||
tunOptions *Options
|
||||
ctx context.Context
|
||||
handler Handler
|
||||
logger logger.Logger
|
||||
tableName string
|
||||
networkMonitor NetworkUpdateMonitor
|
||||
networkListener *list.Element[NetworkUpdateCallback]
|
||||
interfaceFinder control.InterfaceFinder
|
||||
localAddresses []netip.Prefix
|
||||
customRedirectPortFunc func() int
|
||||
customRedirectPort int
|
||||
redirectServer *redirectServer
|
||||
enableIPv4 bool
|
||||
enableIPv6 bool
|
||||
iptablesPath string
|
||||
ip6tablesPath string
|
||||
useNFTables bool
|
||||
androidSu bool
|
||||
suPath string
|
||||
routeAddressSet *[]*netipx.IPSet
|
||||
routeExcludeAddressSet *[]*netipx.IPSet
|
||||
nfqueueHandler *nfqueueHandler
|
||||
nfqueueEnabled bool
|
||||
redirectRouteTableIndex int
|
||||
redirectInterfaces []control.Interface
|
||||
}
|
||||
|
||||
func NewAutoRedirect(options AutoRedirectOptions) (AutoRedirect, error) {
|
||||
@@ -152,6 +154,12 @@ func (r *autoRedirect) Start() error {
|
||||
}
|
||||
r.cleanupNFTables()
|
||||
err = r.setupNFTables()
|
||||
if err == nil && r.tunOptions.AutoRedirectMarkMode {
|
||||
err = r.setupRedirectRoutes()
|
||||
if err != nil {
|
||||
r.cleanupNFTables()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r.cleanupIPTables()
|
||||
err = r.setupIPTables()
|
||||
@@ -164,6 +172,7 @@ func (r *autoRedirect) Close() error {
|
||||
r.nfqueueHandler.Close()
|
||||
}
|
||||
if r.useNFTables {
|
||||
r.cleanupRedirectRoutes()
|
||||
r.cleanupNFTables()
|
||||
} else {
|
||||
r.cleanupIPTables()
|
||||
|
||||
@@ -293,6 +293,12 @@ func (r *autoRedirect) setupNFTables() error {
|
||||
if err != nil {
|
||||
r.logger.Error("update local address set: ", err)
|
||||
}
|
||||
if r.tunOptions.AutoRedirectMarkMode {
|
||||
err = r.updateRedirectRoutes()
|
||||
if err != nil {
|
||||
r.logger.Error("update redirect routes: ", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
179
redirect_route_linux.go
Normal file
179
redirect_route_linux.go
Normal file
@@ -0,0 +1,179 @@
|
||||
//go:build linux
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/sagernet/netlink"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const redirectRouteRulePriority = 1
|
||||
|
||||
func (r *autoRedirect) setupRedirectRoutes() error {
|
||||
for {
|
||||
r.redirectRouteTableIndex = int(rand.Uint32())
|
||||
if r.redirectRouteTableIndex == r.tunOptions.IPRoute2TableIndex {
|
||||
continue
|
||||
}
|
||||
routeList, fErr := netlink.RouteListFiltered(netlink.FAMILY_ALL,
|
||||
&netlink.Route{Table: r.redirectRouteTableIndex},
|
||||
netlink.RT_FILTER_TABLE)
|
||||
if len(routeList) == 0 || fErr != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
err := r.interfaceFinder.Update()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tunName := r.tunOptions.Name
|
||||
r.redirectInterfaces = common.Filter(r.interfaceFinder.Interfaces(), func(it control.Interface) bool {
|
||||
return it.Name != "lo" && it.Name != tunName && it.Flags&net.FlagUp != 0
|
||||
})
|
||||
r.cleanupRedirectRoutes()
|
||||
for _, iface := range r.redirectInterfaces {
|
||||
err = r.addRedirectRoutes(iface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if r.enableIPv4 {
|
||||
rule := netlink.NewRule()
|
||||
rule.Priority = redirectRouteRulePriority
|
||||
rule.Table = r.redirectRouteTableIndex
|
||||
rule.Family = unix.AF_INET
|
||||
err = netlink.RuleAdd(rule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if r.enableIPv6 {
|
||||
rule := netlink.NewRule()
|
||||
rule.Priority = redirectRouteRulePriority
|
||||
rule.Table = r.redirectRouteTableIndex
|
||||
rule.Family = unix.AF_INET6
|
||||
err = netlink.RuleAdd(rule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *autoRedirect) addRedirectRoutes(iface control.Interface) error {
|
||||
if r.enableIPv4 && common.Any(iface.Addresses, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is4()
|
||||
}) {
|
||||
err := netlink.RouteAppend(&netlink.Route{
|
||||
LinkIndex: iface.Index,
|
||||
Dst: &net.IPNet{IP: net.IPv4(127, 0, 0, 1), Mask: net.CIDRMask(32, 32)},
|
||||
Table: r.redirectRouteTableIndex,
|
||||
Type: unix.RTN_LOCAL,
|
||||
Scope: netlink.SCOPE_HOST,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if r.enableIPv6 && common.Any(iface.Addresses, func(it netip.Prefix) bool {
|
||||
return it.Addr().Is6() && !it.Addr().Is4In6()
|
||||
}) {
|
||||
err := netlink.RouteAppend(&netlink.Route{
|
||||
LinkIndex: iface.Index,
|
||||
Dst: &net.IPNet{IP: net.IPv6loopback, Mask: net.CIDRMask(128, 128)},
|
||||
Table: r.redirectRouteTableIndex,
|
||||
Type: unix.RTN_LOCAL,
|
||||
Scope: netlink.SCOPE_HOST,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *autoRedirect) removeRedirectRoutes(linkIndex int) {
|
||||
if r.enableIPv4 {
|
||||
_ = netlink.RouteDel(&netlink.Route{
|
||||
LinkIndex: linkIndex,
|
||||
Dst: &net.IPNet{IP: net.IPv4(127, 0, 0, 1), Mask: net.CIDRMask(32, 32)},
|
||||
Table: r.redirectRouteTableIndex,
|
||||
Type: unix.RTN_LOCAL,
|
||||
})
|
||||
}
|
||||
if r.enableIPv6 {
|
||||
_ = netlink.RouteDel(&netlink.Route{
|
||||
LinkIndex: linkIndex,
|
||||
Dst: &net.IPNet{IP: net.IPv6loopback, Mask: net.CIDRMask(128, 128)},
|
||||
Table: r.redirectRouteTableIndex,
|
||||
Type: unix.RTN_LOCAL,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (r *autoRedirect) updateRedirectRoutes() error {
|
||||
err := r.interfaceFinder.Update()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tunName := r.tunOptions.Name
|
||||
newInterfaces := common.Filter(r.interfaceFinder.Interfaces(), func(it control.Interface) bool {
|
||||
return it.Name != "lo" && it.Name != tunName && it.Flags&net.FlagUp != 0
|
||||
})
|
||||
oldMap := make(map[int]bool, len(r.redirectInterfaces))
|
||||
for _, iface := range r.redirectInterfaces {
|
||||
oldMap[iface.Index] = true
|
||||
}
|
||||
newMap := make(map[int]bool, len(newInterfaces))
|
||||
for _, iface := range newInterfaces {
|
||||
newMap[iface.Index] = true
|
||||
}
|
||||
for _, iface := range newInterfaces {
|
||||
if !oldMap[iface.Index] {
|
||||
err = r.addRedirectRoutes(iface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, iface := range r.redirectInterfaces {
|
||||
if !newMap[iface.Index] {
|
||||
r.removeRedirectRoutes(iface.Index)
|
||||
}
|
||||
}
|
||||
r.redirectInterfaces = newInterfaces
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *autoRedirect) cleanupRedirectRoutes() {
|
||||
if r.redirectRouteTableIndex == 0 {
|
||||
return
|
||||
}
|
||||
routes, _ := netlink.RouteListFiltered(netlink.FAMILY_ALL,
|
||||
&netlink.Route{Table: r.redirectRouteTableIndex},
|
||||
netlink.RT_FILTER_TABLE)
|
||||
for _, route := range routes {
|
||||
_ = netlink.RouteDel(&route)
|
||||
}
|
||||
if r.enableIPv4 {
|
||||
rule := netlink.NewRule()
|
||||
rule.Priority = redirectRouteRulePriority
|
||||
rule.Table = r.redirectRouteTableIndex
|
||||
rule.Family = unix.AF_INET
|
||||
_ = netlink.RuleDel(rule)
|
||||
}
|
||||
if r.enableIPv6 {
|
||||
rule := netlink.NewRule()
|
||||
rule.Priority = redirectRouteRulePriority
|
||||
rule.Table = r.redirectRouteTableIndex
|
||||
rule.Family = unix.AF_INET6
|
||||
_ = netlink.RuleDel(rule)
|
||||
}
|
||||
}
|
||||
@@ -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"))
|
||||
|
||||
@@ -269,7 +269,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"))
|
||||
|
||||
13
tun_linux.go
13
tun_linux.go
@@ -39,6 +39,7 @@ type NativeTun struct {
|
||||
writeAccess sync.Mutex
|
||||
vnetHdr bool
|
||||
writeBuffer []byte
|
||||
vnetHdrWriteBuf []byte
|
||||
gsoToWrite []int
|
||||
tcpGROTable *tcpGROTable
|
||||
udpGroAccess sync.Mutex
|
||||
@@ -328,6 +329,7 @@ func (t *NativeTun) Close() error {
|
||||
if t.options.EXP_ExternalConfiguration {
|
||||
return common.Close(common.PtrOrNil(t.tunFile))
|
||||
}
|
||||
t.unsetSearchDomainForSystemdResolved()
|
||||
t.unsetAddresses()
|
||||
return E.Errors(t.unsetRoute(), t.unsetRules(), common.Close(common.PtrOrNil(t.tunFile)))
|
||||
}
|
||||
@@ -1094,3 +1096,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)
|
||||
|
||||
Reference in New Issue
Block a user