mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-15 21:00:27 +00:00
222 lines
6.5 KiB
Go
222 lines
6.5 KiB
Go
package route
|
|
|
|
import (
|
|
"net"
|
|
"net/netip"
|
|
"os"
|
|
"sync"
|
|
|
|
"github.com/sagernet/sing/common/buf"
|
|
"github.com/sagernet/sing/common/bufio"
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
N "github.com/sagernet/sing/common/network"
|
|
)
|
|
|
|
type fakeIPNATPacketConn struct {
|
|
N.NetPacketConn
|
|
origin M.Socksaddr
|
|
destination M.Socksaddr
|
|
directAccess sync.RWMutex
|
|
directDestinations map[netip.Addr]struct{}
|
|
}
|
|
|
|
func newFakeIPNATPacketConn(conn N.NetPacketConn, origin M.Socksaddr, destination M.Socksaddr) *fakeIPNATPacketConn {
|
|
return &fakeIPNATPacketConn{
|
|
NetPacketConn: conn,
|
|
origin: origin,
|
|
destination: destination,
|
|
directDestinations: make(map[netip.Addr]struct{}),
|
|
}
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) rewriteReadDestination(destination M.Socksaddr) M.Socksaddr {
|
|
if destination.Addr == c.origin.Addr {
|
|
return M.Socksaddr{
|
|
Addr: c.destination.Addr,
|
|
Fqdn: c.destination.Fqdn,
|
|
Port: destination.Port,
|
|
}
|
|
}
|
|
if destination.Addr.IsValid() {
|
|
c.directAccess.RLock()
|
|
_, recorded := c.directDestinations[destination.Addr]
|
|
c.directAccess.RUnlock()
|
|
if !recorded {
|
|
c.directAccess.Lock()
|
|
c.directDestinations[destination.Addr] = struct{}{}
|
|
c.directAccess.Unlock()
|
|
}
|
|
}
|
|
return destination
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) rewriteWriteDestination(destination M.Socksaddr) M.Socksaddr {
|
|
if destination.Addr.IsValid() {
|
|
c.directAccess.RLock()
|
|
_, direct := c.directDestinations[destination.Addr]
|
|
c.directAccess.RUnlock()
|
|
if direct {
|
|
return destination
|
|
}
|
|
}
|
|
return M.Socksaddr{
|
|
Addr: c.origin.Addr,
|
|
Port: destination.Port,
|
|
}
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
|
n, addr, err = c.NetPacketConn.ReadFrom(p)
|
|
if err != nil {
|
|
return
|
|
}
|
|
addr = c.rewriteReadDestination(M.SocksaddrFromNet(addr)).UDPAddr()
|
|
return
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
|
return c.NetPacketConn.WriteTo(p, c.rewriteWriteDestination(M.SocksaddrFromNet(addr)).UDPAddr())
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
|
|
destination, err = c.NetPacketConn.ReadPacket(buffer)
|
|
if err != nil {
|
|
return
|
|
}
|
|
destination = c.rewriteReadDestination(destination)
|
|
return
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
|
return c.NetPacketConn.WritePacket(buffer, c.rewriteWriteDestination(destination))
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) CreateReadWaiter() (N.PacketReadWaiter, bool) {
|
|
waiter, created := bufio.CreatePacketReadWaiter(c.NetPacketConn)
|
|
if !created {
|
|
return nil, false
|
|
}
|
|
return &waitFakeIPNATPacketConn{c, waiter}, true
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) CreatePacketBatchReadWaiter() (N.PacketBatchReadWaiter, bool) {
|
|
waiter, created := bufio.CreatePacketBatchReadWaiter(c.NetPacketConn)
|
|
if !created {
|
|
return nil, false
|
|
}
|
|
return &batchWaitFakeIPNATPacketConn{c, waiter}, true
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) CreateConnectedPacketBatchReadWaiter() (N.ConnectedPacketBatchReadWaiter, bool) {
|
|
waiter, created := bufio.CreateConnectedPacketBatchReadWaiter(c.NetPacketConn)
|
|
if !created {
|
|
return nil, false
|
|
}
|
|
return &connectedBatchWaitFakeIPNATPacketConn{c, waiter}, true
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) CreatePacketBatchWriter() (N.PacketBatchWriter, bool) {
|
|
writer, created := bufio.CreatePacketBatchWriter(c.NetPacketConn)
|
|
if !created {
|
|
return nil, false
|
|
}
|
|
return &fakeIPNATPacketBatchWriter{c, writer}, true
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) CreateConnectedPacketBatchWriter() (N.ConnectedPacketBatchWriter, bool) {
|
|
return bufio.CreateConnectedPacketBatchWriter(c.NetPacketConn)
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) UpdateDestination(destinationAddress netip.Addr) {
|
|
c.destination = M.SocksaddrFrom(destinationAddress, c.destination.Port)
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) RemoteAddr() net.Addr {
|
|
return c.destination.UDPAddr()
|
|
}
|
|
|
|
func (c *fakeIPNATPacketConn) Upstream() any {
|
|
return c.NetPacketConn
|
|
}
|
|
|
|
type waitFakeIPNATPacketConn struct {
|
|
*fakeIPNATPacketConn
|
|
readWaiter N.PacketReadWaiter
|
|
}
|
|
|
|
func (c *waitFakeIPNATPacketConn) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) {
|
|
return c.readWaiter.InitializeReadWaiter(options)
|
|
}
|
|
|
|
func (c *waitFakeIPNATPacketConn) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) {
|
|
buffer, destination, err = c.readWaiter.WaitReadPacket()
|
|
if err != nil {
|
|
return
|
|
}
|
|
destination = c.rewriteReadDestination(destination)
|
|
return
|
|
}
|
|
|
|
type batchWaitFakeIPNATPacketConn struct {
|
|
*fakeIPNATPacketConn
|
|
readWaiter N.PacketBatchReadWaiter
|
|
}
|
|
|
|
func (c *batchWaitFakeIPNATPacketConn) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) {
|
|
return c.readWaiter.InitializeReadWaiter(options)
|
|
}
|
|
|
|
func (c *batchWaitFakeIPNATPacketConn) WaitReadPackets() (buffers []*buf.Buffer, destinations []M.Socksaddr, err error) {
|
|
buffers, destinations, err = c.readWaiter.WaitReadPackets()
|
|
if err != nil {
|
|
return
|
|
}
|
|
for index, destination := range destinations {
|
|
destinations[index] = c.rewriteReadDestination(destination)
|
|
}
|
|
return
|
|
}
|
|
|
|
type connectedBatchWaitFakeIPNATPacketConn struct {
|
|
*fakeIPNATPacketConn
|
|
readWaiter N.ConnectedPacketBatchReadWaiter
|
|
}
|
|
|
|
func (c *connectedBatchWaitFakeIPNATPacketConn) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) {
|
|
return c.readWaiter.InitializeReadWaiter(options)
|
|
}
|
|
|
|
func (c *connectedBatchWaitFakeIPNATPacketConn) WaitReadConnectedPackets() (buffers []*buf.Buffer, destination M.Socksaddr, err error) {
|
|
buffers, destination, err = c.readWaiter.WaitReadConnectedPackets()
|
|
if err != nil {
|
|
return
|
|
}
|
|
destination = c.rewriteReadDestination(destination)
|
|
return
|
|
}
|
|
|
|
type fakeIPNATPacketBatchWriter struct {
|
|
*fakeIPNATPacketConn
|
|
writer N.PacketBatchWriter
|
|
}
|
|
|
|
func (w *fakeIPNATPacketBatchWriter) WritePacketBatch(buffers []*buf.Buffer, destinations []M.Socksaddr) error {
|
|
if len(buffers) == 0 || len(buffers) != len(destinations) {
|
|
buf.ReleaseMulti(buffers)
|
|
return os.ErrInvalid
|
|
}
|
|
for index, destination := range destinations {
|
|
destinations[index] = w.rewriteWriteDestination(destination)
|
|
}
|
|
return w.writer.WritePacketBatch(buffers, destinations)
|
|
}
|
|
|
|
var (
|
|
_ bufio.NATPacketConn = (*fakeIPNATPacketConn)(nil)
|
|
_ N.PacketReadWaitCreator = (*fakeIPNATPacketConn)(nil)
|
|
_ N.PacketBatchReadWaitCreator = (*fakeIPNATPacketConn)(nil)
|
|
_ N.ConnectedPacketBatchReadWaitCreator = (*fakeIPNATPacketConn)(nil)
|
|
_ N.PacketBatchWriteCreator = (*fakeIPNATPacketConn)(nil)
|
|
_ N.ConnectedPacketBatchWriteCreator = (*fakeIPNATPacketConn)(nil)
|
|
)
|