2024-11-01 16:39:02 +00:00
|
|
|
package listener
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net"
|
2024-11-07 13:44:04 +00:00
|
|
|
"net/netip"
|
2024-11-01 16:39:02 +00:00
|
|
|
"sync/atomic"
|
|
|
|
|
|
|
|
"github.com/sagernet/sing-box/adapter"
|
|
|
|
"github.com/sagernet/sing-box/common/settings"
|
|
|
|
"github.com/sagernet/sing-box/option"
|
|
|
|
"github.com/sagernet/sing/common"
|
|
|
|
E "github.com/sagernet/sing/common/exceptions"
|
|
|
|
"github.com/sagernet/sing/common/logger"
|
|
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
|
|
N "github.com/sagernet/sing/common/network"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Listener struct {
|
|
|
|
ctx context.Context
|
|
|
|
logger logger.ContextLogger
|
|
|
|
network []string
|
|
|
|
listenOptions option.ListenOptions
|
|
|
|
connHandler adapter.ConnectionHandlerEx
|
|
|
|
packetHandler adapter.PacketHandlerEx
|
|
|
|
oobPacketHandler adapter.OOBPacketHandlerEx
|
|
|
|
threadUnsafePacketWriter bool
|
|
|
|
disablePacketOutput bool
|
|
|
|
setSystemProxy bool
|
|
|
|
systemProxySOCKS bool
|
|
|
|
|
|
|
|
tcpListener net.Listener
|
|
|
|
systemProxy settings.SystemProxy
|
|
|
|
udpConn *net.UDPConn
|
|
|
|
udpAddr M.Socksaddr
|
|
|
|
packetOutbound chan *N.PacketBuffer
|
|
|
|
packetOutboundClosed chan struct{}
|
|
|
|
shutdown atomic.Bool
|
|
|
|
}
|
|
|
|
|
|
|
|
type Options struct {
|
|
|
|
Context context.Context
|
|
|
|
Logger logger.ContextLogger
|
|
|
|
Network []string
|
|
|
|
Listen option.ListenOptions
|
|
|
|
ConnectionHandler adapter.ConnectionHandlerEx
|
|
|
|
PacketHandler adapter.PacketHandlerEx
|
|
|
|
OOBPacketHandler adapter.OOBPacketHandlerEx
|
|
|
|
ThreadUnsafePacketWriter bool
|
|
|
|
DisablePacketOutput bool
|
|
|
|
SetSystemProxy bool
|
|
|
|
SystemProxySOCKS bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(
|
|
|
|
options Options,
|
|
|
|
) *Listener {
|
|
|
|
return &Listener{
|
|
|
|
ctx: options.Context,
|
|
|
|
logger: options.Logger,
|
|
|
|
network: options.Network,
|
|
|
|
listenOptions: options.Listen,
|
|
|
|
connHandler: options.ConnectionHandler,
|
|
|
|
packetHandler: options.PacketHandler,
|
|
|
|
oobPacketHandler: options.OOBPacketHandler,
|
|
|
|
threadUnsafePacketWriter: options.ThreadUnsafePacketWriter,
|
|
|
|
disablePacketOutput: options.DisablePacketOutput,
|
|
|
|
setSystemProxy: options.SetSystemProxy,
|
|
|
|
systemProxySOCKS: options.SystemProxySOCKS,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *Listener) Start() error {
|
|
|
|
if common.Contains(l.network, N.NetworkTCP) {
|
|
|
|
_, err := l.ListenTCP()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
go l.loopTCPIn()
|
|
|
|
}
|
|
|
|
if common.Contains(l.network, N.NetworkUDP) {
|
|
|
|
_, err := l.ListenUDP()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
l.packetOutboundClosed = make(chan struct{})
|
|
|
|
l.packetOutbound = make(chan *N.PacketBuffer, 64)
|
|
|
|
go l.loopUDPIn()
|
|
|
|
if !l.disablePacketOutput {
|
|
|
|
go l.loopUDPOut()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if l.setSystemProxy {
|
|
|
|
listenPort := M.SocksaddrFromNet(l.tcpListener.Addr()).Port
|
|
|
|
var listenAddrString string
|
2024-11-07 13:44:04 +00:00
|
|
|
listenAddr := l.listenOptions.Listen.Build(netip.IPv4Unspecified())
|
2024-11-01 16:39:02 +00:00
|
|
|
if listenAddr.IsUnspecified() {
|
|
|
|
listenAddrString = "127.0.0.1"
|
|
|
|
} else {
|
|
|
|
listenAddrString = listenAddr.String()
|
|
|
|
}
|
|
|
|
systemProxy, err := settings.NewSystemProxy(l.ctx, M.ParseSocksaddrHostPort(listenAddrString, listenPort), l.systemProxySOCKS)
|
|
|
|
if err != nil {
|
|
|
|
return E.Cause(err, "initialize system proxy")
|
|
|
|
}
|
|
|
|
err = systemProxy.Enable()
|
|
|
|
if err != nil {
|
|
|
|
return E.Cause(err, "set system proxy")
|
|
|
|
}
|
|
|
|
l.systemProxy = systemProxy
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *Listener) Close() error {
|
|
|
|
l.shutdown.Store(true)
|
|
|
|
var err error
|
|
|
|
if l.systemProxy != nil && l.systemProxy.IsEnabled() {
|
|
|
|
err = l.systemProxy.Disable()
|
|
|
|
}
|
|
|
|
return E.Errors(err, common.Close(
|
|
|
|
l.tcpListener,
|
|
|
|
common.PtrOrNil(l.udpConn),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *Listener) TCPListener() net.Listener {
|
|
|
|
return l.tcpListener
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *Listener) UDPConn() *net.UDPConn {
|
|
|
|
return l.udpConn
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *Listener) ListenOptions() option.ListenOptions {
|
|
|
|
return l.listenOptions
|
|
|
|
}
|