Add redir tproxy and dns inbound

This commit is contained in:
世界
2022-07-15 08:42:02 +08:00
parent e13b72afca
commit 2c2eb31e18
19 changed files with 723 additions and 20 deletions

View File

@@ -28,6 +28,12 @@ func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, o
return NewShadowsocks(ctx, router, logger, options.Tag, options.ShadowsocksOptions)
case C.TypeTun:
return NewTun(ctx, router, logger, options.Tag, options.TunOptions)
case C.TypeRedirect:
return NewRedirect(ctx, router, logger, options.Tag, options.RedirectOptions), nil
case C.TypeTProxy:
return NewTProxy(ctx, router, logger, options.Tag, options.TProxyOptions), nil
case C.TypeDNS:
return NewDNS(ctx, router, logger, options.Tag, options.DNSOptions), nil
default:
return nil, E.New("unknown inbound type: ", options.Type)
}

View File

@@ -26,16 +26,17 @@ import (
var _ adapter.Inbound = (*myInboundAdapter)(nil)
type myInboundAdapter struct {
protocol string
network []string
ctx context.Context
router adapter.Router
logger log.ContextLogger
tag string
listenOptions option.ListenOptions
connHandler adapter.ConnectionHandler
packetHandler adapter.PacketHandler
packetUpstream any
protocol string
network []string
ctx context.Context
router adapter.Router
logger log.ContextLogger
tag string
listenOptions option.ListenOptions
connHandler adapter.ConnectionHandler
packetHandler adapter.PacketHandler
oobPacketHandler adapter.OOBPacketHandler
packetUpstream any
// http mixed
@@ -85,12 +86,20 @@ func (a *myInboundAdapter) Start() error {
a.packetForce6 = M.SocksaddrFromNet(udpConn.LocalAddr()).Addr.Is6()
a.packetOutboundClosed = make(chan struct{})
a.packetOutbound = make(chan *myInboundPacket)
if _, threadUnsafeHandler := common.Cast[N.ThreadUnsafeWriter](a.packetUpstream); !threadUnsafeHandler {
go a.loopUDPIn()
if a.oobPacketHandler != nil {
if _, threadUnsafeHandler := common.Cast[N.ThreadUnsafeWriter](a.packetUpstream); !threadUnsafeHandler {
go a.loopUDPOOBIn()
} else {
go a.loopUDPOOBInThreadSafe()
}
} else {
go a.loopUDPInThreadSafe()
if _, threadUnsafeHandler := common.Cast[N.ThreadUnsafeWriter](a.packetUpstream); !threadUnsafeHandler {
go a.loopUDPIn()
} else {
go a.loopUDPInThreadSafe()
}
go a.loopUDPOut()
}
go a.loopUDPOut()
a.logger.Info("udp server started at ", udpConn.LocalAddr())
}
if a.setSystemProxy {
@@ -194,6 +203,37 @@ func (a *myInboundAdapter) loopUDPIn() {
}
}
func (a *myInboundAdapter) loopUDPOOBIn() {
defer close(a.packetOutboundClosed)
_buffer := buf.StackNewPacket()
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
defer buffer.Release()
buffer.IncRef()
defer buffer.DecRef()
packetService := (*myInboundPacketAdapter)(a)
oob := make([]byte, 1024)
for {
buffer.Reset()
n, oobN, _, addr, err := a.udpConn.ReadMsgUDPAddrPort(buffer.FreeBytes(), oob)
if err != nil {
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.SniffEnabled = a.listenOptions.SniffEnabled
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
metadata.Network = C.NetworkUDP
metadata.Source = M.SocksaddrFromNetIP(addr)
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
if err != nil {
a.newError(E.Cause(err, "process packet from ", metadata.Source))
}
}
}
func (a *myInboundAdapter) loopUDPInThreadSafe() {
defer close(a.packetOutboundClosed)
packetService := (*myInboundPacketAdapter)(a)
@@ -220,6 +260,33 @@ func (a *myInboundAdapter) loopUDPInThreadSafe() {
}
}
func (a *myInboundAdapter) loopUDPOOBInThreadSafe() {
defer close(a.packetOutboundClosed)
packetService := (*myInboundPacketAdapter)(a)
oob := make([]byte, 1024)
for {
buffer := buf.NewPacket()
n, oobN, _, addr, err := a.udpConn.ReadMsgUDPAddrPort(buffer.FreeBytes(), oob)
if err != nil {
buffer.Release()
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.SniffEnabled = a.listenOptions.SniffEnabled
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
metadata.Network = C.NetworkUDP
metadata.Source = M.SocksaddrFromNetIP(addr)
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
if err != nil {
buffer.Release()
a.newError(E.Cause(err, "process packet from ", metadata.Source))
}
}
}
func (a *myInboundAdapter) loopUDPOut() {
for {
select {

View File

@@ -46,7 +46,13 @@ func NewDirect(ctx context.Context, router adapter.Router, logger log.ContextLog
inbound.overrideOption = 3
inbound.overrideDestination = M.Socksaddr{Port: options.OverridePort}
}
inbound.udpNat = udpnat.New[netip.AddrPort](options.UDPTimeout, inbound.upstreamContextHandler())
var udpTimeout int64
if options.UDPTimeout != 0 {
udpTimeout = options.UDPTimeout
} else {
udpTimeout = 300
}
inbound.udpNat = udpnat.New[netip.AddrPort](udpTimeout, inbound.upstreamContextHandler())
inbound.connHandler = inbound
inbound.packetHandler = inbound
inbound.packetUpstream = inbound.udpNat
@@ -79,6 +85,8 @@ func (d *Direct) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.B
case 3:
metadata.Destination.Port = d.overrideDestination.Port
}
d.udpNat.NewPacketDirect(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), metadata.Source.AddrPort(), conn, buffer, adapter.UpstreamMetadata(metadata))
d.udpNat.NewContextPacket(ctx, metadata.Source.AddrPort(), buffer, adapter.UpstreamMetadata(metadata), func(natConn N.PacketConn) (context.Context, N.PacketWriter) {
return adapter.WithContext(log.ContextWithNewID(ctx), &metadata), natConn
})
return nil
}

View File

@@ -5,16 +5,59 @@ import (
"encoding/binary"
"io"
"net"
"net/netip"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/udpnat"
"golang.org/x/net/dns/dnsmessage"
)
type DNS struct {
myInboundAdapter
udpNat *udpnat.Service[netip.AddrPort]
}
func NewDNS(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DNSInboundOptions) *DNS {
dns := &DNS{
myInboundAdapter: myInboundAdapter{
protocol: C.TypeTProxy,
network: options.Network.Build(),
ctx: ctx,
router: router,
logger: logger,
tag: tag,
listenOptions: options.ListenOptions,
},
}
dns.connHandler = dns
dns.packetHandler = dns
dns.udpNat = udpnat.New[netip.AddrPort](10, adapter.NewUpstreamContextHandler(nil, dns.newPacketConnection, dns))
dns.packetUpstream = dns.udpNat
return dns
}
func (d *DNS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
return NewDNSConnection(ctx, d.router, d.logger, conn, metadata)
}
func (d *DNS) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error {
d.udpNat.NewContextPacket(ctx, metadata.Source.AddrPort(), buffer, adapter.UpstreamMetadata(metadata), func(natConn N.PacketConn) (context.Context, N.PacketWriter) {
return adapter.WithContext(log.ContextWithNewID(ctx), &metadata), natConn
})
return nil
}
func (d *DNS) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return NewDNSPacketConnection(ctx, d.router, d.logger, conn, metadata)
}
func NewDNSConnection(ctx context.Context, router adapter.Router, logger log.ContextLogger, conn net.Conn, metadata adapter.InboundContext) error {
ctx = adapter.WithContext(ctx, &metadata)
_buffer := buf.StackNewSize(1024)

43
inbound/redirect.go Normal file
View File

@@ -0,0 +1,43 @@
package inbound
import (
"context"
"net"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/redir"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
)
type Redirect struct {
myInboundAdapter
}
func NewRedirect(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.RedirectInboundOptions) *Redirect {
redirect := &Redirect{
myInboundAdapter{
protocol: C.TypeRedirect,
network: []string{C.NetworkTCP},
ctx: ctx,
router: router,
logger: logger,
tag: tag,
listenOptions: options.ListenOptions,
},
}
redirect.connHandler = redirect
return redirect
}
func (r *Redirect) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
destination, err := redir.GetOriginalDestination(conn)
if err != nil {
return E.Cause(err, "get redirect destination")
}
metadata.Destination = M.SocksaddrFromNetIP(destination)
return r.newConnection(ctx, conn, metadata)
}

108
inbound/tproxy.go Normal file
View File

@@ -0,0 +1,108 @@
package inbound
import (
"context"
"net"
"net/netip"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/redir"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"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/sing/common/udpnat"
)
type TProxy struct {
myInboundAdapter
udpNat *udpnat.Service[netip.AddrPort]
}
func NewTProxy(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TProxyInboundOptions) *TProxy {
tproxy := &TProxy{
myInboundAdapter: myInboundAdapter{
protocol: C.TypeTProxy,
network: options.Network.Build(),
ctx: ctx,
router: router,
logger: logger,
tag: tag,
listenOptions: options.ListenOptions,
},
}
var udpTimeout int64
if options.UDPTimeout != 0 {
udpTimeout = options.UDPTimeout
} else {
udpTimeout = 300
}
tproxy.connHandler = tproxy
tproxy.oobPacketHandler = tproxy
tproxy.udpNat = udpnat.New[netip.AddrPort](udpTimeout, tproxy.upstreamContextHandler())
tproxy.packetUpstream = tproxy.udpNat
return tproxy
}
func (t *TProxy) Start() error {
err := t.myInboundAdapter.Start()
if err != nil {
return err
}
if t.tcpListener != nil {
tcpFd, err := common.GetFileDescriptor(t.tcpListener)
if err != nil {
return err
}
err = redir.TProxy(tcpFd, M.SocksaddrFromNet(t.tcpListener.Addr()).Addr.Is6())
if err != nil {
return E.Cause(err, "configure tproxy TCP listener")
}
}
if t.udpConn != nil {
udpFd, err := common.GetFileDescriptor(t.udpConn)
if err != nil {
return err
}
err = redir.TProxyUDP(udpFd, M.SocksaddrFromNet(t.udpConn.LocalAddr()).Addr.Is6())
if err != nil {
return E.Cause(err, "configure tproxy UDP listener")
}
}
return nil
}
func (t *TProxy) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
metadata.Destination = M.SocksaddrFromNet(conn.LocalAddr())
return t.newConnection(ctx, conn, metadata)
}
func (t *TProxy) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, oob []byte, metadata adapter.InboundContext) error {
destination, err := redir.GetOriginalDestinationFromOOB(oob)
if err != nil {
return E.Cause(err, "get tproxy destination")
}
metadata.Destination = M.SocksaddrFromNetIP(destination)
t.udpNat.NewContextPacket(ctx, metadata.Source.AddrPort(), buffer, adapter.UpstreamMetadata(metadata), func(natConn N.PacketConn) (context.Context, N.PacketWriter) {
return adapter.WithContext(log.ContextWithNewID(ctx), &metadata), &tproxyPacketWriter{natConn}
})
return nil
}
type tproxyPacketWriter struct {
source N.PacketConn
}
func (w *tproxyPacketWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
defer buffer.Release()
udpConn, err := redir.DialUDP(destination.UDPAddr(), M.SocksaddrFromNet(w.source.LocalAddr()).UDPAddr())
if err != nil {
return E.Cause(err, "tproxy udp write back")
}
defer udpConn.Close()
return common.Error(udpConn.Write(buffer.Bytes()))
}