1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2025-01-27 19:56:22 -05:00

accounts in protobuf

This commit is contained in:
Darien Raymond 2016-09-18 00:41:21 +02:00
parent 3423adaea4
commit d08cba000f
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
40 changed files with 790 additions and 224 deletions

View File

@ -2,5 +2,12 @@
{ {
"editor.tabSize": 2, "editor.tabSize": 2,
"go.buildTags": "json" "go.buildTags": "json",
"protoc": {
"options": [
"--proto_path=$GOPATH/src/",
"--proto_path=$GOPATH/src/github.com/google/protobuf/src"
]
}
} }

View File

@ -3,3 +3,9 @@ package protocol
type Account interface { type Account interface {
Equals(Account) bool Equals(Account) bool
} }
type AsAccount interface {
AsAccount() (Account, error)
}
type NewAccountFactory func() AsAccount

View File

@ -77,6 +77,6 @@ type CommandSwitchAccount struct {
Port v2net.Port Port v2net.Port
ID *uuid.UUID ID *uuid.UUID
AlterIds uint16 AlterIds uint16
Level UserLevel Level uint32
ValidMin byte ValidMin byte
} }

View File

@ -13,9 +13,9 @@ func TestServerList(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
list := NewServerList() list := NewServerList()
list.AddServer(NewServerSpec(v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(1)), AlwaysValid())) list.AddServer(NewServerSpec(nil, v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(1)), AlwaysValid()))
assert.Uint32(list.Size()).Equals(1) assert.Uint32(list.Size()).Equals(1)
list.AddServer(NewServerSpec(v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(2)), BeforeTime(time.Now().Add(time.Second)))) list.AddServer(NewServerSpec(nil, v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
assert.Uint32(list.Size()).Equals(2) assert.Uint32(list.Size()).Equals(2)
server := list.GetServer(1) server := list.GetServer(1)
@ -32,9 +32,9 @@ func TestServerPicker(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
list := NewServerList() list := NewServerList()
list.AddServer(NewServerSpec(v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(1)), AlwaysValid())) list.AddServer(NewServerSpec(nil, v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(1)), AlwaysValid()))
list.AddServer(NewServerSpec(v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(2)), BeforeTime(time.Now().Add(time.Second)))) list.AddServer(NewServerSpec(nil, v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(2)), BeforeTime(time.Now().Add(time.Second))))
list.AddServer(NewServerSpec(v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(3)), BeforeTime(time.Now().Add(time.Second)))) list.AddServer(NewServerSpec(nil, v2net.TCPDestination(v2net.LocalHostIP, v2net.Port(3)), BeforeTime(time.Now().Add(time.Second))))
picker := NewRoundRobinServerPicker(list) picker := NewRoundRobinServerPicker(list)
server := picker.PickServer() server := picker.PickServer()

View File

@ -48,16 +48,23 @@ type ServerSpec struct {
dest v2net.Destination dest v2net.Destination
users []*User users []*User
valid ValidationStrategy valid ValidationStrategy
newAccount NewAccountFactory
} }
func NewServerSpec(dest v2net.Destination, valid ValidationStrategy, users ...*User) *ServerSpec { func NewServerSpec(newAccount NewAccountFactory, dest v2net.Destination, valid ValidationStrategy, users ...*User) *ServerSpec {
return &ServerSpec{ return &ServerSpec{
dest: dest, dest: dest,
users: users, users: users,
valid: valid, valid: valid,
newAccount: newAccount,
} }
} }
func NewServerSpecFromPB(newAccount NewAccountFactory, spec ServerSpecPB) *ServerSpec {
dest := v2net.TCPDestination(spec.Address.AsAddress(), v2net.Port(spec.Port))
return NewServerSpec(newAccount, dest, AlwaysValid(), spec.Users...)
}
func (this *ServerSpec) Destination() v2net.Destination { func (this *ServerSpec) Destination() v2net.Destination {
return this.dest return this.dest
} }
@ -66,9 +73,13 @@ func (this *ServerSpec) HasUser(user *User) bool {
this.RLock() this.RLock()
defer this.RUnlock() defer this.RUnlock()
account := user.Account accountA, err := user.GetTypedAccount(this.newAccount())
if err != nil {
return false
}
for _, u := range this.users { for _, u := range this.users {
if u.Account.Equals(account) { accountB, err := u.GetTypedAccount(this.newAccount())
if err == nil && accountA.Equals(accountB) {
return true return true
} }
} }

View File

@ -0,0 +1,81 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/common/protocol/server_spec.proto
// DO NOT EDIT!
/*
Package protocol is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/common/protocol/server_spec.proto
v2ray.com/core/common/protocol/user.proto
It has these top-level messages:
ServerSpecPB
User
*/
package protocol
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import com_v2ray_core_common_net "v2ray.com/core/common/net"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type ServerSpecPB struct {
Address *com_v2ray_core_common_net.AddressPB `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"`
Port uint32 `protobuf:"varint,2,opt,name=port" json:"port,omitempty"`
Users []*User `protobuf:"bytes,3,rep,name=users" json:"users,omitempty"`
}
func (m *ServerSpecPB) Reset() { *m = ServerSpecPB{} }
func (m *ServerSpecPB) String() string { return proto.CompactTextString(m) }
func (*ServerSpecPB) ProtoMessage() {}
func (*ServerSpecPB) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *ServerSpecPB) GetAddress() *com_v2ray_core_common_net.AddressPB {
if m != nil {
return m.Address
}
return nil
}
func (m *ServerSpecPB) GetUsers() []*User {
if m != nil {
return m.Users
}
return nil
}
func init() {
proto.RegisterType((*ServerSpecPB)(nil), "com.v2ray.core.common.protocol.ServerSpecPB")
}
func init() { proto.RegisterFile("v2ray.com/core/common/protocol/server_spec.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 209 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x8e, 0x3f, 0x4b, 0xc5, 0x30,
0x14, 0xc5, 0x89, 0xf5, 0x1f, 0x51, 0x97, 0x4c, 0xa5, 0x83, 0x14, 0x11, 0xac, 0xcb, 0x8d, 0xd4,
0xcd, 0x41, 0xb0, 0x9f, 0xa0, 0xb4, 0xb8, 0xb8, 0x48, 0x4d, 0xef, 0x66, 0x7a, 0xc3, 0x4d, 0x2c,
0xf8, 0x65, 0xfc, 0xac, 0xf2, 0x92, 0x97, 0xad, 0xbc, 0xb7, 0x1d, 0x0e, 0xe7, 0x77, 0xce, 0x91,
0x4f, 0x6b, 0xcb, 0xd3, 0x2f, 0x18, 0xb2, 0xda, 0x10, 0xa3, 0x36, 0x64, 0x2d, 0x2d, 0xda, 0x31,
0x05, 0x32, 0xf4, 0xad, 0x3d, 0xf2, 0x8a, 0xfc, 0xe9, 0x1d, 0x1a, 0x88, 0xa6, 0xba, 0x35, 0x64,
0x21, 0x53, 0x8c, 0x90, 0x08, 0xc8, 0x44, 0xf5, 0xb0, 0xdd, 0xb8, 0x60, 0xd0, 0xd3, 0x3c, 0x33,
0x7a, 0x9f, 0xb2, 0xd5, 0xe3, 0x91, 0xe9, 0x1f, 0x8f, 0x9c, 0xa2, 0x77, 0x7f, 0x42, 0x5e, 0x8f,
0xf1, 0xc9, 0xe8, 0xd0, 0xf4, 0x9d, 0x7a, 0x95, 0x17, 0xfb, 0xb2, 0x52, 0xd4, 0xa2, 0xb9, 0x6a,
0xef, 0x61, 0xfb, 0xd6, 0x82, 0x01, 0xde, 0x52, 0xb2, 0xef, 0x86, 0x0c, 0x29, 0x25, 0x4f, 0x1d,
0x71, 0x28, 0x4f, 0x6a, 0xd1, 0xdc, 0x0c, 0x51, 0xab, 0x17, 0x79, 0xb6, 0x9b, 0xf4, 0x65, 0x51,
0x17, 0x07, 0x1a, 0xf3, 0x3f, 0x78, 0xf7, 0xc8, 0x43, 0x42, 0x3a, 0xf9, 0x71, 0x99, 0xfd, 0xaf,
0xf3, 0xa8, 0x9e, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0xde, 0x92, 0x28, 0x40, 0x5b, 0x01, 0x00,
0x00,
}

View File

@ -0,0 +1,13 @@
syntax = "proto3";
import "v2ray.com/core/common/net/address.proto";
import "v2ray.com/core/common/protocol/user.proto";
package com.v2ray.core.common.protocol;
option go_package = "protocol";
message ServerSpecPB {
com.v2ray.core.common.net.AddressPB address = 1;
uint32 port = 2;
repeated com.v2ray.core.common.protocol.User users = 3;
}

View File

@ -4,41 +4,10 @@ import (
"testing" "testing"
"time" "time"
v2net "v2ray.com/core/common/net"
. "v2ray.com/core/common/protocol" . "v2ray.com/core/common/protocol"
"v2ray.com/core/testing/assert" "v2ray.com/core/testing/assert"
) )
type TestAccount struct {
id int
}
func (this *TestAccount) Equals(account Account) bool {
return account.(*TestAccount).id == this.id
}
func TestServerSpecUser(t *testing.T) {
assert := assert.On(t)
account := &TestAccount{
id: 0,
}
user := NewUser(UserLevel(0), "")
user.Account = account
rec := NewServerSpec(v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80), AlwaysValid(), user)
assert.Bool(rec.HasUser(user)).IsTrue()
account2 := &TestAccount{
id: 1,
}
user2 := NewUser(UserLevel(0), "")
user2.Account = account2
assert.Bool(rec.HasUser(user2)).IsFalse()
rec.AddUser(user2)
assert.Bool(rec.HasUser(user2)).IsTrue()
}
func TestAlwaysValidStrategy(t *testing.T) { func TestAlwaysValidStrategy(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)

View File

@ -1,35 +1,44 @@
package protocol package protocol
type UserLevel byte import (
"errors"
const ( "github.com/golang/protobuf/proto"
UserLevelAdmin = UserLevel(255) "github.com/golang/protobuf/ptypes"
UserLevelUntrusted = UserLevel(0)
) )
type User struct { var (
Account Account ErrUserMissing = errors.New("User is not specified.")
Level UserLevel ErrAccountMissing = errors.New("Account is not specified.")
Email string ErrNonMessageType = errors.New("Not a protobuf message.")
)
func (this *User) GetTypedAccount(account AsAccount) (Account, error) {
anyAccount := this.GetAccount()
if anyAccount == nil {
return nil, ErrAccountMissing
}
protoAccount, ok := account.(proto.Message)
if !ok {
return nil, ErrNonMessageType
}
err := ptypes.UnmarshalAny(anyAccount, protoAccount)
if err != nil {
return nil, err
}
return account.AsAccount()
} }
func NewUser(level UserLevel, email string) *User { func (this *User) GetSettings() UserSettings {
return &User{ settings := UserSettings{
Level: level, PayloadReadTimeout: 120,
Email: email,
} }
if this.Level > 0 {
settings.PayloadReadTimeout = 0
}
return settings
} }
type UserSettings struct { type UserSettings struct {
PayloadReadTimeout uint32 PayloadReadTimeout uint32
} }
func GetUserSettings(level UserLevel) UserSettings {
settings := UserSettings{
PayloadReadTimeout: 120,
}
if level > 0 {
settings.PayloadReadTimeout = 0
}
return settings
}

View File

@ -0,0 +1,55 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/common/protocol/user.proto
// DO NOT EDIT!
package protocol
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import google_protobuf "github.com/golang/protobuf/ptypes/any"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type User struct {
Level uint32 `protobuf:"varint,1,opt,name=level" json:"level,omitempty"`
Email string `protobuf:"bytes,2,opt,name=email" json:"email,omitempty"`
Account *google_protobuf.Any `protobuf:"bytes,3,opt,name=account" json:"account,omitempty"`
}
func (m *User) Reset() { *m = User{} }
func (m *User) String() string { return proto.CompactTextString(m) }
func (*User) ProtoMessage() {}
func (*User) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
func (m *User) GetAccount() *google_protobuf.Any {
if m != nil {
return m.Account
}
return nil
}
func init() {
proto.RegisterType((*User)(nil), "com.v2ray.core.common.protocol.User")
}
func init() { proto.RegisterFile("v2ray.com/core/common/protocol/user.proto", fileDescriptor1) }
var fileDescriptor1 = []byte{
// 179 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x34, 0x8e, 0xcb, 0xaa, 0xc2, 0x30,
0x10, 0x86, 0xc9, 0x39, 0x5e, 0x23, 0x6e, 0x4a, 0x17, 0xd5, 0x85, 0x14, 0x57, 0x75, 0x33, 0x81,
0xfa, 0x04, 0xfa, 0x08, 0x05, 0x37, 0xee, 0xd2, 0x61, 0x2c, 0x42, 0x92, 0x91, 0xf4, 0x02, 0x79,
0x7b, 0xb1, 0x21, 0xbb, 0xf9, 0x66, 0xbe, 0xe1, 0xff, 0xe5, 0x65, 0xaa, 0xbd, 0x0e, 0x80, 0x6c,
0x15, 0xb2, 0x27, 0x85, 0x6c, 0x2d, 0x3b, 0xf5, 0xf1, 0x3c, 0x30, 0xb2, 0x51, 0x63, 0x4f, 0x1e,
0x66, 0xca, 0x4e, 0xc8, 0x16, 0x92, 0xee, 0x09, 0xa2, 0x0a, 0x49, 0x3d, 0x1e, 0x3a, 0xe6, 0xce,
0x50, 0xfc, 0x6d, 0xc7, 0x97, 0xd2, 0x2e, 0xc4, 0xeb, 0xb9, 0x95, 0x8b, 0x47, 0x4f, 0x3e, 0xcb,
0xe5, 0xd2, 0xd0, 0x44, 0xa6, 0x10, 0xa5, 0xa8, 0xf6, 0x4d, 0x84, 0xdf, 0x96, 0xac, 0x7e, 0x9b,
0xe2, 0xaf, 0x14, 0xd5, 0xb6, 0x89, 0x90, 0x81, 0x5c, 0x6b, 0x44, 0x1e, 0xdd, 0x50, 0xfc, 0x97,
0xa2, 0xda, 0xd5, 0x39, 0xc4, 0x00, 0x48, 0x01, 0x70, 0x73, 0xa1, 0x49, 0xd2, 0x5d, 0x3e, 0x37,
0xa9, 0x4a, 0xbb, 0x9a, 0xa7, 0xeb, 0x37, 0x00, 0x00, 0xff, 0xff, 0xfa, 0x7e, 0xbf, 0xfa, 0xde,
0x00, 0x00, 0x00,
}

View File

@ -0,0 +1,12 @@
syntax = "proto3";
import "google/protobuf/any.proto";
package com.v2ray.core.common.protocol;
option go_package = "protocol";
message User {
uint32 level = 1;
string email = 2;
google.protobuf.Any account = 3;
}

View File

@ -15,7 +15,7 @@ func (u *User) UnmarshalJSON(data []byte) error {
} }
u.Email = rawUserValue.EmailString u.Email = rawUserValue.EmailString
u.Level = UserLevel(rawUserValue.LevelByte) u.Level = uint32(rawUserValue.LevelByte)
return nil return nil
} }

View File

@ -8,6 +8,35 @@ import (
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
) )
func (this *Config) GetCipher() Cipher {
switch this.Cipher {
case Config_AES_128_CFB:
return &AesCfb{KeyBytes: 16}
case Config_AES_256_CFB:
return &AesCfb{KeyBytes: 32}
case Config_CHACHA20:
return &ChaCha20{IVBytes: 8}
case Config_CHACHA20_IEFT:
return &ChaCha20{IVBytes: 12}
}
panic("Failed to create Cipher. Should not happen.")
}
func (this *Account) Equals(another protocol.Account) bool {
if account, ok := another.(*Account); ok {
return account.Password == this.Password
}
return false
}
func (this *Account) AsAccount() (protocol.Account, error) {
return this, nil
}
func (this *Account) GetCipherKey(size int) []byte {
return PasswordToCipherKey(this.Password, size)
}
type Cipher interface { type Cipher interface {
KeySize() int KeySize() int
IVSize() int IVSize() int
@ -57,14 +86,6 @@ func (this *ChaCha20) NewDecodingStream(key []byte, iv []byte) (cipher.Stream, e
return crypto.NewChaCha20Stream(key, iv), nil return crypto.NewChaCha20Stream(key, iv), nil
} }
type Config struct {
Cipher Cipher
Key []byte
UDP bool
Level protocol.UserLevel
Email string
}
func PasswordToCipherKey(password string, keySize int) []byte { func PasswordToCipherKey(password string, keySize int) []byte {
pwdBytes := []byte(password) pwdBytes := []byte(password)
key := make([]byte, 0, keySize) key := make([]byte, 0, keySize)

View File

@ -0,0 +1,120 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/proxy/shadowsocks/config.proto
// DO NOT EDIT!
/*
Package shadowsocks is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/proxy/shadowsocks/config.proto
It has these top-level messages:
Account
Config
*/
package shadowsocks
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import com_v2ray_core_common_protocol "v2ray.com/core/common/protocol"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Config_Cipher int32
const (
Config_UNKNOWN Config_Cipher = 0
Config_AES_128_CFB Config_Cipher = 1
Config_AES_256_CFB Config_Cipher = 2
Config_CHACHA20 Config_Cipher = 3
Config_CHACHA20_IEFT Config_Cipher = 4
)
var Config_Cipher_name = map[int32]string{
0: "UNKNOWN",
1: "AES_128_CFB",
2: "AES_256_CFB",
3: "CHACHA20",
4: "CHACHA20_IEFT",
}
var Config_Cipher_value = map[string]int32{
"UNKNOWN": 0,
"AES_128_CFB": 1,
"AES_256_CFB": 2,
"CHACHA20": 3,
"CHACHA20_IEFT": 4,
}
func (x Config_Cipher) String() string {
return proto.EnumName(Config_Cipher_name, int32(x))
}
func (Config_Cipher) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1, 0} }
type Account struct {
Password string `protobuf:"bytes,1,opt,name=password" json:"password,omitempty"`
}
func (m *Account) Reset() { *m = Account{} }
func (m *Account) String() string { return proto.CompactTextString(m) }
func (*Account) ProtoMessage() {}
func (*Account) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type Config struct {
Cipher Config_Cipher `protobuf:"varint,1,opt,name=cipher,enum=com.v2ray.core.proxy.shadowsocks.Config_Cipher" json:"cipher,omitempty"`
UdpEnabled bool `protobuf:"varint,2,opt,name=udp_enabled,json=udpEnabled" json:"udp_enabled,omitempty"`
User *com_v2ray_core_common_protocol.User `protobuf:"bytes,3,opt,name=user" json:"user,omitempty"`
}
func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *Config) GetUser() *com_v2ray_core_common_protocol.User {
if m != nil {
return m.User
}
return nil
}
func init() {
proto.RegisterType((*Account)(nil), "com.v2ray.core.proxy.shadowsocks.Account")
proto.RegisterType((*Config)(nil), "com.v2ray.core.proxy.shadowsocks.Config")
proto.RegisterEnum("com.v2ray.core.proxy.shadowsocks.Config_Cipher", Config_Cipher_name, Config_Cipher_value)
}
func init() { proto.RegisterFile("v2ray.com/core/proxy/shadowsocks/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 308 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x8f, 0x41, 0x4f, 0xc2, 0x40,
0x14, 0x84, 0x2d, 0x90, 0x82, 0xaf, 0xa2, 0x75, 0x4f, 0x84, 0x8b, 0x0d, 0xd1, 0x04, 0x0f, 0xee,
0x6a, 0x8d, 0x86, 0x6b, 0x69, 0x40, 0x8c, 0x09, 0x26, 0x55, 0xa2, 0xf1, 0xd2, 0x94, 0xed, 0x2a,
0x44, 0xda, 0xd7, 0xec, 0x52, 0x91, 0x3f, 0xe0, 0xef, 0x36, 0x6e, 0xad, 0x21, 0x5c, 0x3c, 0xbe,
0xc9, 0x7c, 0x6f, 0x66, 0xe0, 0xec, 0xc3, 0x95, 0xd1, 0x9a, 0x72, 0x4c, 0x18, 0x47, 0x29, 0x58,
0x26, 0xf1, 0x73, 0xcd, 0xd4, 0x2c, 0x8a, 0x71, 0xa5, 0x90, 0xbf, 0x2b, 0xc6, 0x31, 0x7d, 0x9d,
0xbf, 0xd1, 0x4c, 0xe2, 0x12, 0x89, 0xc3, 0x31, 0xa1, 0x25, 0x22, 0x05, 0xd5, 0x76, 0xba, 0x61,
0x6f, 0x9f, 0x6e, 0x3d, 0xe4, 0x98, 0x24, 0x98, 0x32, 0x8d, 0x73, 0x5c, 0xb0, 0x5c, 0x09, 0x59,
0x3c, 0xeb, 0x9c, 0x40, 0xdd, 0xe3, 0x1c, 0xf3, 0x74, 0x49, 0xda, 0xd0, 0xc8, 0x22, 0xa5, 0x56,
0x28, 0xe3, 0x96, 0xe1, 0x18, 0xdd, 0xdd, 0xe0, 0xef, 0xee, 0x7c, 0x55, 0xc0, 0xf4, 0x75, 0x09,
0x72, 0x03, 0x26, 0x9f, 0x67, 0x33, 0x21, 0xb5, 0x69, 0xdf, 0x65, 0xf4, 0xbf, 0x3e, 0xb4, 0x20,
0xa9, 0xaf, 0xb1, 0xe0, 0x17, 0x27, 0x47, 0x60, 0xe5, 0x71, 0x16, 0x8a, 0x34, 0x9a, 0x2e, 0x44,
0xdc, 0xaa, 0x38, 0x46, 0xb7, 0x11, 0x40, 0x1e, 0x67, 0x83, 0x42, 0x21, 0x3d, 0xa8, 0xfd, 0x34,
0x6d, 0x55, 0x1d, 0xa3, 0x6b, 0xb9, 0xc7, 0xdb, 0x39, 0xc5, 0x2a, 0x5a, 0xae, 0xa2, 0x13, 0x25,
0x64, 0xa0, 0x89, 0xce, 0x33, 0x98, 0x45, 0x18, 0xb1, 0xa0, 0x3e, 0x19, 0xdf, 0x8d, 0xef, 0x9f,
0xc6, 0xf6, 0x0e, 0x39, 0x00, 0xcb, 0x1b, 0x3c, 0x84, 0x17, 0x6e, 0x2f, 0xf4, 0x87, 0x7d, 0xdb,
0x28, 0x05, 0xf7, 0xea, 0x5a, 0x0b, 0x15, 0xb2, 0x07, 0x0d, 0x7f, 0xe4, 0xf9, 0x23, 0xcf, 0x3d,
0xb7, 0xab, 0xe4, 0x10, 0x9a, 0xe5, 0x15, 0xde, 0x0e, 0x86, 0x8f, 0x76, 0xad, 0xdf, 0x7c, 0xb1,
0x36, 0x96, 0x4d, 0x4d, 0x9d, 0x7e, 0xf9, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x1d, 0xee, 0x41, 0x94,
0xc3, 0x01, 0x00, 0x00,
}

View File

@ -0,0 +1,23 @@
syntax = "proto3";
import "v2ray.com/core/common/protocol/user.proto";
package com.v2ray.core.proxy.shadowsocks;
option go_package = "shadowsocks";
message Account {
string password = 1;
}
message Config {
enum Cipher {
UNKNOWN = 0;
AES_128_CFB = 1;
AES_256_CFB = 2;
CHACHA20 = 3;
CHACHA20_IEFT = 4;
}
Cipher cipher = 1;
bool udp_enabled = 2;
com.v2ray.core.common.protocol.User user = 3;
}

View File

@ -11,6 +11,8 @@ import (
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/proxy/registry" "v2ray.com/core/proxy/registry"
"github.com/golang/protobuf/ptypes"
) )
func (this *Config) UnmarshalJSON(data []byte) error { func (this *Config) UnmarshalJSON(data []byte) error {
@ -26,25 +28,17 @@ func (this *Config) UnmarshalJSON(data []byte) error {
return errors.New("Shadowsocks: Failed to parse config: " + err.Error()) return errors.New("Shadowsocks: Failed to parse config: " + err.Error())
} }
this.UDP = jsonConfig.UDP this.UdpEnabled = jsonConfig.UDP
jsonConfig.Cipher = strings.ToLower(jsonConfig.Cipher) jsonConfig.Cipher = strings.ToLower(jsonConfig.Cipher)
switch jsonConfig.Cipher { switch jsonConfig.Cipher {
case "aes-256-cfb": case "aes-256-cfb":
this.Cipher = &AesCfb{ this.Cipher = Config_AES_256_CFB
KeyBytes: 32,
}
case "aes-128-cfb": case "aes-128-cfb":
this.Cipher = &AesCfb{ this.Cipher = Config_AES_128_CFB
KeyBytes: 16,
}
case "chacha20": case "chacha20":
this.Cipher = &ChaCha20{ this.Cipher = Config_CHACHA20
IVBytes: 8,
}
case "chacha20-ietf": case "chacha20-ietf":
this.Cipher = &ChaCha20{ this.Cipher = Config_CHACHA20_IEFT
IVBytes: 12,
}
default: default:
log.Error("Shadowsocks: Unknown cipher method: ", jsonConfig.Cipher) log.Error("Shadowsocks: Unknown cipher method: ", jsonConfig.Cipher)
return common.ErrBadConfiguration return common.ErrBadConfiguration
@ -54,10 +48,18 @@ func (this *Config) UnmarshalJSON(data []byte) error {
log.Error("Shadowsocks: Password is not specified.") log.Error("Shadowsocks: Password is not specified.")
return common.ErrBadConfiguration return common.ErrBadConfiguration
} }
this.Key = PasswordToCipherKey(jsonConfig.Password, this.Cipher.KeySize()) account, err := ptypes.MarshalAny(&Account{
Password: jsonConfig.Password,
this.Level = protocol.UserLevel(jsonConfig.Level) })
this.Email = jsonConfig.Email if err != nil {
log.Error("Shadowsocks: Failed to create account: ", err)
return common.ErrBadConfiguration
}
this.User = &protocol.User{
Email: jsonConfig.Email,
Level: uint32(jsonConfig.Level),
Account: account,
}
return nil return nil
} }

View File

@ -21,6 +21,8 @@ func TestConfigParsing(t *testing.T) {
err := json.Unmarshal([]byte(rawJson), config) err := json.Unmarshal([]byte(rawJson), config)
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.Int(config.Cipher.KeySize()).Equals(16) assert.Int(config.GetCipher().KeySize()).Equals(16)
assert.Bytes(config.Key).Equals([]byte{160, 224, 26, 2, 22, 110, 9, 80, 65, 52, 80, 20, 38, 243, 224, 241}) account, err := config.User.GetTypedAccount(&Account{})
assert.Error(err).IsNil()
assert.Bytes(account.(*Account).GetCipherKey(config.GetCipher().KeySize())).Equals([]byte{160, 224, 26, 2, 22, 110, 9, 80, 65, 52, 80, 20, 38, 243, 224, 241})
} }

View File

@ -24,6 +24,8 @@ import (
type Server struct { type Server struct {
packetDispatcher dispatcher.PacketDispatcher packetDispatcher dispatcher.PacketDispatcher
config *Config config *Config
cipher Cipher
cipherKey []byte
meta *proxy.InboundHandlerMeta meta *proxy.InboundHandlerMeta
accepting bool accepting bool
tcpHub *internet.TCPHub tcpHub *internet.TCPHub
@ -31,12 +33,31 @@ type Server struct {
udpServer *udp.UDPServer udpServer *udp.UDPServer
} }
func NewServer(config *Config, packetDispatcher dispatcher.PacketDispatcher, meta *proxy.InboundHandlerMeta) *Server { func NewServer(config *Config, space app.Space, meta *proxy.InboundHandlerMeta) (*Server, error) {
return &Server{ if config.GetUser() == nil {
config: config, return nil, protocol.ErrUserMissing
packetDispatcher: packetDispatcher,
meta: meta,
} }
account := new(Account)
if _, err := config.GetUser().GetTypedAccount(account); err != nil {
return nil, err
}
cipher := config.GetCipher()
s := &Server{
config: config,
meta: meta,
cipher: cipher,
cipherKey: account.GetCipherKey(cipher.KeySize()),
}
space.InitializeApplication(func() error {
if !space.HasApp(dispatcher.APP_ID) {
return app.ErrMissingApplication
}
s.packetDispatcher = space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)
return nil
})
return s, nil
} }
func (this *Server) Port() v2net.Port { func (this *Server) Port() v2net.Port {
@ -70,7 +91,7 @@ func (this *Server) Start() error {
} }
this.tcpHub = tcpHub this.tcpHub = tcpHub
if this.config.UDP { if this.config.UdpEnabled {
this.udpServer = udp.NewUDPServer(this.meta, this.packetDispatcher) this.udpServer = udp.NewUDPServer(this.meta, this.packetDispatcher)
udpHub, err := udp.ListenUDP(this.meta.Address, this.meta.Port, udp.ListenOption{Callback: this.handlerUDPPayload}) udpHub, err := udp.ListenUDP(this.meta.Address, this.meta.Port, udp.ListenOption{Callback: this.handlerUDPPayload})
if err != nil { if err != nil {
@ -89,12 +110,11 @@ func (this *Server) handlerUDPPayload(payload *alloc.Buffer, session *proxy.Sess
defer payload.Release() defer payload.Release()
source := session.Source source := session.Source
ivLen := this.config.Cipher.IVSize() ivLen := this.cipher.IVSize()
iv := payload.Value[:ivLen] iv := payload.Value[:ivLen]
key := this.config.Key
payload.SliceFrom(ivLen) payload.SliceFrom(ivLen)
stream, err := this.config.Cipher.NewDecodingStream(key, iv) stream, err := this.cipher.NewDecodingStream(this.cipherKey, iv)
if err != nil { if err != nil {
log.Error("Shadowsocks: Failed to create decoding stream: ", err) log.Error("Shadowsocks: Failed to create decoding stream: ", err)
return return
@ -102,7 +122,7 @@ func (this *Server) handlerUDPPayload(payload *alloc.Buffer, session *proxy.Sess
reader := crypto.NewCryptionReader(stream, payload) reader := crypto.NewCryptionReader(stream, payload)
request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(key, iv)), true) request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(this.cipherKey, iv)), true)
if err != nil { if err != nil {
if err != io.EOF { if err != io.EOF {
log.Access(source, "", log.AccessRejected, err) log.Access(source, "", log.AccessRejected, err)
@ -125,7 +145,7 @@ func (this *Server) handlerUDPPayload(payload *alloc.Buffer, session *proxy.Sess
rand.Read(response.Value) rand.Read(response.Value)
respIv := response.Value respIv := response.Value
stream, err := this.config.Cipher.NewEncodingStream(key, respIv) stream, err := this.cipher.NewEncodingStream(this.cipherKey, respIv)
if err != nil { if err != nil {
log.Error("Shadowsocks: Failed to create encoding stream: ", err) log.Error("Shadowsocks: Failed to create encoding stream: ", err)
return return
@ -149,7 +169,7 @@ func (this *Server) handlerUDPPayload(payload *alloc.Buffer, session *proxy.Sess
writer.Write(payload.Value) writer.Write(payload.Value)
if request.OTA { if request.OTA {
respAuth := NewAuthenticator(HeaderKeyGenerator(key, respIv)) respAuth := NewAuthenticator(HeaderKeyGenerator(this.cipherKey, respIv))
respAuth.Authenticate(response.Value, response.Value[ivLen:]) respAuth.Authenticate(response.Value, response.Value[ivLen:])
} }
@ -169,7 +189,7 @@ func (this *Server) handleConnection(conn internet.Connection) {
bufferedReader := v2io.NewBufferedReader(timedReader) bufferedReader := v2io.NewBufferedReader(timedReader)
defer bufferedReader.Release() defer bufferedReader.Release()
ivLen := this.config.Cipher.IVSize() ivLen := this.cipher.IVSize()
_, err := io.ReadFull(bufferedReader, buffer.Value[:ivLen]) _, err := io.ReadFull(bufferedReader, buffer.Value[:ivLen])
if err != nil { if err != nil {
if err != io.EOF { if err != io.EOF {
@ -180,9 +200,8 @@ func (this *Server) handleConnection(conn internet.Connection) {
} }
iv := buffer.Value[:ivLen] iv := buffer.Value[:ivLen]
key := this.config.Key
stream, err := this.config.Cipher.NewDecodingStream(key, iv) stream, err := this.cipher.NewDecodingStream(this.cipherKey, iv)
if err != nil { if err != nil {
log.Error("Shadowsocks: Failed to create decoding stream: ", err) log.Error("Shadowsocks: Failed to create decoding stream: ", err)
return return
@ -190,7 +209,7 @@ func (this *Server) handleConnection(conn internet.Connection) {
reader := crypto.NewCryptionReader(stream, bufferedReader) reader := crypto.NewCryptionReader(stream, bufferedReader)
request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(key, iv)), false) request, err := ReadRequest(reader, NewAuthenticator(HeaderKeyGenerator(this.cipherKey, iv)), false)
if err != nil { if err != nil {
log.Access(conn.RemoteAddr(), "", log.AccessRejected, err) log.Access(conn.RemoteAddr(), "", log.AccessRejected, err)
log.Warning("Shadowsocks: Invalid request from ", conn.RemoteAddr(), ": ", err) log.Warning("Shadowsocks: Invalid request from ", conn.RemoteAddr(), ": ", err)
@ -199,7 +218,7 @@ func (this *Server) handleConnection(conn internet.Connection) {
defer request.Release() defer request.Release()
bufferedReader.SetCached(false) bufferedReader.SetCached(false)
userSettings := protocol.GetUserSettings(this.config.Level) userSettings := this.config.GetUser().GetSettings()
timedReader.SetTimeOut(userSettings.PayloadReadTimeout) timedReader.SetTimeOut(userSettings.PayloadReadTimeout)
dest := v2net.TCPDestination(request.Address, request.Port) dest := v2net.TCPDestination(request.Address, request.Port)
@ -219,7 +238,7 @@ func (this *Server) handleConnection(conn internet.Connection) {
payload.SliceBack(ivLen) payload.SliceBack(ivLen)
rand.Read(payload.Value[:ivLen]) rand.Read(payload.Value[:ivLen])
stream, err := this.config.Cipher.NewEncodingStream(key, payload.Value[:ivLen]) stream, err := this.cipher.NewEncodingStream(this.cipherKey, payload.Value[:ivLen])
if err != nil { if err != nil {
log.Error("Shadowsocks: Failed to create encoding stream: ", err) log.Error("Shadowsocks: Failed to create encoding stream: ", err)
return return
@ -264,10 +283,7 @@ func (this *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *
if !space.HasApp(dispatcher.APP_ID) { if !space.HasApp(dispatcher.APP_ID) {
return nil, common.ErrBadConfiguration return nil, common.ErrBadConfiguration
} }
return NewServer( return NewServer(rawConfig.(*Config), space, meta)
rawConfig.(*Config),
space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher),
meta), nil
} }
func init() { func init() {

View File

@ -4,15 +4,17 @@ import (
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
) )
type Account struct {
Username string `json:"user"`
Password string `json:"pass"`
}
func (this *Account) Equals(another protocol.Account) bool { func (this *Account) Equals(another protocol.Account) bool {
socksAccount, ok := another.(*Account) if account, ok := another.(*Account); ok {
if !ok { return this.Username == account.Username
}
return false return false
} }
return this.Username == socksAccount.Username
func (this *Account) AsAccount() (protocol.Account, error) {
return this, nil
}
func NewAccount() protocol.AsAccount {
return &Account{}
} }

View File

@ -2,8 +2,27 @@ package socks
import ( import (
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"github.com/golang/protobuf/ptypes"
google_protobuf "github.com/golang/protobuf/ptypes/any"
) )
func AccountEquals(a, b *google_protobuf.Any) bool {
accountA := new(Account)
if err := ptypes.UnmarshalAny(a, accountA); err != nil {
return false
}
accountB := new(Account)
if err := ptypes.UnmarshalAny(b, accountB); err != nil {
return false
}
return accountA.Equals(accountB)
}
func (this *Account) AsAny() (*google_protobuf.Any, error) {
return ptypes.MarshalAny(this)
}
type ClientConfig struct { type ClientConfig struct {
Servers []*protocol.ServerSpec Servers []*protocol.ServerSpec
} }

View File

@ -0,0 +1,61 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/proxy/socks/client_config.proto
// DO NOT EDIT!
/*
Package socks is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/proxy/socks/client_config.proto
v2ray.com/core/proxy/socks/server_config.proto
It has these top-level messages:
Account
ServerConfig
*/
package socks
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Account struct {
Username string `protobuf:"bytes,1,opt,name=username" json:"username,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password" json:"password,omitempty"`
}
func (m *Account) Reset() { *m = Account{} }
func (m *Account) String() string { return proto.CompactTextString(m) }
func (*Account) ProtoMessage() {}
func (*Account) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func init() {
proto.RegisterType((*Account)(nil), "com.v2ray.core.proxy.socks.Account")
}
func init() { proto.RegisterFile("v2ray.com/core/proxy/socks/client_config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 146 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xd2, 0x2b, 0x33, 0x2a, 0x4a,
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x2f, 0x28, 0xca, 0xaf, 0xa8,
0xd4, 0x2f, 0xce, 0x4f, 0xce, 0x2e, 0xd6, 0x4f, 0xce, 0xc9, 0x4c, 0xcd, 0x2b, 0x89, 0x4f, 0xce,
0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x4a, 0xce, 0xcf, 0x85,
0xeb, 0x29, 0x4a, 0xd5, 0x03, 0xab, 0xd7, 0x03, 0xab, 0x57, 0x72, 0xe4, 0x62, 0x77, 0x4c, 0x4e,
0xce, 0x2f, 0xcd, 0x2b, 0x11, 0x92, 0xe2, 0xe2, 0x28, 0x2d, 0x4e, 0x2d, 0xca, 0x4b, 0xcc, 0x4d,
0x95, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x82, 0xf3, 0x41, 0x72, 0x05, 0x89, 0xc5, 0xc5, 0xe5,
0xf9, 0x45, 0x29, 0x12, 0x4c, 0x10, 0x39, 0x18, 0xdf, 0x89, 0x3d, 0x8a, 0x15, 0x6c, 0x56, 0x12,
0x1b, 0xd8, 0x3a, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe9, 0xf0, 0x36, 0x26, 0xa0, 0x00,
0x00, 0x00,
}

View File

@ -0,0 +1,9 @@
syntax = "proto3";
package com.v2ray.core.proxy.socks;
option go_package = "socks";
message Account {
string username = 1;
string password = 2;
}

View File

@ -11,6 +11,20 @@ import (
"v2ray.com/core/proxy/registry" "v2ray.com/core/proxy/registry"
) )
func (this *Account) UnmarshalJSON(data []byte) error {
type JsonConfig struct {
Username string `json:"user"`
Password string `json:"pass"`
}
jsonConfig := new(JsonConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil {
return errors.New("Socks: Failed to parse account: " + err.Error())
}
this.Username = jsonConfig.Username
this.Password = jsonConfig.Password
return nil
}
func (this *ClientConfig) UnmarshalJSON(data []byte) error { func (this *ClientConfig) UnmarshalJSON(data []byte) error {
type ServerConfig struct { type ServerConfig struct {
Address *v2net.AddressPB `json:"address"` Address *v2net.AddressPB `json:"address"`
@ -26,7 +40,7 @@ func (this *ClientConfig) UnmarshalJSON(data []byte) error {
} }
this.Servers = make([]*protocol.ServerSpec, len(jsonConfig.Servers)) this.Servers = make([]*protocol.ServerSpec, len(jsonConfig.Servers))
for idx, serverConfig := range jsonConfig.Servers { for idx, serverConfig := range jsonConfig.Servers {
server := protocol.NewServerSpec(v2net.TCPDestination(serverConfig.Address.AsAddress(), serverConfig.Port), protocol.AlwaysValid()) server := protocol.NewServerSpec(NewAccount, v2net.TCPDestination(serverConfig.Address.AsAddress(), serverConfig.Port), protocol.AlwaysValid())
for _, rawUser := range serverConfig.Users { for _, rawUser := range serverConfig.Users {
user := new(protocol.User) user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil { if err := json.Unmarshal(rawUser, user); err != nil {
@ -36,7 +50,11 @@ func (this *ClientConfig) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(rawUser, account); err != nil { if err := json.Unmarshal(rawUser, account); err != nil {
return errors.New("Socks|Client: Failed to parse socks account: " + err.Error()) return errors.New("Socks|Client: Failed to parse socks account: " + err.Error())
} }
user.Account = account anyAccount, err := account.AsAny()
if err != nil {
return err
}
user.Account = anyAccount
server.AddUser(user) server.AddUser(user)
} }
this.Servers[idx] = server this.Servers[idx] = server

View File

@ -2,15 +2,6 @@
// source: v2ray.com/core/proxy/socks/server_config.proto // source: v2ray.com/core/proxy/socks/server_config.proto
// DO NOT EDIT! // DO NOT EDIT!
/*
Package socks is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/proxy/socks/server_config.proto
It has these top-level messages:
ServerConfig
*/
package socks package socks
import proto "github.com/golang/protobuf/proto" import proto "github.com/golang/protobuf/proto"
@ -23,12 +14,6 @@ var _ = proto.Marshal
var _ = fmt.Errorf var _ = fmt.Errorf
var _ = math.Inf var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type ServerConfig_AuthType int32 type ServerConfig_AuthType int32
const ( const (
@ -48,7 +33,7 @@ var ServerConfig_AuthType_value = map[string]int32{
func (x ServerConfig_AuthType) String() string { func (x ServerConfig_AuthType) String() string {
return proto.EnumName(ServerConfig_AuthType_name, int32(x)) return proto.EnumName(ServerConfig_AuthType_name, int32(x))
} }
func (ServerConfig_AuthType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } func (ServerConfig_AuthType) EnumDescriptor() ([]byte, []int) { return fileDescriptor1, []int{0, 0} }
type ServerConfig struct { type ServerConfig struct {
AuthType ServerConfig_AuthType `protobuf:"varint,1,opt,name=auth_type,json=authType,enum=com.v2ray.core.proxy.socks.ServerConfig_AuthType" json:"auth_type,omitempty"` AuthType ServerConfig_AuthType `protobuf:"varint,1,opt,name=auth_type,json=authType,enum=com.v2ray.core.proxy.socks.ServerConfig_AuthType" json:"auth_type,omitempty"`
@ -61,7 +46,7 @@ type ServerConfig struct {
func (m *ServerConfig) Reset() { *m = ServerConfig{} } func (m *ServerConfig) Reset() { *m = ServerConfig{} }
func (m *ServerConfig) String() string { return proto.CompactTextString(m) } func (m *ServerConfig) String() string { return proto.CompactTextString(m) }
func (*ServerConfig) ProtoMessage() {} func (*ServerConfig) ProtoMessage() {}
func (*ServerConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (*ServerConfig) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
func (m *ServerConfig) GetAccounts() map[string]string { func (m *ServerConfig) GetAccounts() map[string]string {
if m != nil { if m != nil {
@ -82,9 +67,9 @@ func init() {
proto.RegisterEnum("com.v2ray.core.proxy.socks.ServerConfig_AuthType", ServerConfig_AuthType_name, ServerConfig_AuthType_value) proto.RegisterEnum("com.v2ray.core.proxy.socks.ServerConfig_AuthType", ServerConfig_AuthType_name, ServerConfig_AuthType_value)
} }
func init() { proto.RegisterFile("v2ray.com/core/proxy/socks/server_config.proto", fileDescriptor0) } func init() { proto.RegisterFile("v2ray.com/core/proxy/socks/server_config.proto", fileDescriptor1) }
var fileDescriptor0 = []byte{ var fileDescriptor1 = []byte{
// 345 bytes of a gzipped FileDescriptorProto // 345 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x91, 0xd1, 0x4b, 0xeb, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x91, 0xd1, 0x4b, 0xeb, 0x30,
0x14, 0xc6, 0x6f, 0xd7, 0xbb, 0xdb, 0x2e, 0xdd, 0x2e, 0x23, 0xf8, 0x50, 0xf6, 0x62, 0x19, 0x8a, 0x14, 0xc6, 0x6f, 0xd7, 0xbb, 0xdb, 0x2e, 0xdd, 0x2e, 0x23, 0xf8, 0x50, 0xf6, 0x62, 0x19, 0x8a,

46
proxy/vmess/account.go Normal file
View File

@ -0,0 +1,46 @@
package vmess
import (
"v2ray.com/core/common/dice"
"v2ray.com/core/common/log"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
)
type Account struct {
ID *protocol.ID
AlterIDs []*protocol.ID
}
func NewAccount() protocol.AsAccount {
return &AccountPB{}
}
func (this *Account) AnyValidID() *protocol.ID {
if len(this.AlterIDs) == 0 {
return this.ID
}
return this.AlterIDs[dice.Roll(len(this.AlterIDs))]
}
func (this *Account) Equals(account protocol.Account) bool {
vmessAccount, ok := account.(*Account)
if !ok {
return false
}
// TODO: handle AlterIds difference
return this.ID.Equals(vmessAccount.ID)
}
func (this *AccountPB) AsAccount() (protocol.Account, error) {
id, err := uuid.ParseString(this.Id)
if err != nil {
log.Error("VMess: Failed to parse ID: ", err)
return nil, err
}
protoId := protocol.NewID(id)
return &Account{
ID: protoId,
AlterIDs: protocol.NewAlterIDs(protoId, uint16(this.AlterId)),
}, nil
}

58
proxy/vmess/account.pb.go Normal file
View File

@ -0,0 +1,58 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/proxy/vmess/account.proto
// DO NOT EDIT!
/*
Package vmess is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/proxy/vmess/account.proto
It has these top-level messages:
AccountPB
*/
package vmess
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type AccountPB struct {
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
AlterId uint32 `protobuf:"varint,2,opt,name=alterId" json:"alterId,omitempty"`
}
func (m *AccountPB) Reset() { *m = AccountPB{} }
func (m *AccountPB) String() string { return proto.CompactTextString(m) }
func (*AccountPB) ProtoMessage() {}
func (*AccountPB) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func init() {
proto.RegisterType((*AccountPB)(nil), "com.v2ray.core.proxy.vmess.AccountPB")
}
func init() { proto.RegisterFile("v2ray.com/core/proxy/vmess/account.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 138 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xd2, 0x28, 0x33, 0x2a, 0x4a,
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x2f, 0x28, 0xca, 0xaf, 0xa8,
0xd4, 0x2f, 0xcb, 0x4d, 0x2d, 0x2e, 0xd6, 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0xd1, 0x2b,
0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x4a, 0xce, 0xcf, 0xd5, 0x83, 0xa9, 0x2e, 0x4a, 0xd5, 0x03,
0xab, 0xd4, 0x03, 0xab, 0x54, 0x32, 0xe5, 0xe2, 0x74, 0x84, 0x28, 0x0e, 0x70, 0x12, 0xe2, 0xe3,
0x62, 0xca, 0x4c, 0x91, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x62, 0xca, 0x4c, 0x11, 0x92, 0xe0,
0x62, 0x4f, 0xcc, 0x29, 0x49, 0x2d, 0xf2, 0x4c, 0x91, 0x60, 0x52, 0x60, 0xd4, 0xe0, 0x0d, 0x82,
0x71, 0x9d, 0xd8, 0xa3, 0x58, 0xc1, 0xfa, 0x93, 0xd8, 0xc0, 0x56, 0x18, 0x03, 0x02, 0x00, 0x00,
0xff, 0xff, 0xe4, 0xea, 0x97, 0xa3, 0x8e, 0x00, 0x00, 0x00,
}

View File

@ -0,0 +1,9 @@
syntax = "proto3";
package com.v2ray.core.proxy.vmess;
option go_package = "vmess";
message AccountPB {
string id = 1;
uint32 alterId = 2;
}

View File

@ -4,13 +4,9 @@ package vmess
import ( import (
"encoding/json" "encoding/json"
"v2ray.com/core/common/log"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/uuid"
) )
func (u *Account) UnmarshalJSON(data []byte) error { func (u *AccountPB) UnmarshalJSON(data []byte) error {
type JsonConfig struct { type JsonConfig struct {
ID string `json:"id"` ID string `json:"id"`
AlterIds uint16 `json:"alterId"` AlterIds uint16 `json:"alterId"`
@ -19,13 +15,8 @@ func (u *Account) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &rawConfig); err != nil { if err := json.Unmarshal(data, &rawConfig); err != nil {
return err return err
} }
id, err := uuid.ParseString(rawConfig.ID) u.Id = rawConfig.ID
if err != nil { u.AlterId = uint32(rawConfig.AlterIds)
log.Error("VMess: Failed to parse ID: ", err)
return err
}
u.ID = protocol.NewID(id)
u.AlterIDs = protocol.NewAlterIDs(u.ID, rawConfig.AlterIds)
return nil return nil
} }

View File

@ -52,7 +52,12 @@ func NewClientSession(idHash protocol.IDHash) *ClientSession {
func (this *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) { func (this *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) {
timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)() timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)()
idHash := this.idHash(header.User.Account.(*vmess.Account).AnyValidID().Bytes()) account, err := header.User.GetTypedAccount(&vmess.AccountPB{})
if err != nil {
log.Error("VMess: Failed to get user account: ", err)
return
}
idHash := this.idHash(account.(*vmess.Account).AnyValidID().Bytes())
idHash.Write(timestamp.Bytes(nil)) idHash.Write(timestamp.Bytes(nil))
writer.Write(idHash.Sum(nil)) writer.Write(idHash.Sum(nil))
@ -83,8 +88,7 @@ func (this *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, w
timestampHash := md5.New() timestampHash := md5.New()
timestampHash.Write(hashTimestamp(timestamp)) timestampHash.Write(hashTimestamp(timestamp))
iv := timestampHash.Sum(nil) iv := timestampHash.Sum(nil)
account := header.User.Account.(*vmess.Account) aesStream := crypto.NewAesEncryptionStream(account.(*vmess.Account).ID.CmdKey(), iv)
aesStream := crypto.NewAesEncryptionStream(account.ID.CmdKey(), iv)
aesStream.XORKeyStream(buffer, buffer) aesStream.XORKeyStream(buffer, buffer)
writer.Write(buffer) writer.Write(buffer)

View File

@ -139,7 +139,7 @@ func (this *CommandSwitchAccountFactory) Unmarshal(data []byte) (interface{}, er
if len(data) < levelStart+1 { if len(data) < levelStart+1 {
return nil, transport.ErrCorruptedPacket return nil, transport.ErrCorruptedPacket
} }
cmd.Level = protocol.UserLevel(data[levelStart]) cmd.Level = uint32(data[levelStart])
timeStart := levelStart + 1 timeStart := levelStart + 1
if len(data) < timeStart { if len(data) < timeStart {
return nil, transport.ErrCorruptedPacket return nil, transport.ErrCorruptedPacket

View File

@ -10,18 +10,24 @@ import (
"v2ray.com/core/proxy/vmess" "v2ray.com/core/proxy/vmess"
. "v2ray.com/core/proxy/vmess/encoding" . "v2ray.com/core/proxy/vmess/encoding"
"v2ray.com/core/testing/assert" "v2ray.com/core/testing/assert"
"github.com/golang/protobuf/ptypes"
) )
func TestRequestSerialization(t *testing.T) { func TestRequestSerialization(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
user := protocol.NewUser( user := &protocol.User{
protocol.UserLevelUntrusted, Level: 0,
"test@v2ray.com") Email: "test@v2ray.com",
user.Account = &vmess.Account{
ID: protocol.NewID(uuid.New()),
AlterIDs: nil,
} }
account := &vmess.AccountPB{
Id: uuid.New().String(),
AlterId: 0,
}
anyAccount, err := ptypes.MarshalAny(account)
assert.Error(err).IsNil()
user.Account = anyAccount
expectedRequest := &protocol.RequestHeader{ expectedRequest := &protocol.RequestHeader{
Version: 1, Version: 1,

View File

@ -59,8 +59,12 @@ func (this *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Requ
timestampHash := md5.New() timestampHash := md5.New()
timestampHash.Write(hashTimestamp(timestamp)) timestampHash.Write(hashTimestamp(timestamp))
iv := timestampHash.Sum(nil) iv := timestampHash.Sum(nil)
account := user.Account.(*vmess.Account) account, err := user.GetTypedAccount(&vmess.AccountPB{})
aesStream := crypto.NewAesDecryptionStream(account.ID.CmdKey(), iv) if err != nil {
log.Error("Vmess: Failed to get user account: ", err)
return nil, err
}
aesStream := crypto.NewAesDecryptionStream(account.(*vmess.Account).ID.CmdKey(), iv)
decryptor := crypto.NewCryptionReader(aesStream, reader) decryptor := crypto.NewCryptionReader(aesStream, reader)
nBytes, err := io.ReadFull(decryptor, buffer[:41]) nBytes, err := io.ReadFull(decryptor, buffer[:41])

View File

@ -22,10 +22,11 @@ func (this *VMessInboundHandler) generateCommand(request *protocol.RequestHeader
if user == nil { if user == nil {
return nil return nil
} }
account, _ := user.GetTypedAccount(&vmess.AccountPB{})
return &protocol.CommandSwitchAccount{ return &protocol.CommandSwitchAccount{
Port: inboundHandler.Port(), Port: inboundHandler.Port(),
ID: user.Account.(*vmess.Account).ID.UUID(), ID: account.(*vmess.Account).ID.UUID(),
AlterIds: uint16(len(user.Account.(*vmess.Account).AlterIDs)), AlterIds: uint16(len(account.(*vmess.Account).AlterIDs)),
Level: user.Level, Level: user.Level,
ValidMin: byte(availableMin), ValidMin: byte(availableMin),
} }

View File

@ -14,7 +14,7 @@ type FeaturesConfig struct {
type DefaultConfig struct { type DefaultConfig struct {
AlterIDs uint16 AlterIDs uint16
Level protocol.UserLevel Level uint32
} }
type Config struct { type Config struct {

View File

@ -6,9 +6,13 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"v2ray.com/core/common"
"v2ray.com/core/common/log"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/proxy/registry" "v2ray.com/core/proxy/registry"
"v2ray.com/core/proxy/vmess" "v2ray.com/core/proxy/vmess"
"github.com/golang/protobuf/ptypes"
) )
func (this *DetourConfig) UnmarshalJSON(data []byte) error { func (this *DetourConfig) UnmarshalJSON(data []byte) error {
@ -48,7 +52,7 @@ func (this *DefaultConfig) UnmarshalJSON(data []byte) error {
if this.AlterIDs == 0 { if this.AlterIDs == 0 {
this.AlterIDs = 32 this.AlterIDs = 32
} }
this.Level = protocol.UserLevel(jsonConfig.Level) this.Level = uint32(jsonConfig.Level)
return nil return nil
} }
@ -67,7 +71,7 @@ func (this *Config) UnmarshalJSON(data []byte) error {
this.Defaults = jsonConfig.Defaults this.Defaults = jsonConfig.Defaults
if this.Defaults == nil { if this.Defaults == nil {
this.Defaults = &DefaultConfig{ this.Defaults = &DefaultConfig{
Level: protocol.UserLevel(0), Level: 0,
AlterIDs: 32, AlterIDs: 32,
} }
} }
@ -82,11 +86,16 @@ func (this *Config) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(rawData, user); err != nil { if err := json.Unmarshal(rawData, user); err != nil {
return errors.New("VMess|Inbound: Invalid user: " + err.Error()) return errors.New("VMess|Inbound: Invalid user: " + err.Error())
} }
account := new(vmess.Account) account := new(vmess.AccountPB)
if err := json.Unmarshal(rawData, account); err != nil { if err := json.Unmarshal(rawData, account); err != nil {
return errors.New("VMess|Inbound: Invalid user: " + err.Error()) return errors.New("VMess|Inbound: Invalid user: " + err.Error())
} }
user.Account = account anyAccount, err := ptypes.MarshalAny(account)
if err != nil {
log.Error("VMess|Inbound: Failed to create account: ", err)
return common.ErrBadConfiguration
}
user.Account = anyAccount
this.AllowedUsers[idx] = user this.AllowedUsers[idx] = user
} }

View File

@ -20,12 +20,14 @@ import (
"v2ray.com/core/proxy/vmess/encoding" "v2ray.com/core/proxy/vmess/encoding"
vmessio "v2ray.com/core/proxy/vmess/io" vmessio "v2ray.com/core/proxy/vmess/io"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
"github.com/golang/protobuf/ptypes"
) )
type userByEmail struct { type userByEmail struct {
sync.RWMutex sync.RWMutex
cache map[string]*protocol.User cache map[string]*protocol.User
defaultLevel protocol.UserLevel defaultLevel uint32
defaultAlterIDs uint16 defaultAlterIDs uint16
} }
@ -51,14 +53,16 @@ func (this *userByEmail) Get(email string) (*protocol.User, bool) {
this.Lock() this.Lock()
user, found = this.cache[email] user, found = this.cache[email]
if !found { if !found {
id := protocol.NewID(uuid.New()) account := &vmess.AccountPB{
alterIDs := protocol.NewAlterIDs(id, this.defaultAlterIDs) Id: uuid.New().String(),
account := &vmess.Account{ AlterId: uint32(this.defaultAlterIDs),
ID: id, }
AlterIDs: alterIDs, anyAccount, _ := ptypes.MarshalAny(account)
user = &protocol.User{
Level: this.defaultLevel,
Email: email,
Account: anyAccount,
} }
user = protocol.NewUser(this.defaultLevel, email)
user.Account = account
this.cache[email] = user this.cache[email] = user
} }
this.Unlock() this.Unlock()
@ -176,7 +180,7 @@ func (this *VMessInboundHandler) HandleConnection(connection internet.Connection
var readFinish sync.Mutex var readFinish sync.Mutex
readFinish.Lock() readFinish.Lock()
userSettings := protocol.GetUserSettings(request.User.Level) userSettings := request.User.GetSettings()
connReader.SetTimeOut(userSettings.PayloadReadTimeout) connReader.SetTimeOut(userSettings.PayloadReadTimeout)
reader.SetCached(false) reader.SetCached(false)

View File

@ -6,20 +6,24 @@ import (
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/proxy/vmess" "v2ray.com/core/proxy/vmess"
"github.com/golang/protobuf/ptypes"
) )
func (this *VMessOutboundHandler) handleSwitchAccount(cmd *protocol.CommandSwitchAccount) { func (this *VMessOutboundHandler) handleSwitchAccount(cmd *protocol.CommandSwitchAccount) {
primary := protocol.NewID(cmd.ID) account := &vmess.AccountPB{
alters := protocol.NewAlterIDs(primary, cmd.AlterIds) Id: cmd.ID.String(),
account := &vmess.Account{ AlterId: uint32(cmd.AlterIds),
ID: primary, }
AlterIDs: alters, anyAccount, _ := ptypes.MarshalAny(account)
user := &protocol.User{
Email: "",
Level: cmd.Level,
Account: anyAccount,
} }
user := protocol.NewUser(cmd.Level, "")
user.Account = account
dest := v2net.TCPDestination(cmd.Host, cmd.Port) dest := v2net.TCPDestination(cmd.Host, cmd.Port)
until := time.Now().Add(time.Duration(cmd.ValidMin) * time.Minute) until := time.Now().Add(time.Duration(cmd.ValidMin) * time.Minute)
this.serverList.AddServer(protocol.NewServerSpec(dest, protocol.BeforeTime(until), user)) this.serverList.AddServer(protocol.NewServerSpec(vmess.NewAccount, dest, protocol.BeforeTime(until), user))
} }
func (this *VMessOutboundHandler) handleCommand(dest v2net.Destination, cmd protocol.ResponseCommand) { func (this *VMessOutboundHandler) handleCommand(dest v2net.Destination, cmd protocol.ResponseCommand) {

View File

@ -13,6 +13,8 @@ import (
"v2ray.com/core/common/serial" "v2ray.com/core/common/serial"
"v2ray.com/core/proxy/registry" "v2ray.com/core/proxy/registry"
"v2ray.com/core/proxy/vmess" "v2ray.com/core/proxy/vmess"
"github.com/golang/protobuf/ptypes"
) )
func (this *Config) UnmarshalJSON(data []byte) error { func (this *Config) UnmarshalJSON(data []byte) error {
@ -48,19 +50,24 @@ func (this *Config) UnmarshalJSON(data []byte) error {
Ip: serial.Uint32ToBytes(757086633, nil), Ip: serial.Uint32ToBytes(757086633, nil),
} }
} }
spec := protocol.NewServerSpec(v2net.TCPDestination(rec.Address.AsAddress(), rec.Port), protocol.AlwaysValid()) spec := protocol.NewServerSpec(vmess.NewAccount, v2net.TCPDestination(rec.Address.AsAddress(), rec.Port), protocol.AlwaysValid())
for _, rawUser := range rec.Users { for _, rawUser := range rec.Users {
user := new(protocol.User) user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil { if err := json.Unmarshal(rawUser, user); err != nil {
log.Error("VMess|Outbound: Invalid user: ", err) log.Error("VMess|Outbound: Invalid user: ", err)
return err return err
} }
account := new(vmess.Account) account := new(vmess.AccountPB)
if err := json.Unmarshal(rawUser, account); err != nil { if err := json.Unmarshal(rawUser, account); err != nil {
log.Error("VMess|Outbound: Invalid user: ", err) log.Error("VMess|Outbound: Invalid user: ", err)
return err return err
} }
user.Account = account anyAccount, err := ptypes.MarshalAny(account)
if err != nil {
log.Error("VMess|Outbound: Failed to create account: ", err)
return common.ErrBadConfiguration
}
user.Account = anyAccount
spec.AddUser(user) spec.AddUser(user)
} }

View File

@ -9,32 +9,10 @@ import (
"sync" "sync"
"time" "time"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/common/signal" "v2ray.com/core/common/signal"
) )
type Account struct {
ID *protocol.ID
AlterIDs []*protocol.ID
}
func (this *Account) AnyValidID() *protocol.ID {
if len(this.AlterIDs) == 0 {
return this.ID
}
return this.AlterIDs[dice.Roll(len(this.AlterIDs))]
}
func (this *Account) Equals(account protocol.Account) bool {
vmessAccount, ok := account.(*Account)
if !ok {
return false
}
// TODO: handle AlterIds difference
return this.ID.Equals(vmessAccount.ID)
}
const ( const (
updateIntervalSec = 10 updateIntervalSec = 10
cacheDurationSec = 120 cacheDurationSec = 120
@ -140,7 +118,11 @@ L:
func (this *TimedUserValidator) Add(user *protocol.User) error { func (this *TimedUserValidator) Add(user *protocol.User) error {
idx := len(this.validUsers) idx := len(this.validUsers)
this.validUsers = append(this.validUsers, user) this.validUsers = append(this.validUsers, user)
account := user.Account.(*Account) rawAccount, err := user.GetTypedAccount(&AccountPB{})
if err != nil {
return err
}
account := rawAccount.(*Account)
nowSec := time.Now().Unix() nowSec := time.Now().Unix()

View File

@ -5,7 +5,7 @@ for DIR in $(find ./v2ray.com/core -type d -not -path "*.git*"); do
TEST_FILES=($DIR/*.proto) TEST_FILES=($DIR/*.proto)
#echo ${TEST_FILES} #echo ${TEST_FILES}
if [ -f ${TEST_FILES[0]} ]; then if [ -f ${TEST_FILES[0]} ]; then
protoc --proto_path=. --go_out=. $DIR/*.proto protoc --proto_path=. --proto_path=./github.com/google/protobuf/src --go_out=. $DIR/*.proto
fi fi
done done
popd popd