Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
323b9564f0 | ||
|
|
4bc8dc7f27 | ||
|
|
41b2639e13 | ||
|
|
605266e65e | ||
|
|
e881f21013 | ||
|
|
b02f252916 | ||
|
|
91df97aee2 | ||
|
|
6999634511 | ||
|
|
209ec123ca |
3
.github/update_dependencies.sh
vendored
3
.github/update_dependencies.sh
vendored
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PROJECTS=$(dirname "$0")/../..
|
||||
|
||||
go get -x github.com/sagernet/sing@$(git -C $PROJECTS/sing rev-parse HEAD)
|
||||
go get -x github.com/sagernet/$1@$(git -C $PROJECTS/$1 rev-parse HEAD)
|
||||
go mod tidy
|
||||
|
||||
11
Makefile
11
Makefile
@@ -1,7 +1,16 @@
|
||||
build:
|
||||
GOOS=darwin GOARCH=arm64 go build -v -tags with_gvisor .
|
||||
GOOS=ios GOARCH=arm64 go build -v -tags with_gvisor .
|
||||
GOOS=linux GOARCH=amd64 go build -v -tags with_gvisor .
|
||||
GOOS=linux GOARCH=arm64 go build -v -tags with_gvisor .
|
||||
GOOS=linux GOARCH=386 go build -v -tags with_gvisor .
|
||||
GOOS=linux GOARCH=arm go build -v -tags with_gvisor .
|
||||
GOOS=windows GOARCH=amd64 go build -v -tags with_gvisor .
|
||||
|
||||
fmt:
|
||||
@gofumpt -l -w .
|
||||
@gofmt -s -w .
|
||||
@gci write --custom-order -s "standard,prefix(github.com/sagernet/),default" .
|
||||
@gci write --custom-order -s standard -s "prefix(github.com/sagernet/)" -s "default" .
|
||||
|
||||
fmt_install:
|
||||
go install -v mvdan.cc/gofumpt@latest
|
||||
|
||||
14
go.mod
14
go.mod
@@ -4,16 +4,18 @@ go 1.18
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/go-ole/go-ole v1.2.6
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61
|
||||
github.com/sagernet/gvisor v0.0.0-20230611140528-4411f7659a08
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97
|
||||
github.com/sagernet/sing v0.2.4
|
||||
golang.org/x/net v0.9.0
|
||||
golang.org/x/sys v0.7.0
|
||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c
|
||||
github.com/sagernet/sing v0.2.5
|
||||
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9
|
||||
golang.org/x/net v0.11.0
|
||||
golang.org/x/sys v0.9.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
)
|
||||
|
||||
29
go.sum
29
go.sum
@@ -1,24 +1,29 @@
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
|
||||
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
|
||||
github.com/sagernet/gvisor v0.0.0-20230611140528-4411f7659a08 h1:p1z8y0tXLCKSiJ7GbUlaYPhyEbWL8LKLMYFpVxRVsBg=
|
||||
github.com/sagernet/gvisor v0.0.0-20230611140528-4411f7659a08/go.mod h1:FgbjODax/nj7J2lr7+rqe88vHs0Ts93pC9na5ZiG9wg=
|
||||
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.4 h1:gC8BR5sglbJZX23RtMyFa8EETP9YEUADhfbEzU1yVbo=
|
||||
github.com/sagernet/sing v0.2.4/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
||||
github.com/sagernet/sing v0.2.5 h1:N8sUluR8GZvR9DqUiH3FA3vBb4m/EDdOVTYUrDzJvmY=
|
||||
github.com/sagernet/sing v0.2.5/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
||||
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg=
|
||||
github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s=
|
||||
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.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4=
|
||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
||||
123
gvisor.go
123
gvisor.go
@@ -4,26 +4,24 @@ package tun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"syscall"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/adapters/gonet"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv4"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/network/ipv6"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/transport/icmp"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/transport/tcp"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/transport/udp"
|
||||
"github.com/sagernet/gvisor/pkg/waiter"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
"github.com/sagernet/sing/common/canceler"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
const WithGVisor = true
|
||||
@@ -36,12 +34,10 @@ type GVisor struct {
|
||||
tunMtu uint32
|
||||
endpointIndependentNat bool
|
||||
udpTimeout int64
|
||||
router Router
|
||||
handler Handler
|
||||
logger logger.Logger
|
||||
stack *stack.Stack
|
||||
endpoint stack.LinkEndpoint
|
||||
routeMapping *RouteMapping
|
||||
}
|
||||
|
||||
type GVisorTun interface {
|
||||
@@ -63,13 +59,9 @@ func NewGVisor(
|
||||
tunMtu: options.MTU,
|
||||
endpointIndependentNat: options.EndpointIndependentNat,
|
||||
udpTimeout: options.UDPTimeout,
|
||||
router: options.Router,
|
||||
handler: options.Handler,
|
||||
logger: options.Logger,
|
||||
}
|
||||
if gStack.router != nil {
|
||||
gStack.routeMapping = NewRouteMapping(options.UDPTimeout)
|
||||
}
|
||||
return gStack, nil
|
||||
}
|
||||
|
||||
@@ -155,44 +147,7 @@ func (t *GVisor) Start() error {
|
||||
}
|
||||
}()
|
||||
})
|
||||
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, func(id stack.TransportEndpointID, buffer *stack.PacketBuffer) bool {
|
||||
if t.router != nil {
|
||||
var routeSession RouteSession
|
||||
routeSession.Network = syscall.IPPROTO_TCP
|
||||
var ipHdr header.Network
|
||||
if buffer.NetworkProtocolNumber == header.IPv4ProtocolNumber {
|
||||
routeSession.IPVersion = 4
|
||||
ipHdr = header.IPv4(buffer.NetworkHeader().Slice())
|
||||
} else {
|
||||
routeSession.IPVersion = 6
|
||||
ipHdr = header.IPv6(buffer.NetworkHeader().Slice())
|
||||
}
|
||||
tcpHdr := header.TCP(buffer.TransportHeader().Slice())
|
||||
routeSession.Source = M.AddrPortFrom(net.IP(ipHdr.SourceAddress()), tcpHdr.SourcePort())
|
||||
routeSession.Destination = M.AddrPortFrom(net.IP(ipHdr.DestinationAddress()), tcpHdr.DestinationPort())
|
||||
action := t.routeMapping.Lookup(routeSession, func() RouteAction {
|
||||
if routeSession.IPVersion == 4 {
|
||||
return t.router.RouteConnection(routeSession, &systemTCPDirectPacketWriter4{t.tun, routeSession.Source})
|
||||
} else {
|
||||
return t.router.RouteConnection(routeSession, &systemTCPDirectPacketWriter6{t.tun, routeSession.Source})
|
||||
}
|
||||
})
|
||||
switch actionType := action.(type) {
|
||||
case *ActionBlock:
|
||||
// TODO: send icmp unreachable
|
||||
return true
|
||||
case *ActionDirect:
|
||||
buffer.IncRef()
|
||||
err = actionType.WritePacketBuffer(buffer)
|
||||
if err != nil {
|
||||
t.logger.Trace("route gvisor tcp packet: ", err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return tcpForwarder.HandlePacket(id, buffer)
|
||||
})
|
||||
|
||||
ipStack.SetTransportProtocolHandler(tcp.ProtocolNumber, tcpForwarder.HandlePacket)
|
||||
if !t.endpointIndependentNat {
|
||||
udpForwarder := udp.NewForwarder(ipStack, func(request *udp.ForwarderRequest) {
|
||||
var wq waiter.Queue
|
||||
@@ -218,43 +173,7 @@ func (t *GVisor) Start() error {
|
||||
}
|
||||
}()
|
||||
})
|
||||
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, func(id stack.TransportEndpointID, buffer *stack.PacketBuffer) bool {
|
||||
if t.router != nil {
|
||||
var routeSession RouteSession
|
||||
routeSession.Network = syscall.IPPROTO_UDP
|
||||
var ipHdr header.Network
|
||||
if buffer.NetworkProtocolNumber == header.IPv4ProtocolNumber {
|
||||
routeSession.IPVersion = 4
|
||||
ipHdr = header.IPv4(buffer.NetworkHeader().Slice())
|
||||
} else {
|
||||
routeSession.IPVersion = 6
|
||||
ipHdr = header.IPv6(buffer.NetworkHeader().Slice())
|
||||
}
|
||||
udpHdr := header.UDP(buffer.TransportHeader().Slice())
|
||||
routeSession.Source = M.AddrPortFrom(net.IP(ipHdr.SourceAddress()), udpHdr.SourcePort())
|
||||
routeSession.Destination = M.AddrPortFrom(net.IP(ipHdr.DestinationAddress()), udpHdr.DestinationPort())
|
||||
action := t.routeMapping.Lookup(routeSession, func() RouteAction {
|
||||
if routeSession.IPVersion == 4 {
|
||||
return t.router.RouteConnection(routeSession, &systemUDPDirectPacketWriter4{t.tun, routeSession.Source})
|
||||
} else {
|
||||
return t.router.RouteConnection(routeSession, &systemUDPDirectPacketWriter6{t.tun, routeSession.Source})
|
||||
}
|
||||
})
|
||||
switch actionType := action.(type) {
|
||||
case *ActionBlock:
|
||||
// TODO: send icmp unreachable
|
||||
return true
|
||||
case *ActionDirect:
|
||||
buffer.IncRef()
|
||||
err = actionType.WritePacketBuffer(buffer)
|
||||
if err != nil {
|
||||
t.logger.Trace("route gvisor udp packet: ", err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return udpForwarder.HandlePacket(id, buffer)
|
||||
})
|
||||
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, udpForwarder.HandlePacket)
|
||||
} else {
|
||||
ipStack.SetTransportProtocolHandler(udp.ProtocolNumber, NewUDPForwarder(t.ctx, ipStack, t.handler, t.udpTimeout).HandlePacket)
|
||||
}
|
||||
@@ -272,3 +191,19 @@ func (t *GVisor) Close() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AddressFromAddr(destination netip.Addr) tcpip.Address {
|
||||
if destination.Is6() {
|
||||
return tcpip.AddrFrom16(destination.As16())
|
||||
} else {
|
||||
return tcpip.AddrFrom4(destination.As4())
|
||||
}
|
||||
}
|
||||
|
||||
func AddrFromAddress(address tcpip.Address) netip.Addr {
|
||||
if address.Len() == 16 {
|
||||
return netip.AddrFrom16(address.As16())
|
||||
} else {
|
||||
return netip.AddrFrom4(address.As4())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,9 @@ package tun
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/adapters/gonet"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
||||
)
|
||||
|
||||
type gTCPConn struct {
|
||||
|
||||
@@ -5,7 +5,7 @@ package tun
|
||||
import (
|
||||
"time"
|
||||
|
||||
gLog "gvisor.dev/gvisor/pkg/log"
|
||||
gLog "github.com/sagernet/gvisor/pkg/log"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -5,18 +5,17 @@ package tun
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/sagernet/gvisor/pkg/buffer"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/checksum"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/udpnat"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
type UDPForwarder struct {
|
||||
@@ -33,10 +32,10 @@ func NewUDPForwarder(ctx context.Context, stack *stack.Stack, handler Handler, u
|
||||
}
|
||||
}
|
||||
|
||||
func (f *UDPForwarder) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
|
||||
func (f *UDPForwarder) HandlePacket(id stack.TransportEndpointID, pkt stack.PacketBufferPtr) bool {
|
||||
var upstreamMetadata M.Metadata
|
||||
upstreamMetadata.Source = M.SocksaddrFrom(M.AddrFromIP(net.IP(id.RemoteAddress)), id.RemotePort)
|
||||
upstreamMetadata.Destination = M.SocksaddrFrom(M.AddrFromIP(net.IP(id.LocalAddress)), id.LocalPort)
|
||||
upstreamMetadata.Source = M.SocksaddrFrom(AddrFromAddress(id.RemoteAddress), id.RemotePort)
|
||||
upstreamMetadata.Destination = M.SocksaddrFrom(AddrFromAddress(id.LocalAddress), id.LocalPort)
|
||||
var netProto tcpip.NetworkProtocolNumber
|
||||
if upstreamMetadata.Source.IsIPv4() {
|
||||
netProto = header.IPv4ProtocolNumber
|
||||
@@ -62,12 +61,12 @@ type UDPBackWriter struct {
|
||||
sourceNetwork tcpip.NetworkProtocolNumber
|
||||
}
|
||||
|
||||
func (w *UDPBackWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
||||
defer buffer.Release()
|
||||
func (w *UDPBackWriter) WritePacket(packetBuffer *buf.Buffer, destination M.Socksaddr) error {
|
||||
defer packetBuffer.Release()
|
||||
|
||||
route, err := w.stack.FindRoute(
|
||||
defaultNIC,
|
||||
tcpip.Address(destination.Addr.AsSlice()),
|
||||
AddressFromAddr(destination.Addr),
|
||||
w.source,
|
||||
w.sourceNetwork,
|
||||
false,
|
||||
@@ -79,7 +78,7 @@ func (w *UDPBackWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr)
|
||||
|
||||
packet := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: header.UDPMinimumSize + int(route.MaxHeaderLength()),
|
||||
Payload: bufferv2.MakeWithData(buffer.Bytes()),
|
||||
Payload: buffer.MakeWithData(packetBuffer.Bytes()),
|
||||
})
|
||||
defer packet.DecRef()
|
||||
|
||||
@@ -93,9 +92,9 @@ func (w *UDPBackWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr)
|
||||
})
|
||||
|
||||
if route.RequiresTXTransportChecksum() && w.sourceNetwork == header.IPv6ProtocolNumber {
|
||||
xsum := udpHdr.CalculateChecksum(header.ChecksumCombine(
|
||||
xsum := udpHdr.CalculateChecksum(checksum.Combine(
|
||||
route.PseudoHeaderChecksum(header.UDPProtocolNumber, pLen),
|
||||
packet.Data().AsRange().Checksum(),
|
||||
packet.Data().Checksum(),
|
||||
))
|
||||
if xsum != math.MaxUint16 {
|
||||
xsum = ^xsum
|
||||
|
||||
274
internal/winfw/winfw.go
Normal file
274
internal/winfw/winfw.go
Normal file
@@ -0,0 +1,274 @@
|
||||
// Copyright (c) 2018 Samuel Melrose
|
||||
// SPDX-License-Identifier: MIT
|
||||
// https://github.com/iamacarpet/go-win64api/blob/ef6dbdd6db97301ae08a55eedea773476985a602/firewall.go
|
||||
|
||||
//go:build windows
|
||||
|
||||
package winfw
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/go-ole/go-ole"
|
||||
"github.com/go-ole/go-ole/oleutil"
|
||||
"github.com/scjalliance/comshim"
|
||||
)
|
||||
|
||||
// Firewall related API constants.
|
||||
const (
|
||||
NET_FW_IP_PROTOCOL_TCP = 6
|
||||
NET_FW_IP_PROTOCOL_UDP = 17
|
||||
NET_FW_IP_PROTOCOL_ICMPv4 = 1
|
||||
NET_FW_IP_PROTOCOL_ICMPv6 = 58
|
||||
NET_FW_IP_PROTOCOL_ANY = 256
|
||||
|
||||
NET_FW_RULE_DIR_IN = 1
|
||||
NET_FW_RULE_DIR_OUT = 2
|
||||
|
||||
NET_FW_ACTION_BLOCK = 0
|
||||
NET_FW_ACTION_ALLOW = 1
|
||||
|
||||
// NET_FW_PROFILE2_CURRENT is not real API constant, just helper used in FW functions.
|
||||
// It can mean one profile or multiple (even all) profiles. It depends on which profiles
|
||||
// are currently in use. Every active interface can have it's own profile. F.e.: Public for Wifi,
|
||||
// Domain for VPN, and Private for LAN. All at the same time.
|
||||
NET_FW_PROFILE2_CURRENT = 0
|
||||
NET_FW_PROFILE2_DOMAIN = 1
|
||||
NET_FW_PROFILE2_PRIVATE = 2
|
||||
NET_FW_PROFILE2_PUBLIC = 4
|
||||
NET_FW_PROFILE2_ALL = 2147483647
|
||||
)
|
||||
|
||||
// Firewall Rule Groups
|
||||
// Use this magical strings instead of group names. It will work on all language Windows versions.
|
||||
// You can find more string locations here:
|
||||
// https://windows10dll.nirsoft.net/firewallapi_dll.html
|
||||
const (
|
||||
NET_FW_FILE_AND_PRINTER_SHARING = "@FirewallAPI.dll,-28502"
|
||||
NET_FW_REMOTE_DESKTOP = "@FirewallAPI.dll,-28752"
|
||||
)
|
||||
|
||||
// FWRule represents Firewall Rule.
|
||||
type FWRule struct {
|
||||
Name, Description, ApplicationName, ServiceName string
|
||||
LocalPorts, RemotePorts string
|
||||
// LocalAddresses, RemoteAddresses are always returned with netmask, f.e.:
|
||||
// `10.10.1.1/255.255.255.0`
|
||||
LocalAddresses, RemoteAddresses string
|
||||
// ICMPTypesAndCodes is string. You can find define multiple codes separated by ":" (colon).
|
||||
// Types are listed here:
|
||||
// https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml
|
||||
// So to allow ping set it to:
|
||||
// "0"
|
||||
ICMPTypesAndCodes string
|
||||
Grouping string
|
||||
// InterfaceTypes can be:
|
||||
// "LAN", "Wireless", "RemoteAccess", "All"
|
||||
// You can add multiple deviding with comma:
|
||||
// "LAN, Wireless"
|
||||
InterfaceTypes string
|
||||
Protocol, Direction, Action, Profiles int32
|
||||
Enabled, EdgeTraversal bool
|
||||
}
|
||||
|
||||
// FirewallRuleAddAdvanced allows to modify almost all available FW Rule parameters.
|
||||
// You probably do not want to use this, as function allows to create any rule, even opening all ports
|
||||
// in given profile. So use with caution.
|
||||
func FirewallRuleAddAdvanced(rule FWRule) (bool, error) {
|
||||
return firewallRuleAdd(rule.Name, rule.Description, rule.Grouping, rule.ApplicationName, rule.ServiceName,
|
||||
rule.LocalPorts, rule.RemotePorts, rule.LocalAddresses, rule.RemoteAddresses, rule.ICMPTypesAndCodes,
|
||||
rule.Protocol, rule.Direction, rule.Action, rule.Profiles, rule.Enabled, rule.EdgeTraversal)
|
||||
}
|
||||
|
||||
// firewallRuleAdd is universal function to add all kinds of rules.
|
||||
func firewallRuleAdd(name, description, group, appPath, serviceName, ports, remotePorts, localAddresses, remoteAddresses, icmpTypes string, protocol, direction, action, profile int32, enabled, edgeTraversal bool) (bool, error) {
|
||||
if name == "" {
|
||||
return false, fmt.Errorf("empty FW Rule name, name is mandatory")
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
u, fwPolicy, err := firewallAPIInit()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer firewallAPIRelease(u, fwPolicy)
|
||||
|
||||
if profile == NET_FW_PROFILE2_CURRENT {
|
||||
currentProfiles, err := oleutil.GetProperty(fwPolicy, "CurrentProfileTypes")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to get CurrentProfiles: %s", err)
|
||||
}
|
||||
profile = currentProfiles.Value().(int32)
|
||||
}
|
||||
unknownRules, err := oleutil.GetProperty(fwPolicy, "Rules")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to get Rules: %s", err)
|
||||
}
|
||||
rules := unknownRules.ToIDispatch()
|
||||
|
||||
if ok, err := FirewallRuleExistsByName(rules, name); err != nil {
|
||||
return false, fmt.Errorf("Error while checking rules for duplicate: %s", err)
|
||||
} else if ok {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
unknown2, err := oleutil.CreateObject("HNetCfg.FWRule")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Error creating Rule object: %s", err)
|
||||
}
|
||||
defer unknown2.Release()
|
||||
|
||||
fwRule, err := unknown2.QueryInterface(ole.IID_IDispatch)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Error creating Rule object (2): %s", err)
|
||||
}
|
||||
defer fwRule.Release()
|
||||
|
||||
if _, err := oleutil.PutProperty(fwRule, "Name", name); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (Name) of Rule: %s", err)
|
||||
}
|
||||
if _, err := oleutil.PutProperty(fwRule, "Description", description); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (Description) of Rule: %s", err)
|
||||
}
|
||||
if appPath != "" {
|
||||
if _, err := oleutil.PutProperty(fwRule, "Applicationname", appPath); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (Applicationname) of Rule: %s", err)
|
||||
}
|
||||
}
|
||||
if serviceName != "" {
|
||||
if _, err := oleutil.PutProperty(fwRule, "ServiceName", serviceName); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (ServiceName) of Rule: %s", err)
|
||||
}
|
||||
}
|
||||
if protocol != 0 {
|
||||
if _, err := oleutil.PutProperty(fwRule, "Protocol", protocol); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (Protocol) of Rule: %s", err)
|
||||
}
|
||||
}
|
||||
if icmpTypes != "" {
|
||||
if _, err := oleutil.PutProperty(fwRule, "IcmpTypesAndCodes", icmpTypes); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (IcmpTypesAndCodes) of Rule: %s", err)
|
||||
}
|
||||
}
|
||||
if ports != "" {
|
||||
if _, err := oleutil.PutProperty(fwRule, "LocalPorts", ports); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (LocalPorts) of Rule: %s", err)
|
||||
}
|
||||
}
|
||||
if remotePorts != "" {
|
||||
if _, err := oleutil.PutProperty(fwRule, "RemotePorts", remotePorts); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (RemotePorts) of Rule: %s", err)
|
||||
}
|
||||
}
|
||||
if localAddresses != "" {
|
||||
if _, err := oleutil.PutProperty(fwRule, "LocalAddresses", localAddresses); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (LocalAddresses) of Rule: %s", err)
|
||||
}
|
||||
}
|
||||
if remoteAddresses != "" {
|
||||
if _, err := oleutil.PutProperty(fwRule, "RemoteAddresses", remoteAddresses); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (RemoteAddresses) of Rule: %s", err)
|
||||
}
|
||||
}
|
||||
if direction != 0 {
|
||||
if _, err := oleutil.PutProperty(fwRule, "Direction", direction); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (Direction) of Rule: %s", err)
|
||||
}
|
||||
}
|
||||
if _, err := oleutil.PutProperty(fwRule, "Enabled", enabled); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (Enabled) of Rule: %s", err)
|
||||
}
|
||||
if _, err := oleutil.PutProperty(fwRule, "Grouping", group); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (Grouping) of Rule: %s", err)
|
||||
}
|
||||
if _, err := oleutil.PutProperty(fwRule, "Profiles", profile); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (Profiles) of Rule: %s", err)
|
||||
}
|
||||
if _, err := oleutil.PutProperty(fwRule, "Action", action); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (Action) of Rule: %s", err)
|
||||
}
|
||||
if edgeTraversal {
|
||||
if _, err := oleutil.PutProperty(fwRule, "EdgeTraversal", edgeTraversal); err != nil {
|
||||
return false, fmt.Errorf("Error setting property (EdgeTraversal) of Rule: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := oleutil.CallMethod(rules, "Add", fwRule); err != nil {
|
||||
return false, fmt.Errorf("Error adding Rule: %s", err)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func FirewallRuleExistsByName(rules *ole.IDispatch, name string) (bool, error) {
|
||||
enumProperty, err := rules.GetProperty("_NewEnum")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to get enumeration property on Rules: %s", err)
|
||||
}
|
||||
defer enumProperty.Clear()
|
||||
|
||||
enum, err := enumProperty.ToIUnknown().IEnumVARIANT(ole.IID_IEnumVariant)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to cast enum to correct type: %s", err)
|
||||
}
|
||||
if enum == nil {
|
||||
return false, fmt.Errorf("can't get IEnumVARIANT, enum is nil")
|
||||
}
|
||||
|
||||
for itemRaw, length, err := enum.Next(1); length > 0; itemRaw, length, err = enum.Next(1) {
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to seek next Rule item: %s", err)
|
||||
}
|
||||
|
||||
t, err := func() (bool, error) {
|
||||
item := itemRaw.ToIDispatch()
|
||||
defer item.Release()
|
||||
|
||||
if item, err := oleutil.GetProperty(item, "Name"); err != nil {
|
||||
return false, fmt.Errorf("Failed to get Property (Name) of Rule")
|
||||
} else if item.ToString() == name {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
} else if t {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// firewallAPIInit initialize common fw api.
|
||||
// then:
|
||||
// dispatch firewallAPIRelease(u, fwp)
|
||||
func firewallAPIInit() (*ole.IUnknown, *ole.IDispatch, error) {
|
||||
comshim.Add(1)
|
||||
|
||||
unknown, err := oleutil.CreateObject("HNetCfg.FwPolicy2")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Failed to create FwPolicy Object: %s", err)
|
||||
}
|
||||
|
||||
fwPolicy, err := unknown.QueryInterface(ole.IID_IDispatch)
|
||||
if err != nil {
|
||||
unknown.Release()
|
||||
return nil, nil, fmt.Errorf("Failed to create FwPolicy Object (2): %s", err)
|
||||
}
|
||||
|
||||
return unknown, fwPolicy, nil
|
||||
}
|
||||
|
||||
// firewallAPIRelease cleans memory.
|
||||
func firewallAPIRelease(u *ole.IUnknown, fwp *ole.IDispatch) {
|
||||
fwp.Release()
|
||||
u.Release()
|
||||
comshim.Done()
|
||||
}
|
||||
@@ -39,5 +39,6 @@ type DefaultInterfaceMonitor interface {
|
||||
}
|
||||
|
||||
type DefaultInterfaceMonitorOptions struct {
|
||||
OverrideAndroidVPN bool
|
||||
OverrideAndroidVPN bool
|
||||
UnderNetworkExtension bool
|
||||
}
|
||||
|
||||
@@ -122,11 +122,16 @@ func (m *defaultInterfaceMonitor) checkUpdate() error {
|
||||
break
|
||||
}
|
||||
if defaultInterface == nil {
|
||||
defaultInterface, err = getDefaultInterfaceBySocket()
|
||||
if err != nil {
|
||||
return err
|
||||
if m.options.UnderNetworkExtension {
|
||||
defaultInterface, err = getDefaultInterfaceBySocket()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if defaultInterface == nil {
|
||||
return ErrNoRoute
|
||||
}
|
||||
oldInterface := m.defaultInterfaceName
|
||||
oldIndex := m.defaultInterfaceIndex
|
||||
m.defaultInterfaceIndex = defaultInterface.Index
|
||||
|
||||
92
route.go
92
route.go
@@ -1,92 +0,0 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
type ActionType = uint8
|
||||
|
||||
const (
|
||||
ActionTypeUnknown ActionType = iota
|
||||
ActionTypeReturn
|
||||
ActionTypeBlock
|
||||
ActionTypeDirect
|
||||
)
|
||||
|
||||
func ParseActionType(action string) (ActionType, error) {
|
||||
switch action {
|
||||
case "return":
|
||||
return ActionTypeReturn, nil
|
||||
case "block":
|
||||
return ActionTypeBlock, nil
|
||||
case "direct":
|
||||
return ActionTypeDirect, nil
|
||||
default:
|
||||
return 0, E.New("unknown action: ", action)
|
||||
}
|
||||
}
|
||||
|
||||
func ActionTypeName(actionType ActionType) (string, error) {
|
||||
switch actionType {
|
||||
case ActionTypeUnknown:
|
||||
return "", nil
|
||||
case ActionTypeReturn:
|
||||
return "return", nil
|
||||
case ActionTypeBlock:
|
||||
return "block", nil
|
||||
case ActionTypeDirect:
|
||||
return "direct", nil
|
||||
default:
|
||||
return "", E.New("unknown action: ", actionType)
|
||||
}
|
||||
}
|
||||
|
||||
type RouteSession struct {
|
||||
IPVersion uint8
|
||||
Network uint8
|
||||
Source netip.AddrPort
|
||||
Destination netip.AddrPort
|
||||
}
|
||||
|
||||
type RouteContext interface {
|
||||
WritePacket(packet []byte) error
|
||||
}
|
||||
|
||||
type Router interface {
|
||||
RouteConnection(session RouteSession, context RouteContext) RouteAction
|
||||
}
|
||||
|
||||
type RouteAction interface {
|
||||
ActionType() ActionType
|
||||
Timeout() bool
|
||||
}
|
||||
|
||||
type ActionReturn struct{}
|
||||
|
||||
func (r *ActionReturn) ActionType() ActionType {
|
||||
return ActionTypeReturn
|
||||
}
|
||||
|
||||
func (r *ActionReturn) Timeout() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type ActionBlock struct{}
|
||||
|
||||
func (r *ActionBlock) ActionType() ActionType {
|
||||
return ActionTypeBlock
|
||||
}
|
||||
|
||||
func (r *ActionBlock) Timeout() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type ActionDirect struct {
|
||||
DirectDestination
|
||||
}
|
||||
|
||||
func (r *ActionDirect) ActionType() ActionType {
|
||||
return ActionTypeDirect
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
//go:build with_gvisor
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
type DirectDestination interface {
|
||||
WritePacket(buffer *buf.Buffer) error
|
||||
WritePacketBuffer(buffer *stack.PacketBuffer) error
|
||||
Close() error
|
||||
Timeout() bool
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/cache"
|
||||
)
|
||||
|
||||
type RouteMapping struct {
|
||||
status *cache.LruCache[RouteSession, RouteAction]
|
||||
}
|
||||
|
||||
func NewRouteMapping(maxAge int64) *RouteMapping {
|
||||
return &RouteMapping{
|
||||
status: cache.New(
|
||||
cache.WithAge[RouteSession, RouteAction](maxAge),
|
||||
cache.WithUpdateAgeOnGet[RouteSession, RouteAction](),
|
||||
cache.WithEvict[RouteSession, RouteAction](func(key RouteSession, conn RouteAction) {
|
||||
common.Close(conn)
|
||||
}),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *RouteMapping) Lookup(session RouteSession, constructor func() RouteAction) RouteAction {
|
||||
action, _ := m.status.LoadOrStore(session, constructor)
|
||||
if action.Timeout() {
|
||||
common.Close(action)
|
||||
action = constructor()
|
||||
m.status.Store(session, action)
|
||||
}
|
||||
return action
|
||||
}
|
||||
119
route_nat.go
119
route_nat.go
@@ -1,119 +0,0 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-tun/internal/clashtcpip"
|
||||
)
|
||||
|
||||
type NatMapping struct {
|
||||
access sync.RWMutex
|
||||
sessions map[RouteSession]RouteContext
|
||||
ipRewrite bool
|
||||
}
|
||||
|
||||
func NewNatMapping(ipRewrite bool) *NatMapping {
|
||||
return &NatMapping{
|
||||
sessions: make(map[RouteSession]RouteContext),
|
||||
ipRewrite: ipRewrite,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *NatMapping) CreateSession(session RouteSession, context RouteContext) {
|
||||
if m.ipRewrite {
|
||||
session.Source = netip.AddrPort{}
|
||||
}
|
||||
m.access.Lock()
|
||||
m.sessions[session] = context
|
||||
m.access.Unlock()
|
||||
}
|
||||
|
||||
func (m *NatMapping) DeleteSession(session RouteSession) {
|
||||
if m.ipRewrite {
|
||||
session.Source = netip.AddrPort{}
|
||||
}
|
||||
m.access.Lock()
|
||||
delete(m.sessions, session)
|
||||
m.access.Unlock()
|
||||
}
|
||||
|
||||
func (m *NatMapping) WritePacket(packet []byte) (bool, error) {
|
||||
var routeSession RouteSession
|
||||
var ipHdr clashtcpip.IP
|
||||
switch ipVersion := packet[0] >> 4; ipVersion {
|
||||
case 4:
|
||||
routeSession.IPVersion = 4
|
||||
ipHdr = clashtcpip.IPv4Packet(packet)
|
||||
case 6:
|
||||
routeSession.IPVersion = 6
|
||||
ipHdr = clashtcpip.IPv6Packet(packet)
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
routeSession.Network = ipHdr.Protocol()
|
||||
switch routeSession.Network {
|
||||
case clashtcpip.TCP:
|
||||
tcpHdr := clashtcpip.TCPPacket(ipHdr.Payload())
|
||||
routeSession.Destination = netip.AddrPortFrom(ipHdr.SourceIP(), tcpHdr.SourcePort())
|
||||
if !m.ipRewrite {
|
||||
routeSession.Source = netip.AddrPortFrom(ipHdr.DestinationIP(), tcpHdr.DestinationPort())
|
||||
}
|
||||
case clashtcpip.UDP:
|
||||
udpHdr := clashtcpip.UDPPacket(ipHdr.Payload())
|
||||
routeSession.Destination = netip.AddrPortFrom(ipHdr.SourceIP(), udpHdr.SourcePort())
|
||||
if !m.ipRewrite {
|
||||
routeSession.Source = netip.AddrPortFrom(ipHdr.DestinationIP(), udpHdr.DestinationPort())
|
||||
}
|
||||
default:
|
||||
routeSession.Destination = netip.AddrPortFrom(ipHdr.SourceIP(), 0)
|
||||
if !m.ipRewrite {
|
||||
routeSession.Source = netip.AddrPortFrom(ipHdr.DestinationIP(), 0)
|
||||
}
|
||||
}
|
||||
m.access.RLock()
|
||||
context, loaded := m.sessions[routeSession]
|
||||
m.access.RUnlock()
|
||||
if !loaded {
|
||||
return false, nil
|
||||
}
|
||||
return true, context.WritePacket(packet)
|
||||
}
|
||||
|
||||
type NatWriter struct {
|
||||
inet4Address netip.Addr
|
||||
inet6Address netip.Addr
|
||||
}
|
||||
|
||||
func NewNatWriter(inet4Address netip.Addr, inet6Address netip.Addr) *NatWriter {
|
||||
return &NatWriter{
|
||||
inet4Address: inet4Address,
|
||||
inet6Address: inet6Address,
|
||||
}
|
||||
}
|
||||
|
||||
func (w *NatWriter) RewritePacket(packet []byte) {
|
||||
var ipHdr clashtcpip.IP
|
||||
var bindAddr netip.Addr
|
||||
switch ipVersion := packet[0] >> 4; ipVersion {
|
||||
case 4:
|
||||
ipHdr = clashtcpip.IPv4Packet(packet)
|
||||
bindAddr = w.inet4Address
|
||||
case 6:
|
||||
ipHdr = clashtcpip.IPv6Packet(packet)
|
||||
bindAddr = w.inet6Address
|
||||
default:
|
||||
return
|
||||
}
|
||||
ipHdr.SetSourceIP(bindAddr)
|
||||
switch ipHdr.Protocol() {
|
||||
case clashtcpip.TCP:
|
||||
tcpHdr := clashtcpip.TCPPacket(ipHdr.Payload())
|
||||
tcpHdr.ResetChecksum(ipHdr.PseudoSum())
|
||||
case clashtcpip.UDP:
|
||||
udpHdr := clashtcpip.UDPPacket(ipHdr.Payload())
|
||||
udpHdr.ResetChecksum(ipHdr.PseudoSum())
|
||||
default:
|
||||
}
|
||||
ipHdr.ResetChecksum()
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
//go:build with_gvisor
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
func (w *NatWriter) RewritePacketBuffer(packetBuffer *stack.PacketBuffer) {
|
||||
var bindAddr tcpip.Address
|
||||
if packetBuffer.NetworkProtocolNumber == header.IPv4ProtocolNumber {
|
||||
bindAddr = tcpip.Address(w.inet4Address.AsSlice())
|
||||
} else {
|
||||
bindAddr = tcpip.Address(w.inet6Address.AsSlice())
|
||||
}
|
||||
var ipHdr header.Network
|
||||
switch packetBuffer.NetworkProtocolNumber {
|
||||
case header.IPv4ProtocolNumber:
|
||||
ipHdr = header.IPv4(packetBuffer.NetworkHeader().Slice())
|
||||
case header.IPv6ProtocolNumber:
|
||||
ipHdr = header.IPv6(packetBuffer.NetworkHeader().Slice())
|
||||
default:
|
||||
return
|
||||
}
|
||||
oldAddr := ipHdr.SourceAddress()
|
||||
if checksumHdr, needChecksum := ipHdr.(header.ChecksummableNetwork); needChecksum {
|
||||
checksumHdr.SetSourceAddressWithChecksumUpdate(bindAddr)
|
||||
} else {
|
||||
ipHdr.SetSourceAddress(bindAddr)
|
||||
}
|
||||
switch packetBuffer.TransportProtocolNumber {
|
||||
case header.TCPProtocolNumber:
|
||||
tcpHdr := header.TCP(packetBuffer.TransportHeader().Slice())
|
||||
tcpHdr.UpdateChecksumPseudoHeaderAddress(oldAddr, bindAddr, true)
|
||||
case header.UDPProtocolNumber:
|
||||
udpHdr := header.UDP(packetBuffer.TransportHeader().Slice())
|
||||
udpHdr.UpdateChecksumPseudoHeaderAddress(oldAddr, bindAddr, true)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
//go:build !with_gvisor
|
||||
|
||||
package tun
|
||||
|
||||
import "github.com/sagernet/sing/common/buf"
|
||||
|
||||
type DirectDestination interface {
|
||||
WritePacket(buffer *buf.Buffer) error
|
||||
Close() error
|
||||
Timeout() bool
|
||||
}
|
||||
1
stack.go
1
stack.go
@@ -23,7 +23,6 @@ type StackOptions struct {
|
||||
Inet6Address []netip.Prefix
|
||||
EndpointIndependentNat bool
|
||||
UDPTimeout int64
|
||||
Router Router
|
||||
Handler Handler
|
||||
Logger logger.Logger
|
||||
ForwarderBindInterface bool
|
||||
|
||||
100
system.go
100
system.go
@@ -23,7 +23,6 @@ type System struct {
|
||||
tun Tun
|
||||
tunName string
|
||||
mtu uint32
|
||||
router Router
|
||||
handler Handler
|
||||
logger logger.Logger
|
||||
inet4Prefixes []netip.Prefix
|
||||
@@ -39,7 +38,6 @@ type System struct {
|
||||
tcpPort6 uint16
|
||||
tcpNat *TCPNat
|
||||
udpNat *udpnat.Service[netip.AddrPort]
|
||||
routeMapping *RouteMapping
|
||||
bindInterface bool
|
||||
interfaceFinder control.InterfaceFinder
|
||||
}
|
||||
@@ -58,7 +56,6 @@ func NewSystem(options StackOptions) (Stack, error) {
|
||||
tunName: options.Name,
|
||||
mtu: options.MTU,
|
||||
udpTimeout: options.UDPTimeout,
|
||||
router: options.Router,
|
||||
handler: options.Handler,
|
||||
logger: options.Logger,
|
||||
inet4Prefixes: options.Inet4Address,
|
||||
@@ -66,9 +63,6 @@ func NewSystem(options StackOptions) (Stack, error) {
|
||||
bindInterface: options.ForwarderBindInterface,
|
||||
interfaceFinder: options.InterfaceFinder,
|
||||
}
|
||||
if stack.router != nil {
|
||||
stack.routeMapping = NewRouteMapping(options.UDPTimeout)
|
||||
}
|
||||
if len(options.Inet4Address) > 0 {
|
||||
if options.Inet4Address[0].Bits() == 32 {
|
||||
return nil, E.New("need one more IPv4 address in first prefix for system stack")
|
||||
@@ -97,6 +91,10 @@ func (s *System) Close() error {
|
||||
}
|
||||
|
||||
func (s *System) Start() error {
|
||||
err := fixWindowsFirewall()
|
||||
if err != nil {
|
||||
return E.Cause(err, "fix windows firewall for system stack")
|
||||
}
|
||||
var listener net.ListenConfig
|
||||
if s.bindInterface {
|
||||
listener.Control = control.Append(listener.Control, func(network, address string, conn syscall.RawConn) error {
|
||||
@@ -271,21 +269,6 @@ func (s *System) processIPv4TCP(packet clashtcpip.IPv4Packet, header clashtcpip.
|
||||
packet.SetDestinationIP(session.Source.Addr())
|
||||
header.SetDestinationPort(session.Source.Port())
|
||||
} else {
|
||||
if s.router != nil {
|
||||
session := RouteSession{4, syscall.IPPROTO_TCP, source, destination}
|
||||
action := s.routeMapping.Lookup(session, func() RouteAction {
|
||||
return s.router.RouteConnection(session, &systemTCPDirectPacketWriter4{s.tun, source})
|
||||
})
|
||||
switch actionType := action.(type) {
|
||||
case *ActionBlock:
|
||||
// TODO: send ICMP unreachable
|
||||
return nil
|
||||
case *ActionDirect:
|
||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
||||
return E.Cause(err, "route ipv4 tcp packet")
|
||||
})
|
||||
}
|
||||
}
|
||||
natPort := s.tcpNat.Lookup(source, destination)
|
||||
packet.SetSourceIP(s.inet4Address)
|
||||
header.SetSourcePort(natPort)
|
||||
@@ -312,21 +295,6 @@ func (s *System) processIPv6TCP(packet clashtcpip.IPv6Packet, header clashtcpip.
|
||||
packet.SetDestinationIP(session.Source.Addr())
|
||||
header.SetDestinationPort(session.Source.Port())
|
||||
} else {
|
||||
if s.router != nil {
|
||||
session := RouteSession{6, syscall.IPPROTO_TCP, source, destination}
|
||||
action := s.routeMapping.Lookup(session, func() RouteAction {
|
||||
return s.router.RouteConnection(session, &systemTCPDirectPacketWriter6{s.tun, source})
|
||||
})
|
||||
switch actionType := action.(type) {
|
||||
case *ActionBlock:
|
||||
// TODO: send RST
|
||||
return nil
|
||||
case *ActionDirect:
|
||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
||||
return E.Cause(err, "route ipv6 tcp packet")
|
||||
})
|
||||
}
|
||||
}
|
||||
natPort := s.tcpNat.Lookup(source, destination)
|
||||
packet.SetSourceIP(s.inet6Address)
|
||||
header.SetSourcePort(natPort)
|
||||
@@ -350,21 +318,6 @@ func (s *System) processIPv4UDP(packet clashtcpip.IPv4Packet, header clashtcpip.
|
||||
if !destination.Addr().IsGlobalUnicast() {
|
||||
return common.Error(s.tun.Write(packet))
|
||||
}
|
||||
if s.router != nil {
|
||||
routeSession := RouteSession{4, syscall.IPPROTO_UDP, source, destination}
|
||||
action := s.routeMapping.Lookup(routeSession, func() RouteAction {
|
||||
return s.router.RouteConnection(routeSession, &systemUDPDirectPacketWriter4{s.tun, source})
|
||||
})
|
||||
switch actionType := action.(type) {
|
||||
case *ActionBlock:
|
||||
// TODO: send icmp unreachable
|
||||
return nil
|
||||
case *ActionDirect:
|
||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
||||
return E.Cause(err, "route ipv4 udp packet")
|
||||
})
|
||||
}
|
||||
}
|
||||
data := buf.As(header.Payload())
|
||||
if data.Len() == 0 {
|
||||
return nil
|
||||
@@ -388,21 +341,6 @@ func (s *System) processIPv6UDP(packet clashtcpip.IPv6Packet, header clashtcpip.
|
||||
if !destination.Addr().IsGlobalUnicast() {
|
||||
return common.Error(s.tun.Write(packet))
|
||||
}
|
||||
if s.router != nil {
|
||||
routeSession := RouteSession{6, syscall.IPPROTO_UDP, source, destination}
|
||||
action := s.routeMapping.Lookup(routeSession, func() RouteAction {
|
||||
return s.router.RouteConnection(routeSession, &systemUDPDirectPacketWriter6{s.tun, source})
|
||||
})
|
||||
switch actionType := action.(type) {
|
||||
case *ActionBlock:
|
||||
// TODO: send icmp unreachable
|
||||
return nil
|
||||
case *ActionDirect:
|
||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
||||
return E.Cause(err, "route ipv6 udp packet")
|
||||
})
|
||||
}
|
||||
}
|
||||
data := buf.As(header.Payload())
|
||||
if data.Len() == 0 {
|
||||
return nil
|
||||
@@ -421,21 +359,6 @@ func (s *System) processIPv6UDP(packet clashtcpip.IPv6Packet, header clashtcpip.
|
||||
}
|
||||
|
||||
func (s *System) processIPv4ICMP(packet clashtcpip.IPv4Packet, header clashtcpip.ICMPPacket) error {
|
||||
if s.router != nil {
|
||||
routeSession := RouteSession{4, clashtcpip.ICMP, netip.AddrPortFrom(packet.SourceIP(), 0), netip.AddrPortFrom(packet.DestinationIP(), 0)}
|
||||
action := s.routeMapping.Lookup(routeSession, func() RouteAction {
|
||||
return s.router.RouteConnection(routeSession, &systemICMPDirectPacketWriter4{s.tun, packet.SourceIP()})
|
||||
})
|
||||
switch actionType := action.(type) {
|
||||
case *ActionBlock:
|
||||
// TODO: send icmp unreachable
|
||||
return nil
|
||||
case *ActionDirect:
|
||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
||||
return E.Cause(err, "route ipv4 icmp packet")
|
||||
})
|
||||
}
|
||||
}
|
||||
if header.Type() != clashtcpip.ICMPTypePingRequest || header.Code() != 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -449,21 +372,6 @@ func (s *System) processIPv4ICMP(packet clashtcpip.IPv4Packet, header clashtcpip
|
||||
}
|
||||
|
||||
func (s *System) processIPv6ICMP(packet clashtcpip.IPv6Packet, header clashtcpip.ICMPv6Packet) error {
|
||||
if s.router != nil {
|
||||
routeSession := RouteSession{6, clashtcpip.ICMPv6, netip.AddrPortFrom(packet.SourceIP(), 0), netip.AddrPortFrom(packet.DestinationIP(), 0)}
|
||||
action := s.routeMapping.Lookup(routeSession, func() RouteAction {
|
||||
return s.router.RouteConnection(routeSession, &systemICMPDirectPacketWriter6{s.tun, packet.SourceIP()})
|
||||
})
|
||||
switch actionType := action.(type) {
|
||||
case *ActionBlock:
|
||||
// TODO: send icmp unreachable
|
||||
return nil
|
||||
case *ActionDirect:
|
||||
return E.Append(nil, actionType.WritePacket(buf.As(packet).ToOwned()), func(err error) error {
|
||||
return E.Cause(err, "route ipv6 icmp packet")
|
||||
})
|
||||
}
|
||||
}
|
||||
if header.Type() != clashtcpip.ICMPv6EchoRequest || header.Code() != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
7
system_nonwindows.go
Normal file
7
system_nonwindows.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build !windows
|
||||
|
||||
package tun
|
||||
|
||||
func fixWindowsFirewall() error {
|
||||
return nil
|
||||
}
|
||||
25
system_windows.go
Normal file
25
system_windows.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/sagernet/sing-tun/internal/winfw"
|
||||
)
|
||||
|
||||
func fixWindowsFirewall() error {
|
||||
absPath, err := filepath.Abs(os.Args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rule := winfw.FWRule{
|
||||
Name: "sing-tun (" + absPath + ")",
|
||||
ApplicationName: absPath,
|
||||
Enabled: true,
|
||||
Protocol: winfw.NET_FW_IP_PROTOCOL_TCP,
|
||||
Direction: winfw.NET_FW_RULE_DIR_IN,
|
||||
Action: winfw.NET_FW_ACTION_ALLOW,
|
||||
}
|
||||
_, err = winfw.FirewallRuleAddAdvanced(rule)
|
||||
return err
|
||||
}
|
||||
@@ -25,8 +25,8 @@ type NativeTun struct {
|
||||
tunFile *os.File
|
||||
tunWriter N.VectorisedWriter
|
||||
mtu uint32
|
||||
inet4Address string
|
||||
inet6Address string
|
||||
inet4Address [4]byte
|
||||
inet6Address [16]byte
|
||||
}
|
||||
|
||||
func New(options Options) (Tun, error) {
|
||||
@@ -57,10 +57,10 @@ func New(options Options) (Tun, error) {
|
||||
mtu: options.MTU,
|
||||
}
|
||||
if len(options.Inet4Address) > 0 {
|
||||
nativeTun.inet4Address = string(options.Inet4Address[0].Addr().AsSlice())
|
||||
nativeTun.inet4Address = options.Inet4Address[0].Addr().As4()
|
||||
}
|
||||
if len(options.Inet6Address) > 0 {
|
||||
nativeTun.inet6Address = string(options.Inet6Address[0].Addr().AsSlice())
|
||||
nativeTun.inet6Address = options.Inet6Address[0].Addr().As16()
|
||||
}
|
||||
var ok bool
|
||||
nativeTun.tunWriter, ok = bufio.CreateVectorisedWriter(nativeTun.tunFile)
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"github.com/sagernet/gvisor/pkg/buffer"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
var _ GVisorTun = (*NativeTun)(nil)
|
||||
@@ -56,9 +55,9 @@ func (e *DarwinEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
func (e *DarwinEndpoint) dispatchLoop() {
|
||||
_buffer := buf.StackNewSize(int(e.tun.mtu) + 4)
|
||||
defer common.KeepAlive(_buffer)
|
||||
buffer := common.Dup(_buffer)
|
||||
defer buffer.Release()
|
||||
data := buffer.FreeBytes()
|
||||
packetBuffer := common.Dup(_buffer)
|
||||
defer packetBuffer.Release()
|
||||
data := packetBuffer.FreeBytes()
|
||||
for {
|
||||
n, err := e.tun.tunFile.Read(data)
|
||||
if err != nil {
|
||||
@@ -69,13 +68,13 @@ func (e *DarwinEndpoint) dispatchLoop() {
|
||||
switch header.IPVersion(packet) {
|
||||
case header.IPv4Version:
|
||||
networkProtocol = header.IPv4ProtocolNumber
|
||||
if header.IPv4(packet).DestinationAddress() == tcpip.Address(e.tun.inet4Address) {
|
||||
if header.IPv4(packet).DestinationAddress().As4() == e.tun.inet4Address {
|
||||
e.tun.tunFile.Write(data[:n])
|
||||
continue
|
||||
}
|
||||
case header.IPv6Version:
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
if header.IPv6(packet).DestinationAddress() == tcpip.Address(e.tun.inet6Address) {
|
||||
if header.IPv6(packet).DestinationAddress().As16() == e.tun.inet6Address {
|
||||
e.tun.tunFile.Write(data[:n])
|
||||
continue
|
||||
}
|
||||
@@ -84,7 +83,7 @@ func (e *DarwinEndpoint) dispatchLoop() {
|
||||
continue
|
||||
}
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Payload: bufferv2.MakeWithData(data[4:n]),
|
||||
Payload: buffer.MakeWithData(data[4:n]),
|
||||
IsForwardedPacket: true,
|
||||
})
|
||||
pkt.NetworkProtocolNumber = networkProtocol
|
||||
@@ -109,7 +108,7 @@ func (e *DarwinEndpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
return header.ARPHardwareNone
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) AddHeader(buffer *stack.PacketBuffer) {
|
||||
func (e *DarwinEndpoint) AddHeader(buffer stack.PacketBufferPtr) {
|
||||
}
|
||||
|
||||
func (e *DarwinEndpoint) WritePackets(packetBufferList stack.PacketBufferList) (int, tcpip.Error) {
|
||||
|
||||
17
tun_linux.go
17
tun_linux.go
@@ -167,7 +167,7 @@ func (t *NativeTun) configure(tunLink netlink.Link) error {
|
||||
return err
|
||||
}
|
||||
|
||||
setSearchDomainForSystemdResolved(t.options.Name)
|
||||
t.setSearchDomainForSystemdResolved()
|
||||
|
||||
if t.options.AutoRoute && runtime.GOOS == "android" {
|
||||
t.interfaceCallback = t.options.InterfaceMonitor.RegisterCallback(t.routeUpdate)
|
||||
@@ -599,10 +599,21 @@ func (t *NativeTun) routeUpdate(event int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setSearchDomainForSystemdResolved(interfaceName string) {
|
||||
func (t *NativeTun) setSearchDomainForSystemdResolved() {
|
||||
ctlPath, err := exec.LookPath("resolvectl")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
shell.Exec(ctlPath, "domain", interfaceName, "~.").Run()
|
||||
var dnsServer []netip.Addr
|
||||
if len(t.options.Inet4Address) > 0 {
|
||||
dnsServer = append(dnsServer, t.options.Inet4Address[0].Addr().Next())
|
||||
}
|
||||
if len(t.options.Inet6Address) > 0 {
|
||||
dnsServer = append(dnsServer, t.options.Inet6Address[0].Addr().Next())
|
||||
}
|
||||
shell.Exec(ctlPath, "domain", t.options.Name, "~.").Start()
|
||||
if t.options.AutoRoute {
|
||||
shell.Exec(ctlPath, "default-route", t.options.Name, "true").Start()
|
||||
shell.Exec(ctlPath, append([]string{"dns", t.options.Name}, common.Map(dnsServer, netip.Addr.String)...)...).Start()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/link/fdbased"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
var _ GVisorTun = (*NativeTun)(nil)
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
"github.com/sagernet/gvisor/pkg/buffer"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/header"
|
||||
"github.com/sagernet/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
var _ GVisorTun = (*NativeTun)(nil)
|
||||
@@ -51,16 +51,16 @@ func (e *WintunEndpoint) Attach(dispatcher stack.NetworkDispatcher) {
|
||||
|
||||
func (e *WintunEndpoint) dispatchLoop() {
|
||||
for {
|
||||
var buffer bufferv2.Buffer
|
||||
var packetBuffer buffer.Buffer
|
||||
err := e.tun.ReadFunc(func(b []byte) {
|
||||
buffer = bufferv2.MakeWithData(b)
|
||||
packetBuffer = buffer.MakeWithData(b)
|
||||
})
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
ihl, ok := buffer.PullUp(0, 1)
|
||||
ihl, ok := packetBuffer.PullUp(0, 1)
|
||||
if !ok {
|
||||
buffer.Release()
|
||||
packetBuffer.Release()
|
||||
continue
|
||||
}
|
||||
var networkProtocol tcpip.NetworkProtocolNumber
|
||||
@@ -70,12 +70,12 @@ func (e *WintunEndpoint) dispatchLoop() {
|
||||
case header.IPv6Version:
|
||||
networkProtocol = header.IPv6ProtocolNumber
|
||||
default:
|
||||
e.tun.Write(buffer.Flatten())
|
||||
buffer.Release()
|
||||
e.tun.Write(packetBuffer.Flatten())
|
||||
packetBuffer.Release()
|
||||
continue
|
||||
}
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Payload: buffer,
|
||||
Payload: packetBuffer,
|
||||
IsForwardedPacket: true,
|
||||
})
|
||||
dispatcher := e.dispatcher
|
||||
@@ -99,7 +99,7 @@ func (e *WintunEndpoint) ARPHardwareType() header.ARPHardwareType {
|
||||
return header.ARPHardwareNone
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) AddHeader(buffer *stack.PacketBuffer) {
|
||||
func (e *WintunEndpoint) AddHeader(buffer stack.PacketBufferPtr) {
|
||||
}
|
||||
|
||||
func (e *WintunEndpoint) WritePackets(packetBufferList stack.PacketBufferList) (int, tcpip.Error) {
|
||||
|
||||
Reference in New Issue
Block a user