Compare commits

..

12 Commits

Author SHA1 Message Date
v2ray
164465e60d more test case 2015-12-12 17:17:23 +01:00
v2ray
b87cc5baf1 fix a bug in fieldrule 2015-12-12 17:15:29 +01:00
v2ray
fed5697dc3 SwitchAccount command 2015-12-12 13:11:49 +01:00
v2ray
47f35b1c3e uuid 2015-12-12 11:32:40 +01:00
Darien Raymond
b6ed26aedf pubsub 2015-12-11 14:56:10 +00:00
Darien Raymond
a540d7dc99 allow dns modification only from trusted tags 2015-12-11 11:08:07 +00:00
Darien Raymond
dd81fc6f6a hide space implementations from interfaces 2015-12-11 11:01:20 +00:00
v2ray
46ab9c45cc space with context 2015-12-10 23:55:39 +01:00
v2ray
5b3e84ede6 dns config 2015-12-10 22:08:36 +01:00
v2ray
95c8910f87 fix v2ray tmp path 2015-12-10 15:45:51 +01:00
v2ray
e57132a36e update to 1.1.3 2015-12-10 15:10:15 +01:00
v2ray
aa83ea35ca really fix test break 2015-12-10 15:03:55 +01:00
49 changed files with 748 additions and 87 deletions

View File

@@ -0,0 +1,36 @@
package controller
import (
"github.com/v2ray/v2ray-core/app"
"github.com/v2ray/v2ray-core/app/internal"
)
// A SpaceController is supposed to be used by a shell to create Spaces. It should not be used
// directly by proxies.
type SpaceController struct {
packetDispatcher internal.PacketDispatcherWithContext
dnsCache internal.DnsCacheWithContext
pubsub internal.PubsubWithContext
}
func New() *SpaceController {
return new(SpaceController)
}
func (this *SpaceController) Bind(object interface{}) {
if packetDispatcher, ok := object.(internal.PacketDispatcherWithContext); ok {
this.packetDispatcher = packetDispatcher
}
if dnsCache, ok := object.(internal.DnsCacheWithContext); ok {
this.dnsCache = dnsCache
}
if pubsub, ok := object.(internal.PubsubWithContext); ok {
this.pubsub = pubsub
}
}
func (this *SpaceController) ForContext(tag string) app.Space {
return internal.NewSpace(tag, this.packetDispatcher, this.dnsCache, this.pubsub)
}

View File

@@ -4,6 +4,7 @@ import (
"net"
)
// A DnsCache is an internal cache of DNS resolutions.
type DnsCache interface {
Get(domain string) net.IP
Add(domain string, ip net.IP)

View File

@@ -1,5 +1,5 @@
package dns
type CacheConfig interface {
TrustedSource() []string
IsTrustedSource(tag string) bool
}

View File

@@ -4,6 +4,8 @@ import (
"net"
"sync"
"time"
"github.com/v2ray/v2ray-core/app"
)
type entry struct {
@@ -31,12 +33,14 @@ func (this *entry) Extend() {
type DnsCache struct {
sync.RWMutex
cache map[string]*entry
cache map[string]*entry
config CacheConfig
}
func NewCache() *DnsCache {
func NewCache(config CacheConfig) *DnsCache {
cache := &DnsCache{
cache: make(map[string]*entry),
cache: make(map[string]*entry),
config: config,
}
go cache.cleanup()
return cache
@@ -63,7 +67,12 @@ func (this *DnsCache) cleanup() {
}
}
func (this *DnsCache) Add(domain string, ip net.IP) {
func (this *DnsCache) Add(context app.Context, domain string, ip net.IP) {
callerTag := context.CallerTag()
if !this.config.IsTrustedSource(callerTag) {
return
}
this.RLock()
entry, found := this.cache[domain]
this.RUnlock()
@@ -77,7 +86,7 @@ func (this *DnsCache) Add(domain string, ip net.IP) {
}
}
func (this *DnsCache) Get(domain string) net.IP {
func (this *DnsCache) Get(context app.Context, domain string) net.IP {
this.RLock()
entry, found := this.cache[domain]
this.RUnlock()

View File

@@ -5,6 +5,8 @@ import (
"testing"
"github.com/v2ray/v2ray-core/app/dns"
dnstesting "github.com/v2ray/v2ray-core/app/dns/testing"
apptesting "github.com/v2ray/v2ray-core/app/testing"
netassert "github.com/v2ray/v2ray-core/common/net/testing/assert"
v2testing "github.com/v2ray/v2ray-core/testing"
)
@@ -13,11 +15,19 @@ func TestDnsAdd(t *testing.T) {
v2testing.Current(t)
domain := "v2ray.com"
cache := dns.NewCache()
ip := cache.Get(domain)
cache := dns.NewCache(&dnstesting.CacheConfig{
TrustedTags: map[string]bool{
"testtag": true,
},
})
ip := cache.Get(&apptesting.Context{}, domain)
netassert.IP(ip).IsNil()
cache.Add(domain, []byte{1, 2, 3, 4})
ip = cache.Get(domain)
cache.Add(&apptesting.Context{CallerTagValue: "notvalidtag"}, domain, []byte{1, 2, 3, 4})
ip = cache.Get(&apptesting.Context{}, domain)
netassert.IP(ip).IsNil()
cache.Add(&apptesting.Context{CallerTagValue: "testtag"}, domain, []byte{1, 2, 3, 4})
ip = cache.Get(&apptesting.Context{}, domain)
netassert.IP(ip).Equals(net.IP([]byte{1, 2, 3, 4}))
}

35
app/dns/json/config.go Normal file
View File

@@ -0,0 +1,35 @@
package json
import (
"strings"
serialjson "github.com/v2ray/v2ray-core/common/serial/json"
)
type TagList map[string]bool
func NewTagList(tags []string) TagList {
list := TagList(make(map[string]bool))
for _, tag := range tags {
list[strings.TrimSpace(tag)] = true
}
return list
}
func (this *TagList) UnmarshalJSON(data []byte) error {
tags, err := serialjson.UnmarshalStringList(data)
if err != nil {
return err
}
*this = NewTagList(tags)
return nil
}
type CacheConfig struct {
TrustedTags TagList `json:"trustedTags"`
}
func (this *CacheConfig) IsTrustedSource(tag string) bool {
_, found := this.TrustedTags[tag]
return found
}

10
app/dns/testing/config.go Normal file
View File

@@ -0,0 +1,10 @@
package testing
type CacheConfig struct {
TrustedTags map[string]bool
}
func (this *CacheConfig) IsTrustedSource(tag string) bool {
_, found := this.TrustedTags[tag]
return found
}

9
app/internal/context.go Normal file
View File

@@ -0,0 +1,9 @@
package internal
type contextImpl struct {
callerTag string
}
func (this *contextImpl) CallerTag() string {
return this.callerTag
}

25
app/internal/dns.go Normal file
View File

@@ -0,0 +1,25 @@
package internal
import (
"net"
"github.com/v2ray/v2ray-core/app"
)
type DnsCacheWithContext interface {
Get(context app.Context, domain string) net.IP
Add(contaxt app.Context, domain string, ip net.IP)
}
type contextedDnsCache struct {
context app.Context
dnsCache DnsCacheWithContext
}
func (this *contextedDnsCache) Get(domain string) net.IP {
return this.dnsCache.Get(this.context, domain)
}
func (this *contextedDnsCache) Add(domain string, ip net.IP) {
this.dnsCache.Add(this.context, domain, ip)
}

View File

@@ -0,0 +1,20 @@
package internal
import (
"github.com/v2ray/v2ray-core/app"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/transport/ray"
)
type PacketDispatcherWithContext interface {
DispatchToOutbound(context app.Context, packet v2net.Packet) ray.InboundRay
}
type contextedPacketDispatcher struct {
context app.Context
packetDispatcher PacketDispatcherWithContext
}
func (this *contextedPacketDispatcher) DispatchToOutbound(packet v2net.Packet) ray.InboundRay {
return this.packetDispatcher.DispatchToOutbound(this.context, packet)
}

23
app/internal/pubsub.go Normal file
View File

@@ -0,0 +1,23 @@
package internal
import (
"github.com/v2ray/v2ray-core/app"
)
type PubsubWithContext interface {
Publish(context app.Context, topic string, message app.PubsubMessage)
Subscribe(context app.Context, topic string, handler app.TopicHandler)
}
type contextedPubsub struct {
context app.Context
pubsub PubsubWithContext
}
func (this *contextedPubsub) Publish(topic string, message app.PubsubMessage) {
this.pubsub.Publish(this.context, topic, message)
}
func (this *contextedPubsub) Subscribe(topic string, handler app.TopicHandler) {
this.pubsub.Subscribe(this.context, topic, handler)
}

60
app/internal/space.go Normal file
View File

@@ -0,0 +1,60 @@
package internal
import (
"github.com/v2ray/v2ray-core/app"
)
type Space struct {
packetDispatcher PacketDispatcherWithContext
dnsCache DnsCacheWithContext
pubsub PubsubWithContext
tag string
}
func NewSpace(tag string, packetDispatcher PacketDispatcherWithContext, dnsCache DnsCacheWithContext, pubsub PubsubWithContext) *Space {
return &Space{
tag: tag,
packetDispatcher: packetDispatcher,
dnsCache: dnsCache,
pubsub: pubsub,
}
}
func (this *Space) HasPacketDispatcher() bool {
return this.packetDispatcher != nil
}
func (this *Space) PacketDispatcher() app.PacketDispatcher {
return &contextedPacketDispatcher{
packetDispatcher: this.packetDispatcher,
context: &contextImpl{
callerTag: this.tag,
},
}
}
func (this *Space) HasDnsCache() bool {
return this.dnsCache != nil
}
func (this *Space) DnsCache() app.DnsCache {
return &contextedDnsCache{
dnsCache: this.dnsCache,
context: &contextImpl{
callerTag: this.tag,
},
}
}
func (this *Space) HasPubsub() bool {
return this.pubsub != nil
}
func (this *Space) Pubsub() app.Pubsub {
return &contextedPubsub{
pubsub: this.pubsub,
context: &contextImpl{
callerTag: this.tag,
},
}
}

9
app/pubsub.go Normal file
View File

@@ -0,0 +1,9 @@
package app
type PubsubMessage []byte
type TopicHandler func(PubsubMessage)
type Pubsub interface {
Publish(topic string, message PubsubMessage)
Subscribe(topic string, handler TopicHandler)
}

64
app/pubsub/pubsub.go Normal file
View File

@@ -0,0 +1,64 @@
package pubsub
import (
"sync"
"github.com/v2ray/v2ray-core/app"
"github.com/v2ray/v2ray-core/app/internal"
)
type TopicHandlerList struct {
sync.RWMutex
handlers []app.TopicHandler
}
func NewTopicHandlerList(handlers ...app.TopicHandler) *TopicHandlerList {
return &TopicHandlerList{
handlers: handlers,
}
}
func (this *TopicHandlerList) Add(handler app.TopicHandler) {
this.Lock()
this.handlers = append(this.handlers, handler)
this.Unlock()
}
func (this *TopicHandlerList) Dispatch(message app.PubsubMessage) {
this.RLock()
for _, handler := range this.handlers {
go handler(message)
}
this.RUnlock()
}
type Pubsub struct {
topics map[string]*TopicHandlerList
sync.RWMutex
}
func New() internal.PubsubWithContext {
return &Pubsub{
topics: make(map[string]*TopicHandlerList),
}
}
func (this *Pubsub) Publish(context app.Context, topic string, message app.PubsubMessage) {
this.RLock()
list, found := this.topics[topic]
this.RUnlock()
if found {
list.Dispatch(message)
}
}
func (this *Pubsub) Subscribe(context app.Context, topic string, handler app.TopicHandler) {
this.Lock()
defer this.Unlock()
if list, found := this.topics[topic]; found {
list.Add(handler)
} else {
this.topics[topic] = NewTopicHandlerList(handler)
}
}

38
app/pubsub/pubsub_test.go Normal file
View File

@@ -0,0 +1,38 @@
package pubsub_test
import (
"testing"
"time"
"github.com/v2ray/v2ray-core/app"
. "github.com/v2ray/v2ray-core/app/pubsub"
apptesting "github.com/v2ray/v2ray-core/app/testing"
v2testing "github.com/v2ray/v2ray-core/testing"
"github.com/v2ray/v2ray-core/testing/assert"
)
func TestPubsub(t *testing.T) {
v2testing.Current(t)
messages := make(map[string]app.PubsubMessage)
pubsub := New()
pubsub.Subscribe(&apptesting.Context{}, "t1", func(message app.PubsubMessage) {
messages["t1"] = message
})
pubsub.Subscribe(&apptesting.Context{}, "t2", func(message app.PubsubMessage) {
messages["t2"] = message
})
message := app.PubsubMessage([]byte("This is a pubsub message."))
pubsub.Publish(&apptesting.Context{}, "t2", message)
<-time.Tick(time.Second)
_, found := messages["t1"]
assert.Bool(found).IsFalse()
actualMessage, found := messages["t2"]
assert.Bool(found).IsTrue()
assert.StringLiteral(string(actualMessage)).Equals(string(message))
}

View File

@@ -57,7 +57,7 @@ func NewPlainDomainMatcher(pattern string) *PlainDomainMatcher {
}
func (this *PlainDomainMatcher) Match(domain string) bool {
return strings.Contains(this.pattern, strings.ToLower(domain))
return strings.Contains(strings.ToLower(domain), this.pattern)
}
type RegexpDomainMatcher struct {

View File

@@ -119,4 +119,7 @@ func TestDomainNotMatchingDomain(t *testing.T) {
rule := parseRule([]byte(rawJson))
dest := v2net.NewTCPDestination(v2net.DomainAddress("baidu.com", 80))
assert.Bool(rule.Apply(dest)).IsFalse()
dest = v2net.NewTCPDestination(v2net.DomainAddress("www.google.com", 80))
assert.Bool(rule.Apply(dest)).IsTrue()
}

View File

@@ -1,36 +1,19 @@
package app
type Space struct {
packetDispatcher PacketDispatcher
dnsCache DnsCache
// Context of a function call from proxy to app.
type Context interface {
CallerTag() string
}
func NewSpace() *Space {
return new(Space)
}
// A Space contains all apps that may be available in a V2Ray runtime.
// Caller must check the availability of an app by calling HasXXX before getting its instance.
type Space interface {
HasPacketDispatcher() bool
PacketDispatcher() PacketDispatcher
func (this *Space) Bind(object interface{}) {
if packetDispatcher, ok := object.(PacketDispatcher); ok {
this.packetDispatcher = packetDispatcher
}
HasDnsCache() bool
DnsCache() DnsCache
if dnsCache, ok := object.(DnsCache); ok {
this.dnsCache = dnsCache
}
}
func (this *Space) HasPacketDispatcher() bool {
return this.packetDispatcher != nil
}
func (this *Space) PacketDispatcher() PacketDispatcher {
return this.packetDispatcher
}
func (this *Space) HasDnsCache() bool {
return this.dnsCache != nil
}
func (this *Space) DnsCache() DnsCache {
return this.dnsCache
HasPubsub() bool
Pubsub() Pubsub
}

9
app/testing/space.go Normal file
View File

@@ -0,0 +1,9 @@
package testing
type Context struct {
CallerTagValue string
}
func (this *Context) CallerTag() string {
return this.CallerTagValue
}

View File

@@ -1,11 +1,10 @@
package json
import (
"encoding/json"
"errors"
"strings"
v2net "github.com/v2ray/v2ray-core/common/net"
serialjson "github.com/v2ray/v2ray-core/common/serial/json"
)
type NetworkList []string
@@ -19,21 +18,12 @@ func NewNetworkList(networks []string) NetworkList {
}
func (this *NetworkList) UnmarshalJSON(data []byte) error {
var strList []string
err := json.Unmarshal(data, &strList)
if err == nil {
*this = NewNetworkList(strList)
return nil
strlist, err := serialjson.UnmarshalStringList(data)
if err != nil {
return err
}
var str string
err = json.Unmarshal(data, &str)
if err == nil {
strList := strings.Split(str, ",")
*this = NewNetworkList(strList)
return nil
}
return errors.New("Unknown format of network list: " + string(data))
*this = NewNetworkList(strlist)
return nil
}
func (this *NetworkList) HasNetwork(network v2net.Network) bool {

23
common/serial/bytes.go Normal file
View File

@@ -0,0 +1,23 @@
package serial
type Bytes interface {
Bytes() []byte
}
type BytesLiteral []byte
func (this BytesLiteral) Value() []byte {
return []byte(this)
}
func (this BytesLiteral) Int64Value() int64 {
value := this.Value()
return int64(value[0])<<56 +
int64(value[1])<<48 +
int64(value[2])<<40 +
int64(value[3])<<32 +
int64(value[4])<<24 +
int64(value[5])<<16 +
int64(value[6])<<8 +
int64(value[7])
}

View File

@@ -0,0 +1,21 @@
package json
import (
"encoding/json"
"errors"
"strings"
)
func UnmarshalStringList(data []byte) ([]string, error) {
var strarray []string
if err := json.Unmarshal(data, &strarray); err == nil {
return strarray, nil
}
var rawstr string
if err := json.Unmarshal(data, &rawstr); err == nil {
strlist := strings.Split(rawstr, ",")
return strlist, nil
}
return nil, errors.New("Unknown format of a string list: " + string(data))
}

View File

@@ -31,3 +31,27 @@ func (this IntLiteral) String() string {
func (this IntLiteral) Value() int {
return int(this)
}
type Int64Literal int64
func (this Int64Literal) String() string {
return strconv.FormatInt(this.Value(), 10)
}
func (this Int64Literal) Value() int64 {
return int64(this)
}
func (this Int64Literal) Bytes() []byte {
value := this.Value()
return []byte{
byte(value >> 56),
byte(value >> 48),
byte(value >> 40),
byte(value >> 32),
byte(value >> 24),
byte(value >> 16),
byte(value >> 8),
byte(value),
}
}

85
common/uuid/uuid.go Normal file
View File

@@ -0,0 +1,85 @@
package uuid
import (
"crypto/rand"
"encoding/hex"
"errors"
)
var (
byteGroups = []int{8, 4, 4, 4, 12}
InvalidID = errors.New("Invalid ID.")
)
type UUID struct {
byteValue []byte
stringValue string
}
func (this *UUID) String() string {
return this.stringValue
}
func (this *UUID) Bytes() []byte {
return this.byteValue[:]
}
func bytesToString(bytes []byte) string {
result := hex.EncodeToString(bytes[0 : byteGroups[0]/2])
start := byteGroups[0] / 2
for i := 1; i < len(byteGroups); i++ {
nBytes := byteGroups[i] / 2
result += "-"
result += hex.EncodeToString(bytes[start : start+nBytes])
start += nBytes
}
return result
}
func New() *UUID {
bytes := make([]byte, 16)
rand.Read(bytes)
uuid, _ := ParseBytes(bytes)
return uuid
}
func ParseBytes(bytes []byte) (*UUID, error) {
if len(bytes) != 16 {
return nil, InvalidID
}
return &UUID{
byteValue: bytes,
stringValue: bytesToString(bytes),
}, nil
}
func ParseString(str string) (*UUID, error) {
text := []byte(str)
if len(text) < 32 {
return nil, InvalidID
}
uuid := &UUID{
byteValue: make([]byte, 16),
stringValue: str,
}
b := uuid.byteValue[:]
for _, byteGroup := range byteGroups {
if text[0] == '-' {
text = text[1:]
}
_, err := hex.Decode(b[:byteGroup/2], text[:byteGroup])
if err != nil {
return nil, err
}
text = text[byteGroup:]
b = b[byteGroup/2:]
}
return uuid, nil
}

52
common/uuid/uuid_test.go Normal file
View File

@@ -0,0 +1,52 @@
package uuid_test
import (
"testing"
. "github.com/v2ray/v2ray-core/common/uuid"
v2testing "github.com/v2ray/v2ray-core/testing"
"github.com/v2ray/v2ray-core/testing/assert"
)
func TestParseBytes(t *testing.T) {
v2testing.Current(t)
str := "2418d087-648d-4990-86e8-19dca1d006d3"
bytes := []byte{0x24, 0x18, 0xd0, 0x87, 0x64, 0x8d, 0x49, 0x90, 0x86, 0xe8, 0x19, 0xdc, 0xa1, 0xd0, 0x06, 0xd3}
uuid, err := ParseBytes(bytes)
assert.Error(err).IsNil()
assert.String(uuid).Equals(str)
}
func TestParseString(t *testing.T) {
v2testing.Current(t)
str := "2418d087-648d-4990-86e8-19dca1d006d3"
expectedBytes := []byte{0x24, 0x18, 0xd0, 0x87, 0x64, 0x8d, 0x49, 0x90, 0x86, 0xe8, 0x19, 0xdc, 0xa1, 0xd0, 0x06, 0xd3}
uuid, err := ParseString(str)
assert.Error(err).IsNil()
assert.Bytes(uuid.Bytes()).Equals(expectedBytes)
}
func TestNewUUID(t *testing.T) {
v2testing.Current(t)
uuid := New()
uuid2, err := ParseString(uuid.String())
assert.Error(err).IsNil()
assert.StringLiteral(uuid.String()).Equals(uuid2.String())
assert.Bytes(uuid.Bytes()).Equals(uuid2.Bytes())
}
func TestRandom(t *testing.T) {
v2testing.Current(t)
uuid := New()
uuid2 := New()
assert.StringLiteral(uuid.String()).NotEquals(uuid2.String())
assert.Bytes(uuid.Bytes()).NotEquals(uuid2.Bytes())
}

View File

@@ -8,7 +8,7 @@ import (
)
var (
version = "1.1.2"
version = "1.1.3"
build = "Custom"
codename = "Post Apocalypse"
intro = "A stable and unbreakable connection for everyone."

View File

@@ -32,7 +32,7 @@ func (this *BlackHole) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) e
type BlackHoleFactory struct {
}
func (this BlackHoleFactory) Create(space *app.Space, config interface{}) (connhandler.OutboundConnectionHandler, error) {
func (this BlackHoleFactory) Create(space app.Space, config interface{}) (connhandler.OutboundConnectionHandler, error) {
return NewBlackHole(), nil
}

View File

@@ -8,7 +8,7 @@ import (
// A InboundConnectionHandlerFactory creates InboundConnectionHandler on demand.
type InboundConnectionHandlerFactory interface {
// Create creates a new InboundConnectionHandler with given configuration.
Create(space *app.Space, config interface{}) (InboundConnectionHandler, error)
Create(space app.Space, config interface{}) (InboundConnectionHandler, error)
}
// A InboundConnectionHandler handles inbound network connections to V2Ray.

View File

@@ -9,7 +9,7 @@ import (
// An OutboundConnectionHandlerFactory creates OutboundConnectionHandler on demand.
type OutboundConnectionHandlerFactory interface {
// Create creates a new OutboundConnectionHandler with given config.
Create(space *app.Space, config interface{}) (OutboundConnectionHandler, error)
Create(space app.Space, config interface{}) (OutboundConnectionHandler, error)
}
// An OutboundConnectionHandler handles outbound network connection for V2Ray.

View File

@@ -16,10 +16,10 @@ type DokodemoDoor struct {
config Config
accepting bool
address v2net.Address
space *app.Space
space app.Space
}
func NewDokodemoDoor(space *app.Space, config Config) *DokodemoDoor {
func NewDokodemoDoor(space app.Space, config Config) *DokodemoDoor {
return &DokodemoDoor{
config: config,
space: space,

View File

@@ -8,7 +8,7 @@ import (
type DokodemoDoorFactory struct {
}
func (this DokodemoDoorFactory) Create(space *app.Space, rawConfig interface{}) (connhandler.InboundConnectionHandler, error) {
func (this DokodemoDoorFactory) Create(space app.Space, rawConfig interface{}) (connhandler.InboundConnectionHandler, error) {
config := rawConfig.(Config)
return NewDokodemoDoor(space, config), nil
}

View File

@@ -11,7 +11,7 @@ import (
)
type FreedomConnection struct {
space *app.Space
space app.Space
}
func (this *FreedomConnection) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) error {

View File

@@ -8,7 +8,7 @@ import (
type FreedomFactory struct {
}
func (this FreedomFactory) Create(space *app.Space, config interface{}) (connhandler.OutboundConnectionHandler, error) {
func (this FreedomFactory) Create(space app.Space, config interface{}) (connhandler.OutboundConnectionHandler, error) {
return &FreedomConnection{space: space}, nil
}

View File

@@ -24,11 +24,11 @@ var (
// SocksServer is a SOCKS 5 proxy server
type SocksServer struct {
accepting bool
space *app.Space
space app.Space
config Config
}
func NewSocksServer(space *app.Space, config Config) *SocksServer {
func NewSocksServer(space app.Space, config Config) *SocksServer {
return &SocksServer{
space: space,
config: config,

View File

@@ -8,7 +8,7 @@ import (
type SocksServerFactory struct {
}
func (this SocksServerFactory) Create(space *app.Space, rawConfig interface{}) (connhandler.InboundConnectionHandler, error) {
func (this SocksServerFactory) Create(space app.Space, rawConfig interface{}) (connhandler.InboundConnectionHandler, error) {
return NewSocksServer(space, rawConfig.(Config)), nil
}

View File

@@ -11,7 +11,7 @@ import (
type InboundConnectionHandler struct {
Port v2net.Port
space *app.Space
space app.Space
ConnInput io.Reader
ConnOutput io.Writer
}
@@ -49,7 +49,7 @@ func (this *InboundConnectionHandler) Communicate(packet v2net.Packet) error {
return nil
}
func (this *InboundConnectionHandler) Create(space *app.Space, config interface{}) (connhandler.InboundConnectionHandler, error) {
func (this *InboundConnectionHandler) Create(space app.Space, config interface{}) (connhandler.InboundConnectionHandler, error) {
this.space = space
return this, nil
}

View File

@@ -45,6 +45,6 @@ func (this *OutboundConnectionHandler) Dispatch(packet v2net.Packet, ray ray.Out
return nil
}
func (this *OutboundConnectionHandler) Create(space *app.Space, config interface{}) (connhandler.OutboundConnectionHandler, error) {
func (this *OutboundConnectionHandler) Create(space app.Space, config interface{}) (connhandler.OutboundConnectionHandler, error) {
return this, nil
}

View File

@@ -0,0 +1,40 @@
package command
import (
"io"
"time"
"github.com/v2ray/v2ray-core/common/serial"
"github.com/v2ray/v2ray-core/common/uuid"
"github.com/v2ray/v2ray-core/transport"
)
func init() {
RegisterResponseCommand(1, func() Command { return new(SwitchAccount) })
}
// Size: 16 + 8 = 24
type SwitchAccount struct {
ID *uuid.UUID
ValidUntil time.Time
}
func (this *SwitchAccount) Marshal(writer io.Writer) (int, error) {
idBytes := this.ID.Bytes()
timestamp := this.ValidUntil.Unix()
timeBytes := serial.Int64Literal(timestamp).Bytes()
writer.Write(idBytes)
writer.Write(timeBytes)
return 24, nil
}
func (this *SwitchAccount) Unmarshal(data []byte) error {
if len(data) != 24 {
return transport.CorruptedPacket
}
this.ID, _ = uuid.ParseBytes(data[0:16])
this.ValidUntil = time.Unix(serial.BytesLiteral(data[16:24]).Int64Value(), 0)
return nil
}

View File

@@ -0,0 +1,35 @@
package command_test
import (
"bytes"
"testing"
"time"
"github.com/v2ray/v2ray-core/common/uuid"
. "github.com/v2ray/v2ray-core/proxy/vmess/command"
v2testing "github.com/v2ray/v2ray-core/testing"
"github.com/v2ray/v2ray-core/testing/assert"
)
func TestSwitchAccount(t *testing.T) {
v2testing.Current(t)
sa := &SwitchAccount{
ID: uuid.New(),
ValidUntil: time.Now(),
}
cmd, err := CreateResponseCommand(1)
assert.Error(err).IsNil()
buffer := bytes.NewBuffer(make([]byte, 0, 1024))
nBytes, err := sa.Marshal(buffer)
assert.Error(err).IsNil()
assert.Int(nBytes).Equals(buffer.Len())
cmd.Unmarshal(buffer.Bytes())
sa2, ok := cmd.(*SwitchAccount)
assert.Bool(ok).IsTrue()
assert.String(sa.ID).Equals(sa2.ID.String())
assert.Int64(sa.ValidUntil.Unix()).Equals(sa2.ValidUntil.Unix())
}

View File

@@ -0,0 +1,17 @@
package command
import (
"errors"
"io"
)
var (
ErrorNoSuchCommand = errors.New("No such command.")
)
type Command interface {
Marshal(io.Writer) (int, error)
Unmarshal([]byte) error
}
type CommandCreator func() Command

View File

@@ -0,0 +1,18 @@
package command
var (
cmdCache = make(map[byte]CommandCreator)
)
func RegisterResponseCommand(id byte, cmdFactory CommandCreator) error {
cmdCache[id] = cmdFactory
return nil
}
func CreateResponseCommand(id byte) (Command, error) {
creator, found := cmdCache[id]
if !found {
return nil, ErrorNoSuchCommand
}
return creator(), nil
}

View File

@@ -20,12 +20,12 @@ import (
// Inbound connection handler that handles messages in VMess format.
type VMessInboundHandler struct {
space *app.Space
space app.Space
clients user.UserSet
accepting bool
}
func NewVMessInboundHandler(space *app.Space, clients user.UserSet) *VMessInboundHandler {
func NewVMessInboundHandler(space app.Space, clients user.UserSet) *VMessInboundHandler {
return &VMessInboundHandler{
space: space,
clients: clients,
@@ -142,7 +142,7 @@ func handleOutput(request *protocol.VMessRequest, writer io.Writer, output <-cha
type VMessInboundHandlerFactory struct {
}
func (this *VMessInboundHandlerFactory) Create(space *app.Space, rawConfig interface{}) (connhandler.InboundConnectionHandler, error) {
func (this *VMessInboundHandlerFactory) Create(space app.Space, rawConfig interface{}) (connhandler.InboundConnectionHandler, error) {
config := rawConfig.(Config)
allowedClients := user.NewTimedUserSet()

View File

@@ -19,7 +19,7 @@ import (
type VMessOutboundHandler struct {
receiverManager *ReceiverManager
space *app.Space
space app.Space
}
func (this *VMessOutboundHandler) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) error {
@@ -175,7 +175,7 @@ func handleResponse(conn net.Conn, request *protocol.VMessRequest, output chan<-
type VMessOutboundHandlerFactory struct {
}
func (this *VMessOutboundHandlerFactory) Create(space *app.Space, rawConfig interface{}) (connhandler.OutboundConnectionHandler, error) {
func (this *VMessOutboundHandlerFactory) Create(space app.Space, rawConfig interface{}) (connhandler.OutboundConnectionHandler, error) {
vOutConfig := rawConfig.(Config)
return &VMessOutboundHandler{
space: space,

View File

@@ -2,7 +2,7 @@
echo "Please make sure unzip and daemon are installed before running this script."
VER="v1.1.2"
VER="v1.1.3"
ARCH=$(uname -m)
VDIS="64"
@@ -49,7 +49,7 @@ fi
# Configure SysV if necessary.
if [ -d "/etc/init.d" ]; then
if [ ! -f "/etc/init.d/v2ray" ]; then
cp "/tmp/v2ray/systemv/v2ray" "/etc/init.d/v2ray"
cp "/tmp/v2ray/v2ray-${VER}-linux-${VDIS}/systemv/v2ray" "/etc/init.d/v2ray"
chmod +x "/etc/init.d/v2ray"
update-rc.d v2ray defaults
fi

View File

@@ -15,7 +15,7 @@ type InboundConnectionHandlerWithPort struct {
// Handler for inbound detour connections.
type InboundDetourHandler struct {
space *app.Space
space app.Space
config InboundDetourConfig
ich []*InboundConnectionHandlerWithPort
}

View File

@@ -4,7 +4,6 @@ import (
"path/filepath"
"testing"
v2net "github.com/v2ray/v2ray-core/common/net"
netassert "github.com/v2ray/v2ray-core/common/net/testing/assert"
_ "github.com/v2ray/v2ray-core/proxy/dokodemo/json"
_ "github.com/v2ray/v2ray-core/proxy/freedom/json"

View File

@@ -6,6 +6,7 @@ package point
import (
"github.com/v2ray/v2ray-core/app"
"github.com/v2ray/v2ray-core/app/controller"
"github.com/v2ray/v2ray-core/app/router"
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
@@ -22,7 +23,7 @@ type Point struct {
idh []*InboundDetourHandler
odh map[string]connhandler.OutboundConnectionHandler
router router.Router
space *app.Space
space *controller.SpaceController
}
// NewPoint returns a new Point server based on given configuration.
@@ -50,7 +51,7 @@ func NewPoint(pConfig PointConfig) (*Point, error) {
log.SetLogLevel(logConfig.LogLevel())
}
vpoint.space = app.NewSpace()
vpoint.space = controller.New()
vpoint.space.Bind(vpoint)
ichFactory := connhandler.GetInboundConnectionHandlerFactory(pConfig.InboundConfig().Protocol())
@@ -59,7 +60,7 @@ func NewPoint(pConfig PointConfig) (*Point, error) {
return nil, BadConfiguration
}
ichConfig := pConfig.InboundConfig().Settings()
ich, err := ichFactory.Create(vpoint.space, ichConfig)
ich, err := ichFactory.Create(vpoint.space.ForContext("vpoint-default-inbound"), ichConfig)
if err != nil {
log.Error("Failed to create inbound connection handler: %v", err)
return nil, err
@@ -72,7 +73,7 @@ func NewPoint(pConfig PointConfig) (*Point, error) {
return nil, BadConfiguration
}
ochConfig := pConfig.OutboundConfig().Settings()
och, err := ochFactory.Create(vpoint.space, ochConfig)
och, err := ochFactory.Create(vpoint.space.ForContext("vpoint-default-outbound"), ochConfig)
if err != nil {
log.Error("Failed to create outbound connection handler: %v", err)
return nil, err
@@ -84,7 +85,7 @@ func NewPoint(pConfig PointConfig) (*Point, error) {
vpoint.idh = make([]*InboundDetourHandler, len(detours))
for idx, detourConfig := range detours {
detourHandler := &InboundDetourHandler{
space: vpoint.space,
space: vpoint.space.ForContext(detourConfig.Tag()),
config: detourConfig,
}
err := detourHandler.Initialize()
@@ -104,7 +105,7 @@ func NewPoint(pConfig PointConfig) (*Point, error) {
log.Error("Unknown detour outbound connection handler factory %s", detourConfig.Protocol())
return nil, BadConfiguration
}
detourHandler, err := detourFactory.Create(vpoint.space, detourConfig.Settings())
detourHandler, err := detourFactory.Create(vpoint.space.ForContext(detourConfig.Tag()), detourConfig.Settings())
if err != nil {
log.Error("Failed to create detour outbound connection handler: %v", err)
return nil, err
@@ -159,7 +160,7 @@ func (this *Point) Start() error {
// Dispatches a Packet to an OutboundConnection.
// The packet will be passed through the router (if configured), and then sent to an outbound
// connection with matching tag.
func (this *Point) DispatchToOutbound(packet v2net.Packet) ray.InboundRay {
func (this *Point) DispatchToOutbound(context app.Context, packet v2net.Packet) ray.InboundRay {
direct := ray.NewRay()
dest := packet.Destination()

View File

@@ -33,3 +33,9 @@ func (subject *BytesSubject) Equals(expectation []byte) {
subject.Fail("is equal to", expectation)
}
}
func (subject *BytesSubject) NotEquals(expectation []byte) {
if bytes.Equal(subject.value, expectation) {
subject.Fail("is not equal to", expectation)
}
}

View File

@@ -34,6 +34,12 @@ func (subject *StringSubject) Equals(expectation string) {
}
}
func (subject *StringSubject) NotEquals(expectation string) {
if subject.value.String() == expectation {
subject.Fail(subject.DisplayString(), "is not equal to ", serial.StringLiteral(expectation))
}
}
func (subject *StringSubject) Contains(substring serial.String) {
if !strings.Contains(subject.value.String(), substring.String()) {
subject.Fail(subject.DisplayString(), "contains", substring)