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

View File

@ -1,12 +1,15 @@
package vmess
import (
"bytes"
"crypto/md5"
"encoding/binary"
"encoding/hex"
"errors"
"strings"
"time"
"github.com/nadoo/glider/common/log"
)
// User of vmess client
@ -16,16 +19,38 @@ type User struct {
}
// NewUser .
func NewUser(uuidStr string) (*User, error) {
uuid, err := StrToUUID(uuidStr)
if err != nil {
return nil, err
}
func NewUser(uuid [16]byte) *User {
u := &User{UUID: 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.

View File

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