mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-19 16:30:07 +08:00
chore: ready for handwritten addons parsing
This commit is contained in:
parent
108bf645fa
commit
0d3d31dc5f
61
transport/vless/addons.go
Normal file
61
transport/vless/addons.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package vless
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ReadAddons(data []byte) (*Addons, error) {
|
||||||
|
reader := bytes.NewReader(data)
|
||||||
|
var addons Addons
|
||||||
|
for reader.Len() > 0 {
|
||||||
|
protoHeader, err := reader.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch protoHeader {
|
||||||
|
case (1 << 3) | 2:
|
||||||
|
flowLen, err := binary.ReadUvarint(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
flowBytes := make([]byte, flowLen)
|
||||||
|
_, err = io.ReadFull(reader, flowBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
addons.Flow = string(flowBytes)
|
||||||
|
case (2 << 3) | 2:
|
||||||
|
seedLen, err := binary.ReadUvarint(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
seedBytes := make([]byte, seedLen)
|
||||||
|
_, err = io.ReadFull(reader, seedBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
addons.Seed = seedBytes
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown protobuf message header: %v", protoHeader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &addons, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteAddons(addons *Addons) []byte {
|
||||||
|
var writer bytes.Buffer
|
||||||
|
if len(addons.Flow) > 0 {
|
||||||
|
writer.WriteByte((1 << 3) | 2)
|
||||||
|
writer.Write(binary.AppendUvarint(nil, uint64(len(addons.Flow))))
|
||||||
|
writer.WriteString(addons.Flow)
|
||||||
|
}
|
||||||
|
if len(addons.Seed) > 0 {
|
||||||
|
writer.WriteByte((2 << 3) | 2)
|
||||||
|
writer.Write(binary.AppendUvarint(nil, uint64(len(addons.Seed))))
|
||||||
|
writer.Write(addons.Seed)
|
||||||
|
}
|
||||||
|
return writer.Bytes()
|
||||||
|
}
|
||||||
95
transport/vless/addons_test.go
Normal file
95
transport/vless/addons_test.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package vless
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddons(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
flow string
|
||||||
|
seed []byte
|
||||||
|
}{
|
||||||
|
{XRV, nil},
|
||||||
|
{XRS, []byte{1, 2, 3}},
|
||||||
|
{"", []byte{1, 2, 3}},
|
||||||
|
{"", nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||||
|
t.Run("proto->handwritten", func(t *testing.T) {
|
||||||
|
addons := new(Addons)
|
||||||
|
addons.Flow = test.flow
|
||||||
|
addons.Seed = test.seed
|
||||||
|
|
||||||
|
addonsBytes, err := proto.Marshal(addons)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error marshalling addons: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addons, err = ReadAddons(addonsBytes)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error reading addons: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if addons.Flow != test.flow {
|
||||||
|
t.Errorf("got %v; want %v", addons.Flow, test.flow)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !bytes.Equal(addons.Seed, test.seed) {
|
||||||
|
t.Errorf("got %v; want %v", addons.Seed, test.seed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handwritten->proto", func(t *testing.T) {
|
||||||
|
addons := new(Addons)
|
||||||
|
addons.Flow = test.flow
|
||||||
|
addons.Seed = test.seed
|
||||||
|
|
||||||
|
addonsBytes := WriteAddons(addons)
|
||||||
|
err := proto.Unmarshal(addonsBytes, addons)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error reading addons: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if addons.Flow != test.flow {
|
||||||
|
t.Errorf("got %v; want %v", addons.Flow, test.flow)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !bytes.Equal(addons.Seed, test.seed) {
|
||||||
|
t.Errorf("got %v; want %v", addons.Seed, test.seed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("handwritten->handwritten", func(t *testing.T) {
|
||||||
|
addons := new(Addons)
|
||||||
|
addons.Flow = test.flow
|
||||||
|
addons.Seed = test.seed
|
||||||
|
|
||||||
|
addonsBytes := WriteAddons(addons)
|
||||||
|
addons, err := ReadAddons(addonsBytes)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error reading addons: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if addons.Flow != test.flow {
|
||||||
|
t.Errorf("got %v; want %v", addons.Flow, test.flow)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !bytes.Equal(addons.Seed, test.seed) {
|
||||||
|
t.Errorf("got %v; want %v", addons.Seed, test.seed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,6 @@ package vision
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/subtle"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -57,8 +56,8 @@ func (vc *Conn) Read(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
|
func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
|
||||||
toRead := buffer.FreeBytes()
|
|
||||||
if vc.readRemainingContent > 0 {
|
if vc.readRemainingContent > 0 {
|
||||||
|
toRead := buffer.FreeBytes()
|
||||||
if vc.readRemainingContent < buffer.FreeLen() {
|
if vc.readRemainingContent < buffer.FreeLen() {
|
||||||
toRead = toRead[:vc.readRemainingContent]
|
toRead = toRead[:vc.readRemainingContent]
|
||||||
}
|
}
|
||||||
@ -79,12 +78,12 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
|
|||||||
switch vc.readLastCommand {
|
switch vc.readLastCommand {
|
||||||
case commandPaddingContinue:
|
case commandPaddingContinue:
|
||||||
//if vc.isTLS || vc.packetsToFilter > 0 {
|
//if vc.isTLS || vc.packetsToFilter > 0 {
|
||||||
headerUUIDLen := 0
|
need := PaddingHeaderLen
|
||||||
if vc.readFilterUUID {
|
if !vc.readFilterUUID {
|
||||||
headerUUIDLen = uuid.Size
|
need = PaddingHeaderLen - uuid.Size
|
||||||
}
|
}
|
||||||
var header []byte
|
var header []byte
|
||||||
if need := headerUUIDLen + PaddingHeaderLen - uuid.Size; buffer.FreeLen() < need {
|
if buffer.FreeLen() < need {
|
||||||
header = make([]byte, need)
|
header = make([]byte, need)
|
||||||
} else {
|
} else {
|
||||||
header = buffer.FreeBytes()[:need]
|
header = buffer.FreeBytes()[:need]
|
||||||
@ -95,9 +94,8 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
|
|||||||
}
|
}
|
||||||
if vc.readFilterUUID {
|
if vc.readFilterUUID {
|
||||||
vc.readFilterUUID = false
|
vc.readFilterUUID = false
|
||||||
if subtle.ConstantTimeCompare(vc.userUUID.Bytes(), header[:uuid.Size]) != 1 {
|
if !bytes.Equal(vc.userUUID.Bytes(), header[:uuid.Size]) {
|
||||||
err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s",
|
err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", uuid.FromBytesOrNil(header[:uuid.Size]))
|
||||||
uuid.FromBytesOrNil(header[:uuid.Size]).String())
|
|
||||||
log.Errorln(err.Error())
|
log.Errorln(err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -180,7 +178,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) {
|
|||||||
for i, buffer := range buffers {
|
for i, buffer := range buffers {
|
||||||
command := commandPaddingContinue
|
command := commandPaddingContinue
|
||||||
if applyPadding {
|
if applyPadding {
|
||||||
if vc.isTLS && buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) {
|
if vc.isTLS && buffer.Len() > 6 && bytes.Equal(tlsApplicationDataStart, buffer.To(3)) {
|
||||||
command = commandPaddingEnd
|
command = commandPaddingEnd
|
||||||
if vc.enableXTLS {
|
if vc.enableXTLS {
|
||||||
command = commandPaddingDirect
|
command = commandPaddingDirect
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/common/buf"
|
"github.com/metacubex/mihomo/common/buf"
|
||||||
|
N "github.com/metacubex/mihomo/common/net"
|
||||||
"github.com/metacubex/mihomo/log"
|
"github.com/metacubex/mihomo/log"
|
||||||
N "github.com/metacubex/sing/common/network"
|
|
||||||
|
|
||||||
"github.com/gofrs/uuid/v5"
|
"github.com/gofrs/uuid/v5"
|
||||||
"github.com/metacubex/randv2"
|
"github.com/metacubex/randv2"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user