Compare commits

...
56 changed files with 850 additions and 2986 deletions
+3 -3
View File
@@ -10,12 +10,12 @@ import (
// [,) // [,)
func RandBetween(from int64, to int64) int64 { func RandBetween(from int64, to int64) int64 {
if from == to {
return from
}
if from > to { if from > to {
from, to = to, from from, to = to, from
} }
if d := to - from; d == 0 || d == 1 {
return from
}
bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from)) bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from))
return from + bigInt.Int64() return from + bigInt.Int64()
} }
+6 -19
View File
@@ -7,7 +7,6 @@ import (
"github.com/xtls/xray-core/common/ctx" "github.com/xtls/xray-core/common/ctx"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/outbound" "github.com/xtls/xray-core/features/outbound"
"github.com/xtls/xray-core/features/routing"
) )
//go:linkname IndependentCancelCtx context.newCancelCtx //go:linkname IndependentCancelCtx context.newCancelCtx
@@ -20,14 +19,13 @@ const (
isReverseMuxKey ctx.SessionKey = 4 // is reverse mux isReverseMuxKey ctx.SessionKey = 4 // is reverse mux
sockoptSessionKey ctx.SessionKey = 5 // used by dokodemo to only receive sockopt.Mark sockoptSessionKey ctx.SessionKey = 5 // used by dokodemo to only receive sockopt.Mark
trackedConnectionErrorKey ctx.SessionKey = 6 // used by observer to get outbound error trackedConnectionErrorKey ctx.SessionKey = 6 // used by observer to get outbound error
dispatcherKey ctx.SessionKey = 7 // used by ss2022 inbounds to get dispatcher timeoutOnlyKey ctx.SessionKey = 7 // mux context's child contexts to only cancel when its own traffic times out
timeoutOnlyKey ctx.SessionKey = 8 // mux context's child contexts to only cancel when its own traffic times out allowedNetworkKey ctx.SessionKey = 8 // muxcool server control incoming request tcp/udp
allowedNetworkKey ctx.SessionKey = 9 // muxcool server control incoming request tcp/udp fullHandlerKey ctx.SessionKey = 9 // outbound gets full handler
fullHandlerKey ctx.SessionKey = 10 // outbound gets full handler mitmAlpn11Key ctx.SessionKey = 10 // used by TLS dialer
mitmAlpn11Key ctx.SessionKey = 11 // used by TLS dialer mitmServerNameKey ctx.SessionKey = 11 // used by TLS dialer
mitmServerNameKey ctx.SessionKey = 12 // used by TLS dialer
streamSettingsKey ctx.SessionKey = 13 streamSettingsKey ctx.SessionKey = 12
) )
func ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context { func ContextWithInbound(ctx context.Context, inbound *Inbound) context.Context {
@@ -129,17 +127,6 @@ func TrackedConnectionError(ctx context.Context, tracker TrackedRequestErrorFeed
return context.WithValue(ctx, trackedConnectionErrorKey, tracker) return context.WithValue(ctx, trackedConnectionErrorKey, tracker)
} }
func ContextWithDispatcher(ctx context.Context, dispatcher routing.Dispatcher) context.Context {
return context.WithValue(ctx, dispatcherKey, dispatcher)
}
func DispatcherFromContext(ctx context.Context) routing.Dispatcher {
if dispatcher, ok := ctx.Value(dispatcherKey).(routing.Dispatcher); ok {
return dispatcher
}
return nil
}
func ContextWithTimeoutOnly(ctx context.Context, only bool) context.Context { func ContextWithTimeoutOnly(ctx context.Context, only bool) context.Context {
return context.WithValue(ctx, timeoutOnlyKey, only) return context.WithValue(ctx, timeoutOnlyKey, only)
} }
-53
View File
@@ -1,53 +0,0 @@
package singbridge
import (
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
)
func ToNetwork(network string) net.Network {
switch N.NetworkName(network) {
case N.NetworkTCP:
return net.Network_TCP
case N.NetworkUDP:
return net.Network_UDP
default:
return net.Network_Unknown
}
}
func ToDestination(socksaddr M.Socksaddr, network net.Network) (net.Destination, error) {
// IsFqdn() implicitly checks if the domain name is valid
if socksaddr.IsFqdn() {
return net.Destination{
Network: network,
Address: net.DomainAddress(socksaddr.Fqdn),
Port: net.Port(socksaddr.Port),
}, nil
}
// IsIP() implicitly checks if the IP address is valid
if socksaddr.IsIP() {
return net.Destination{
Network: network,
Address: net.IPAddress(socksaddr.Addr.AsSlice()),
Port: net.Port(socksaddr.Port),
}, nil
}
return net.Destination{}, errors.New("invalid socks address: ", socksaddr)
}
func ToSocksaddr(destination net.Destination) M.Socksaddr {
var addr M.Socksaddr
switch destination.Address.Family() {
case net.AddressFamilyDomain:
addr.Fqdn = destination.Address.Domain()
default:
addr.Addr = M.AddrFromIP(destination.Address.IP())
}
addr.Port = uint16(destination.Port)
return addr
}
-72
View File
@@ -1,72 +0,0 @@
package singbridge
import (
"context"
"os"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/proxy"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/pipe"
)
var _ N.Dialer = (*XrayDialer)(nil)
type XrayDialer struct {
internet.Dialer
}
func NewDialer(dialer internet.Dialer) *XrayDialer {
return &XrayDialer{dialer}
}
func (d *XrayDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
dest, err := ToDestination(destination, ToNetwork(network))
if err != nil {
return nil, err
}
return d.Dialer.Dial(ctx, dest)
}
func (d *XrayDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return nil, os.ErrInvalid
}
type XrayOutboundDialer struct {
outbound proxy.Outbound
dialer internet.Dialer
}
func NewOutboundDialer(outbound proxy.Outbound, dialer internet.Dialer) *XrayOutboundDialer {
return &XrayOutboundDialer{outbound, dialer}
}
func (d *XrayOutboundDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
dest, err := ToDestination(destination, ToNetwork(network))
if err != nil {
return nil, err
}
outbounds := session.OutboundsFromContext(ctx)
if len(outbounds) == 0 {
outbounds = []*session.Outbound{{}}
ctx = session.ContextWithOutbounds(ctx, outbounds)
}
ob := outbounds[len(outbounds)-1]
ob.Target = dest
opts := []pipe.Option{pipe.WithSizeLimit(64 * 1024)}
uplinkReader, uplinkWriter := pipe.New(opts...)
downlinkReader, downlinkWriter := pipe.New(opts...)
conn := cnc.NewConnection(cnc.ConnectionInputMulti(downlinkWriter), cnc.ConnectionOutputMulti(uplinkReader))
go d.outbound.Process(ctx, &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}, d.dialer)
return conn, nil
}
func (d *XrayOutboundDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return nil, os.ErrInvalid
}
-10
View File
@@ -1,10 +0,0 @@
package singbridge
import E "github.com/sagernet/sing/common/exceptions"
func ReturnError(err error) error {
if E.IsClosedOrCanceled(err) {
return nil
}
return err
}
-58
View File
@@ -1,58 +0,0 @@
package singbridge
import (
"context"
"io"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport"
)
var (
_ N.TCPConnectionHandler = (*Dispatcher)(nil)
_ N.UDPConnectionHandler = (*Dispatcher)(nil)
)
type Dispatcher struct {
upstream routing.Dispatcher
newErrorFunc func(values ...any) *errors.Error
}
func NewDispatcher(dispatcher routing.Dispatcher, newErrorFunc func(values ...any) *errors.Error) *Dispatcher {
return &Dispatcher{
upstream: dispatcher,
newErrorFunc: newErrorFunc,
}
}
func (d *Dispatcher) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
dest, err := ToDestination(metadata.Destination, net.Network_TCP)
if err != nil {
return err
}
xConn := NewConn(conn)
return d.upstream.DispatchLink(ctx, dest, &transport.Link{
Reader: xConn,
Writer: xConn,
})
}
func (d *Dispatcher) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
dest, err := ToDestination(metadata.Destination, net.Network_UDP)
if err != nil {
return err
}
return d.upstream.DispatchLink(ctx, dest, &transport.Link{
Reader: buf.NewPacketReader(conn.(io.Reader)),
Writer: buf.NewWriter(conn.(io.Writer)),
})
}
func (d *Dispatcher) NewError(ctx context.Context, err error) {
errors.LogInfo(ctx, err.Error())
}
-70
View File
@@ -1,70 +0,0 @@
package singbridge
import (
"context"
"github.com/sagernet/sing/common/logger"
"github.com/xtls/xray-core/common/errors"
)
var _ logger.ContextLogger = (*XrayLogger)(nil)
type XrayLogger struct {
newError func(values ...any) *errors.Error
}
func NewLogger(newErrorFunc func(values ...any) *errors.Error) *XrayLogger {
return &XrayLogger{
newErrorFunc,
}
}
func (l *XrayLogger) Trace(args ...any) {
}
func (l *XrayLogger) Debug(args ...any) {
errors.LogDebug(context.Background(), args...)
}
func (l *XrayLogger) Info(args ...any) {
errors.LogInfo(context.Background(), args...)
}
func (l *XrayLogger) Warn(args ...any) {
errors.LogWarning(context.Background(), args...)
}
func (l *XrayLogger) Error(args ...any) {
errors.LogError(context.Background(), args...)
}
func (l *XrayLogger) Fatal(args ...any) {
}
func (l *XrayLogger) Panic(args ...any) {
}
func (l *XrayLogger) TraceContext(ctx context.Context, args ...any) {
}
func (l *XrayLogger) DebugContext(ctx context.Context, args ...any) {
errors.LogDebug(ctx, args...)
}
func (l *XrayLogger) InfoContext(ctx context.Context, args ...any) {
errors.LogInfo(ctx, args...)
}
func (l *XrayLogger) WarnContext(ctx context.Context, args ...any) {
errors.LogWarning(ctx, args...)
}
func (l *XrayLogger) ErrorContext(ctx context.Context, args ...any) {
errors.LogError(ctx, args...)
}
func (l *XrayLogger) FatalContext(ctx context.Context, args ...any) {
}
func (l *XrayLogger) PanicContext(ctx context.Context, args ...any) {
}
-107
View File
@@ -1,107 +0,0 @@
package singbridge
import (
"context"
"time"
B "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/transport"
)
func CopyPacketConn(ctx context.Context, inboundConn net.Conn, link *transport.Link, destination net.Destination, serverConn net.PacketConn) error {
cancel := func() {
common.Interrupt(link.Reader)
common.Interrupt(serverConn)
}
conn := &PacketConnWrapper{
Reader: link.Reader,
Writer: link.Writer,
Dest: destination,
Conn: inboundConn,
T: signal.CancelAfterInactivity(ctx, cancel, 300*time.Second),
}
return ReturnError(bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(serverConn)))
}
type PacketConnWrapper struct {
buf.Reader
buf.Writer
net.Conn
Dest net.Destination
cached buf.MultiBuffer
// A simple patch to avoid goroutine leak since sing infra cannot awake read block by write err
T *signal.ActivityTimer
}
func (w *PacketConnWrapper) ReadPacket(buffer *B.Buffer) (addr M.Socksaddr, err error) {
w.T.Update()
defer func() {
if err != nil {
// uplinkonly
w.T.SetTimeout(2 * time.Second)
}
}()
if w.cached != nil {
mb, bb := buf.SplitFirst(w.cached)
if bb == nil {
w.cached = nil
} else {
buffer.Write(bb.Bytes())
w.cached = mb
var destination net.Destination
if bb.UDP != nil {
destination = *bb.UDP
} else {
destination = w.Dest
}
bb.Release()
return ToSocksaddr(destination), nil
}
}
mb, err := w.ReadMultiBuffer()
nb, bb := buf.SplitFirst(mb)
if bb == nil {
return M.Socksaddr{}, nil
} else {
buffer.Write(bb.Bytes())
w.cached = nb
var destination net.Destination
if bb.UDP != nil {
destination = *bb.UDP
} else {
destination = w.Dest
}
bb.Release()
return ToSocksaddr(destination), nil
}
}
func (w *PacketConnWrapper) WritePacket(buffer *B.Buffer, destination M.Socksaddr) (err error) {
w.T.Update()
defer func() {
if err != nil {
// downlinkonly
w.T.SetTimeout(5 * time.Second)
}
}()
endpoint, err := ToDestination(destination, net.Network_UDP)
if err != nil {
return err
}
vBuf := buf.New()
vBuf.Write(buffer.Bytes())
vBuf.UDP = &endpoint
return w.WriteMultiBuffer(buf.MultiBuffer{vBuf})
}
func (w *PacketConnWrapper) Close() error {
buf.ReleaseMulti(w.cached)
return nil
}
-81
View File
@@ -1,81 +0,0 @@
package singbridge
import (
"context"
"io"
"net"
"time"
"github.com/sagernet/sing/common/bufio"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/transport"
)
func CopyConn(ctx context.Context, inboundConn net.Conn, link *transport.Link, serverConn net.Conn) error {
conn := &PipeConnWrapper{
W: link.Writer,
Conn: inboundConn,
}
if ir, ok := link.Reader.(io.Reader); ok {
conn.R = ir
} else {
conn.R = &buf.BufferedReader{Reader: link.Reader}
}
cancel := func() {
common.Interrupt(link.Reader)
common.Interrupt(serverConn)
}
conn.T = signal.CancelAfterInactivity(ctx, cancel, 300*time.Second)
return ReturnError(bufio.CopyConn(ctx, conn, serverConn))
}
type PipeConnWrapper struct {
R io.Reader
W buf.Writer
net.Conn
// A simple patch to avoid goroutine leak since sing infra cannot awake read block by write err
T *signal.ActivityTimer
}
func (w *PipeConnWrapper) Close() error {
return nil
}
func (w *PipeConnWrapper) Read(b []byte) (n int, err error) {
w.T.Update()
n, err = w.R.Read(b)
if err != nil {
// uplinkonly
w.T.SetTimeout(2 * time.Second)
}
return
}
func (w *PipeConnWrapper) Write(p []byte) (n int, err error) {
w.T.Update()
n = len(p)
var mb buf.MultiBuffer
pLen := len(p)
for pLen > 0 {
buffer := buf.New()
if pLen > buf.Size {
_, err = buffer.Write(p[:buf.Size])
p = p[buf.Size:]
} else {
buffer.Write(p)
}
pLen -= int(buffer.Len())
mb = append(mb, buffer)
}
err = w.W.WriteMultiBuffer(mb)
if err != nil {
n = 0
buf.ReleaseMulti(mb)
// downlinkonly
w.T.SetTimeout(5 * time.Second)
}
return
}
-66
View File
@@ -1,66 +0,0 @@
package singbridge
import (
"time"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/bufio"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
)
var (
_ buf.Reader = (*Conn)(nil)
_ buf.TimeoutReader = (*Conn)(nil)
_ buf.Writer = (*Conn)(nil)
)
type Conn struct {
net.Conn
writer N.VectorisedWriter
}
func NewConn(conn net.Conn) *Conn {
writer, _ := bufio.CreateVectorisedWriter(conn)
return &Conn{
Conn: conn,
writer: writer,
}
}
func (c *Conn) ReadMultiBuffer() (buf.MultiBuffer, error) {
buffer, err := buf.ReadBuffer(c.Conn)
if err != nil {
return nil, err
}
return buf.MultiBuffer{buffer}, nil
}
func (c *Conn) ReadMultiBufferTimeout(duration time.Duration) (buf.MultiBuffer, error) {
err := c.SetReadDeadline(time.Now().Add(duration))
if err != nil {
return nil, err
}
defer c.SetReadDeadline(time.Time{})
return c.ReadMultiBuffer()
}
func (c *Conn) WriteMultiBuffer(bufferList buf.MultiBuffer) error {
defer buf.ReleaseMulti(bufferList)
if c.writer != nil {
bytesList := make([][]byte, len(bufferList))
for i, buffer := range bufferList {
bytesList[i] = buffer.Bytes()
}
return common.Error(bufio.WriteVectorised(c.writer, bytesList))
}
// Since this conn is only used by tun, we don't force buffer writes to merge.
for _, buffer := range bufferList {
_, err := c.Conn.Write(buffer.Bytes())
if err != nil {
return err
}
}
return nil
}
+1 -1
View File
@@ -20,7 +20,7 @@ import (
var ( var (
Version_x byte = 26 Version_x byte = 26
Version_y byte = 9 Version_y byte = 9
Version_z byte = 8 Version_z byte = 9
) )
var ( var (
-2
View File
@@ -18,8 +18,6 @@ require (
github.com/pires/go-proxyproto v0.15.0 github.com/pires/go-proxyproto v0.15.0
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/sagernet/sing v0.5.1
github.com/sagernet/sing-shadowsocks v0.2.7
github.com/stretchr/testify v1.12.1 github.com/stretchr/testify v1.12.1
github.com/vishvananda/netlink v1.3.1 github.com/vishvananda/netlink v1.3.1
github.com/xtls/reality v0.0.0-20260908062103-8cdf7bf9c7f0 github.com/xtls/reality v0.0.0-20260908062103-8cdf7bf9c7f0
-4
View File
@@ -76,10 +76,6 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g= github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g=
github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs=
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0= github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0=
+4 -104
View File
@@ -3,14 +3,11 @@ package conf
import ( import (
"strings" "strings"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
C "github.com/sagernet/sing/common"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/protocol" "github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial" "github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/task" "github.com/xtls/xray-core/common/task"
"github.com/xtls/xray-core/proxy/shadowsocks" "github.com/xtls/xray-core/proxy/shadowsocks"
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
@@ -30,12 +27,10 @@ func cipherFromString(c string) shadowsocks.CipherType {
} }
type ShadowsocksUserConfig struct { type ShadowsocksUserConfig struct {
Cipher string `json:"method"` Cipher string `json:"method"`
Password string `json:"password"` Password string `json:"password"`
Level byte `json:"level"` Level byte `json:"level"`
Email string `json:"email"` Email string `json:"email"`
Address *Address `json:"address"`
Port uint16 `json:"port"`
} }
type ShadowsocksServerConfig struct { type ShadowsocksServerConfig struct {
@@ -55,10 +50,6 @@ func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
v.Users = v.Clients v.Users = v.Clients
} }
if C.Contains(shadowaead_2022.List, v.Cipher) {
return buildShadowsocks2022(v)
}
config := new(shadowsocks.ServerConfig) config := new(shadowsocks.ServerConfig)
config.Network = v.NetworkList.Build() config.Network = v.NetworkList.Build()
@@ -110,72 +101,6 @@ func (v *ShadowsocksServerConfig) Build() (proto.Message, error) {
return config, nil return config, nil
} }
func buildShadowsocks2022(v *ShadowsocksServerConfig) (proto.Message, error) {
if len(v.Users) == 0 {
config := new(shadowsocks_2022.ServerConfig)
config.Method = v.Cipher
config.Key = v.Password
config.Network = v.NetworkList.Build()
config.Email = v.Email
return config, nil
}
if v.Cipher == "" {
return nil, errors.New("shadowsocks 2022 (multi-user): missing server method")
}
if !strings.Contains(v.Cipher, "aes") {
return nil, errors.New("shadowsocks 2022 (multi-user): only blake3-aes-*-gcm methods are supported")
}
if v.Users[0].Address == nil {
config := new(shadowsocks_2022.MultiUserServerConfig)
config.Method = v.Cipher
config.Key = v.Password
config.Network = v.NetworkList.Build()
config.Users = make([]*protocol.User, len(v.Users))
processUser := func(idx int) error {
user := v.Users[idx]
if user.Cipher != "" {
return errors.New("shadowsocks 2022 (multi-user): users must have empty method")
}
account := &shadowsocks_2022.Account{
Key: user.Password,
}
config.Users[idx] = &protocol.User{
Email: user.Email,
Level: uint32(user.Level),
Account: serial.ToTypedMessage(account),
}
return nil
}
if err := task.ParallelForN(len(v.Users), processUser); err != nil {
return nil, err
}
return config, nil
}
config := new(shadowsocks_2022.RelayServerConfig)
config.Method = v.Cipher
config.Key = v.Password
config.Network = v.NetworkList.Build()
for _, user := range v.Users {
if user.Cipher != "" {
return nil, errors.New("shadowsocks 2022 (relay): users must have empty method")
}
if user.Address == nil {
return nil, errors.New("shadowsocks 2022 (relay): all users must have relay address")
}
config.Destinations = append(config.Destinations, &shadowsocks_2022.RelayDestination{
Key: user.Password,
Email: user.Email,
Address: user.Address.Build(),
Port: uint32(user.Port),
})
}
return config, nil
}
type ShadowsocksServerTarget struct { type ShadowsocksServerTarget struct {
Address *Address `json:"address"` Address *Address `json:"address"`
Port uint16 `json:"port"` Port uint16 `json:"port"`
@@ -214,33 +139,8 @@ func (v *ShadowsocksClientConfig) Build() (proto.Message, error) {
return nil, errors.New(`Shadowsocks settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple Shadowsocks outbounds and routing balancer instead`) return nil, errors.New(`Shadowsocks settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple Shadowsocks outbounds and routing balancer instead`)
} }
if len(v.Servers) == 1 {
server := v.Servers[0]
if C.Contains(shadowaead_2022.List, server.Cipher) {
if server.Address == nil {
return nil, errors.New("Shadowsocks server address is not set.")
}
if server.Port == 0 {
return nil, errors.New("Invalid Shadowsocks port.")
}
if server.Password == "" {
return nil, errors.New("Shadowsocks password is not specified.")
}
config := new(shadowsocks_2022.ClientConfig)
config.Address = server.Address.Build()
config.Port = uint32(server.Port)
config.Method = server.Cipher
config.Key = server.Password
return config, nil
}
}
config := new(shadowsocks.ClientConfig) config := new(shadowsocks.ClientConfig)
for _, server := range v.Servers { for _, server := range v.Servers {
if C.Contains(shadowaead_2022.List, server.Cipher) {
return nil, errors.New("Shadowsocks 2022 accept no multi servers")
}
if server.Address == nil { if server.Address == nil {
return nil, errors.New("Shadowsocks server address is not set.") return nil, errors.New("Shadowsocks server address is not set.")
} }
+59 -1
View File
@@ -14,6 +14,7 @@ import (
googleuuid "github.com/google/uuid" googleuuid "github.com/google/uuid"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/finalmask/fragment" "github.com/xtls/xray-core/transport/internet/finalmask/fragment"
"github.com/xtls/xray-core/transport/internet/finalmask/header/custom" "github.com/xtls/xray-core/transport/internet/finalmask/header/custom"
"github.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm" "github.com/xtls/xray-core/transport/internet/finalmask/mkcp/aes128gcm"
@@ -23,6 +24,7 @@ import (
"github.com/xtls/xray-core/transport/internet/finalmask/realm" "github.com/xtls/xray-core/transport/internet/finalmask/realm"
"github.com/xtls/xray-core/transport/internet/finalmask/salamander" "github.com/xtls/xray-core/transport/internet/finalmask/salamander"
"github.com/xtls/xray-core/transport/internet/finalmask/sudoku" "github.com/xtls/xray-core/transport/internet/finalmask/sudoku"
"github.com/xtls/xray-core/transport/internet/finalmask/udphop"
"github.com/xtls/xray-core/transport/internet/finalmask/xdns" "github.com/xtls/xray-core/transport/internet/finalmask/xdns"
"github.com/xtls/xray-core/transport/internet/finalmask/xicmp" "github.com/xtls/xray-core/transport/internet/finalmask/xicmp"
"github.com/xtls/xray-core/transport/internet/finalmask/xmc" "github.com/xtls/xray-core/transport/internet/finalmask/xmc"
@@ -83,6 +85,7 @@ var (
"xdns": func() interface{} { return new(Xdns) }, "xdns": func() interface{} { return new(Xdns) },
"xicmp": func() interface{} { return new(Xicmp) }, "xicmp": func() interface{} { return new(Xicmp) },
"realm": func() interface{} { return new(Realm) }, "realm": func() interface{} { return new(Realm) },
"udphop": func() interface{} { return new(UDPHop) },
}, "type", "settings") }, "type", "settings")
) )
@@ -905,6 +908,62 @@ func (c *Realm) Build() (proto.Message, error) {
}, nil }, nil
} }
type UDPHop struct {
Sockopt *SocketConfig `json:"sockopt"`
Mode string `json:"mode"`
Interval Int32Range `json:"interval"`
RemotePorts PortList `json:"remotePorts"`
RemoteIPs []string `json:"remoteIPs"`
}
func (c *UDPHop) Build() (proto.Message, error) {
var sockopt *internet.SocketConfig
if c.Sockopt != nil {
var err error
sockopt, err = c.Sockopt.Build()
if err != nil {
return nil, err
}
}
var local, remote, remoteOnce bool
for _, mode := range strings.Split(c.Mode, ",") {
switch strings.ToLower(mode) {
case "intervallocal":
local = true
case "intervalremote":
remote = true
case "perconnremote":
remoteOnce = true
default:
return nil, errors.New("invalid mode ", mode)
}
}
var remoteIPs []string
for _, ip := range c.RemoteIPs {
prefix, err := netip.ParsePrefix(ip)
if err == nil {
remoteIPs = append(remoteIPs, prefix.String())
continue
}
addr, err := netip.ParseAddr(ip)
if err == nil {
remoteIPs = append(remoteIPs, netip.PrefixFrom(addr, addr.BitLen()).String())
continue
}
return nil, errors.New("invalid ip ", ip)
}
return &udphop.Config{
Sockopt: sockopt,
Local: local,
Remote: remote,
RemoteOnce: remoteOnce,
IntervalMin: int64(c.Interval.From),
IntervalMax: int64(c.Interval.To),
RemotePorts: c.RemotePorts.Build().Ports(),
RemoteIPs: remoteIPs,
}, nil
}
type Mask struct { type Mask struct {
Type string `json:"type"` Type string `json:"type"`
Settings *json.RawMessage `json:"settings"` Settings *json.RawMessage `json:"settings"`
@@ -938,7 +997,6 @@ type QuicParamsConfig struct {
BrutalUp Bandwidth `json:"brutalUp"` BrutalUp Bandwidth `json:"brutalUp"`
BrutalDown Bandwidth `json:"brutalDown"` BrutalDown Bandwidth `json:"brutalDown"`
BrutalDisableLossCompensation bool `json:"brutalDisableLossCompensation"` BrutalDisableLossCompensation bool `json:"brutalDisableLossCompensation"`
UdpHop UdpHop `json:"udpHop"`
InitStreamReceiveWindow uint64 `json:"initStreamReceiveWindow"` InitStreamReceiveWindow uint64 `json:"initStreamReceiveWindow"`
MaxStreamReceiveWindow uint64 `json:"maxStreamReceiveWindow"` MaxStreamReceiveWindow uint64 `json:"maxStreamReceiveWindow"`
InitConnectionReceiveWindow uint64 `json:"initConnectionReceiveWindow"` InitConnectionReceiveWindow uint64 `json:"initConnectionReceiveWindow"`
+11 -20
View File
@@ -253,10 +253,6 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal") return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal")
} }
if (c.FinalMask.QuicParams.UdpHop.Interval.From != 0 && c.FinalMask.QuicParams.UdpHop.Interval.From < 5) || (c.FinalMask.QuicParams.UdpHop.Interval.To != 0 && c.FinalMask.QuicParams.UdpHop.Interval.To < 5) {
return nil, errors.New("Interval must be at least 5")
}
if c.FinalMask.QuicParams.InitStreamReceiveWindow > 0 && c.FinalMask.QuicParams.InitStreamReceiveWindow < 16384 { if c.FinalMask.QuicParams.InitStreamReceiveWindow > 0 && c.FinalMask.QuicParams.InitStreamReceiveWindow < 16384 {
return nil, errors.New("InitStreamReceiveWindow must be at least 16384") return nil, errors.New("InitStreamReceiveWindow must be at least 16384")
} }
@@ -290,22 +286,17 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
BrutalUp: up, BrutalUp: up,
BrutalDown: down, BrutalDown: down,
BrutalDisableLossCompensation: c.FinalMask.QuicParams.BrutalDisableLossCompensation, BrutalDisableLossCompensation: c.FinalMask.QuicParams.BrutalDisableLossCompensation,
UdpHop: &internet.UdpHop{ InitStreamReceiveWindow: c.FinalMask.QuicParams.InitStreamReceiveWindow,
Ports: c.FinalMask.QuicParams.UdpHop.PortList.Build().Ports(), MaxStreamReceiveWindow: c.FinalMask.QuicParams.MaxStreamReceiveWindow,
IntervalMin: int64(c.FinalMask.QuicParams.UdpHop.Interval.From), InitConnReceiveWindow: c.FinalMask.QuicParams.InitConnectionReceiveWindow,
IntervalMax: int64(c.FinalMask.QuicParams.UdpHop.Interval.To), MaxConnReceiveWindow: c.FinalMask.QuicParams.MaxConnectionReceiveWindow,
}, MaxIdleTimeout: c.FinalMask.QuicParams.MaxIdleTimeout,
InitStreamReceiveWindow: c.FinalMask.QuicParams.InitStreamReceiveWindow, KeepAlivePeriod: c.FinalMask.QuicParams.KeepAlivePeriod,
MaxStreamReceiveWindow: c.FinalMask.QuicParams.MaxStreamReceiveWindow, DisablePathMtuDiscovery: c.FinalMask.QuicParams.DisablePathMTUDiscovery,
InitConnReceiveWindow: c.FinalMask.QuicParams.InitConnectionReceiveWindow, DisableChromeParrot: c.FinalMask.QuicParams.DisableChromeParrot,
MaxConnReceiveWindow: c.FinalMask.QuicParams.MaxConnectionReceiveWindow, DisableGSO: c.FinalMask.QuicParams.DisableGSO,
MaxIdleTimeout: c.FinalMask.QuicParams.MaxIdleTimeout, MaxIncomingStreams: c.FinalMask.QuicParams.MaxIncomingStreams,
KeepAlivePeriod: c.FinalMask.QuicParams.KeepAlivePeriod, DisableStatelessReset: c.FinalMask.QuicParams.DisableStatelessReset,
DisablePathMtuDiscovery: c.FinalMask.QuicParams.DisablePathMTUDiscovery,
DisableChromeParrot: c.FinalMask.QuicParams.DisableChromeParrot,
DisableGSO: c.FinalMask.QuicParams.DisableGSO,
MaxIncomingStreams: c.FinalMask.QuicParams.MaxIncomingStreams,
DisableStatelessReset: c.FinalMask.QuicParams.DisableStatelessReset,
} }
} }
} }
+6 -26
View File
@@ -1,7 +1,6 @@
package conf package conf
import ( import (
"context"
"encoding/json" "encoding/json"
"math/big" "math/big"
"net/url" "net/url"
@@ -534,10 +533,6 @@ type KCPConfig struct {
// Build implements Buildable. // Build implements Buildable.
func (c *KCPConfig) Build() (proto.Message, error) { func (c *KCPConfig) Build() (proto.Message, error) {
if c.HeaderConfig != nil || c.Seed != nil {
return nil, errors.PrintRemovedFeatureError("mkcp header & seed", "finalmask/udp header-* & mkcp-original & mkcp-aes128gcm")
}
config := common.Must2(internet.CreateTransportConfig(kcp.ProtocolName)).(*kcp.Config) config := common.Must2(internet.CreateTransportConfig(kcp.ProtocolName)).(*kcp.Config)
if c.Mtu != nil { if c.Mtu != nil {
@@ -560,16 +555,16 @@ func (c *KCPConfig) Build() (proto.Message, error) {
} }
if config.Mtu < 21 { if config.Mtu < 21 {
return nil, errors.New("Mtu must be at least 21").AtError() return nil, errors.New("MTU must be at least 21")
} }
if config.Tti < 10 || config.Tti > 1000 { if config.Tti < 10 || config.Tti > 1000 {
return nil, errors.New("invalid mKCP TTI: ", c.Tti).AtError() return nil, errors.New("TTI must be between 10 and 1000")
} }
if config.CwndMultiplier < 1 { if config.CwndMultiplier < 1 {
return nil, errors.New("CwndMultiplier must be at least 1").AtError() return nil, errors.New("CwndMultiplier must be at least 1")
} }
if config.GetSendingBufferSize() == 0 { if config.GetSendingBufferSize() == 0 {
return nil, errors.New("MaxSendingWindow must be >= Mtu").AtError() return nil, errors.New("MaxSendingWindow must be at least ", config.Mtu)
} }
return config, nil return config, nil
@@ -739,11 +734,6 @@ func (b Bandwidth) Bps() (uint64, error) {
return uint64(val*float64(mul)) / 8, nil return uint64(val*float64(mul)) / 8, nil
} }
type UdpHop struct {
PortList PortList `json:"ports"`
Interval Int32Range `json:"interval"`
}
type Masquerade struct { type Masquerade struct {
Type string `json:"type"` Type string `json:"type"`
@@ -760,14 +750,8 @@ type Masquerade struct {
} }
type HysteriaConfig struct { type HysteriaConfig struct {
Version int32 `json:"version"` Version int32 `json:"version"`
Auth string `json:"auth"` Auth string `json:"auth"`
Congestion *string `json:"congestion"`
Up *Bandwidth `json:"up"`
Down *Bandwidth `json:"down"`
UdpHop *UdpHop `json:"udphop"`
UdpIdleTimeout int64 `json:"udpIdleTimeout"` UdpIdleTimeout int64 `json:"udpIdleTimeout"`
Masquerade Masquerade `json:"masquerade"` Masquerade Masquerade `json:"masquerade"`
} }
@@ -777,10 +761,6 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
return nil, errors.New("version != 2") return nil, errors.New("version != 2")
} }
if c.Congestion != nil || c.Up != nil || c.Down != nil || c.UdpHop != nil {
errors.LogWarning(context.Background(), "congestion & up & down & udphop move to finalmask/quicParams")
}
if c.UdpIdleTimeout != 0 && (c.UdpIdleTimeout < 2 || c.UdpIdleTimeout > 600) { if c.UdpIdleTimeout != 0 && (c.UdpIdleTimeout < 2 || c.UdpIdleTimeout > 600) {
return nil, errors.New("UdpIdleTimeout must be between 2 and 600") return nil, errors.New("UdpIdleTimeout must be between 2 and 600")
} }
@@ -13,7 +13,6 @@ import (
"github.com/xtls/xray-core/infra/conf" "github.com/xtls/xray-core/infra/conf"
"github.com/xtls/xray-core/infra/conf/serial" "github.com/xtls/xray-core/infra/conf/serial"
"github.com/xtls/xray-core/proxy/shadowsocks" "github.com/xtls/xray-core/proxy/shadowsocks"
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
"github.com/xtls/xray-core/proxy/trojan" "github.com/xtls/xray-core/proxy/trojan"
vlessin "github.com/xtls/xray-core/proxy/vless/inbound" vlessin "github.com/xtls/xray-core/proxy/vless/inbound"
vmessin "github.com/xtls/xray-core/proxy/vmess/inbound" vmessin "github.com/xtls/xray-core/proxy/vmess/inbound"
@@ -86,8 +85,6 @@ func extractInboundUsers(inb *core.InboundHandlerConfig) []*protocol.User {
return ty.Users return ty.Users
case *shadowsocks.ServerConfig: case *shadowsocks.ServerConfig:
return ty.Users return ty.Users
case *shadowsocks_2022.MultiUserServerConfig:
return ty.Users
default: default:
fmt.Println("unsupported inbound type") fmt.Println("unsupported inbound type")
} }
+16 -15
View File
@@ -4,7 +4,6 @@ import (
"context" "context"
"crypto/rand" "crypto/rand"
"io" "io"
"strings"
"sync/atomic" "sync/atomic"
"time" "time"
@@ -164,12 +163,9 @@ func getDefaultFinalRule(inbound *session.Inbound) *FinalRule {
switch inbound.Name { switch inbound.Name {
case "vless-reverse": case "vless-reverse":
return defaultBlockAllRule return defaultBlockAllRule
case "vless", "vmess", "trojan", "hysteria", "wireguard": case "vless", "vmess", "trojan", "hysteria", "wireguard", "shadowsocks":
return defaultBlockPrivateRule return defaultBlockPrivateRule
default: default:
if strings.HasPrefix(inbound.Name, "shadowsocks") {
return defaultBlockPrivateRule
}
} }
return nil return nil
} }
@@ -190,6 +186,12 @@ func (h *Handler) matchFinalRule(network net.Network, address net.Address, port
func (h *Handler) Init(config *Config, pm policy.Manager) error { func (h *Handler) Init(config *Config, pm policy.Manager) error {
h.config = config h.config = config
h.policyManager = pm h.policyManager = pm
if h.usesDialerProxy { // freedom is not the final outbound, final rules do not apply
if len(config.FinalRules) > 0 {
errors.LogWarning(context.Background(), `The "finalRules" setting is ignored when "sockopt.dialerProxy" is set, since freedom is not the final outbound.`)
}
return nil
}
h.finalRules = make([]*FinalRule, 0, len(config.FinalRules)) h.finalRules = make([]*FinalRule, 0, len(config.FinalRules))
for _, rc := range config.FinalRules { for _, rc := range config.FinalRules {
rule, err := buildFinalRule(rc) rule, err := buildFinalRule(rc)
@@ -253,7 +255,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
ob.Name = "freedom" ob.Name = "freedom"
ob.CanSpliceCopy = 1 ob.CanSpliceCopy = 1
inbound := session.InboundFromContext(ctx) inbound := session.InboundFromContext(ctx)
defaultRule := getDefaultFinalRule(inbound) var defaultRule *FinalRule
if !h.usesDialerProxy { // freedom is not the final outbound, final rules do not apply (and the domain is not resolved)
defaultRule = getDefaultFinalRule(inbound)
}
destination := ob.Target destination := ob.Target
origTargetAddr := ob.OriginalTarget.Address origTargetAddr := ob.OriginalTarget.Address
@@ -342,15 +347,11 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return h.blackhole(ctx, input, output, blockedRule, blockedDest) return h.blackhole(ctx, input, output, blockedRule, blockedDest)
} }
if destination.Address.Family().IsDomain() && (defaultRule != nil || len(h.finalRules) > 0) { if destination.Address.Family().IsDomain() && (defaultRule != nil || len(h.finalRules) > 0) {
if h.usesDialerProxy { // pre-check may fail or dialer may select another IP
errors.LogInfo(ctx, "skipping final rule check for proxied remote endpoint, original target: ", destination) remoteDest := net.DestinationFromAddr(conn.RemoteAddr())
} else { if rule := h.matchFinalRule(remoteDest.Network, remoteDest.Address, remoteDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
// pre-check may fail or dialer may select another IP conn.Close()
remoteDest := net.DestinationFromAddr(conn.RemoteAddr()) return h.blackhole(ctx, input, output, rule, &remoteDest)
if rule := h.matchFinalRule(remoteDest.Network, remoteDest.Address, remoteDest.Port, defaultRule); rule != nil && rule.action == RuleAction_Block {
conn.Close()
return h.blackhole(ctx, input, output, rule, &remoteDest)
}
} }
} }
-33
View File
@@ -1,33 +0,0 @@
package shadowsocks_2022
import (
"google.golang.org/protobuf/proto"
"github.com/xtls/xray-core/common/protocol"
)
// MemoryAccount is an account type converted from Account.
type MemoryAccount struct {
Key string
}
// AsAccount implements protocol.AsAccount.
func (u *Account) AsAccount() (protocol.Account, error) {
return &MemoryAccount{
Key: u.GetKey(),
}, nil
}
// Equals implements protocol.Account.Equals().
func (a *MemoryAccount) Equals(another protocol.Account) bool {
if account, ok := another.(*MemoryAccount); ok {
return a.Key == account.Key
}
return false
}
func (a *MemoryAccount) ToProto() proto.Message {
return &Account{
Key: a.Key,
}
}
-523
View File
@@ -1,523 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v6.33.5
// source: proxy/shadowsocks_2022/config.proto
package shadowsocks_2022
import (
net "github.com/xtls/xray-core/common/net"
protocol "github.com/xtls/xray-core/common/protocol"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ServerConfig struct {
state protoimpl.MessageState `protogen:"open.v1"`
Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"`
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
Email string `protobuf:"bytes,3,opt,name=email,proto3" json:"email,omitempty"`
Level int32 `protobuf:"varint,4,opt,name=level,proto3" json:"level,omitempty"`
Network []net.Network `protobuf:"varint,5,rep,packed,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ServerConfig) Reset() {
*x = ServerConfig{}
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ServerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServerConfig) ProtoMessage() {}
func (x *ServerConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServerConfig.ProtoReflect.Descriptor instead.
func (*ServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_shadowsocks_2022_config_proto_rawDescGZIP(), []int{0}
}
func (x *ServerConfig) GetMethod() string {
if x != nil {
return x.Method
}
return ""
}
func (x *ServerConfig) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *ServerConfig) GetEmail() string {
if x != nil {
return x.Email
}
return ""
}
func (x *ServerConfig) GetLevel() int32 {
if x != nil {
return x.Level
}
return 0
}
func (x *ServerConfig) GetNetwork() []net.Network {
if x != nil {
return x.Network
}
return nil
}
type MultiUserServerConfig struct {
state protoimpl.MessageState `protogen:"open.v1"`
Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"`
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
Users []*protocol.User `protobuf:"bytes,3,rep,name=users,proto3" json:"users,omitempty"`
Network []net.Network `protobuf:"varint,4,rep,packed,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *MultiUserServerConfig) Reset() {
*x = MultiUserServerConfig{}
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *MultiUserServerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MultiUserServerConfig) ProtoMessage() {}
func (x *MultiUserServerConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MultiUserServerConfig.ProtoReflect.Descriptor instead.
func (*MultiUserServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_shadowsocks_2022_config_proto_rawDescGZIP(), []int{1}
}
func (x *MultiUserServerConfig) GetMethod() string {
if x != nil {
return x.Method
}
return ""
}
func (x *MultiUserServerConfig) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *MultiUserServerConfig) GetUsers() []*protocol.User {
if x != nil {
return x.Users
}
return nil
}
func (x *MultiUserServerConfig) GetNetwork() []net.Network {
if x != nil {
return x.Network
}
return nil
}
type RelayDestination struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Address *net.IPOrDomain `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
Port uint32 `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"`
Email string `protobuf:"bytes,4,opt,name=email,proto3" json:"email,omitempty"`
Level int32 `protobuf:"varint,5,opt,name=level,proto3" json:"level,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RelayDestination) Reset() {
*x = RelayDestination{}
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RelayDestination) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RelayDestination) ProtoMessage() {}
func (x *RelayDestination) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RelayDestination.ProtoReflect.Descriptor instead.
func (*RelayDestination) Descriptor() ([]byte, []int) {
return file_proxy_shadowsocks_2022_config_proto_rawDescGZIP(), []int{2}
}
func (x *RelayDestination) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *RelayDestination) GetAddress() *net.IPOrDomain {
if x != nil {
return x.Address
}
return nil
}
func (x *RelayDestination) GetPort() uint32 {
if x != nil {
return x.Port
}
return 0
}
func (x *RelayDestination) GetEmail() string {
if x != nil {
return x.Email
}
return ""
}
func (x *RelayDestination) GetLevel() int32 {
if x != nil {
return x.Level
}
return 0
}
type RelayServerConfig struct {
state protoimpl.MessageState `protogen:"open.v1"`
Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"`
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
Destinations []*RelayDestination `protobuf:"bytes,3,rep,name=destinations,proto3" json:"destinations,omitempty"`
Network []net.Network `protobuf:"varint,4,rep,packed,name=network,proto3,enum=xray.common.net.Network" json:"network,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RelayServerConfig) Reset() {
*x = RelayServerConfig{}
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RelayServerConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RelayServerConfig) ProtoMessage() {}
func (x *RelayServerConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RelayServerConfig.ProtoReflect.Descriptor instead.
func (*RelayServerConfig) Descriptor() ([]byte, []int) {
return file_proxy_shadowsocks_2022_config_proto_rawDescGZIP(), []int{3}
}
func (x *RelayServerConfig) GetMethod() string {
if x != nil {
return x.Method
}
return ""
}
func (x *RelayServerConfig) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *RelayServerConfig) GetDestinations() []*RelayDestination {
if x != nil {
return x.Destinations
}
return nil
}
func (x *RelayServerConfig) GetNetwork() []net.Network {
if x != nil {
return x.Network
}
return nil
}
type Account struct {
state protoimpl.MessageState `protogen:"open.v1"`
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Account) Reset() {
*x = Account{}
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Account) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Account) ProtoMessage() {}
func (x *Account) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
func (*Account) Descriptor() ([]byte, []int) {
return file_proxy_shadowsocks_2022_config_proto_rawDescGZIP(), []int{4}
}
func (x *Account) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
type ClientConfig struct {
state protoimpl.MessageState `protogen:"open.v1"`
Address *net.IPOrDomain `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Port uint32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"`
Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ClientConfig) Reset() {
*x = ClientConfig{}
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ClientConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ClientConfig) ProtoMessage() {}
func (x *ClientConfig) ProtoReflect() protoreflect.Message {
mi := &file_proxy_shadowsocks_2022_config_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.
func (*ClientConfig) Descriptor() ([]byte, []int) {
return file_proxy_shadowsocks_2022_config_proto_rawDescGZIP(), []int{5}
}
func (x *ClientConfig) GetAddress() *net.IPOrDomain {
if x != nil {
return x.Address
}
return nil
}
func (x *ClientConfig) GetPort() uint32 {
if x != nil {
return x.Port
}
return 0
}
func (x *ClientConfig) GetMethod() string {
if x != nil {
return x.Method
}
return ""
}
func (x *ClientConfig) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
var File_proxy_shadowsocks_2022_config_proto protoreflect.FileDescriptor
const file_proxy_shadowsocks_2022_config_proto_rawDesc = "" +
"\n" +
"#proxy/shadowsocks_2022/config.proto\x12\x1bxray.proxy.shadowsocks_2022\x1a\x18common/net/network.proto\x1a\x18common/net/address.proto\x1a\x1acommon/protocol/user.proto\"\x98\x01\n" +
"\fServerConfig\x12\x16\n" +
"\x06method\x18\x01 \x01(\tR\x06method\x12\x10\n" +
"\x03key\x18\x02 \x01(\tR\x03key\x12\x14\n" +
"\x05email\x18\x03 \x01(\tR\x05email\x12\x14\n" +
"\x05level\x18\x04 \x01(\x05R\x05level\x122\n" +
"\anetwork\x18\x05 \x03(\x0e2\x18.xray.common.net.NetworkR\anetwork\"\xa7\x01\n" +
"\x15MultiUserServerConfig\x12\x16\n" +
"\x06method\x18\x01 \x01(\tR\x06method\x12\x10\n" +
"\x03key\x18\x02 \x01(\tR\x03key\x120\n" +
"\x05users\x18\x03 \x03(\v2\x1a.xray.common.protocol.UserR\x05users\x122\n" +
"\anetwork\x18\x04 \x03(\x0e2\x18.xray.common.net.NetworkR\anetwork\"\x9b\x01\n" +
"\x10RelayDestination\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x125\n" +
"\aaddress\x18\x02 \x01(\v2\x1b.xray.common.net.IPOrDomainR\aaddress\x12\x12\n" +
"\x04port\x18\x03 \x01(\rR\x04port\x12\x14\n" +
"\x05email\x18\x04 \x01(\tR\x05email\x12\x14\n" +
"\x05level\x18\x05 \x01(\x05R\x05level\"\xc4\x01\n" +
"\x11RelayServerConfig\x12\x16\n" +
"\x06method\x18\x01 \x01(\tR\x06method\x12\x10\n" +
"\x03key\x18\x02 \x01(\tR\x03key\x12Q\n" +
"\fdestinations\x18\x03 \x03(\v2-.xray.proxy.shadowsocks_2022.RelayDestinationR\fdestinations\x122\n" +
"\anetwork\x18\x04 \x03(\x0e2\x18.xray.common.net.NetworkR\anetwork\"\x1b\n" +
"\aAccount\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\"\x83\x01\n" +
"\fClientConfig\x125\n" +
"\aaddress\x18\x01 \x01(\v2\x1b.xray.common.net.IPOrDomainR\aaddress\x12\x12\n" +
"\x04port\x18\x02 \x01(\rR\x04port\x12\x16\n" +
"\x06method\x18\x03 \x01(\tR\x06method\x12\x10\n" +
"\x03key\x18\x04 \x01(\tR\x03keyBr\n" +
"\x1fcom.xray.proxy.shadowsocks_2022P\x01Z0github.com/xtls/xray-core/proxy/shadowsocks_2022\xaa\x02\x1aXray.Proxy.Shadowsocks2022b\x06proto3"
var (
file_proxy_shadowsocks_2022_config_proto_rawDescOnce sync.Once
file_proxy_shadowsocks_2022_config_proto_rawDescData []byte
)
func file_proxy_shadowsocks_2022_config_proto_rawDescGZIP() []byte {
file_proxy_shadowsocks_2022_config_proto_rawDescOnce.Do(func() {
file_proxy_shadowsocks_2022_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proxy_shadowsocks_2022_config_proto_rawDesc), len(file_proxy_shadowsocks_2022_config_proto_rawDesc)))
})
return file_proxy_shadowsocks_2022_config_proto_rawDescData
}
var file_proxy_shadowsocks_2022_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_proxy_shadowsocks_2022_config_proto_goTypes = []any{
(*ServerConfig)(nil), // 0: xray.proxy.shadowsocks_2022.ServerConfig
(*MultiUserServerConfig)(nil), // 1: xray.proxy.shadowsocks_2022.MultiUserServerConfig
(*RelayDestination)(nil), // 2: xray.proxy.shadowsocks_2022.RelayDestination
(*RelayServerConfig)(nil), // 3: xray.proxy.shadowsocks_2022.RelayServerConfig
(*Account)(nil), // 4: xray.proxy.shadowsocks_2022.Account
(*ClientConfig)(nil), // 5: xray.proxy.shadowsocks_2022.ClientConfig
(net.Network)(0), // 6: xray.common.net.Network
(*protocol.User)(nil), // 7: xray.common.protocol.User
(*net.IPOrDomain)(nil), // 8: xray.common.net.IPOrDomain
}
var file_proxy_shadowsocks_2022_config_proto_depIdxs = []int32{
6, // 0: xray.proxy.shadowsocks_2022.ServerConfig.network:type_name -> xray.common.net.Network
7, // 1: xray.proxy.shadowsocks_2022.MultiUserServerConfig.users:type_name -> xray.common.protocol.User
6, // 2: xray.proxy.shadowsocks_2022.MultiUserServerConfig.network:type_name -> xray.common.net.Network
8, // 3: xray.proxy.shadowsocks_2022.RelayDestination.address:type_name -> xray.common.net.IPOrDomain
2, // 4: xray.proxy.shadowsocks_2022.RelayServerConfig.destinations:type_name -> xray.proxy.shadowsocks_2022.RelayDestination
6, // 5: xray.proxy.shadowsocks_2022.RelayServerConfig.network:type_name -> xray.common.net.Network
8, // 6: xray.proxy.shadowsocks_2022.ClientConfig.address:type_name -> xray.common.net.IPOrDomain
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_proxy_shadowsocks_2022_config_proto_init() }
func file_proxy_shadowsocks_2022_config_proto_init() {
if File_proxy_shadowsocks_2022_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proxy_shadowsocks_2022_config_proto_rawDesc), len(file_proxy_shadowsocks_2022_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proxy_shadowsocks_2022_config_proto_goTypes,
DependencyIndexes: file_proxy_shadowsocks_2022_config_proto_depIdxs,
MessageInfos: file_proxy_shadowsocks_2022_config_proto_msgTypes,
}.Build()
File_proxy_shadowsocks_2022_config_proto = out.File
file_proxy_shadowsocks_2022_config_proto_goTypes = nil
file_proxy_shadowsocks_2022_config_proto_depIdxs = nil
}
-52
View File
@@ -1,52 +0,0 @@
syntax = "proto3";
package xray.proxy.shadowsocks_2022;
option csharp_namespace = "Xray.Proxy.Shadowsocks2022";
option go_package = "github.com/xtls/xray-core/proxy/shadowsocks_2022";
option java_package = "com.xray.proxy.shadowsocks_2022";
option java_multiple_files = true;
import "common/net/network.proto";
import "common/net/address.proto";
import "common/protocol/user.proto";
message ServerConfig {
string method = 1;
string key = 2;
string email = 3;
int32 level = 4;
repeated xray.common.net.Network network = 5;
}
message MultiUserServerConfig {
string method = 1;
string key = 2;
repeated xray.common.protocol.User users = 3;
repeated xray.common.net.Network network = 4;
}
message RelayDestination {
string key = 1;
xray.common.net.IPOrDomain address = 2;
uint32 port = 3;
string email = 4;
int32 level = 5;
}
message RelayServerConfig {
string method = 1;
string key = 2;
repeated RelayDestination destinations = 3;
repeated xray.common.net.Network network = 4;
}
message Account {
string key = 1;
}
message ClientConfig {
xray.common.net.IPOrDomain address = 1;
uint32 port = 2;
string method = 3;
string key = 4;
}
-183
View File
@@ -1,183 +0,0 @@
package shadowsocks_2022
import (
"context"
"time"
shadowsocks "github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
C "github.com/sagernet/sing/common"
B "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
)
func init() {
common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewServer(ctx, config.(*ServerConfig))
}))
}
type Inbound struct {
networks []net.Network
service shadowsocks.Service
email string
level int
}
func NewServer(ctx context.Context, config *ServerConfig) (*Inbound, error) {
networks := config.Network
if len(networks) == 0 {
networks = []net.Network{
net.Network_TCP,
net.Network_UDP,
}
}
inbound := &Inbound{
networks: networks,
email: config.Email,
level: int(config.Level),
}
if !C.Contains(shadowaead_2022.List, config.Method) {
return nil, errors.New("unsupported method ", config.Method)
}
service, err := shadowaead_2022.NewServiceWithPassword(config.Method, config.Key, 500, inbound, nil)
if err != nil {
return nil, errors.New("create service").Base(err)
}
inbound.service = service
return inbound, nil
}
func (i *Inbound) Network() []net.Network {
return i.networks
}
func (i *Inbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
inbound := session.InboundFromContext(ctx)
inbound.Name = "shadowsocks-2022"
inbound.CanSpliceCopy = 3
var metadata M.Metadata
if inbound.Source.IsValid() {
metadata.Source = M.ParseSocksaddr(inbound.Source.NetAddr())
}
ctx = session.ContextWithDispatcher(ctx, dispatcher)
if network == net.Network_TCP {
return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
} else {
reader := buf.NewReader(connection)
pc := &natPacketConn{connection}
for {
mb, err := reader.ReadMultiBuffer()
if err != nil {
buf.ReleaseMulti(mb)
return singbridge.ReturnError(err)
}
for _, buffer := range mb {
packet := B.As(buffer.Bytes()).ToOwned()
buffer.Release()
err = i.service.NewPacket(ctx, pc, packet, metadata)
if err != nil {
packet.Release()
buf.ReleaseMulti(mb)
return err
}
}
}
}
}
func (i *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
inbound := session.InboundFromContext(ctx)
inbound.User = &protocol.MemoryUser{
Email: i.email,
Level: uint32(i.level),
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: metadata.Source,
To: metadata.Destination,
Status: log.AccessAccepted,
Email: i.email,
})
errors.LogInfo(ctx, "tunnelling request to tcp:", metadata.Destination)
dispatcher := session.DispatcherFromContext(ctx)
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_TCP)
if err != nil {
return err
}
link, err := dispatcher.Dispatch(ctx, destination)
if err != nil {
return err
}
return singbridge.CopyConn(ctx, nil, link, conn)
}
func (i *Inbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
inbound := session.InboundFromContext(ctx)
inbound.User = &protocol.MemoryUser{
Email: i.email,
Level: uint32(i.level),
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: metadata.Source,
To: metadata.Destination,
Status: log.AccessAccepted,
Email: i.email,
})
errors.LogInfo(ctx, "tunnelling request to udp:", metadata.Destination)
dispatcher := session.DispatcherFromContext(ctx)
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
if err != nil {
return err
}
link, err := dispatcher.Dispatch(ctx, destination)
if err != nil {
return err
}
outConn := &singbridge.PacketConnWrapper{
Reader: link.Reader,
Writer: link.Writer,
Dest: destination,
T: signal.CancelAfterInactivity(ctx, func() {
common.Interrupt(link.Reader)
}, 300*time.Second),
}
return bufio.CopyPacketConn(ctx, conn, outConn)
}
func (i *Inbound) NewError(ctx context.Context, err error) {
if E.IsClosed(err) {
return
}
errors.LogWarning(ctx, err.Error())
}
type natPacketConn struct {
net.Conn
}
func (c *natPacketConn) ReadPacket(buffer *B.Buffer) (addr M.Socksaddr, err error) {
_, err = buffer.ReadFrom(c)
return
}
func (c *natPacketConn) WritePacket(buffer *B.Buffer, addr M.Socksaddr) error {
_, err := buffer.WriteTo(c)
return err
}
-290
View File
@@ -1,290 +0,0 @@
package shadowsocks_2022
import (
"context"
"encoding/base64"
"strconv"
"strings"
"sync"
"time"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
C "github.com/sagernet/sing/common"
A "github.com/sagernet/sing/common/auth"
B "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
)
func init() {
common.Must(common.RegisterConfig((*MultiUserServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewMultiServer(ctx, config.(*MultiUserServerConfig))
}))
}
type MultiUserInbound struct {
sync.Mutex
networks []net.Network
users []*protocol.MemoryUser
service *shadowaead_2022.MultiService[int]
}
func NewMultiServer(ctx context.Context, config *MultiUserServerConfig) (*MultiUserInbound, error) {
networks := config.Network
if len(networks) == 0 {
networks = []net.Network{
net.Network_TCP,
net.Network_UDP,
}
}
memUsers := []*protocol.MemoryUser{}
for i, user := range config.Users {
if user.Email == "" {
u := uuid.New()
user.Email = "unnamed-user-" + strconv.Itoa(i) + "-" + u.String()
}
u, err := user.ToMemoryUser()
if err != nil {
return nil, errors.New("failed to get shadowsocks user").Base(err).AtError()
}
memUsers = append(memUsers, u)
}
inbound := &MultiUserInbound{
networks: networks,
users: memUsers,
}
if config.Key == "" {
return nil, errors.New("missing key")
}
psk, err := base64.StdEncoding.DecodeString(config.Key)
if err != nil {
return nil, errors.New("parse config").Base(err)
}
service, err := shadowaead_2022.NewMultiService[int](config.Method, psk, 500, inbound, nil)
if err != nil {
return nil, errors.New("create service").Base(err)
}
err = service.UpdateUsersWithPasswords(
C.MapIndexed(memUsers, func(index int, it *protocol.MemoryUser) int { return index }),
C.Map(memUsers, func(it *protocol.MemoryUser) string { return it.Account.(*MemoryAccount).Key }),
)
if err != nil {
return nil, errors.New("create service").Base(err)
}
inbound.service = service
return inbound, nil
}
// AddUser implements proxy.UserManager.AddUser().
func (i *MultiUserInbound) AddUser(ctx context.Context, u *protocol.MemoryUser) error {
i.Lock()
defer i.Unlock()
if u.Email != "" {
for idx := range i.users {
if i.users[idx].Email == u.Email {
return errors.New("User ", u.Email, " already exists.")
}
}
}
i.users = append(i.users, u)
// sync to multi service
// Considering implements shadowsocks2022 in xray-core may have better performance.
i.service.UpdateUsersWithPasswords(
C.MapIndexed(i.users, func(index int, it *protocol.MemoryUser) int { return index }),
C.Map(i.users, func(it *protocol.MemoryUser) string { return it.Account.(*MemoryAccount).Key }),
)
return nil
}
// RemoveUser implements proxy.UserManager.RemoveUser().
func (i *MultiUserInbound) RemoveUser(ctx context.Context, email string) error {
if email == "" {
return errors.New("Email must not be empty.")
}
i.Lock()
defer i.Unlock()
idx := -1
for ii, u := range i.users {
if strings.EqualFold(u.Email, email) {
idx = ii
break
}
}
if idx == -1 {
return errors.New("User ", email, " not found.")
}
ulen := len(i.users)
i.users[idx] = i.users[ulen-1]
i.users[ulen-1] = nil
i.users = i.users[:ulen-1]
// sync to multi service
// Considering implements shadowsocks2022 in xray-core may have better performance.
i.service.UpdateUsersWithPasswords(
C.MapIndexed(i.users, func(index int, it *protocol.MemoryUser) int { return index }),
C.Map(i.users, func(it *protocol.MemoryUser) string { return it.Account.(*MemoryAccount).Key }),
)
return nil
}
// GetUser implements proxy.UserManager.GetUser().
func (i *MultiUserInbound) GetUser(ctx context.Context, email string) *protocol.MemoryUser {
if email == "" {
return nil
}
i.Lock()
defer i.Unlock()
for _, u := range i.users {
if strings.EqualFold(u.Email, email) {
return u
}
}
return nil
}
// GetUsers implements proxy.UserManager.GetUsers().
func (i *MultiUserInbound) GetUsers(ctx context.Context) []*protocol.MemoryUser {
i.Lock()
defer i.Unlock()
dst := make([]*protocol.MemoryUser, len(i.users))
copy(dst, i.users)
return dst
}
// GetUsersCount implements proxy.UserManager.GetUsersCount().
func (i *MultiUserInbound) GetUsersCount(context.Context) int64 {
i.Lock()
defer i.Unlock()
return int64(len(i.users))
}
func (i *MultiUserInbound) Network() []net.Network {
return i.networks
}
func (i *MultiUserInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
inbound := session.InboundFromContext(ctx)
inbound.Name = "shadowsocks-2022-multi"
inbound.CanSpliceCopy = 3
var metadata M.Metadata
if inbound.Source.IsValid() {
metadata.Source = M.ParseSocksaddr(inbound.Source.NetAddr())
}
ctx = session.ContextWithDispatcher(ctx, dispatcher)
if network == net.Network_TCP {
return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
} else {
reader := buf.NewReader(connection)
pc := &natPacketConn{connection}
for {
mb, err := reader.ReadMultiBuffer()
if err != nil {
buf.ReleaseMulti(mb)
return singbridge.ReturnError(err)
}
for _, buffer := range mb {
packet := B.As(buffer.Bytes()).ToOwned()
buffer.Release()
err = i.service.NewPacket(ctx, pc, packet, metadata)
if err != nil {
packet.Release()
buf.ReleaseMulti(mb)
return err
}
}
}
}
}
func (i *MultiUserInbound) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
inbound := session.InboundFromContext(ctx)
userInt, _ := A.UserFromContext[int](ctx)
user := i.users[userInt]
inbound.User = user
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: metadata.Source,
To: metadata.Destination,
Status: log.AccessAccepted,
Email: user.Email,
})
errors.LogInfo(ctx, "tunnelling request to tcp:", metadata.Destination)
dispatcher := session.DispatcherFromContext(ctx)
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_TCP)
if err != nil {
return err
}
link, err := dispatcher.Dispatch(ctx, destination)
if err != nil {
return err
}
return singbridge.CopyConn(ctx, conn, link, conn)
}
func (i *MultiUserInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
inbound := session.InboundFromContext(ctx)
userInt, _ := A.UserFromContext[int](ctx)
user := i.users[userInt]
inbound.User = user
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: metadata.Source,
To: metadata.Destination,
Status: log.AccessAccepted,
Email: user.Email,
})
errors.LogInfo(ctx, "tunnelling request to udp:", metadata.Destination)
dispatcher := session.DispatcherFromContext(ctx)
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
if err != nil {
return err
}
link, err := dispatcher.Dispatch(ctx, destination)
if err != nil {
return err
}
outConn := &singbridge.PacketConnWrapper{
Reader: link.Reader,
Writer: link.Writer,
Dest: destination,
T: signal.CancelAfterInactivity(ctx, func() {
common.Interrupt(link.Reader)
}, 300*time.Second),
}
return bufio.CopyPacketConn(ctx, conn, outConn)
}
func (i *MultiUserInbound) NewError(ctx context.Context, err error) {
if E.IsClosed(err) {
return
}
errors.LogWarning(ctx, err.Error())
}
-194
View File
@@ -1,194 +0,0 @@
package shadowsocks_2022
import (
"context"
"strconv"
"strings"
"time"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
C "github.com/sagernet/sing/common"
A "github.com/sagernet/sing/common/auth"
B "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/features/routing"
"github.com/xtls/xray-core/transport/internet/stat"
)
func init() {
common.Must(common.RegisterConfig((*RelayServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewRelayServer(ctx, config.(*RelayServerConfig))
}))
}
type RelayInbound struct {
networks []net.Network
destinations []*RelayDestination
service *shadowaead_2022.RelayService[int]
}
func NewRelayServer(ctx context.Context, config *RelayServerConfig) (*RelayInbound, error) {
networks := config.Network
if len(networks) == 0 {
networks = []net.Network{
net.Network_TCP,
net.Network_UDP,
}
}
inbound := &RelayInbound{
networks: networks,
destinations: config.Destinations,
}
if !C.Contains(shadowaead_2022.List, config.Method) || !strings.Contains(config.Method, "aes") {
return nil, errors.New("unsupported method ", config.Method)
}
service, err := shadowaead_2022.NewRelayServiceWithPassword[int](config.Method, config.Key, 500, inbound)
if err != nil {
return nil, errors.New("create service").Base(err)
}
for i, destination := range config.Destinations {
if destination.Email == "" {
u := uuid.New()
destination.Email = "unnamed-destination-" + strconv.Itoa(i) + "-" + u.String()
}
}
err = service.UpdateUsersWithPasswords(
C.MapIndexed(config.Destinations, func(index int, it *RelayDestination) int { return index }),
C.Map(config.Destinations, func(it *RelayDestination) string { return it.Key }),
C.Map(config.Destinations, func(it *RelayDestination) M.Socksaddr {
return singbridge.ToSocksaddr(net.Destination{
Address: it.Address.AsAddress(),
Port: net.Port(it.Port),
})
}),
)
if err != nil {
return nil, errors.New("create service").Base(err)
}
inbound.service = service
return inbound, nil
}
func (i *RelayInbound) Network() []net.Network {
return i.networks
}
func (i *RelayInbound) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
inbound := session.InboundFromContext(ctx)
inbound.Name = "shadowsocks-2022-relay"
inbound.CanSpliceCopy = 3
var metadata M.Metadata
if inbound.Source.IsValid() {
metadata.Source = M.ParseSocksaddr(inbound.Source.NetAddr())
}
ctx = session.ContextWithDispatcher(ctx, dispatcher)
if network == net.Network_TCP {
return singbridge.ReturnError(i.service.NewConnection(ctx, connection, metadata))
} else {
reader := buf.NewReader(connection)
pc := &natPacketConn{connection}
for {
mb, err := reader.ReadMultiBuffer()
if err != nil {
buf.ReleaseMulti(mb)
return singbridge.ReturnError(err)
}
for _, buffer := range mb {
packet := B.As(buffer.Bytes()).ToOwned()
buffer.Release()
err = i.service.NewPacket(ctx, pc, packet, metadata)
if err != nil {
packet.Release()
buf.ReleaseMulti(mb)
return err
}
}
}
}
}
func (i *RelayInbound) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
inbound := session.InboundFromContext(ctx)
userInt, _ := A.UserFromContext[int](ctx)
user := i.destinations[userInt]
inbound.User = &protocol.MemoryUser{
Email: user.Email,
Level: uint32(user.Level),
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: metadata.Source,
To: metadata.Destination,
Status: log.AccessAccepted,
Email: user.Email,
})
errors.LogInfo(ctx, "tunnelling request to tcp:", metadata.Destination)
dispatcher := session.DispatcherFromContext(ctx)
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_TCP)
if err != nil {
return err
}
link, err := dispatcher.Dispatch(ctx, destination)
if err != nil {
return err
}
return singbridge.CopyConn(ctx, nil, link, conn)
}
func (i *RelayInbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
inbound := session.InboundFromContext(ctx)
userInt, _ := A.UserFromContext[int](ctx)
user := i.destinations[userInt]
inbound.User = &protocol.MemoryUser{
Email: user.Email,
Level: uint32(user.Level),
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: metadata.Source,
To: metadata.Destination,
Status: log.AccessAccepted,
Email: user.Email,
})
errors.LogInfo(ctx, "tunnelling request to udp:", metadata.Destination)
dispatcher := session.DispatcherFromContext(ctx)
destination, err := singbridge.ToDestination(metadata.Destination, net.Network_UDP)
if err != nil {
return err
}
link, err := dispatcher.Dispatch(ctx, destination)
if err != nil {
return err
}
outConn := &singbridge.PacketConnWrapper{
Reader: link.Reader,
Writer: link.Writer,
Dest: destination,
T: signal.CancelAfterInactivity(ctx, func() {
common.Interrupt(link.Reader)
}, 300*time.Second),
}
return bufio.CopyPacketConn(ctx, conn, outConn)
}
func (i *RelayInbound) NewError(ctx context.Context, err error) {
if E.IsClosed(err) {
return
}
errors.LogWarning(ctx, err.Error())
}
-147
View File
@@ -1,147 +0,0 @@
package shadowsocks_2022
import (
"context"
"time"
shadowsocks "github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
C "github.com/sagernet/sing/common"
B "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
N "github.com/sagernet/sing/common/network"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/session"
"github.com/xtls/xray-core/common/signal"
"github.com/xtls/xray-core/common/singbridge"
"github.com/xtls/xray-core/transport"
"github.com/xtls/xray-core/transport/internet"
)
func init() {
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewClient(ctx, config.(*ClientConfig))
}))
}
type Outbound struct {
ctx context.Context
server net.Destination
method shadowsocks.Method
}
func NewClient(ctx context.Context, config *ClientConfig) (*Outbound, error) {
o := &Outbound{
ctx: ctx,
server: net.Destination{
Address: config.Address.AsAddress(),
Port: net.Port(config.Port),
Network: net.Network_TCP,
},
}
if C.Contains(shadowaead_2022.List, config.Method) {
if config.Key == "" {
return nil, errors.New("missing psk")
}
method, err := shadowaead_2022.NewWithPassword(config.Method, config.Key, nil)
if err != nil {
return nil, errors.New("create method").Base(err)
}
o.method = method
} else {
return nil, errors.New("unknown method ", config.Method)
}
return o, nil
}
func (o *Outbound) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
var inboundConn net.Conn
inbound := session.InboundFromContext(ctx)
if inbound != nil {
inboundConn = inbound.Conn
}
outbounds := session.OutboundsFromContext(ctx)
ob := outbounds[len(outbounds)-1]
if !ob.Target.IsValid() {
return errors.New("target not specified")
}
ob.Name = "shadowsocks-2022"
ob.CanSpliceCopy = 3
destination := ob.Target
network := destination.Network
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", o.server.NetAddr())
serverDestination := o.server
serverDestination.Network = network
connection, err := dialer.Dial(ctx, serverDestination)
if err != nil {
return errors.New("failed to connect to server").Base(err)
}
defer connection.Close()
if session.TimeoutOnlyFromContext(ctx) {
ctx, _ = context.WithCancel(context.Background())
}
if network == net.Network_TCP {
serverConn := o.method.DialEarlyConn(connection, singbridge.ToSocksaddr(destination))
var handshake bool
if timeoutReader, isTimeoutReader := link.Reader.(buf.TimeoutReader); isTimeoutReader {
mb, err := timeoutReader.ReadMultiBufferTimeout(time.Millisecond * 100)
if err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
return errors.New("read payload").Base(err)
}
payload := B.New()
for {
payload.Reset()
nb, n := buf.SplitBytes(mb, payload.FreeBytes())
if n > 0 {
payload.Truncate(n)
_, err = serverConn.Write(payload.Bytes())
if err != nil {
payload.Release()
return errors.New("write payload").Base(err)
}
handshake = true
}
if nb.IsEmpty() {
break
}
mb = nb
}
payload.Release()
}
if !handshake {
_, err = serverConn.Write(nil)
if err != nil {
return errors.New("client handshake").Base(err)
}
}
return singbridge.CopyConn(ctx, inboundConn, link, serverConn)
} else {
var packetConn N.PacketConn
if pc, isPacketConn := inboundConn.(N.PacketConn); isPacketConn {
packetConn = pc
} else if nc, isNetPacket := inboundConn.(net.PacketConn); isNetPacket {
packetConn = bufio.NewPacketConn(nc)
} else {
packetConn = &singbridge.PacketConnWrapper{
Reader: link.Reader,
Writer: link.Writer,
Conn: inboundConn,
Dest: destination,
T: signal.CancelAfterInactivity(ctx, func() {
common.Interrupt(link.Reader)
}, 300*time.Second),
}
}
serverConn := o.method.DialPacketConn(connection)
return singbridge.ReturnError(bufio.CopyPacketConn(ctx, packetConn, serverConn))
}
}
@@ -1 +0,0 @@
package shadowsocks_2022
-221
View File
@@ -1,221 +0,0 @@
package scenarios
import (
"crypto/rand"
"encoding/base64"
"testing"
"time"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
"github.com/xtls/xray-core/app/log"
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common"
clog "github.com/xtls/xray-core/common/log"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/core"
"github.com/xtls/xray-core/proxy/dokodemo"
"github.com/xtls/xray-core/proxy/freedom"
"github.com/xtls/xray-core/proxy/shadowsocks_2022"
"github.com/xtls/xray-core/testing/servers/tcp"
"github.com/xtls/xray-core/testing/servers/udp"
"golang.org/x/sync/errgroup"
)
func TestShadowsocks2022Tcp(t *testing.T) {
for _, method := range shadowaead_2022.List {
password := make([]byte, 32)
rand.Read(password)
t.Run(method, func(t *testing.T) {
testShadowsocks2022Tcp(t, method, base64.StdEncoding.EncodeToString(password))
})
}
}
func TestShadowsocks2022UdpAES128(t *testing.T) {
password := make([]byte, 32)
rand.Read(password)
testShadowsocks2022Udp(t, shadowaead_2022.List[0], base64.StdEncoding.EncodeToString(password))
}
func TestShadowsocks2022UdpAES256(t *testing.T) {
password := make([]byte, 32)
rand.Read(password)
testShadowsocks2022Udp(t, shadowaead_2022.List[1], base64.StdEncoding.EncodeToString(password))
}
func TestShadowsocks2022UdpChacha(t *testing.T) {
password := make([]byte, 32)
rand.Read(password)
testShadowsocks2022Udp(t, shadowaead_2022.List[2], base64.StdEncoding.EncodeToString(password))
}
func testShadowsocks2022Tcp(t *testing.T, method string, password string) {
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()
serverPort := tcp.PickPort()
serverConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&shadowsocks_2022.ServerConfig{
Method: method,
Key: password,
Network: []net.Network{net.Network_TCP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
}),
},
},
}
clientPort := tcp.PickPort()
clientConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
RewriteAddress: net.NewIPOrDomain(dest.Address),
RewritePort: uint32(dest.Port),
AllowedNetworks: []net.Network{net.Network_TCP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&shadowsocks_2022.ClientConfig{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
Method: method,
Key: password,
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)
var errGroup errgroup.Group
for range 3 {
errGroup.Go(testTCPConn(clientPort, 10240*1024, time.Second*20))
}
if err := errGroup.Wait(); err != nil {
t.Error(err)
}
}
func testShadowsocks2022Udp(t *testing.T, method string, password string) {
udpServer := udp.Server{
MsgProcessor: xor,
}
udpDest, err := udpServer.Start()
common.Must(err)
defer udpServer.Close()
serverPort := udp.PickPort()
serverConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&shadowsocks_2022.ServerConfig{
Method: method,
Key: password,
Network: []net.Network{net.Network_UDP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
}),
},
},
}
udpClientPort := udp.PickPort()
clientConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&log.Config{
ErrorLogLevel: clog.Severity_Debug,
ErrorLogType: log.LogType_Console,
}),
},
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(udpClientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
RewriteAddress: net.NewIPOrDomain(udpDest.Address),
RewritePort: uint32(udpDest.Port),
AllowedNetworks: []net.Network{net.Network_UDP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&shadowsocks_2022.ClientConfig{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
Method: method,
Key: password,
}),
},
},
}
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)
var errGroup errgroup.Group
for range 3 {
errGroup.Go(testUDPConn(udpClientPort, 1024, time.Second*5))
}
if err := errGroup.Wait(); err != nil {
t.Error(err)
}
}
+63 -138
View File
@@ -206,7 +206,7 @@ func (x SocketConfig_TProxyMode) Number() protoreflect.EnumNumber {
// Deprecated: Use SocketConfig_TProxyMode.Descriptor instead. // Deprecated: Use SocketConfig_TProxyMode.Descriptor instead.
func (SocketConfig_TProxyMode) EnumDescriptor() ([]byte, []int) { func (SocketConfig_TProxyMode) EnumDescriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{5, 0} return file_transport_internet_config_proto_rawDescGZIP(), []int{4, 0}
} }
type TransportConfig struct { type TransportConfig struct {
@@ -382,66 +382,6 @@ func (x *StreamConfig) GetSocketSettings() *SocketConfig {
return nil return nil
} }
type UdpHop struct {
state protoimpl.MessageState `protogen:"open.v1"`
Ports []uint32 `protobuf:"varint,1,rep,packed,name=ports,proto3" json:"ports,omitempty"`
IntervalMin int64 `protobuf:"varint,2,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"`
IntervalMax int64 `protobuf:"varint,3,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *UdpHop) Reset() {
*x = UdpHop{}
mi := &file_transport_internet_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UdpHop) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UdpHop) ProtoMessage() {}
func (x *UdpHop) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_config_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UdpHop.ProtoReflect.Descriptor instead.
func (*UdpHop) Descriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{2}
}
func (x *UdpHop) GetPorts() []uint32 {
if x != nil {
return x.Ports
}
return nil
}
func (x *UdpHop) GetIntervalMin() int64 {
if x != nil {
return x.IntervalMin
}
return 0
}
func (x *UdpHop) GetIntervalMax() int64 {
if x != nil {
return x.IntervalMax
}
return 0
}
type QuicParams struct { type QuicParams struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Congestion string `protobuf:"bytes,1,opt,name=congestion,proto3" json:"congestion,omitempty"` Congestion string `protobuf:"bytes,1,opt,name=congestion,proto3" json:"congestion,omitempty"`
@@ -449,25 +389,24 @@ type QuicParams struct {
BrutalUp uint64 `protobuf:"varint,3,opt,name=brutal_up,json=brutalUp,proto3" json:"brutal_up,omitempty"` BrutalUp uint64 `protobuf:"varint,3,opt,name=brutal_up,json=brutalUp,proto3" json:"brutal_up,omitempty"`
BrutalDown uint64 `protobuf:"varint,4,opt,name=brutal_down,json=brutalDown,proto3" json:"brutal_down,omitempty"` BrutalDown uint64 `protobuf:"varint,4,opt,name=brutal_down,json=brutalDown,proto3" json:"brutal_down,omitempty"`
BrutalDisableLossCompensation bool `protobuf:"varint,5,opt,name=brutal_disable_loss_compensation,json=brutalDisableLossCompensation,proto3" json:"brutal_disable_loss_compensation,omitempty"` BrutalDisableLossCompensation bool `protobuf:"varint,5,opt,name=brutal_disable_loss_compensation,json=brutalDisableLossCompensation,proto3" json:"brutal_disable_loss_compensation,omitempty"`
UdpHop *UdpHop `protobuf:"bytes,6,opt,name=udp_hop,json=udpHop,proto3" json:"udp_hop,omitempty"` InitStreamReceiveWindow uint64 `protobuf:"varint,6,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"`
InitStreamReceiveWindow uint64 `protobuf:"varint,7,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"` MaxStreamReceiveWindow uint64 `protobuf:"varint,7,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"`
MaxStreamReceiveWindow uint64 `protobuf:"varint,8,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"` InitConnReceiveWindow uint64 `protobuf:"varint,8,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"`
InitConnReceiveWindow uint64 `protobuf:"varint,9,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"` MaxConnReceiveWindow uint64 `protobuf:"varint,9,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"`
MaxConnReceiveWindow uint64 `protobuf:"varint,10,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"` MaxIdleTimeout int64 `protobuf:"varint,10,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"`
MaxIdleTimeout int64 `protobuf:"varint,11,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"` KeepAlivePeriod int64 `protobuf:"varint,11,opt,name=keep_alive_period,json=keepAlivePeriod,proto3" json:"keep_alive_period,omitempty"`
KeepAlivePeriod int64 `protobuf:"varint,12,opt,name=keep_alive_period,json=keepAlivePeriod,proto3" json:"keep_alive_period,omitempty"` DisablePathMtuDiscovery bool `protobuf:"varint,12,opt,name=disable_path_mtu_discovery,json=disablePathMtuDiscovery,proto3" json:"disable_path_mtu_discovery,omitempty"`
DisablePathMtuDiscovery bool `protobuf:"varint,13,opt,name=disable_path_mtu_discovery,json=disablePathMtuDiscovery,proto3" json:"disable_path_mtu_discovery,omitempty"` DisableChromeParrot bool `protobuf:"varint,13,opt,name=disable_chrome_parrot,json=disableChromeParrot,proto3" json:"disable_chrome_parrot,omitempty"`
DisableChromeParrot bool `protobuf:"varint,14,opt,name=disable_chrome_parrot,json=disableChromeParrot,proto3" json:"disable_chrome_parrot,omitempty"` DisableGSO bool `protobuf:"varint,14,opt,name=disableGSO,proto3" json:"disableGSO,omitempty"`
DisableGSO bool `protobuf:"varint,15,opt,name=disableGSO,proto3" json:"disableGSO,omitempty"` MaxIncomingStreams int64 `protobuf:"varint,15,opt,name=max_incoming_streams,json=maxIncomingStreams,proto3" json:"max_incoming_streams,omitempty"`
MaxIncomingStreams int64 `protobuf:"varint,16,opt,name=max_incoming_streams,json=maxIncomingStreams,proto3" json:"max_incoming_streams,omitempty"` DisableStatelessReset bool `protobuf:"varint,16,opt,name=disable_stateless_reset,json=disableStatelessReset,proto3" json:"disable_stateless_reset,omitempty"`
DisableStatelessReset bool `protobuf:"varint,17,opt,name=disable_stateless_reset,json=disableStatelessReset,proto3" json:"disable_stateless_reset,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
func (x *QuicParams) Reset() { func (x *QuicParams) Reset() {
*x = QuicParams{} *x = QuicParams{}
mi := &file_transport_internet_config_proto_msgTypes[3] mi := &file_transport_internet_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -479,7 +418,7 @@ func (x *QuicParams) String() string {
func (*QuicParams) ProtoMessage() {} func (*QuicParams) ProtoMessage() {}
func (x *QuicParams) ProtoReflect() protoreflect.Message { func (x *QuicParams) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_config_proto_msgTypes[3] mi := &file_transport_internet_config_proto_msgTypes[2]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -492,7 +431,7 @@ func (x *QuicParams) ProtoReflect() protoreflect.Message {
// Deprecated: Use QuicParams.ProtoReflect.Descriptor instead. // Deprecated: Use QuicParams.ProtoReflect.Descriptor instead.
func (*QuicParams) Descriptor() ([]byte, []int) { func (*QuicParams) Descriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{3} return file_transport_internet_config_proto_rawDescGZIP(), []int{2}
} }
func (x *QuicParams) GetCongestion() string { func (x *QuicParams) GetCongestion() string {
@@ -530,13 +469,6 @@ func (x *QuicParams) GetBrutalDisableLossCompensation() bool {
return false return false
} }
func (x *QuicParams) GetUdpHop() *UdpHop {
if x != nil {
return x.UdpHop
}
return nil
}
func (x *QuicParams) GetInitStreamReceiveWindow() uint64 { func (x *QuicParams) GetInitStreamReceiveWindow() uint64 {
if x != nil { if x != nil {
return x.InitStreamReceiveWindow return x.InitStreamReceiveWindow
@@ -628,7 +560,7 @@ type CustomSockopt struct {
func (x *CustomSockopt) Reset() { func (x *CustomSockopt) Reset() {
*x = CustomSockopt{} *x = CustomSockopt{}
mi := &file_transport_internet_config_proto_msgTypes[4] mi := &file_transport_internet_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -640,7 +572,7 @@ func (x *CustomSockopt) String() string {
func (*CustomSockopt) ProtoMessage() {} func (*CustomSockopt) ProtoMessage() {}
func (x *CustomSockopt) ProtoReflect() protoreflect.Message { func (x *CustomSockopt) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_config_proto_msgTypes[4] mi := &file_transport_internet_config_proto_msgTypes[3]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -653,7 +585,7 @@ func (x *CustomSockopt) ProtoReflect() protoreflect.Message {
// Deprecated: Use CustomSockopt.ProtoReflect.Descriptor instead. // Deprecated: Use CustomSockopt.ProtoReflect.Descriptor instead.
func (*CustomSockopt) Descriptor() ([]byte, []int) { func (*CustomSockopt) Descriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{4} return file_transport_internet_config_proto_rawDescGZIP(), []int{3}
} }
func (x *CustomSockopt) GetSystem() string { func (x *CustomSockopt) GetSystem() string {
@@ -733,7 +665,7 @@ type SocketConfig struct {
func (x *SocketConfig) Reset() { func (x *SocketConfig) Reset() {
*x = SocketConfig{} *x = SocketConfig{}
mi := &file_transport_internet_config_proto_msgTypes[5] mi := &file_transport_internet_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -745,7 +677,7 @@ func (x *SocketConfig) String() string {
func (*SocketConfig) ProtoMessage() {} func (*SocketConfig) ProtoMessage() {}
func (x *SocketConfig) ProtoReflect() protoreflect.Message { func (x *SocketConfig) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_config_proto_msgTypes[5] mi := &file_transport_internet_config_proto_msgTypes[4]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -758,7 +690,7 @@ func (x *SocketConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use SocketConfig.ProtoReflect.Descriptor instead. // Deprecated: Use SocketConfig.ProtoReflect.Descriptor instead.
func (*SocketConfig) Descriptor() ([]byte, []int) { func (*SocketConfig) Descriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{5} return file_transport_internet_config_proto_rawDescGZIP(), []int{4}
} }
func (x *SocketConfig) GetMark() int32 { func (x *SocketConfig) GetMark() int32 {
@@ -920,7 +852,7 @@ type HappyEyeballsConfig struct {
func (x *HappyEyeballsConfig) Reset() { func (x *HappyEyeballsConfig) Reset() {
*x = HappyEyeballsConfig{} *x = HappyEyeballsConfig{}
mi := &file_transport_internet_config_proto_msgTypes[6] mi := &file_transport_internet_config_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -932,7 +864,7 @@ func (x *HappyEyeballsConfig) String() string {
func (*HappyEyeballsConfig) ProtoMessage() {} func (*HappyEyeballsConfig) ProtoMessage() {}
func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message { func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_config_proto_msgTypes[6] mi := &file_transport_internet_config_proto_msgTypes[5]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -945,7 +877,7 @@ func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use HappyEyeballsConfig.ProtoReflect.Descriptor instead. // Deprecated: Use HappyEyeballsConfig.ProtoReflect.Descriptor instead.
func (*HappyEyeballsConfig) Descriptor() ([]byte, []int) { func (*HappyEyeballsConfig) Descriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{6} return file_transport_internet_config_proto_rawDescGZIP(), []int{5}
} }
func (x *HappyEyeballsConfig) GetPrioritizeIpv6() bool { func (x *HappyEyeballsConfig) GetPrioritizeIpv6() bool {
@@ -996,11 +928,7 @@ const file_transport_internet_config_proto_rawDesc = "" +
"\btcpmasks\x18\v \x03(\v2 .xray.common.serial.TypedMessageR\btcpmasks\x12D\n" + "\btcpmasks\x18\v \x03(\v2 .xray.common.serial.TypedMessageR\btcpmasks\x12D\n" +
"\vquic_params\x18\f \x01(\v2#.xray.transport.internet.QuicParamsR\n" + "\vquic_params\x18\f \x01(\v2#.xray.transport.internet.QuicParamsR\n" +
"quicParams\x12N\n" + "quicParams\x12N\n" +
"\x0fsocket_settings\x18\x06 \x01(\v2%.xray.transport.internet.SocketConfigR\x0esocketSettings\"d\n" + "\x0fsocket_settings\x18\x06 \x01(\v2%.xray.transport.internet.SocketConfigR\x0esocketSettings\"\x8d\x06\n" +
"\x06UdpHop\x12\x14\n" +
"\x05ports\x18\x01 \x03(\rR\x05ports\x12!\n" +
"\finterval_min\x18\x02 \x01(\x03R\vintervalMin\x12!\n" +
"\finterval_max\x18\x03 \x01(\x03R\vintervalMax\"\xc7\x06\n" +
"\n" + "\n" +
"QuicParams\x12\x1e\n" + "QuicParams\x12\x1e\n" +
"\n" + "\n" +
@@ -1011,22 +939,21 @@ const file_transport_internet_config_proto_rawDesc = "" +
"\tbrutal_up\x18\x03 \x01(\x04R\bbrutalUp\x12\x1f\n" + "\tbrutal_up\x18\x03 \x01(\x04R\bbrutalUp\x12\x1f\n" +
"\vbrutal_down\x18\x04 \x01(\x04R\n" + "\vbrutal_down\x18\x04 \x01(\x04R\n" +
"brutalDown\x12G\n" + "brutalDown\x12G\n" +
" brutal_disable_loss_compensation\x18\x05 \x01(\bR\x1dbrutalDisableLossCompensation\x128\n" + " brutal_disable_loss_compensation\x18\x05 \x01(\bR\x1dbrutalDisableLossCompensation\x12;\n" +
"\audp_hop\x18\x06 \x01(\v2\x1f.xray.transport.internet.UdpHopR\x06udpHop\x12;\n" + "\x1ainit_stream_receive_window\x18\x06 \x01(\x04R\x17initStreamReceiveWindow\x129\n" +
"\x1ainit_stream_receive_window\x18\a \x01(\x04R\x17initStreamReceiveWindow\x129\n" + "\x19max_stream_receive_window\x18\a \x01(\x04R\x16maxStreamReceiveWindow\x127\n" +
"\x19max_stream_receive_window\x18\b \x01(\x04R\x16maxStreamReceiveWindow\x127\n" + "\x18init_conn_receive_window\x18\b \x01(\x04R\x15initConnReceiveWindow\x125\n" +
"\x18init_conn_receive_window\x18\t \x01(\x04R\x15initConnReceiveWindow\x125\n" + "\x17max_conn_receive_window\x18\t \x01(\x04R\x14maxConnReceiveWindow\x12(\n" +
"\x17max_conn_receive_window\x18\n" + "\x10max_idle_timeout\x18\n" +
" \x01(\x04R\x14maxConnReceiveWindow\x12(\n" + " \x01(\x03R\x0emaxIdleTimeout\x12*\n" +
"\x10max_idle_timeout\x18\v \x01(\x03R\x0emaxIdleTimeout\x12*\n" + "\x11keep_alive_period\x18\v \x01(\x03R\x0fkeepAlivePeriod\x12;\n" +
"\x11keep_alive_period\x18\f \x01(\x03R\x0fkeepAlivePeriod\x12;\n" + "\x1adisable_path_mtu_discovery\x18\f \x01(\bR\x17disablePathMtuDiscovery\x122\n" +
"\x1adisable_path_mtu_discovery\x18\r \x01(\bR\x17disablePathMtuDiscovery\x122\n" + "\x15disable_chrome_parrot\x18\r \x01(\bR\x13disableChromeParrot\x12\x1e\n" +
"\x15disable_chrome_parrot\x18\x0e \x01(\bR\x13disableChromeParrot\x12\x1e\n" +
"\n" + "\n" +
"disableGSO\x18\x0f \x01(\bR\n" + "disableGSO\x18\x0e \x01(\bR\n" +
"disableGSO\x120\n" + "disableGSO\x120\n" +
"\x14max_incoming_streams\x18\x10 \x01(\x03R\x12maxIncomingStreams\x126\n" + "\x14max_incoming_streams\x18\x0f \x01(\x03R\x12maxIncomingStreams\x126\n" +
"\x17disable_stateless_reset\x18\x11 \x01(\bR\x15disableStatelessReset\"\x93\x01\n" + "\x17disable_stateless_reset\x18\x10 \x01(\bR\x15disableStatelessReset\"\x93\x01\n" +
"\rCustomSockopt\x12\x16\n" + "\rCustomSockopt\x12\x16\n" +
"\x06system\x18\x01 \x01(\tR\x06system\x12\x18\n" + "\x06system\x18\x01 \x01(\tR\x06system\x12\x18\n" +
"\anetwork\x18\x02 \x01(\tR\anetwork\x12\x14\n" + "\anetwork\x18\x02 \x01(\tR\anetwork\x12\x14\n" +
@@ -1110,41 +1037,39 @@ func file_transport_internet_config_proto_rawDescGZIP() []byte {
} }
var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_transport_internet_config_proto_goTypes = []any{ var file_transport_internet_config_proto_goTypes = []any{
(DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy (DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy
(AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy (AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy
(SocketConfig_TProxyMode)(0), // 2: xray.transport.internet.SocketConfig.TProxyMode (SocketConfig_TProxyMode)(0), // 2: xray.transport.internet.SocketConfig.TProxyMode
(*TransportConfig)(nil), // 3: xray.transport.internet.TransportConfig (*TransportConfig)(nil), // 3: xray.transport.internet.TransportConfig
(*StreamConfig)(nil), // 4: xray.transport.internet.StreamConfig (*StreamConfig)(nil), // 4: xray.transport.internet.StreamConfig
(*UdpHop)(nil), // 5: xray.transport.internet.UdpHop (*QuicParams)(nil), // 5: xray.transport.internet.QuicParams
(*QuicParams)(nil), // 6: xray.transport.internet.QuicParams (*CustomSockopt)(nil), // 6: xray.transport.internet.CustomSockopt
(*CustomSockopt)(nil), // 7: xray.transport.internet.CustomSockopt (*SocketConfig)(nil), // 7: xray.transport.internet.SocketConfig
(*SocketConfig)(nil), // 8: xray.transport.internet.SocketConfig (*HappyEyeballsConfig)(nil), // 8: xray.transport.internet.HappyEyeballsConfig
(*HappyEyeballsConfig)(nil), // 9: xray.transport.internet.HappyEyeballsConfig (*serial.TypedMessage)(nil), // 9: xray.common.serial.TypedMessage
(*serial.TypedMessage)(nil), // 10: xray.common.serial.TypedMessage (*net.IPOrDomain)(nil), // 10: xray.common.net.IPOrDomain
(*net.IPOrDomain)(nil), // 11: xray.common.net.IPOrDomain
} }
var file_transport_internet_config_proto_depIdxs = []int32{ var file_transport_internet_config_proto_depIdxs = []int32{
10, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage 9, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage
11, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain 10, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain
3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig 3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig
10, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage 9, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage
10, // 4: xray.transport.internet.StreamConfig.udpmasks:type_name -> xray.common.serial.TypedMessage 9, // 4: xray.transport.internet.StreamConfig.udpmasks:type_name -> xray.common.serial.TypedMessage
10, // 5: xray.transport.internet.StreamConfig.tcpmasks:type_name -> xray.common.serial.TypedMessage 9, // 5: xray.transport.internet.StreamConfig.tcpmasks:type_name -> xray.common.serial.TypedMessage
6, // 6: xray.transport.internet.StreamConfig.quic_params:type_name -> xray.transport.internet.QuicParams 5, // 6: xray.transport.internet.StreamConfig.quic_params:type_name -> xray.transport.internet.QuicParams
8, // 7: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig 7, // 7: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig
5, // 8: xray.transport.internet.QuicParams.udp_hop:type_name -> xray.transport.internet.UdpHop 2, // 8: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode
2, // 9: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode 0, // 9: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
0, // 10: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy 6, // 10: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt
7, // 11: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt 1, // 11: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy
1, // 12: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy 8, // 12: xray.transport.internet.SocketConfig.happy_eyeballs:type_name -> xray.transport.internet.HappyEyeballsConfig
9, // 13: xray.transport.internet.SocketConfig.happy_eyeballs:type_name -> xray.transport.internet.HappyEyeballsConfig 13, // [13:13] is the sub-list for method output_type
14, // [14:14] is the sub-list for method output_type 13, // [13:13] is the sub-list for method input_type
14, // [14:14] is the sub-list for method input_type 13, // [13:13] is the sub-list for extension type_name
14, // [14:14] is the sub-list for extension type_name 13, // [13:13] is the sub-list for extension extendee
14, // [14:14] is the sub-list for extension extendee 0, // [0:13] is the sub-list for field type_name
0, // [0:14] is the sub-list for field type_name
} }
func init() { file_transport_internet_config_proto_init() } func init() { file_transport_internet_config_proto_init() }
@@ -1158,7 +1083,7 @@ func file_transport_internet_config_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_config_proto_rawDesc), len(file_transport_internet_config_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_config_proto_rawDesc), len(file_transport_internet_config_proto_rawDesc)),
NumEnums: 3, NumEnums: 3,
NumMessages: 7, NumMessages: 6,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },
+11 -18
View File
@@ -64,30 +64,23 @@ message StreamConfig {
SocketConfig socket_settings = 6; SocketConfig socket_settings = 6;
} }
message UdpHop {
repeated uint32 ports = 1;
int64 interval_min = 2;
int64 interval_max = 3;
}
message QuicParams { message QuicParams {
string congestion = 1; string congestion = 1;
string bbr_profile = 2; string bbr_profile = 2;
uint64 brutal_up = 3; uint64 brutal_up = 3;
uint64 brutal_down = 4; uint64 brutal_down = 4;
bool brutal_disable_loss_compensation = 5; bool brutal_disable_loss_compensation = 5;
UdpHop udp_hop = 6; uint64 init_stream_receive_window = 6;
uint64 init_stream_receive_window = 7; uint64 max_stream_receive_window = 7;
uint64 max_stream_receive_window = 8; uint64 init_conn_receive_window = 8;
uint64 init_conn_receive_window = 9; uint64 max_conn_receive_window = 9;
uint64 max_conn_receive_window = 10; int64 max_idle_timeout = 10;
int64 max_idle_timeout = 11; int64 keep_alive_period = 11;
int64 keep_alive_period = 12; bool disable_path_mtu_discovery = 12;
bool disable_path_mtu_discovery = 13; bool disable_chrome_parrot = 13;
bool disable_chrome_parrot = 14; bool disableGSO = 14;
bool disableGSO = 15; int64 max_incoming_streams = 15;
int64 max_incoming_streams = 16; bool disable_stateless_reset = 16;
bool disable_stateless_reset = 17;
} }
message CustomSockopt { message CustomSockopt {
+8 -14
View File
@@ -10,8 +10,6 @@ import (
) )
type Udpmask interface { type Udpmask interface {
UDP()
WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error)
WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error)
} }
@@ -21,15 +19,14 @@ type UdpmaskManager struct {
} }
func NewUdpmaskManager(udpmasks []Udpmask) *UdpmaskManager { func NewUdpmaskManager(udpmasks []Udpmask) *UdpmaskManager {
return &UdpmaskManager{ slices.Reverse(udpmasks)
udpmasks: udpmasks, return &UdpmaskManager{udpmasks: udpmasks}
}
} }
func (m *UdpmaskManager) WrapPacketConnClient(raw net.PacketConn) (net.PacketConn, error) { func (m *UdpmaskManager) WrapPacketConnClient(raw net.PacketConn) (net.PacketConn, error) {
var sizes []int var sizes []int
var conns []net.PacketConn var conns []net.PacketConn
for i, mask := range slices.Backward(m.udpmasks) { for i, mask := range m.udpmasks {
if _, ok := mask.(headerConn); ok { if _, ok := mask.(headerConn); ok {
conn, err := mask.WrapPacketConnClient(nil, i, len(m.udpmasks)-1) conn, err := mask.WrapPacketConnClient(nil, i, len(m.udpmasks)-1)
if err != nil { if err != nil {
@@ -62,7 +59,7 @@ func (m *UdpmaskManager) WrapPacketConnClient(raw net.PacketConn) (net.PacketCon
func (m *UdpmaskManager) WrapPacketConnServer(raw net.PacketConn) (net.PacketConn, error) { func (m *UdpmaskManager) WrapPacketConnServer(raw net.PacketConn) (net.PacketConn, error) {
var sizes []int var sizes []int
var conns []net.PacketConn var conns []net.PacketConn
for i, mask := range slices.Backward(m.udpmasks) { for i, mask := range m.udpmasks {
if _, ok := mask.(headerConn); ok { if _, ok := mask.(headerConn); ok {
conn, err := mask.WrapPacketConnServer(nil, i, len(m.udpmasks)-1) conn, err := mask.WrapPacketConnServer(nil, i, len(m.udpmasks)-1)
if err != nil { if err != nil {
@@ -195,8 +192,6 @@ func (c *headerManagerConn) WriteTo(p []byte, addr net.Addr) (n int, err error)
} }
type Tcpmask interface { type Tcpmask interface {
TCP()
WrapConnClient(net.Conn) (net.Conn, error) WrapConnClient(net.Conn) (net.Conn, error)
WrapConnServer(net.Conn) (net.Conn, error) WrapConnServer(net.Conn) (net.Conn, error)
} }
@@ -206,14 +201,13 @@ type TcpmaskManager struct {
} }
func NewTcpmaskManager(tcpmasks []Tcpmask) *TcpmaskManager { func NewTcpmaskManager(tcpmasks []Tcpmask) *TcpmaskManager {
return &TcpmaskManager{ slices.Reverse(tcpmasks)
tcpmasks: tcpmasks, return &TcpmaskManager{tcpmasks: tcpmasks}
}
} }
func (m *TcpmaskManager) WrapConnClient(raw net.Conn) (net.Conn, error) { func (m *TcpmaskManager) WrapConnClient(raw net.Conn) (net.Conn, error) {
var err error var err error
for _, mask := range slices.Backward(m.tcpmasks) { for _, mask := range m.tcpmasks {
raw, err = mask.WrapConnClient(raw) raw, err = mask.WrapConnClient(raw)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -224,7 +218,7 @@ func (m *TcpmaskManager) WrapConnClient(raw net.Conn) (net.Conn, error) {
func (m *TcpmaskManager) WrapConnServer(raw net.Conn) (net.Conn, error) { func (m *TcpmaskManager) WrapConnServer(raw net.Conn) (net.Conn, error) {
var err error var err error
for _, mask := range slices.Backward(m.tcpmasks) { for _, mask := range m.tcpmasks {
raw, err = mask.WrapConnServer(raw) raw, err = mask.WrapConnServer(raw)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -2,9 +2,6 @@ package fragment
import "net" import "net"
func (c *Config) TCP() {
}
func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) { func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) {
return NewConnClient(c, raw, false) return NewConnClient(c, raw, false)
} }
@@ -4,8 +4,6 @@ import (
"net" "net"
) )
func (c *TCPConfig) TCP() {}
func (c *TCPConfig) WrapConnClient(raw net.Conn) (net.Conn, error) { func (c *TCPConfig) WrapConnClient(raw net.Conn) (net.Conn, error) {
return NewConnClientTCP(c, raw) return NewConnClientTCP(c, raw)
} }
@@ -14,8 +12,6 @@ func (c *TCPConfig) WrapConnServer(raw net.Conn) (net.Conn, error) {
return NewConnServerTCP(c, raw) return NewConnServerTCP(c, raw)
} }
func (c *UDPConfig) UDP() {}
func (c *UDPConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *UDPConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return NewConnClientUDP(c, raw) return NewConnClientUDP(c, raw)
} }
@@ -24,8 +20,6 @@ func (c *UDPConfig) WrapPacketConnServer(raw net.PacketConn, level int, levelCou
return NewConnServerUDP(c, raw) return NewConnServerUDP(c, raw)
} }
func (c *UDPStandaloneConfig) UDP() {}
func (c *UDPStandaloneConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *UDPStandaloneConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return NewConnClientUDPStandalone(c, raw) return NewConnClientUDPStandalone(c, raw)
} }
@@ -4,8 +4,6 @@ import (
"net" "net"
) )
func (c *Config) UDP() {}
func (c *Config) HeaderConn() {} func (c *Config) HeaderConn() {}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
@@ -4,8 +4,6 @@ import (
"net" "net"
) )
func (c *Config) UDP() {}
func (c *Config) HeaderConn() {} func (c *Config) HeaderConn() {}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
@@ -4,8 +4,6 @@ import (
"net" "net"
) )
func (c *Config) UDP() {}
func (c *Config) HeaderConn() {} func (c *Config) HeaderConn() {}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
@@ -2,9 +2,6 @@ package noise
import "net" import "net"
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return NewConnClient(c, raw) return NewConnClient(c, raw)
} }
+1 -5
View File
@@ -5,15 +5,11 @@ import (
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/hysteria/udphop"
) )
func (c *Config) UDP() {}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
_, ok1 := raw.(*internet.FakePacketConn) _, ok1 := raw.(*internet.FakePacketConn)
_, ok2 := raw.(*udphop.UdpHopPacketConn) if level != 0 || ok1 {
if level != 0 || ok1 || ok2 {
return nil, errors.New("realm requires being at the outermost level") return nil, errors.New("realm requires being at the outermost level")
} }
return NewConnClient(c, raw) return NewConnClient(c, raw)
@@ -4,8 +4,6 @@ import (
"net" "net"
) )
func (c *Config) UDP() {}
func (c *Config) HeaderConn() {} func (c *Config) HeaderConn() {}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
@@ -16,8 +14,6 @@ func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount
return NewSalamanderConnServer(c, raw) return NewSalamanderConnServer(c, raw)
} }
func (c *GeckoConfig) UDP() {}
func (c *GeckoConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *GeckoConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return NewGeckoConnClient(c, raw) return NewGeckoConnClient(c, raw)
} }
@@ -6,12 +6,6 @@ import (
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
) )
func (c *Config) TCP() {
}
func (c *Config) UDP() {
}
// Sudoku in finalmask mode is a pure appearance transform with no standalone handshake. // Sudoku in finalmask mode is a pure appearance transform with no standalone handshake.
// TCP always keeps classic sudoku on uplink and uses packed downlink optimization on server writes. // TCP always keeps classic sudoku on uplink and uses packed downlink optimization on server writes.
func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) { func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) {
@@ -0,0 +1,20 @@
package udphop
import (
"net"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet"
)
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
_, ok1 := raw.(*internet.FakePacketConn)
if level != 0 || ok1 {
return nil, errors.New("udphop requires being at the outermost level")
}
return NewUDPHopConn(c, raw)
}
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
return nil, errors.New("udphop: client only")
}
@@ -0,0 +1,190 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v6.33.5
// source: transport/internet/finalmask/udphop/config.proto
package udphop
import (
internet "github.com/xtls/xray-core/transport/internet"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Config struct {
state protoimpl.MessageState `protogen:"open.v1"`
Sockopt *internet.SocketConfig `protobuf:"bytes,1,opt,name=sockopt,proto3" json:"sockopt,omitempty"`
Local bool `protobuf:"varint,2,opt,name=local,proto3" json:"local,omitempty"`
Remote bool `protobuf:"varint,3,opt,name=remote,proto3" json:"remote,omitempty"`
RemoteOnce bool `protobuf:"varint,4,opt,name=remote_once,json=remoteOnce,proto3" json:"remote_once,omitempty"`
IntervalMin int64 `protobuf:"varint,5,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"`
IntervalMax int64 `protobuf:"varint,6,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"`
RemotePorts []uint32 `protobuf:"varint,7,rep,packed,name=remote_ports,json=remotePorts,proto3" json:"remote_ports,omitempty"`
RemoteIPs []string `protobuf:"bytes,8,rep,name=remoteIPs,proto3" json:"remoteIPs,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
*x = Config{}
mi := &file_transport_internet_finalmask_udphop_config_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Config) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Config) ProtoMessage() {}
func (x *Config) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_finalmask_udphop_config_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
func (*Config) Descriptor() ([]byte, []int) {
return file_transport_internet_finalmask_udphop_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetSockopt() *internet.SocketConfig {
if x != nil {
return x.Sockopt
}
return nil
}
func (x *Config) GetLocal() bool {
if x != nil {
return x.Local
}
return false
}
func (x *Config) GetRemote() bool {
if x != nil {
return x.Remote
}
return false
}
func (x *Config) GetRemoteOnce() bool {
if x != nil {
return x.RemoteOnce
}
return false
}
func (x *Config) GetIntervalMin() int64 {
if x != nil {
return x.IntervalMin
}
return 0
}
func (x *Config) GetIntervalMax() int64 {
if x != nil {
return x.IntervalMax
}
return 0
}
func (x *Config) GetRemotePorts() []uint32 {
if x != nil {
return x.RemotePorts
}
return nil
}
func (x *Config) GetRemoteIPs() []string {
if x != nil {
return x.RemoteIPs
}
return nil
}
var File_transport_internet_finalmask_udphop_config_proto protoreflect.FileDescriptor
const file_transport_internet_finalmask_udphop_config_proto_rawDesc = "" +
"\n" +
"0transport/internet/finalmask/udphop/config.proto\x12(xray.transport.internet.finalmask.udphop\x1a\x1ftransport/internet/config.proto\"\x9f\x02\n" +
"\x06Config\x12?\n" +
"\asockopt\x18\x01 \x01(\v2%.xray.transport.internet.SocketConfigR\asockopt\x12\x14\n" +
"\x05local\x18\x02 \x01(\bR\x05local\x12\x16\n" +
"\x06remote\x18\x03 \x01(\bR\x06remote\x12\x1f\n" +
"\vremote_once\x18\x04 \x01(\bR\n" +
"remoteOnce\x12!\n" +
"\finterval_min\x18\x05 \x01(\x03R\vintervalMin\x12!\n" +
"\finterval_max\x18\x06 \x01(\x03R\vintervalMax\x12!\n" +
"\fremote_ports\x18\a \x03(\rR\vremotePorts\x12\x1c\n" +
"\tremoteIPs\x18\b \x03(\tR\tremoteIPsB\x9a\x01\n" +
",com.xray.transport.internet.finalmask.udphopP\x01Z=github.com/xtls/xray-core/transport/internet/finalmask/udphop\xaa\x02(Xray.Transport.Internet.Finalmask.Udphopb\x06proto3"
var (
file_transport_internet_finalmask_udphop_config_proto_rawDescOnce sync.Once
file_transport_internet_finalmask_udphop_config_proto_rawDescData []byte
)
func file_transport_internet_finalmask_udphop_config_proto_rawDescGZIP() []byte {
file_transport_internet_finalmask_udphop_config_proto_rawDescOnce.Do(func() {
file_transport_internet_finalmask_udphop_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_udphop_config_proto_rawDesc), len(file_transport_internet_finalmask_udphop_config_proto_rawDesc)))
})
return file_transport_internet_finalmask_udphop_config_proto_rawDescData
}
var file_transport_internet_finalmask_udphop_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_transport_internet_finalmask_udphop_config_proto_goTypes = []any{
(*Config)(nil), // 0: xray.transport.internet.finalmask.udphop.Config
(*internet.SocketConfig)(nil), // 1: xray.transport.internet.SocketConfig
}
var file_transport_internet_finalmask_udphop_config_proto_depIdxs = []int32{
1, // 0: xray.transport.internet.finalmask.udphop.Config.sockopt:type_name -> xray.transport.internet.SocketConfig
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_transport_internet_finalmask_udphop_config_proto_init() }
func file_transport_internet_finalmask_udphop_config_proto_init() {
if File_transport_internet_finalmask_udphop_config_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_udphop_config_proto_rawDesc), len(file_transport_internet_finalmask_udphop_config_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_transport_internet_finalmask_udphop_config_proto_goTypes,
DependencyIndexes: file_transport_internet_finalmask_udphop_config_proto_depIdxs,
MessageInfos: file_transport_internet_finalmask_udphop_config_proto_msgTypes,
}.Build()
File_transport_internet_finalmask_udphop_config_proto = out.File
file_transport_internet_finalmask_udphop_config_proto_goTypes = nil
file_transport_internet_finalmask_udphop_config_proto_depIdxs = nil
}
@@ -0,0 +1,21 @@
syntax = "proto3";
package xray.transport.internet.finalmask.udphop;
option csharp_namespace = "Xray.Transport.Internet.Finalmask.Udphop";
option go_package = "github.com/xtls/xray-core/transport/internet/finalmask/udphop";
option java_package = "com.xray.transport.internet.finalmask.udphop";
option java_multiple_files = true;
import "transport/internet/config.proto";
message Config {
xray.transport.internet.SocketConfig sockopt = 1;
bool local = 2;
bool remote = 3;
bool remote_once = 4;
int64 interval_min = 5;
int64 interval_max = 6;
repeated uint32 remote_ports = 7;
repeated string remoteIPs = 8;
}
+305
View File
@@ -0,0 +1,305 @@
package udphop
import (
"context"
"crypto/rand"
goerrors "errors"
"io"
mrand "math/rand"
gonet "net"
"net/netip"
"reflect"
"sync"
"time"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/net/cnc"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/finalmask"
)
var pool = sync.Pool{
New: func() any {
return make([]byte, finalmask.UDPSize)
},
}
type packet struct {
p []byte
addr net.Addr
err error
}
type udpHopConn struct {
conn net.PacketConn
sockopt *internet.SocketConfig
local bool
remote bool
remoteOnce bool
intervalMin int64
intervalMax int64
remotePorts []uint32
remoteIPs []netip.Prefix
deadline time.Time
readDeadline time.Time
writeDeadline time.Time
pre net.PacketConn
cur net.PacketConn
addr *net.UDPAddr
readCh chan packet
closeCh chan struct{}
wg sync.WaitGroup
mu sync.Mutex
}
func NewUDPHopConn(c *Config, raw net.PacketConn) (net.PacketConn, error) {
if c.IntervalMin < 5 || c.IntervalMax < 5 {
return nil, errors.New("invalid interval")
}
remoteIPs := make([]netip.Prefix, 0, len(c.RemoteIPs))
for _, ip := range c.RemoteIPs {
remoteIPs = append(remoteIPs, netip.MustParsePrefix(ip))
}
conn := &udpHopConn{
conn: raw,
sockopt: c.Sockopt,
local: c.Local,
remote: c.Remote,
remoteOnce: c.RemoteOnce,
intervalMin: c.IntervalMin,
intervalMax: c.IntervalMax,
remotePorts: c.RemotePorts,
remoteIPs: remoteIPs,
readCh: make(chan packet),
closeCh: make(chan struct{}),
}
return conn, nil
}
func (c *udpHopConn) closed() bool {
select {
case <-c.closeCh:
return true
default:
return false
}
}
func (c *udpHopConn) hop(addr *net.UDPAddr) {
if c.closed() {
return
}
newAddr := &net.UDPAddr{IP: addr.IP, Port: addr.Port}
newConn := c.conn
if c.remote || c.remoteOnce && c.addr == nil {
if len(c.remotePorts) > 0 {
newAddr.Port = int(c.remotePorts[mrand.Intn(len(c.remotePorts))])
}
if len(c.remoteIPs) > 0 {
newAddr.IP = randPrefix(c.remoteIPs[mrand.Intn(len(c.remoteIPs))])
}
}
if c.local {
raw, err := internet.DialSystem(context.Background(), net.UDPDestination(net.IPAddress(newAddr.IP), net.Port(newAddr.Port)), c.sockopt)
if err != nil {
errors.LogErrorInner(context.Background(), err, "hop err")
return
}
switch c := raw.(type) {
case *internet.PacketConnWrapper:
newConn = c.PacketConn
case *cnc.Connection:
newConn = &internet.FakePacketConn{Conn: c}
default:
panic(reflect.TypeOf(c))
}
newConn.SetDeadline(c.deadline)
newConn.SetReadDeadline(c.readDeadline)
newConn.SetWriteDeadline(c.writeDeadline)
if c.pre != nil {
_ = c.pre.Close()
}
c.pre = c.cur
c.wg.Add(1)
go c.recv(newConn)
}
c.addr = newAddr
c.cur = newConn
}
func (c *udpHopConn) recv(conn net.PacketConn) {
defer c.wg.Done()
for {
if c.closed() {
return
}
p := pool.Get().([]byte)
n, addr, err := conn.ReadFrom(p)
if err != nil {
pool.Put(p[:cap(p)])
if goerrors.Is(err, io.EOF) || goerrors.Is(err, io.ErrClosedPipe) || goerrors.Is(err, gonet.ErrClosed) {
break
}
var netErr net.Error
if goerrors.As(err, &netErr) && netErr.Timeout() {
select {
case c.readCh <- packet{err: err}:
case <-c.closeCh:
return
}
}
errors.LogErrorInner(context.Background(), err, "recv err")
continue
}
select {
case c.readCh <- packet{p: p[:n], addr: addr}:
case <-c.closeCh:
pool.Put(p[:cap(p)])
return
}
}
}
func (c *udpHopConn) hopLoop() {
ticker := time.NewTicker(time.Second * time.Duration(crypto.RandBetween(c.intervalMin, c.intervalMax+1)))
defer ticker.Stop()
for {
select {
case <-ticker.C:
ticker.Reset(time.Second * time.Duration(crypto.RandBetween(c.intervalMin, c.intervalMax+1)))
c.mu.Lock()
c.hop(c.addr)
c.mu.Unlock()
case <-c.closeCh:
return
}
}
}
func (c *udpHopConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
packet, ok := <-c.readCh
if ok {
if packet.p != nil {
n = copy(p, packet.p)
pool.Put(packet.p[:cap(packet.p)])
}
return n, packet.addr, packet.err
}
return 0, nil, io.EOF
}
func (c *udpHopConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.cur == nil {
c.hop(addr.(*net.UDPAddr))
if c.cur == nil {
return 0, nil
}
go c.hopLoop()
}
_, err = c.cur.WriteTo(p, c.addr)
if err != nil {
errors.LogErrorInner(context.Background(), err, "send err")
return 0, err
}
return len(p), nil
}
func (c *udpHopConn) Close() error {
c.mu.Lock()
defer c.mu.Unlock()
if c.closed() {
return nil
}
close(c.closeCh)
if c.pre != nil {
_ = c.pre.Close()
}
if c.cur != nil {
_ = c.cur.Close()
}
_ = c.conn.Close()
c.wg.Wait()
select {
case p := <-c.readCh:
if p.p != nil {
pool.Put(p.p[:cap(p.p)])
}
default:
}
close(c.readCh)
return nil
}
func (c *udpHopConn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
func (c *udpHopConn) SetDeadline(t time.Time) error {
c.mu.Lock()
defer c.mu.Unlock()
c.deadline = t
if c.pre != nil {
_ = c.pre.SetDeadline(t)
}
if c.cur != nil {
_ = c.cur.SetDeadline(t)
}
return nil
}
func (c *udpHopConn) SetReadDeadline(t time.Time) error {
c.mu.Lock()
defer c.mu.Unlock()
c.readDeadline = t
if c.pre != nil {
_ = c.pre.SetReadDeadline(t)
}
if c.cur != nil {
_ = c.cur.SetReadDeadline(t)
}
return nil
}
func (c *udpHopConn) SetWriteDeadline(t time.Time) error {
c.mu.Lock()
defer c.mu.Unlock()
c.writeDeadline = t
if c.pre != nil {
_ = c.pre.SetWriteDeadline(t)
}
if c.cur != nil {
_ = c.cur.SetWriteDeadline(t)
}
return nil
}
func randPrefix(p netip.Prefix) []byte {
if p.IsSingleIP() {
return p.Addr().AsSlice()
}
b := p.Addr().AsSlice()
prefix := p.Bits()
var new [16]byte
common.Must2(rand.Read(new[:len(b)]))
i := prefix / 8
j := prefix % 8
if i+1 < len(b) {
copy(b[i+1:], new[i+1:])
}
mask := byte(0xff << (8 - j))
b[i] = (b[i] & mask) | (new[i] &^ mask)
return b
}
@@ -4,9 +4,6 @@ import (
"net" "net"
) )
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
// _, ok1 := raw.(*internet.FakePacketConn) // _, ok1 := raw.(*internet.FakePacketConn)
// _, ok2 := raw.(*udphop.UdpHopPacketConn) // _, ok2 := raw.(*udphop.UdpHopPacketConn)
+30 -17
View File
@@ -45,7 +45,8 @@ type xicmpConnClient struct {
id int id int
seq int seq int
readCh chan packet readCh chan packet
closedCh chan struct{} closeCh chan struct{}
wg sync.WaitGroup
mu sync.Mutex mu sync.Mutex
} }
@@ -81,9 +82,10 @@ func NewConnClient(c *Config, raw net.PacketConn) (net.PacketConn, error) {
id: mathrand.Intn(65536), id: mathrand.Intn(65536),
seq: 1, seq: 1,
readCh: make(chan packet), readCh: make(chan packet),
closedCh: make(chan struct{}), closeCh: make(chan struct{}),
} }
conn.wg.Add(2)
go conn.recv4() go conn.recv4()
go conn.recv6() go conn.recv6()
@@ -96,7 +98,7 @@ func (c *xicmpConnClient) ring(a, b uint16) uint16 {
func (c *xicmpConnClient) closed() bool { func (c *xicmpConnClient) closed() bool {
select { select {
case <-c.closedCh: case <-c.closeCh:
return true return true
default: default:
return false return false
@@ -104,8 +106,9 @@ func (c *xicmpConnClient) closed() bool {
} }
func (c *xicmpConnClient) recv4() { func (c *xicmpConnClient) recv4() {
var b [finalmask.UDPSize]byte defer c.wg.Done()
var b [finalmask.UDPSize]byte
for { for {
if c.closed() { if c.closed() {
return return
@@ -119,10 +122,11 @@ func (c *xicmpConnClient) recv4() {
case c.readCh <- packet{ case c.readCh <- packet{
err: err, err: err,
}: }:
case <-c.closedCh: case <-c.closeCh:
return return
} }
} }
errors.LogErrorInner(context.Background(), err, "recv4 err")
continue continue
} }
@@ -166,7 +170,7 @@ func (c *xicmpConnClient) recv4() {
p: p, p: p,
addr: addr, addr: addr,
}: }:
case <-c.closedCh: case <-c.closeCh:
pool.Put(p) pool.Put(p)
return return
} }
@@ -174,11 +178,12 @@ func (c *xicmpConnClient) recv4() {
} }
func (c *xicmpConnClient) recv6() { func (c *xicmpConnClient) recv6() {
var b [finalmask.UDPSize]byte defer c.wg.Done()
var b [finalmask.UDPSize]byte
for { for {
if c.closed() { if c.closed() {
break return
} }
n, addr, err := c.icmp6.ReadFrom(b[:]) n, addr, err := c.icmp6.ReadFrom(b[:])
@@ -189,10 +194,11 @@ func (c *xicmpConnClient) recv6() {
case c.readCh <- packet{ case c.readCh <- packet{
err: err, err: err,
}: }:
case <-c.closedCh: case <-c.closeCh:
return return
} }
} }
errors.LogErrorInner(context.Background(), err, "recv6 err")
continue continue
} }
@@ -236,7 +242,7 @@ func (c *xicmpConnClient) recv6() {
p: p, p: p,
addr: addr, addr: addr,
}: }:
case <-c.closedCh: case <-c.closeCh:
pool.Put(p) pool.Put(p)
return return
} }
@@ -244,16 +250,15 @@ func (c *xicmpConnClient) recv6() {
} }
func (c *xicmpConnClient) ReadFrom(p []byte) (n int, addr net.Addr, err error) { func (c *xicmpConnClient) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
select { packet, ok := <-c.readCh
case packet := <-c.readCh: if ok {
if packet.p != nil { if packet.p != nil {
n = copy(p, packet.p) n = copy(p, packet.p)
pool.Put(packet.p) pool.Put(packet.p)
} }
return n, packet.addr, packet.err return n, packet.addr, packet.err
case <-c.closedCh:
return 0, nil, io.EOF
} }
return 0, nil, io.EOF
} }
func (c *xicmpConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) { func (c *xicmpConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) {
@@ -294,10 +299,9 @@ func (c *xicmpConnClient) WriteTo(p []byte, addr net.Addr) (n int, err error) {
} }
if err != nil { if err != nil {
errors.LogErrorInner(context.Background(), err, "xicmp write") errors.LogErrorInner(context.Background(), err, "send err")
return 0, err return 0, err
} }
return len(p), nil return len(p), nil
} }
@@ -307,10 +311,19 @@ func (c *xicmpConnClient) Close() error {
if c.closed() { if c.closed() {
return nil return nil
} }
close(c.closedCh) close(c.closeCh)
_ = c.icmp4.Close() _ = c.icmp4.Close()
_ = c.icmp6.Close() _ = c.icmp6.Close()
_ = c.conn.Close() _ = c.conn.Close()
c.wg.Wait()
select {
case p := <-c.readCh:
if p.p != nil {
pool.Put(p.p)
}
default:
}
close(c.readCh)
return nil return nil
} }
+1 -6
View File
@@ -5,16 +5,11 @@ import (
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/hysteria/udphop"
) )
func (c *Config) UDP() {
}
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) { func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
_, ok1 := raw.(*internet.FakePacketConn) _, ok1 := raw.(*internet.FakePacketConn)
_, ok2 := raw.(*udphop.UdpHopPacketConn) if level != 0 || ok1 {
if level != 0 || ok1 || ok2 {
return nil, errors.New("xicmp requires being at the outermost level") return nil, errors.New("xicmp requires being at the outermost level")
} }
return NewConnClient(c, raw) return NewConnClient(c, raw)
+43 -30
View File
@@ -37,14 +37,15 @@ type record struct {
} }
type xicmpConnServer struct { type xicmpConnServer struct {
conn net.PacketConn conn net.PacketConn
icmp4 *icmp.PacketConn icmp4 *icmp.PacketConn
icmp6 *icmp.PacketConn icmp6 *icmp.PacketConn
ips map[netip.Addr]struct{} ips map[netip.Addr]struct{}
rec map[string]record rec map[string]record
readCh chan packet readCh chan packet
closedCh chan struct{} closeCh chan struct{}
mu sync.Mutex wg sync.WaitGroup
mu sync.Mutex
} }
func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) { func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
@@ -63,16 +64,17 @@ func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
} }
conn := &xicmpConnServer{ conn := &xicmpConnServer{
conn: raw, conn: raw,
icmp4: icmp4, icmp4: icmp4,
icmp6: icmp6, icmp6: icmp6,
ips: ips, ips: ips,
rec: make(map[string]record), rec: make(map[string]record),
readCh: make(chan packet), readCh: make(chan packet),
closedCh: make(chan struct{}), closeCh: make(chan struct{}),
} }
go conn.clean() go conn.clean()
conn.wg.Add(2)
go conn.recv4() go conn.recv4()
go conn.recv6() go conn.recv6()
@@ -81,7 +83,7 @@ func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
func (c *xicmpConnServer) closed() bool { func (c *xicmpConnServer) closed() bool {
select { select {
case <-c.closedCh: case <-c.closeCh:
return true return true
default: default:
return false return false
@@ -102,15 +104,16 @@ func (c *xicmpConnServer) clean() {
} }
} }
c.mu.Unlock() c.mu.Unlock()
case <-c.closedCh: case <-c.closeCh:
return return
} }
} }
} }
func (c *xicmpConnServer) recv4() { func (c *xicmpConnServer) recv4() {
var b [finalmask.UDPSize]byte defer c.wg.Done()
var b [finalmask.UDPSize]byte
for { for {
if c.closed() { if c.closed() {
return return
@@ -124,10 +127,11 @@ func (c *xicmpConnServer) recv4() {
case c.readCh <- packet{ case c.readCh <- packet{
err: err, err: err,
}: }:
case <-c.closedCh: case <-c.closeCh:
return return
} }
} }
errors.LogErrorInner(context.Background(), err, "recv4 err")
continue continue
} }
@@ -179,7 +183,7 @@ func (c *xicmpConnServer) recv4() {
p: p, p: p,
addr: cAddr, addr: cAddr,
}: }:
case <-c.closedCh: case <-c.closeCh:
pool.Put(p) pool.Put(p)
return return
} }
@@ -187,8 +191,9 @@ func (c *xicmpConnServer) recv4() {
} }
func (c *xicmpConnServer) recv6() { func (c *xicmpConnServer) recv6() {
var b [finalmask.UDPSize]byte defer c.wg.Done()
var b [finalmask.UDPSize]byte
for { for {
if c.closed() { if c.closed() {
return return
@@ -202,10 +207,11 @@ func (c *xicmpConnServer) recv6() {
case c.readCh <- packet{ case c.readCh <- packet{
err: err, err: err,
}: }:
case <-c.closedCh: case <-c.closeCh:
return return
} }
} }
errors.LogErrorInner(context.Background(), err, "recv6 err")
continue continue
} }
@@ -257,7 +263,7 @@ func (c *xicmpConnServer) recv6() {
p: p, p: p,
addr: cAddr, addr: cAddr,
}: }:
case <-c.closedCh: case <-c.closeCh:
pool.Put(p) pool.Put(p)
return return
} }
@@ -265,16 +271,15 @@ func (c *xicmpConnServer) recv6() {
} }
func (c *xicmpConnServer) ReadFrom(p []byte) (n int, addr net.Addr, err error) { func (c *xicmpConnServer) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
select { packet, ok := <-c.readCh
case packet := <-c.readCh: if ok {
if packet.p != nil { if packet.p != nil {
n = copy(p, packet.p) n = copy(p, packet.p)
pool.Put(packet.p) pool.Put(packet.p)
} }
return n, packet.addr, packet.err return n, packet.addr, packet.err
case <-c.closedCh:
return 0, nil, io.EOF
} }
return 0, nil, io.EOF
} }
func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) { func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
@@ -310,10 +315,9 @@ func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
} }
if err != nil { if err != nil {
errors.LogErrorInner(context.Background(), err, "xicmp write") errors.LogErrorInner(context.Background(), err, "send err")
return 0, err return 0, err
} }
return len(p), nil return len(p), nil
} }
@@ -323,10 +327,19 @@ func (c *xicmpConnServer) Close() error {
if c.closed() { if c.closed() {
return nil return nil
} }
close(c.closedCh) close(c.closeCh)
_ = c.icmp4.Close() _ = c.icmp4.Close()
_ = c.icmp6.Close() _ = c.icmp6.Close()
_ = c.conn.Close() _ = c.conn.Close()
c.wg.Wait()
select {
case p := <-c.readCh:
if p.p != nil {
pool.Put(p.p)
}
default:
}
close(c.readCh)
return nil return nil
} }
@@ -39,16 +39,17 @@ type record struct {
} }
type xicmpConnServer struct { type xicmpConnServer struct {
conn net.PacketConn conn net.PacketConn
icmp4 *icmp.PacketConn icmp4 *icmp.PacketConn
icmp6 *icmp.PacketConn icmp6 *icmp.PacketConn
ipv4PC *ipv4.PacketConn ipv4PC *ipv4.PacketConn
ipv6PC *ipv6.PacketConn ipv6PC *ipv6.PacketConn
ips map[netip.Addr]struct{} ips map[netip.Addr]struct{}
rec map[string]record rec map[string]record
readCh chan packet readCh chan packet
closedCh chan struct{} closeCh chan struct{}
mu sync.Mutex wg sync.WaitGroup
mu sync.Mutex
} }
func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) { func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
@@ -67,21 +68,22 @@ func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
} }
conn := &xicmpConnServer{ conn := &xicmpConnServer{
conn: raw, conn: raw,
icmp4: icmp4, icmp4: icmp4,
icmp6: icmp6, icmp6: icmp6,
ipv4PC: icmp4.IPv4PacketConn(), ipv4PC: icmp4.IPv4PacketConn(),
ipv6PC: icmp6.IPv6PacketConn(), ipv6PC: icmp6.IPv6PacketConn(),
ips: ips, ips: ips,
rec: make(map[string]record), rec: make(map[string]record),
readCh: make(chan packet), readCh: make(chan packet),
closedCh: make(chan struct{}), closeCh: make(chan struct{}),
} }
common.Must(conn.ipv4PC.SetControlMessage(ipv4.FlagDst, true)) common.Must(conn.ipv4PC.SetControlMessage(ipv4.FlagDst, true))
common.Must(conn.ipv6PC.SetControlMessage(ipv6.FlagDst, true)) common.Must(conn.ipv6PC.SetControlMessage(ipv6.FlagDst, true))
go conn.clean() go conn.clean()
conn.wg.Add(2)
go conn.recv4() go conn.recv4()
go conn.recv6() go conn.recv6()
@@ -90,7 +92,7 @@ func NewConnServer(c *Config, raw net.PacketConn) (net.PacketConn, error) {
func (c *xicmpConnServer) closed() bool { func (c *xicmpConnServer) closed() bool {
select { select {
case <-c.closedCh: case <-c.closeCh:
return true return true
default: default:
return false return false
@@ -111,15 +113,16 @@ func (c *xicmpConnServer) clean() {
} }
} }
c.mu.Unlock() c.mu.Unlock()
case <-c.closedCh: case <-c.closeCh:
return return
} }
} }
} }
func (c *xicmpConnServer) recv4() { func (c *xicmpConnServer) recv4() {
var b [finalmask.UDPSize]byte defer c.wg.Done()
var b [finalmask.UDPSize]byte
for { for {
if c.closed() { if c.closed() {
return return
@@ -133,10 +136,11 @@ func (c *xicmpConnServer) recv4() {
case c.readCh <- packet{ case c.readCh <- packet{
err: err, err: err,
}: }:
case <-c.closedCh: case <-c.closeCh:
return return
} }
} }
errors.LogErrorInner(context.Background(), err, "recv4 err")
continue continue
} }
@@ -189,7 +193,7 @@ func (c *xicmpConnServer) recv4() {
p: p, p: p,
addr: cAddr, addr: cAddr,
}: }:
case <-c.closedCh: case <-c.closeCh:
pool.Put(p) pool.Put(p)
return return
} }
@@ -197,8 +201,9 @@ func (c *xicmpConnServer) recv4() {
} }
func (c *xicmpConnServer) recv6() { func (c *xicmpConnServer) recv6() {
var b [finalmask.UDPSize]byte defer c.wg.Done()
var b [finalmask.UDPSize]byte
for { for {
if c.closed() { if c.closed() {
return return
@@ -212,10 +217,11 @@ func (c *xicmpConnServer) recv6() {
case c.readCh <- packet{ case c.readCh <- packet{
err: err, err: err,
}: }:
case <-c.closedCh: case <-c.closeCh:
return return
} }
} }
errors.LogErrorInner(context.Background(), err, "recv6 err")
continue continue
} }
@@ -268,7 +274,7 @@ func (c *xicmpConnServer) recv6() {
p: p, p: p,
addr: cAddr, addr: cAddr,
}: }:
case <-c.closedCh: case <-c.closeCh:
pool.Put(p) pool.Put(p)
return return
} }
@@ -276,16 +282,15 @@ func (c *xicmpConnServer) recv6() {
} }
func (c *xicmpConnServer) ReadFrom(p []byte) (n int, addr net.Addr, err error) { func (c *xicmpConnServer) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
select { packet, ok := <-c.readCh
case packet := <-c.readCh: if ok {
if packet.p != nil { if packet.p != nil {
n = copy(p, packet.p) n = copy(p, packet.p)
pool.Put(packet.p) pool.Put(packet.p)
} }
return n, packet.addr, packet.err return n, packet.addr, packet.err
case <-c.closedCh:
return 0, nil, io.EOF
} }
return 0, nil, io.EOF
} }
func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) { func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
@@ -321,10 +326,9 @@ func (c *xicmpConnServer) WriteTo(p []byte, addr net.Addr) (n int, err error) {
} }
if err != nil { if err != nil {
errors.LogErrorInner(context.Background(), err, "xicmp write") errors.LogErrorInner(context.Background(), err, "send err")
return 0, err return 0, err
} }
return len(p), nil return len(p), nil
} }
@@ -334,10 +338,19 @@ func (c *xicmpConnServer) Close() error {
if c.closed() { if c.closed() {
return nil return nil
} }
close(c.closedCh) close(c.closeCh)
_ = c.icmp4.Close() _ = c.icmp4.Close()
_ = c.icmp6.Close() _ = c.icmp6.Close()
_ = c.conn.Close() _ = c.conn.Close()
c.wg.Wait()
select {
case p := <-c.readCh:
if p.p != nil {
pool.Put(p.p)
}
default:
}
close(c.readCh)
return nil return nil
} }
@@ -5,9 +5,6 @@ import (
"net" "net"
) )
func (c *Config) TCP() {
}
func (c *Config) WrapConnClient(conn net.Conn) (net.Conn, error) { func (c *Config) WrapConnClient(conn net.Conn) (net.Conn, error) {
profiles, err := profilesFromConfig(c.Profiles) profiles, err := profilesFromConfig(c.Profiles)
if err != nil { if err != nil {
+4 -7
View File
@@ -103,14 +103,11 @@ func (c *InterConn) Update() {
func (c *InterConn) Read(p []byte) (int, error) { func (c *InterConn) Read(p []byte) (int, error) {
b, ok := <-c.ch b, ok := <-c.ch
if !ok { if ok {
return 0, io.EOF c.Update()
return copy(p, b), nil
} }
if len(p) < len(b) { return 0, io.EOF
return 0, io.ErrShortBuffer
}
c.Update()
return copy(p, b), nil
} }
func (c *InterConn) Write(p []byte) (int, error) { func (c *InterConn) Write(p []byte) (int, error) {
-34
View File
@@ -3,7 +3,6 @@ package hysteria
import ( import (
"context" "context"
go_tls "crypto/tls" go_tls "crypto/tls"
"math/rand"
"net/http" "net/http"
"net/url" "net/url"
"reflect" "reflect"
@@ -22,7 +21,6 @@ import (
"github.com/xtls/xray-core/transport/internet/finalmask" "github.com/xtls/xray-core/transport/internet/finalmask"
"github.com/xtls/xray-core/transport/internet/hysteria/congestion" "github.com/xtls/xray-core/transport/internet/hysteria/congestion"
"github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr" "github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr"
"github.com/xtls/xray-core/transport/internet/hysteria/udphop"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
) )
@@ -78,7 +76,6 @@ func (c *client) dial(ctx context.Context) error {
if quicParams == nil { if quicParams == nil {
quicParams = &internet.QuicParams{ quicParams = &internet.QuicParams{
BbrProfile: string(bbr.ProfileStandard), BbrProfile: string(bbr.ProfileStandard),
UdpHop: &internet.UdpHop{},
} }
} }
@@ -115,35 +112,8 @@ func (c *client) dial(ctx context.Context) error {
// quicConfig.KeepAlivePeriod = 10 * time.Second // quicConfig.KeepAlivePeriod = 10 * time.Second
// } // }
udpHopDialer := func(addr *net.UDPAddr) (net.PacketConn, error) {
conn, err := internet.DialSystem(ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), c.socketConfig)
if err != nil {
errors.LogInfoInner(context.Background(), err, "skip hop: failed to dial to dest")
return nil, errors.New("")
}
var pktConn net.PacketConn
switch c := conn.(type) {
case *internet.PacketConnWrapper:
pktConn = c.PacketConn
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
default:
panic(reflect.TypeOf(c))
}
return pktConn, nil
}
var pktConn net.PacketConn var pktConn net.PacketConn
var udpAddr *net.UDPAddr var udpAddr *net.UDPAddr
var index int
if len(quicParams.UdpHop.Ports) > 0 {
index = rand.Intn(len(quicParams.UdpHop.Ports))
c.dest.Port = net.Port(quicParams.UdpHop.Ports[index])
}
raw, err := internet.DialSystem(ctx, c.dest, c.socketConfig) raw, err := internet.DialSystem(ctx, c.dest, c.socketConfig)
if err != nil { if err != nil {
@@ -160,10 +130,6 @@ func (c *client) dial(ctx context.Context) error {
panic(reflect.TypeOf(c)) panic(reflect.TypeOf(c))
} }
if len(quicParams.UdpHop.Ports) > 0 {
pktConn = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer, pktConn, index)
}
if c.udpmaskManager != nil { if c.udpmaskManager != nil {
newConn, err := c.udpmaskManager.WrapPacketConnClient(pktConn) newConn, err := c.udpmaskManager.WrapPacketConnClient(pktConn)
if err != nil { if err != nil {
-1
View File
@@ -281,7 +281,6 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
if quicParams == nil { if quicParams == nil {
quicParams = &internet.QuicParams{ quicParams = &internet.QuicParams{
BbrProfile: string(bbr.ProfileStandard), BbrProfile: string(bbr.ProfileStandard),
UdpHop: &internet.UdpHop{},
} }
} }
-254
View File
@@ -1,254 +0,0 @@
package udphop
import (
"errors"
"math/rand"
"net"
"sync"
"time"
"github.com/xtls/xray-core/transport/internet/finalmask"
)
const (
packetQueueSize = 1024
udpBufferSize = finalmask.UDPSize
defaultHopInterval = 30 * time.Second
)
type UdpHopPacketConn struct {
Addrs []net.Addr
HopIntervalMin time.Duration
HopIntervalMax time.Duration
ListenUDPFunc func(addr *net.UDPAddr) (net.PacketConn, error)
connMutex sync.RWMutex
prevConn net.PacketConn
currentConn net.PacketConn
addrIndex int
deadline time.Time
readDeadline time.Time
writeDeadline time.Time
recvQueue chan *udpPacket
closeChan chan struct{}
closed bool
bufPool sync.Pool
}
type udpPacket struct {
Buf []byte
N int
Addr net.Addr
Err error
}
func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopIntervalMax time.Duration, listenUDPFunc func(addr *net.UDPAddr) (net.PacketConn, error), currentConn net.PacketConn, addrIndex int) net.PacketConn {
if len(addrs) == 0 {
panic("len(addrs) == 0")
}
if hopIntervalMin == 0 {
hopIntervalMin = defaultHopInterval
}
if hopIntervalMax == 0 {
hopIntervalMax = defaultHopInterval
}
if hopIntervalMin < 5*time.Second {
panic("hopIntervalMin < 5*time.Second")
}
if hopIntervalMax < 5*time.Second {
panic("hopIntervalMax < 5*time.Second")
}
if hopIntervalMax < hopIntervalMin {
panic("hopIntervalMax < hopIntervalMin")
}
if listenUDPFunc == nil {
panic("listenUDPFunc is nil")
}
hConn := &UdpHopPacketConn{
Addrs: addrs,
HopIntervalMin: hopIntervalMin,
HopIntervalMax: hopIntervalMax,
ListenUDPFunc: listenUDPFunc,
prevConn: nil,
currentConn: currentConn,
addrIndex: addrIndex,
recvQueue: make(chan *udpPacket, packetQueueSize),
closeChan: make(chan struct{}),
bufPool: sync.Pool{
New: func() interface{} {
return make([]byte, udpBufferSize)
},
},
}
go hConn.recvLoop(hConn.currentConn)
go hConn.hopLoop()
return hConn
}
func (u *UdpHopPacketConn) recvLoop(conn net.PacketConn) {
for {
buf := u.bufPool.Get().([]byte)
n, addr, err := conn.ReadFrom(buf)
if err != nil {
u.bufPool.Put(buf)
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
u.recvQueue <- &udpPacket{nil, 0, nil, netErr}
continue
}
return
}
select {
case u.recvQueue <- &udpPacket{buf, n, addr, nil}:
default:
u.bufPool.Put(buf)
}
}
}
func (u *UdpHopPacketConn) hopLoop() {
timer := time.NewTimer(u.nextHopInterval())
defer timer.Stop()
for {
select {
case <-timer.C:
u.hop()
timer.Reset(u.nextHopInterval())
case <-u.closeChan:
return
}
}
}
func (u *UdpHopPacketConn) nextHopInterval() time.Duration {
if u.HopIntervalMin == u.HopIntervalMax {
return u.HopIntervalMin
}
return u.HopIntervalMin + time.Duration(rand.Int63n(int64(u.HopIntervalMax-u.HopIntervalMin)+1))
}
func (u *UdpHopPacketConn) hop() {
u.connMutex.Lock()
defer u.connMutex.Unlock()
if u.closed {
return
}
addrIndex := rand.Intn(len(u.Addrs))
newConn, err := u.ListenUDPFunc(u.Addrs[addrIndex].(*net.UDPAddr))
if err != nil {
return
}
if u.prevConn != nil {
_ = u.prevConn.Close()
}
u.prevConn = u.currentConn
u.addrIndex = addrIndex
u.currentConn = newConn
if !u.deadline.IsZero() {
_ = u.currentConn.SetDeadline(u.deadline)
}
if !u.readDeadline.IsZero() {
_ = u.currentConn.SetReadDeadline(u.readDeadline)
}
if !u.writeDeadline.IsZero() {
_ = u.currentConn.SetWriteDeadline(u.writeDeadline)
}
go u.recvLoop(newConn)
}
func (u *UdpHopPacketConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
for {
select {
case p := <-u.recvQueue:
if p.Err != nil {
return 0, nil, p.Err
}
n := copy(b, p.Buf[:p.N])
u.bufPool.Put(p.Buf)
return n, p.Addr, nil
case <-u.closeChan:
return 0, nil, net.ErrClosed
}
}
}
func (u *UdpHopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
u.connMutex.RLock()
defer u.connMutex.RUnlock()
if u.closed {
return 0, net.ErrClosed
}
return u.currentConn.WriteTo(b, u.Addrs[u.addrIndex])
}
func (u *UdpHopPacketConn) Close() error {
u.connMutex.Lock()
defer u.connMutex.Unlock()
if u.closed {
return nil
}
if u.prevConn != nil {
_ = u.prevConn.Close()
}
err := u.currentConn.Close()
close(u.closeChan)
u.closed = true
u.Addrs = nil
return err
}
func (u *UdpHopPacketConn) LocalAddr() net.Addr {
u.connMutex.RLock()
defer u.connMutex.RUnlock()
return u.currentConn.LocalAddr()
}
func (u *UdpHopPacketConn) SetDeadline(t time.Time) error {
u.connMutex.Lock()
defer u.connMutex.Unlock()
u.deadline = t
u.readDeadline = t
u.writeDeadline = t
if u.prevConn != nil {
_ = u.prevConn.SetDeadline(t)
}
return u.currentConn.SetDeadline(t)
}
func (u *UdpHopPacketConn) SetReadDeadline(t time.Time) error {
u.connMutex.Lock()
defer u.connMutex.Unlock()
u.deadline = time.Time{}
u.readDeadline = t
if u.prevConn != nil {
_ = u.prevConn.SetReadDeadline(t)
}
return u.currentConn.SetReadDeadline(t)
}
func (u *UdpHopPacketConn) SetWriteDeadline(t time.Time) error {
u.connMutex.Lock()
defer u.connMutex.Unlock()
u.deadline = time.Time{}
u.writeDeadline = t
if u.prevConn != nil {
_ = u.prevConn.SetWriteDeadline(t)
}
return u.currentConn.SetWriteDeadline(t)
}
func ToAddrs(ip net.IP, ports []uint32) []net.Addr {
var addrs []net.Addr
for _, port := range ports {
addr := &net.UDPAddr{
IP: ip,
Port: int(port),
}
addrs = append(addrs, addr)
}
return addrs
}
-34
View File
@@ -5,7 +5,6 @@ import (
gotls "crypto/tls" gotls "crypto/tls"
"fmt" "fmt"
"io" "io"
"math/rand"
"net/http" "net/http"
"net/http/httptrace" "net/http/httptrace"
"net/url" "net/url"
@@ -28,7 +27,6 @@ import (
"github.com/xtls/xray-core/transport/internet/browser_dialer" "github.com/xtls/xray-core/transport/internet/browser_dialer"
"github.com/xtls/xray-core/transport/internet/hysteria/congestion" "github.com/xtls/xray-core/transport/internet/hysteria/congestion"
"github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr" "github.com/xtls/xray-core/transport/internet/hysteria/congestion/bbr"
"github.com/xtls/xray-core/transport/internet/hysteria/udphop"
"github.com/xtls/xray-core/transport/internet/reality" "github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
@@ -162,7 +160,6 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
if quicParams == nil { if quicParams == nil {
quicParams = &internet.QuicParams{ quicParams = &internet.QuicParams{
BbrProfile: string(bbr.ProfileStandard), BbrProfile: string(bbr.ProfileStandard),
UdpHop: &internet.UdpHop{},
} }
} }
@@ -198,35 +195,8 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
QUICConfig: quicConfig, QUICConfig: quicConfig,
TLSClientConfig: gotlsConfig, TLSClientConfig: gotlsConfig,
Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (*quic.Conn, error) { Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (*quic.Conn, error) {
udpHopDialer := func(addr *net.UDPAddr) (net.PacketConn, error) {
conn, err := internet.DialSystem(ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), streamSettings.SocketSettings)
if err != nil {
errors.LogInfoInner(context.Background(), err, "skip hop: failed to dial to dest")
return nil, errors.New("")
}
var pktConn net.PacketConn
switch c := conn.(type) {
case *internet.PacketConnWrapper:
pktConn = c.PacketConn
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
default:
panic(reflect.TypeOf(c))
}
return pktConn, nil
}
var pktConn net.PacketConn var pktConn net.PacketConn
var udpAddr *net.UDPAddr var udpAddr *net.UDPAddr
var index int
if len(quicParams.UdpHop.Ports) > 0 {
index = rand.Intn(len(quicParams.UdpHop.Ports))
dest.Port = net.Port(quicParams.UdpHop.Ports[index])
}
raw, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings) raw, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
if err != nil { if err != nil {
@@ -243,10 +213,6 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
panic(reflect.TypeOf(c)) panic(reflect.TypeOf(c))
} }
if len(quicParams.UdpHop.Ports) > 0 {
pktConn = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer, pktConn, index)
}
if streamSettings.UdpmaskManager != nil { if streamSettings.UdpmaskManager != nil {
newConn, err := streamSettings.UdpmaskManager.WrapPacketConnClient(pktConn) newConn, err := streamSettings.UdpmaskManager.WrapPacketConnClient(pktConn)
if err != nil { if err != nil {
-1
View File
@@ -493,7 +493,6 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
if quicParams == nil { if quicParams == nil {
quicParams = &internet.QuicParams{ quicParams = &internet.QuicParams{
BbrProfile: string(bbr.ProfileStandard), BbrProfile: string(bbr.ProfileStandard),
UdpHop: &internet.UdpHop{},
} }
} }