vmess: support alterID

This commit is contained in:
nadoo 2018-07-03 14:30:56 +08:00
parent 14cded4665
commit f6fae13d88
3 changed files with 95 additions and 51 deletions

View File

@ -40,7 +40,14 @@ const (
// Client vmess client // Client vmess client
type Client struct { type Client struct {
user *User users []*User
count int
}
// Conn is a connection to vmess server
type Conn struct {
user *User
atype AType atype AType
addr Addr addr Addr
port Port port Port
@ -56,15 +63,28 @@ type Client struct {
} }
// NewClient . // NewClient .
func NewClient(uuid, target string) (*Client, error) { func NewClient(uuidStr string, alterID int) (*Client, error) {
user, err := NewUser(uuid) uuid, err := StrToUUID(uuidStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
c := &Client{user: user} c := &Client{}
user := NewUser(uuid)
c.users = append(c.users, user)
c.users = append(c.users, user.GenAlterIDUsers(alterID)...)
c.count = len(c.users)
c.atype, c.addr, c.port, err = ParseAddr(target) return c, nil
}
// NewConn .
func (c *Client) NewConn(rc net.Conn, target string) (*Conn, error) {
r := rand.Intn(c.count)
conn := &Conn{user: c.users[r]}
var err error
conn.atype, conn.addr, conn.port, err = ParseAddr(target)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -72,18 +92,30 @@ func NewClient(uuid, target string) (*Client, error) {
randBytes := make([]byte, 33) randBytes := make([]byte, 33)
rand.Read(randBytes) rand.Read(randBytes)
copy(c.reqBodyIV[:], randBytes[:16]) copy(conn.reqBodyIV[:], randBytes[:16])
copy(c.reqBodyKey[:], randBytes[16:32]) copy(conn.reqBodyKey[:], randBytes[16:32])
c.reqRespV = randBytes[32] conn.reqRespV = randBytes[32]
c.respBodyIV = md5.Sum(c.reqBodyIV[:]) conn.respBodyIV = md5.Sum(conn.reqBodyIV[:])
c.respBodyKey = md5.Sum(c.reqBodyKey[:]) conn.respBodyKey = md5.Sum(conn.reqBodyKey[:])
return c, nil // AuthInfo
rc.Write(conn.EncodeAuthInfo())
// Request
req, err := conn.EncodeRequest()
if err != nil {
return nil, err
}
rc.Write(req)
conn.Conn = rc
return conn, nil
} }
// EncodeAuthInfo returns HMAC("md5", UUID, UTC) result // EncodeAuthInfo returns HMAC("md5", UUID, UTC) result
func (c *Client) EncodeAuthInfo() []byte { func (c *Conn) EncodeAuthInfo() []byte {
ts := make([]byte, 8) ts := make([]byte, 8)
binary.BigEndian.PutUint64(ts, uint64(time.Now().UTC().Unix())) binary.BigEndian.PutUint64(ts, uint64(time.Now().UTC().Unix()))
@ -94,7 +126,7 @@ func (c *Client) EncodeAuthInfo() []byte {
} }
// EncodeRequest encodes requests to network bytes // EncodeRequest encodes requests to network bytes
func (c *Client) EncodeRequest() ([]byte, error) { func (c *Conn) EncodeRequest() ([]byte, error) {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
// Request // Request
@ -141,7 +173,7 @@ func (c *Client) EncodeRequest() ([]byte, error) {
} }
// DecodeRespHeader . // DecodeRespHeader .
func (c *Client) DecodeRespHeader() error { func (c *Conn) DecodeRespHeader() error {
block, err := aes.NewCipher(c.respBodyKey[:]) block, err := aes.NewCipher(c.respBodyKey[:])
if err != nil { if err != nil {
return err return err
@ -167,24 +199,7 @@ func (c *Client) DecodeRespHeader() error {
} }
// NewConn wraps a net.Conn to VMessConn func (c *Conn) Read(b []byte) (n int, err error) {
func (c *Client) NewConn(rc net.Conn) (net.Conn, error) {
// AuthInfo
rc.Write(c.EncodeAuthInfo())
// Request
req, err := c.EncodeRequest()
if err != nil {
return nil, err
}
rc.Write(req)
c.Conn = rc
return c, err
}
func (c *Client) Read(b []byte) (n int, err error) {
if !c.connected { if !c.connected {
c.DecodeRespHeader() c.DecodeRespHeader()
} }
@ -192,6 +207,6 @@ func (c *Client) Read(b []byte) (n int, err error) {
return c.Conn.Read(b) return c.Conn.Read(b)
} }
func (c *Client) Write(b []byte) (n int, err error) { func (c *Conn) Write(b []byte) (n int, err error) {
return c.Conn.Write(b) return c.Conn.Write(b)
} }

View File

@ -1,12 +1,15 @@
package vmess package vmess
import ( import (
"bytes"
"crypto/md5" "crypto/md5"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"errors" "errors"
"strings" "strings"
"time" "time"
"github.com/nadoo/glider/common/log"
) )
// User of vmess client // User of vmess client
@ -16,16 +19,38 @@ type User struct {
} }
// NewUser . // NewUser .
func NewUser(uuidStr string) (*User, error) { func NewUser(uuid [16]byte) *User {
uuid, err := StrToUUID(uuidStr)
if err != nil {
return nil, err
}
u := &User{UUID: uuid} u := &User{UUID: uuid}
copy(u.CmdKey[:], GetKey(uuid)) copy(u.CmdKey[:], GetKey(uuid))
return u
}
return u, nil func nextID(oldID [16]byte) (newID [16]byte) {
md5hash := md5.New()
md5hash.Write(oldID[:])
md5hash.Write([]byte("16167dc8-16b6-4e6d-b8bb-65dd68113a81"))
for {
md5hash.Sum(newID[:0])
if !bytes.Equal(oldID[:], newID[:]) {
log.F("oldID: %x, newID: %x", oldID, newID)
return
}
md5hash.Write([]byte("533eff8a-4113-4b10-b5ce-0f5d76b98cd2"))
}
}
// GenAlterIDUsers generates users according to primary user's id and alterID
func (u *User) GenAlterIDUsers(alterID int) []*User {
users := make([]*User, alterID)
preID := u.UUID
for i := 0; i < alterID; i++ {
newID := nextID(preID)
// NOTE: alterID user is a user which have a different uuid but a same cmdkey with the primary user.
users[i] = &User{UUID: newID, CmdKey: u.CmdKey}
preID = newID
}
return users
} }
// StrToUUID converts string to uuid. // StrToUUID converts string to uuid.

View File

@ -16,8 +16,10 @@ type VMess struct {
addr string addr string
uuid string uuid string
alertID uint32 alterID int
security string security string
client *Client
} }
func init() { func init() {
@ -46,13 +48,19 @@ func NewVMess(s string, dialer proxy.Dialer) (*VMess, error) {
aid := "0" aid := "0"
params, _ := url.ParseQuery(u.RawQuery) params, _ := url.ParseQuery(u.RawQuery)
if v, ok := params["alertId"]; ok { if v, ok := params["alterID"]; ok {
aid = v[0] aid = v[0]
} }
alertID, err := strconv.ParseUint(aid, 10, 32) alterID, err := strconv.ParseUint(aid, 10, 32)
if err != nil { if err != nil {
log.F("parse alertID err: %s", err) log.F("parse alterID err: %s", err)
return nil, err
}
client, err := NewClient(uuid, int(alterID))
if err != nil {
log.F("create vmess client err: %s", err)
return nil, err return nil, err
} }
@ -60,8 +68,9 @@ func NewVMess(s string, dialer proxy.Dialer) (*VMess, error) {
dialer: dialer, dialer: dialer,
addr: addr, addr: addr,
uuid: uuid, uuid: uuid,
alertID: uint32(alertID), alterID: int(alterID),
security: security, security: security,
client: client,
} }
return p, nil return p, nil
@ -85,12 +94,7 @@ func (s *VMess) Dial(network, addr string) (net.Conn, error) {
return nil, err return nil, err
} }
client, err := NewClient(s.uuid, addr) return s.client.NewConn(rc, addr)
if err != nil {
return nil, err
}
return client.NewConn(rc)
} }
// DialUDP connects to the given address via the proxy. // DialUDP connects to the given address via the proxy.