You've already forked v2ray-core
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
294376edc0 | ||
|
|
2f721c4006 | ||
|
|
58dcfd5e84 | ||
|
|
bbc41c5e63 | ||
|
|
f474fc32a7 | ||
|
|
96c5d32d59 | ||
|
|
2c710d6b1c | ||
|
|
280c138cb4 | ||
|
|
462aa6f041 | ||
|
|
cf0e0b579b | ||
|
|
481c367154 | ||
|
|
401d61cb5f | ||
|
|
6fefaaaf5a | ||
|
|
30d7b39410 | ||
|
|
f44d270c88 | ||
|
|
c4ab202c11 | ||
|
|
9cd78bee07 |
@@ -27,7 +27,8 @@ deploy:
|
||||
- "$GOPATH/bin/v2ray-windows-32.zip"
|
||||
- "$GOPATH/bin/v2ray-linux-64.zip"
|
||||
- "$GOPATH/bin/v2ray-linux-32.zip"
|
||||
- "$GOPATH/bin/v2ray-armv6.zip"
|
||||
- "$GOPATH/bin/v2ray-linux-arm.zip"
|
||||
- "$GOPATH/bin/v2ray-linux-arm64.zip"
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
|
||||
@@ -124,7 +124,7 @@ func (p *bufferPool) cleanup(tick <-chan time.Time) {
|
||||
}
|
||||
}
|
||||
|
||||
var smallPool = newBufferPool(1024, 16, 64)
|
||||
var smallPool = newBufferPool(1024, 64, 512)
|
||||
var mediumPool = newBufferPool(8*1024, 256, 2048)
|
||||
var largePool = newBufferPool(64*1024, 128, 1024)
|
||||
|
||||
|
||||
@@ -17,6 +17,20 @@ func ReadFrom(reader io.Reader, buffer *alloc.Buffer) (*alloc.Buffer, error) {
|
||||
return buffer, err
|
||||
}
|
||||
|
||||
// ReadAllBytes reads all bytes required from reader, if no error happens.
|
||||
func ReadAllBytes(reader io.Reader, buffer []byte) (int, error) {
|
||||
bytesRead := 0
|
||||
bytesAsked := len(buffer)
|
||||
for bytesRead < bytesAsked {
|
||||
nBytes, err := reader.Read(buffer[bytesRead:])
|
||||
bytesRead += nBytes
|
||||
if err != nil {
|
||||
return bytesRead, err
|
||||
}
|
||||
}
|
||||
return bytesRead, nil
|
||||
}
|
||||
|
||||
// ReaderToChan dumps all content from a given reader to a chan by constantly reading it until EOF.
|
||||
func ReaderToChan(stream chan<- *alloc.Buffer, reader io.Reader) error {
|
||||
allocate := alloc.NewBuffer
|
||||
|
||||
2
core.go
2
core.go
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
version = "0.9"
|
||||
version = "0.10"
|
||||
build = "Custom"
|
||||
codename = "Post Apocalypse"
|
||||
intro = "A stable and unbreakable connection for everyone."
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/alloc"
|
||||
v2io "github.com/v2ray/v2ray-core/common/io"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
@@ -67,14 +68,14 @@ func NewVMessRequestReader(vUserSet user.UserSet) *VMessRequestReader {
|
||||
|
||||
// Read reads a VMessRequest from a byte stream.
|
||||
func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
|
||||
buffer := make([]byte, 256)
|
||||
buffer := alloc.NewSmallBuffer()
|
||||
|
||||
nBytes, err := reader.Read(buffer[:config.IDBytesLen])
|
||||
nBytes, err := v2net.ReadAllBytes(reader, buffer.Value[:config.IDBytesLen])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userId, timeSec, valid := r.vUserSet.GetUser(buffer[:nBytes])
|
||||
userId, timeSec, valid := r.vUserSet.GetUser(buffer.Value[:nBytes])
|
||||
if !valid {
|
||||
return nil, proxy.InvalidAuthentication
|
||||
}
|
||||
@@ -90,7 +91,7 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nBytes, err = decryptor.Read(buffer[:41])
|
||||
nBytes, err = v2net.ReadAllBytes(decryptor, buffer.Value[:41])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -98,7 +99,7 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
|
||||
|
||||
request := &VMessRequest{
|
||||
UserId: *userId,
|
||||
Version: buffer[0],
|
||||
Version: buffer.Value[0],
|
||||
}
|
||||
|
||||
if request.Version != Version {
|
||||
@@ -106,51 +107,51 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
|
||||
return nil, proxy.InvalidProtocolVersion
|
||||
}
|
||||
|
||||
request.RequestIV = buffer[1:17] // 16 bytes
|
||||
request.RequestKey = buffer[17:33] // 16 bytes
|
||||
request.ResponseHeader = buffer[33:37] // 4 bytes
|
||||
request.Command = buffer[37]
|
||||
request.RequestIV = buffer.Value[1:17] // 16 bytes
|
||||
request.RequestKey = buffer.Value[17:33] // 16 bytes
|
||||
request.ResponseHeader = buffer.Value[33:37] // 4 bytes
|
||||
request.Command = buffer.Value[37]
|
||||
|
||||
port := binary.BigEndian.Uint16(buffer[38:40])
|
||||
port := binary.BigEndian.Uint16(buffer.Value[38:40])
|
||||
|
||||
switch buffer[40] {
|
||||
switch buffer.Value[40] {
|
||||
case addrTypeIPv4:
|
||||
_, err = decryptor.Read(buffer[41:45]) // 4 bytes
|
||||
_, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:45]) // 4 bytes
|
||||
bufferLen += 4
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Address = v2net.IPAddress(buffer[41:45], port)
|
||||
request.Address = v2net.IPAddress(buffer.Value[41:45], port)
|
||||
case addrTypeIPv6:
|
||||
_, err = decryptor.Read(buffer[41:57]) // 16 bytes
|
||||
_, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:57]) // 16 bytes
|
||||
bufferLen += 16
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Address = v2net.IPAddress(buffer[41:57], port)
|
||||
request.Address = v2net.IPAddress(buffer.Value[41:57], port)
|
||||
case addrTypeDomain:
|
||||
_, err = decryptor.Read(buffer[41:42])
|
||||
_, err = v2net.ReadAllBytes(decryptor, buffer.Value[41:42])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainLength := int(buffer[41])
|
||||
_, err = decryptor.Read(buffer[42 : 42+domainLength])
|
||||
domainLength := int(buffer.Value[41])
|
||||
_, err = v2net.ReadAllBytes(decryptor, buffer.Value[42:42+domainLength])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bufferLen += 1 + domainLength
|
||||
request.Address = v2net.DomainAddress(string(buffer[42:42+domainLength]), port)
|
||||
request.Address = v2net.DomainAddress(string(buffer.Value[42:42+domainLength]), port)
|
||||
}
|
||||
|
||||
_, err = decryptor.Read(buffer[bufferLen : bufferLen+4])
|
||||
_, err = v2net.ReadAllBytes(decryptor, buffer.Value[bufferLen:bufferLen+4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fnv1a := fnv.New32a()
|
||||
fnv1a.Write(buffer[:bufferLen])
|
||||
fnv1a.Write(buffer.Value[:bufferLen])
|
||||
actualHash := fnv1a.Sum32()
|
||||
expectedHash := binary.BigEndian.Uint32(buffer[bufferLen : bufferLen+4])
|
||||
expectedHash := binary.BigEndian.Uint32(buffer.Value[bufferLen : bufferLen+4])
|
||||
|
||||
if actualHash != expectedHash {
|
||||
return nil, transport.CorruptedPacket
|
||||
@@ -160,48 +161,44 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
|
||||
}
|
||||
|
||||
// ToBytes returns a VMessRequest in the form of byte array.
|
||||
func (request *VMessRequest) ToBytes(idHash user.CounterHash, randomRangeInt64 user.RandomInt64InRange, buffer []byte) ([]byte, error) {
|
||||
func (request *VMessRequest) ToBytes(idHash user.CounterHash, randomRangeInt64 user.RandomInt64InRange, buffer *alloc.Buffer) (*alloc.Buffer, error) {
|
||||
if buffer == nil {
|
||||
buffer = make([]byte, 0, 300)
|
||||
buffer = alloc.NewSmallBuffer().Clear()
|
||||
}
|
||||
|
||||
counter := randomRangeInt64(time.Now().UTC().Unix(), 30)
|
||||
hash := idHash.Hash(request.UserId.Bytes[:], counter)
|
||||
|
||||
buffer = append(buffer, hash...)
|
||||
buffer.Append(hash)
|
||||
|
||||
encryptionBegin := len(buffer)
|
||||
encryptionBegin := buffer.Len()
|
||||
|
||||
buffer = append(buffer, request.Version)
|
||||
buffer = append(buffer, request.RequestIV...)
|
||||
buffer = append(buffer, request.RequestKey...)
|
||||
buffer = append(buffer, request.ResponseHeader...)
|
||||
buffer = append(buffer, request.Command)
|
||||
buffer = append(buffer, request.Address.PortBytes()...)
|
||||
buffer.AppendBytes(request.Version)
|
||||
buffer.Append(request.RequestIV)
|
||||
buffer.Append(request.RequestKey)
|
||||
buffer.Append(request.ResponseHeader)
|
||||
buffer.AppendBytes(request.Command)
|
||||
buffer.Append(request.Address.PortBytes())
|
||||
|
||||
switch {
|
||||
case request.Address.IsIPv4():
|
||||
buffer = append(buffer, addrTypeIPv4)
|
||||
buffer = append(buffer, request.Address.IP()...)
|
||||
buffer.AppendBytes(addrTypeIPv4)
|
||||
buffer.Append(request.Address.IP())
|
||||
case request.Address.IsIPv6():
|
||||
buffer = append(buffer, addrTypeIPv6)
|
||||
buffer = append(buffer, request.Address.IP()...)
|
||||
buffer.AppendBytes(addrTypeIPv6)
|
||||
buffer.Append(request.Address.IP())
|
||||
case request.Address.IsDomain():
|
||||
buffer = append(buffer, addrTypeDomain)
|
||||
buffer = append(buffer, byte(len(request.Address.Domain())))
|
||||
buffer = append(buffer, []byte(request.Address.Domain())...)
|
||||
buffer.AppendBytes(addrTypeDomain, byte(len(request.Address.Domain())))
|
||||
buffer.Append([]byte(request.Address.Domain()))
|
||||
}
|
||||
|
||||
encryptionEnd := len(buffer)
|
||||
encryptionEnd := buffer.Len()
|
||||
|
||||
fnv1a := fnv.New32a()
|
||||
fnv1a.Write(buffer[encryptionBegin:encryptionEnd])
|
||||
fnv1a.Write(buffer.Value[encryptionBegin:encryptionEnd])
|
||||
|
||||
fnvHash := fnv1a.Sum32()
|
||||
buffer = append(buffer, byte(fnvHash>>24))
|
||||
buffer = append(buffer, byte(fnvHash>>16))
|
||||
buffer = append(buffer, byte(fnvHash>>8))
|
||||
buffer = append(buffer, byte(fnvHash))
|
||||
buffer.AppendBytes(byte(fnvHash>>24), byte(fnvHash>>16), byte(fnvHash>>8), byte(fnvHash))
|
||||
encryptionEnd += 4
|
||||
|
||||
aesCipher, err := aes.NewCipher(request.UserId.CmdKey())
|
||||
@@ -209,7 +206,7 @@ func (request *VMessRequest) ToBytes(idHash user.CounterHash, randomRangeInt64 u
|
||||
return nil, err
|
||||
}
|
||||
aesStream := cipher.NewCFBEncrypter(aesCipher, user.Int64Hash(counter))
|
||||
aesStream.XORKeyStream(buffer[encryptionBegin:encryptionEnd], buffer[encryptionBegin:encryptionEnd])
|
||||
aesStream.XORKeyStream(buffer.Value[encryptionBegin:encryptionEnd], buffer.Value[encryptionBegin:encryptionEnd])
|
||||
|
||||
return buffer, nil
|
||||
}
|
||||
|
||||
@@ -46,16 +46,17 @@ func TestVMessSerialization(t *testing.T) {
|
||||
request.Address = v2net.DomainAddress("v2ray.com", 80)
|
||||
|
||||
mockTime := int64(1823730)
|
||||
|
||||
buffer, err := request.ToBytes(user.NewTimeHash(user.HMACHash{}), func(base int64, delta int) int64 { return mockTime }, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
userSet.UserHashes[string(buffer[:16])] = 0
|
||||
userSet.Timestamps[string(buffer[:16])] = mockTime
|
||||
userSet.UserHashes[string(buffer.Value[:16])] = 0
|
||||
userSet.Timestamps[string(buffer.Value[:16])] = mockTime
|
||||
|
||||
requestReader := NewVMessRequestReader(&userSet)
|
||||
actualRequest, err := requestReader.Read(bytes.NewReader(buffer))
|
||||
actualRequest, err := requestReader.Read(bytes.NewReader(buffer.Value))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func (handler *VMessInboundHandler) AcceptConnections(listener *net.TCPListener)
|
||||
func (handler *VMessInboundHandler) HandleConnection(connection *net.TCPConn) error {
|
||||
defer connection.Close()
|
||||
|
||||
connReader := v2net.NewTimeOutReader(120, connection)
|
||||
connReader := v2net.NewTimeOutReader(16, connection)
|
||||
requestReader := protocol.NewVMessRequestReader(handler.clients)
|
||||
|
||||
request, err := requestReader.Read(connReader)
|
||||
@@ -91,6 +91,7 @@ func (handler *VMessInboundHandler) HandleConnection(connection *net.TCPConn) er
|
||||
readFinish.Lock()
|
||||
writeFinish.Lock()
|
||||
|
||||
connReader.SetTimeOut(120)
|
||||
go handleInput(request, connReader, input, &readFinish)
|
||||
|
||||
responseKey := md5.Sum(request.RequestKey)
|
||||
|
||||
@@ -34,20 +34,22 @@ func (handler *VMessInboundHandler) ListenUDP(port uint16) error {
|
||||
|
||||
func (handler *VMessInboundHandler) AcceptPackets(conn *net.UDPConn) {
|
||||
for {
|
||||
buffer := make([]byte, bufferSize)
|
||||
nBytes, addr, err := conn.ReadFromUDP(buffer)
|
||||
buffer := alloc.NewBuffer()
|
||||
nBytes, addr, err := conn.ReadFromUDP(buffer.Value)
|
||||
if err != nil {
|
||||
log.Error("VMessIn failed to read UDP packets: %v", err)
|
||||
buffer.Release()
|
||||
continue
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(buffer[:nBytes])
|
||||
reader := bytes.NewReader(buffer.Value[:nBytes])
|
||||
requestReader := protocol.NewVMessRequestReader(handler.clients)
|
||||
|
||||
request, err := requestReader.Read(reader)
|
||||
if err != nil {
|
||||
log.Access(addr.String(), "", log.AccessRejected, err.Error())
|
||||
log.Warning("VMessIn: Invalid request from (%s): %v", addr.String(), err)
|
||||
buffer.Release()
|
||||
continue
|
||||
}
|
||||
log.Access(addr.String(), request.Address.String(), log.AccessAccepted, "")
|
||||
@@ -55,11 +57,13 @@ func (handler *VMessInboundHandler) AcceptPackets(conn *net.UDPConn) {
|
||||
cryptReader, err := v2io.NewAesDecryptReader(request.RequestKey, request.RequestIV, reader)
|
||||
if err != nil {
|
||||
log.Error("VMessIn: Failed to create decrypt reader: %v", err)
|
||||
buffer.Release()
|
||||
continue
|
||||
}
|
||||
|
||||
data := alloc.NewBuffer()
|
||||
nBytes, err = cryptReader.Read(data.Value)
|
||||
buffer.Release()
|
||||
if err != nil {
|
||||
log.Warning("VMessIn: Unable to decrypt data: %v", err)
|
||||
data.Release()
|
||||
|
||||
@@ -19,10 +19,6 @@ import (
|
||||
"github.com/v2ray/v2ray-core/transport/ray"
|
||||
)
|
||||
|
||||
const (
|
||||
InfoTimeNotSync = "Please check the User ID in your vmess configuration, and make sure the time on your local and remote server are in sync."
|
||||
)
|
||||
|
||||
type VMessOutboundHandler struct {
|
||||
vNextList []*config.OutboundTarget
|
||||
vNextListUDP []*config.OutboundTarget
|
||||
@@ -76,11 +72,12 @@ func (handler *VMessOutboundHandler) Dispatch(firstPacket v2net.Packet, ray ray.
|
||||
Address: firstPacket.Destination().Address(),
|
||||
}
|
||||
|
||||
buffer := make([]byte, 36) // 16 + 16 + 4
|
||||
rand.Read(buffer)
|
||||
request.RequestIV = buffer[:16]
|
||||
request.RequestKey = buffer[16:32]
|
||||
request.ResponseHeader = buffer[32:]
|
||||
buffer := alloc.NewSmallBuffer()
|
||||
defer buffer.Release()
|
||||
v2net.ReadAllBytes(rand.Reader, buffer.Value[:36]) // 16 + 16 + 4
|
||||
request.RequestIV = buffer.Value[:16]
|
||||
request.RequestKey = buffer.Value[16:32]
|
||||
request.ResponseHeader = buffer.Value[32:36]
|
||||
|
||||
return startCommunicate(request, vNextAddress, ray, firstPacket)
|
||||
}
|
||||
@@ -124,7 +121,7 @@ func handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2
|
||||
}
|
||||
|
||||
buffer := alloc.NewBuffer().Clear()
|
||||
requestBytes, err := request.ToBytes(user.NewTimeHash(user.HMACHash{}), user.GenerateRandomInt64InRange, buffer.Value)
|
||||
buffer, err = request.ToBytes(user.NewTimeHash(user.HMACHash{}), user.GenerateRandomInt64InRange, buffer)
|
||||
if err != nil {
|
||||
log.Error("VMessOut: Failed to serialize VMess request: %v", err)
|
||||
return
|
||||
@@ -140,10 +137,10 @@ func handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2
|
||||
|
||||
if firstChunk != nil {
|
||||
encryptRequestWriter.Crypt(firstChunk.Value)
|
||||
requestBytes = append(requestBytes, firstChunk.Value...)
|
||||
buffer.Append(firstChunk.Value)
|
||||
firstChunk.Release()
|
||||
|
||||
_, err = conn.Write(requestBytes)
|
||||
_, err = conn.Write(buffer.Value)
|
||||
buffer.Release()
|
||||
if err != nil {
|
||||
log.Error("VMessOut: Failed to write VMess request: %v", err)
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
"protocol": "socks", // 传入数据所用协议
|
||||
"settings": {
|
||||
"auth": "noauth", // 认证方式,暂时只支持匿名
|
||||
"udp": false // 如果要使用 UDP 转发,请改成 true
|
||||
"udp": false, // 如果要使用 UDP 转发,请改成 true
|
||||
"ip": "127.0.0.1" // 如果 Server A 不是运行在本地,请标明 Server A 的实际 IP 地址,否则 UDP 转发将无法进行。
|
||||
}
|
||||
},
|
||||
"outbound": {
|
||||
|
||||
@@ -1,34 +1,8 @@
|
||||
# V2Ray 开发计划
|
||||
|
||||
## 版本号
|
||||
V2Ray 的版本号形如 X.Y,其中 X 表示 Milestone,Y 表示 Release,如 2.3 表示第二个 Milestone 的第三个 Release。
|
||||
V2Ray 的版本号形如 X.Y.Z,其中 X 表示 Milestone,Y 表示 Release,如 2.3 表示第二个 Milestone 的第三个 Release;Z 仅作为修复紧急 Bug 之后的发布使用,一般不出现。
|
||||
|
||||
## 周期
|
||||
V2Ray 将在每周一发布一个 [Release](https://github.com/v2ray/v2ray-core/releases),每 12 周左右完成一个 Milestone。
|
||||
|
||||
## Milestones
|
||||
|
||||
### Milestone 0
|
||||
**目标:可用**
|
||||
|
||||
M0 将提供一个可用的 V2Ray Point Server,包含 Windows、Mac OS 和 Linux(Debian 为主)的预编译文件。主要功能和限制如下:
|
||||
* SOCKS 4 / 5 协议,仅提供 TCP 代理;
|
||||
* 使用自有 [VMess 协议](https://github.com/V2Ray/v2ray-core/blob/master/spec/vmess.md)做隧道;
|
||||
* 服务器端支持多用户;
|
||||
* 客户端支持多服务器,暂不支持负载平衡,多服务器时随机选择服务器;
|
||||
|
||||
### Milestone 1
|
||||
**目标:兼容**
|
||||
|
||||
M1 将完成在服务器端对兼容 Shadowsocks 和 GoAgent 协议的兼容,为用户提供多种选择。期望的功能如下:
|
||||
* SOCKS 协议的 UDP 代理;
|
||||
* 可选择路由,不必要的网站不使用代理;
|
||||
* WebSocket 代理;
|
||||
|
||||
### Milestone 2
|
||||
**目标:交互**
|
||||
|
||||
M2 将提供必要的 API 供第三方程序调用。主要功能如下:
|
||||
* 可以查询 V2Ray 进程的当前状态;
|
||||
* 可以远程和 V2Ray 进程通信并控制;
|
||||
* 可以动态管理用户和服务器列表;
|
||||
|
||||
@@ -12,10 +12,6 @@ func TestRevParse(t *testing.T) {
|
||||
rev, err := RevParse("HEAD")
|
||||
assert.Error(err).IsNil()
|
||||
assert.Int(len(rev)).GreaterThan(0)
|
||||
|
||||
rev, err = RevParse("v0.8")
|
||||
assert.Error(err).IsNil()
|
||||
assert.String(rev).Equals("de7a1d30c3e6bda6a1297b5815369fcfa0e74f0e")
|
||||
}
|
||||
|
||||
func TestRepoVersion(t *testing.T) {
|
||||
@@ -24,8 +20,4 @@ func TestRepoVersion(t *testing.T) {
|
||||
version, err := RepoVersionHead()
|
||||
assert.Error(err).IsNil()
|
||||
assert.Int(len(version)).GreaterThan(0)
|
||||
|
||||
version, err = RepoVersion("de7a1d30c3e6bda6a1297b5815369fcfa0e74f0e")
|
||||
assert.Error(err).IsNil()
|
||||
assert.String(version).Equals("v0.8")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user