Explorar o código

re-enable vmess test

V2Ray %!s(int64=10) %!d(string=hai) anos
pai
achega
228e1eeabe
Modificáronse 11 ficheiros con 137 adicións e 68 borrados
  1. 51 0
      hash/id.go
  2. 15 0
      hash/int.go
  3. 5 51
      id.go
  4. 1 1
      io/socks/socks_test.go
  5. 19 0
      io/socks/udp.go
  6. 17 8
      io/vmess/vmess.go
  7. 8 5
      io/vmess/vmess_test.go
  8. 12 0
      math/rand.go
  9. 3 1
      net/vmess/vmessout.go
  10. 2 1
      testing/mocks/mockuserset.go
  11. 4 1
      userset.go

+ 51 - 0
hash/id.go

@@ -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),
+	}
+}

+ 15 - 0
hash/int.go

@@ -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)
+}

+ 5 - 51
id.go

@@ -1,11 +1,8 @@
 package core
 
 import (
-	"crypto/hmac"
 	"crypto/md5"
 	"encoding/hex"
-	mrand "math/rand"
-	"time"
 
 	"github.com/v2ray/v2ray-core/log"
 )
@@ -32,60 +29,17 @@ func NewID(id string) (ID, error) {
 	md5hash.Write([]byte("c48619fe-8f02-49e0-b9e9-edf763e17e21"))
 	cmdKey := md5.Sum(nil)
 
-	return ID{id, idBytes, cmdKey[:]}, nil
-}
-
-func (v ID) TimeRangeHash(rangeSec int) ([]byte, int64) {
-	nowSec := time.Now().UTC().Unix()
-	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)
+	return ID{
+		String: id,
+		Bytes:  idBytes,
+		cmdKey: cmdKey[:],
+	}, nil
 }
 
 func (v ID) CmdKey() []byte {
 	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}
 
 // TODO: leverage a full functional UUID library

+ 1 - 1
io/socks/socks_test.go

@@ -43,7 +43,7 @@ func TestAuthenticationResponseWrite(t *testing.T) {
 	response := NewAuthenticationResponse(byte(0x05))
 
 	buffer := bytes.NewBuffer(make([]byte, 0, 10))
-	WriteAuthentication(buffer, &response)
+	WriteAuthentication(buffer, response)
 	assert.Bytes(buffer.Bytes()).Equals([]byte{socksVersion, byte(0x05)})
 }
 

+ 19 - 0
io/socks/udp.go

@@ -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
+}

+ 17 - 8
io/vmess/vmess.go

@@ -10,10 +10,13 @@ import (
 	"fmt"
 	"io"
 	mrand "math/rand"
+	"time"
 
 	"github.com/v2ray/v2ray-core"
+	v2hash "github.com/v2ray/v2ray-core/hash"
 	v2io "github.com/v2ray/v2ray-core/io"
 	"github.com/v2ray/v2ray-core/log"
+	v2math "github.com/v2ray/v2ray-core/math"
 	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) {
-
 	buffer := make([]byte, 256)
 
 	nBytes, err := reader.Read(buffer[:core.IDBytesLen])
@@ -76,7 +78,7 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
 	if err != nil {
 		return nil, err
 	}
-	aesStream := cipher.NewCFBDecrypter(aesCipher, core.TimestampHash(timeSec))
+	aesStream := cipher.NewCFBDecrypter(aesCipher, v2hash.Int64Hash(timeSec))
 	decryptor := v2io.NewCryptionReader(aesStream, reader)
 
 	if err != nil {
@@ -180,18 +182,25 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
 }
 
 type VMessRequestWriter struct {
+	idHash           v2hash.CounterHash
+	randomRangeInt64 v2math.RandomInt64InRange
 }
 
-func NewVMessRequestWriter() *VMessRequestWriter {
-	return &VMessRequestWriter{}
+func NewVMessRequestWriter(idHash v2hash.CounterHash, randomRangeInt64 v2math.RandomInt64InRange) *VMessRequestWriter {
+	return &VMessRequestWriter{
+		idHash:           idHash,
+		randomRangeInt64: randomRangeInt64,
+	}
 }
 
 func (w *VMessRequestWriter) Write(writer io.Writer, request *VMessRequest) error {
 	buffer := make([]byte, 0, 300)
-	userHash, timeSec := request.UserId.TimeRangeHash(30)
 
-	log.Debug("Writing userhash: %v", userHash)
-	buffer = append(buffer, userHash...)
+	counter := w.randomRangeInt64(time.Now().UTC().Unix(), 30)
+	idHash := w.idHash.Hash(request.UserId.Bytes, counter)
+
+	log.Debug("Writing userhash: %v", idHash)
+	buffer = append(buffer, idHash...)
 
 	encryptionBegin := len(buffer)
 
@@ -241,7 +250,7 @@ func (w *VMessRequestWriter) Write(writer io.Writer, request *VMessRequest) erro
 	if err != nil {
 		return err
 	}
-	aesStream := cipher.NewCFBEncrypter(aesCipher, core.TimestampHash(timeSec))
+	aesStream := cipher.NewCFBEncrypter(aesCipher, v2hash.Int64Hash(counter))
 	cWriter := v2io.NewCryptionWriter(aesStream, writer)
 
 	_, err = writer.Write(buffer[0:encryptionBegin])

+ 8 - 5
io/vmess/vmess_test.go

@@ -7,13 +7,14 @@ import (
 	"testing"
 
 	"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"
 	"github.com/v2ray/v2ray-core/testing/mocks"
 	"github.com/v2ray/v2ray-core/testing/unit"
 )
 
 func TestVMessSerialization(t *testing.T) {
-	t.Skip()
 	assert := unit.Assert(t)
 
 	userId, err := core.NewID("2b2966ac-16aa-4fbf-8d81-c5f172a3da51")
@@ -21,7 +22,7 @@ func TestVMessSerialization(t *testing.T) {
 		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})
 
 	request := new(VMessRequest)
@@ -47,13 +48,15 @@ func TestVMessSerialization(t *testing.T) {
 	request.Address = v2net.DomainAddress("v2ray.com", 80)
 
 	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)
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	userSet.UserHashes[string(buffer.Bytes()[:16])] = 0
+	userSet.Timestamps[string(buffer.Bytes()[:16])] = mockTime
 
 	requestReader := NewVMessRequestReader(&userSet)
 	actualRequest, err := requestReader.Read(buffer)
@@ -72,7 +75,7 @@ func TestVMessSerialization(t *testing.T) {
 
 func BenchmarkVMessRequestWriting(b *testing.B) {
 	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})
 
 	request := new(VMessRequest)
@@ -86,7 +89,7 @@ func BenchmarkVMessRequestWriting(b *testing.B) {
 	request.Command = byte(0x01)
 	request.Address = v2net.DomainAddress("v2ray.com", 80)
 
-	requestWriter := NewVMessRequestWriter()
+	requestWriter := NewVMessRequestWriter(v2hash.NewTimeHash(v2hash.HMACHash{}), v2math.GenerateRandomInt64InRange)
 	for i := 0; i < b.N; i++ {
 		requestWriter.Write(ioutil.Discard, request)
 	}

+ 12 - 0
math/rand.go

@@ -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)
+}

+ 3 - 1
net/vmess/vmessout.go

@@ -7,9 +7,11 @@ import (
 	"net"
 
 	"github.com/v2ray/v2ray-core"
+	v2hash "github.com/v2ray/v2ray-core/hash"
 	v2io "github.com/v2ray/v2ray-core/io"
 	vmessio "github.com/v2ray/v2ray-core/io/vmess"
 	"github.com/v2ray/v2ray-core/log"
+	v2math "github.com/v2ray/v2ray-core/math"
 	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 {
 	defer close(finish)
-	requestWriter := vmessio.NewVMessRequestWriter()
+	requestWriter := vmessio.NewVMessRequestWriter(v2hash.NewTimeHash(v2hash.HMACHash{}), v2math.GenerateRandomInt64InRange)
 	err := requestWriter.Write(conn, request)
 	if err != nil {
 		log.Error("Failed to write VMess request: %v", err)

+ 2 - 1
testing/mocks/mockuserset.go

@@ -7,6 +7,7 @@ import (
 type MockUserSet struct {
 	UserIds    []core.ID
 	UserHashes map[string]int
+	Timestamps map[string]int64
 }
 
 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) {
 	idx, found := us.UserHashes[string(userhash)]
 	if found {
-		return &us.UserIds[idx], 1234, true
+		return &us.UserIds[idx], us.Timestamps[string(userhash)], true
 	}
 	return nil, 0, false
 }

+ 4 - 1
userset.go

@@ -2,6 +2,8 @@ package core
 
 import (
 	"time"
+
+	v2hash "github.com/v2ray/v2ray-core/hash"
 )
 
 const (
@@ -44,6 +46,7 @@ func (us *TimedUserSet) updateUserHash(tick <-chan time.Time) {
 
 	hash2Remove := make(chan hashEntry, cacheDurationSec*3*len(us.validUserIds))
 	lastSec2Remove := now.Unix()
+	idHash := v2hash.NewTimeHash(v2hash.HMACHash{})
 	for {
 		now := <-tick
 		nowSec := now.UTC().Unix()
@@ -59,7 +62,7 @@ func (us *TimedUserSet) updateUserHash(tick <-chan time.Time) {
 
 		for lastSec < nowSec+cacheDurationSec {
 			for idx, id := range us.validUserIds {
-				idHash := id.TimeHash(lastSec)
+				idHash := idHash.Hash(id.Bytes, lastSec)
 				hash2Remove <- hashEntry{string(idHash), lastSec}
 				us.userHashes[string(idHash)] = indexTimePair{idx, lastSec}
 			}