Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a0bf239fc1 | |||
| dee64ef240 | |||
| 0a1b5bfb51 |
@@ -411,8 +411,10 @@ type MultiplexingConfig struct {
|
|||||||
XudpConcurrency int32 `protobuf:"varint,3,opt,name=xudpConcurrency,proto3" json:"xudpConcurrency,omitempty"`
|
XudpConcurrency int32 `protobuf:"varint,3,opt,name=xudpConcurrency,proto3" json:"xudpConcurrency,omitempty"`
|
||||||
// "reject" (default), "allow" or "skip".
|
// "reject" (default), "allow" or "skip".
|
||||||
XudpProxyUDP443 string `protobuf:"bytes,4,opt,name=xudpProxyUDP443,proto3" json:"xudpProxyUDP443,omitempty"`
|
XudpProxyUDP443 string `protobuf:"bytes,4,opt,name=xudpProxyUDP443,proto3" json:"xudpProxyUDP443,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
// MaxReuseTimes for an connection
|
||||||
sizeCache protoimpl.SizeCache
|
MaxReuseTimes int32 `protobuf:"varint,5,opt,name=maxReuseTimes,proto3" json:"maxReuseTimes,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *MultiplexingConfig) Reset() {
|
func (x *MultiplexingConfig) Reset() {
|
||||||
@@ -473,6 +475,13 @@ func (x *MultiplexingConfig) GetXudpProxyUDP443() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *MultiplexingConfig) GetMaxReuseTimes() int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MaxReuseTimes
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
var File_app_proxyman_config_proto protoreflect.FileDescriptor
|
var File_app_proxyman_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_app_proxyman_config_proto_rawDesc = "" +
|
const file_app_proxyman_config_proto_rawDesc = "" +
|
||||||
@@ -503,12 +512,13 @@ const file_app_proxyman_config_proto_rawDesc = "" +
|
|||||||
"\x0eproxy_settings\x18\x03 \x01(\v2$.xray.transport.internet.ProxyConfigR\rproxySettings\x12T\n" +
|
"\x0eproxy_settings\x18\x03 \x01(\v2$.xray.transport.internet.ProxyConfigR\rproxySettings\x12T\n" +
|
||||||
"\x12multiplex_settings\x18\x04 \x01(\v2%.xray.app.proxyman.MultiplexingConfigR\x11multiplexSettings\x12\x19\n" +
|
"\x12multiplex_settings\x18\x04 \x01(\v2%.xray.app.proxyman.MultiplexingConfigR\x11multiplexSettings\x12\x19\n" +
|
||||||
"\bvia_cidr\x18\x05 \x01(\tR\aviaCidr\x12P\n" +
|
"\bvia_cidr\x18\x05 \x01(\tR\aviaCidr\x12P\n" +
|
||||||
"\x0ftarget_strategy\x18\x06 \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0etargetStrategy\"\xa4\x01\n" +
|
"\x0ftarget_strategy\x18\x06 \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0etargetStrategy\"\xca\x01\n" +
|
||||||
"\x12MultiplexingConfig\x12\x18\n" +
|
"\x12MultiplexingConfig\x12\x18\n" +
|
||||||
"\aenabled\x18\x01 \x01(\bR\aenabled\x12 \n" +
|
"\aenabled\x18\x01 \x01(\bR\aenabled\x12 \n" +
|
||||||
"\vconcurrency\x18\x02 \x01(\x05R\vconcurrency\x12(\n" +
|
"\vconcurrency\x18\x02 \x01(\x05R\vconcurrency\x12(\n" +
|
||||||
"\x0fxudpConcurrency\x18\x03 \x01(\x05R\x0fxudpConcurrency\x12(\n" +
|
"\x0fxudpConcurrency\x18\x03 \x01(\x05R\x0fxudpConcurrency\x12(\n" +
|
||||||
"\x0fxudpProxyUDP443\x18\x04 \x01(\tR\x0fxudpProxyUDP443BU\n" +
|
"\x0fxudpProxyUDP443\x18\x04 \x01(\tR\x0fxudpProxyUDP443\x12$\n" +
|
||||||
|
"\rmaxReuseTimes\x18\x05 \x01(\x05R\rmaxReuseTimesBU\n" +
|
||||||
"\x15com.xray.app.proxymanP\x01Z&github.com/xtls/xray-core/app/proxyman\xaa\x02\x11Xray.App.Proxymanb\x06proto3"
|
"\x15com.xray.app.proxymanP\x01Z&github.com/xtls/xray-core/app/proxyman\xaa\x02\x11Xray.App.Proxymanb\x06proto3"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -68,4 +68,6 @@ message MultiplexingConfig {
|
|||||||
int32 xudpConcurrency = 3;
|
int32 xudpConcurrency = 3;
|
||||||
// "reject" (default), "allow" or "skip".
|
// "reject" (default), "allow" or "skip".
|
||||||
string xudpProxyUDP443 = 4;
|
string xudpProxyUDP443 = 4;
|
||||||
|
// MaxReuseTimes for an connection
|
||||||
|
int32 maxReuseTimes = 5;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,12 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
|||||||
|
|
||||||
if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil {
|
if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil {
|
||||||
if config := h.senderSettings.MultiplexSettings; config.Enabled {
|
if config := h.senderSettings.MultiplexSettings; config.Enabled {
|
||||||
|
// MaxReuseTimes use 60000 as default, and it also means the upper limit of MaxReuseTimes
|
||||||
|
// In mux cool spec, connection ID is 2 bytes, so physical limit is 65535, bu we reserve some IDs for future use
|
||||||
|
MaxReuseTimes := uint32(60000)
|
||||||
|
if config.MaxReuseTimes != 0 && config.MaxReuseTimes < 60000 {
|
||||||
|
MaxReuseTimes = uint32(config.MaxReuseTimes)
|
||||||
|
}
|
||||||
if config.Concurrency < 0 {
|
if config.Concurrency < 0 {
|
||||||
h.mux = &mux.ClientManager{Enabled: false}
|
h.mux = &mux.ClientManager{Enabled: false}
|
||||||
}
|
}
|
||||||
@@ -136,7 +142,7 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
|||||||
Dialer: h,
|
Dialer: h,
|
||||||
Strategy: mux.ClientStrategy{
|
Strategy: mux.ClientStrategy{
|
||||||
MaxConcurrency: uint32(config.Concurrency),
|
MaxConcurrency: uint32(config.Concurrency),
|
||||||
MaxConnection: 128,
|
MaxReuseTimes: MaxReuseTimes,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -157,7 +163,7 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
|||||||
Dialer: h,
|
Dialer: h,
|
||||||
Strategy: mux.ClientStrategy{
|
Strategy: mux.ClientStrategy{
|
||||||
MaxConcurrency: uint32(config.XudpConcurrency),
|
MaxConcurrency: uint32(config.XudpConcurrency),
|
||||||
MaxConnection: 128,
|
MaxReuseTimes: 128,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ type readError struct {
|
|||||||
error
|
error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewReadError(err error) error {
|
||||||
|
return readError{err}
|
||||||
|
}
|
||||||
|
|
||||||
func (e readError) Error() string {
|
func (e readError) Error() string {
|
||||||
return e.error.Error()
|
return e.error.Error()
|
||||||
}
|
}
|
||||||
@@ -74,6 +78,10 @@ type writeError struct {
|
|||||||
error
|
error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewWriteError(err error) error {
|
||||||
|
return writeError{err}
|
||||||
|
}
|
||||||
|
|
||||||
func (e writeError) Error() string {
|
func (e writeError) Error() string {
|
||||||
return e.error.Error()
|
return e.error.Error()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package mux_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common"
|
||||||
|
"github.com/xtls/xray-core/common/buf"
|
||||||
|
"github.com/xtls/xray-core/common/mux"
|
||||||
|
"github.com/xtls/xray-core/common/net"
|
||||||
|
"github.com/xtls/xray-core/common/session"
|
||||||
|
"github.com/xtls/xray-core/transport"
|
||||||
|
"github.com/xtls/xray-core/transport/pipe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkMuxThroughput(b *testing.B) {
|
||||||
|
serverCtx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{}})
|
||||||
|
muxServerUplink, muxServerDownlink := newLinkPair()
|
||||||
|
dispatcher := TestDispatcher{
|
||||||
|
OnDispatch: func(ctx context.Context, dest net.Destination) (*transport.Link, error) {
|
||||||
|
inputReader, inputWriter := pipe.New(pipe.WithSizeLimit(512 * 1024))
|
||||||
|
outputReader, outputWriter := pipe.New(pipe.WithSizeLimit(512 * 1024))
|
||||||
|
go func() {
|
||||||
|
defer outputWriter.Close()
|
||||||
|
for {
|
||||||
|
mb, err := inputReader.ReadMultiBuffer()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
buf.ReleaseMulti(mb)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return &transport.Link{
|
||||||
|
Reader: outputReader,
|
||||||
|
Writer: inputWriter,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_, err := mux.NewServerWorker(serverCtx, &dispatcher, muxServerUplink)
|
||||||
|
common.Must(err)
|
||||||
|
client, err := mux.NewClientWorker(*muxServerDownlink, mux.ClientStrategy{})
|
||||||
|
common.Must(err)
|
||||||
|
clientCtx := session.ContextWithOutbounds(context.Background(), []*session.Outbound{{
|
||||||
|
Target: net.TCPDestination(net.DomainAddress("www.example.com"), 80),
|
||||||
|
}})
|
||||||
|
muxClientUplink, muxClientDownlink := newLinkPair()
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
mb, err := muxClientDownlink.Reader.ReadMultiBuffer()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
buf.ReleaseMulti(mb)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
ok := client.Dispatch(clientCtx, muxClientUplink)
|
||||||
|
if !ok {
|
||||||
|
b.Fatal("failed to dispatch")
|
||||||
|
}
|
||||||
|
data := buf.FromBytes(make([]byte, 8192))
|
||||||
|
b.SetBytes(int64(8192))
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := muxClientUplink.Writer.WriteMultiBuffer(buf.MultiBuffer{data})
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
-6
@@ -170,7 +170,7 @@ func (f *DialingWorkerFactory) Create() (*ClientWorker, error) {
|
|||||||
|
|
||||||
type ClientStrategy struct {
|
type ClientStrategy struct {
|
||||||
MaxConcurrency uint32
|
MaxConcurrency uint32
|
||||||
MaxConnection uint32
|
MaxReuseTimes uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientWorker struct {
|
type ClientWorker struct {
|
||||||
@@ -179,6 +179,7 @@ type ClientWorker struct {
|
|||||||
done *done.Instance
|
done *done.Instance
|
||||||
timer *time.Ticker
|
timer *time.Ticker
|
||||||
strategy ClientStrategy
|
strategy ClientStrategy
|
||||||
|
timeCretaed time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -194,6 +195,7 @@ func NewClientWorker(stream transport.Link, s ClientStrategy) (*ClientWorker, er
|
|||||||
done: done.New(),
|
done: done.New(),
|
||||||
timer: time.NewTicker(time.Second * 16),
|
timer: time.NewTicker(time.Second * 16),
|
||||||
strategy: s,
|
strategy: s,
|
||||||
|
timeCretaed: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
go c.fetchOutput()
|
go c.fetchOutput()
|
||||||
@@ -288,7 +290,7 @@ func fetchInput(ctx context.Context, s *Session, output buf.Writer) {
|
|||||||
|
|
||||||
func (m *ClientWorker) IsClosing() bool {
|
func (m *ClientWorker) IsClosing() bool {
|
||||||
sm := m.sessionManager
|
sm := m.sessionManager
|
||||||
if m.strategy.MaxConnection > 0 && sm.Count() >= int(m.strategy.MaxConnection) {
|
if m.strategy.MaxReuseTimes > 0 && sm.Count() >= int(m.strategy.MaxReuseTimes) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -318,6 +320,7 @@ func (m *ClientWorker) Dispatch(ctx context.Context, link *transport.Link) bool
|
|||||||
if s == nil {
|
if s == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
errors.LogInfo(ctx, "Allocated mux.cool sub connection ID: ", s.ID, "/", m.strategy.MaxReuseTimes, " living: ", m.ActiveConnections(), "/", m.strategy.MaxConcurrency, " age: ", time.Since(m.timeCretaed).Truncate(time.Second))
|
||||||
s.input = link.Reader
|
s.input = link.Reader
|
||||||
s.output = link.Writer
|
s.output = link.Writer
|
||||||
go fetchInput(ctx, s, m.link.Writer)
|
go fetchInput(ctx, s, m.link.Writer)
|
||||||
@@ -332,14 +335,14 @@ func (m *ClientWorker) Dispatch(ctx context.Context, link *transport.Link) bool
|
|||||||
|
|
||||||
func (m *ClientWorker) handleStatueKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
func (m *ClientWorker) handleStatueKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||||
if meta.Option.Has(OptionData) {
|
if meta.Option.Has(OptionData) {
|
||||||
return buf.Copy(NewStreamReader(reader), buf.Discard)
|
return CopyChunk(reader, buf.Discard)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ClientWorker) handleStatusNew(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
func (m *ClientWorker) handleStatusNew(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||||
if meta.Option.Has(OptionData) {
|
if meta.Option.Has(OptionData) {
|
||||||
return buf.Copy(NewStreamReader(reader), buf.Discard)
|
return CopyChunk(reader, buf.Discard)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -355,7 +358,19 @@ func (m *ClientWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
|
|||||||
closingWriter := NewResponseWriter(meta.SessionID, m.link.Writer, protocol.TransferTypeStream)
|
closingWriter := NewResponseWriter(meta.SessionID, m.link.Writer, protocol.TransferTypeStream)
|
||||||
closingWriter.Close()
|
closingWriter.Close()
|
||||||
|
|
||||||
return buf.Copy(NewStreamReader(reader), buf.Discard)
|
return CopyChunk(reader, buf.Discard)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.transferType == protocol.TransferTypeStream {
|
||||||
|
err := CopyChunk(reader, s.output)
|
||||||
|
if err != nil && buf.IsWriteError(err) {
|
||||||
|
errors.LogInfoInner(context.Background(), err, "failed to write to downstream. closing session ", s.ID)
|
||||||
|
s.Close(false)
|
||||||
|
// down stream can have a write err but don't return the err to terminate the whole mux connection
|
||||||
|
// because it's still available for other sessions
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rr := s.NewReader(reader, &meta.Target)
|
rr := s.NewReader(reader, &meta.Target)
|
||||||
@@ -374,7 +389,7 @@ func (m *ClientWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.Buffered
|
|||||||
s.Close(false)
|
s.Close(false)
|
||||||
}
|
}
|
||||||
if meta.Option.Has(OptionData) {
|
if meta.Option.Has(OptionData) {
|
||||||
return buf.Copy(NewStreamReader(reader), buf.Discard)
|
return CopyChunk(reader, buf.Discard)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func TestClientWorkerClose(t *testing.T) {
|
|||||||
Writer: w1,
|
Writer: w1,
|
||||||
}, mux.ClientStrategy{
|
}, mux.ClientStrategy{
|
||||||
MaxConcurrency: 4,
|
MaxConcurrency: 4,
|
||||||
MaxConnection: 4,
|
MaxReuseTimes: 4,
|
||||||
})
|
})
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ func TestClientWorkerClose(t *testing.T) {
|
|||||||
Writer: w2,
|
Writer: w2,
|
||||||
}, mux.ClientStrategy{
|
}, mux.ClientStrategy{
|
||||||
MaxConcurrency: 4,
|
MaxConcurrency: 4,
|
||||||
MaxConnection: 4,
|
MaxReuseTimes: 4,
|
||||||
})
|
})
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
|
|||||||
@@ -57,3 +57,32 @@ func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
func NewStreamReader(reader *buf.BufferedReader) buf.Reader {
|
func NewStreamReader(reader *buf.BufferedReader) buf.Reader {
|
||||||
return crypto.NewChunkStreamReaderWithChunkCount(crypto.PlainChunkSizeParser{}, reader, 1)
|
return crypto.NewChunkStreamReaderWithChunkCount(crypto.PlainChunkSizeParser{}, reader, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CopyChunk(reader *buf.BufferedReader, writer buf.Writer) error {
|
||||||
|
size, err := serial.ReadUint16(reader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var writeErr error
|
||||||
|
for size > 0 {
|
||||||
|
mb, readErr := reader.ReadAtMost(int32(size))
|
||||||
|
if !mb.IsEmpty() {
|
||||||
|
size -= uint16(mb.Len())
|
||||||
|
if writeErr == nil {
|
||||||
|
if err := writer.WriteMultiBuffer(mb); err != nil {
|
||||||
|
writeErr = err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf.ReleaseMulti(mb)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if readErr != nil {
|
||||||
|
return buf.NewReadError(readErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if writeErr != nil {
|
||||||
|
return buf.NewWriteError(writeErr)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
+25
-4
@@ -157,7 +157,7 @@ func (w *ServerWorker) Close() error {
|
|||||||
|
|
||||||
func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
func (w *ServerWorker) handleStatusKeepAlive(meta *FrameMetadata, reader *buf.BufferedReader) error {
|
||||||
if meta.Option.Has(OptionData) {
|
if meta.Option.Has(OptionData) {
|
||||||
return buf.Copy(NewStreamReader(reader), buf.Discard)
|
return CopyChunk(reader, buf.Discard)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -264,7 +264,7 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
|
|||||||
link, err := w.dispatcher.Dispatch(ctx, meta.Target)
|
link, err := w.dispatcher.Dispatch(ctx, meta.Target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if meta.Option.Has(OptionData) {
|
if meta.Option.Has(OptionData) {
|
||||||
buf.Copy(NewStreamReader(reader), buf.Discard)
|
CopyChunk(reader, buf.Discard)
|
||||||
}
|
}
|
||||||
return errors.New("failed to dispatch request.").Base(err)
|
return errors.New("failed to dispatch request.").Base(err)
|
||||||
}
|
}
|
||||||
@@ -287,6 +287,15 @@ func (w *ServerWorker) handleStatusNew(ctx context.Context, meta *FrameMetadata,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.transferType == protocol.TransferTypeStream {
|
||||||
|
err = CopyChunk(reader, s.output)
|
||||||
|
if err != nil && buf.IsWriteError(err) {
|
||||||
|
s.Close(false)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
rr := s.NewReader(reader, &meta.Target)
|
rr := s.NewReader(reader, &meta.Target)
|
||||||
err = buf.Copy(rr, s.output)
|
err = buf.Copy(rr, s.output)
|
||||||
|
|
||||||
@@ -308,7 +317,19 @@ func (w *ServerWorker) handleStatusKeep(meta *FrameMetadata, reader *buf.Buffere
|
|||||||
closingWriter := NewResponseWriter(meta.SessionID, w.link.Writer, protocol.TransferTypeStream)
|
closingWriter := NewResponseWriter(meta.SessionID, w.link.Writer, protocol.TransferTypeStream)
|
||||||
closingWriter.Close()
|
closingWriter.Close()
|
||||||
|
|
||||||
return buf.Copy(NewStreamReader(reader), buf.Discard)
|
return CopyChunk(reader, buf.Discard)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.transferType == protocol.TransferTypeStream {
|
||||||
|
err := CopyChunk(reader, s.output)
|
||||||
|
if err != nil && buf.IsWriteError(err) {
|
||||||
|
errors.LogInfoInner(context.Background(), err, "failed to write to downstream writer. closing session ", s.ID)
|
||||||
|
s.Close(false)
|
||||||
|
// down stream can have a write err but don't return the err to terminate the whole mux connection
|
||||||
|
// because it's still available for other sessions
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rr := s.NewReader(reader, &meta.Target)
|
rr := s.NewReader(reader, &meta.Target)
|
||||||
@@ -328,7 +349,7 @@ func (w *ServerWorker) handleStatusEnd(meta *FrameMetadata, reader *buf.Buffered
|
|||||||
s.Close(false)
|
s.Close(false)
|
||||||
}
|
}
|
||||||
if meta.Option.Has(OptionData) {
|
if meta.Option.Has(OptionData) {
|
||||||
return buf.Copy(NewStreamReader(reader), buf.Discard)
|
return CopyChunk(reader, buf.Discard)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func newLinkPair() (*transport.Link, *transport.Link) {
|
func newLinkPair() (*transport.Link, *transport.Link) {
|
||||||
opt := pipe.WithoutSizeLimit()
|
opt := pipe.WithSizeLimit(512 * 1024)
|
||||||
uplinkReader, uplinkWriter := pipe.New(opt)
|
uplinkReader, uplinkWriter := pipe.New(opt)
|
||||||
downlinkReader, downlinkWriter := pipe.New(opt)
|
downlinkReader, downlinkWriter := pipe.New(opt)
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func (m *SessionManager) Allocate(Strategy *ClientStrategy) *Session {
|
|||||||
defer m.Unlock()
|
defer m.Unlock()
|
||||||
|
|
||||||
MaxConcurrency := int(Strategy.MaxConcurrency)
|
MaxConcurrency := int(Strategy.MaxConcurrency)
|
||||||
MaxConnection := uint16(Strategy.MaxConnection)
|
MaxConnection := uint16(Strategy.MaxReuseTimes)
|
||||||
|
|
||||||
if m.closed || (MaxConcurrency > 0 && len(m.sessions) >= MaxConcurrency) || (MaxConnection > 0 && m.count >= MaxConnection) {
|
if m.closed || (MaxConcurrency > 0 && len(m.sessions) >= MaxConcurrency) || (MaxConnection > 0 && m.count >= MaxConnection) {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AccessField can used to access unexported field of a struct
|
|
||||||
// valueType must be the exact type of the field or it will panic
|
|
||||||
func AccessField[valueType any](obj any, fieldName string) *valueType {
|
|
||||||
field := reflect.ValueOf(obj).Elem().FieldByName(fieldName)
|
|
||||||
if field.Type() != reflect.TypeOf(*new(valueType)) {
|
|
||||||
panic("field type: " + field.Type().String() + ", valueType: " + reflect.TypeOf(*new(valueType)).String())
|
|
||||||
}
|
|
||||||
v := (*valueType)(unsafe.Pointer(field.UnsafeAddr()))
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
+1
-1
@@ -19,7 +19,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
Version_x byte = 26
|
Version_x byte = 26
|
||||||
Version_y byte = 2
|
Version_y byte = 2
|
||||||
Version_z byte = 4
|
Version_z byte = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package conf
|
package conf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -11,7 +10,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
|
||||||
|
|
||||||
"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"
|
||||||
@@ -452,31 +450,6 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
|
|||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type XDriveConfig struct {
|
|
||||||
RemoteFolder string `json:"remoteFolder"`
|
|
||||||
Service string `json:"service"`
|
|
||||||
Secrets []string `json:"secrets"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build implements Buildable.
|
|
||||||
func (c *XDriveConfig) Build() (proto.Message, error) {
|
|
||||||
switch c.Service {
|
|
||||||
case "local":
|
|
||||||
case "Google Drive":
|
|
||||||
if len(c.Secrets) != 3 {
|
|
||||||
return nil, errors.New("Google Drive needs 3 secrets in order of ClientID, ClientSecret, RefreshToken")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, errors.New("unsupported service")
|
|
||||||
}
|
|
||||||
config := &xdrive.Config{
|
|
||||||
RemoteFolder: c.RemoteFolder,
|
|
||||||
Service: c.Service,
|
|
||||||
Secrets: c.Secrets,
|
|
||||||
}
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Byte = 1
|
Byte = 1
|
||||||
Kilobyte = 1024 * Byte
|
Kilobyte = 1024 * Byte
|
||||||
@@ -774,12 +747,7 @@ func (c *TLSConfig) Build() (proto.Message, error) {
|
|||||||
config.MasterKeyLog = c.MasterKeyLog
|
config.MasterKeyLog = c.MasterKeyLog
|
||||||
|
|
||||||
if c.AllowInsecure {
|
if c.AllowInsecure {
|
||||||
if time.Now().After(time.Date(2026, 6, 1, 0, 0, 0, 0, time.UTC)) {
|
return nil, errors.PrintRemovedFeatureError(`"allowInsecure"`, `"pinnedPeerCertSha256"`)
|
||||||
return nil, errors.PrintRemovedFeatureError(`"allowInsecure"`, `"pinnedPeerCertSha256"`)
|
|
||||||
} else {
|
|
||||||
errors.LogWarning(context.Background(), `"allowInsecure" will be removed automatically after 2026-06-01, please use "pinnedPeerCertSha256"(pcs) and "verifyPeerCertByName"(vcn) instead, PLEASE CONTACT YOUR SERVICE PROVIDER (AIRPORT)`)
|
|
||||||
config.AllowInsecure = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if c.PinnedPeerCertSha256 != "" {
|
if c.PinnedPeerCertSha256 != "" {
|
||||||
for v := range strings.SplitSeq(c.PinnedPeerCertSha256, ",") {
|
for v := range strings.SplitSeq(c.PinnedPeerCertSha256, ",") {
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
|
|||||||
type MuxConfig struct {
|
type MuxConfig struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Concurrency int16 `json:"concurrency"`
|
Concurrency int16 `json:"concurrency"`
|
||||||
|
MaxReuseTimes int32 `json:"maxReuseTimes"`
|
||||||
XudpConcurrency int16 `json:"xudpConcurrency"`
|
XudpConcurrency int16 `json:"xudpConcurrency"`
|
||||||
XudpProxyUDP443 string `json:"xudpProxyUDP443"`
|
XudpProxyUDP443 string `json:"xudpProxyUDP443"`
|
||||||
}
|
}
|
||||||
@@ -117,6 +118,7 @@ func (m *MuxConfig) Build() (*proxyman.MultiplexingConfig, error) {
|
|||||||
return &proxyman.MultiplexingConfig{
|
return &proxyman.MultiplexingConfig{
|
||||||
Enabled: m.Enabled,
|
Enabled: m.Enabled,
|
||||||
Concurrency: int32(m.Concurrency),
|
Concurrency: int32(m.Concurrency),
|
||||||
|
MaxReuseTimes: m.MaxReuseTimes,
|
||||||
XudpConcurrency: int32(m.XudpConcurrency),
|
XudpConcurrency: int32(m.XudpConcurrency),
|
||||||
XudpProxyUDP443: m.XudpProxyUDP443,
|
XudpProxyUDP443: m.XudpProxyUDP443,
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
@@ -6,13 +6,8 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"text/tabwriter"
|
|
||||||
|
|
||||||
utls "github.com/refraction-networking/utls"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/utils"
|
|
||||||
"github.com/xtls/xray-core/main/commands/base"
|
"github.com/xtls/xray-core/main/commands/base"
|
||||||
. "github.com/xtls/xray-core/transport/internet/tls"
|
. "github.com/xtls/xray-core/transport/internet/tls"
|
||||||
)
|
)
|
||||||
@@ -51,7 +46,6 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
} else {
|
} else {
|
||||||
TargetPort, _ = strconv.Atoi(port)
|
TargetPort, _ = strconv.Atoi(port)
|
||||||
}
|
}
|
||||||
tabWriter := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
|
||||||
|
|
||||||
var ip net.IP
|
var ip net.IP
|
||||||
if len(*pingIPStr) > 0 {
|
if len(*pingIPStr) > 0 {
|
||||||
@@ -76,7 +70,7 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("Failed to dial tcp: %s", err)
|
base.Fatalf("Failed to dial tcp: %s", err)
|
||||||
}
|
}
|
||||||
tlsConn := GeneraticUClient(tcpConn, &gotls.Config{
|
tlsConn := gotls.Client(tcpConn, &gotls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
NextProtos: []string{"h2", "http/1.1"},
|
NextProtos: []string{"h2", "http/1.1"},
|
||||||
MaxVersion: gotls.VersionTLS13,
|
MaxVersion: gotls.VersionTLS13,
|
||||||
@@ -87,9 +81,8 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
fmt.Println("Handshake failure: ", err)
|
fmt.Println("Handshake failure: ", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Handshake succeeded")
|
fmt.Println("Handshake succeeded")
|
||||||
printTLSConnDetail(tabWriter, tlsConn)
|
printTLSConnDetail(tlsConn)
|
||||||
printCertificates(tabWriter, tlsConn.ConnectionState().PeerCertificates)
|
printCertificates(tlsConn.ConnectionState().PeerCertificates)
|
||||||
tabWriter.Flush()
|
|
||||||
}
|
}
|
||||||
tlsConn.Close()
|
tlsConn.Close()
|
||||||
}
|
}
|
||||||
@@ -101,7 +94,7 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("Failed to dial tcp: %s", err)
|
base.Fatalf("Failed to dial tcp: %s", err)
|
||||||
}
|
}
|
||||||
tlsConn := GeneraticUClient(tcpConn, &gotls.Config{
|
tlsConn := gotls.Client(tcpConn, &gotls.Config{
|
||||||
ServerName: domain,
|
ServerName: domain,
|
||||||
NextProtos: []string{"h2", "http/1.1"},
|
NextProtos: []string{"h2", "http/1.1"},
|
||||||
MaxVersion: gotls.VersionTLS13,
|
MaxVersion: gotls.VersionTLS13,
|
||||||
@@ -112,9 +105,8 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
fmt.Println("Handshake failure: ", err)
|
fmt.Println("Handshake failure: ", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Handshake succeeded")
|
fmt.Println("Handshake succeeded")
|
||||||
printTLSConnDetail(tabWriter, tlsConn)
|
printTLSConnDetail(tlsConn)
|
||||||
printCertificates(tabWriter, tlsConn.ConnectionState().PeerCertificates)
|
printCertificates(tlsConn.ConnectionState().PeerCertificates)
|
||||||
tabWriter.Flush()
|
|
||||||
}
|
}
|
||||||
tlsConn.Close()
|
tlsConn.Close()
|
||||||
}
|
}
|
||||||
@@ -123,45 +115,38 @@ func executePing(cmd *base.Command, args []string) {
|
|||||||
fmt.Println("TLS ping finished")
|
fmt.Println("TLS ping finished")
|
||||||
}
|
}
|
||||||
|
|
||||||
func printCertificates(tabWriter *tabwriter.Writer, certs []*x509.Certificate) {
|
func printCertificates(certs []*x509.Certificate) {
|
||||||
var leaf *x509.Certificate
|
var leaf *x509.Certificate
|
||||||
var CAs []*x509.Certificate
|
|
||||||
var length int
|
var length int
|
||||||
for _, cert := range certs {
|
for _, cert := range certs {
|
||||||
length += len(cert.Raw)
|
length += len(cert.Raw)
|
||||||
if len(cert.DNSNames) != 0 {
|
if len(cert.DNSNames) != 0 {
|
||||||
leaf = cert
|
leaf = cert
|
||||||
} else {
|
|
||||||
CAs = append(CAs, cert)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Fprintf(tabWriter, "Certificate chain's total length: \t %d (certs count: %s)\n", length, strconv.Itoa(len(certs)))
|
fmt.Println("Certificate chain's total length: ", length, "(certs count: "+strconv.Itoa(len(certs))+")")
|
||||||
if leaf != nil {
|
if leaf != nil {
|
||||||
fmt.Fprintf(tabWriter, "Cert's signature algorithm: \t %s\n", leaf.SignatureAlgorithm.String())
|
fmt.Println("Cert's signature algorithm: ", leaf.SignatureAlgorithm.String())
|
||||||
fmt.Fprintf(tabWriter, "Cert's publicKey algorithm: \t %s\n", leaf.PublicKeyAlgorithm.String())
|
fmt.Println("Cert's publicKey algorithm: ", leaf.PublicKeyAlgorithm.String())
|
||||||
fmt.Fprintf(tabWriter, "Cert's leaf SHA256: \t %s\n", hex.EncodeToString(GenerateCertHash(leaf)))
|
fmt.Println("Cert's allowed domains: ", leaf.DNSNames)
|
||||||
for _, ca := range CAs {
|
fmt.Println("Cert's leaf SHA256: ", hex.EncodeToString(GenerateCertHash(leaf)))
|
||||||
fmt.Fprintf(tabWriter, "Cert's CA: %s SHA256: \t %s\n", ca.Subject.CommonName, hex.EncodeToString(GenerateCertHash(ca)))
|
|
||||||
}
|
|
||||||
fmt.Fprintf(tabWriter, "Cert's allowed domains: \t %v\n", leaf.DNSNames)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printTLSConnDetail(tabWriter *tabwriter.Writer, tlsConn *utls.UConn) {
|
func printTLSConnDetail(tlsConn *gotls.Conn) {
|
||||||
connectionState := tlsConn.ConnectionState()
|
connectionState := tlsConn.ConnectionState()
|
||||||
var tlsVersion string
|
var tlsVersion string
|
||||||
switch connectionState.Version {
|
if connectionState.Version == gotls.VersionTLS13 {
|
||||||
case gotls.VersionTLS13:
|
|
||||||
tlsVersion = "TLS 1.3"
|
tlsVersion = "TLS 1.3"
|
||||||
case gotls.VersionTLS12:
|
} else if connectionState.Version == gotls.VersionTLS12 {
|
||||||
tlsVersion = "TLS 1.2"
|
tlsVersion = "TLS 1.2"
|
||||||
}
|
}
|
||||||
fmt.Fprintf(tabWriter, "TLS Version: \t %s\n", tlsVersion)
|
fmt.Println("TLS Version: ", tlsVersion)
|
||||||
curveID := utils.AccessField[utls.CurveID](tlsConn.Conn, "curveID")
|
curveID := connectionState.CurveID
|
||||||
if curveID != nil {
|
if curveID != 0 {
|
||||||
PostQuantum := (*curveID == utls.X25519MLKEM768)
|
PostQuantum := (curveID == gotls.X25519MLKEM768)
|
||||||
fmt.Fprintf(tabWriter, "TLS Post-Quantum key exchange: \t %t (%s)\n", PostQuantum, curveID.String())
|
fmt.Println("TLS Post-Quantum key exchange: ", PostQuantum, "("+curveID.String()+")")
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(tabWriter, "TLS Post-Quantum key exchange: false (RSA Exchange)\n")
|
fmt.Println("TLS Post-Quantum key exchange: false (RSA Exchange)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ import (
|
|||||||
_ "github.com/xtls/xray-core/transport/internet/tls"
|
_ "github.com/xtls/xray-core/transport/internet/tls"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/udp"
|
_ "github.com/xtls/xray-core/transport/internet/udp"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/websocket"
|
_ "github.com/xtls/xray-core/transport/internet/websocket"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/xdrive"
|
|
||||||
|
|
||||||
// Transport headers
|
// Transport headers
|
||||||
_ "github.com/xtls/xray-core/transport/internet/headers/http"
|
_ "github.com/xtls/xray-core/transport/internet/headers/http"
|
||||||
|
|||||||
@@ -54,15 +54,15 @@ func DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet
|
|||||||
return nil, errors.New("failed to dial to dest: ", err).AtWarning().Base(err)
|
return nil, errors.New("failed to dial to dest: ", err).AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wrapper, ok := rawConn.(*internet.PacketConnWrapper)
|
||||||
|
if !ok {
|
||||||
|
rawConn.Close()
|
||||||
|
return nil, errors.New("raw is not PacketConnWrapper")
|
||||||
|
}
|
||||||
|
|
||||||
|
raw := wrapper.Conn
|
||||||
|
|
||||||
if streamSettings.UdpmaskManager != nil {
|
if streamSettings.UdpmaskManager != nil {
|
||||||
wrapper, ok := rawConn.(*internet.PacketConnWrapper)
|
|
||||||
if !ok {
|
|
||||||
rawConn.Close()
|
|
||||||
return nil, errors.New("raw is not PacketConnWrapper")
|
|
||||||
}
|
|
||||||
|
|
||||||
raw := wrapper.Conn
|
|
||||||
|
|
||||||
wrapper.Conn, err = streamSettings.UdpmaskManager.WrapPacketConnClient(raw)
|
wrapper.Conn, err = streamSettings.UdpmaskManager.WrapPacketConnClient(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
raw.Close()
|
raw.Close()
|
||||||
|
|||||||
@@ -384,7 +384,6 @@ func (c *Config) GetTLSConfig(opts ...Option) *tls.Config {
|
|||||||
PinnedPeerCertSha256: c.PinnedPeerCertSha256,
|
PinnedPeerCertSha256: c.PinnedPeerCertSha256,
|
||||||
}
|
}
|
||||||
config := &tls.Config{
|
config := &tls.Config{
|
||||||
InsecureSkipVerify: c.AllowInsecure,
|
|
||||||
Rand: randCarrier,
|
Rand: randCarrier,
|
||||||
ClientSessionCache: globalSessionCache,
|
ClientSessionCache: globalSessionCache,
|
||||||
RootCAs: root,
|
RootCAs: root,
|
||||||
|
|||||||
@@ -177,8 +177,7 @@ func (x *Certificate) GetBuildChain() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
AllowInsecure bool `protobuf:"varint,1,opt,name=allow_insecure,json=allowInsecure,proto3" json:"allow_insecure,omitempty"`
|
|
||||||
// List of certificates to be served on server.
|
// List of certificates to be served on server.
|
||||||
Certificate []*Certificate `protobuf:"bytes,2,rep,name=certificate,proto3" json:"certificate,omitempty"`
|
Certificate []*Certificate `protobuf:"bytes,2,rep,name=certificate,proto3" json:"certificate,omitempty"`
|
||||||
// Override server name.
|
// Override server name.
|
||||||
@@ -242,13 +241,6 @@ func (*Config) Descriptor() ([]byte, []int) {
|
|||||||
return file_transport_internet_tls_config_proto_rawDescGZIP(), []int{1}
|
return file_transport_internet_tls_config_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetAllowInsecure() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.AllowInsecure
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetCertificate() []*Certificate {
|
func (x *Config) GetCertificate() []*Certificate {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Certificate
|
return x.Certificate
|
||||||
@@ -393,9 +385,8 @@ const file_transport_internet_tls_config_proto_rawDesc = "" +
|
|||||||
"\x05Usage\x12\x10\n" +
|
"\x05Usage\x12\x10\n" +
|
||||||
"\fENCIPHERMENT\x10\x00\x12\x14\n" +
|
"\fENCIPHERMENT\x10\x00\x12\x14\n" +
|
||||||
"\x10AUTHORITY_VERIFY\x10\x01\x12\x13\n" +
|
"\x10AUTHORITY_VERIFY\x10\x01\x12\x13\n" +
|
||||||
"\x0fAUTHORITY_ISSUE\x10\x02\"\xf5\x06\n" +
|
"\x0fAUTHORITY_ISSUE\x10\x02\"\xce\x06\n" +
|
||||||
"\x06Config\x12%\n" +
|
"\x06Config\x12J\n" +
|
||||||
"\x0eallow_insecure\x18\x01 \x01(\bR\rallowInsecure\x12J\n" +
|
|
||||||
"\vcertificate\x18\x02 \x03(\v2(.xray.transport.internet.tls.CertificateR\vcertificate\x12\x1f\n" +
|
"\vcertificate\x18\x02 \x03(\v2(.xray.transport.internet.tls.CertificateR\vcertificate\x12\x1f\n" +
|
||||||
"\vserver_name\x18\x03 \x01(\tR\n" +
|
"\vserver_name\x18\x03 \x01(\tR\n" +
|
||||||
"serverName\x12#\n" +
|
"serverName\x12#\n" +
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ message Certificate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message Config {
|
message Config {
|
||||||
bool allow_insecure = 1;
|
|
||||||
|
|
||||||
// List of certificates to be served on server.
|
// List of certificates to be served on server.
|
||||||
repeated Certificate certificate = 2;
|
repeated Certificate certificate = 2;
|
||||||
|
|
||||||
|
|||||||
@@ -126,10 +126,6 @@ func UClient(c net.Conn, config *tls.Config, fingerprint *utls.ClientHelloID) ne
|
|||||||
return &UConn{UConn: utlsConn}
|
return &UConn{UConn: utlsConn}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GeneraticUClient(c net.Conn, config *tls.Config) *utls.UConn {
|
|
||||||
return utls.UClient(c, copyConfig(config), utls.HelloChrome_Auto)
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyConfig(c *tls.Config) *utls.Config {
|
func copyConfig(c *tls.Config) *utls.Config {
|
||||||
return &utls.Config{
|
return &utls.Config{
|
||||||
Rand: c.Rand,
|
Rand: c.Rand,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"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"
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
"github.com/xtls/xray-core/transport/internet/stat"
|
||||||
@@ -21,24 +20,7 @@ func init() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if streamSettings != nil && streamSettings.UdpmaskManager != nil {
|
|
||||||
wrapper, ok := conn.(*internet.PacketConnWrapper)
|
|
||||||
if !ok {
|
|
||||||
conn.Close()
|
|
||||||
return nil, errors.New("conn is not PacketConnWrapper")
|
|
||||||
}
|
|
||||||
|
|
||||||
raw := wrapper.Conn
|
|
||||||
|
|
||||||
wrapper.Conn, err = streamSettings.UdpmaskManager.WrapPacketConnClient(raw)
|
|
||||||
if err != nil {
|
|
||||||
raw.Close()
|
|
||||||
return nil, errors.New("mask err").Base(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle dialer options
|
// TODO: handle dialer options
|
||||||
return conn, nil
|
return stat.Connection(conn), nil
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,140 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.36.11
|
|
||||||
// protoc v6.33.5
|
|
||||||
// source: transport/internet/xdrive/config.proto
|
|
||||||
|
|
||||||
package xdrive
|
|
||||||
|
|
||||||
import (
|
|
||||||
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"`
|
|
||||||
RemoteFolder string `protobuf:"bytes,1,opt,name=remote_folder,json=remoteFolder,proto3" json:"remote_folder,omitempty"`
|
|
||||||
Service string `protobuf:"bytes,2,opt,name=service,proto3" json:"service,omitempty"`
|
|
||||||
Secrets []string `protobuf:"bytes,3,rep,name=secrets,proto3" json:"secrets,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
|
||||||
*x = Config{}
|
|
||||||
mi := &file_transport_internet_xdrive_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_xdrive_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_xdrive_config_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetRemoteFolder() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.RemoteFolder
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetService() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Service
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetSecrets() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Secrets
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_transport_internet_xdrive_config_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
const file_transport_internet_xdrive_config_proto_rawDesc = "" +
|
|
||||||
"\n" +
|
|
||||||
"&transport/internet/xdrive/config.proto\x12\x1exray.transport.internet.xdrive\"a\n" +
|
|
||||||
"\x06Config\x12#\n" +
|
|
||||||
"\rremote_folder\x18\x01 \x01(\tR\fremoteFolder\x12\x18\n" +
|
|
||||||
"\aservice\x18\x02 \x01(\tR\aservice\x12\x18\n" +
|
|
||||||
"\asecrets\x18\x03 \x03(\tR\asecretsB5Z3github.com/xtls/xray-core/transport/internet/xdriveb\x06proto3"
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_transport_internet_xdrive_config_proto_rawDescOnce sync.Once
|
|
||||||
file_transport_internet_xdrive_config_proto_rawDescData []byte
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_transport_internet_xdrive_config_proto_rawDescGZIP() []byte {
|
|
||||||
file_transport_internet_xdrive_config_proto_rawDescOnce.Do(func() {
|
|
||||||
file_transport_internet_xdrive_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_xdrive_config_proto_rawDesc), len(file_transport_internet_xdrive_config_proto_rawDesc)))
|
|
||||||
})
|
|
||||||
return file_transport_internet_xdrive_config_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_transport_internet_xdrive_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
|
||||||
var file_transport_internet_xdrive_config_proto_goTypes = []any{
|
|
||||||
(*Config)(nil), // 0: xray.transport.internet.xdrive.Config
|
|
||||||
}
|
|
||||||
var file_transport_internet_xdrive_config_proto_depIdxs = []int32{
|
|
||||||
0, // [0:0] is the sub-list for method output_type
|
|
||||||
0, // [0:0] is the sub-list for method input_type
|
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
|
||||||
0, // [0:0] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_transport_internet_xdrive_config_proto_init() }
|
|
||||||
func file_transport_internet_xdrive_config_proto_init() {
|
|
||||||
if File_transport_internet_xdrive_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_xdrive_config_proto_rawDesc), len(file_transport_internet_xdrive_config_proto_rawDesc)),
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 1,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_transport_internet_xdrive_config_proto_goTypes,
|
|
||||||
DependencyIndexes: file_transport_internet_xdrive_config_proto_depIdxs,
|
|
||||||
MessageInfos: file_transport_internet_xdrive_config_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_transport_internet_xdrive_config_proto = out.File
|
|
||||||
file_transport_internet_xdrive_config_proto_goTypes = nil
|
|
||||||
file_transport_internet_xdrive_config_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.transport.internet.xdrive;
|
|
||||||
option go_package = "github.com/xtls/xray-core/transport/internet/xdrive";
|
|
||||||
|
|
||||||
message Config {
|
|
||||||
string remote_folder = 1;
|
|
||||||
string service = 2;
|
|
||||||
repeated string secrets = 3;
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package xdrive
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
|
||||||
)
|
|
||||||
|
|
||||||
const protocolName = "xdrive"
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
|
|
||||||
return new(Config)
|
|
||||||
}))
|
|
||||||
common.Must(internet.RegisterTransportDialer(protocolName, Dial))
|
|
||||||
common.Must(internet.RegisterTransportListener(protocolName, Serve))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) {
|
|
||||||
//config := streamSettings.ProtocolSettings.(*Config)
|
|
||||||
|
|
||||||
var conn net.Conn
|
|
||||||
return stat.Connection(conn), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
config *Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) Addr() net.Addr {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Serve(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (internet.Listener, error) {
|
|
||||||
var server Server
|
|
||||||
|
|
||||||
return &server, nil
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user