Skip to content

Commit 0d3d31d

Browse files
committed
chore: ready for handwritten addons parsing
1 parent 108bf64 commit 0d3d31d

File tree

4 files changed

+165
-11
lines changed

4 files changed

+165
-11
lines changed

transport/vless/addons.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package vless
2+
3+
import (
4+
"bytes"
5+
"encoding/binary"
6+
"fmt"
7+
"io"
8+
)
9+
10+
func ReadAddons(data []byte) (*Addons, error) {
11+
reader := bytes.NewReader(data)
12+
var addons Addons
13+
for reader.Len() > 0 {
14+
protoHeader, err := reader.ReadByte()
15+
if err != nil {
16+
return nil, err
17+
}
18+
switch protoHeader {
19+
case (1 << 3) | 2:
20+
flowLen, err := binary.ReadUvarint(reader)
21+
if err != nil {
22+
return nil, err
23+
}
24+
flowBytes := make([]byte, flowLen)
25+
_, err = io.ReadFull(reader, flowBytes)
26+
if err != nil {
27+
return nil, err
28+
}
29+
addons.Flow = string(flowBytes)
30+
case (2 << 3) | 2:
31+
seedLen, err := binary.ReadUvarint(reader)
32+
if err != nil {
33+
return nil, err
34+
}
35+
seedBytes := make([]byte, seedLen)
36+
_, err = io.ReadFull(reader, seedBytes)
37+
if err != nil {
38+
return nil, err
39+
}
40+
addons.Seed = seedBytes
41+
default:
42+
return nil, fmt.Errorf("unknown protobuf message header: %v", protoHeader)
43+
}
44+
}
45+
return &addons, nil
46+
}
47+
48+
func WriteAddons(addons *Addons) []byte {
49+
var writer bytes.Buffer
50+
if len(addons.Flow) > 0 {
51+
writer.WriteByte((1 << 3) | 2)
52+
writer.Write(binary.AppendUvarint(nil, uint64(len(addons.Flow))))
53+
writer.WriteString(addons.Flow)
54+
}
55+
if len(addons.Seed) > 0 {
56+
writer.WriteByte((2 << 3) | 2)
57+
writer.Write(binary.AppendUvarint(nil, uint64(len(addons.Seed))))
58+
writer.Write(addons.Seed)
59+
}
60+
return writer.Bytes()
61+
}

transport/vless/addons_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package vless
2+
3+
import (
4+
"bytes"
5+
"strconv"
6+
"testing"
7+
8+
"google.golang.org/protobuf/proto"
9+
)
10+
11+
func TestAddons(t *testing.T) {
12+
var tests = []struct {
13+
flow string
14+
seed []byte
15+
}{
16+
{XRV, nil},
17+
{XRS, []byte{1, 2, 3}},
18+
{"", []byte{1, 2, 3}},
19+
{"", nil},
20+
}
21+
22+
for i, test := range tests {
23+
t.Run(strconv.Itoa(i), func(t *testing.T) {
24+
t.Run("proto->handwritten", func(t *testing.T) {
25+
addons := new(Addons)
26+
addons.Flow = test.flow
27+
addons.Seed = test.seed
28+
29+
addonsBytes, err := proto.Marshal(addons)
30+
if err != nil {
31+
t.Errorf("error marshalling addons: %v", err)
32+
return
33+
}
34+
addons, err = ReadAddons(addonsBytes)
35+
if err != nil {
36+
t.Errorf("error reading addons: %v", err)
37+
return
38+
}
39+
40+
if addons.Flow != test.flow {
41+
t.Errorf("got %v; want %v", addons.Flow, test.flow)
42+
return
43+
}
44+
if !bytes.Equal(addons.Seed, test.seed) {
45+
t.Errorf("got %v; want %v", addons.Seed, test.seed)
46+
return
47+
}
48+
})
49+
50+
t.Run("handwritten->proto", func(t *testing.T) {
51+
addons := new(Addons)
52+
addons.Flow = test.flow
53+
addons.Seed = test.seed
54+
55+
addonsBytes := WriteAddons(addons)
56+
err := proto.Unmarshal(addonsBytes, addons)
57+
if err != nil {
58+
t.Errorf("error reading addons: %v", err)
59+
return
60+
}
61+
62+
if addons.Flow != test.flow {
63+
t.Errorf("got %v; want %v", addons.Flow, test.flow)
64+
return
65+
}
66+
if !bytes.Equal(addons.Seed, test.seed) {
67+
t.Errorf("got %v; want %v", addons.Seed, test.seed)
68+
return
69+
}
70+
})
71+
72+
t.Run("handwritten->handwritten", func(t *testing.T) {
73+
addons := new(Addons)
74+
addons.Flow = test.flow
75+
addons.Seed = test.seed
76+
77+
addonsBytes := WriteAddons(addons)
78+
addons, err := ReadAddons(addonsBytes)
79+
if err != nil {
80+
t.Errorf("error reading addons: %v", err)
81+
return
82+
}
83+
84+
if addons.Flow != test.flow {
85+
t.Errorf("got %v; want %v", addons.Flow, test.flow)
86+
return
87+
}
88+
if !bytes.Equal(addons.Seed, test.seed) {
89+
t.Errorf("got %v; want %v", addons.Seed, test.seed)
90+
return
91+
}
92+
})
93+
})
94+
}
95+
}

transport/vless/vision/conn.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package vision
22

33
import (
44
"bytes"
5-
"crypto/subtle"
65
"encoding/binary"
76
"errors"
87
"fmt"
@@ -57,8 +56,8 @@ func (vc *Conn) Read(b []byte) (int, error) {
5756
}
5857

5958
func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
60-
toRead := buffer.FreeBytes()
6159
if vc.readRemainingContent > 0 {
60+
toRead := buffer.FreeBytes()
6261
if vc.readRemainingContent < buffer.FreeLen() {
6362
toRead = toRead[:vc.readRemainingContent]
6463
}
@@ -79,12 +78,12 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
7978
switch vc.readLastCommand {
8079
case commandPaddingContinue:
8180
//if vc.isTLS || vc.packetsToFilter > 0 {
82-
headerUUIDLen := 0
83-
if vc.readFilterUUID {
84-
headerUUIDLen = uuid.Size
81+
need := PaddingHeaderLen
82+
if !vc.readFilterUUID {
83+
need = PaddingHeaderLen - uuid.Size
8584
}
8685
var header []byte
87-
if need := headerUUIDLen + PaddingHeaderLen - uuid.Size; buffer.FreeLen() < need {
86+
if buffer.FreeLen() < need {
8887
header = make([]byte, need)
8988
} else {
9089
header = buffer.FreeBytes()[:need]
@@ -95,9 +94,8 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
9594
}
9695
if vc.readFilterUUID {
9796
vc.readFilterUUID = false
98-
if subtle.ConstantTimeCompare(vc.userUUID.Bytes(), header[:uuid.Size]) != 1 {
99-
err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s",
100-
uuid.FromBytesOrNil(header[:uuid.Size]).String())
97+
if !bytes.Equal(vc.userUUID.Bytes(), header[:uuid.Size]) {
98+
err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", uuid.FromBytesOrNil(header[:uuid.Size]))
10199
log.Errorln(err.Error())
102100
return err
103101
}
@@ -180,7 +178,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) {
180178
for i, buffer := range buffers {
181179
command := commandPaddingContinue
182180
if applyPadding {
183-
if vc.isTLS && buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) {
181+
if vc.isTLS && buffer.Len() > 6 && bytes.Equal(tlsApplicationDataStart, buffer.To(3)) {
184182
command = commandPaddingEnd
185183
if vc.enableXTLS {
186184
command = commandPaddingDirect

transport/vless/vision/padding.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import (
55
"encoding/binary"
66

77
"github.com/metacubex/mihomo/common/buf"
8+
N "github.com/metacubex/mihomo/common/net"
89
"github.com/metacubex/mihomo/log"
9-
N "github.com/metacubex/sing/common/network"
1010

1111
"github.com/gofrs/uuid/v5"
1212
"github.com/metacubex/randv2"

0 commit comments

Comments
 (0)