mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-06-05 10:47:32 +03:00
Add L3 routing support
This commit is contained in:
@@ -8,10 +8,12 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/wireguard-go/tun"
|
||||
wgTun "github.com/sagernet/wireguard-go/tun"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/bufferv2"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
@@ -25,33 +27,38 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
|
||||
)
|
||||
|
||||
var _ Device = (*StackDevice)(nil)
|
||||
var _ NatDevice = (*StackDevice)(nil)
|
||||
|
||||
const defaultNIC tcpip.NICID = 1
|
||||
|
||||
type StackDevice struct {
|
||||
stack *stack.Stack
|
||||
mtu uint32
|
||||
events chan tun.Event
|
||||
outbound chan *stack.PacketBuffer
|
||||
done chan struct{}
|
||||
dispatcher stack.NetworkDispatcher
|
||||
addr4 tcpip.Address
|
||||
addr6 tcpip.Address
|
||||
stack *stack.Stack
|
||||
mtu uint32
|
||||
events chan wgTun.Event
|
||||
outbound chan *stack.PacketBuffer
|
||||
packetOutbound chan *buf.Buffer
|
||||
done chan struct{}
|
||||
dispatcher stack.NetworkDispatcher
|
||||
addr4 tcpip.Address
|
||||
addr6 tcpip.Address
|
||||
mapping *tun.NatMapping
|
||||
writer *tun.NatWriter
|
||||
}
|
||||
|
||||
func NewStackDevice(localAddresses []netip.Prefix, mtu uint32) (*StackDevice, error) {
|
||||
func NewStackDevice(localAddresses []netip.Prefix, mtu uint32, ipRewrite bool) (*StackDevice, error) {
|
||||
ipStack := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
|
||||
TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol, icmp.NewProtocol4, icmp.NewProtocol6},
|
||||
HandleLocal: true,
|
||||
})
|
||||
tunDevice := &StackDevice{
|
||||
stack: ipStack,
|
||||
mtu: mtu,
|
||||
events: make(chan tun.Event, 1),
|
||||
outbound: make(chan *stack.PacketBuffer, 256),
|
||||
done: make(chan struct{}),
|
||||
stack: ipStack,
|
||||
mtu: mtu,
|
||||
events: make(chan wgTun.Event, 1),
|
||||
outbound: make(chan *stack.PacketBuffer, 256),
|
||||
packetOutbound: make(chan *buf.Buffer, 256),
|
||||
done: make(chan struct{}),
|
||||
mapping: tun.NewNatMapping(ipRewrite),
|
||||
}
|
||||
err := ipStack.CreateNIC(defaultNIC, (*wireEndpoint)(tunDevice))
|
||||
if err != nil {
|
||||
@@ -77,6 +84,9 @@ func NewStackDevice(localAddresses []netip.Prefix, mtu uint32) (*StackDevice, er
|
||||
return nil, E.New("parse local address ", protoAddr.AddressWithPrefix, ": ", err.String())
|
||||
}
|
||||
}
|
||||
if ipRewrite {
|
||||
tunDevice.writer = tun.NewNatWriter(tunDevice.Inet4Address(), tunDevice.Inet6Address())
|
||||
}
|
||||
sOpt := tcpip.TCPSACKEnabled(true)
|
||||
ipStack.SetTransportProtocolOption(tcp.ProtocolNumber, &sOpt)
|
||||
cOpt := tcpip.CongestionControlOption("cubic")
|
||||
@@ -144,8 +154,16 @@ func (w *StackDevice) ListenPacket(ctx context.Context, destination M.Socksaddr)
|
||||
return udpConn, nil
|
||||
}
|
||||
|
||||
func (w *StackDevice) Inet4Address() netip.Addr {
|
||||
return M.AddrFromIP(net.IP(w.addr4))
|
||||
}
|
||||
|
||||
func (w *StackDevice) Inet6Address() netip.Addr {
|
||||
return M.AddrFromIP(net.IP(w.addr6))
|
||||
}
|
||||
|
||||
func (w *StackDevice) Start() error {
|
||||
w.events <- tun.EventUp
|
||||
w.events <- wgTun.EventUp
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -165,6 +183,10 @@ func (w *StackDevice) Read(p []byte, offset int) (n int, err error) {
|
||||
n += copy(p[n:], slice)
|
||||
}
|
||||
return
|
||||
case packet := <-w.packetOutbound:
|
||||
defer packet.Release()
|
||||
n = copy(p[offset:], packet.Bytes())
|
||||
return
|
||||
case <-w.done:
|
||||
return 0, os.ErrClosed
|
||||
}
|
||||
@@ -175,6 +197,10 @@ func (w *StackDevice) Write(p []byte, offset int) (n int, err error) {
|
||||
if len(p) == 0 {
|
||||
return
|
||||
}
|
||||
handled, err := w.mapping.WritePacket(p)
|
||||
if handled {
|
||||
return len(p), err
|
||||
}
|
||||
var networkProtocol tcpip.NetworkProtocolNumber
|
||||
switch header.IPVersion(p) {
|
||||
case header.IPv4Version:
|
||||
@@ -203,7 +229,7 @@ func (w *StackDevice) Name() (string, error) {
|
||||
return "sing-box", nil
|
||||
}
|
||||
|
||||
func (w *StackDevice) Events() chan tun.Event {
|
||||
func (w *StackDevice) Events() chan wgTun.Event {
|
||||
return w.events
|
||||
}
|
||||
|
||||
@@ -222,6 +248,44 @@ func (w *StackDevice) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *StackDevice) CreateDestination(session tun.RouteSession, conn tun.RouteContext) tun.DirectDestination {
|
||||
w.mapping.CreateSession(session, conn)
|
||||
return &stackNatDestination{
|
||||
device: w,
|
||||
session: session,
|
||||
}
|
||||
}
|
||||
|
||||
type stackNatDestination struct {
|
||||
device *StackDevice
|
||||
session tun.RouteSession
|
||||
}
|
||||
|
||||
func (d *stackNatDestination) WritePacket(buffer *buf.Buffer) error {
|
||||
if d.device.writer != nil {
|
||||
d.device.writer.RewritePacket(buffer.Bytes())
|
||||
}
|
||||
d.device.packetOutbound <- buffer
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *stackNatDestination) WritePacketBuffer(buffer *stack.PacketBuffer) error {
|
||||
if d.device.writer != nil {
|
||||
d.device.writer.RewritePacketBuffer(buffer)
|
||||
}
|
||||
d.device.outbound <- buffer
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *stackNatDestination) Close() error {
|
||||
d.device.mapping.DeleteSession(d.session)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *stackNatDestination) Timeout() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var _ stack.LinkEndpoint = (*wireEndpoint)(nil)
|
||||
|
||||
type wireEndpoint StackDevice
|
||||
|
||||
Reference in New Issue
Block a user