Refactor struct & Add override dialer options

This commit is contained in:
世界
2022-07-03 20:59:25 +08:00
parent 28b865acf0
commit 18e3f43df3
33 changed files with 282 additions and 166 deletions

View File

@@ -1,40 +0,0 @@
package inbound
import (
"context"
"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"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
)
func New(ctx context.Context, router adapter.Router, logger log.Logger, index int, options option.Inbound) (adapter.Inbound, error) {
if common.IsEmptyByEquals(options) {
return nil, E.New("empty inbound config")
}
var tag string
if options.Tag != "" {
tag = options.Tag
} else {
tag = F.ToString(index)
}
inboundLogger := logger.WithPrefix(F.ToString("inbound/", options.Type, "[", tag, "]: "))
switch options.Type {
case C.TypeDirect:
return NewDirect(ctx, router, inboundLogger, options.Tag, options.DirectOptions), nil
case C.TypeSocks:
return NewSocks(ctx, router, inboundLogger, options.Tag, options.SocksOptions), nil
case C.TypeHTTP:
return NewHTTP(ctx, router, inboundLogger, options.Tag, options.HTTPOptions), nil
case C.TypeMixed:
return NewMixed(ctx, router, inboundLogger, options.Tag, options.MixedOptions), nil
case C.TypeShadowsocks:
return NewShadowsocks(ctx, router, inboundLogger, options.Tag, options.ShadowsocksOptions)
default:
return nil, E.New("unknown inbound type: ", options.Type)
}
}

View File

@@ -1,305 +0,0 @@
package inbound
import (
"context"
"net"
"net/netip"
"os"
"sync"
"time"
"github.com/database64128/tfo-go"
"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"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
var _ adapter.Inbound = (*myInboundAdapter)(nil)
type myInboundAdapter struct {
protocol string
network []string
ctx context.Context
router adapter.Router
logger log.Logger
tag string
listenOptions option.ListenOptions
connHandler adapter.ConnectionHandler
packetHandler adapter.PacketHandler
packetUpstream any
// internal
tcpListener *net.TCPListener
udpConn *net.UDPConn
packetForce6 bool
packetAccess sync.RWMutex
packetOutboundClosed chan struct{}
packetOutbound chan *myInboundPacket
}
func (a *myInboundAdapter) Type() string {
return a.protocol
}
func (a *myInboundAdapter) Tag() string {
return a.tag
}
func (a *myInboundAdapter) Start() error {
bindAddr := M.SocksaddrFromAddrPort(netip.Addr(a.listenOptions.Listen), a.listenOptions.Port)
var listenAddr net.Addr
if common.Contains(a.network, C.NetworkTCP) {
var tcpListener *net.TCPListener
var err error
if !a.listenOptions.TCPFastOpen {
tcpListener, err = net.ListenTCP(M.NetworkFromNetAddr("tcp", bindAddr.Addr), bindAddr.TCPAddr())
} else {
tcpListener, err = tfo.ListenTCP(M.NetworkFromNetAddr("tcp", bindAddr.Addr), bindAddr.TCPAddr())
}
if err != nil {
return err
}
a.tcpListener = tcpListener
go a.loopTCPIn()
listenAddr = tcpListener.Addr()
}
if common.Contains(a.network, C.NetworkUDP) {
udpConn, err := net.ListenUDP(M.NetworkFromNetAddr("udp", bindAddr.Addr), bindAddr.UDPAddr())
if err != nil {
return err
}
a.udpConn = udpConn
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()
} else {
go a.loopUDPInThreadSafe()
}
go a.loopUDPOut()
if listenAddr == nil {
listenAddr = udpConn.LocalAddr()
}
}
a.logger.Info("server started at ", listenAddr)
return nil
}
func (a *myInboundAdapter) Close() error {
return common.Close(
common.PtrOrNil(a.tcpListener),
common.PtrOrNil(a.udpConn),
)
}
func (a *myInboundAdapter) upstreamHandler(metadata adapter.InboundContext) adapter.UpstreamHandlerAdapter {
return adapter.NewUpstreamHandler(metadata, a.newConnection, a.streamPacketConnection, a)
}
func (a *myInboundAdapter) upstreamContextHandler() adapter.UpstreamHandlerAdapter {
return adapter.NewUpstreamContextHandler(a.newConnection, a.newPacketConnection, a)
}
func (a *myInboundAdapter) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
a.logger.WithContext(ctx).Info("inbound connection to ", metadata.Destination)
return a.router.RouteConnection(ctx, conn, metadata)
}
func (a *myInboundAdapter) streamPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
a.logger.WithContext(ctx).Info("inbound packet connection to ", metadata.Destination)
return a.router.RoutePacketConnection(ctx, conn, metadata)
}
func (a *myInboundAdapter) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
ctx = log.ContextWithID(ctx)
a.logger.WithContext(ctx).Info("inbound packet connection from ", metadata.Source)
a.logger.WithContext(ctx).Info("inbound packet connection to ", metadata.Destination)
return a.router.RoutePacketConnection(ctx, conn, metadata)
}
func (a *myInboundAdapter) loopTCPIn() {
tcpListener := a.tcpListener
for {
conn, err := tcpListener.Accept()
if err != nil {
return
}
go func() {
ctx := log.ContextWithID(a.ctx)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.Network = "tcp"
metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr())
a.logger.WithContext(ctx).Info("inbound connection from ", metadata.Source)
hErr := a.connHandler.NewConnection(ctx, conn, metadata)
if hErr != nil {
a.NewError(ctx, E.Cause(hErr, "process connection from ", metadata.Source))
}
}()
}
}
func (a *myInboundAdapter) loopUDPIn() {
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)
for {
buffer.Reset()
n, addr, err := a.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes())
if err != nil {
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.Network = "udp"
metadata.Source = M.SocksaddrFromNetIP(addr)
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, 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)
for {
buffer := buf.NewPacket()
n, addr, err := a.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes())
if err != nil {
buffer.Release()
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.Network = "udp"
metadata.Source = M.SocksaddrFromNetIP(addr)
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
if err != nil {
buffer.Release()
a.newError(E.Cause(err, "process packet from ", metadata.Source))
}
}
}
func (a *myInboundAdapter) loopUDPOut() {
for {
select {
case packet := <-a.packetOutbound:
err := a.writePacket(packet.buffer, packet.destination)
if err != nil && !E.IsClosed(err) {
a.newError(E.New("write back udp: ", err))
}
continue
case <-a.packetOutboundClosed:
}
for {
select {
case packet := <-a.packetOutbound:
packet.buffer.Release()
default:
return
}
}
}
}
func (a *myInboundAdapter) newError(err error) {
a.logger.Error(err)
}
func (a *myInboundAdapter) NewError(ctx context.Context, err error) {
common.Close(err)
if E.IsClosed(err) {
a.logger.WithContext(ctx).Debug("connection closed")
return
}
a.logger.Error(err)
}
func (a *myInboundAdapter) writePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
defer buffer.Release()
if destination.IsFqdn() {
udpAddr, err := net.ResolveUDPAddr("udp", destination.String())
if err != nil {
return err
}
return common.Error(a.udpConn.WriteTo(buffer.Bytes(), udpAddr))
}
if a.packetForce6 && destination.Addr.Is4() {
destination.Addr = netip.AddrFrom16(destination.Addr.As16())
}
return common.Error(a.udpConn.WriteToUDPAddrPort(buffer.Bytes(), destination.AddrPort()))
}
type myInboundPacketAdapter myInboundAdapter
func (s *myInboundPacketAdapter) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) {
n, addr, err := s.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes())
if err != nil {
return M.Socksaddr{}, err
}
buffer.Truncate(n)
return M.SocksaddrFromNetIP(addr), nil
}
func (s *myInboundPacketAdapter) WriteIsThreadUnsafe() {
}
type myInboundPacket struct {
buffer *buf.Buffer
destination M.Socksaddr
}
func (s *myInboundPacketAdapter) Upstream() any {
return s.udpConn
}
func (s *myInboundPacketAdapter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
s.packetAccess.RLock()
defer s.packetAccess.RUnlock()
select {
case <-s.packetOutboundClosed:
return os.ErrClosed
default:
}
s.packetOutbound <- &myInboundPacket{buffer, destination}
return nil
}
func (s *myInboundPacketAdapter) Close() error {
return s.udpConn.Close()
}
func (s *myInboundPacketAdapter) LocalAddr() net.Addr {
return s.udpConn.LocalAddr()
}
func (s *myInboundPacketAdapter) SetDeadline(t time.Time) error {
return s.udpConn.SetDeadline(t)
}
func (s *myInboundPacketAdapter) SetReadDeadline(t time.Time) error {
return s.udpConn.SetReadDeadline(t)
}
func (s *myInboundPacketAdapter) SetWriteDeadline(t time.Time) error {
return s.udpConn.SetWriteDeadline(t)
}

View File

@@ -1,86 +0,0 @@
package inbound
import (
"context"
"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/buf"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/udpnat"
)
var _ adapter.Inbound = (*Direct)(nil)
type Direct struct {
myInboundAdapter
udpNat *udpnat.Service[netip.AddrPort]
overrideOption int
overrideDestination M.Socksaddr
}
func NewDirect(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.DirectInboundOptions) *Direct {
inbound := &Direct{
myInboundAdapter: myInboundAdapter{
protocol: C.TypeDirect,
network: options.Network.Build(),
ctx: ctx,
router: router,
logger: logger,
tag: tag,
listenOptions: options.ListenOptions,
},
}
if options.OverrideAddress != "" && options.OverridePort != 0 {
inbound.overrideOption = 1
inbound.overrideDestination = M.ParseSocksaddrHostPort(options.OverrideAddress, options.OverridePort)
} else if options.OverrideAddress != "" {
inbound.overrideOption = 2
inbound.overrideDestination = M.ParseSocksaddrHostPort(options.OverrideAddress, options.OverridePort)
} else if options.OverridePort != 0 {
inbound.overrideOption = 3
inbound.overrideDestination = M.Socksaddr{Port: options.OverridePort}
}
inbound.udpNat = udpnat.New[netip.AddrPort](options.UDPTimeout, inbound.upstreamContextHandler())
inbound.connHandler = inbound
inbound.packetHandler = inbound
return inbound
}
func (d *Direct) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
switch d.overrideOption {
case 1:
metadata.Destination = d.overrideDestination
case 2:
destination := d.overrideDestination
destination.Port = metadata.Destination.Port
metadata.Destination = destination
case 3:
metadata.Destination.Port = d.overrideDestination.Port
}
d.logger.WithContext(ctx).Info("inbound connection to ", metadata.Destination)
return d.router.RouteConnection(ctx, conn, metadata)
}
func (d *Direct) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error {
switch d.overrideOption {
case 1:
metadata.Destination = d.overrideDestination
case 2:
destination := d.overrideDestination
destination.Port = metadata.Destination.Port
metadata.Destination = destination
case 3:
metadata.Destination.Port = d.overrideDestination.Port
}
var upstreamMetadata M.Metadata
upstreamMetadata.Source = metadata.Source
upstreamMetadata.Destination = metadata.Destination
d.udpNat.NewPacketDirect(&adapter.MetadataContext{Context: log.ContextWithID(ctx), Metadata: metadata}, metadata.Source.AddrPort(), conn, buffer, upstreamMetadata)
return nil
}

View File

@@ -1,43 +0,0 @@
package inbound
import (
std_bufio "bufio"
"context"
"net"
"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/auth"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/protocol/http"
)
var _ adapter.Inbound = (*HTTP)(nil)
type HTTP struct {
myInboundAdapter
authenticator auth.Authenticator
}
func NewHTTP(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.SimpleInboundOptions) *HTTP {
inbound := &HTTP{
myInboundAdapter{
protocol: C.TypeHTTP,
network: []string{C.NetworkTCP},
ctx: ctx,
router: router,
logger: logger,
tag: tag,
listenOptions: options.ListenOptions,
},
auth.NewAuthenticator(options.Users),
}
inbound.connHandler = inbound
return inbound
}
func (h *HTTP) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
return http.HandleConnection(ctx, conn, std_bufio.NewReader(conn), h.authenticator, h.upstreamHandler(metadata), M.Metadata{})
}

View File

@@ -1,58 +0,0 @@
package inbound
import (
std_bufio "bufio"
"context"
"net"
"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/auth"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/rw"
"github.com/sagernet/sing/protocol/http"
"github.com/sagernet/sing/protocol/socks"
"github.com/sagernet/sing/protocol/socks/socks4"
"github.com/sagernet/sing/protocol/socks/socks5"
)
var _ adapter.Inbound = (*Mixed)(nil)
type Mixed struct {
myInboundAdapter
authenticator auth.Authenticator
}
func NewMixed(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.SimpleInboundOptions) *Mixed {
inbound := &Mixed{
myInboundAdapter{
protocol: C.TypeMixed,
network: []string{C.NetworkTCP},
ctx: ctx,
router: router,
logger: logger,
tag: tag,
listenOptions: options.ListenOptions,
},
auth.NewAuthenticator(options.Users),
}
inbound.connHandler = inbound
return inbound
}
func (h *Mixed) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
headerType, err := rw.ReadByte(conn)
if err != nil {
return err
}
switch headerType {
case socks4.Version, socks5.Version:
return socks.HandleConnection0(ctx, conn, headerType, h.authenticator, h.upstreamHandler(metadata), M.Metadata{})
}
reader := std_bufio.NewReader(bufio.NewCachedReader(conn, buf.As([]byte{headerType})))
return http.HandleConnection(ctx, conn, reader, h.authenticator, h.upstreamHandler(metadata), M.Metadata{})
}

View File

@@ -1,74 +0,0 @@
package inbound
import (
"context"
"net"
"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-shadowsocks"
"github.com/sagernet/sing-shadowsocks/shadowaead"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
"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"
)
var _ adapter.Inbound = (*Shadowsocks)(nil)
type Shadowsocks struct {
myInboundAdapter
service shadowsocks.Service
}
func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.ShadowsocksInboundOptions) (*Shadowsocks, error) {
inbound := &Shadowsocks{
myInboundAdapter: myInboundAdapter{
protocol: C.TypeShadowsocks,
network: options.Network.Build(),
ctx: ctx,
router: router,
logger: logger,
tag: tag,
listenOptions: options.ListenOptions,
},
}
inbound.connHandler = inbound
inbound.packetHandler = inbound
var udpTimeout int64
if options.UDPTimeout != 0 {
udpTimeout = options.UDPTimeout
} else {
udpTimeout = 300
}
var err error
switch {
case options.Method == shadowsocks.MethodNone:
inbound.service = shadowsocks.NewNoneService(options.UDPTimeout, inbound.upstreamContextHandler())
case common.Contains(shadowaead.List, options.Method):
inbound.service, err = shadowaead.NewService(options.Method, nil, options.Password, udpTimeout, inbound.upstreamContextHandler())
case common.Contains(shadowaead_2022.List, options.Method):
inbound.service, err = shadowaead_2022.NewServiceWithPassword(options.Method, options.Password, udpTimeout, inbound.upstreamContextHandler())
default:
err = E.New("shadowsocks: unsupported method: ", options.Method)
}
inbound.packetUpstream = inbound.service
return inbound, err
}
func (h *Shadowsocks) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
return h.service.NewConnection(&adapter.MetadataContext{Context: ctx, Metadata: metadata}, conn, M.Metadata{
Source: metadata.Source,
})
}
func (h *Shadowsocks) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext) error {
h.logger.Trace("inbound packet from ", metadata.Source)
return h.service.NewPacket(&adapter.MetadataContext{Context: ctx, Metadata: metadata}, conn, buffer, M.Metadata{
Source: metadata.Source,
})
}

View File

@@ -1,42 +0,0 @@
package inbound
import (
"context"
"net"
"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/auth"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/protocol/socks"
)
var _ adapter.Inbound = (*Socks)(nil)
type Socks struct {
myInboundAdapter
authenticator auth.Authenticator
}
func NewSocks(ctx context.Context, router adapter.Router, logger log.Logger, tag string, options option.SimpleInboundOptions) *Socks {
inbound := &Socks{
myInboundAdapter{
protocol: C.TypeSocks,
network: []string{C.NetworkTCP},
ctx: ctx,
router: router,
logger: logger,
tag: tag,
listenOptions: options.ListenOptions,
},
auth.NewAuthenticator(options.Users),
}
inbound.connHandler = inbound
return inbound
}
func (h *Socks) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
return socks.HandleConnection(ctx, conn, h.authenticator, h.upstreamHandler(metadata), M.Metadata{})
}