Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea508727de |
@@ -196,47 +196,6 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
|||||||
return inboundLink, outboundLink
|
return inboundLink, outboundLink
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDispatcher) WrapLink(ctx context.Context, link *transport.Link) *transport.Link {
|
|
||||||
sessionInbound := session.InboundFromContext(ctx)
|
|
||||||
var user *protocol.MemoryUser
|
|
||||||
if sessionInbound != nil {
|
|
||||||
user = sessionInbound.User
|
|
||||||
}
|
|
||||||
|
|
||||||
link.Reader = &buf.TimeoutWrapperReader{Reader: link.Reader}
|
|
||||||
|
|
||||||
if user != nil && len(user.Email) > 0 {
|
|
||||||
p := d.policy.ForLevel(user.Level)
|
|
||||||
if p.Stats.UserUplink {
|
|
||||||
name := "user>>>" + user.Email + ">>>traffic>>>uplink"
|
|
||||||
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
|
||||||
link.Reader.(*buf.TimeoutWrapperReader).Counter = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if p.Stats.UserDownlink {
|
|
||||||
name := "user>>>" + user.Email + ">>>traffic>>>downlink"
|
|
||||||
if c, _ := stats.GetOrRegisterCounter(d.stats, name); c != nil {
|
|
||||||
link.Writer = &SizeStatWriter{
|
|
||||||
Counter: c,
|
|
||||||
Writer: link.Writer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if p.Stats.UserOnline {
|
|
||||||
name := "user>>>" + user.Email + ">>>online"
|
|
||||||
if om, _ := stats.GetOrRegisterOnlineMap(d.stats, name); om != nil {
|
|
||||||
sessionInbounds := session.InboundFromContext(ctx)
|
|
||||||
userIP := sessionInbounds.Source.Address.String()
|
|
||||||
om.AddIP(userIP)
|
|
||||||
// log Online user with ips
|
|
||||||
// errors.LogDebug(ctx, "user>>>" + user.Email + ">>>online", om.Count(), om.List())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return link
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
func (d *DefaultDispatcher) shouldOverride(ctx context.Context, result SniffResult, request session.SniffingRequest, destination net.Destination) bool {
|
||||||
domain := result.Domain()
|
domain := result.Domain()
|
||||||
if domain == "" {
|
if domain == "" {
|
||||||
@@ -357,7 +316,6 @@ func (d *DefaultDispatcher) DispatchLink(ctx context.Context, destination net.De
|
|||||||
content = new(session.Content)
|
content = new(session.Content)
|
||||||
ctx = session.ContextWithContent(ctx, content)
|
ctx = session.ContextWithContent(ctx, content)
|
||||||
}
|
}
|
||||||
outbound = d.WrapLink(ctx, outbound)
|
|
||||||
sniffingRequest := content.SniffingRequest
|
sniffingRequest := content.SniffingRequest
|
||||||
if !sniffingRequest.Enabled {
|
if !sniffingRequest.Enabled {
|
||||||
d.routedDispatch(ctx, outbound, destination)
|
d.routedDispatch(ctx, outbound, destination)
|
||||||
|
|||||||
+16
-16
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/dispatcher"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/mux"
|
"github.com/xtls/xray-core/common/mux"
|
||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
@@ -149,23 +148,25 @@ func (w *BridgeWorker) Connections() uint32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
|
func (w *BridgeWorker) handleInternalConn(link *transport.Link) {
|
||||||
reader := link.Reader
|
go func() {
|
||||||
for {
|
reader := link.Reader
|
||||||
mb, err := reader.ReadMultiBuffer()
|
for {
|
||||||
if err != nil {
|
mb, err := reader.ReadMultiBuffer()
|
||||||
break
|
if err != nil {
|
||||||
}
|
|
||||||
for _, b := range mb {
|
|
||||||
var ctl Control
|
|
||||||
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
|
|
||||||
errors.LogInfoInner(context.Background(), err, "failed to parse proto message")
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if ctl.State != w.state {
|
for _, b := range mb {
|
||||||
w.state = ctl.State
|
var ctl Control
|
||||||
|
if err := proto.Unmarshal(b.Bytes(), &ctl); err != nil {
|
||||||
|
errors.LogInfoInner(context.Background(), err, "failed to parse proto message")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if ctl.State != w.state {
|
||||||
|
w.state = ctl.State
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
|
func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*transport.Link, error) {
|
||||||
@@ -180,7 +181,7 @@ func (w *BridgeWorker) Dispatch(ctx context.Context, dest net.Destination) (*tra
|
|||||||
uplinkReader, uplinkWriter := pipe.New(opt...)
|
uplinkReader, uplinkWriter := pipe.New(opt...)
|
||||||
downlinkReader, downlinkWriter := pipe.New(opt...)
|
downlinkReader, downlinkWriter := pipe.New(opt...)
|
||||||
|
|
||||||
go w.handleInternalConn(&transport.Link{
|
w.handleInternalConn(&transport.Link{
|
||||||
Reader: downlinkReader,
|
Reader: downlinkReader,
|
||||||
Writer: uplinkWriter,
|
Writer: uplinkWriter,
|
||||||
})
|
})
|
||||||
@@ -199,7 +200,6 @@ func (w *BridgeWorker) DispatchLink(ctx context.Context, dest net.Destination, l
|
|||||||
return w.dispatcher.DispatchLink(ctx, dest, link)
|
return w.dispatcher.DispatchLink(ctx, dest, link)
|
||||||
}
|
}
|
||||||
|
|
||||||
link = w.dispatcher.(*dispatcher.DefaultDispatcher).WrapLink(ctx, link)
|
|
||||||
w.handleInternalConn(link)
|
w.handleInternalConn(link)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+5
-18
@@ -30,7 +30,6 @@ type TimeoutReader interface {
|
|||||||
|
|
||||||
type TimeoutWrapperReader struct {
|
type TimeoutWrapperReader struct {
|
||||||
Reader
|
Reader
|
||||||
stats.Counter
|
|
||||||
mb MultiBuffer
|
mb MultiBuffer
|
||||||
err error
|
err error
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
@@ -40,16 +39,11 @@ func (r *TimeoutWrapperReader) ReadMultiBuffer() (MultiBuffer, error) {
|
|||||||
if r.done != nil {
|
if r.done != nil {
|
||||||
<-r.done
|
<-r.done
|
||||||
r.done = nil
|
r.done = nil
|
||||||
if r.Counter != nil {
|
|
||||||
r.Counter.Add(int64(r.mb.Len()))
|
|
||||||
}
|
|
||||||
return r.mb, r.err
|
return r.mb, r.err
|
||||||
}
|
}
|
||||||
r.mb, r.err = r.Reader.ReadMultiBuffer()
|
r.mb = nil
|
||||||
if r.Counter != nil {
|
r.err = nil
|
||||||
r.Counter.Add(int64(r.mb.Len()))
|
return r.Reader.ReadMultiBuffer()
|
||||||
}
|
|
||||||
return r.mb, r.err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *TimeoutWrapperReader) ReadMultiBufferTimeout(duration time.Duration) (MultiBuffer, error) {
|
func (r *TimeoutWrapperReader) ReadMultiBufferTimeout(duration time.Duration) (MultiBuffer, error) {
|
||||||
@@ -60,19 +54,12 @@ func (r *TimeoutWrapperReader) ReadMultiBufferTimeout(duration time.Duration) (M
|
|||||||
close(r.done)
|
close(r.done)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
timeout := make(chan struct{})
|
time.Sleep(duration)
|
||||||
go func() {
|
|
||||||
time.Sleep(duration)
|
|
||||||
close(timeout)
|
|
||||||
}()
|
|
||||||
select {
|
select {
|
||||||
case <-r.done:
|
case <-r.done:
|
||||||
r.done = nil
|
r.done = nil
|
||||||
if r.Counter != nil {
|
|
||||||
r.Counter.Add(int64(r.mb.Len()))
|
|
||||||
}
|
|
||||||
return r.mb, r.err
|
return r.mb, r.err
|
||||||
case <-timeout:
|
default:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-17
@@ -75,10 +75,9 @@ func (w *BufferToBytesWriter) ReadFrom(reader io.Reader) (int64, error) {
|
|||||||
// BufferedWriter is a Writer with internal buffer.
|
// BufferedWriter is a Writer with internal buffer.
|
||||||
type BufferedWriter struct {
|
type BufferedWriter struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
writer Writer
|
writer Writer
|
||||||
buffer *Buffer
|
buffer *Buffer
|
||||||
buffered bool
|
buffered bool
|
||||||
flushNext bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBufferedWriter creates a new BufferedWriter.
|
// NewBufferedWriter creates a new BufferedWriter.
|
||||||
@@ -162,12 +161,6 @@ func (w *BufferedWriter) WriteMultiBuffer(b MultiBuffer) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.flushNext {
|
|
||||||
w.buffered = false
|
|
||||||
w.flushNext = false
|
|
||||||
return w.flushInternal()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,13 +201,6 @@ func (w *BufferedWriter) SetBuffered(f bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFlushNext will wait the next WriteMultiBuffer to flush and set buffered = false
|
|
||||||
func (w *BufferedWriter) SetFlushNext() {
|
|
||||||
w.Lock()
|
|
||||||
defer w.Unlock()
|
|
||||||
w.flushNext = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadFrom implements io.ReaderFrom.
|
// ReadFrom implements io.ReaderFrom.
|
||||||
func (w *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) {
|
func (w *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) {
|
||||||
if err := w.SetBuffered(false); err != nil {
|
if err := w.SetBuffered(false); err != nil {
|
||||||
|
|||||||
@@ -10,9 +10,6 @@ func RandBetween(from int64, to int64) int64 {
|
|||||||
if from == to {
|
if from == to {
|
||||||
return from
|
return from
|
||||||
}
|
}
|
||||||
if from > to {
|
|
||||||
from, to = to, 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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/dispatcher"
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
@@ -62,7 +61,6 @@ func (s *Server) DispatchLink(ctx context.Context, dest net.Destination, link *t
|
|||||||
if dest.Address != muxCoolAddress {
|
if dest.Address != muxCoolAddress {
|
||||||
return s.dispatcher.DispatchLink(ctx, dest, link)
|
return s.dispatcher.DispatchLink(ctx, dest, link)
|
||||||
}
|
}
|
||||||
link = s.dispatcher.(*dispatcher.DefaultDispatcher).WrapLink(ctx, link)
|
|
||||||
_, err := NewServerWorker(ctx, s.dispatcher, link)
|
_, err := NewServerWorker(ctx, s.dispatcher, link)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -18,8 +18,8 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
Version_x byte = 25
|
Version_x byte = 25
|
||||||
Version_y byte = 9
|
Version_y byte = 8
|
||||||
Version_z byte = 5
|
Version_z byte = 29
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
+12
-36
@@ -74,7 +74,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if account.Encryption != "" {
|
if account.Encryption != "" {
|
||||||
return nil, errors.New(`VLESS clients: "encryption" should not be in inbound settings`)
|
return nil, errors.New(`VLESS clients: "encryption" should not in inbound settings`)
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Account = serial.ToTypedMessage(account)
|
user.Account = serial.ToTypedMessage(account)
|
||||||
@@ -96,34 +96,23 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
|||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
t := strings.SplitN(strings.TrimSuffix(s[2], "s"), "-", 2)
|
if s[2] != "1rtt" {
|
||||||
i, err := strconv.Atoi(t[0])
|
t := strings.TrimSuffix(s[2], "s")
|
||||||
if err != nil {
|
if t == s[2] {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
config.SecondsFrom = int64(i)
|
i, err := strconv.Atoi(t)
|
||||||
if len(t) == 2 {
|
|
||||||
i, err := strconv.Atoi(t[1])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
config.SecondsTo = int64(i)
|
config.Seconds = uint32(i)
|
||||||
}
|
}
|
||||||
padding := 0
|
for i := 3; i < len(s); i++ {
|
||||||
for _, r := range s[3:] {
|
if b, _ := base64.RawURLEncoding.DecodeString(s[i]); len(b) != 32 && len(b) != 64 {
|
||||||
if len(r) < 20 {
|
|
||||||
padding += len(r) + 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if b, _ := base64.RawURLEncoding.DecodeString(r); len(b) != 32 && len(b) != 64 {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config.Decryption = config.Decryption[27+len(s[2]):]
|
config.Decryption = config.Decryption[27+len(s[2]):]
|
||||||
if padding > 0 {
|
|
||||||
config.Padding = config.Decryption[:padding-1]
|
|
||||||
config.Decryption = config.Decryption[padding:]
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}() && config.Decryption != "none" {
|
}() && config.Decryption != "none" {
|
||||||
if config.Decryption == "" {
|
if config.Decryption == "" {
|
||||||
@@ -132,10 +121,6 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
|||||||
return nil, errors.New(`VLESS settings: unsupported "decryption": ` + config.Decryption)
|
return nil, errors.New(`VLESS settings: unsupported "decryption": ` + config.Decryption)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Decryption != "none" && c.Fallbacks != nil {
|
|
||||||
return nil, errors.New(`VLESS settings: "fallbacks" can not be used together with "decryption"`)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, fb := range c.Fallbacks {
|
for _, fb := range c.Fallbacks {
|
||||||
var i uint16
|
var i uint16
|
||||||
var s string
|
var s string
|
||||||
@@ -265,21 +250,12 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
|||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
padding := 0
|
for i := 3; i < len(s); i++ {
|
||||||
for _, r := range s[3:] {
|
if b, _ := base64.RawURLEncoding.DecodeString(s[i]); len(b) != 32 && len(b) != 1184 {
|
||||||
if len(r) < 20 {
|
|
||||||
padding += len(r) + 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if b, _ := base64.RawURLEncoding.DecodeString(r); len(b) != 32 && len(b) != 1184 {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
account.Encryption = account.Encryption[27+len(s[2]):]
|
account.Encryption = account.Encryption[27+len(s[2]):]
|
||||||
if padding > 0 {
|
|
||||||
account.Padding = account.Encryption[:padding-1]
|
|
||||||
account.Encryption = account.Encryption[padding:]
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}() && account.Encryption != "none" {
|
}() && account.Encryption != "none" {
|
||||||
if account.Encryption == "" {
|
if account.Encryption == "" {
|
||||||
|
|||||||
@@ -18,6 +18,5 @@ func init() {
|
|||||||
cmdWG,
|
cmdWG,
|
||||||
cmdMLDSA65,
|
cmdMLDSA65,
|
||||||
cmdMLKEM768,
|
cmdMLKEM768,
|
||||||
cmdVLESSEnc,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,21 +25,6 @@ func Curve25519Genkey(StdEncoding bool, input_base64 string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
privateKey, password, hash32, err := genCurve25519(privateKey)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Printf("PrivateKey: %v\nPassword: %v\nHash32: %v\n",
|
|
||||||
encoding.EncodeToString(privateKey),
|
|
||||||
encoding.EncodeToString(password),
|
|
||||||
encoding.EncodeToString(hash32[:]))
|
|
||||||
}
|
|
||||||
|
|
||||||
func genCurve25519(inputPrivateKey []byte) (privateKey []byte, password []byte, hash32 [32]byte, returnErr error) {
|
|
||||||
if len(inputPrivateKey) > 0 {
|
|
||||||
privateKey = inputPrivateKey
|
|
||||||
}
|
|
||||||
if privateKey == nil {
|
if privateKey == nil {
|
||||||
privateKey = make([]byte, 32)
|
privateKey = make([]byte, 32)
|
||||||
rand.Read(privateKey)
|
rand.Read(privateKey)
|
||||||
@@ -54,10 +39,13 @@ func genCurve25519(inputPrivateKey []byte) (privateKey []byte, password []byte,
|
|||||||
|
|
||||||
key, err := ecdh.X25519().NewPrivateKey(privateKey)
|
key, err := ecdh.X25519().NewPrivateKey(privateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
returnErr = err
|
fmt.Println(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
password = key.PublicKey().Bytes()
|
password := key.PublicKey().Bytes()
|
||||||
hash32 = blake3.Sum256(password)
|
hash32 := blake3.Sum256(password)
|
||||||
return
|
fmt.Printf("PrivateKey: %v\nPassword: %v\nHash32: %v",
|
||||||
|
encoding.EncodeToString(privateKey),
|
||||||
|
encoding.EncodeToString(password),
|
||||||
|
encoding.EncodeToString(hash32[:]))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func executeMLDSA65(cmd *base.Command, args []string) {
|
|||||||
rand.Read(seed[:])
|
rand.Read(seed[:])
|
||||||
}
|
}
|
||||||
pub, _ := mldsa65.NewKeyFromSeed(&seed)
|
pub, _ := mldsa65.NewKeyFromSeed(&seed)
|
||||||
fmt.Printf("Seed: %v\nVerify: %v\n",
|
fmt.Printf("Seed: %v\nVerify: %v",
|
||||||
base64.RawURLEncoding.EncodeToString(seed[:]),
|
base64.RawURLEncoding.EncodeToString(seed[:]),
|
||||||
base64.RawURLEncoding.EncodeToString(pub.Bytes()))
|
base64.RawURLEncoding.EncodeToString(pub.Bytes()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import (
|
|||||||
|
|
||||||
var cmdMLKEM768 = &base.Command{
|
var cmdMLKEM768 = &base.Command{
|
||||||
UsageLine: `{{.Exec}} mlkem768 [-i "seed (base64.RawURLEncoding)"]`,
|
UsageLine: `{{.Exec}} mlkem768 [-i "seed (base64.RawURLEncoding)"]`,
|
||||||
Short: `Generate key pair for ML-KEM-768 post-quantum key exchange (VLESS Encryption)`,
|
Short: `Generate key pair for ML-KEM-768 post-quantum key exchange (VLESS)`,
|
||||||
Long: `
|
Long: `
|
||||||
Generate key pair for ML-KEM-768 post-quantum key exchange (VLESS Encryption).
|
Generate key pair for ML-KEM-768 post-quantum key exchange (VLESS).
|
||||||
|
|
||||||
Random: {{.Exec}} mlkem768
|
Random: {{.Exec}} mlkem768
|
||||||
|
|
||||||
@@ -40,21 +40,11 @@ func executeMLKEM768(cmd *base.Command, args []string) {
|
|||||||
} else {
|
} else {
|
||||||
rand.Read(seed[:])
|
rand.Read(seed[:])
|
||||||
}
|
}
|
||||||
seed, client, hash32 := genMLKEM768(&seed)
|
key, _ := mlkem.NewDecapsulationKey768(seed[:])
|
||||||
fmt.Printf("Seed: %v\nClient: %v\nHash32: %v\n",
|
client := key.EncapsulationKey().Bytes()
|
||||||
|
hash32 := blake3.Sum256(client)
|
||||||
|
fmt.Printf("Seed: %v\nClient: %v\nHash32: %v",
|
||||||
base64.RawURLEncoding.EncodeToString(seed[:]),
|
base64.RawURLEncoding.EncodeToString(seed[:]),
|
||||||
base64.RawURLEncoding.EncodeToString(client),
|
base64.RawURLEncoding.EncodeToString(client),
|
||||||
base64.RawURLEncoding.EncodeToString(hash32[:]))
|
base64.RawURLEncoding.EncodeToString(hash32[:]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func genMLKEM768(inputSeed *[64]byte) (seed [64]byte, client []byte, hash32 [32]byte) {
|
|
||||||
if inputSeed == nil {
|
|
||||||
rand.Read(seed[:])
|
|
||||||
} else {
|
|
||||||
seed = *inputSeed
|
|
||||||
}
|
|
||||||
key, _ := mlkem.NewDecapsulationKey768(seed[:])
|
|
||||||
client = key.EncapsulationKey().Bytes()
|
|
||||||
hash32 = blake3.Sum256(client)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
package all
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/main/commands/base"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cmdVLESSEnc = &base.Command{
|
|
||||||
UsageLine: `{{.Exec}} vlessenc`,
|
|
||||||
Short: `Generate decryption/encryption json pair (VLESS Encryption)`,
|
|
||||||
Long: `
|
|
||||||
Generate decryption/encryption json pair (VLESS Encryption).
|
|
||||||
`,
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
cmdVLESSEnc.Run = executeVLESSEnc // break init loop
|
|
||||||
}
|
|
||||||
|
|
||||||
func executeVLESSEnc(cmd *base.Command, args []string) {
|
|
||||||
privateKey, password, _, _ := genCurve25519(nil)
|
|
||||||
serverKey := base64.RawURLEncoding.EncodeToString(privateKey)
|
|
||||||
clientKey := base64.RawURLEncoding.EncodeToString(password)
|
|
||||||
decryption := generateDotConfig("mlkem768x25519plus", "native", "600s", serverKey)
|
|
||||||
encryption := generateDotConfig("mlkem768x25519plus", "native", "0rtt", clientKey)
|
|
||||||
seed, client, _ := genMLKEM768(nil)
|
|
||||||
serverKeyPQ := base64.RawURLEncoding.EncodeToString(seed[:])
|
|
||||||
clientKeyPQ := base64.RawURLEncoding.EncodeToString(client)
|
|
||||||
decryptionPQ := generateDotConfig("mlkem768x25519plus", "native", "600s", serverKeyPQ)
|
|
||||||
encryptionPQ := generateDotConfig("mlkem768x25519plus", "native", "0rtt", clientKeyPQ)
|
|
||||||
fmt.Printf("Choose one Authentication to use, do not mix them. Ephemeral key exchange is Post-Quantum safe anyway.\n\n")
|
|
||||||
fmt.Printf("Authentication: X25519, not Post-Quantum\n\"decryption\": \"%v\"\n\"encryption\": \"%v\"\n\n", decryption, encryption)
|
|
||||||
fmt.Printf("Authentication: ML-KEM-768, Post-Quantum\n\"decryption\": \"%v\"\n\"encryption\": \"%v\"\n", decryptionPQ, encryptionPQ)
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateDotConfig(fields ...string) string {
|
|
||||||
return strings.Join(fields, ".")
|
|
||||||
}
|
|
||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
|
|
||||||
var cmdX25519 = &base.Command{
|
var cmdX25519 = &base.Command{
|
||||||
UsageLine: `{{.Exec}} x25519 [-i "private key (base64.RawURLEncoding)"] [--std-encoding]`,
|
UsageLine: `{{.Exec}} x25519 [-i "private key (base64.RawURLEncoding)"] [--std-encoding]`,
|
||||||
Short: `Generate key pair for X25519 key exchange (REALITY, VLESS Encryption)`,
|
Short: `Generate key pair for X25519 key exchange (VLESS, REALITY)`,
|
||||||
Long: `
|
Long: `
|
||||||
Generate key pair for X25519 key exchange (REALITY, VLESS Encryption).
|
Generate key pair for X25519 key exchange (VLESS, REALITY).
|
||||||
|
|
||||||
Random: {{.Exec}} x25519
|
Random: {{.Exec}} x25519
|
||||||
|
|
||||||
|
|||||||
@@ -1,512 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.33.0
|
|
||||||
// protoc v4.23.1
|
|
||||||
// source: proxy/addons.proto
|
|
||||||
|
|
||||||
package proxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
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 SeedMode int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
SeedMode_Unknown SeedMode = 0
|
|
||||||
SeedMode_PaddingOnly SeedMode = 1
|
|
||||||
SeedMode_PaddingPlusDelay SeedMode = 2
|
|
||||||
SeedMode_IndependentScheduler SeedMode = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
// Enum value maps for SeedMode.
|
|
||||||
var (
|
|
||||||
SeedMode_name = map[int32]string{
|
|
||||||
0: "Unknown",
|
|
||||||
1: "PaddingOnly",
|
|
||||||
2: "PaddingPlusDelay",
|
|
||||||
3: "IndependentScheduler",
|
|
||||||
}
|
|
||||||
SeedMode_value = map[string]int32{
|
|
||||||
"Unknown": 0,
|
|
||||||
"PaddingOnly": 1,
|
|
||||||
"PaddingPlusDelay": 2,
|
|
||||||
"IndependentScheduler": 3,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (x SeedMode) Enum() *SeedMode {
|
|
||||||
p := new(SeedMode)
|
|
||||||
*p = x
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x SeedMode) String() string {
|
|
||||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (SeedMode) Descriptor() protoreflect.EnumDescriptor {
|
|
||||||
return file_proxy_addons_proto_enumTypes[0].Descriptor()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (SeedMode) Type() protoreflect.EnumType {
|
|
||||||
return &file_proxy_addons_proto_enumTypes[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x SeedMode) Number() protoreflect.EnumNumber {
|
|
||||||
return protoreflect.EnumNumber(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use SeedMode.Descriptor instead.
|
|
||||||
func (SeedMode) EnumDescriptor() ([]byte, []int) {
|
|
||||||
return file_proxy_addons_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Addons struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Flow string `protobuf:"bytes,1,opt,name=Flow,proto3" json:"Flow,omitempty"`
|
|
||||||
Seed []byte `protobuf:"bytes,2,opt,name=Seed,proto3" json:"Seed,omitempty"`
|
|
||||||
Mode SeedMode `protobuf:"varint,3,opt,name=Mode,proto3,enum=xray.proxy.SeedMode" json:"Mode,omitempty"`
|
|
||||||
Duration string `protobuf:"bytes,4,opt,name=Duration,proto3" json:"Duration,omitempty"` // "0-8" means apply to number of packets, "1000b-" means start applying once both side exchange 1kb data, counting two-ways
|
|
||||||
Padding *PaddingConfig `protobuf:"bytes,5,opt,name=Padding,proto3" json:"Padding,omitempty"`
|
|
||||||
Delay *DelayConfig `protobuf:"bytes,6,opt,name=Delay,proto3" json:"Delay,omitempty"`
|
|
||||||
Scheduler *SchedulerConfig `protobuf:"bytes,7,opt,name=Scheduler,proto3" json:"Scheduler,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) Reset() {
|
|
||||||
*x = Addons{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_proxy_addons_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Addons) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Addons) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_proxy_addons_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Addons.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Addons) Descriptor() ([]byte, []int) {
|
|
||||||
return file_proxy_addons_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) GetFlow() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Flow
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) GetSeed() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.Seed
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) GetMode() SeedMode {
|
|
||||||
if x != nil {
|
|
||||||
return x.Mode
|
|
||||||
}
|
|
||||||
return SeedMode_Unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) GetDuration() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Duration
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) GetPadding() *PaddingConfig {
|
|
||||||
if x != nil {
|
|
||||||
return x.Padding
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) GetDelay() *DelayConfig {
|
|
||||||
if x != nil {
|
|
||||||
return x.Delay
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) GetScheduler() *SchedulerConfig {
|
|
||||||
if x != nil {
|
|
||||||
return x.Scheduler
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type PaddingConfig struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
RegularMin uint32 `protobuf:"varint,1,opt,name=RegularMin,proto3" json:"RegularMin,omitempty"`
|
|
||||||
RegularMax uint32 `protobuf:"varint,2,opt,name=RegularMax,proto3" json:"RegularMax,omitempty"`
|
|
||||||
LongMin uint32 `protobuf:"varint,3,opt,name=LongMin,proto3" json:"LongMin,omitempty"`
|
|
||||||
LongMax uint32 `protobuf:"varint,4,opt,name=LongMax,proto3" json:"LongMax,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) Reset() {
|
|
||||||
*x = PaddingConfig{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_proxy_addons_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*PaddingConfig) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_proxy_addons_proto_msgTypes[1]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use PaddingConfig.ProtoReflect.Descriptor instead.
|
|
||||||
func (*PaddingConfig) Descriptor() ([]byte, []int) {
|
|
||||||
return file_proxy_addons_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) GetRegularMin() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.RegularMin
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) GetRegularMax() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.RegularMax
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) GetLongMin() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.LongMin
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) GetLongMax() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.LongMax
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type DelayConfig struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
IsRandom bool `protobuf:"varint,1,opt,name=IsRandom,proto3" json:"IsRandom,omitempty"`
|
|
||||||
MinMillis uint32 `protobuf:"varint,2,opt,name=MinMillis,proto3" json:"MinMillis,omitempty"`
|
|
||||||
MaxMillis uint32 `protobuf:"varint,3,opt,name=MaxMillis,proto3" json:"MaxMillis,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DelayConfig) Reset() {
|
|
||||||
*x = DelayConfig{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_proxy_addons_proto_msgTypes[2]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DelayConfig) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*DelayConfig) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *DelayConfig) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_proxy_addons_proto_msgTypes[2]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use DelayConfig.ProtoReflect.Descriptor instead.
|
|
||||||
func (*DelayConfig) Descriptor() ([]byte, []int) {
|
|
||||||
return file_proxy_addons_proto_rawDescGZIP(), []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DelayConfig) GetIsRandom() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.IsRandom
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DelayConfig) GetMinMillis() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.MinMillis
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DelayConfig) GetMaxMillis() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.MaxMillis
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type SchedulerConfig struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
TimeoutMillis uint32 `protobuf:"varint,1,opt,name=TimeoutMillis,proto3" json:"TimeoutMillis,omitempty"` // original traffic will not be sent right away but when scheduler want to send or pending buffer times out
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SchedulerConfig) Reset() {
|
|
||||||
*x = SchedulerConfig{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_proxy_addons_proto_msgTypes[3]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SchedulerConfig) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*SchedulerConfig) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *SchedulerConfig) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_proxy_addons_proto_msgTypes[3]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use SchedulerConfig.ProtoReflect.Descriptor instead.
|
|
||||||
func (*SchedulerConfig) Descriptor() ([]byte, []int) {
|
|
||||||
return file_proxy_addons_proto_rawDescGZIP(), []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SchedulerConfig) GetTimeoutMillis() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.TimeoutMillis
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_proxy_addons_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_proxy_addons_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x61, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x2e, 0x70,
|
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
|
||||||
0x22, 0x95, 0x02, 0x0a, 0x06, 0x41, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x46,
|
|
||||||
0x6c, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12,
|
|
||||||
0x12, 0x0a, 0x04, 0x53, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x53,
|
|
||||||
0x65, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
|
|
||||||
0x0e, 0x32, 0x14, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53,
|
|
||||||
0x65, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a,
|
|
||||||
0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
|
||||||
0x08, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x07, 0x50, 0x61, 0x64,
|
|
||||||
0x64, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x78, 0x72, 0x61,
|
|
||||||
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x43,
|
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x2d,
|
|
||||||
0x0a, 0x05, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
|
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x44, 0x65, 0x6c, 0x61, 0x79,
|
|
||||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x39, 0x0a,
|
|
||||||
0x09, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
|
|
||||||
0x32, 0x1b, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x53, 0x63,
|
|
||||||
0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x53,
|
|
||||||
0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x22, 0x83, 0x01, 0x0a, 0x0d, 0x50, 0x61, 0x64,
|
|
||||||
0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x65,
|
|
||||||
0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a,
|
|
||||||
0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d, 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x65,
|
|
||||||
0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d, 0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a,
|
|
||||||
0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d, 0x61, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x4c, 0x6f,
|
|
||||||
0x6e, 0x67, 0x4d, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x4c, 0x6f, 0x6e,
|
|
||||||
0x67, 0x4d, 0x69, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x61, 0x78, 0x18,
|
|
||||||
0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x61, 0x78, 0x22, 0x65,
|
|
||||||
0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a,
|
|
||||||
0x08, 0x49, 0x73, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
|
|
||||||
0x08, 0x49, 0x73, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x69, 0x6e,
|
|
||||||
0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4d, 0x69,
|
|
||||||
0x6e, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x61, 0x78, 0x4d, 0x69,
|
|
||||||
0x6c, 0x6c, 0x69, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4d, 0x61, 0x78, 0x4d,
|
|
||||||
0x69, 0x6c, 0x6c, 0x69, 0x73, 0x22, 0x37, 0x0a, 0x0f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
|
|
||||||
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x69, 0x6d, 0x65,
|
|
||||||
0x6f, 0x75, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
|
||||||
0x0d, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x2a, 0x58,
|
|
||||||
0x0a, 0x08, 0x53, 0x65, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e,
|
|
||||||
0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x61, 0x64, 0x64, 0x69,
|
|
||||||
0x6e, 0x67, 0x4f, 0x6e, 0x6c, 0x79, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x61, 0x64, 0x64,
|
|
||||||
0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75, 0x73, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x10, 0x02, 0x12, 0x18,
|
|
||||||
0x0a, 0x14, 0x49, 0x6e, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x68,
|
|
||||||
0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x10, 0x03, 0x42, 0x40, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e,
|
|
||||||
0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x01, 0x5a, 0x1f, 0x67, 0x69,
|
|
||||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72,
|
|
||||||
0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0xaa, 0x02, 0x0a,
|
|
||||||
0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
|
||||||
0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_proxy_addons_proto_rawDescOnce sync.Once
|
|
||||||
file_proxy_addons_proto_rawDescData = file_proxy_addons_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_proxy_addons_proto_rawDescGZIP() []byte {
|
|
||||||
file_proxy_addons_proto_rawDescOnce.Do(func() {
|
|
||||||
file_proxy_addons_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_addons_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_proxy_addons_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_proxy_addons_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
|
||||||
var file_proxy_addons_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
|
||||||
var file_proxy_addons_proto_goTypes = []interface{}{
|
|
||||||
(SeedMode)(0), // 0: xray.proxy.SeedMode
|
|
||||||
(*Addons)(nil), // 1: xray.proxy.Addons
|
|
||||||
(*PaddingConfig)(nil), // 2: xray.proxy.PaddingConfig
|
|
||||||
(*DelayConfig)(nil), // 3: xray.proxy.DelayConfig
|
|
||||||
(*SchedulerConfig)(nil), // 4: xray.proxy.SchedulerConfig
|
|
||||||
}
|
|
||||||
var file_proxy_addons_proto_depIdxs = []int32{
|
|
||||||
0, // 0: xray.proxy.Addons.Mode:type_name -> xray.proxy.SeedMode
|
|
||||||
2, // 1: xray.proxy.Addons.Padding:type_name -> xray.proxy.PaddingConfig
|
|
||||||
3, // 2: xray.proxy.Addons.Delay:type_name -> xray.proxy.DelayConfig
|
|
||||||
4, // 3: xray.proxy.Addons.Scheduler:type_name -> xray.proxy.SchedulerConfig
|
|
||||||
4, // [4:4] is the sub-list for method output_type
|
|
||||||
4, // [4:4] is the sub-list for method input_type
|
|
||||||
4, // [4:4] is the sub-list for extension type_name
|
|
||||||
4, // [4:4] is the sub-list for extension extendee
|
|
||||||
0, // [0:4] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_proxy_addons_proto_init() }
|
|
||||||
func file_proxy_addons_proto_init() {
|
|
||||||
if File_proxy_addons_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_proxy_addons_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*Addons); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_proxy_addons_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*PaddingConfig); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_proxy_addons_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*DelayConfig); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_proxy_addons_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*SchedulerConfig); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_proxy_addons_proto_rawDesc,
|
|
||||||
NumEnums: 1,
|
|
||||||
NumMessages: 4,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_proxy_addons_proto_goTypes,
|
|
||||||
DependencyIndexes: file_proxy_addons_proto_depIdxs,
|
|
||||||
EnumInfos: file_proxy_addons_proto_enumTypes,
|
|
||||||
MessageInfos: file_proxy_addons_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_proxy_addons_proto = out.File
|
|
||||||
file_proxy_addons_proto_rawDesc = nil
|
|
||||||
file_proxy_addons_proto_goTypes = nil
|
|
||||||
file_proxy_addons_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.proxy;
|
|
||||||
option csharp_namespace = "Xray.Proxy";
|
|
||||||
option go_package = "github.com/xtls/xray-core/proxy";
|
|
||||||
option java_package = "com.xray.proxy";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
|
|
||||||
message Addons {
|
|
||||||
string Flow = 1;
|
|
||||||
bytes Seed = 2;
|
|
||||||
SeedMode Mode = 3;
|
|
||||||
string Duration = 4; // "0-8" means apply to number of packets, "1000b-" means start applying once both side exchange 1kb data, counting two-ways
|
|
||||||
PaddingConfig Padding = 5;
|
|
||||||
DelayConfig Delay = 6;
|
|
||||||
SchedulerConfig Scheduler = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum SeedMode {
|
|
||||||
Unknown = 0;
|
|
||||||
PaddingOnly = 1;
|
|
||||||
PaddingPlusDelay = 2;
|
|
||||||
IndependentScheduler = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message PaddingConfig {
|
|
||||||
uint32 RegularMin = 1;
|
|
||||||
uint32 RegularMax = 2;
|
|
||||||
uint32 LongMin = 3;
|
|
||||||
uint32 LongMax = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
message DelayConfig {
|
|
||||||
bool IsRandom = 1;
|
|
||||||
uint32 MinMillis = 2;
|
|
||||||
uint32 MaxMillis = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SchedulerConfig {
|
|
||||||
uint32 TimeoutMillis = 1; // original traffic will not be sent right away but when scheduler want to send or pending buffer times out
|
|
||||||
// Other TBD
|
|
||||||
}
|
|
||||||
+21
-51
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
go_errors "errors"
|
go_errors "errors"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -169,15 +168,11 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
terminate := func() {
|
timer := signal.CancelAfterInactivity(ctx, cancel, h.timeout)
|
||||||
cancel()
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
timer := signal.CancelAfterInactivity(ctx, terminate, h.timeout)
|
|
||||||
defer timer.SetTimeout(0)
|
|
||||||
|
|
||||||
request := func() error {
|
request := func() error {
|
||||||
defer timer.SetTimeout(0)
|
defer conn.Close()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
b, err := reader.ReadMessage()
|
b, err := reader.ReadMessage()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@@ -195,33 +190,24 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
|||||||
if len(h.blockTypes) > 0 {
|
if len(h.blockTypes) > 0 {
|
||||||
for _, blocktype := range h.blockTypes {
|
for _, blocktype := range h.blockTypes {
|
||||||
if blocktype == int32(qType) {
|
if blocktype == int32(qType) {
|
||||||
b.Release()
|
|
||||||
errors.LogInfo(ctx, "blocked type ", qType, " query for domain ", domain)
|
|
||||||
if h.nonIPQuery == "reject" {
|
if h.nonIPQuery == "reject" {
|
||||||
err := h.rejectNonIPQuery(id, qType, domain, writer)
|
go h.rejectNonIPQuery(id, qType, domain, writer)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
errors.LogInfo(ctx, "blocked type ", qType, " query for domain ", domain)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isIPQuery {
|
if isIPQuery {
|
||||||
b.Release()
|
go h.handleIPQuery(id, qType, domain, writer)
|
||||||
go h.handleIPQuery(id, qType, domain, writer, timer)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
if h.nonIPQuery == "drop" {
|
if isIPQuery || h.nonIPQuery == "drop" {
|
||||||
b.Release()
|
b.Release()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if h.nonIPQuery == "reject" {
|
if h.nonIPQuery == "reject" {
|
||||||
|
go h.rejectNonIPQuery(id, qType, domain, writer)
|
||||||
b.Release()
|
b.Release()
|
||||||
err := h.rejectNonIPQuery(id, qType, domain, writer)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,7 +219,6 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
|||||||
}
|
}
|
||||||
|
|
||||||
response := func() error {
|
response := func() error {
|
||||||
defer timer.SetTimeout(0)
|
|
||||||
for {
|
for {
|
||||||
b, err := connReader.ReadMessage()
|
b, err := connReader.ReadMessage()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
@@ -259,7 +244,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, d internet.
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter, timer *signal.ActivityTimer) {
|
func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter) {
|
||||||
var ips []net.IP
|
var ips []net.IP
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@@ -334,21 +319,16 @@ func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogInfoInner(context.Background(), err, "pack message")
|
errors.LogInfoInner(context.Background(), err, "pack message")
|
||||||
b.Release()
|
b.Release()
|
||||||
timer.SetTimeout(0)
|
return
|
||||||
}
|
}
|
||||||
b.Resize(0, int32(len(msgBytes)))
|
b.Resize(0, int32(len(msgBytes)))
|
||||||
|
|
||||||
if err := writer.WriteMessage(b); err != nil {
|
if err := writer.WriteMessage(b); err != nil {
|
||||||
errors.LogInfoInner(context.Background(), err, "write IP answer")
|
errors.LogInfoInner(context.Background(), err, "write IP answer")
|
||||||
timer.SetTimeout(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) rejectNonIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter) error {
|
func (h *Handler) rejectNonIPQuery(id uint16, qType dnsmessage.Type, domain string, writer dns_proto.MessageWriter) {
|
||||||
domainT := strings.TrimSuffix(domain, ".")
|
|
||||||
if domainT == "" {
|
|
||||||
return errors.New("empty domain name")
|
|
||||||
}
|
|
||||||
b := buf.New()
|
b := buf.New()
|
||||||
rawBytes := b.Extend(buf.Size)
|
rawBytes := b.Extend(buf.Size)
|
||||||
builder := dnsmessage.NewBuilder(rawBytes[:0], dnsmessage.Header{
|
builder := dnsmessage.NewBuilder(rawBytes[:0], dnsmessage.Header{
|
||||||
@@ -369,22 +349,20 @@ func (h *Handler) rejectNonIPQuery(id uint16, qType dnsmessage.Type, domain stri
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogInfo(context.Background(), "unexpected domain ", domain, " when building reject message: ", err)
|
errors.LogInfo(context.Background(), "unexpected domain ", domain, " when building reject message: ", err)
|
||||||
b.Release()
|
b.Release()
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
msgBytes, err := builder.Finish()
|
msgBytes, err := builder.Finish()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogInfoInner(context.Background(), err, "pack reject message")
|
errors.LogInfoInner(context.Background(), err, "pack reject message")
|
||||||
b.Release()
|
b.Release()
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
b.Resize(0, int32(len(msgBytes)))
|
b.Resize(0, int32(len(msgBytes)))
|
||||||
|
|
||||||
if err := writer.WriteMessage(b); err != nil {
|
if err := writer.WriteMessage(b); err != nil {
|
||||||
errors.LogInfoInner(context.Background(), err, "write reject answer")
|
errors.LogInfoInner(context.Background(), err, "write reject answer")
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type outboundConn struct {
|
type outboundConn struct {
|
||||||
@@ -393,7 +371,6 @@ type outboundConn struct {
|
|||||||
|
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
connReady chan struct{}
|
connReady chan struct{}
|
||||||
closed bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *outboundConn) dial() error {
|
func (c *outboundConn) dial() error {
|
||||||
@@ -408,16 +385,12 @@ func (c *outboundConn) dial() error {
|
|||||||
|
|
||||||
func (c *outboundConn) Write(b []byte) (int, error) {
|
func (c *outboundConn) Write(b []byte) (int, error) {
|
||||||
c.access.Lock()
|
c.access.Lock()
|
||||||
if c.closed {
|
|
||||||
c.access.Unlock()
|
|
||||||
return 0, errors.New("outbound connection closed")
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.conn == nil {
|
if c.conn == nil {
|
||||||
if err := c.dial(); err != nil {
|
if err := c.dial(); err != nil {
|
||||||
c.access.Unlock()
|
c.access.Unlock()
|
||||||
errors.LogWarningInner(context.Background(), err, "failed to dial outbound connection")
|
errors.LogWarningInner(context.Background(), err, "failed to dial outbound connection")
|
||||||
return 0, err
|
return len(b), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,27 +400,24 @@ func (c *outboundConn) Write(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *outboundConn) Read(b []byte) (int, error) {
|
func (c *outboundConn) Read(b []byte) (int, error) {
|
||||||
|
var conn net.Conn
|
||||||
c.access.Lock()
|
c.access.Lock()
|
||||||
if c.closed {
|
conn = c.conn
|
||||||
c.access.Unlock()
|
c.access.Unlock()
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.conn == nil {
|
if conn == nil {
|
||||||
c.access.Unlock()
|
|
||||||
_, open := <-c.connReady
|
_, open := <-c.connReady
|
||||||
if !open {
|
if !open {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
return c.conn.Read(b)
|
conn = c.conn
|
||||||
}
|
}
|
||||||
c.access.Unlock()
|
|
||||||
return c.conn.Read(b)
|
return conn.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *outboundConn) Close() error {
|
func (c *outboundConn) Close() error {
|
||||||
c.access.Lock()
|
c.access.Lock()
|
||||||
c.closed = true
|
|
||||||
close(c.connReady)
|
close(c.connReady)
|
||||||
if c.conn != nil {
|
if c.conn != nil {
|
||||||
c.conn.Close()
|
c.conn.Close()
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn st
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := dispatcher.DispatchLink(ctx, dest, &transport.Link{
|
if err := dispatcher.DispatchLink(ctx, dest, &transport.Link{
|
||||||
Reader: reader,
|
Reader: &buf.TimeoutWrapperReader{Reader: reader},
|
||||||
Writer: writer},
|
Writer: writer},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return errors.New("failed to dispatch request").Base(err)
|
return errors.New("failed to dispatch request").Base(err)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
"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"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/tls"
|
||||||
)
|
)
|
||||||
|
|
||||||
var useSplice bool
|
var useSplice bool
|
||||||
@@ -211,14 +212,16 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
responseDone := func() error {
|
responseDone := func() error {
|
||||||
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
|
defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
|
||||||
if destination.Network == net.Network_TCP && useSplice && proxy.IsRAWTransportWithoutSecurity(conn) { // it would be tls conn in special use case of MITM, we need to let link handle traffic
|
if destination.Network == net.Network_TCP {
|
||||||
var writeConn net.Conn
|
var writeConn net.Conn
|
||||||
var inTimer *signal.ActivityTimer
|
var inTimer *signal.ActivityTimer
|
||||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil {
|
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil && useSplice {
|
||||||
writeConn = inbound.Conn
|
writeConn = inbound.Conn
|
||||||
inTimer = inbound.Timer
|
inTimer = inbound.Timer
|
||||||
}
|
}
|
||||||
return proxy.CopyRawConnIfExist(ctx, conn, writeConn, link.Writer, timer, inTimer)
|
if !isTLSConn(conn) { // it would be tls conn in special use case of MITM, we need to let link handle traffic
|
||||||
|
return proxy.CopyRawConnIfExist(ctx, conn, writeConn, link.Writer, timer, inTimer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var reader buf.Reader
|
var reader buf.Reader
|
||||||
if destination.Network == net.Network_TCP {
|
if destination.Network == net.Network_TCP {
|
||||||
@@ -243,6 +246,22 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isTLSConn(conn stat.Connection) bool {
|
||||||
|
if conn != nil {
|
||||||
|
statConn, ok := conn.(*stat.CounterConnection)
|
||||||
|
if ok {
|
||||||
|
conn = statConn.Connection
|
||||||
|
}
|
||||||
|
if _, ok := conn.(*tls.Conn); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if _, ok := conn.(*tls.UConn); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.Destination) buf.Reader {
|
func NewPacketReader(conn net.Conn, UDPOverride net.Destination, DialDest net.Destination) buf.Reader {
|
||||||
iConn := conn
|
iConn := conn
|
||||||
statConn, ok := iConn.(*stat.CounterConnection)
|
statConn, ok := iConn.(*stat.CounterConnection)
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ func (s *Server) ProcessWithFirstbyte(ctx context.Context, network net.Network,
|
|||||||
inbound.User = &protocol.MemoryUser{
|
inbound.User = &protocol.MemoryUser{
|
||||||
Level: s.config.UserLevel,
|
Level: s.config.UserLevel,
|
||||||
}
|
}
|
||||||
if !proxy.IsRAWTransportWithoutSecurity(conn) {
|
if !proxy.IsRAWTransport(conn) {
|
||||||
inbound.CanSpliceCopy = 3
|
inbound.CanSpliceCopy = 3
|
||||||
}
|
}
|
||||||
var reader *bufio.Reader
|
var reader *bufio.Reader
|
||||||
@@ -193,7 +193,7 @@ func (s *Server) handleConnect(ctx context.Context, _ *http.Request, buffer *buf
|
|||||||
inbound.CanSpliceCopy = 1
|
inbound.CanSpliceCopy = 1
|
||||||
}
|
}
|
||||||
if err := dispatcher.DispatchLink(ctx, dest, &transport.Link{
|
if err := dispatcher.DispatchLink(ctx, dest, &transport.Link{
|
||||||
Reader: reader,
|
Reader: &buf.TimeoutWrapperReader{Reader: reader},
|
||||||
Writer: buf.NewWriter(conn)},
|
Writer: buf.NewWriter(conn)},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return errors.New("failed to dispatch request").Base(err)
|
return errors.New("failed to dispatch request").Base(err)
|
||||||
|
|||||||
+96
-255
@@ -13,7 +13,6 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pires/go-proxyproto"
|
"github.com/pires/go-proxyproto"
|
||||||
@@ -103,11 +102,6 @@ type GetOutbound interface {
|
|||||||
// It is used by XTLS to determine if switch to raw copy mode, It is used by Vision to calculate padding
|
// It is used by XTLS to determine if switch to raw copy mode, It is used by Vision to calculate padding
|
||||||
type TrafficState struct {
|
type TrafficState struct {
|
||||||
UserUUID []byte
|
UserUUID []byte
|
||||||
StartTime time.Time
|
|
||||||
ByteSent int64
|
|
||||||
ByteReceived int64
|
|
||||||
NumberOfPacketSent int
|
|
||||||
NumberOfPacketReceived int
|
|
||||||
NumberOfPacketToFilter int
|
NumberOfPacketToFilter int
|
||||||
EnableXtls bool
|
EnableXtls bool
|
||||||
IsTLS12orAbove bool
|
IsTLS12orAbove bool
|
||||||
@@ -144,14 +138,9 @@ type OutboundState struct {
|
|||||||
UplinkWriterDirectCopy bool
|
UplinkWriterDirectCopy bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTrafficState(userUUID []byte, flow string) *TrafficState {
|
func NewTrafficState(userUUID []byte) *TrafficState {
|
||||||
var state = TrafficState{
|
return &TrafficState{
|
||||||
UserUUID: userUUID,
|
UserUUID: userUUID,
|
||||||
StartTime: time.Time{},
|
|
||||||
ByteSent: 0,
|
|
||||||
ByteReceived: 0,
|
|
||||||
NumberOfPacketSent: 0,
|
|
||||||
NumberOfPacketReceived: 0,
|
|
||||||
NumberOfPacketToFilter: 8,
|
NumberOfPacketToFilter: 8,
|
||||||
EnableXtls: false,
|
EnableXtls: false,
|
||||||
IsTLS12orAbove: false,
|
IsTLS12orAbove: false,
|
||||||
@@ -159,185 +148,121 @@ func NewTrafficState(userUUID []byte, flow string) *TrafficState {
|
|||||||
Cipher: 0,
|
Cipher: 0,
|
||||||
RemainingServerHello: -1,
|
RemainingServerHello: -1,
|
||||||
Inbound: InboundState{
|
Inbound: InboundState{
|
||||||
|
WithinPaddingBuffers: true,
|
||||||
UplinkReaderDirectCopy: false,
|
UplinkReaderDirectCopy: false,
|
||||||
RemainingCommand: -1,
|
RemainingCommand: -1,
|
||||||
RemainingContent: -1,
|
RemainingContent: -1,
|
||||||
RemainingPadding: -1,
|
RemainingPadding: -1,
|
||||||
CurrentCommand: 0,
|
CurrentCommand: 0,
|
||||||
DownlinkWriterDirectCopy: false,
|
|
||||||
IsPadding: true,
|
IsPadding: true,
|
||||||
|
DownlinkWriterDirectCopy: false,
|
||||||
},
|
},
|
||||||
Outbound: OutboundState{
|
Outbound: OutboundState{
|
||||||
|
WithinPaddingBuffers: true,
|
||||||
DownlinkReaderDirectCopy: false,
|
DownlinkReaderDirectCopy: false,
|
||||||
RemainingCommand: -1,
|
RemainingCommand: -1,
|
||||||
RemainingContent: -1,
|
RemainingContent: -1,
|
||||||
RemainingPadding: -1,
|
RemainingPadding: -1,
|
||||||
CurrentCommand: 0,
|
CurrentCommand: 0,
|
||||||
UplinkWriterDirectCopy: false,
|
|
||||||
IsPadding: true,
|
IsPadding: true,
|
||||||
|
UplinkWriterDirectCopy: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if len(flow) > 0 {
|
|
||||||
state.Inbound.WithinPaddingBuffers = true;
|
|
||||||
state.Outbound.WithinPaddingBuffers = true;
|
|
||||||
}
|
|
||||||
return &state
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisionReader is used to read seed protocol
|
// VisionReader is used to read xtls vision protocol
|
||||||
// Note Vision probably only make sense as the inner most layer of reader, since it need assess traffic state from origin proxy traffic
|
// Note Vision probably only make sense as the inner most layer of reader, since it need assess traffic state from origin proxy traffic
|
||||||
type VisionReader struct {
|
type VisionReader struct {
|
||||||
buf.Reader
|
buf.Reader
|
||||||
addons *Addons
|
|
||||||
trafficState *TrafficState
|
trafficState *TrafficState
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
isUplink bool
|
isUplink bool
|
||||||
conn net.Conn
|
|
||||||
input *bytes.Reader
|
|
||||||
rawInput *bytes.Buffer
|
|
||||||
ob *session.Outbound
|
|
||||||
|
|
||||||
// internal
|
|
||||||
directReadCounter stats.Counter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVisionReader(reader buf.Reader, addon *Addons, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, ob *session.Outbound) *VisionReader {
|
func NewVisionReader(reader buf.Reader, state *TrafficState, isUplink bool, context context.Context) *VisionReader {
|
||||||
return &VisionReader{
|
return &VisionReader{
|
||||||
Reader: reader,
|
Reader: reader,
|
||||||
addons: addon,
|
trafficState: state,
|
||||||
trafficState: trafficState,
|
ctx: context,
|
||||||
ctx: ctx,
|
|
||||||
isUplink: isUplink,
|
isUplink: isUplink,
|
||||||
conn: conn,
|
|
||||||
input: input,
|
|
||||||
rawInput: rawInput,
|
|
||||||
ob: ob,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
func (w *VisionReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||||
buffer, err := w.Reader.ReadMultiBuffer()
|
buffer, err := w.Reader.ReadMultiBuffer()
|
||||||
if buffer.IsEmpty() {
|
if !buffer.IsEmpty() {
|
||||||
return buffer, err
|
var withinPaddingBuffers *bool
|
||||||
}
|
var remainingContent *int32
|
||||||
if w.trafficState.StartTime.IsZero() {
|
var remainingPadding *int32
|
||||||
w.trafficState.StartTime = time.Now()
|
var currentCommand *int
|
||||||
}
|
var switchToDirectCopy *bool
|
||||||
w.trafficState.ByteReceived += int64(buffer.Len())
|
if w.isUplink {
|
||||||
|
withinPaddingBuffers = &w.trafficState.Inbound.WithinPaddingBuffers
|
||||||
var withinPaddingBuffers *bool
|
remainingContent = &w.trafficState.Inbound.RemainingContent
|
||||||
var remainingContent *int32
|
remainingPadding = &w.trafficState.Inbound.RemainingPadding
|
||||||
var remainingPadding *int32
|
currentCommand = &w.trafficState.Inbound.CurrentCommand
|
||||||
var currentCommand *int
|
switchToDirectCopy = &w.trafficState.Inbound.UplinkReaderDirectCopy
|
||||||
var switchToDirectCopy *bool
|
|
||||||
if w.isUplink {
|
|
||||||
withinPaddingBuffers = &w.trafficState.Inbound.WithinPaddingBuffers
|
|
||||||
remainingContent = &w.trafficState.Inbound.RemainingContent
|
|
||||||
remainingPadding = &w.trafficState.Inbound.RemainingPadding
|
|
||||||
currentCommand = &w.trafficState.Inbound.CurrentCommand
|
|
||||||
switchToDirectCopy = &w.trafficState.Inbound.UplinkReaderDirectCopy
|
|
||||||
} else {
|
|
||||||
withinPaddingBuffers = &w.trafficState.Outbound.WithinPaddingBuffers
|
|
||||||
remainingContent = &w.trafficState.Outbound.RemainingContent
|
|
||||||
remainingPadding = &w.trafficState.Outbound.RemainingPadding
|
|
||||||
currentCommand = &w.trafficState.Outbound.CurrentCommand
|
|
||||||
switchToDirectCopy = &w.trafficState.Outbound.DownlinkReaderDirectCopy
|
|
||||||
}
|
|
||||||
|
|
||||||
if *switchToDirectCopy {
|
|
||||||
if w.directReadCounter != nil {
|
|
||||||
w.directReadCounter.Add(int64(buffer.Len()))
|
|
||||||
}
|
|
||||||
return buffer, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if *withinPaddingBuffers || w.trafficState.NumberOfPacketReceived <= 8 || !ShouldStopSeed(w.addons, w.trafficState) {
|
|
||||||
mb2 := make(buf.MultiBuffer, 0, len(buffer))
|
|
||||||
for _, b := range buffer {
|
|
||||||
newbuffer := XtlsUnpadding(b, w.trafficState, w.isUplink, w.ctx)
|
|
||||||
if newbuffer.Len() > 0 {
|
|
||||||
mb2 = append(mb2, newbuffer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer = mb2
|
|
||||||
if *remainingContent > 0 || *remainingPadding > 0 || *currentCommand == 0 {
|
|
||||||
*withinPaddingBuffers = true
|
|
||||||
} else if *currentCommand == 1 {
|
|
||||||
*withinPaddingBuffers = false
|
|
||||||
} else if *currentCommand == 2 {
|
|
||||||
*withinPaddingBuffers = false
|
|
||||||
*switchToDirectCopy = true
|
|
||||||
} else {
|
} else {
|
||||||
errors.LogInfo(w.ctx, "XtlsRead unknown command ", *currentCommand, buffer.Len())
|
withinPaddingBuffers = &w.trafficState.Outbound.WithinPaddingBuffers
|
||||||
|
remainingContent = &w.trafficState.Outbound.RemainingContent
|
||||||
|
remainingPadding = &w.trafficState.Outbound.RemainingPadding
|
||||||
|
currentCommand = &w.trafficState.Outbound.CurrentCommand
|
||||||
|
switchToDirectCopy = &w.trafficState.Outbound.DownlinkReaderDirectCopy
|
||||||
}
|
}
|
||||||
}
|
|
||||||
w.trafficState.NumberOfPacketReceived += len(buffer)
|
|
||||||
if w.trafficState.NumberOfPacketToFilter > 0 {
|
|
||||||
XtlsFilterTls(buffer, w.trafficState, w.ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
if *switchToDirectCopy {
|
if *withinPaddingBuffers || w.trafficState.NumberOfPacketToFilter > 0 {
|
||||||
// XTLS Vision processes TLS-like conn's input and rawInput
|
mb2 := make(buf.MultiBuffer, 0, len(buffer))
|
||||||
if inputBuffer, err := buf.ReadFrom(w.input); err == nil && !inputBuffer.IsEmpty() {
|
for _, b := range buffer {
|
||||||
buffer, _ = buf.MergeMulti(buffer, inputBuffer)
|
newbuffer := XtlsUnpadding(b, w.trafficState, w.isUplink, w.ctx)
|
||||||
}
|
if newbuffer.Len() > 0 {
|
||||||
if rawInputBuffer, err := buf.ReadFrom(w.rawInput); err == nil && !rawInputBuffer.IsEmpty() {
|
mb2 = append(mb2, newbuffer)
|
||||||
buffer, _ = buf.MergeMulti(buffer, rawInputBuffer)
|
}
|
||||||
}
|
|
||||||
*w.input = bytes.Reader{} // release memory
|
|
||||||
w.input = nil
|
|
||||||
*w.rawInput = bytes.Buffer{} // release memory
|
|
||||||
w.rawInput = nil
|
|
||||||
|
|
||||||
if inbound := session.InboundFromContext(w.ctx); inbound != nil && inbound.Conn != nil {
|
|
||||||
if w.isUplink && inbound.CanSpliceCopy == 2 {
|
|
||||||
inbound.CanSpliceCopy = 1
|
|
||||||
}
|
}
|
||||||
if !w.isUplink && w.ob != nil && w.ob.CanSpliceCopy == 2 { // ob need to be passed in due to context can have more than one ob
|
buffer = mb2
|
||||||
w.ob.CanSpliceCopy = 1
|
if *remainingContent > 0 || *remainingPadding > 0 || *currentCommand == 0 {
|
||||||
|
*withinPaddingBuffers = true
|
||||||
|
} else if *currentCommand == 1 {
|
||||||
|
*withinPaddingBuffers = false
|
||||||
|
} else if *currentCommand == 2 {
|
||||||
|
*withinPaddingBuffers = false
|
||||||
|
*switchToDirectCopy = true
|
||||||
|
} else {
|
||||||
|
errors.LogInfo(w.ctx, "XtlsRead unknown command ", *currentCommand, buffer.Len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
readerConn, readCounter, _ := UnwrapRawConn(w.conn)
|
if w.trafficState.NumberOfPacketToFilter > 0 {
|
||||||
w.directReadCounter = readCounter
|
XtlsFilterTls(buffer, w.trafficState, w.ctx)
|
||||||
w.Reader = buf.NewReader(readerConn)
|
}
|
||||||
}
|
}
|
||||||
return buffer, err
|
return buffer, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisionWriter is used to write seed protocol
|
// VisionWriter is used to write xtls vision protocol
|
||||||
// Note Vision probably only make sense as the inner most layer of writer, since it need assess traffic state from origin proxy traffic
|
// Note Vision probably only make sense as the inner most layer of writer, since it need assess traffic state from origin proxy traffic
|
||||||
type VisionWriter struct {
|
type VisionWriter struct {
|
||||||
buf.Writer
|
buf.Writer
|
||||||
addons *Addons
|
trafficState *TrafficState
|
||||||
trafficState *TrafficState
|
ctx context.Context
|
||||||
ctx context.Context
|
writeOnceUserUUID []byte
|
||||||
isUplink bool
|
isUplink bool
|
||||||
conn net.Conn
|
|
||||||
ob *session.Outbound
|
|
||||||
|
|
||||||
// internal
|
|
||||||
writeOnceUserUUID *[]byte
|
|
||||||
directWriteCounter stats.Counter
|
|
||||||
scheduler *Scheduler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVisionWriter(writer buf.Writer, addon *Addons, trafficState *TrafficState, isUplink bool, ctx context.Context, conn net.Conn, ob *session.Outbound) *VisionWriter {
|
func NewVisionWriter(writer buf.Writer, state *TrafficState, isUplink bool, context context.Context) *VisionWriter {
|
||||||
w := make([]byte, len(trafficState.UserUUID))
|
w := make([]byte, len(state.UserUUID))
|
||||||
copy(w, trafficState.UserUUID)
|
copy(w, state.UserUUID)
|
||||||
return &VisionWriter{
|
return &VisionWriter{
|
||||||
Writer: writer,
|
Writer: writer,
|
||||||
addons: addon,
|
trafficState: state,
|
||||||
trafficState: trafficState,
|
ctx: context,
|
||||||
ctx: ctx,
|
writeOnceUserUUID: w,
|
||||||
writeOnceUserUUID: &w,
|
|
||||||
isUplink: isUplink,
|
isUplink: isUplink,
|
||||||
conn: conn,
|
|
||||||
ob: ob,
|
|
||||||
scheduler: NewScheduler(writer, addon, trafficState, &w, ctx),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||||
|
if w.trafficState.NumberOfPacketToFilter > 0 {
|
||||||
|
XtlsFilterTls(mb, w.trafficState, w.ctx)
|
||||||
|
}
|
||||||
var isPadding *bool
|
var isPadding *bool
|
||||||
var switchToDirectCopy *bool
|
var switchToDirectCopy *bool
|
||||||
if w.isUplink {
|
if w.isUplink {
|
||||||
@@ -347,82 +272,45 @@ func (w *VisionWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|||||||
isPadding = &w.trafficState.Inbound.IsPadding
|
isPadding = &w.trafficState.Inbound.IsPadding
|
||||||
switchToDirectCopy = &w.trafficState.Inbound.DownlinkWriterDirectCopy
|
switchToDirectCopy = &w.trafficState.Inbound.DownlinkWriterDirectCopy
|
||||||
}
|
}
|
||||||
|
if *isPadding {
|
||||||
if *switchToDirectCopy {
|
|
||||||
if inbound := session.InboundFromContext(w.ctx); inbound != nil {
|
|
||||||
if !w.isUplink && inbound.CanSpliceCopy == 2 {
|
|
||||||
inbound.CanSpliceCopy = 1
|
|
||||||
}
|
|
||||||
if w.isUplink && w.ob != nil && w.ob.CanSpliceCopy == 2 {
|
|
||||||
w.ob.CanSpliceCopy = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rawConn, _, writerCounter := UnwrapRawConn(w.conn)
|
|
||||||
w.Writer = buf.NewWriter(rawConn)
|
|
||||||
w.directWriteCounter = writerCounter
|
|
||||||
*switchToDirectCopy = false
|
|
||||||
}
|
|
||||||
if !mb.IsEmpty() && w.directWriteCounter != nil {
|
|
||||||
w.directWriteCounter.Add(int64(mb.Len()))
|
|
||||||
}
|
|
||||||
|
|
||||||
w.trafficState.NumberOfPacketSent += len(mb)
|
|
||||||
if w.trafficState.NumberOfPacketToFilter > 0 {
|
|
||||||
XtlsFilterTls(mb, w.trafficState, w.ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
if *isPadding && ShouldStartSeed(w.addons, w.trafficState) {
|
|
||||||
if len(mb) == 1 && mb[0] == nil {
|
if len(mb) == 1 && mb[0] == nil {
|
||||||
mb[0] = XtlsPadding(nil, CommandPaddingContinue, w.writeOnceUserUUID, true, w.addons, w.ctx) // we do a long padding to hide vless header
|
mb[0] = XtlsPadding(nil, CommandPaddingContinue, &w.writeOnceUserUUID, true, w.ctx) // we do a long padding to hide vless header
|
||||||
} else {
|
return w.Writer.WriteMultiBuffer(mb)
|
||||||
mb = ReshapeMultiBuffer(w.ctx, mb)
|
}
|
||||||
longPadding := w.trafficState.IsTLS
|
mb = ReshapeMultiBuffer(w.ctx, mb)
|
||||||
for i, b := range mb {
|
longPadding := w.trafficState.IsTLS
|
||||||
if w.trafficState.IsTLS && b.Len() >= 6 && bytes.Equal(TlsApplicationDataStart, b.BytesTo(3)) {
|
for i, b := range mb {
|
||||||
if w.trafficState.EnableXtls {
|
if w.trafficState.IsTLS && b.Len() >= 6 && bytes.Equal(TlsApplicationDataStart, b.BytesTo(3)) {
|
||||||
*switchToDirectCopy = true
|
if w.trafficState.EnableXtls {
|
||||||
}
|
*switchToDirectCopy = true
|
||||||
var command byte = CommandPaddingContinue
|
|
||||||
if i == len(mb) - 1 {
|
|
||||||
if w.trafficState.EnableXtls {
|
|
||||||
command = CommandPaddingDirect
|
|
||||||
*isPadding = false
|
|
||||||
} else if ShouldStopSeed(w.addons, w.trafficState) {
|
|
||||||
command = CommandPaddingEnd
|
|
||||||
*isPadding = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mb[i] = XtlsPadding(b, command, w.writeOnceUserUUID, true, w.addons, w.ctx)
|
|
||||||
longPadding = false
|
|
||||||
continue
|
|
||||||
} else if !w.trafficState.IsTLS12orAbove && ShouldStopSeed(w.addons, w.trafficState) {
|
|
||||||
*isPadding = false
|
|
||||||
mb[i] = XtlsPadding(b, CommandPaddingEnd, w.writeOnceUserUUID, longPadding, w.addons, w.ctx)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
var command byte = CommandPaddingContinue
|
var command byte = CommandPaddingContinue
|
||||||
if i == len(mb)-1 && !*isPadding {
|
if i == len(mb)-1 {
|
||||||
command = CommandPaddingEnd
|
command = CommandPaddingEnd
|
||||||
if w.trafficState.EnableXtls {
|
if w.trafficState.EnableXtls {
|
||||||
command = CommandPaddingDirect
|
command = CommandPaddingDirect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mb[i] = XtlsPadding(b, command, w.writeOnceUserUUID, longPadding, w.addons, w.ctx)
|
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, true, w.ctx)
|
||||||
|
*isPadding = false // padding going to end
|
||||||
|
longPadding = false
|
||||||
|
continue
|
||||||
|
} else if !w.trafficState.IsTLS12orAbove && w.trafficState.NumberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early
|
||||||
|
*isPadding = false
|
||||||
|
mb[i] = XtlsPadding(b, CommandPaddingEnd, &w.writeOnceUserUUID, longPadding, w.ctx)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
var command byte = CommandPaddingContinue
|
||||||
|
if i == len(mb)-1 && !*isPadding {
|
||||||
|
command = CommandPaddingEnd
|
||||||
|
if w.trafficState.EnableXtls {
|
||||||
|
command = CommandPaddingDirect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mb[i] = XtlsPadding(b, command, &w.writeOnceUserUUID, longPadding, w.ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.trafficState.ByteSent += int64(mb.Len())
|
return w.Writer.WriteMultiBuffer(mb)
|
||||||
if w.trafficState.StartTime.IsZero() {
|
|
||||||
w.trafficState.StartTime = time.Now()
|
|
||||||
}
|
|
||||||
w.scheduler.Buffer <- mb
|
|
||||||
if w.addons.Scheduler == nil {
|
|
||||||
w.scheduler.Trigger <- -1 // send all buffers
|
|
||||||
}
|
|
||||||
if len(w.scheduler.Error) > 0 {
|
|
||||||
return <-w.scheduler.Error
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReshapeMultiBuffer prepare multi buffer for padding structure (max 21 bytes)
|
// ReshapeMultiBuffer prepare multi buffer for padding structure (max 21 bytes)
|
||||||
@@ -461,24 +349,24 @@ func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// XtlsPadding add padding to eliminate length signature during tls handshake
|
// XtlsPadding add padding to eliminate length signature during tls handshake
|
||||||
func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, addons *Addons, ctx context.Context) *buf.Buffer {
|
func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, ctx context.Context) *buf.Buffer {
|
||||||
var contentLen int32 = 0
|
var contentLen int32 = 0
|
||||||
var paddingLen int32 = 0
|
var paddingLen int32 = 0
|
||||||
if b != nil {
|
if b != nil {
|
||||||
contentLen = b.Len()
|
contentLen = b.Len()
|
||||||
}
|
}
|
||||||
if contentLen < int32(addons.Padding.LongMin) && longPadding {
|
if contentLen < 900 && longPadding {
|
||||||
l, err := rand.Int(rand.Reader, big.NewInt(int64(addons.Padding.LongMax - addons.Padding.LongMin)))
|
l, err := rand.Int(rand.Reader, big.NewInt(500))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogDebugInner(ctx, err, "failed to generate padding")
|
errors.LogDebugInner(ctx, err, "failed to generate padding")
|
||||||
}
|
}
|
||||||
paddingLen = int32(l.Int64()) + int32(addons.Padding.LongMin) - contentLen
|
paddingLen = int32(l.Int64()) + 900 - contentLen
|
||||||
} else {
|
} else {
|
||||||
l, err := rand.Int(rand.Reader, big.NewInt(int64(addons.Padding.RegularMax - addons.Padding.RegularMin)))
|
l, err := rand.Int(rand.Reader, big.NewInt(256))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogDebugInner(ctx, err, "failed to generate padding")
|
errors.LogDebugInner(ctx, err, "failed to generate padding")
|
||||||
}
|
}
|
||||||
paddingLen = int32(l.Int64()) + int32(addons.Padding.RegularMin)
|
paddingLen = int32(l.Int64())
|
||||||
}
|
}
|
||||||
if paddingLen > buf.Size-21-contentLen {
|
if paddingLen > buf.Size-21-contentLen {
|
||||||
paddingLen = buf.Size - 21 - contentLen
|
paddingLen = buf.Size - 21 - contentLen
|
||||||
@@ -764,7 +652,7 @@ func readV(ctx context.Context, reader buf.Reader, writer buf.Writer, timer sign
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsRAWTransportWithoutSecurity(conn stat.Connection) bool {
|
func IsRAWTransport(conn stat.Connection) bool {
|
||||||
iConn := conn
|
iConn := conn
|
||||||
if statConn, ok := iConn.(*stat.CounterConnection); ok {
|
if statConn, ok := iConn.(*stat.CounterConnection); ok {
|
||||||
iConn = statConn.Connection
|
iConn = statConn.Connection
|
||||||
@@ -774,50 +662,3 @@ func IsRAWTransportWithoutSecurity(conn stat.Connection) bool {
|
|||||||
_, ok3 := iConn.(*internet.UnixConnWrapper)
|
_, ok3 := iConn.(*internet.UnixConnWrapper)
|
||||||
return ok1 || ok2 || ok3
|
return ok1 || ok2 || ok3
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShouldStartSeed(addons *Addons, trafficState *TrafficState) bool {
|
|
||||||
if len(addons.Duration) == 0 || len(strings.Split(addons.Duration, "-")) < 2 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
start := strings.ToLower(strings.Split(addons.Duration, "-")[0])
|
|
||||||
if len(start) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if strings.Contains(start, "b") {
|
|
||||||
start = strings.TrimRight(start, "b")
|
|
||||||
i, err := strconv.Atoi(start)
|
|
||||||
if err == nil && i <= int(trafficState.ByteSent + trafficState.ByteSent) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
i, err := strconv.Atoi(start)
|
|
||||||
if err == nil && i <= trafficState.NumberOfPacketSent + trafficState.NumberOfPacketReceived {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func ShouldStopSeed(addons *Addons, trafficState *TrafficState) bool {
|
|
||||||
if len(addons.Duration) == 0 || len(strings.Split(addons.Duration, "-")) < 2 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
start := strings.ToLower(strings.Split(addons.Duration, "-")[1])
|
|
||||||
if len(start) == 0 { // infinite
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if strings.Contains(start, "b") {
|
|
||||||
start = strings.TrimRight(start, "b")
|
|
||||||
i, err := strconv.Atoi(start)
|
|
||||||
if err == nil && i > int(trafficState.ByteSent + trafficState.ByteSent) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
i, err := strconv.Atoi(start)
|
|
||||||
if err == nil && i > trafficState.NumberOfPacketSent + trafficState.NumberOfPacketReceived {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
package proxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/rand"
|
|
||||||
"math/big"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/buf"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Scheduler struct {
|
|
||||||
Buffer chan buf.MultiBuffer
|
|
||||||
Trigger chan int
|
|
||||||
Error chan error
|
|
||||||
closed chan int
|
|
||||||
bufferReadLock *sync.Mutex
|
|
||||||
writer buf.Writer
|
|
||||||
addons *Addons
|
|
||||||
trafficState *TrafficState
|
|
||||||
writeOnceUserUUID *[]byte
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewScheduler(w buf.Writer, addon *Addons, state *TrafficState, userUUID *[]byte, context context.Context) *Scheduler {
|
|
||||||
var s = Scheduler{
|
|
||||||
Buffer: make(chan buf.MultiBuffer, 100),
|
|
||||||
Trigger: make(chan int),
|
|
||||||
Error: make(chan error, 100),
|
|
||||||
closed: make(chan int),
|
|
||||||
bufferReadLock: new(sync.Mutex),
|
|
||||||
writer: w,
|
|
||||||
addons: addon,
|
|
||||||
trafficState: state,
|
|
||||||
writeOnceUserUUID: userUUID,
|
|
||||||
ctx: context,
|
|
||||||
}
|
|
||||||
go s.mainLoop()
|
|
||||||
if s.addons.Scheduler != nil {
|
|
||||||
go s.exampleIndependentScheduler()
|
|
||||||
}
|
|
||||||
return &s
|
|
||||||
}
|
|
||||||
|
|
||||||
func(s *Scheduler) mainLoop() {
|
|
||||||
for trigger := range s.Trigger {
|
|
||||||
if len(s.closed) > 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go func() { // each trigger has independent delay, trigger does not block
|
|
||||||
var d = 0 * time.Millisecond
|
|
||||||
if s.addons.Delay != nil {
|
|
||||||
l, err := rand.Int(rand.Reader, big.NewInt(int64(s.addons.Delay.MaxMillis - s.addons.Delay.MinMillis)))
|
|
||||||
if err != nil {
|
|
||||||
errors.LogWarningInner(s.ctx, err, "failed to generate delay", trigger)
|
|
||||||
}
|
|
||||||
d = time.Duration(uint32(l.Int64()) + s.addons.Delay.MinMillis) * time.Millisecond
|
|
||||||
time.Sleep(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.bufferReadLock.Lock() // guard against multiple trigger threads
|
|
||||||
var sending = len(s.Buffer)
|
|
||||||
if sending > 0 {
|
|
||||||
errors.LogDebug(s.ctx, "Scheduler Trigger for ", sending, " buffer(s) with ", d, " ", trigger)
|
|
||||||
for i := 0; i<sending; i++ {
|
|
||||||
err := s.writer.WriteMultiBuffer(<-s.Buffer)
|
|
||||||
if err != nil {
|
|
||||||
s.Error <- err
|
|
||||||
s.closed <- 1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if trigger > 0 && (s.trafficState.Inbound.IsPadding || s.trafficState.Outbound.IsPadding) && ShouldStartSeed(s.addons, s.trafficState) && !ShouldStopSeed(s.addons, s.trafficState) {
|
|
||||||
errors.LogDebug(s.ctx, "Scheduler Trigger for fake buffer with ", d, " ", trigger)
|
|
||||||
s.trafficState.NumberOfPacketSent += 1
|
|
||||||
mb := make(buf.MultiBuffer, 1)
|
|
||||||
mb[0] = XtlsPadding(nil, CommandPaddingContinue, s.writeOnceUserUUID, true, s.addons, s.ctx)
|
|
||||||
s.trafficState.ByteSent += int64(mb.Len())
|
|
||||||
if s.trafficState.StartTime.IsZero() {
|
|
||||||
s.trafficState.StartTime = time.Now()
|
|
||||||
}
|
|
||||||
err := s.writer.WriteMultiBuffer(mb)
|
|
||||||
if err != nil {
|
|
||||||
s.Error <- err
|
|
||||||
s.closed <- 1
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if buffered, ok := s.writer.(*buf.BufferedWriter); ok {
|
|
||||||
buffered.SetBuffered(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.bufferReadLock.Unlock()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func(s *Scheduler) exampleIndependentScheduler() {
|
|
||||||
for {
|
|
||||||
if len(s.closed) > 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.Trigger <- 1 // send fake buffer if no pending
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -75,7 +75,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
|||||||
inbound.User = &protocol.MemoryUser{
|
inbound.User = &protocol.MemoryUser{
|
||||||
Level: s.config.UserLevel,
|
Level: s.config.UserLevel,
|
||||||
}
|
}
|
||||||
if !proxy.IsRAWTransportWithoutSecurity(conn) {
|
if !proxy.IsRAWTransport(conn) {
|
||||||
inbound.CanSpliceCopy = 3
|
inbound.CanSpliceCopy = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ func (s *Server) processTCP(ctx context.Context, conn stat.Connection, dispatche
|
|||||||
inbound.CanSpliceCopy = 1
|
inbound.CanSpliceCopy = 1
|
||||||
}
|
}
|
||||||
if err := dispatcher.DispatchLink(ctx, dest, &transport.Link{
|
if err := dispatcher.DispatchLink(ctx, dest, &transport.Link{
|
||||||
Reader: reader,
|
Reader: &buf.TimeoutWrapperReader{Reader: reader},
|
||||||
Writer: buf.NewWriter(conn)},
|
Writer: buf.NewWriter(conn)},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return errors.New("failed to dispatch request").Base(err)
|
return errors.New("failed to dispatch request").Base(err)
|
||||||
|
|||||||
@@ -253,6 +253,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, sessionPolicy policy.Sess
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
|
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
|
||||||
defer timer.SetTimeout(0)
|
defer timer.SetTimeout(0)
|
||||||
|
ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
|
||||||
udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {
|
udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {
|
||||||
udpPayload := packet.Payload
|
udpPayload := packet.Payload
|
||||||
if udpPayload.UDP == nil {
|
if udpPayload.UDP == nil {
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ func (a *Account) AsAccount() (protocol.Account, error) {
|
|||||||
Encryption: a.Encryption, // needs parser here?
|
Encryption: a.Encryption, // needs parser here?
|
||||||
XorMode: a.XorMode,
|
XorMode: a.XorMode,
|
||||||
Seconds: a.Seconds,
|
Seconds: a.Seconds,
|
||||||
Padding: a.Padding,
|
|
||||||
Seed: a.Seed,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,9 +33,6 @@ type MemoryAccount struct {
|
|||||||
Encryption string
|
Encryption string
|
||||||
XorMode uint32
|
XorMode uint32
|
||||||
Seconds uint32
|
Seconds uint32
|
||||||
Padding string
|
|
||||||
// Seed. Details TBD
|
|
||||||
Seed string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equals implements protocol.Account.Equals().
|
// Equals implements protocol.Account.Equals().
|
||||||
@@ -56,6 +51,5 @@ func (a *MemoryAccount) ToProto() proto.Message {
|
|||||||
Encryption: a.Encryption,
|
Encryption: a.Encryption,
|
||||||
XorMode: a.XorMode,
|
XorMode: a.XorMode,
|
||||||
Seconds: a.Seconds,
|
Seconds: a.Seconds,
|
||||||
Padding: a.Padding,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-39
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.8
|
// protoc-gen-go v1.35.1
|
||||||
// protoc v5.28.2
|
// protoc v5.28.2
|
||||||
// source: proxy/vless/account.proto
|
// source: proxy/vless/account.proto
|
||||||
|
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -22,7 +21,10 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
|
// ID of the account, in the form of a UUID, e.g., "66ad4540-b58c-4ad2-9926-ea63445a9b57".
|
||||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
// Flow settings. May be "xtls-rprx-vision".
|
// Flow settings. May be "xtls-rprx-vision".
|
||||||
@@ -30,11 +32,6 @@ type Account struct {
|
|||||||
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`
|
Encryption string `protobuf:"bytes,3,opt,name=encryption,proto3" json:"encryption,omitempty"`
|
||||||
XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"`
|
XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"`
|
||||||
Seconds uint32 `protobuf:"varint,5,opt,name=seconds,proto3" json:"seconds,omitempty"`
|
Seconds uint32 `protobuf:"varint,5,opt,name=seconds,proto3" json:"seconds,omitempty"`
|
||||||
Padding string `protobuf:"bytes,6,opt,name=padding,proto3" json:"padding,omitempty"`
|
|
||||||
// Seed settings. Details TBD
|
|
||||||
Seed string `protobuf:"bytes,7,opt,name=seed,proto3" json:"seed,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Account) Reset() {
|
func (x *Account) Reset() {
|
||||||
@@ -102,45 +99,36 @@ func (x *Account) GetSeconds() uint32 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Account) GetPadding() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Padding
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Account) GetSeed() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Seed
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_proxy_vless_account_proto protoreflect.FileDescriptor
|
var File_proxy_vless_account_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_proxy_vless_account_proto_rawDesc = "" +
|
var file_proxy_vless_account_proto_rawDesc = []byte{
|
||||||
"\n" +
|
0x0a, 0x19, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x61, 0x63,
|
||||||
"\x19proxy/vless/account.proto\x12\x10xray.proxy.vless\"\xaf\x01\n" +
|
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x78, 0x72, 0x61,
|
||||||
"\aAccount\x12\x0e\n" +
|
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x22, 0x81, 0x01,
|
||||||
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
|
0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
|
||||||
"\x04flow\x18\x02 \x01(\tR\x04flow\x12\x1e\n" +
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x6c, 0x6f,
|
||||||
"\n" +
|
0x77, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1e, 0x0a,
|
||||||
"encryption\x18\x03 \x01(\tR\n" +
|
0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||||
"encryption\x12\x18\n" +
|
0x09, 0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a,
|
||||||
"\axorMode\x18\x04 \x01(\rR\axorMode\x12\x18\n" +
|
0x07, 0x78, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07,
|
||||||
"\aseconds\x18\x05 \x01(\rR\aseconds\x12\x18\n" +
|
0x78, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e,
|
||||||
"\apadding\x18\x06 \x01(\tR\apadding\x12\x12\n" +
|
0x64, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64,
|
||||||
"\x04seed\x18\a \x01(\tR\x04seedBR\n" +
|
0x73, 0x42, 0x52, 0x0a, 0x14, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72,
|
||||||
"\x14com.xray.proxy.vlessP\x01Z%github.com/xtls/xray-core/proxy/vless\xaa\x02\x10Xray.Proxy.Vlessb\x06proto3"
|
0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x50, 0x01, 0x5a, 0x25, 0x67, 0x69, 0x74,
|
||||||
|
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61,
|
||||||
|
0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65,
|
||||||
|
0x73, 0x73, 0xaa, 0x02, 0x10, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e,
|
||||||
|
0x56, 0x6c, 0x65, 0x73, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_proxy_vless_account_proto_rawDescOnce sync.Once
|
file_proxy_vless_account_proto_rawDescOnce sync.Once
|
||||||
file_proxy_vless_account_proto_rawDescData []byte
|
file_proxy_vless_account_proto_rawDescData = file_proxy_vless_account_proto_rawDesc
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_proxy_vless_account_proto_rawDescGZIP() []byte {
|
func file_proxy_vless_account_proto_rawDescGZIP() []byte {
|
||||||
file_proxy_vless_account_proto_rawDescOnce.Do(func() {
|
file_proxy_vless_account_proto_rawDescOnce.Do(func() {
|
||||||
file_proxy_vless_account_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proxy_vless_account_proto_rawDesc), len(file_proxy_vless_account_proto_rawDesc)))
|
file_proxy_vless_account_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_vless_account_proto_rawDescData)
|
||||||
})
|
})
|
||||||
return file_proxy_vless_account_proto_rawDescData
|
return file_proxy_vless_account_proto_rawDescData
|
||||||
}
|
}
|
||||||
@@ -166,7 +154,7 @@ func file_proxy_vless_account_proto_init() {
|
|||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proxy_vless_account_proto_rawDesc), len(file_proxy_vless_account_proto_rawDesc)),
|
RawDescriptor: file_proxy_vless_account_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 1,
|
NumMessages: 1,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
@@ -177,6 +165,7 @@ func file_proxy_vless_account_proto_init() {
|
|||||||
MessageInfos: file_proxy_vless_account_proto_msgTypes,
|
MessageInfos: file_proxy_vless_account_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_proxy_vless_account_proto = out.File
|
File_proxy_vless_account_proto = out.File
|
||||||
|
file_proxy_vless_account_proto_rawDesc = nil
|
||||||
file_proxy_vless_account_proto_goTypes = nil
|
file_proxy_vless_account_proto_goTypes = nil
|
||||||
file_proxy_vless_account_proto_depIdxs = nil
|
file_proxy_vless_account_proto_depIdxs = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,4 @@ message Account {
|
|||||||
string encryption = 3;
|
string encryption = 3;
|
||||||
uint32 xorMode = 4;
|
uint32 xorMode = 4;
|
||||||
uint32 seconds = 5;
|
uint32 seconds = 5;
|
||||||
string padding = 6;
|
|
||||||
// Seed settings. Details TBD
|
|
||||||
string seed = 7;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
package encoding
|
package encoding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"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/session"
|
|
||||||
"github.com/xtls/xray-core/proxy"
|
"github.com/xtls/xray-core/proxy"
|
||||||
"github.com/xtls/xray-core/proxy/vless"
|
"github.com/xtls/xray-core/proxy/vless"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func EncodeHeaderAddons(buffer *buf.Buffer, addons *proxy.Addons) error {
|
func EncodeHeaderAddons(buffer *buf.Buffer, addons *Addons) error {
|
||||||
if addons.Flow == vless.XRV || len(addons.Seed) > 0 {
|
switch addons.Flow {
|
||||||
|
case vless.XRV:
|
||||||
bytes, err := proto.Marshal(addons)
|
bytes, err := proto.Marshal(addons)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to marshal addons protobuf value").Base(err)
|
return errors.New("failed to marshal addons protobuf value").Base(err)
|
||||||
@@ -27,16 +25,17 @@ func EncodeHeaderAddons(buffer *buf.Buffer, addons *proxy.Addons) error {
|
|||||||
if _, err := buffer.Write(bytes); err != nil {
|
if _, err := buffer.Write(bytes); err != nil {
|
||||||
return errors.New("failed to write addons protobuf value").Base(err)
|
return errors.New("failed to write addons protobuf value").Base(err)
|
||||||
}
|
}
|
||||||
} else {
|
default:
|
||||||
if err := buffer.WriteByte(0); err != nil {
|
if err := buffer.WriteByte(0); err != nil {
|
||||||
return errors.New("failed to write addons protobuf length").Base(err)
|
return errors.New("failed to write addons protobuf length").Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*proxy.Addons, error) {
|
func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*Addons, error) {
|
||||||
addons := new(proxy.Addons)
|
addons := new(Addons)
|
||||||
buffer.Clear()
|
buffer.Clear()
|
||||||
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
|
if _, err := buffer.ReadFullFrom(reader, 1); err != nil {
|
||||||
return nil, errors.New("failed to read addons protobuf length").Base(err)
|
return nil, errors.New("failed to read addons protobuf length").Base(err)
|
||||||
@@ -51,27 +50,37 @@ func DecodeHeaderAddons(buffer *buf.Buffer, reader io.Reader) (*proxy.Addons, er
|
|||||||
if err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {
|
if err := proto.Unmarshal(buffer.Bytes(), addons); err != nil {
|
||||||
return nil, errors.New("failed to unmarshal addons protobuf value").Base(err)
|
return nil, errors.New("failed to unmarshal addons protobuf value").Base(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verification.
|
||||||
|
switch addons.Flow {
|
||||||
|
default:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return addons, nil
|
return addons, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
|
// EncodeBodyAddons returns a Writer that auto-encrypt content written by caller.
|
||||||
func EncodeBodyAddons(writer buf.Writer, request *protocol.RequestHeader, addons *proxy.Addons, state *proxy.TrafficState, isUplink bool, context context.Context, conn net.Conn, ob *session.Outbound) buf.Writer {
|
func EncodeBodyAddons(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons, state *proxy.TrafficState, isUplink bool, context context.Context) buf.Writer {
|
||||||
w := proxy.NewVisionWriter(writer, addons, state, isUplink, context, conn, ob)
|
|
||||||
if request.Command == protocol.RequestCommandUDP {
|
if request.Command == protocol.RequestCommandUDP {
|
||||||
return NewMultiLengthPacketWriter(w)
|
return NewMultiLengthPacketWriter(writer.(buf.Writer))
|
||||||
}
|
}
|
||||||
return writer
|
w := buf.NewWriter(writer)
|
||||||
|
if requestAddons.Flow == vless.XRV {
|
||||||
|
w = proxy.NewVisionWriter(w, state, isUplink, context)
|
||||||
|
}
|
||||||
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.
|
// DecodeBodyAddons returns a Reader from which caller can fetch decrypted body.
|
||||||
func DecodeBodyAddons(reader io.Reader, request *protocol.RequestHeader, addons *proxy.Addons, state *proxy.TrafficState, isUplink bool, context context.Context, conn net.Conn, input *bytes.Reader, rawInput *bytes.Buffer, ob *session.Outbound) buf.Reader {
|
func DecodeBodyAddons(reader io.Reader, request *protocol.RequestHeader, addons *Addons) buf.Reader {
|
||||||
r := proxy.NewVisionReader(buf.NewReader(reader), addons, state, isUplink, context, conn, input, rawInput, ob)
|
switch addons.Flow {
|
||||||
if request.Command == protocol.RequestCommandUDP {
|
default:
|
||||||
return NewLengthPacketReader(&buf.BufferedReader{Reader: r})
|
if request.Command == protocol.RequestCommandUDP {
|
||||||
|
return NewLengthPacketReader(reader)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return r
|
return buf.NewReader(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMultiLengthPacketWriter(writer buf.Writer) *MultiLengthPacketWriter {
|
func NewMultiLengthPacketWriter(writer buf.Writer) *MultiLengthPacketWriter {
|
||||||
@@ -179,78 +188,3 @@ func (r *LengthPacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
}
|
}
|
||||||
return mb, nil
|
return mb, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PopulateSeed(seed string, addons *proxy.Addons) {
|
|
||||||
if len(seed) > 0 {
|
|
||||||
addons.Seed = []byte {1} // only turn on, more TBD
|
|
||||||
addons.Mode = proxy.SeedMode_PaddingPlusDelay
|
|
||||||
addons.Duration = "0-8"
|
|
||||||
addons.Padding = &proxy.PaddingConfig{
|
|
||||||
RegularMin: 0,
|
|
||||||
RegularMax: 256,
|
|
||||||
LongMin: 900,
|
|
||||||
LongMax: 1400,
|
|
||||||
}
|
|
||||||
// addons.Delay = &proxy.DelayConfig{
|
|
||||||
// IsRandom: true,
|
|
||||||
// MinMillis: 100,
|
|
||||||
// MaxMillis: 500,
|
|
||||||
// }
|
|
||||||
addons.Scheduler = &proxy.SchedulerConfig{
|
|
||||||
TimeoutMillis: 600,
|
|
||||||
}
|
|
||||||
} else if addons.Flow == vless.XRV {
|
|
||||||
addons.Seed = []byte {1} // only turn on, more TBD
|
|
||||||
addons.Mode = proxy.SeedMode_PaddingOnly
|
|
||||||
addons.Duration = "0-8"
|
|
||||||
addons.Padding = &proxy.PaddingConfig{
|
|
||||||
RegularMin: 0,
|
|
||||||
RegularMax: 256,
|
|
||||||
LongMin: 900,
|
|
||||||
LongMax: 1400,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckSeed(requestAddons *proxy.Addons, responseAddons *proxy.Addons) error {
|
|
||||||
if !bytes.Equal(requestAddons.Seed, responseAddons.Seed) {
|
|
||||||
return errors.New("Seed bytes not match", requestAddons.Seed, responseAddons.Seed)
|
|
||||||
}
|
|
||||||
if responseAddons.Flow == vless.XRV && len(responseAddons.Seed) == 0 && requestAddons.Mode == proxy.SeedMode_Unknown {
|
|
||||||
// old vision server config allow empty seed from clients for backwards compatibility
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if requestAddons.Mode != responseAddons.Mode {
|
|
||||||
return errors.New("Mode not match", requestAddons.Mode, responseAddons.Mode)
|
|
||||||
}
|
|
||||||
if requestAddons.Duration != responseAddons.Duration {
|
|
||||||
return errors.New("Duration not match", requestAddons.Duration, responseAddons.Duration)
|
|
||||||
}
|
|
||||||
if requestAddons.Padding != nil && responseAddons.Padding != nil {
|
|
||||||
if requestAddons.Padding.RegularMin != responseAddons.Padding.RegularMin ||
|
|
||||||
requestAddons.Padding.RegularMax != responseAddons.Padding.RegularMax ||
|
|
||||||
requestAddons.Padding.LongMin != responseAddons.Padding.LongMin ||
|
|
||||||
requestAddons.Padding.LongMax != responseAddons.Padding.LongMax {
|
|
||||||
return errors.New("Padding not match")
|
|
||||||
}
|
|
||||||
} else if requestAddons.Padding != nil || responseAddons.Padding != nil {
|
|
||||||
return errors.New("Padding of one is nil but the other is not nil")
|
|
||||||
}
|
|
||||||
if requestAddons.Delay != nil && responseAddons.Delay != nil {
|
|
||||||
if requestAddons.Delay.IsRandom != responseAddons.Delay.IsRandom ||
|
|
||||||
requestAddons.Delay.MinMillis != responseAddons.Delay.MinMillis ||
|
|
||||||
requestAddons.Delay.MaxMillis != responseAddons.Delay.MaxMillis {
|
|
||||||
return errors.New("Delay not match")
|
|
||||||
}
|
|
||||||
} else if requestAddons.Delay != nil || responseAddons.Delay != nil {
|
|
||||||
return errors.New("Delay of one is nil but the other is not nil")
|
|
||||||
}
|
|
||||||
if requestAddons.Scheduler != nil && responseAddons.Scheduler != nil {
|
|
||||||
if requestAddons.Scheduler.TimeoutMillis != responseAddons.Scheduler.TimeoutMillis {
|
|
||||||
return errors.New("Scheduler not match")
|
|
||||||
}
|
|
||||||
} else if requestAddons.Scheduler != nil || responseAddons.Scheduler != nil {
|
|
||||||
return errors.New("Scheduler of one is nil but the other is not nil")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -20,70 +20,13 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
type SeedMode int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
SeedMode_Unknown SeedMode = 0
|
|
||||||
SeedMode_PaddingOnly SeedMode = 1
|
|
||||||
SeedMode_PaddingPlusDelay SeedMode = 2
|
|
||||||
SeedMode_IndependentScheduler SeedMode = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
// Enum value maps for SeedMode.
|
|
||||||
var (
|
|
||||||
SeedMode_name = map[int32]string{
|
|
||||||
0: "Unknown",
|
|
||||||
1: "PaddingOnly",
|
|
||||||
2: "PaddingPlusDelay",
|
|
||||||
3: "IndependentScheduler",
|
|
||||||
}
|
|
||||||
SeedMode_value = map[string]int32{
|
|
||||||
"Unknown": 0,
|
|
||||||
"PaddingOnly": 1,
|
|
||||||
"PaddingPlusDelay": 2,
|
|
||||||
"IndependentScheduler": 3,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (x SeedMode) Enum() *SeedMode {
|
|
||||||
p := new(SeedMode)
|
|
||||||
*p = x
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x SeedMode) String() string {
|
|
||||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (SeedMode) Descriptor() protoreflect.EnumDescriptor {
|
|
||||||
return file_proxy_vless_encoding_addons_proto_enumTypes[0].Descriptor()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (SeedMode) Type() protoreflect.EnumType {
|
|
||||||
return &file_proxy_vless_encoding_addons_proto_enumTypes[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x SeedMode) Number() protoreflect.EnumNumber {
|
|
||||||
return protoreflect.EnumNumber(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use SeedMode.Descriptor instead.
|
|
||||||
func (SeedMode) EnumDescriptor() ([]byte, []int) {
|
|
||||||
return file_proxy_vless_encoding_addons_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Addons struct {
|
type Addons struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Flow string `protobuf:"bytes,1,opt,name=Flow,proto3" json:"Flow,omitempty"`
|
Flow string `protobuf:"bytes,1,opt,name=Flow,proto3" json:"Flow,omitempty"`
|
||||||
Seed []byte `protobuf:"bytes,2,opt,name=Seed,proto3" json:"Seed,omitempty"`
|
Seed []byte `protobuf:"bytes,2,opt,name=Seed,proto3" json:"Seed,omitempty"`
|
||||||
Mode SeedMode `protobuf:"varint,3,opt,name=Mode,proto3,enum=xray.proxy.vless.encoding.SeedMode" json:"Mode,omitempty"`
|
|
||||||
Duration string `protobuf:"bytes,4,opt,name=Duration,proto3" json:"Duration,omitempty"` // "0-8" means apply to number of packets, "1kb-" means start applying once both side exchange 1kb data, counting two-ways
|
|
||||||
Padding *PaddingConfig `protobuf:"bytes,5,opt,name=Padding,proto3" json:"Padding,omitempty"`
|
|
||||||
Delay *DelayConfig `protobuf:"bytes,6,opt,name=Delay,proto3" json:"Delay,omitempty"`
|
|
||||||
Scheduler *SchedulerConfig `protobuf:"bytes,7,opt,name=Scheduler,proto3" json:"Scheduler,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Addons) Reset() {
|
func (x *Addons) Reset() {
|
||||||
@@ -130,282 +73,24 @@ func (x *Addons) GetSeed() []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Addons) GetMode() SeedMode {
|
|
||||||
if x != nil {
|
|
||||||
return x.Mode
|
|
||||||
}
|
|
||||||
return SeedMode_Unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) GetDuration() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Duration
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) GetPadding() *PaddingConfig {
|
|
||||||
if x != nil {
|
|
||||||
return x.Padding
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) GetDelay() *DelayConfig {
|
|
||||||
if x != nil {
|
|
||||||
return x.Delay
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Addons) GetScheduler() *SchedulerConfig {
|
|
||||||
if x != nil {
|
|
||||||
return x.Scheduler
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type PaddingConfig struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
RegularMin uint32 `protobuf:"varint,1,opt,name=RegularMin,proto3" json:"RegularMin,omitempty"`
|
|
||||||
RegularMax uint32 `protobuf:"varint,2,opt,name=RegularMax,proto3" json:"RegularMax,omitempty"`
|
|
||||||
LongMin uint32 `protobuf:"varint,3,opt,name=LongMin,proto3" json:"LongMin,omitempty"`
|
|
||||||
LongMax uint32 `protobuf:"varint,4,opt,name=LongMax,proto3" json:"LongMax,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) Reset() {
|
|
||||||
*x = PaddingConfig{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*PaddingConfig) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[1]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use PaddingConfig.ProtoReflect.Descriptor instead.
|
|
||||||
func (*PaddingConfig) Descriptor() ([]byte, []int) {
|
|
||||||
return file_proxy_vless_encoding_addons_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) GetRegularMin() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.RegularMin
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) GetRegularMax() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.RegularMax
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) GetLongMin() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.LongMin
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PaddingConfig) GetLongMax() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.LongMax
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type DelayConfig struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
IsRandom bool `protobuf:"varint,1,opt,name=IsRandom,proto3" json:"IsRandom,omitempty"`
|
|
||||||
MinMillis uint32 `protobuf:"varint,2,opt,name=MinMillis,proto3" json:"MinMillis,omitempty"`
|
|
||||||
MaxMillis uint32 `protobuf:"varint,3,opt,name=MaxMillis,proto3" json:"MaxMillis,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DelayConfig) Reset() {
|
|
||||||
*x = DelayConfig{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[2]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DelayConfig) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*DelayConfig) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *DelayConfig) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[2]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use DelayConfig.ProtoReflect.Descriptor instead.
|
|
||||||
func (*DelayConfig) Descriptor() ([]byte, []int) {
|
|
||||||
return file_proxy_vless_encoding_addons_proto_rawDescGZIP(), []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DelayConfig) GetIsRandom() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.IsRandom
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DelayConfig) GetMinMillis() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.MinMillis
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *DelayConfig) GetMaxMillis() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.MaxMillis
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type SchedulerConfig struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
TimeoutMillis uint32 `protobuf:"varint,1,opt,name=TimeoutMillis,proto3" json:"TimeoutMillis,omitempty"` // original traffic will not be sent right away but when scheduler want to send or pending buffer times out
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SchedulerConfig) Reset() {
|
|
||||||
*x = SchedulerConfig{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[3]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SchedulerConfig) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*SchedulerConfig) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *SchedulerConfig) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_proxy_vless_encoding_addons_proto_msgTypes[3]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use SchedulerConfig.ProtoReflect.Descriptor instead.
|
|
||||||
func (*SchedulerConfig) Descriptor() ([]byte, []int) {
|
|
||||||
return file_proxy_vless_encoding_addons_proto_rawDescGZIP(), []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SchedulerConfig) GetTimeoutMillis() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.TimeoutMillis
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_proxy_vless_encoding_addons_proto protoreflect.FileDescriptor
|
var File_proxy_vless_encoding_addons_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_proxy_vless_encoding_addons_proto_rawDesc = []byte{
|
var file_proxy_vless_encoding_addons_proto_rawDesc = []byte{
|
||||||
0x0a, 0x21, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x65, 0x6e,
|
0x0a, 0x21, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x65, 0x6e,
|
||||||
0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72,
|
0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2f, 0x61, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72,
|
||||||
0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
|
0x6f, 0x74, 0x6f, 0x12, 0x19, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e,
|
||||||
0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xd1,
|
0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x30,
|
||||||
0x02, 0x0a, 0x06, 0x41, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x46, 0x6c, 0x6f,
|
0x0a, 0x06, 0x41, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x46, 0x6c, 0x6f, 0x77,
|
||||||
0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x12, 0x0a,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x12, 0x0a, 0x04,
|
||||||
0x04, 0x53, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x53, 0x65, 0x65,
|
0x53, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x53, 0x65, 0x65, 0x64,
|
||||||
0x64, 0x12, 0x37, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
|
||||||
0x23, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65,
|
0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e,
|
||||||
0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x65, 0x65, 0x64,
|
0x67, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
||||||
0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x75,
|
0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70,
|
||||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x44, 0x75,
|
0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x65, 0x6e, 0x63, 0x6f, 0x64,
|
||||||
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x07, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e,
|
0x69, 0x6e, 0x67, 0xaa, 0x02, 0x19, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79,
|
||||||
0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70,
|
0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x62,
|
||||||
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64,
|
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
|
||||||
0x67, 0x52, 0x07, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x3c, 0x0a, 0x05, 0x44, 0x65,
|
|
||||||
0x6c, 0x61, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
|
||||||
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63,
|
|
||||||
0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
|
||||||
0x67, 0x52, 0x05, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x48, 0x0a, 0x09, 0x53, 0x63, 0x68, 0x65,
|
|
||||||
0x64, 0x75, 0x6c, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x78, 0x72,
|
|
||||||
0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65,
|
|
||||||
0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
|
|
||||||
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
|
|
||||||
0x65, 0x72, 0x22, 0x83, 0x01, 0x0a, 0x0d, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f,
|
|
||||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d,
|
|
||||||
0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61,
|
|
||||||
0x72, 0x4d, 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x4d,
|
|
||||||
0x61, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61,
|
|
||||||
0x72, 0x4d, 0x61, 0x78, 0x12, 0x18, 0x0a, 0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x69, 0x6e, 0x18,
|
|
||||||
0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x69, 0x6e, 0x12, 0x18,
|
|
||||||
0x0a, 0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x61, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52,
|
|
||||||
0x07, 0x4c, 0x6f, 0x6e, 0x67, 0x4d, 0x61, 0x78, 0x22, 0x65, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x61,
|
|
||||||
0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x73, 0x52, 0x61, 0x6e,
|
|
||||||
0x64, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x49, 0x73, 0x52, 0x61, 0x6e,
|
|
||||||
0x64, 0x6f, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x69, 0x6e, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73,
|
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4d, 0x69, 0x6e, 0x4d, 0x69, 0x6c, 0x6c, 0x69,
|
|
||||||
0x73, 0x12, 0x1c, 0x0a, 0x09, 0x4d, 0x61, 0x78, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x03,
|
|
||||||
0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x4d, 0x61, 0x78, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x22,
|
|
||||||
0x37, 0x0a, 0x0f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
|
|
||||||
0x69, 0x67, 0x12, 0x24, 0x0a, 0x0d, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4d, 0x69, 0x6c,
|
|
||||||
0x6c, 0x69, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x54, 0x69, 0x6d, 0x65, 0x6f,
|
|
||||||
0x75, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x2a, 0x58, 0x0a, 0x08, 0x53, 0x65, 0x65, 0x64,
|
|
||||||
0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10,
|
|
||||||
0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x4f, 0x6e, 0x6c, 0x79,
|
|
||||||
0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x6c, 0x75,
|
|
||||||
0x73, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x49, 0x6e, 0x64, 0x65,
|
|
||||||
0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72,
|
|
||||||
0x10, 0x03, 0x42, 0x6d, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70,
|
|
||||||
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x65, 0x6e, 0x63, 0x6f, 0x64,
|
|
||||||
0x69, 0x6e, 0x67, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
|
||||||
0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
|
|
||||||
0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x65, 0x6e, 0x63,
|
|
||||||
0x6f, 0x64, 0x69, 0x6e, 0x67, 0xaa, 0x02, 0x19, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f,
|
|
||||||
0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e,
|
|
||||||
0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -420,25 +105,16 @@ func file_proxy_vless_encoding_addons_proto_rawDescGZIP() []byte {
|
|||||||
return file_proxy_vless_encoding_addons_proto_rawDescData
|
return file_proxy_vless_encoding_addons_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_proxy_vless_encoding_addons_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
var file_proxy_vless_encoding_addons_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||||
var file_proxy_vless_encoding_addons_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
var file_proxy_vless_encoding_addons_proto_goTypes = []any{
|
||||||
var file_proxy_vless_encoding_addons_proto_goTypes = []interface{}{
|
(*Addons)(nil), // 0: xray.proxy.vless.encoding.Addons
|
||||||
(SeedMode)(0), // 0: xray.proxy.vless.encoding.SeedMode
|
|
||||||
(*Addons)(nil), // 1: xray.proxy.vless.encoding.Addons
|
|
||||||
(*PaddingConfig)(nil), // 2: xray.proxy.vless.encoding.PaddingConfig
|
|
||||||
(*DelayConfig)(nil), // 3: xray.proxy.vless.encoding.DelayConfig
|
|
||||||
(*SchedulerConfig)(nil), // 4: xray.proxy.vless.encoding.SchedulerConfig
|
|
||||||
}
|
}
|
||||||
var file_proxy_vless_encoding_addons_proto_depIdxs = []int32{
|
var file_proxy_vless_encoding_addons_proto_depIdxs = []int32{
|
||||||
0, // 0: xray.proxy.vless.encoding.Addons.Mode:type_name -> xray.proxy.vless.encoding.SeedMode
|
0, // [0:0] is the sub-list for method output_type
|
||||||
2, // 1: xray.proxy.vless.encoding.Addons.Padding:type_name -> xray.proxy.vless.encoding.PaddingConfig
|
0, // [0:0] is the sub-list for method input_type
|
||||||
3, // 2: xray.proxy.vless.encoding.Addons.Delay:type_name -> xray.proxy.vless.encoding.DelayConfig
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
4, // 3: xray.proxy.vless.encoding.Addons.Scheduler:type_name -> xray.proxy.vless.encoding.SchedulerConfig
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
4, // [4:4] is the sub-list for method output_type
|
0, // [0:0] is the sub-list for field type_name
|
||||||
4, // [4:4] is the sub-list for method input_type
|
|
||||||
4, // [4:4] is the sub-list for extension type_name
|
|
||||||
4, // [4:4] is the sub-list for extension extendee
|
|
||||||
0, // [0:4] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_proxy_vless_encoding_addons_proto_init() }
|
func init() { file_proxy_vless_encoding_addons_proto_init() }
|
||||||
@@ -446,69 +122,18 @@ func file_proxy_vless_encoding_addons_proto_init() {
|
|||||||
if File_proxy_vless_encoding_addons_proto != nil {
|
if File_proxy_vless_encoding_addons_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_proxy_vless_encoding_addons_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
|
||||||
switch v := v.(*Addons); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_proxy_vless_encoding_addons_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*PaddingConfig); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_proxy_vless_encoding_addons_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*DelayConfig); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_proxy_vless_encoding_addons_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*SchedulerConfig); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_proxy_vless_encoding_addons_proto_rawDesc,
|
RawDescriptor: file_proxy_vless_encoding_addons_proto_rawDesc,
|
||||||
NumEnums: 1,
|
NumEnums: 0,
|
||||||
NumMessages: 4,
|
NumMessages: 1,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
GoTypes: file_proxy_vless_encoding_addons_proto_goTypes,
|
GoTypes: file_proxy_vless_encoding_addons_proto_goTypes,
|
||||||
DependencyIndexes: file_proxy_vless_encoding_addons_proto_depIdxs,
|
DependencyIndexes: file_proxy_vless_encoding_addons_proto_depIdxs,
|
||||||
EnumInfos: file_proxy_vless_encoding_addons_proto_enumTypes,
|
|
||||||
MessageInfos: file_proxy_vless_encoding_addons_proto_msgTypes,
|
MessageInfos: file_proxy_vless_encoding_addons_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_proxy_vless_encoding_addons_proto = out.File
|
File_proxy_vless_encoding_addons_proto = out.File
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package xray.proxy.vless.encoding;
|
||||||
|
option csharp_namespace = "Xray.Proxy.Vless.Encoding";
|
||||||
|
option go_package = "github.com/xtls/xray-core/proxy/vless/encoding";
|
||||||
|
option java_package = "com.xray.proxy.vless.encoding";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
message Addons {
|
||||||
|
string Flow = 1;
|
||||||
|
bytes Seed = 2;
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package encoding
|
package encoding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/session"
|
"github.com/xtls/xray-core/common/session"
|
||||||
"github.com/xtls/xray-core/common/signal"
|
"github.com/xtls/xray-core/common/signal"
|
||||||
|
"github.com/xtls/xray-core/features/stats"
|
||||||
"github.com/xtls/xray-core/proxy"
|
"github.com/xtls/xray-core/proxy"
|
||||||
"github.com/xtls/xray-core/proxy/vless"
|
"github.com/xtls/xray-core/proxy/vless"
|
||||||
)
|
)
|
||||||
@@ -26,7 +28,7 @@ var addrParser = protocol.NewAddressParser(
|
|||||||
)
|
)
|
||||||
|
|
||||||
// EncodeRequestHeader writes encoded request header into the given writer.
|
// EncodeRequestHeader writes encoded request header into the given writer.
|
||||||
func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requestAddons *proxy.Addons) error {
|
func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons) error {
|
||||||
buffer := buf.StackNew()
|
buffer := buf.StackNew()
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|
||||||
@@ -60,7 +62,7 @@ func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.
|
// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.
|
||||||
func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validator vless.Validator) ([]byte, *protocol.RequestHeader, *proxy.Addons, bool, error) {
|
func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validator vless.Validator) ([]byte, *protocol.RequestHeader, *Addons, bool, error) {
|
||||||
buffer := buf.StackNew()
|
buffer := buf.StackNew()
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|
||||||
@@ -129,7 +131,7 @@ func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EncodeResponseHeader writes encoded response header into the given writer.
|
// EncodeResponseHeader writes encoded response header into the given writer.
|
||||||
func EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, responseAddons *proxy.Addons) error {
|
func EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, responseAddons *Addons) error {
|
||||||
buffer := buf.StackNew()
|
buffer := buf.StackNew()
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|
||||||
@@ -149,7 +151,7 @@ func EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, res
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DecodeResponseHeader decodes and returns (if successful) a ResponseHeader from an input stream.
|
// DecodeResponseHeader decodes and returns (if successful) a ResponseHeader from an input stream.
|
||||||
func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*proxy.Addons, error) {
|
func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*Addons, error) {
|
||||||
buffer := buf.StackNew()
|
buffer := buf.StackNew()
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|
||||||
@@ -169,8 +171,8 @@ func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*p
|
|||||||
return responseAddons, nil
|
return responseAddons, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// XtlsRead can switch to splice copy
|
// XtlsRead filter and read xtls protocol
|
||||||
func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer, conn net.Conn, trafficState *proxy.TrafficState, isUplink bool, ctx context.Context) error {
|
func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer, conn net.Conn, peerCache *[]byte, input *bytes.Reader, rawInput *bytes.Buffer, trafficState *proxy.TrafficState, ob *session.Outbound, isUplink bool, ctx context.Context) error {
|
||||||
err := func() error {
|
err := func() error {
|
||||||
for {
|
for {
|
||||||
if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy {
|
if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy {
|
||||||
@@ -179,11 +181,80 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer *signal.ActivityTimer,
|
|||||||
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil {
|
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil {
|
||||||
writerConn = inbound.Conn
|
writerConn = inbound.Conn
|
||||||
inTimer = inbound.Timer
|
inTimer = inbound.Timer
|
||||||
|
if isUplink && inbound.CanSpliceCopy == 2 {
|
||||||
|
inbound.CanSpliceCopy = 1
|
||||||
|
}
|
||||||
|
if !isUplink && ob != nil && ob.CanSpliceCopy == 2 { // ob need to be passed in due to context can change
|
||||||
|
ob.CanSpliceCopy = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return proxy.CopyRawConnIfExist(ctx, conn, writerConn, writer, timer, inTimer)
|
return proxy.CopyRawConnIfExist(ctx, conn, writerConn, writer, timer, inTimer)
|
||||||
}
|
}
|
||||||
buffer, err := reader.ReadMultiBuffer()
|
buffer, err := reader.ReadMultiBuffer()
|
||||||
if !buffer.IsEmpty() {
|
if !buffer.IsEmpty() {
|
||||||
|
timer.Update()
|
||||||
|
if isUplink && trafficState.Inbound.UplinkReaderDirectCopy || !isUplink && trafficState.Outbound.DownlinkReaderDirectCopy {
|
||||||
|
// XTLS Vision processes struct Encryption Conn's peerCache or TLS Conn's input and rawInput
|
||||||
|
if peerCache != nil {
|
||||||
|
if len(*peerCache) != 0 {
|
||||||
|
buffer = buf.MergeBytes(buffer, *peerCache)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if inputBuffer, err := buf.ReadFrom(input); err == nil {
|
||||||
|
if !inputBuffer.IsEmpty() {
|
||||||
|
buffer, _ = buf.MergeMulti(buffer, inputBuffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rawInputBuffer, err := buf.ReadFrom(rawInput); err == nil {
|
||||||
|
if !rawInputBuffer.IsEmpty() {
|
||||||
|
buffer, _ = buf.MergeMulti(buffer, rawInputBuffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||||
|
return werr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err != nil && errors.Cause(err) != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// XtlsWrite filter and write xtls protocol
|
||||||
|
func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, trafficState *proxy.TrafficState, ob *session.Outbound, isUplink bool, ctx context.Context) error {
|
||||||
|
err := func() error {
|
||||||
|
var ct stats.Counter
|
||||||
|
for {
|
||||||
|
buffer, err := reader.ReadMultiBuffer()
|
||||||
|
if isUplink && trafficState.Outbound.UplinkWriterDirectCopy || !isUplink && trafficState.Inbound.DownlinkWriterDirectCopy {
|
||||||
|
if inbound := session.InboundFromContext(ctx); inbound != nil {
|
||||||
|
if !isUplink && inbound.CanSpliceCopy == 2 {
|
||||||
|
inbound.CanSpliceCopy = 1
|
||||||
|
}
|
||||||
|
if isUplink && ob != nil && ob.CanSpliceCopy == 2 {
|
||||||
|
ob.CanSpliceCopy = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rawConn, _, writerCounter := proxy.UnwrapRawConn(conn)
|
||||||
|
writer = buf.NewWriter(rawConn)
|
||||||
|
ct = writerCounter
|
||||||
|
if isUplink {
|
||||||
|
trafficState.Outbound.UplinkWriterDirectCopy = false
|
||||||
|
} else {
|
||||||
|
trafficState.Inbound.DownlinkWriterDirectCopy = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !buffer.IsEmpty() {
|
||||||
|
if ct != nil {
|
||||||
|
ct.Add(int64(buffer.Len()))
|
||||||
|
}
|
||||||
timer.Update()
|
timer.Update()
|
||||||
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
if werr := writer.WriteMultiBuffer(buffer); werr != nil {
|
||||||
return werr
|
return werr
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/net"
|
"github.com/xtls/xray-core/common/net"
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
"github.com/xtls/xray-core/common/protocol"
|
||||||
"github.com/xtls/xray-core/common/uuid"
|
"github.com/xtls/xray-core/common/uuid"
|
||||||
"github.com/xtls/xray-core/proxy"
|
|
||||||
"github.com/xtls/xray-core/proxy/vless"
|
"github.com/xtls/xray-core/proxy/vless"
|
||||||
. "github.com/xtls/xray-core/proxy/vless/encoding"
|
. "github.com/xtls/xray-core/proxy/vless/encoding"
|
||||||
)
|
)
|
||||||
@@ -38,7 +37,7 @@ func TestRequestSerialization(t *testing.T) {
|
|||||||
Address: net.DomainAddress("www.example.com"),
|
Address: net.DomainAddress("www.example.com"),
|
||||||
Port: net.Port(443),
|
Port: net.Port(443),
|
||||||
}
|
}
|
||||||
expectedAddons := &proxy.Addons{}
|
expectedAddons := &Addons{}
|
||||||
|
|
||||||
buffer := buf.StackNew()
|
buffer := buf.StackNew()
|
||||||
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
||||||
@@ -53,7 +52,7 @@ func TestRequestSerialization(t *testing.T) {
|
|||||||
t.Error(r)
|
t.Error(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
addonsComparer := func(x, y *proxy.Addons) bool {
|
addonsComparer := func(x, y *Addons) bool {
|
||||||
return (x.Flow == y.Flow) && (cmp.Equal(x.Seed, y.Seed))
|
return (x.Flow == y.Flow) && (cmp.Equal(x.Seed, y.Seed))
|
||||||
}
|
}
|
||||||
if r := cmp.Diff(actualAddons, expectedAddons, cmp.Comparer(addonsComparer)); r != "" {
|
if r := cmp.Diff(actualAddons, expectedAddons, cmp.Comparer(addonsComparer)); r != "" {
|
||||||
@@ -79,7 +78,7 @@ func TestInvalidRequest(t *testing.T) {
|
|||||||
Address: net.DomainAddress("www.example.com"),
|
Address: net.DomainAddress("www.example.com"),
|
||||||
Port: net.Port(443),
|
Port: net.Port(443),
|
||||||
}
|
}
|
||||||
expectedAddons := &proxy.Addons{}
|
expectedAddons := &Addons{}
|
||||||
|
|
||||||
buffer := buf.StackNew()
|
buffer := buf.StackNew()
|
||||||
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
||||||
@@ -110,7 +109,7 @@ func TestMuxRequest(t *testing.T) {
|
|||||||
Command: protocol.RequestCommandMux,
|
Command: protocol.RequestCommandMux,
|
||||||
Address: net.DomainAddress("v1.mux.cool"),
|
Address: net.DomainAddress("v1.mux.cool"),
|
||||||
}
|
}
|
||||||
expectedAddons := &proxy.Addons{}
|
expectedAddons := &Addons{}
|
||||||
|
|
||||||
buffer := buf.StackNew()
|
buffer := buf.StackNew()
|
||||||
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
common.Must(EncodeRequestHeader(&buffer, expectedRequest, expectedAddons))
|
||||||
@@ -125,7 +124,7 @@ func TestMuxRequest(t *testing.T) {
|
|||||||
t.Error(r)
|
t.Error(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
addonsComparer := func(x, y *proxy.Addons) bool {
|
addonsComparer := func(x, y *Addons) bool {
|
||||||
return (x.Flow == y.Flow) && (cmp.Equal(x.Seed, y.Seed))
|
return (x.Flow == y.Flow) && (cmp.Equal(x.Seed, y.Seed))
|
||||||
}
|
}
|
||||||
if r := cmp.Diff(actualAddons, expectedAddons, cmp.Comparer(addonsComparer)); r != "" {
|
if r := cmp.Diff(actualAddons, expectedAddons, cmp.Comparer(addonsComparer)); r != "" {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/common/crypto"
|
||||||
"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"
|
||||||
"lukechampine.com/blake3"
|
"lukechampine.com/blake3"
|
||||||
@@ -22,8 +23,6 @@ type ClientInstance struct {
|
|||||||
RelaysLength int
|
RelaysLength int
|
||||||
XorMode uint32
|
XorMode uint32
|
||||||
Seconds uint32
|
Seconds uint32
|
||||||
PaddingLens [][3]int
|
|
||||||
PaddingGaps [][3]int
|
|
||||||
|
|
||||||
RWLock sync.RWMutex
|
RWLock sync.RWMutex
|
||||||
Expire time.Time
|
Expire time.Time
|
||||||
@@ -31,13 +30,15 @@ type ClientInstance struct {
|
|||||||
Ticket []byte
|
Ticket []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ClientInstance) Init(nfsPKeysBytes [][]byte, xorMode, seconds uint32, padding string) (err error) {
|
func (i *ClientInstance) Init(nfsPKeysBytes [][]byte, xorMode, seconds uint32) (err error) {
|
||||||
if i.NfsPKeys != nil {
|
if i.NfsPKeys != nil {
|
||||||
return errors.New("already initialized")
|
err = errors.New("already initialized")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
l := len(nfsPKeysBytes)
|
l := len(nfsPKeysBytes)
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
return errors.New("empty nfsPKeysBytes")
|
err = errors.New("empty nfsPKeysBytes")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
i.NfsPKeys = make([]any, l)
|
i.NfsPKeys = make([]any, l)
|
||||||
i.NfsPKeysBytes = nfsPKeysBytes
|
i.NfsPKeysBytes = nfsPKeysBytes
|
||||||
@@ -59,7 +60,7 @@ func (i *ClientInstance) Init(nfsPKeysBytes [][]byte, xorMode, seconds uint32, p
|
|||||||
i.RelaysLength -= 32
|
i.RelaysLength -= 32
|
||||||
i.XorMode = xorMode
|
i.XorMode = xorMode
|
||||||
i.Seconds = seconds
|
i.Seconds = seconds
|
||||||
return ParsePadding(padding, &i.PaddingLens, &i.PaddingGaps)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
|
func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
|
||||||
@@ -70,7 +71,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
|
|||||||
|
|
||||||
ivAndRealysLength := 16 + i.RelaysLength
|
ivAndRealysLength := 16 + i.RelaysLength
|
||||||
pfsKeyExchangeLength := 18 + 1184 + 32 + 16
|
pfsKeyExchangeLength := 18 + 1184 + 32 + 16
|
||||||
paddingLength, paddingLens, paddingGaps := CreatPadding(i.PaddingLens, i.PaddingGaps)
|
paddingLength := int(crypto.RandBetween(100, 1000))
|
||||||
clientHello := make([]byte, ivAndRealysLength+pfsKeyExchangeLength+paddingLength)
|
clientHello := make([]byte, ivAndRealysLength+pfsKeyExchangeLength+paddingLength)
|
||||||
|
|
||||||
iv := clientHello[:16]
|
iv := clientHello[:16]
|
||||||
@@ -139,18 +140,10 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
|
|||||||
nfsAEAD.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
|
nfsAEAD.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
|
||||||
nfsAEAD.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
|
nfsAEAD.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
|
||||||
|
|
||||||
paddingLens[0] = ivAndRealysLength + pfsKeyExchangeLength + paddingLens[0]
|
if _, err := conn.Write(clientHello); err != nil {
|
||||||
for i, l := range paddingLens { // sends padding in a fragmented way, to create variable traffic pattern, before inner VLESS flow takes control
|
return nil, err
|
||||||
if l > 0 {
|
|
||||||
if _, err := conn.Write(clientHello[:l]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
clientHello = clientHello[l:]
|
|
||||||
}
|
|
||||||
if len(paddingGaps) > i {
|
|
||||||
time.Sleep(paddingGaps[i])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// padding can be sent in a fragmented way, to create variable traffic pattern, before inner VLESS flow takes control
|
||||||
|
|
||||||
encryptedPfsPublicKey := make([]byte, 1088+32+16)
|
encryptedPfsPublicKey := make([]byte, 1088+32+16)
|
||||||
if _, err := io.ReadFull(conn, encryptedPfsPublicKey); err != nil {
|
if _, err := io.ReadFull(conn, encryptedPfsPublicKey); err != nil {
|
||||||
|
|||||||
@@ -7,12 +7,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/crypto"
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"golang.org/x/crypto/chacha20poly1305"
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
"lukechampine.com/blake3"
|
"lukechampine.com/blake3"
|
||||||
@@ -33,14 +31,15 @@ type CommonConn struct {
|
|||||||
AEAD *AEAD
|
AEAD *AEAD
|
||||||
PeerAEAD *AEAD
|
PeerAEAD *AEAD
|
||||||
PeerPadding []byte
|
PeerPadding []byte
|
||||||
rawInput bytes.Buffer
|
PeerInBytes []byte
|
||||||
input bytes.Reader
|
PeerCache []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCommonConn(conn net.Conn, useAES bool) *CommonConn {
|
func NewCommonConn(conn net.Conn, useAES bool) *CommonConn {
|
||||||
return &CommonConn{
|
return &CommonConn{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
UseAES: useAES,
|
UseAES: useAES,
|
||||||
|
PeerInBytes: make([]byte, 5+17000), // no need to use sync.Pool, because we are always reading
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,14 +99,16 @@ func (c *CommonConn) Read(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
c.PeerPadding = nil
|
c.PeerPadding = nil
|
||||||
}
|
}
|
||||||
if c.input.Len() > 0 {
|
if len(c.PeerCache) > 0 {
|
||||||
return c.input.Read(b)
|
n := copy(b, c.PeerCache)
|
||||||
|
c.PeerCache = c.PeerCache[n:]
|
||||||
|
return n, nil
|
||||||
}
|
}
|
||||||
peerHeader := [5]byte{}
|
peerHeader := c.PeerInBytes[:5]
|
||||||
if _, err := io.ReadFull(c.Conn, peerHeader[:]); err != nil {
|
if _, err := io.ReadFull(c.Conn, peerHeader); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
l, err := DecodeHeader(peerHeader[:]) // l: 17~17000
|
l, err := DecodeHeader(c.PeerInBytes[:5]) // l: 17~17000
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if c.Client != nil && strings.Contains(err.Error(), "invalid header: ") { // client's 0-RTT
|
if c.Client != nil && strings.Contains(err.Error(), "invalid header: ") { // client's 0-RTT
|
||||||
c.Client.RWLock.Lock()
|
c.Client.RWLock.Lock()
|
||||||
@@ -120,10 +121,7 @@ func (c *CommonConn) Read(b []byte) (int, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
c.Client = nil
|
c.Client = nil
|
||||||
if c.rawInput.Cap() < l {
|
peerData := c.PeerInBytes[5 : 5+l]
|
||||||
c.rawInput.Grow(l) // no need to use sync.Pool, because we are always reading
|
|
||||||
}
|
|
||||||
peerData := c.rawInput.Bytes()[:l]
|
|
||||||
if _, err := io.ReadFull(c.Conn, peerData); err != nil {
|
if _, err := io.ReadFull(c.Conn, peerData); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -133,9 +131,9 @@ func (c *CommonConn) Read(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
var newAEAD *AEAD
|
var newAEAD *AEAD
|
||||||
if bytes.Equal(c.PeerAEAD.Nonce[:], MaxNonce) {
|
if bytes.Equal(c.PeerAEAD.Nonce[:], MaxNonce) {
|
||||||
newAEAD = NewAEAD(append(peerHeader[:], peerData...), c.UnitedKey, c.UseAES)
|
newAEAD = NewAEAD(c.PeerInBytes[:5+l], c.UnitedKey, c.UseAES)
|
||||||
}
|
}
|
||||||
_, err = c.PeerAEAD.Open(dst[:0], nil, peerData, peerHeader[:])
|
_, err = c.PeerAEAD.Open(dst[:0], nil, peerData, peerHeader)
|
||||||
if newAEAD != nil {
|
if newAEAD != nil {
|
||||||
c.PeerAEAD = newAEAD
|
c.PeerAEAD = newAEAD
|
||||||
}
|
}
|
||||||
@@ -143,7 +141,7 @@ func (c *CommonConn) Read(b []byte) (int, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if len(dst) > len(b) {
|
if len(dst) > len(b) {
|
||||||
c.input.Reset(dst[copy(b, dst):])
|
c.PeerCache = dst[copy(b, dst):]
|
||||||
dst = b // for len(dst)
|
dst = b // for len(dst)
|
||||||
}
|
}
|
||||||
return len(dst), nil
|
return len(dst), nil
|
||||||
@@ -215,66 +213,7 @@ func DecodeHeader(h []byte) (l int, err error) {
|
|||||||
l = 0
|
l = 0
|
||||||
}
|
}
|
||||||
if l < 17 || l > 17000 { // TODO: TLSv1.3 max length
|
if l < 17 || l > 17000 { // TODO: TLSv1.3 max length
|
||||||
err = errors.New("invalid header: " + fmt.Sprintf("%v", h[:5])) // DO NOT CHANGE: relied by client's Read()
|
err = errors.New("invalid header: ", fmt.Sprintf("%v", h[:5])) // DO NOT CHANGE: relied by client's Read()
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParsePadding(padding string, paddingLens, paddingGaps *[][3]int) (err error) {
|
|
||||||
if padding == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
maxLen := 0
|
|
||||||
for i, s := range strings.Split(padding, ".") {
|
|
||||||
x := strings.Split(s, "-")
|
|
||||||
if len(x) < 3 || x[0] == "" || x[1] == "" || x[2] == "" {
|
|
||||||
return errors.New("invalid padding lenth/gap parameter: " + s)
|
|
||||||
}
|
|
||||||
y := [3]int{}
|
|
||||||
if y[0], err = strconv.Atoi(x[0]); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if y[1], err = strconv.Atoi(x[1]); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if y[2], err = strconv.Atoi(x[2]); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if i == 0 && (y[0] < 100 || y[1] < 18+17 || y[2] < 18+17) {
|
|
||||||
return errors.New("first padding length must not be smaller than 35")
|
|
||||||
}
|
|
||||||
if i%2 == 0 {
|
|
||||||
*paddingLens = append(*paddingLens, y)
|
|
||||||
maxLen += max(y[1], y[2])
|
|
||||||
} else {
|
|
||||||
*paddingGaps = append(*paddingGaps, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if maxLen > 18+65535 {
|
|
||||||
return errors.New("total padding length must not be larger than 65553")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreatPadding(paddingLens, paddingGaps [][3]int) (length int, lens []int, gaps []time.Duration) {
|
|
||||||
if len(paddingLens) == 0 {
|
|
||||||
paddingLens = [][3]int{{100, 111, 1111}, {50, 0, 3333}}
|
|
||||||
paddingGaps = [][3]int{{75, 0, 111}}
|
|
||||||
}
|
|
||||||
for _, y := range paddingLens {
|
|
||||||
l := 0
|
|
||||||
if y[0] >= int(crypto.RandBetween(0, 100)) {
|
|
||||||
l = int(crypto.RandBetween(int64(y[1]), int64(y[2])))
|
|
||||||
}
|
|
||||||
lens = append(lens, l)
|
|
||||||
length += l
|
|
||||||
}
|
|
||||||
for _, y := range paddingGaps {
|
|
||||||
g := 0
|
|
||||||
if y[0] >= int(crypto.RandBetween(0, 100)) {
|
|
||||||
g = int(crypto.RandBetween(int64(y[1]), int64(y[2])))
|
|
||||||
}
|
|
||||||
gaps = append(gaps, time.Duration(g)*time.Millisecond)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ServerSession struct {
|
type ServerSession struct {
|
||||||
|
Expire time.Time
|
||||||
PfsKey []byte
|
PfsKey []byte
|
||||||
NfsKeys sync.Map
|
NfsKeys sync.Map
|
||||||
}
|
}
|
||||||
@@ -28,25 +29,22 @@ type ServerInstance struct {
|
|||||||
Hash32s [][32]byte
|
Hash32s [][32]byte
|
||||||
RelaysLength int
|
RelaysLength int
|
||||||
XorMode uint32
|
XorMode uint32
|
||||||
SecondsFrom int64
|
Seconds uint32
|
||||||
SecondsTo int64
|
|
||||||
PaddingLens [][3]int
|
|
||||||
PaddingGaps [][3]int
|
|
||||||
|
|
||||||
RWLock sync.RWMutex
|
RWLock sync.RWMutex
|
||||||
Closed bool
|
|
||||||
Lasts map[int64][16]byte
|
|
||||||
Tickets [][16]byte
|
|
||||||
Sessions map[[16]byte]*ServerSession
|
Sessions map[[16]byte]*ServerSession
|
||||||
|
Closed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ServerInstance) Init(nfsSKeysBytes [][]byte, xorMode uint32, secondsFrom, secondsTo int64, padding string) (err error) {
|
func (i *ServerInstance) Init(nfsSKeysBytes [][]byte, xorMode, seconds uint32) (err error) {
|
||||||
if i.NfsSKeys != nil {
|
if i.NfsSKeys != nil {
|
||||||
return errors.New("already initialized")
|
err = errors.New("already initialized")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
l := len(nfsSKeysBytes)
|
l := len(nfsSKeysBytes)
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
return errors.New("empty nfsSKeysBytes")
|
err = errors.New("empty nfsSKeysBytes")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
i.NfsSKeys = make([]any, l)
|
i.NfsSKeys = make([]any, l)
|
||||||
i.NfsPKeysBytes = make([][]byte, l)
|
i.NfsPKeysBytes = make([][]byte, l)
|
||||||
@@ -69,15 +67,8 @@ func (i *ServerInstance) Init(nfsSKeysBytes [][]byte, xorMode uint32, secondsFro
|
|||||||
}
|
}
|
||||||
i.RelaysLength -= 32
|
i.RelaysLength -= 32
|
||||||
i.XorMode = xorMode
|
i.XorMode = xorMode
|
||||||
i.SecondsFrom = secondsFrom
|
if seconds > 0 {
|
||||||
i.SecondsTo = secondsTo
|
i.Seconds = seconds
|
||||||
err = ParsePadding(padding, &i.PaddingLens, &i.PaddingGaps)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if i.SecondsFrom > 0 || i.SecondsTo > 0 {
|
|
||||||
i.Lasts = make(map[int64][16]byte)
|
|
||||||
i.Tickets = make([][16]byte, 0, 1024)
|
|
||||||
i.Sessions = make(map[[16]byte]*ServerSession)
|
i.Sessions = make(map[[16]byte]*ServerSession)
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
@@ -87,17 +78,10 @@ func (i *ServerInstance) Init(nfsSKeysBytes [][]byte, xorMode uint32, secondsFro
|
|||||||
i.RWLock.Unlock()
|
i.RWLock.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
minute := time.Now().Unix() / 60
|
now := time.Now()
|
||||||
last := i.Lasts[minute]
|
for ticket, session := range i.Sessions {
|
||||||
delete(i.Lasts, minute)
|
if now.After(session.Expire) {
|
||||||
delete(i.Lasts, minute-1) // for insurance
|
|
||||||
if last != [16]byte{} {
|
|
||||||
for j, ticket := range i.Tickets {
|
|
||||||
delete(i.Sessions, ticket)
|
delete(i.Sessions, ticket)
|
||||||
if ticket == last {
|
|
||||||
i.Tickets = i.Tickets[j+1:]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i.RWLock.Unlock()
|
i.RWLock.Unlock()
|
||||||
@@ -114,7 +98,7 @@ func (i *ServerInstance) Close() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn, error) {
|
func (i *ServerInstance) Handshake(conn net.Conn) (*CommonConn, error) {
|
||||||
if i.NfsSKeys == nil {
|
if i.NfsSKeys == nil {
|
||||||
return nil, errors.New("uninitialized")
|
return nil, errors.New("uninitialized")
|
||||||
}
|
}
|
||||||
@@ -124,9 +108,6 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
|
|||||||
if _, err := io.ReadFull(conn, ivAndRelays); err != nil {
|
if _, err := io.ReadFull(conn, ivAndRelays); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if fallback != nil {
|
|
||||||
*fallback = append(*fallback, ivAndRelays...)
|
|
||||||
}
|
|
||||||
iv := ivAndRelays[:16]
|
iv := ivAndRelays[:16]
|
||||||
relays := ivAndRelays[16:]
|
relays := ivAndRelays[16:]
|
||||||
var nfsKey []byte
|
var nfsKey []byte
|
||||||
@@ -140,16 +121,13 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
|
|||||||
index = 1088
|
index = 1088
|
||||||
}
|
}
|
||||||
if i.XorMode > 0 {
|
if i.XorMode > 0 {
|
||||||
NewCTR(i.NfsPKeysBytes[j], iv).XORKeyStream(relays, relays[:index]) // we don't use buggy elligator2, because we have PSK :)
|
NewCTR(i.NfsPKeysBytes[j], iv).XORKeyStream(relays, relays[:index]) // we don't use buggy elligator, because we have PSK :)
|
||||||
}
|
}
|
||||||
if k, ok := k.(*ecdh.PrivateKey); ok {
|
if k, ok := k.(*ecdh.PrivateKey); ok {
|
||||||
publicKey, err := ecdh.X25519().NewPublicKey(relays[:index])
|
publicKey, err := ecdh.X25519().NewPublicKey(relays[:index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if publicKey.Bytes()[31] > 127 { // we just don't want the observer can change even one bit without breaking the connection, though it has nothing to do with security
|
|
||||||
return nil, errors.New("the highest bit of the last byte of the peer-sent X25519 public key is not 0")
|
|
||||||
}
|
|
||||||
nfsKey, err = k.ECDH(publicKey)
|
nfsKey, err = k.ECDH(publicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -179,9 +157,6 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
|
|||||||
if _, err := io.ReadFull(conn, encryptedLength); err != nil {
|
if _, err := io.ReadFull(conn, encryptedLength); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if fallback != nil {
|
|
||||||
*fallback = append(*fallback, encryptedLength...)
|
|
||||||
}
|
|
||||||
decryptedLength := make([]byte, 2)
|
decryptedLength := make([]byte, 2)
|
||||||
if _, err := nfsAEAD.Open(decryptedLength[:0], nil, encryptedLength, nil); err != nil {
|
if _, err := nfsAEAD.Open(decryptedLength[:0], nil, encryptedLength, nil); err != nil {
|
||||||
c.UseAES = !c.UseAES
|
c.UseAES = !c.UseAES
|
||||||
@@ -190,13 +165,10 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fallback != nil {
|
|
||||||
*fallback = nil
|
|
||||||
}
|
|
||||||
length := DecodeLength(decryptedLength)
|
length := DecodeLength(decryptedLength)
|
||||||
|
|
||||||
if length == 32 {
|
if length == 32 {
|
||||||
if i.SecondsFrom == 0 && i.SecondsTo == 0 {
|
if i.Seconds == 0 {
|
||||||
return nil, errors.New("0-RTT is not allowed")
|
return nil, errors.New("0-RTT is not allowed")
|
||||||
}
|
}
|
||||||
encryptedTicket := make([]byte, 32)
|
encryptedTicket := make([]byte, 32)
|
||||||
@@ -211,7 +183,7 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
|
|||||||
s := i.Sessions[[16]byte(ticket)]
|
s := i.Sessions[[16]byte(ticket)]
|
||||||
i.RWLock.RUnlock()
|
i.RWLock.RUnlock()
|
||||||
if s == nil {
|
if s == nil {
|
||||||
noises := make([]byte, crypto.RandBetween(1279, 2279)) // matches 1-RTT's server hello length for "random", though it is not important, just for example
|
noises := make([]byte, crypto.RandBetween(1268, 2268)) // matches 1-RTT's server hello length for "random", though it is not important, just for example
|
||||||
var err error
|
var err error
|
||||||
for err == nil {
|
for err == nil {
|
||||||
rand.Read(noises)
|
rand.Read(noises)
|
||||||
@@ -265,45 +237,32 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
|
|||||||
c.UnitedKey = append(pfsKey, nfsKey...)
|
c.UnitedKey = append(pfsKey, nfsKey...)
|
||||||
c.AEAD = NewAEAD(pfsPublicKey, c.UnitedKey, c.UseAES)
|
c.AEAD = NewAEAD(pfsPublicKey, c.UnitedKey, c.UseAES)
|
||||||
c.PeerAEAD = NewAEAD(encryptedPfsPublicKey[:1184+32], c.UnitedKey, c.UseAES)
|
c.PeerAEAD = NewAEAD(encryptedPfsPublicKey[:1184+32], c.UnitedKey, c.UseAES)
|
||||||
|
ticket := make([]byte, 16)
|
||||||
ticket := [16]byte{}
|
rand.Read(ticket)
|
||||||
rand.Read(ticket[:])
|
copy(ticket, EncodeLength(int(i.Seconds*4/5)))
|
||||||
var seconds int64
|
|
||||||
if i.SecondsTo == 0 {
|
|
||||||
seconds = i.SecondsFrom * crypto.RandBetween(50, 100) / 100
|
|
||||||
} else {
|
|
||||||
seconds = crypto.RandBetween(i.SecondsFrom, i.SecondsTo)
|
|
||||||
}
|
|
||||||
copy(ticket[:], EncodeLength(int(seconds)))
|
|
||||||
if seconds > 0 {
|
|
||||||
i.RWLock.Lock()
|
|
||||||
i.Lasts[(time.Now().Unix()+max(i.SecondsFrom, i.SecondsTo))/60+2] = ticket
|
|
||||||
i.Tickets = append(i.Tickets, ticket)
|
|
||||||
i.Sessions[ticket] = &ServerSession{PfsKey: pfsKey}
|
|
||||||
i.RWLock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
pfsKeyExchangeLength := 1088 + 32 + 16
|
pfsKeyExchangeLength := 1088 + 32 + 16
|
||||||
encryptedTicketLength := 32
|
encryptedTicketLength := 32
|
||||||
paddingLength, paddingLens, paddingGaps := CreatPadding(i.PaddingLens, i.PaddingGaps)
|
paddingLength := int(crypto.RandBetween(100, 1000))
|
||||||
serverHello := make([]byte, pfsKeyExchangeLength+encryptedTicketLength+paddingLength)
|
serverHello := make([]byte, pfsKeyExchangeLength+encryptedTicketLength+paddingLength)
|
||||||
nfsAEAD.Seal(serverHello[:0], MaxNonce, pfsPublicKey, nil)
|
nfsAEAD.Seal(serverHello[:0], MaxNonce, pfsPublicKey, nil)
|
||||||
c.AEAD.Seal(serverHello[:pfsKeyExchangeLength], nil, ticket[:], nil)
|
c.AEAD.Seal(serverHello[:pfsKeyExchangeLength], nil, ticket, nil)
|
||||||
padding := serverHello[pfsKeyExchangeLength+encryptedTicketLength:]
|
padding := serverHello[pfsKeyExchangeLength+encryptedTicketLength:]
|
||||||
c.AEAD.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
|
c.AEAD.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
|
||||||
c.AEAD.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
|
c.AEAD.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
|
||||||
|
|
||||||
paddingLens[0] = pfsKeyExchangeLength + encryptedTicketLength + paddingLens[0]
|
if _, err := conn.Write(serverHello); err != nil {
|
||||||
for i, l := range paddingLens { // sends padding in a fragmented way, to create variable traffic pattern, before inner VLESS flow takes control
|
return nil, err
|
||||||
if l > 0 {
|
}
|
||||||
if _, err := conn.Write(serverHello[:l]); err != nil {
|
// padding can be sent in a fragmented way, to create variable traffic pattern, before inner VLESS flow takes control
|
||||||
return nil, err
|
|
||||||
}
|
if i.Seconds > 0 {
|
||||||
serverHello = serverHello[l:]
|
i.RWLock.Lock()
|
||||||
}
|
i.Sessions[[16]byte(ticket)] = &ServerSession{
|
||||||
if len(paddingGaps) > i {
|
Expire: time.Now().Add(time.Duration(i.Seconds) * time.Second),
|
||||||
time.Sleep(paddingGaps[i])
|
PfsKey: pfsKey,
|
||||||
}
|
}
|
||||||
|
i.RWLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// important: allows client sends padding slowly, eliminating 1-RTT's traffic pattern
|
// important: allows client sends padding slowly, eliminating 1-RTT's traffic pattern
|
||||||
@@ -322,7 +281,7 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
|
|||||||
}
|
}
|
||||||
|
|
||||||
if i.XorMode == 2 {
|
if i.XorMode == 2 {
|
||||||
c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, ticket[:]), NewCTR(c.UnitedKey, iv), 0, 0)
|
c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, ticket), NewCTR(c.UnitedKey, iv), 0, 0)
|
||||||
}
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,13 +111,11 @@ type Config struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Clients []*protocol.User `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"`
|
Clients []*protocol.User `protobuf:"bytes,1,rep,name=clients,proto3" json:"clients,omitempty"`
|
||||||
Fallbacks []*Fallback `protobuf:"bytes,2,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"`
|
Fallbacks []*Fallback `protobuf:"bytes,2,rep,name=fallbacks,proto3" json:"fallbacks,omitempty"`
|
||||||
Decryption string `protobuf:"bytes,3,opt,name=decryption,proto3" json:"decryption,omitempty"`
|
Decryption string `protobuf:"bytes,3,opt,name=decryption,proto3" json:"decryption,omitempty"`
|
||||||
XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"`
|
XorMode uint32 `protobuf:"varint,4,opt,name=xorMode,proto3" json:"xorMode,omitempty"`
|
||||||
SecondsFrom int64 `protobuf:"varint,5,opt,name=seconds_from,json=secondsFrom,proto3" json:"seconds_from,omitempty"`
|
Seconds uint32 `protobuf:"varint,5,opt,name=seconds,proto3" json:"seconds,omitempty"`
|
||||||
SecondsTo int64 `protobuf:"varint,6,opt,name=seconds_to,json=secondsTo,proto3" json:"seconds_to,omitempty"`
|
|
||||||
Padding string `protobuf:"bytes,7,opt,name=padding,proto3" json:"padding,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -178,27 +176,13 @@ func (x *Config) GetXorMode() uint32 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetSecondsFrom() int64 {
|
func (x *Config) GetSeconds() uint32 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.SecondsFrom
|
return x.Seconds
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetSecondsTo() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.SecondsTo
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetPadding() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Padding
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_proxy_vless_inbound_config_proto protoreflect.FileDescriptor
|
var File_proxy_vless_inbound_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_proxy_vless_inbound_config_proto_rawDesc = []byte{
|
var file_proxy_vless_inbound_config_proto_rawDesc = []byte{
|
||||||
@@ -215,7 +199,7 @@ var file_proxy_vless_inbound_config_proto_rawDesc = []byte{
|
|||||||
0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20,
|
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65,
|
0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65,
|
||||||
0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0x96, 0x02,
|
0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0xd4, 0x01,
|
||||||
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65,
|
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65,
|
||||||
0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
|
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
|
||||||
@@ -227,20 +211,16 @@ var file_proxy_vless_inbound_config_proto_rawDesc = []byte{
|
|||||||
0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03,
|
0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e,
|
||||||
0x12, 0x18, 0x0a, 0x07, 0x78, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
|
0x12, 0x18, 0x0a, 0x07, 0x78, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||||
0x0d, 0x52, 0x07, 0x78, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65,
|
0x0d, 0x52, 0x07, 0x78, 0x6f, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65,
|
||||||
0x63, 0x6f, 0x6e, 0x64, 0x73, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03,
|
0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x65, 0x63,
|
||||||
0x52, 0x0b, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x1d, 0x0a,
|
0x6f, 0x6e, 0x64, 0x73, 0x42, 0x6a, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79,
|
||||||
0x0a, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x5f, 0x74, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28,
|
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62,
|
||||||
0x03, 0x52, 0x09, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x54, 0x6f, 0x12, 0x18, 0x0a, 0x07,
|
0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||||
0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70,
|
0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72,
|
||||||
0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x42, 0x6a, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72,
|
0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e,
|
||||||
0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69,
|
0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x18, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f,
|
||||||
0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
|
||||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63,
|
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f,
|
|
||||||
0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x18, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50,
|
|
||||||
0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75,
|
|
||||||
0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -23,7 +23,5 @@ message Config {
|
|||||||
|
|
||||||
string decryption = 3;
|
string decryption = 3;
|
||||||
uint32 xorMode = 4;
|
uint32 xorMode = 4;
|
||||||
int64 seconds_from = 5;
|
uint32 seconds = 5;
|
||||||
int64 seconds_to = 6;
|
|
||||||
string padding = 7;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/proxy/vless"
|
"github.com/xtls/xray-core/proxy/vless"
|
||||||
"github.com/xtls/xray-core/proxy/vless/encoding"
|
"github.com/xtls/xray-core/proxy/vless/encoding"
|
||||||
"github.com/xtls/xray-core/proxy/vless/encryption"
|
"github.com/xtls/xray-core/proxy/vless/encryption"
|
||||||
"github.com/xtls/xray-core/transport"
|
|
||||||
"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"
|
||||||
@@ -93,7 +92,7 @@ func New(ctx context.Context, config *Config, dc dns.Client, validator vless.Val
|
|||||||
nfsSKeysBytes = append(nfsSKeysBytes, b)
|
nfsSKeysBytes = append(nfsSKeysBytes, b)
|
||||||
}
|
}
|
||||||
handler.decryption = &encryption.ServerInstance{}
|
handler.decryption = &encryption.ServerInstance{}
|
||||||
if err := handler.decryption.Init(nfsSKeysBytes, config.XorMode, config.SecondsFrom, config.SecondsTo, config.Padding); err != nil {
|
if err := handler.decryption.Init(nfsSKeysBytes, config.XorMode, config.Seconds); err != nil {
|
||||||
return nil, errors.New("failed to use decryption").Base(err).AtError()
|
return nil, errors.New("failed to use decryption").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +220,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
|
|
||||||
if h.decryption != nil {
|
if h.decryption != nil {
|
||||||
var err error
|
var err error
|
||||||
if connection, err = h.decryption.Handshake(connection, nil); err != nil {
|
connection, err = h.decryption.Handshake(connection)
|
||||||
|
if err != nil {
|
||||||
return errors.New("ML-KEM-768 handshake failed").Base(err).AtInfo()
|
return errors.New("ML-KEM-768 handshake failed").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,7 +246,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
|
|
||||||
var userSentID []byte // not MemoryAccount.ID
|
var userSentID []byte // not MemoryAccount.ID
|
||||||
var request *protocol.RequestHeader
|
var request *protocol.RequestHeader
|
||||||
var requestAddons *proxy.Addons
|
var requestAddons *encoding.Addons
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
napfb := h.fallbacks
|
napfb := h.fallbacks
|
||||||
@@ -487,14 +487,11 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
|
|
||||||
account := request.User.Account.(*vless.MemoryAccount)
|
account := request.User.Account.(*vless.MemoryAccount)
|
||||||
|
|
||||||
responseAddons := &proxy.Addons{
|
responseAddons := &encoding.Addons{
|
||||||
Flow: account.Flow,
|
// Flow: requestAddons.Flow,
|
||||||
}
|
|
||||||
encoding.PopulateSeed(account.Seed, responseAddons)
|
|
||||||
if check := encoding.CheckSeed(requestAddons, responseAddons); check != nil {
|
|
||||||
return errors.New("Seed configuration mis-match").Base(check).AtWarning()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var peerCache *[]byte
|
||||||
var input *bytes.Reader
|
var input *bytes.Reader
|
||||||
var rawInput *bytes.Buffer
|
var rawInput *bytes.Buffer
|
||||||
switch requestAddons.Flow {
|
switch requestAddons.Flow {
|
||||||
@@ -507,15 +504,16 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
case protocol.RequestCommandMux:
|
case protocol.RequestCommandMux:
|
||||||
fallthrough // we will break Mux connections that contain TCP requests
|
fallthrough // we will break Mux connections that contain TCP requests
|
||||||
case protocol.RequestCommandTCP:
|
case protocol.RequestCommandTCP:
|
||||||
|
if serverConn, ok := connection.(*encryption.CommonConn); ok {
|
||||||
|
peerCache = &serverConn.PeerCache
|
||||||
|
if _, ok := serverConn.Conn.(*encryption.XorConn); ok || !proxy.IsRAWTransport(iConn) {
|
||||||
|
inbound.CanSpliceCopy = 3 // full-random xorConn / non-RAW transport can not use Linux Splice
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
var t reflect.Type
|
var t reflect.Type
|
||||||
var p uintptr
|
var p uintptr
|
||||||
if commonConn, ok := connection.(*encryption.CommonConn); ok {
|
if tlsConn, ok := iConn.(*tls.Conn); ok {
|
||||||
if _, ok := commonConn.Conn.(*encryption.XorConn); ok || !proxy.IsRAWTransportWithoutSecurity(iConn) {
|
|
||||||
inbound.CanSpliceCopy = 3 // full-random xorConn / non-RAW transport / another securityConn should not be penetrated
|
|
||||||
}
|
|
||||||
t = reflect.TypeOf(commonConn).Elem()
|
|
||||||
p = uintptr(unsafe.Pointer(commonConn))
|
|
||||||
} else if tlsConn, ok := iConn.(*tls.Conn); ok {
|
|
||||||
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
||||||
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning()
|
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning()
|
||||||
}
|
}
|
||||||
@@ -556,21 +554,89 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP)
|
ctx = session.ContextWithAllowedNetwork(ctx, net.Network_UDP)
|
||||||
}
|
}
|
||||||
|
|
||||||
trafficState := proxy.NewTrafficState(userSentID, account.Flow)
|
sessionPolicy = h.policyManager.ForLevel(request.User.Level)
|
||||||
clientReader := encoding.DecodeBodyAddons(reader, request, responseAddons, trafficState, true, ctx, connection, input, rawInput, nil)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
|
||||||
|
inbound.Timer = timer
|
||||||
|
ctx = policy.ContextWithBufferPolicy(ctx, sessionPolicy.Buffer)
|
||||||
|
|
||||||
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))
|
link, err := dispatcher.Dispatch(ctx, request.Destination())
|
||||||
if err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to encode response header").Base(err).AtWarning()
|
return errors.New("failed to dispatch request to ", request.Destination()).Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, responseAddons, trafficState, false, ctx, connection, nil)
|
|
||||||
bufferWriter.SetFlushNext()
|
|
||||||
|
|
||||||
if err := dispatcher.DispatchLink(ctx, request.Destination(), &transport.Link{
|
serverReader := link.Reader // .(*pipe.Reader)
|
||||||
Reader: clientReader,
|
serverWriter := link.Writer // .(*pipe.Writer)
|
||||||
Writer: clientWriter},
|
trafficState := proxy.NewTrafficState(userSentID)
|
||||||
); err != nil {
|
postRequest := func() error {
|
||||||
return errors.New("failed to dispatch request").Base(err)
|
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
||||||
|
|
||||||
|
// default: clientReader := reader
|
||||||
|
clientReader := encoding.DecodeBodyAddons(reader, request, requestAddons)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if requestAddons.Flow == vless.XRV {
|
||||||
|
ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice
|
||||||
|
clientReader = proxy.NewVisionReader(clientReader, trafficState, true, ctx1)
|
||||||
|
err = encoding.XtlsRead(clientReader, serverWriter, timer, connection, peerCache, input, rawInput, trafficState, nil, true, ctx1)
|
||||||
|
} else {
|
||||||
|
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBuffer
|
||||||
|
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("failed to transfer request payload").Base(err).AtInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getResponse := func() error {
|
||||||
|
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||||
|
|
||||||
|
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))
|
||||||
|
if err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {
|
||||||
|
return errors.New("failed to encode response header").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
|
||||||
|
// default: clientWriter := bufferWriter
|
||||||
|
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, false, ctx)
|
||||||
|
multiBuffer, err1 := serverReader.ReadMultiBuffer()
|
||||||
|
if err1 != nil {
|
||||||
|
return err1 // ...
|
||||||
|
}
|
||||||
|
if err := clientWriter.WriteMultiBuffer(multiBuffer); err != nil {
|
||||||
|
return err // ...
|
||||||
|
}
|
||||||
|
// Flush; bufferWriter.WriteMultiBuffer now is bufferWriter.writer.WriteMultiBuffer
|
||||||
|
if err := bufferWriter.SetBuffered(false); err != nil {
|
||||||
|
return errors.New("failed to write A response payload").Base(err).AtWarning()
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if requestAddons.Flow == vless.XRV {
|
||||||
|
err = encoding.XtlsWrite(serverReader, clientWriter, timer, connection, trafficState, nil, false, ctx)
|
||||||
|
} else {
|
||||||
|
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer
|
||||||
|
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("failed to transfer response payload").Base(err).AtInfo()
|
||||||
|
}
|
||||||
|
// Indicates the end of response payload.
|
||||||
|
switch responseAddons.Flow {
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), getResponse); err != nil {
|
||||||
|
common.Interrupt(serverReader)
|
||||||
|
common.Interrupt(serverWriter)
|
||||||
|
return errors.New("connection ends").Base(err).AtInfo()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||||||
nfsPKeysBytes = append(nfsPKeysBytes, b)
|
nfsPKeysBytes = append(nfsPKeysBytes, b)
|
||||||
}
|
}
|
||||||
handler.encryption = &encryption.ClientInstance{}
|
handler.encryption = &encryption.ClientInstance{}
|
||||||
if err := handler.encryption.Init(nfsPKeysBytes, a.XorMode, a.Seconds, a.Padding); err != nil {
|
if err := handler.encryption.Init(nfsPKeysBytes, a.XorMode, a.Seconds); err != nil {
|
||||||
return nil, errors.New("failed to use encryption").Base(err).AtError()
|
return nil, errors.New("failed to use encryption").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,8 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
if h.encryption != nil {
|
if h.encryption != nil {
|
||||||
var err error
|
var err error
|
||||||
if conn, err = h.encryption.Handshake(conn); err != nil {
|
conn, err = h.encryption.Handshake(conn)
|
||||||
|
if err != nil {
|
||||||
return errors.New("ML-KEM-768 handshake failed").Base(err).AtInfo()
|
return errors.New("ML-KEM-768 handshake failed").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,11 +142,11 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
account := request.User.Account.(*vless.MemoryAccount)
|
account := request.User.Account.(*vless.MemoryAccount)
|
||||||
|
|
||||||
requestAddons := &proxy.Addons{
|
requestAddons := &encoding.Addons{
|
||||||
Flow: account.Flow,
|
Flow: account.Flow,
|
||||||
}
|
}
|
||||||
encoding.PopulateSeed(account.Seed, requestAddons)
|
|
||||||
|
|
||||||
|
var peerCache *[]byte
|
||||||
var input *bytes.Reader
|
var input *bytes.Reader
|
||||||
var rawInput *bytes.Buffer
|
var rawInput *bytes.Buffer
|
||||||
allowUDP443 := false
|
allowUDP443 := false
|
||||||
@@ -164,15 +165,16 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
case protocol.RequestCommandMux:
|
case protocol.RequestCommandMux:
|
||||||
fallthrough // let server break Mux connections that contain TCP requests
|
fallthrough // let server break Mux connections that contain TCP requests
|
||||||
case protocol.RequestCommandTCP:
|
case protocol.RequestCommandTCP:
|
||||||
|
if clientConn, ok := conn.(*encryption.CommonConn); ok {
|
||||||
|
peerCache = &clientConn.PeerCache
|
||||||
|
if _, ok := clientConn.Conn.(*encryption.XorConn); ok || !proxy.IsRAWTransport(iConn) {
|
||||||
|
ob.CanSpliceCopy = 3 // full-random xorConn / non-RAW transport can not use Linux Splice
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
var t reflect.Type
|
var t reflect.Type
|
||||||
var p uintptr
|
var p uintptr
|
||||||
if commonConn, ok := conn.(*encryption.CommonConn); ok {
|
if tlsConn, ok := iConn.(*tls.Conn); ok {
|
||||||
if _, ok := commonConn.Conn.(*encryption.XorConn); ok || !proxy.IsRAWTransportWithoutSecurity(iConn) {
|
|
||||||
ob.CanSpliceCopy = 3 // full-random xorConn / non-RAW transport / another securityConn should not be penetrated
|
|
||||||
}
|
|
||||||
t = reflect.TypeOf(commonConn).Elem()
|
|
||||||
p = uintptr(unsafe.Pointer(commonConn))
|
|
||||||
} else if tlsConn, ok := iConn.(*tls.Conn); ok {
|
|
||||||
t = reflect.TypeOf(tlsConn.Conn).Elem()
|
t = reflect.TypeOf(tlsConn.Conn).Elem()
|
||||||
p = uintptr(unsafe.Pointer(tlsConn.Conn))
|
p = uintptr(unsafe.Pointer(tlsConn.Conn))
|
||||||
} else if utlsConn, ok := iConn.(*tls.UConn); ok {
|
} else if utlsConn, ok := iConn.(*tls.UConn); ok {
|
||||||
@@ -210,7 +212,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
clientReader := link.Reader // .(*pipe.Reader)
|
clientReader := link.Reader // .(*pipe.Reader)
|
||||||
clientWriter := link.Writer // .(*pipe.Writer)
|
clientWriter := link.Writer // .(*pipe.Writer)
|
||||||
trafficState := proxy.NewTrafficState(account.ID.Bytes(), account.Flow)
|
trafficState := proxy.NewTrafficState(account.ID.Bytes())
|
||||||
if request.Command == protocol.RequestCommandUDP && (requestAddons.Flow == vless.XRV || (h.cone && request.Port != 53 && request.Port != 443)) {
|
if request.Command == protocol.RequestCommandUDP && (requestAddons.Flow == vless.XRV || (h.cone && request.Port != 53 && request.Port != 443)) {
|
||||||
request.Command = protocol.RequestCommandMux
|
request.Command = protocol.RequestCommandMux
|
||||||
request.Address = net.DomainAddress("v1.mux.cool")
|
request.Address = net.DomainAddress("v1.mux.cool")
|
||||||
@@ -226,7 +228,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// default: serverWriter := bufferWriter
|
// default: serverWriter := bufferWriter
|
||||||
serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, true, ctx, conn, ob)
|
serverWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, true, ctx)
|
||||||
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
|
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
|
||||||
serverWriter = xudp.NewPacketWriter(serverWriter, target, xudp.GetGlobalID(ctx))
|
serverWriter = xudp.NewPacketWriter(serverWriter, target, xudp.GetGlobalID(ctx))
|
||||||
}
|
}
|
||||||
@@ -254,6 +256,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
return errors.New("failed to write A request payload").Base(err).AtWarning()
|
return errors.New("failed to write A request payload").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
if requestAddons.Flow == vless.XRV {
|
if requestAddons.Flow == vless.XRV {
|
||||||
if tlsConn, ok := iConn.(*tls.Conn); ok {
|
if tlsConn, ok := iConn.(*tls.Conn); ok {
|
||||||
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
||||||
@@ -264,8 +267,12 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, utlsConn.ConnectionState().Version).AtWarning()
|
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, utlsConn.ConnectionState().Version).AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ctx1 := session.ContextWithInbound(ctx, nil) // TODO enable splice
|
||||||
|
err = encoding.XtlsWrite(clientReader, serverWriter, timer, conn, trafficState, ob, true, ctx1)
|
||||||
|
} else {
|
||||||
|
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBuffer
|
||||||
|
err = buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
||||||
}
|
}
|
||||||
err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to transfer request payload").Base(err).AtInfo()
|
return errors.New("failed to transfer request payload").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
@@ -286,13 +293,20 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// default: serverReader := buf.NewReader(conn)
|
// default: serverReader := buf.NewReader(conn)
|
||||||
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons, trafficState, false, ctx, conn, input, rawInput, ob)
|
serverReader := encoding.DecodeBodyAddons(conn, request, responseAddons)
|
||||||
|
if requestAddons.Flow == vless.XRV {
|
||||||
|
serverReader = proxy.NewVisionReader(serverReader, trafficState, false, ctx)
|
||||||
|
}
|
||||||
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
|
if request.Command == protocol.RequestCommandMux && request.Port == 666 {
|
||||||
serverReader = xudp.NewPacketReader(&buf.BufferedReader{Reader: serverReader})
|
if requestAddons.Flow == vless.XRV {
|
||||||
|
serverReader = xudp.NewPacketReader(&buf.BufferedReader{Reader: serverReader})
|
||||||
|
} else {
|
||||||
|
serverReader = xudp.NewPacketReader(conn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if requestAddons.Flow == vless.XRV {
|
if requestAddons.Flow == vless.XRV {
|
||||||
err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, trafficState, false, ctx)
|
err = encoding.XtlsRead(serverReader, clientWriter, timer, conn, peerCache, input, rawInput, trafficState, ob, false, ctx)
|
||||||
} else {
|
} else {
|
||||||
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer
|
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBuffer
|
||||||
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
|
err = buf.Copy(serverReader, clientWriter, buf.UpdateActivity(timer))
|
||||||
|
|||||||
@@ -125,104 +125,6 @@ func TestVless(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVlessSeedWithIndependentScheduler(t *testing.T) {
|
|
||||||
tcpServer := tcp.Server{
|
|
||||||
MsgProcessor: xor,
|
|
||||||
}
|
|
||||||
dest, err := tcpServer.Start()
|
|
||||||
common.Must(err)
|
|
||||||
defer tcpServer.Close()
|
|
||||||
|
|
||||||
userID := protocol.NewID(uuid.New())
|
|
||||||
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(&inbound.Config{
|
|
||||||
Clients: []*protocol.User{
|
|
||||||
{
|
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
Seed: "1",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
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{
|
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
|
||||||
Port: uint32(dest.Port),
|
|
||||||
Networks: []net.Network{net.Network_TCP},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
|
||||||
Vnext: []*protocol.ServerEndpoint{
|
|
||||||
{
|
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
Port: uint32(serverPort),
|
|
||||||
User: []*protocol.User{
|
|
||||||
{
|
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
Seed: "1",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
|
|
||||||
common.Must(err)
|
|
||||||
defer CloseAllServers(servers)
|
|
||||||
|
|
||||||
var errg errgroup.Group
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
errg.Go(testTCPConn(clientPort, 1024*1024, time.Second*30))
|
|
||||||
}
|
|
||||||
if err := errg.Wait(); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVlessTls(t *testing.T) {
|
func TestVlessTls(t *testing.T) {
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
MsgProcessor: xor,
|
MsgProcessor: xor,
|
||||||
@@ -469,132 +371,6 @@ func TestVlessXtlsVision(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVlessXtlsVisionWithSeed(t *testing.T) {
|
|
||||||
tcpServer := tcp.Server{
|
|
||||||
MsgProcessor: xor,
|
|
||||||
}
|
|
||||||
dest, err := tcpServer.Start()
|
|
||||||
common.Must(err)
|
|
||||||
defer tcpServer.Close()
|
|
||||||
|
|
||||||
userID := protocol.NewID(uuid.New())
|
|
||||||
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),
|
|
||||||
StreamSettings: &internet.StreamConfig{
|
|
||||||
ProtocolName: "tcp",
|
|
||||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
|
||||||
SecuritySettings: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&tls.Config{
|
|
||||||
Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&inbound.Config{
|
|
||||||
Clients: []*protocol.User{
|
|
||||||
{
|
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
Flow: vless.XRV,
|
|
||||||
Seed: "1",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
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{
|
|
||||||
Address: net.NewIPOrDomain(dest.Address),
|
|
||||||
Port: uint32(dest.Port),
|
|
||||||
Networks: []net.Network{net.Network_TCP},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&outbound.Config{
|
|
||||||
Vnext: []*protocol.ServerEndpoint{
|
|
||||||
{
|
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
Port: uint32(serverPort),
|
|
||||||
User: []*protocol.User{
|
|
||||||
{
|
|
||||||
Account: serial.ToTypedMessage(&vless.Account{
|
|
||||||
Id: userID.String(),
|
|
||||||
Flow: vless.XRV,
|
|
||||||
Seed: "1",
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
|
||||||
StreamSettings: &internet.StreamConfig{
|
|
||||||
ProtocolName: "tcp",
|
|
||||||
TransportSettings: []*internet.TransportConfig{
|
|
||||||
{
|
|
||||||
ProtocolName: "tcp",
|
|
||||||
Settings: serial.ToTypedMessage(&transtcp.Config{}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
|
||||||
SecuritySettings: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&tls.Config{
|
|
||||||
AllowInsecure: true,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
servers, err := InitializeServerConfigs(serverConfig, clientConfig)
|
|
||||||
common.Must(err)
|
|
||||||
defer CloseAllServers(servers)
|
|
||||||
|
|
||||||
var errg errgroup.Group
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
errg.Go(testTCPConn(clientPort, 1024*1024, time.Second*30))
|
|
||||||
}
|
|
||||||
if err := errg.Wait(); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVlessXtlsVisionReality(t *testing.T) {
|
func TestVlessXtlsVisionReality(t *testing.T) {
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
MsgProcessor: xor,
|
MsgProcessor: xor,
|
||||||
|
|||||||
Reference in New Issue
Block a user