mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-12-24 13:27:56 +08:00
令vmess可用,已经过验证,添加vmess.client.toml配置文件
This commit is contained in:
12
examples/vmess.client.toml
Normal file
12
examples/vmess.client.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[[listen]]
|
||||
protocol = "socks5"
|
||||
host = "127.0.0.1"
|
||||
port = 10800
|
||||
|
||||
|
||||
[[dial]]
|
||||
protocol = "vmess"
|
||||
uuid = "a684455c-b14f-11ea-bf0d-42010aaa0003"
|
||||
host = "127.0.0.1"
|
||||
port = 4434
|
||||
extra = { vmess_security = "aes-128-gcm" }
|
||||
1
main.go
1
main.go
@@ -29,6 +29,7 @@ import (
|
||||
_ "github.com/e1732a364fed/v2ray_simple/proxy/socks5http"
|
||||
_ "github.com/e1732a364fed/v2ray_simple/proxy/trojan"
|
||||
_ "github.com/e1732a364fed/v2ray_simple/proxy/vless"
|
||||
_ "github.com/e1732a364fed/v2ray_simple/proxy/vmess"
|
||||
)
|
||||
|
||||
//statistics
|
||||
|
||||
@@ -3,8 +3,8 @@ package vmess
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash/fnv"
|
||||
@@ -67,6 +67,7 @@ func (ClientCreator) NewClient(dc *proxy.DialConf) (proxy.Client, error) {
|
||||
if err = c.specifySecurityByStr(str); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,20 +122,28 @@ func (c *Client) commonHandshake(underlay net.Conn, firstPayload []byte, target
|
||||
conn.addr, conn.atyp = target.AddressBytes()
|
||||
conn.port = uint16(target.Port)
|
||||
|
||||
randBytes := utils.GetBytes(32)
|
||||
randBytes := utils.GetBytes(33)
|
||||
rand.Read(randBytes)
|
||||
copy(conn.reqBodyIV[:], randBytes[:16])
|
||||
copy(conn.reqBodyKey[:], randBytes[16:32])
|
||||
utils.PutBytes(randBytes)
|
||||
conn.reqRespV = byte(rand.Intn(1 << 8))
|
||||
conn.respBodyIV = md5.Sum(conn.reqBodyIV[:])
|
||||
conn.respBodyKey = md5.Sum(conn.reqBodyKey[:])
|
||||
conn.reqRespV = randBytes[32]
|
||||
|
||||
//non-aead
|
||||
//conn.respBodyIV = md5.Sum(conn.reqBodyIV[:])
|
||||
//conn.respBodyKey = md5.Sum(conn.reqBodyKey[:])
|
||||
|
||||
bodyKey := sha256.Sum256(conn.reqBodyKey[:])
|
||||
bodyIV := sha256.Sum256(conn.reqBodyIV[:])
|
||||
copy(conn.respBodyKey[:], bodyKey[:16])
|
||||
copy(conn.respBodyIV[:], bodyIV[:16])
|
||||
|
||||
// Auth
|
||||
err := conn.auth()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//err := conn.non_aead_auth()
|
||||
//if err != nil {
|
||||
// return nil, err
|
||||
//}
|
||||
var err error
|
||||
|
||||
// Request
|
||||
if target.IsUDP() {
|
||||
@@ -145,11 +154,15 @@ func (c *Client) commonHandshake(underlay net.Conn, firstPayload []byte, target
|
||||
err = conn.handshake(CmdTCP)
|
||||
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(firstPayload) > 0 {
|
||||
_, err = conn.Write(firstPayload)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// ClientConn is a connection to vmess server
|
||||
@@ -188,7 +201,7 @@ func (c *ClientConn) Fullcone() bool {
|
||||
func (c *ClientConn) ReadMsgFrom() (bs []byte, target netLayer.Addr, err error) {
|
||||
bs = utils.GetPacket()
|
||||
var n int
|
||||
n, err = c.Conn.Read(bs)
|
||||
n, err = c.Read(bs)
|
||||
if err != nil {
|
||||
utils.PutPacket(bs)
|
||||
bs = nil
|
||||
@@ -204,20 +217,6 @@ func (c *ClientConn) WriteMsgTo(b []byte, _ netLayer.Addr) error {
|
||||
return e
|
||||
}
|
||||
|
||||
// send auth info: HMAC("md5", UUID, UTC)
|
||||
func (c *ClientConn) auth() error {
|
||||
ts := utils.GetBytes(8)
|
||||
defer utils.PutBytes(ts)
|
||||
|
||||
binary.BigEndian.PutUint64(ts, uint64(time.Now().UTC().Unix()))
|
||||
|
||||
h := hmac.New(md5.New, c.user.IdentityBytes())
|
||||
h.Write(ts)
|
||||
|
||||
_, err := c.Conn.Write(h.Sum(nil))
|
||||
return err
|
||||
}
|
||||
|
||||
// handshake sends request to server.
|
||||
func (c *ClientConn) handshake(cmd byte) error {
|
||||
buf := utils.GetBuf()
|
||||
@@ -264,45 +263,68 @@ func (c *ClientConn) handshake(cmd byte) error {
|
||||
buf.Write(fnv1a.Sum(nil))
|
||||
|
||||
// log.Printf("Request Send %v", buf.Bytes())
|
||||
/*
|
||||
//non-aead procedure
|
||||
|
||||
block, err := aes.NewCipher(GetKey(c.user))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
block, err := aes.NewCipher(GetKey(c.user))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, TimestampHash(time.Now().UTC().Unix()))
|
||||
stream.XORKeyStream(buf.Bytes(), buf.Bytes())
|
||||
|
||||
_, err = c.Conn.Write(buf.Bytes())
|
||||
stream := cipher.NewCFBEncrypter(block, TimestampHash(time.Now().UTC().Unix()))
|
||||
stream.XORKeyStream(buf.Bytes(), buf.Bytes())
|
||||
*/
|
||||
|
||||
var fixedLengthCmdKey [16]byte
|
||||
copy(fixedLengthCmdKey[:], GetKey(c.user))
|
||||
vmessout := sealVMessAEADHeader(fixedLengthCmdKey, buf.Bytes(), time.Now())
|
||||
_, err = c.Conn.Write(vmessout)
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
// DecodeRespHeader decodes response header.
|
||||
func (c *ClientConn) DecodeRespHeader() error {
|
||||
block, err := aes.NewCipher(c.respBodyKey[:])
|
||||
func (vc *ClientConn) aead_decodeRespHeader() error {
|
||||
var buf []byte
|
||||
aeadResponseHeaderLengthEncryptionKey := kdf(vc.respBodyKey[:], kdfSaltConstAEADRespHeaderLenKey)[:16]
|
||||
aeadResponseHeaderLengthEncryptionIV := kdf(vc.respBodyIV[:], kdfSaltConstAEADRespHeaderLenIV)[:12]
|
||||
|
||||
aeadResponseHeaderLengthEncryptionKeyAESBlock, _ := aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)
|
||||
aeadResponseHeaderLengthEncryptionAEAD, _ := cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)
|
||||
|
||||
aeadEncryptedResponseHeaderLength := make([]byte, 18)
|
||||
if _, err := io.ReadFull(vc.Conn, aeadEncryptedResponseHeaderLength); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
decryptedResponseHeaderLengthBinaryBuffer, err := aeadResponseHeaderLengthEncryptionAEAD.Open(nil, aeadResponseHeaderLengthEncryptionIV, aeadEncryptedResponseHeaderLength[:], nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
decryptedResponseHeaderLength := binary.BigEndian.Uint16(decryptedResponseHeaderLengthBinaryBuffer)
|
||||
aeadResponseHeaderPayloadEncryptionKey := kdf(vc.respBodyKey[:], kdfSaltConstAEADRespHeaderPayloadKey)[:16]
|
||||
aeadResponseHeaderPayloadEncryptionIV := kdf(vc.respBodyIV[:], kdfSaltConstAEADRespHeaderPayloadIV)[:12]
|
||||
aeadResponseHeaderPayloadEncryptionKeyAESBlock, _ := aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)
|
||||
aeadResponseHeaderPayloadEncryptionAEAD, _ := cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)
|
||||
|
||||
encryptedResponseHeaderBuffer := make([]byte, decryptedResponseHeaderLength+16)
|
||||
if _, err := io.ReadFull(vc.Conn, encryptedResponseHeaderBuffer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf, err = aeadResponseHeaderPayloadEncryptionAEAD.Open(nil, aeadResponseHeaderPayloadEncryptionIV, encryptedResponseHeaderBuffer, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, c.respBodyIV[:])
|
||||
|
||||
b := utils.GetBytes(4)
|
||||
defer utils.PutBytes(b)
|
||||
|
||||
_, err = io.ReadFull(c.Conn, b)
|
||||
if err != nil {
|
||||
return err
|
||||
if len(buf) < 4 {
|
||||
return errors.New("unexpected buffer length")
|
||||
}
|
||||
|
||||
stream.XORKeyStream(b, b)
|
||||
|
||||
if b[0] != c.reqRespV {
|
||||
if buf[0] != vc.reqRespV {
|
||||
return errors.New("unexpected response header")
|
||||
}
|
||||
|
||||
if b[2] != 0 {
|
||||
// dataLen := int32(buf[3])
|
||||
if buf[2] != 0 {
|
||||
return errors.New("dynamic port is not supported now")
|
||||
}
|
||||
|
||||
@@ -345,7 +367,8 @@ func (c *ClientConn) Read(b []byte) (n int, err error) {
|
||||
return c.dataReader.Read(b)
|
||||
}
|
||||
|
||||
err = c.DecodeRespHeader()
|
||||
err = c.aead_decodeRespHeader()
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
58
proxy/vmess/deprecated.go
Normal file
58
proxy/vmess/deprecated.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package vmess
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||||
)
|
||||
|
||||
//Deprecated: send non_aead_auth info: HMAC("md5", UUID, UTC)
|
||||
func (c *ClientConn) non_aead_auth() error {
|
||||
ts := utils.GetBytes(8)
|
||||
defer utils.PutBytes(ts)
|
||||
|
||||
binary.BigEndian.PutUint64(ts, uint64(time.Now().UTC().Unix()))
|
||||
|
||||
h := hmac.New(md5.New, c.user.IdentityBytes())
|
||||
h.Write(ts)
|
||||
|
||||
_, err := c.Conn.Write(h.Sum(nil))
|
||||
return err
|
||||
}
|
||||
|
||||
//Deprecated: non_aead is depreated
|
||||
func (c *ClientConn) non_aead_decodeRespHeader() error {
|
||||
block, err := aes.NewCipher(c.respBodyKey[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, c.respBodyIV[:])
|
||||
|
||||
b := utils.GetBytes(4)
|
||||
defer utils.PutBytes(b)
|
||||
|
||||
_, err = io.ReadFull(c.Conn, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stream.XORKeyStream(b, b)
|
||||
|
||||
if b[0] != c.reqRespV {
|
||||
return errors.New("unexpected response header")
|
||||
}
|
||||
|
||||
if b[2] != 0 {
|
||||
return errors.New("dynamic port is not supported now")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
103
proxy/vmess/header.go
Normal file
103
proxy/vmess/header.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package vmess
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
kdfSaltConstAuthIDEncryptionKey = "AES Auth ID Encryption"
|
||||
kdfSaltConstAEADRespHeaderLenKey = "AEAD Resp Header Len Key"
|
||||
kdfSaltConstAEADRespHeaderLenIV = "AEAD Resp Header Len IV"
|
||||
kdfSaltConstAEADRespHeaderPayloadKey = "AEAD Resp Header Key"
|
||||
kdfSaltConstAEADRespHeaderPayloadIV = "AEAD Resp Header IV"
|
||||
kdfSaltConstVMessAEADKDF = "VMess AEAD KDF"
|
||||
kdfSaltConstVMessHeaderPayloadAEADKey = "VMess Header AEAD Key"
|
||||
kdfSaltConstVMessHeaderPayloadAEADIV = "VMess Header AEAD Nonce"
|
||||
kdfSaltConstVMessHeaderPayloadLengthAEADKey = "VMess Header AEAD Key_Length"
|
||||
kdfSaltConstVMessHeaderPayloadLengthAEADIV = "VMess Header AEAD Nonce_Length"
|
||||
)
|
||||
|
||||
func kdf(key []byte, path ...string) []byte {
|
||||
hmacCreator := &hMacCreator{value: []byte(kdfSaltConstVMessAEADKDF)}
|
||||
for _, v := range path {
|
||||
hmacCreator = &hMacCreator{value: []byte(v), parent: hmacCreator}
|
||||
}
|
||||
hmacf := hmacCreator.Create()
|
||||
hmacf.Write(key)
|
||||
return hmacf.Sum(nil)
|
||||
}
|
||||
|
||||
type hMacCreator struct {
|
||||
parent *hMacCreator
|
||||
value []byte
|
||||
}
|
||||
|
||||
func (h *hMacCreator) Create() hash.Hash {
|
||||
if h.parent == nil {
|
||||
return hmac.New(sha256.New, h.value)
|
||||
}
|
||||
return hmac.New(h.parent.Create, h.value)
|
||||
}
|
||||
|
||||
func createAuthID(cmdKey []byte, time int64) [16]byte {
|
||||
buf := &bytes.Buffer{}
|
||||
binary.Write(buf, binary.BigEndian, time)
|
||||
|
||||
random := make([]byte, 4)
|
||||
rand.Read(random)
|
||||
buf.Write(random)
|
||||
zero := crc32.ChecksumIEEE(buf.Bytes())
|
||||
binary.Write(buf, binary.BigEndian, zero)
|
||||
|
||||
aesBlock, _ := aes.NewCipher(kdf(cmdKey[:], kdfSaltConstAuthIDEncryptionKey)[:16])
|
||||
var result [16]byte
|
||||
aesBlock.Encrypt(result[:], buf.Bytes())
|
||||
return result
|
||||
}
|
||||
|
||||
func sealVMessAEADHeader(key [16]byte, data []byte, t time.Time) []byte {
|
||||
generatedAuthID := createAuthID(key[:], t.Unix())
|
||||
connectionNonce := make([]byte, 8)
|
||||
rand.Read(connectionNonce)
|
||||
|
||||
aeadPayloadLengthSerializedByte := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(aeadPayloadLengthSerializedByte, uint16(len(data)))
|
||||
|
||||
var payloadHeaderLengthAEADEncrypted []byte
|
||||
|
||||
{
|
||||
payloadHeaderLengthAEADKey := kdf(key[:], kdfSaltConstVMessHeaderPayloadLengthAEADKey, string(generatedAuthID[:]), string(connectionNonce))[:16]
|
||||
payloadHeaderLengthAEADNonce := kdf(key[:], kdfSaltConstVMessHeaderPayloadLengthAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]
|
||||
payloadHeaderLengthAEADAESBlock, _ := aes.NewCipher(payloadHeaderLengthAEADKey)
|
||||
payloadHeaderAEAD, _ := cipher.NewGCM(payloadHeaderLengthAEADAESBlock)
|
||||
payloadHeaderLengthAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderLengthAEADNonce, aeadPayloadLengthSerializedByte, generatedAuthID[:])
|
||||
}
|
||||
|
||||
var payloadHeaderAEADEncrypted []byte
|
||||
|
||||
{
|
||||
payloadHeaderAEADKey := kdf(key[:], kdfSaltConstVMessHeaderPayloadAEADKey, string(generatedAuthID[:]), string(connectionNonce))[:16]
|
||||
payloadHeaderAEADNonce := kdf(key[:], kdfSaltConstVMessHeaderPayloadAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]
|
||||
payloadHeaderAEADAESBlock, _ := aes.NewCipher(payloadHeaderAEADKey)
|
||||
payloadHeaderAEAD, _ := cipher.NewGCM(payloadHeaderAEADAESBlock)
|
||||
payloadHeaderAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:])
|
||||
}
|
||||
|
||||
outputBuffer := &bytes.Buffer{}
|
||||
|
||||
outputBuffer.Write(generatedAuthID[:])
|
||||
outputBuffer.Write(payloadHeaderLengthAEADEncrypted)
|
||||
outputBuffer.Write(connectionNonce)
|
||||
outputBuffer.Write(payloadHeaderAEADEncrypted)
|
||||
|
||||
return outputBuffer.Bytes()
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Package tlsLayer provides facilities for tls, including sniffing.
|
||||
Package tlsLayer provides facilities for tls, including uTls, sniffing and random certificate.
|
||||
*/
|
||||
package tlsLayer
|
||||
|
||||
|
||||
Reference in New Issue
Block a user