github.com/xraypb/xray-core@v1.6.6/proxy/shadowsocks/validator.go (about) 1 package shadowsocks 2 3 import ( 4 "crypto/cipher" 5 "crypto/hmac" 6 "crypto/sha256" 7 "hash/crc64" 8 "strings" 9 "sync" 10 11 "github.com/xraypb/xray-core/common/dice" 12 "github.com/xraypb/xray-core/common/protocol" 13 ) 14 15 // Validator stores valid Shadowsocks users. 16 type Validator struct { 17 sync.RWMutex 18 users []*protocol.MemoryUser 19 20 behaviorSeed uint64 21 behaviorFused bool 22 } 23 24 var ErrNotFound = newError("Not Found") 25 26 // Add a Shadowsocks user. 27 func (v *Validator) Add(u *protocol.MemoryUser) error { 28 v.Lock() 29 defer v.Unlock() 30 31 account := u.Account.(*MemoryAccount) 32 if !account.Cipher.IsAEAD() && len(v.users) > 0 { 33 return newError("The cipher is not support Single-port Multi-user") 34 } 35 v.users = append(v.users, u) 36 37 if !v.behaviorFused { 38 hashkdf := hmac.New(sha256.New, []byte("SSBSKDF")) 39 hashkdf.Write(account.Key) 40 v.behaviorSeed = crc64.Update(v.behaviorSeed, crc64.MakeTable(crc64.ECMA), hashkdf.Sum(nil)) 41 } 42 43 return nil 44 } 45 46 // Del a Shadowsocks user with a non-empty Email. 47 func (v *Validator) Del(email string) error { 48 if email == "" { 49 return newError("Email must not be empty.") 50 } 51 52 v.Lock() 53 defer v.Unlock() 54 55 email = strings.ToLower(email) 56 idx := -1 57 for i, u := range v.users { 58 if strings.EqualFold(u.Email, email) { 59 idx = i 60 break 61 } 62 } 63 64 if idx == -1 { 65 return newError("User ", email, " not found.") 66 } 67 ulen := len(v.users) 68 69 v.users[idx] = v.users[ulen-1] 70 v.users[ulen-1] = nil 71 v.users = v.users[:ulen-1] 72 73 return nil 74 } 75 76 // Get a Shadowsocks user. 77 func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol.MemoryUser, aead cipher.AEAD, ret []byte, ivLen int32, err error) { 78 v.RLock() 79 defer v.RUnlock() 80 81 for _, user := range v.users { 82 if account := user.Account.(*MemoryAccount); account.Cipher.IsAEAD() { 83 aeadCipher := account.Cipher.(*AEADCipher) 84 ivLen = aeadCipher.IVSize() 85 iv := bs[:ivLen] 86 subkey := make([]byte, 32) 87 subkey = subkey[:aeadCipher.KeyBytes] 88 hkdfSHA1(account.Key, iv, subkey) 89 aead = aeadCipher.AEADAuthCreator(subkey) 90 91 var matchErr error 92 switch command { 93 case protocol.RequestCommandTCP: 94 data := make([]byte, 4+aead.NonceSize()) 95 ret, matchErr = aead.Open(data[:0], data[4:], bs[ivLen:ivLen+18], nil) 96 case protocol.RequestCommandUDP: 97 data := make([]byte, 8192) 98 ret, matchErr = aead.Open(data[:0], data[8192-aead.NonceSize():8192], bs[ivLen:], nil) 99 } 100 101 if matchErr == nil { 102 u = user 103 err = account.CheckIV(iv) 104 return 105 } 106 } else { 107 u = user 108 ivLen = user.Account.(*MemoryAccount).Cipher.IVSize() 109 // err = user.Account.(*MemoryAccount).CheckIV(bs[:ivLen]) // The IV size of None Cipher is 0. 110 return 111 } 112 } 113 114 return nil, nil, nil, 0, ErrNotFound 115 } 116 117 func (v *Validator) GetBehaviorSeed() uint64 { 118 v.Lock() 119 defer v.Unlock() 120 121 v.behaviorFused = true 122 if v.behaviorSeed == 0 { 123 v.behaviorSeed = dice.RollUint64() 124 } 125 return v.behaviorSeed 126 }