You've already forked v2ray-core
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
164465e60d | ||
|
|
b87cc5baf1 | ||
|
|
fed5697dc3 | ||
|
|
47f35b1c3e | ||
|
|
b6ed26aedf | ||
|
|
a540d7dc99 | ||
|
|
dd81fc6f6a | ||
|
|
46ab9c45cc | ||
|
|
5b3e84ede6 | ||
|
|
95c8910f87 | ||
|
|
e57132a36e | ||
|
|
aa83ea35ca |
36
app/controller/controller.go
Normal file
36
app/controller/controller.go
Normal 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)
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package dns
|
||||
|
||||
type CacheConfig interface {
|
||||
TrustedSource() []string
|
||||
IsTrustedSource(tag string) bool
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
35
app/dns/json/config.go
Normal 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
10
app/dns/testing/config.go
Normal 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
9
app/internal/context.go
Normal 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
25
app/internal/dns.go
Normal 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)
|
||||
}
|
||||
20
app/internal/packet_dispatcher.go
Normal file
20
app/internal/packet_dispatcher.go
Normal 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
23
app/internal/pubsub.go
Normal 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
60
app/internal/space.go
Normal 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
9
app/pubsub.go
Normal 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
64
app/pubsub/pubsub.go
Normal 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
38
app/pubsub/pubsub_test.go
Normal 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))
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
41
app/space.go
41
app/space.go
@@ -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
9
app/testing/space.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package testing
|
||||
|
||||
type Context struct {
|
||||
CallerTagValue string
|
||||
}
|
||||
|
||||
func (this *Context) CallerTag() string {
|
||||
return this.CallerTagValue
|
||||
}
|
||||
@@ -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
23
common/serial/bytes.go
Normal 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])
|
||||
}
|
||||
21
common/serial/json/string_list.go
Normal file
21
common/serial/json/string_list.go
Normal 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))
|
||||
}
|
||||
@@ -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
85
common/uuid/uuid.go
Normal 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
52
common/uuid/uuid_test.go
Normal 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())
|
||||
}
|
||||
2
core.go
2
core.go
@@ -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."
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
40
proxy/vmess/command/accounts.go
Normal file
40
proxy/vmess/command/accounts.go
Normal 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
|
||||
}
|
||||
35
proxy/vmess/command/accounts_test.go
Normal file
35
proxy/vmess/command/accounts_test.go
Normal 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())
|
||||
}
|
||||
17
proxy/vmess/command/command.go
Normal file
17
proxy/vmess/command/command.go
Normal 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
|
||||
18
proxy/vmess/command/response.go
Normal file
18
proxy/vmess/command/response.go
Normal 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
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user