mirror of https://github.com/v2ray/v2ray-core
re-enable vmess test
parent
8f93612dec
commit
228e1eeabe
|
@ -0,0 +1,51 @@
|
||||||
|
package hash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/md5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CounterHash interface {
|
||||||
|
Hash(key []byte, counter int64) []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type StringHash interface {
|
||||||
|
Hash(key []byte, data []byte) []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type TimeHash struct {
|
||||||
|
baseHash StringHash
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTimeHash(baseHash StringHash) CounterHash {
|
||||||
|
return TimeHash{
|
||||||
|
baseHash: baseHash,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h TimeHash) Hash(key []byte, counter int64) []byte {
|
||||||
|
counterBytes := int64ToBytes(counter)
|
||||||
|
return h.baseHash.Hash(key, counterBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
type HMACHash struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h HMACHash) Hash(key []byte, data []byte) []byte {
|
||||||
|
hash := hmac.New(md5.New, key)
|
||||||
|
hash.Write(data)
|
||||||
|
return hash.Sum(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func int64ToBytes(value int64) []byte {
|
||||||
|
return []byte{
|
||||||
|
byte(value >> 56),
|
||||||
|
byte(value >> 48),
|
||||||
|
byte(value >> 40),
|
||||||
|
byte(value >> 32),
|
||||||
|
byte(value >> 24),
|
||||||
|
byte(value >> 16),
|
||||||
|
byte(value >> 8),
|
||||||
|
byte(value),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package hash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Int64Hash(value int64) []byte {
|
||||||
|
md5hash := md5.New()
|
||||||
|
buffer := int64ToBytes(value)
|
||||||
|
md5hash.Write(buffer)
|
||||||
|
md5hash.Write(buffer)
|
||||||
|
md5hash.Write(buffer)
|
||||||
|
md5hash.Write(buffer)
|
||||||
|
return md5hash.Sum(nil)
|
||||||
|
}
|
56
id.go
56
id.go
|
@ -1,11 +1,8 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
mrand "math/rand"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/v2ray/v2ray-core/log"
|
"github.com/v2ray/v2ray-core/log"
|
||||||
)
|
)
|
||||||
|
@ -32,60 +29,17 @@ func NewID(id string) (ID, error) {
|
||||||
md5hash.Write([]byte("c48619fe-8f02-49e0-b9e9-edf763e17e21"))
|
md5hash.Write([]byte("c48619fe-8f02-49e0-b9e9-edf763e17e21"))
|
||||||
cmdKey := md5.Sum(nil)
|
cmdKey := md5.Sum(nil)
|
||||||
|
|
||||||
return ID{id, idBytes, cmdKey[:]}, nil
|
return ID{
|
||||||
}
|
String: id,
|
||||||
|
Bytes: idBytes,
|
||||||
func (v ID) TimeRangeHash(rangeSec int) ([]byte, int64) {
|
cmdKey: cmdKey[:],
|
||||||
nowSec := time.Now().UTC().Unix()
|
}, nil
|
||||||
delta := mrand.Intn(rangeSec*2) - rangeSec
|
|
||||||
|
|
||||||
targetSec := nowSec + int64(delta)
|
|
||||||
return v.TimeHash(targetSec), targetSec
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v ID) TimeHash(timeSec int64) []byte {
|
|
||||||
buffer := []byte{
|
|
||||||
byte(timeSec >> 56),
|
|
||||||
byte(timeSec >> 48),
|
|
||||||
byte(timeSec >> 40),
|
|
||||||
byte(timeSec >> 32),
|
|
||||||
byte(timeSec >> 24),
|
|
||||||
byte(timeSec >> 16),
|
|
||||||
byte(timeSec >> 8),
|
|
||||||
byte(timeSec),
|
|
||||||
}
|
|
||||||
return v.Hash(buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v ID) Hash(data []byte) []byte {
|
|
||||||
hasher := hmac.New(md5.New, v.Bytes)
|
|
||||||
hasher.Write(data)
|
|
||||||
return hasher.Sum(nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v ID) CmdKey() []byte {
|
func (v ID) CmdKey() []byte {
|
||||||
return v.cmdKey
|
return v.cmdKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func TimestampHash(timeSec int64) []byte {
|
|
||||||
md5hash := md5.New()
|
|
||||||
buffer := []byte{
|
|
||||||
byte(timeSec >> 56),
|
|
||||||
byte(timeSec >> 48),
|
|
||||||
byte(timeSec >> 40),
|
|
||||||
byte(timeSec >> 32),
|
|
||||||
byte(timeSec >> 24),
|
|
||||||
byte(timeSec >> 16),
|
|
||||||
byte(timeSec >> 8),
|
|
||||||
byte(timeSec),
|
|
||||||
}
|
|
||||||
md5hash.Write(buffer)
|
|
||||||
md5hash.Write(buffer)
|
|
||||||
md5hash.Write(buffer)
|
|
||||||
md5hash.Write(buffer)
|
|
||||||
return md5hash.Sum(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
var byteGroups = []int{8, 4, 4, 4, 12}
|
var byteGroups = []int{8, 4, 4, 4, 12}
|
||||||
|
|
||||||
// TODO: leverage a full functional UUID library
|
// TODO: leverage a full functional UUID library
|
||||||
|
|
|
@ -43,7 +43,7 @@ func TestAuthenticationResponseWrite(t *testing.T) {
|
||||||
response := NewAuthenticationResponse(byte(0x05))
|
response := NewAuthenticationResponse(byte(0x05))
|
||||||
|
|
||||||
buffer := bytes.NewBuffer(make([]byte, 0, 10))
|
buffer := bytes.NewBuffer(make([]byte, 0, 10))
|
||||||
WriteAuthentication(buffer, &response)
|
WriteAuthentication(buffer, response)
|
||||||
assert.Bytes(buffer.Bytes()).Equals([]byte{socksVersion, byte(0x05)})
|
assert.Bytes(buffer.Bytes()).Equals([]byte{socksVersion, byte(0x05)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package socks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
v2net "github.com/v2ray/v2ray-core/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Socks5UDPRequest struct {
|
||||||
|
fragment byte
|
||||||
|
address v2net.Address
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadUDPRequest(reader io.Reader) (request Socks5UDPRequest, err error) {
|
||||||
|
//buf := make([]byte, 4 * 1024) // Regular UDP packet size is 1500 bytes.
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -10,10 +10,13 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
mrand "math/rand"
|
mrand "math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/v2ray/v2ray-core"
|
"github.com/v2ray/v2ray-core"
|
||||||
|
v2hash "github.com/v2ray/v2ray-core/hash"
|
||||||
v2io "github.com/v2ray/v2ray-core/io"
|
v2io "github.com/v2ray/v2ray-core/io"
|
||||||
"github.com/v2ray/v2ray-core/log"
|
"github.com/v2ray/v2ray-core/log"
|
||||||
|
v2math "github.com/v2ray/v2ray-core/math"
|
||||||
v2net "github.com/v2ray/v2ray-core/net"
|
v2net "github.com/v2ray/v2ray-core/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -57,7 +60,6 @@ func NewVMessRequestReader(vUserSet core.UserSet) *VMessRequestReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
|
func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
|
||||||
|
|
||||||
buffer := make([]byte, 256)
|
buffer := make([]byte, 256)
|
||||||
|
|
||||||
nBytes, err := reader.Read(buffer[:core.IDBytesLen])
|
nBytes, err := reader.Read(buffer[:core.IDBytesLen])
|
||||||
|
@ -76,7 +78,7 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
aesStream := cipher.NewCFBDecrypter(aesCipher, core.TimestampHash(timeSec))
|
aesStream := cipher.NewCFBDecrypter(aesCipher, v2hash.Int64Hash(timeSec))
|
||||||
decryptor := v2io.NewCryptionReader(aesStream, reader)
|
decryptor := v2io.NewCryptionReader(aesStream, reader)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -180,18 +182,25 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type VMessRequestWriter struct {
|
type VMessRequestWriter struct {
|
||||||
|
idHash v2hash.CounterHash
|
||||||
|
randomRangeInt64 v2math.RandomInt64InRange
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVMessRequestWriter() *VMessRequestWriter {
|
func NewVMessRequestWriter(idHash v2hash.CounterHash, randomRangeInt64 v2math.RandomInt64InRange) *VMessRequestWriter {
|
||||||
return &VMessRequestWriter{}
|
return &VMessRequestWriter{
|
||||||
|
idHash: idHash,
|
||||||
|
randomRangeInt64: randomRangeInt64,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *VMessRequestWriter) Write(writer io.Writer, request *VMessRequest) error {
|
func (w *VMessRequestWriter) Write(writer io.Writer, request *VMessRequest) error {
|
||||||
buffer := make([]byte, 0, 300)
|
buffer := make([]byte, 0, 300)
|
||||||
userHash, timeSec := request.UserId.TimeRangeHash(30)
|
|
||||||
|
|
||||||
log.Debug("Writing userhash: %v", userHash)
|
counter := w.randomRangeInt64(time.Now().UTC().Unix(), 30)
|
||||||
buffer = append(buffer, userHash...)
|
idHash := w.idHash.Hash(request.UserId.Bytes, counter)
|
||||||
|
|
||||||
|
log.Debug("Writing userhash: %v", idHash)
|
||||||
|
buffer = append(buffer, idHash...)
|
||||||
|
|
||||||
encryptionBegin := len(buffer)
|
encryptionBegin := len(buffer)
|
||||||
|
|
||||||
|
@ -241,7 +250,7 @@ func (w *VMessRequestWriter) Write(writer io.Writer, request *VMessRequest) erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
aesStream := cipher.NewCFBEncrypter(aesCipher, core.TimestampHash(timeSec))
|
aesStream := cipher.NewCFBEncrypter(aesCipher, v2hash.Int64Hash(counter))
|
||||||
cWriter := v2io.NewCryptionWriter(aesStream, writer)
|
cWriter := v2io.NewCryptionWriter(aesStream, writer)
|
||||||
|
|
||||||
_, err = writer.Write(buffer[0:encryptionBegin])
|
_, err = writer.Write(buffer[0:encryptionBegin])
|
||||||
|
|
|
@ -7,13 +7,14 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/v2ray/v2ray-core"
|
"github.com/v2ray/v2ray-core"
|
||||||
|
v2hash "github.com/v2ray/v2ray-core/hash"
|
||||||
|
v2math "github.com/v2ray/v2ray-core/math"
|
||||||
v2net "github.com/v2ray/v2ray-core/net"
|
v2net "github.com/v2ray/v2ray-core/net"
|
||||||
"github.com/v2ray/v2ray-core/testing/mocks"
|
"github.com/v2ray/v2ray-core/testing/mocks"
|
||||||
"github.com/v2ray/v2ray-core/testing/unit"
|
"github.com/v2ray/v2ray-core/testing/unit"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestVMessSerialization(t *testing.T) {
|
func TestVMessSerialization(t *testing.T) {
|
||||||
t.Skip()
|
|
||||||
assert := unit.Assert(t)
|
assert := unit.Assert(t)
|
||||||
|
|
||||||
userId, err := core.NewID("2b2966ac-16aa-4fbf-8d81-c5f172a3da51")
|
userId, err := core.NewID("2b2966ac-16aa-4fbf-8d81-c5f172a3da51")
|
||||||
|
@ -21,7 +22,7 @@ func TestVMessSerialization(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
userSet := mocks.MockUserSet{[]core.ID{}, make(map[string]int)}
|
userSet := mocks.MockUserSet{[]core.ID{}, make(map[string]int), make(map[string]int64)}
|
||||||
userSet.AddUser(core.User{userId})
|
userSet.AddUser(core.User{userId})
|
||||||
|
|
||||||
request := new(VMessRequest)
|
request := new(VMessRequest)
|
||||||
|
@ -47,13 +48,15 @@ func TestVMessSerialization(t *testing.T) {
|
||||||
request.Address = v2net.DomainAddress("v2ray.com", 80)
|
request.Address = v2net.DomainAddress("v2ray.com", 80)
|
||||||
|
|
||||||
buffer := bytes.NewBuffer(make([]byte, 0, 300))
|
buffer := bytes.NewBuffer(make([]byte, 0, 300))
|
||||||
requestWriter := NewVMessRequestWriter()
|
mockTime := int64(1823730)
|
||||||
|
requestWriter := NewVMessRequestWriter(v2hash.NewTimeHash(v2hash.HMACHash{}), func(base int64, delta int) int64 { return mockTime })
|
||||||
err = requestWriter.Write(buffer, request)
|
err = requestWriter.Write(buffer, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
userSet.UserHashes[string(buffer.Bytes()[:16])] = 0
|
userSet.UserHashes[string(buffer.Bytes()[:16])] = 0
|
||||||
|
userSet.Timestamps[string(buffer.Bytes()[:16])] = mockTime
|
||||||
|
|
||||||
requestReader := NewVMessRequestReader(&userSet)
|
requestReader := NewVMessRequestReader(&userSet)
|
||||||
actualRequest, err := requestReader.Read(buffer)
|
actualRequest, err := requestReader.Read(buffer)
|
||||||
|
@ -72,7 +75,7 @@ func TestVMessSerialization(t *testing.T) {
|
||||||
|
|
||||||
func BenchmarkVMessRequestWriting(b *testing.B) {
|
func BenchmarkVMessRequestWriting(b *testing.B) {
|
||||||
userId, _ := core.NewID("2b2966ac-16aa-4fbf-8d81-c5f172a3da51")
|
userId, _ := core.NewID("2b2966ac-16aa-4fbf-8d81-c5f172a3da51")
|
||||||
userSet := mocks.MockUserSet{[]core.ID{}, make(map[string]int)}
|
userSet := mocks.MockUserSet{[]core.ID{}, make(map[string]int), make(map[string]int64)}
|
||||||
userSet.AddUser(core.User{userId})
|
userSet.AddUser(core.User{userId})
|
||||||
|
|
||||||
request := new(VMessRequest)
|
request := new(VMessRequest)
|
||||||
|
@ -86,7 +89,7 @@ func BenchmarkVMessRequestWriting(b *testing.B) {
|
||||||
request.Command = byte(0x01)
|
request.Command = byte(0x01)
|
||||||
request.Address = v2net.DomainAddress("v2ray.com", 80)
|
request.Address = v2net.DomainAddress("v2ray.com", 80)
|
||||||
|
|
||||||
requestWriter := NewVMessRequestWriter()
|
requestWriter := NewVMessRequestWriter(v2hash.NewTimeHash(v2hash.HMACHash{}), v2math.GenerateRandomInt64InRange)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
requestWriter.Write(ioutil.Discard, request)
|
requestWriter.Write(ioutil.Discard, request)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package math
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RandomInt64InRange func(base int64, delta int) int64
|
||||||
|
|
||||||
|
func GenerateRandomInt64InRange(base int64, delta int) int64 {
|
||||||
|
rangeInDelta := rand.Intn(delta*2) - delta
|
||||||
|
return base + int64(rangeInDelta)
|
||||||
|
}
|
|
@ -7,9 +7,11 @@ import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/v2ray/v2ray-core"
|
"github.com/v2ray/v2ray-core"
|
||||||
|
v2hash "github.com/v2ray/v2ray-core/hash"
|
||||||
v2io "github.com/v2ray/v2ray-core/io"
|
v2io "github.com/v2ray/v2ray-core/io"
|
||||||
vmessio "github.com/v2ray/v2ray-core/io/vmess"
|
vmessio "github.com/v2ray/v2ray-core/io/vmess"
|
||||||
"github.com/v2ray/v2ray-core/log"
|
"github.com/v2ray/v2ray-core/log"
|
||||||
|
v2math "github.com/v2ray/v2ray-core/math"
|
||||||
v2net "github.com/v2ray/v2ray-core/net"
|
v2net "github.com/v2ray/v2ray-core/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -94,7 +96,7 @@ func startCommunicate(request *vmessio.VMessRequest, dest v2net.Address, ray cor
|
||||||
|
|
||||||
func handleRequest(conn *net.TCPConn, request *vmessio.VMessRequest, input <-chan []byte, finish chan<- bool) error {
|
func handleRequest(conn *net.TCPConn, request *vmessio.VMessRequest, input <-chan []byte, finish chan<- bool) error {
|
||||||
defer close(finish)
|
defer close(finish)
|
||||||
requestWriter := vmessio.NewVMessRequestWriter()
|
requestWriter := vmessio.NewVMessRequestWriter(v2hash.NewTimeHash(v2hash.HMACHash{}), v2math.GenerateRandomInt64InRange)
|
||||||
err := requestWriter.Write(conn, request)
|
err := requestWriter.Write(conn, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to write VMess request: %v", err)
|
log.Error("Failed to write VMess request: %v", err)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
type MockUserSet struct {
|
type MockUserSet struct {
|
||||||
UserIds []core.ID
|
UserIds []core.ID
|
||||||
UserHashes map[string]int
|
UserHashes map[string]int
|
||||||
|
Timestamps map[string]int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *MockUserSet) AddUser(user core.User) error {
|
func (us *MockUserSet) AddUser(user core.User) error {
|
||||||
|
@ -17,7 +18,7 @@ func (us *MockUserSet) AddUser(user core.User) error {
|
||||||
func (us *MockUserSet) GetUser(userhash []byte) (*core.ID, int64, bool) {
|
func (us *MockUserSet) GetUser(userhash []byte) (*core.ID, int64, bool) {
|
||||||
idx, found := us.UserHashes[string(userhash)]
|
idx, found := us.UserHashes[string(userhash)]
|
||||||
if found {
|
if found {
|
||||||
return &us.UserIds[idx], 1234, true
|
return &us.UserIds[idx], us.Timestamps[string(userhash)], true
|
||||||
}
|
}
|
||||||
return nil, 0, false
|
return nil, 0, false
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
v2hash "github.com/v2ray/v2ray-core/hash"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -44,6 +46,7 @@ func (us *TimedUserSet) updateUserHash(tick <-chan time.Time) {
|
||||||
|
|
||||||
hash2Remove := make(chan hashEntry, cacheDurationSec*3*len(us.validUserIds))
|
hash2Remove := make(chan hashEntry, cacheDurationSec*3*len(us.validUserIds))
|
||||||
lastSec2Remove := now.Unix()
|
lastSec2Remove := now.Unix()
|
||||||
|
idHash := v2hash.NewTimeHash(v2hash.HMACHash{})
|
||||||
for {
|
for {
|
||||||
now := <-tick
|
now := <-tick
|
||||||
nowSec := now.UTC().Unix()
|
nowSec := now.UTC().Unix()
|
||||||
|
@ -59,7 +62,7 @@ func (us *TimedUserSet) updateUserHash(tick <-chan time.Time) {
|
||||||
|
|
||||||
for lastSec < nowSec+cacheDurationSec {
|
for lastSec < nowSec+cacheDurationSec {
|
||||||
for idx, id := range us.validUserIds {
|
for idx, id := range us.validUserIds {
|
||||||
idHash := id.TimeHash(lastSec)
|
idHash := idHash.Hash(id.Bytes, lastSec)
|
||||||
hash2Remove <- hashEntry{string(idHash), lastSec}
|
hash2Remove <- hashEntry{string(idHash), lastSec}
|
||||||
us.userHashes[string(idHash)] = indexTimePair{idx, lastSec}
|
us.userHashes[string(idHash)] = indexTimePair{idx, lastSec}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue