mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-06-11 13:58:15 +03:00
Add new admin panel, failover, dns fallback, providers, limiters. Update XHTTP
This commit is contained in:
109
protocol/failover/outbound.go
Normal file
109
protocol/failover/outbound.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package failover
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/gofrs/uuid/v5"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/outbound"
|
||||
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"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/uot"
|
||||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
func RegisterOutbound(registry *outbound.Registry) {
|
||||
outbound.Register[option.FailoverOutboundOptions](registry, C.TypeFailover, NewFailover)
|
||||
}
|
||||
|
||||
type Failover struct {
|
||||
outbound.Adapter
|
||||
ctx context.Context
|
||||
outbound adapter.OutboundManager
|
||||
logger logger.ContextLogger
|
||||
dial DialStrategy
|
||||
uotClient *uot.Client
|
||||
}
|
||||
|
||||
func NewFailover(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.FailoverOutboundOptions) (adapter.Outbound, error) {
|
||||
if len(options.Outbounds) == 0 {
|
||||
return nil, E.New("missing outbounds")
|
||||
}
|
||||
outboundRegistry := service.FromContext[adapter.OutboundRegistry](ctx)
|
||||
outbounds := make([]adapter.Outbound, len(options.Outbounds))
|
||||
for i, outboundOptions := range options.Outbounds {
|
||||
outbound, err := outboundRegistry.UnsafeCreateOutbound(ctx, router, logger, outboundOptions.Tag, outboundOptions.Type, outboundOptions.Options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbounds[i] = outbound
|
||||
}
|
||||
dial, err := CreateStrategy(options.Strategy, outbounds, logger, options.Delay.Build())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound := &Failover{
|
||||
Adapter: outbound.NewAdapter(C.TypeFailover, tag, []string{N.NetworkTCP, N.NetworkUDP}, []string{}),
|
||||
ctx: ctx,
|
||||
outbound: service.FromContext[adapter.OutboundManager](ctx),
|
||||
logger: logger,
|
||||
dial: dial,
|
||||
}
|
||||
outbound.uotClient = &uot.Client{
|
||||
Dialer: outbound,
|
||||
Version: uot.Version,
|
||||
}
|
||||
return outbound, nil
|
||||
}
|
||||
|
||||
func (f *Failover) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
if N.NetworkName(network) == N.NetworkUDP {
|
||||
return f.uotClient.DialContext(ctx, network, destination)
|
||||
}
|
||||
conn, err := f.dial(ctx, network, Destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sessionUUID, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = WriteRequest(conn, &Request{Command: CommandTCP, UUID: sessionUUID, Destination: destination})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewFailoverConn(ctx, conn, func() (net.Conn, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, C.TCPConnectTimeout)
|
||||
defer cancel()
|
||||
conn, err := f.dial(ctx, network, Destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = WriteRequest(conn, &Request{Command: CommandReconnect, UUID: sessionUUID, Destination: destination})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var data [1]byte
|
||||
_, err = io.ReadFull(conn, data[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var status uint8 = data[0]
|
||||
if status == StatusSessionNotFound {
|
||||
conn.Close()
|
||||
return nil, SessionNotFound
|
||||
}
|
||||
return conn, nil
|
||||
}, nil), nil
|
||||
}
|
||||
|
||||
func (f *Failover) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
return f.uotClient.ListenPacket(ctx, destination)
|
||||
}
|
||||
Reference in New Issue
Block a user