support using specific address

pull/298/head^2
v2ray 2016-06-04 00:38:22 +02:00
parent 6c31ff91e6
commit a4d76dc394
48 changed files with 412 additions and 301 deletions

View File

@ -20,7 +20,7 @@ func TestDnsAdd(t *testing.T) {
space := app.NewSpace() space := app.NewSpace()
outboundHandlerManager := proxyman.NewDefaultOutboundHandlerManager() outboundHandlerManager := proxyman.NewDefaultOutboundHandlerManager()
outboundHandlerManager.SetDefaultHandler(freedom.NewFreedomConnection(&freedom.Config{}, space)) outboundHandlerManager.SetDefaultHandler(freedom.NewFreedomConnection(&freedom.Config{}, space, v2net.AnyIP))
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundHandlerManager) space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundHandlerManager)
space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space)) space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space))

View File

@ -22,6 +22,10 @@ func (this Network) AsList() *NetworkList {
return &list return &list
} }
func (this Network) String() string {
return string(this)
}
// NetworkList is a list of Networks. // NetworkList is a list of Networks.
type NetworkList []Network type NetworkList []Network

View File

@ -6,5 +6,5 @@ import (
) )
func PickPort() v2net.Port { func PickPort() v2net.Port {
return v2net.Port(30000 + dice.Roll(5000)) return v2net.Port(30000 + dice.Roll(20000))
} }

View File

@ -50,7 +50,7 @@ func NewTimedUserValidator(hasher IDHash) UserValidator {
hasher: hasher, hasher: hasher,
cancel: signal.NewCloseSignal(), cancel: signal.NewCloseSignal(),
} }
go tus.updateUserHash(time.Tick(updateIntervalSec*time.Second), tus.cancel) go tus.updateUserHash(updateIntervalSec*time.Second, tus.cancel)
return tus return tus
} }
@ -88,11 +88,11 @@ func (this *TimedUserValidator) generateNewHashes(nowSec Timestamp, idx int, ent
} }
} }
func (this *TimedUserValidator) updateUserHash(tick <-chan time.Time, cancel *signal.CancelSignal) { func (this *TimedUserValidator) updateUserHash(interval time.Duration, cancel *signal.CancelSignal) {
L: L:
for { for {
select { select {
case now := <-tick: case now := <-time.After(interval):
nowSec := Timestamp(now.Unix() + cacheDurationSec) nowSec := Timestamp(now.Unix() + cacheDurationSec)
for _, entry := range this.ids { for _, entry := range this.ids {
this.generateNewHashes(nowSec, entry.userIdx, entry) this.generateNewHashes(nowSec, entry.userIdx, entry)

View File

@ -31,7 +31,7 @@ func (this *BlackHole) Dispatch(destination v2net.Destination, payload *alloc.Bu
func init() { func init() {
internal.MustRegisterOutboundHandlerCreator("blackhole", internal.MustRegisterOutboundHandlerCreator("blackhole",
func(space app.Space, config interface{}) (proxy.OutboundHandler, error) { func(space app.Space, config interface{}, sendThrough v2net.Address) (proxy.OutboundHandler, error) {
return NewBlackHole(), nil return NewBlackHole(), nil
}) })
} }

View File

@ -29,11 +29,13 @@ type DokodemoDoor struct {
listeningAddress v2net.Address listeningAddress v2net.Address
} }
func NewDokodemoDoor(config *Config, space app.Space) *DokodemoDoor { func NewDokodemoDoor(config *Config, space app.Space, listen v2net.Address, port v2net.Port) *DokodemoDoor {
d := &DokodemoDoor{ d := &DokodemoDoor{
config: config, config: config,
address: config.Address, address: config.Address,
port: config.Port, port: config.Port,
listeningAddress: listen,
listeningPort: port,
} }
space.InitializeApplication(func() error { space.InitializeApplication(func() error {
if !space.HasApp(dispatcher.APP_ID) { if !space.HasApp(dispatcher.APP_ID) {
@ -66,26 +68,20 @@ func (this *DokodemoDoor) Close() {
} }
} }
func (this *DokodemoDoor) Listen(address v2net.Address, port v2net.Port) error { func (this *DokodemoDoor) Start() error {
if this.accepting { if this.accepting {
if this.listeningPort == port && this.listeningAddress.Equals(address) { return nil
return nil
} else {
return proxy.ErrorAlreadyListening
}
} }
this.listeningPort = port
this.listeningAddress = address
this.accepting = true this.accepting = true
if this.config.Network.HasNetwork(v2net.TCPNetwork) { if this.config.Network.HasNetwork(v2net.TCPNetwork) {
err := this.ListenTCP(address, port) err := this.ListenTCP(this.listeningAddress, this.listeningPort)
if err != nil { if err != nil {
return err return err
} }
} }
if this.config.Network.HasNetwork(v2net.UDPNetwork) { if this.config.Network.HasNetwork(v2net.UDPNetwork) {
err := this.ListenUDP(address, port) err := this.ListenUDP(this.listeningAddress, this.listeningPort)
if err != nil { if err != nil {
return err return err
} }
@ -168,7 +164,7 @@ func (this *DokodemoDoor) HandleTCPConnection(conn *hub.Connection) {
func init() { func init() {
internal.MustRegisterInboundHandlerCreator("dokodemo-door", internal.MustRegisterInboundHandlerCreator("dokodemo-door",
func(space app.Space, rawConfig interface{}) (proxy.InboundHandler, error) { func(space app.Space, rawConfig interface{}, listen v2net.Address, port v2net.Port) (proxy.InboundHandler, error) {
return NewDokodemoDoor(rawConfig.(*Config), space), nil return NewDokodemoDoor(rawConfig.(*Config), space, listen, port), nil
}) })
} }

View File

@ -37,23 +37,23 @@ func TestDokodemoTCP(t *testing.T) {
space := app.NewSpace() space := app.NewSpace()
space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space)) space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space))
ohm := proxyman.NewDefaultOutboundHandlerManager() ohm := proxyman.NewDefaultOutboundHandlerManager()
ohm.SetDefaultHandler(freedom.NewFreedomConnection(&freedom.Config{}, space)) ohm.SetDefaultHandler(freedom.NewFreedomConnection(&freedom.Config{}, space, v2net.LocalHostIP))
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm) space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm)
data2Send := "Data to be sent to remote." data2Send := "Data to be sent to remote."
port := v2nettesting.PickPort()
dokodemo := NewDokodemoDoor(&Config{ dokodemo := NewDokodemoDoor(&Config{
Address: v2net.LocalHostIP, Address: v2net.LocalHostIP,
Port: tcpServer.Port, Port: tcpServer.Port,
Network: v2net.TCPNetwork.AsList(), Network: v2net.TCPNetwork.AsList(),
Timeout: 600, Timeout: 600,
}, space) }, space, v2net.LocalHostIP, port)
defer dokodemo.Close() defer dokodemo.Close()
assert.Error(space.Initialize()).IsNil() assert.Error(space.Initialize()).IsNil()
port := v2nettesting.PickPort() err = dokodemo.Start()
err = dokodemo.Listen(v2net.LocalHostIP, port)
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.Port(port).Equals(dokodemo.Port()) assert.Port(port).Equals(dokodemo.Port())
@ -95,23 +95,23 @@ func TestDokodemoUDP(t *testing.T) {
space := app.NewSpace() space := app.NewSpace()
space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space)) space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space))
ohm := proxyman.NewDefaultOutboundHandlerManager() ohm := proxyman.NewDefaultOutboundHandlerManager()
ohm.SetDefaultHandler(freedom.NewFreedomConnection(&freedom.Config{}, space)) ohm.SetDefaultHandler(freedom.NewFreedomConnection(&freedom.Config{}, space, v2net.AnyIP))
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm) space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm)
data2Send := "Data to be sent to remote." data2Send := "Data to be sent to remote."
port := v2nettesting.PickPort()
dokodemo := NewDokodemoDoor(&Config{ dokodemo := NewDokodemoDoor(&Config{
Address: v2net.LocalHostIP, Address: v2net.LocalHostIP,
Port: udpServer.Port, Port: udpServer.Port,
Network: v2net.UDPNetwork.AsList(), Network: v2net.UDPNetwork.AsList(),
Timeout: 600, Timeout: 600,
}, space) }, space, v2net.LocalHostIP, port)
defer dokodemo.Close() defer dokodemo.Close()
assert.Error(space.Initialize()).IsNil() assert.Error(space.Initialize()).IsNil()
port := v2nettesting.PickPort() err = dokodemo.Start()
err = dokodemo.Listen(v2net.LocalHostIP, port)
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.Port(port).Equals(dokodemo.Port()) assert.Port(port).Equals(dokodemo.Port())

View File

@ -23,12 +23,14 @@ type FreedomConnection struct {
domainStrategy DomainStrategy domainStrategy DomainStrategy
timeout uint32 timeout uint32
dns dns.Server dns dns.Server
sendThrough v2net.Address
} }
func NewFreedomConnection(config *Config, space app.Space) *FreedomConnection { func NewFreedomConnection(config *Config, space app.Space, sendThrough v2net.Address) *FreedomConnection {
f := &FreedomConnection{ f := &FreedomConnection{
domainStrategy: config.DomainStrategy, domainStrategy: config.DomainStrategy,
timeout: config.Timeout, timeout: config.Timeout,
sendThrough: sendThrough,
} }
space.InitializeApplication(func() error { space.InitializeApplication(func() error {
if config.DomainStrategy == DomainStrategyUseIP { if config.DomainStrategy == DomainStrategyUseIP {
@ -78,7 +80,7 @@ func (this *FreedomConnection) Dispatch(destination v2net.Destination, payload *
destination = this.ResolveIP(destination) destination = this.ResolveIP(destination)
} }
err := retry.Timed(5, 100).On(func() error { err := retry.Timed(5, 100).On(func() error {
rawConn, err := hub.DialWithoutCache(destination) rawConn, err := hub.DialWithoutCache(this.sendThrough, destination)
if err != nil { if err != nil {
return err return err
} }
@ -138,7 +140,7 @@ func (this *FreedomConnection) Dispatch(destination v2net.Destination, payload *
func init() { func init() {
internal.MustRegisterOutboundHandlerCreator("freedom", internal.MustRegisterOutboundHandlerCreator("freedom",
func(space app.Space, config interface{}) (proxy.OutboundHandler, error) { func(space app.Space, config interface{}, sendThrough v2net.Address) (proxy.OutboundHandler, error) {
return NewFreedomConnection(config.(*Config), space), nil return NewFreedomConnection(config.(*Config), space, sendThrough), nil
}) })
} }

View File

@ -37,7 +37,7 @@ func TestSinglePacket(t *testing.T) {
assert.Error(err).IsNil() assert.Error(err).IsNil()
space := app.NewSpace() space := app.NewSpace()
freedom := NewFreedomConnection(&Config{}, space) freedom := NewFreedomConnection(&Config{}, space, v2net.AnyIP)
space.Initialize() space.Initialize()
traffic := ray.NewRay() traffic := ray.NewRay()
@ -57,7 +57,7 @@ func TestSinglePacket(t *testing.T) {
func TestUnreachableDestination(t *testing.T) { func TestUnreachableDestination(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
freedom := NewFreedomConnection(&Config{}, app.NewSpace()) freedom := NewFreedomConnection(&Config{}, app.NewSpace(), v2net.AnyIP)
traffic := ray.NewRay() traffic := ray.NewRay()
data2Send := "Data to be sent to remote" data2Send := "Data to be sent to remote"
payload := alloc.NewSmallBuffer().Clear().Append([]byte(data2Send)) payload := alloc.NewSmallBuffer().Clear().Append([]byte(data2Send))
@ -81,7 +81,7 @@ func TestIPResolution(t *testing.T) {
}) })
space.BindApp(dns.APP_ID, dnsServer) space.BindApp(dns.APP_ID, dnsServer)
freedom := NewFreedomConnection(&Config{DomainStrategy: DomainStrategyUseIP}, space) freedom := NewFreedomConnection(&Config{DomainStrategy: DomainStrategyUseIP}, space, v2net.AnyIP)
space.Initialize() space.Initialize()

View File

@ -33,10 +33,12 @@ type Server struct {
listeningAddress v2net.Address listeningAddress v2net.Address
} }
func NewServer(config *Config, packetDispatcher dispatcher.PacketDispatcher) *Server { func NewServer(config *Config, packetDispatcher dispatcher.PacketDispatcher, listen v2net.Address, port v2net.Port) *Server {
return &Server{ return &Server{
packetDispatcher: packetDispatcher, packetDispatcher: packetDispatcher,
config: config, config: config,
listeningAddress: listen,
listeningPort: port,
} }
} }
@ -54,24 +56,18 @@ func (this *Server) Close() {
} }
} }
func (this *Server) Listen(address v2net.Address, port v2net.Port) error { func (this *Server) Start() error {
if this.accepting { if this.accepting {
if this.listeningPort == port && this.listeningAddress.Equals(address) { return nil
return nil
} else {
return proxy.ErrorAlreadyListening
}
} }
this.listeningPort = port
this.listeningAddress = address
var tlsConfig *tls.Config var tlsConfig *tls.Config
if this.config.TLSConfig != nil { if this.config.TLSConfig != nil {
tlsConfig = this.config.TLSConfig.GetConfig() tlsConfig = this.config.TLSConfig.GetConfig()
} }
tcpListener, err := hub.ListenTCP(address, port, this.handleConnection, tlsConfig) tcpListener, err := hub.ListenTCP(this.listeningAddress, this.listeningPort, this.handleConnection, tlsConfig)
if err != nil { if err != nil {
log.Error("HTTP: Failed listen on port ", port, ": ", err) log.Error("HTTP: Failed listen on port ", this.listeningPort, ": ", err)
return err return err
} }
this.Lock() this.Lock()
@ -276,12 +272,14 @@ func (this *Server) handlePlainHTTP(request *http.Request, dest v2net.Destinatio
func init() { func init() {
internal.MustRegisterInboundHandlerCreator("http", internal.MustRegisterInboundHandlerCreator("http",
func(space app.Space, rawConfig interface{}) (proxy.InboundHandler, error) { func(space app.Space, rawConfig interface{}, listen v2net.Address, port v2net.Port) (proxy.InboundHandler, error) {
if !space.HasApp(dispatcher.APP_ID) { if !space.HasApp(dispatcher.APP_ID) {
return nil, internal.ErrorBadConfiguration return nil, internal.ErrorBadConfiguration
} }
return NewServer( return NewServer(
rawConfig.(*Config), rawConfig.(*Config),
space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)), nil space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher),
listen,
port), nil
}) })
} }

View File

@ -52,11 +52,11 @@ func TestNormalGetRequest(t *testing.T) {
testPacketDispatcher := testdispatcher.NewTestPacketDispatcher(nil) testPacketDispatcher := testdispatcher.NewTestPacketDispatcher(nil)
httpProxy := NewServer(&Config{}, testPacketDispatcher) port := v2nettesting.PickPort()
httpProxy := NewServer(&Config{}, testPacketDispatcher, v2net.LocalHostIP, port)
defer httpProxy.Close() defer httpProxy.Close()
port := v2nettesting.PickPort() err := httpProxy.Start()
err := httpProxy.Listen(v2net.LocalHostIP, port)
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.Port(port).Equals(httpProxy.Port()) assert.Port(port).Equals(httpProxy.Port())

View File

@ -2,8 +2,9 @@ package internal
import ( import (
"github.com/v2ray/v2ray-core/app" "github.com/v2ray/v2ray-core/app"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy" "github.com/v2ray/v2ray-core/proxy"
) )
type InboundHandlerCreator func(space app.Space, config interface{}) (proxy.InboundHandler, error) type InboundHandlerCreator func(space app.Space, config interface{}, listenOn v2net.Address, port v2net.Port) (proxy.InboundHandler, error)
type OutboundHandlerCreator func(space app.Space, config interface{}) (proxy.OutboundHandler, error) type OutboundHandlerCreator func(space app.Space, config interface{}, sendThrough v2net.Address) (proxy.OutboundHandler, error)

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"github.com/v2ray/v2ray-core/app" "github.com/v2ray/v2ray-core/app"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy" "github.com/v2ray/v2ray-core/proxy"
"github.com/v2ray/v2ray-core/proxy/internal/config" "github.com/v2ray/v2ray-core/proxy/internal/config"
) )
@ -45,7 +46,7 @@ func MustRegisterOutboundHandlerCreator(name string, creator OutboundHandlerCrea
} }
} }
func CreateInboundHandler(name string, space app.Space, rawConfig []byte) (proxy.InboundHandler, error) { func CreateInboundHandler(name string, space app.Space, rawConfig []byte, listen v2net.Address, port v2net.Port) (proxy.InboundHandler, error) {
creator, found := inboundFactories[name] creator, found := inboundFactories[name]
if !found { if !found {
return nil, ErrorProxyNotFound return nil, ErrorProxyNotFound
@ -55,12 +56,12 @@ func CreateInboundHandler(name string, space app.Space, rawConfig []byte) (proxy
if err != nil { if err != nil {
return nil, err return nil, err
} }
return creator(space, proxyConfig) return creator(space, proxyConfig, listen, port)
} }
return creator(space, nil) return creator(space, nil, listen, port)
} }
func CreateOutboundHandler(name string, space app.Space, rawConfig []byte) (proxy.OutboundHandler, error) { func CreateOutboundHandler(name string, space app.Space, rawConfig []byte, sendThrough v2net.Address) (proxy.OutboundHandler, error) {
creator, found := outboundFactories[name] creator, found := outboundFactories[name]
if !found { if !found {
return nil, ErrorNameExists return nil, ErrorNameExists
@ -71,8 +72,8 @@ func CreateOutboundHandler(name string, space app.Space, rawConfig []byte) (prox
if err != nil { if err != nil {
return nil, err return nil, err
} }
return creator(space, proxyConfig) return creator(space, proxyConfig, sendThrough)
} }
return creator(space, nil) return creator(space, nil, sendThrough)
} }

View File

@ -16,8 +16,8 @@ const (
// An InboundHandler handles inbound network connections to V2Ray. // An InboundHandler handles inbound network connections to V2Ray.
type InboundHandler interface { type InboundHandler interface {
// Listen starts a InboundHandler by listen on a specific port. // Listen starts a InboundHandler.
Listen(on v2net.Address, port v2net.Port) error Start() error
// Close stops the handler to accepting anymore inbound connections. // Close stops the handler to accepting anymore inbound connections.
Close() Close()
// Port returns the port that the handler is listening on. // Port returns the port that the handler is listening on.

View File

@ -2,14 +2,15 @@ package repo
import ( import (
"github.com/v2ray/v2ray-core/app" "github.com/v2ray/v2ray-core/app"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy" "github.com/v2ray/v2ray-core/proxy"
"github.com/v2ray/v2ray-core/proxy/internal" "github.com/v2ray/v2ray-core/proxy/internal"
) )
func CreateInboundHandler(name string, space app.Space, rawConfig []byte) (proxy.InboundHandler, error) { func CreateInboundHandler(name string, space app.Space, rawConfig []byte, listen v2net.Address, port v2net.Port) (proxy.InboundHandler, error) {
return internal.CreateInboundHandler(name, space, rawConfig) return internal.CreateInboundHandler(name, space, rawConfig, listen, port)
} }
func CreateOutboundHandler(name string, space app.Space, rawConfig []byte) (proxy.OutboundHandler, error) { func CreateOutboundHandler(name string, space app.Space, rawConfig []byte, sendThrough v2net.Address) (proxy.OutboundHandler, error) {
return internal.CreateOutboundHandler(name, space, rawConfig) return internal.CreateOutboundHandler(name, space, rawConfig, sendThrough)
} }

View File

@ -1,6 +1,7 @@
package shadowsocks_test package shadowsocks_test
import ( import (
"io"
"testing" "testing"
"github.com/v2ray/v2ray-core/common/alloc" "github.com/v2ray/v2ray-core/common/alloc"
@ -29,7 +30,7 @@ func TestEmptyPayload(t *testing.T) {
buffer := alloc.NewSmallBuffer().Clear() buffer := alloc.NewSmallBuffer().Clear()
_, err := ReadRequest(buffer, nil, false) _, err := ReadRequest(buffer, nil, false)
assert.Error(err).Equals(transport.ErrorCorruptedPacket) assert.Error(err).Equals(io.EOF)
} }
func TestSingleBytePayload(t *testing.T) { func TestSingleBytePayload(t *testing.T) {

View File

@ -30,10 +30,12 @@ type Server struct {
udpServer *hub.UDPServer udpServer *hub.UDPServer
} }
func NewServer(config *Config, packetDispatcher dispatcher.PacketDispatcher) *Server { func NewServer(config *Config, packetDispatcher dispatcher.PacketDispatcher, listen v2net.Address, port v2net.Port) *Server {
return &Server{ return &Server{
config: config, config: config,
packetDispatcher: packetDispatcher, packetDispatcher: packetDispatcher,
address: listen,
port: port,
} }
} }
@ -56,34 +58,28 @@ func (this *Server) Close() {
} }
func (this *Server) Listen(address v2net.Address, port v2net.Port) error { func (this *Server) Start() error {
if this.accepting { if this.accepting {
if this.port == port && this.address.Equals(address) { return nil
return nil
} else {
return proxy.ErrorAlreadyListening
}
} }
tcpHub, err := hub.ListenTCP(address, port, this.handleConnection, nil) tcpHub, err := hub.ListenTCP(this.address, this.port, this.handleConnection, nil)
if err != nil { if err != nil {
log.Error("Shadowsocks: Failed to listen TCP on port ", port, ": ", err) log.Error("Shadowsocks: Failed to listen TCP on port ", this.port, ": ", err)
return err return err
} }
this.tcpHub = tcpHub this.tcpHub = tcpHub
if this.config.UDP { if this.config.UDP {
this.udpServer = hub.NewUDPServer(this.packetDispatcher) this.udpServer = hub.NewUDPServer(this.packetDispatcher)
udpHub, err := hub.ListenUDP(address, port, this.handlerUDPPayload) udpHub, err := hub.ListenUDP(this.address, this.port, this.handlerUDPPayload)
if err != nil { if err != nil {
log.Error("Shadowsocks: Failed to listen UDP on port ", port, ": ", err) log.Error("Shadowsocks: Failed to listen UDP on port ", this.port, ": ", err)
return err return err
} }
this.udpHub = udpHub this.udpHub = udpHub
} }
this.port = port
this.address = address
this.accepting = true this.accepting = true
return nil return nil
@ -256,12 +252,14 @@ func (this *Server) handleConnection(conn *hub.Connection) {
func init() { func init() {
internal.MustRegisterInboundHandlerCreator("shadowsocks", internal.MustRegisterInboundHandlerCreator("shadowsocks",
func(space app.Space, rawConfig interface{}) (proxy.InboundHandler, error) { func(space app.Space, rawConfig interface{}, listen v2net.Address, port v2net.Port) (proxy.InboundHandler, error) {
if !space.HasApp(dispatcher.APP_ID) { if !space.HasApp(dispatcher.APP_ID) {
return nil, internal.ErrorBadConfiguration return nil, internal.ErrorBadConfiguration
} }
return NewServer( return NewServer(
rawConfig.(*Config), rawConfig.(*Config),
space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)), nil space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher),
listen,
port), nil
}) })
} }

View File

@ -38,10 +38,12 @@ type Server struct {
} }
// NewServer creates a new Server object. // NewServer creates a new Server object.
func NewServer(config *Config, packetDispatcher dispatcher.PacketDispatcher) *Server { func NewServer(config *Config, packetDispatcher dispatcher.PacketDispatcher, listen v2net.Address, port v2net.Port) *Server {
return &Server{ return &Server{
config: config, config: config,
packetDispatcher: packetDispatcher, packetDispatcher: packetDispatcher,
listeningAddress: listen,
listeningPort: port,
} }
} }
@ -68,20 +70,18 @@ func (this *Server) Close() {
} }
// Listen implements InboundHandler.Listen(). // Listen implements InboundHandler.Listen().
func (this *Server) Listen(address v2net.Address, port v2net.Port) error { func (this *Server) Start() error {
if this.accepting { if this.accepting {
if this.listeningPort == port && this.listeningAddress.Equals(address) { return nil
return nil
} else {
return proxy.ErrorAlreadyListening
}
} }
this.listeningPort = port
this.listeningAddress = address
listener, err := hub.ListenTCP(address, port, this.handleConnection, nil) listener, err := hub.ListenTCP(
this.listeningAddress,
this.listeningPort,
this.handleConnection,
nil)
if err != nil { if err != nil {
log.Error("Socks: failed to listen on port ", port, ": ", err) log.Error("Socks: failed to listen on port ", this.listeningPort, ": ", err)
return err return err
} }
this.accepting = true this.accepting = true
@ -89,7 +89,7 @@ func (this *Server) Listen(address v2net.Address, port v2net.Port) error {
this.tcpListener = listener this.tcpListener = listener
this.tcpMutex.Unlock() this.tcpMutex.Unlock()
if this.config.UDPEnabled { if this.config.UDPEnabled {
this.listenUDP(address, port) this.listenUDP(this.listeningAddress, this.listeningPort)
} }
return nil return nil
} }
@ -301,12 +301,14 @@ func (this *Server) transport(reader io.Reader, writer io.Writer, destination v2
func init() { func init() {
internal.MustRegisterInboundHandlerCreator("socks", internal.MustRegisterInboundHandlerCreator("socks",
func(space app.Space, rawConfig interface{}) (proxy.InboundHandler, error) { func(space app.Space, rawConfig interface{}, listen v2net.Address, port v2net.Port) (proxy.InboundHandler, error) {
if !space.HasApp(dispatcher.APP_ID) { if !space.HasApp(dispatcher.APP_ID) {
return nil, internal.ErrorBadConfiguration return nil, internal.ErrorBadConfiguration
} }
return NewServer( return NewServer(
rawConfig.(*Config), rawConfig.(*Config),
space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)), nil space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher),
listen,
port), nil
}) })
} }

View File

@ -31,16 +31,17 @@ func TestSocksTcpConnect(t *testing.T) {
ConnInput: bytes.NewReader(connInput), ConnInput: bytes.NewReader(connInput),
} }
protocol, err := proxytesting.RegisterOutboundConnectionHandlerCreator("mock_och", func(space app.Space, config interface{}) (v2proxy.OutboundHandler, error) { protocol, err := proxytesting.RegisterOutboundConnectionHandlerCreator("mock_och",
return och, nil func(space app.Space, config interface{}, sendThrough v2net.Address) (v2proxy.OutboundHandler, error) {
}) return och, nil
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
config := &point.Config{ config := &point.Config{
Port: port, Port: port,
ListenOn: v2net.LocalHostIP, InboundConfig: &point.InboundConnectionConfig{
InboundConfig: &point.ConnectionConfig{
Protocol: "socks", Protocol: "socks",
ListenOn: v2net.LocalHostIP,
Settings: []byte(` Settings: []byte(`
{ {
"auth": "noauth" "auth": "noauth"
@ -51,7 +52,7 @@ func TestSocksTcpConnect(t *testing.T) {
v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)), v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
}, },
}, },
OutboundConfig: &point.ConnectionConfig{ OutboundConfig: &point.OutboundConnectionConfig{
Protocol: protocol, Protocol: protocol,
Settings: nil, Settings: nil,
}, },
@ -96,16 +97,17 @@ func TestSocksTcpConnectWithUserPass(t *testing.T) {
ConnOutput: connOutput, ConnOutput: connOutput,
} }
protocol, err := proxytesting.RegisterOutboundConnectionHandlerCreator("mock_och", func(space app.Space, config interface{}) (v2proxy.OutboundHandler, error) { protocol, err := proxytesting.RegisterOutboundConnectionHandlerCreator("mock_och",
return och, nil func(space app.Space, config interface{}, sendThrough v2net.Address) (v2proxy.OutboundHandler, error) {
}) return och, nil
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
config := &point.Config{ config := &point.Config{
Port: port, Port: port,
ListenOn: v2net.LocalHostIP, InboundConfig: &point.InboundConnectionConfig{
InboundConfig: &point.ConnectionConfig{
Protocol: "socks", Protocol: "socks",
ListenOn: v2net.LocalHostIP,
Settings: []byte(` Settings: []byte(`
{ {
"auth": "password", "auth": "password",
@ -119,7 +121,7 @@ func TestSocksTcpConnectWithUserPass(t *testing.T) {
v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)), v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
}, },
}, },
OutboundConfig: &point.ConnectionConfig{ OutboundConfig: &point.OutboundConnectionConfig{
Protocol: protocol, Protocol: protocol,
Settings: nil, Settings: nil,
}, },
@ -164,16 +166,17 @@ func TestSocksTcpConnectWithWrongUserPass(t *testing.T) {
ConnOutput: connOutput, ConnOutput: connOutput,
} }
protocol, err := proxytesting.RegisterOutboundConnectionHandlerCreator("mock_och", func(space app.Space, config interface{}) (v2proxy.OutboundHandler, error) { protocol, err := proxytesting.RegisterOutboundConnectionHandlerCreator("mock_och",
return och, nil func(space app.Space, config interface{}, sendThrough v2net.Address) (v2proxy.OutboundHandler, error) {
}) return och, nil
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
config := &point.Config{ config := &point.Config{
Port: port, Port: port,
ListenOn: v2net.LocalHostIP, InboundConfig: &point.InboundConnectionConfig{
InboundConfig: &point.ConnectionConfig{
Protocol: "socks", Protocol: "socks",
ListenOn: v2net.LocalHostIP,
Settings: []byte(` Settings: []byte(`
{ {
"auth": "password", "auth": "password",
@ -187,7 +190,7 @@ func TestSocksTcpConnectWithWrongUserPass(t *testing.T) {
v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)), v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
}, },
}, },
OutboundConfig: &point.ConnectionConfig{ OutboundConfig: &point.OutboundConnectionConfig{
Protocol: protocol, Protocol: protocol,
Settings: nil, Settings: nil,
}, },
@ -218,15 +221,16 @@ func TestSocksTcpConnectWithWrongAuthMethod(t *testing.T) {
ConnOutput: connOutput, ConnOutput: connOutput,
} }
protocol, err := proxytesting.RegisterOutboundConnectionHandlerCreator("mock_och", func(space app.Space, config interface{}) (v2proxy.OutboundHandler, error) { protocol, err := proxytesting.RegisterOutboundConnectionHandlerCreator("mock_och",
return och, nil func(space app.Space, config interface{}, sendThrough v2net.Address) (v2proxy.OutboundHandler, error) {
}) return och, nil
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
config := &point.Config{ config := &point.Config{
Port: port, Port: port,
ListenOn: v2net.LocalHostIP, InboundConfig: &point.InboundConnectionConfig{
InboundConfig: &point.ConnectionConfig{ ListenOn: v2net.LocalHostIP,
Protocol: "socks", Protocol: "socks",
Settings: []byte(` Settings: []byte(`
{ {
@ -241,7 +245,7 @@ func TestSocksTcpConnectWithWrongAuthMethod(t *testing.T) {
v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)), v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
}, },
}, },
OutboundConfig: &point.ConnectionConfig{ OutboundConfig: &point.OutboundConnectionConfig{
Protocol: protocol, Protocol: protocol,
Settings: nil, Settings: nil,
}, },

View File

@ -10,21 +10,19 @@ import (
) )
type InboundConnectionHandler struct { type InboundConnectionHandler struct {
port v2net.Port ListeningPort v2net.Port
address v2net.Address ListeningAddress v2net.Address
PacketDispatcher dispatcher.PacketDispatcher PacketDispatcher dispatcher.PacketDispatcher
ConnInput io.Reader ConnInput io.Reader
ConnOutput io.Writer ConnOutput io.Writer
} }
func (this *InboundConnectionHandler) Listen(address v2net.Address, port v2net.Port) error { func (this *InboundConnectionHandler) Start() error {
this.port = port
this.address = address
return nil return nil
} }
func (this *InboundConnectionHandler) Port() v2net.Port { func (this *InboundConnectionHandler) Port() v2net.Port {
return this.port return this.ListeningPort
} }
func (this *InboundConnectionHandler) Close() { func (this *InboundConnectionHandler) Close() {

View File

@ -50,6 +50,6 @@ func (this *OutboundConnectionHandler) Dispatch(destination v2net.Destination, p
return nil return nil
} }
func (this *OutboundConnectionHandler) Create(space app.Space, config interface{}) (proxy.OutboundHandler, error) { func (this *OutboundConnectionHandler) Create(space app.Space, config interface{}, sendThrough v2net.Address) (proxy.OutboundHandler, error) {
return this, nil return this, nil
} }

View File

@ -88,6 +88,8 @@ func (this *VMessInboundHandler) Close() {
this.Lock() this.Lock()
this.listener.Close() this.listener.Close()
this.listener = nil this.listener = nil
this.clients.Release()
this.clients = nil
this.Unlock() this.Unlock()
} }
} }
@ -100,20 +102,14 @@ func (this *VMessInboundHandler) GetUser(email string) *protocol.User {
return user return user
} }
func (this *VMessInboundHandler) Listen(address v2net.Address, port v2net.Port) error { func (this *VMessInboundHandler) Start() error {
if this.accepting { if this.accepting {
if this.listeningPort == port && this.listeningAddress.Equals(address) { return nil
return nil
} else {
return proxy.ErrorAlreadyListening
}
} }
this.listeningPort = port
this.listeningAddress = address
tcpListener, err := hub.ListenTCP(address, port, this.HandleConnection, nil) tcpListener, err := hub.ListenTCP(this.listeningAddress, this.listeningPort, this.HandleConnection, nil)
if err != nil { if err != nil {
log.Error("Unable to listen tcp port ", port, ": ", err) log.Error("Unable to listen tcp port ", this.listeningPort, ": ", err)
return err return err
} }
this.accepting = true this.accepting = true
@ -224,7 +220,7 @@ func (this *VMessInboundHandler) HandleConnection(connection *hub.Connection) {
func init() { func init() {
internal.MustRegisterInboundHandlerCreator("vmess", internal.MustRegisterInboundHandlerCreator("vmess",
func(space app.Space, rawConfig interface{}) (proxy.InboundHandler, error) { func(space app.Space, rawConfig interface{}, listen v2net.Address, port v2net.Port) (proxy.InboundHandler, error) {
if !space.HasApp(dispatcher.APP_ID) { if !space.HasApp(dispatcher.APP_ID) {
return nil, internal.ErrorBadConfiguration return nil, internal.ErrorBadConfiguration
} }
@ -240,6 +236,8 @@ func init() {
clients: allowedClients, clients: allowedClients,
detours: config.DetourConfig, detours: config.DetourConfig,
usersByEmail: NewUserByEmail(config.AllowedUsers, config.Defaults), usersByEmail: NewUserByEmail(config.AllowedUsers, config.Defaults),
listeningAddress: listen,
listeningPort: port,
} }
if space.HasApp(proxyman.APP_ID_INBOUND_MANAGER) { if space.HasApp(proxyman.APP_ID_INBOUND_MANAGER) {

View File

@ -21,6 +21,7 @@ import (
type VMessOutboundHandler struct { type VMessOutboundHandler struct {
receiverManager *ReceiverManager receiverManager *ReceiverManager
sendThrough v2net.Address
} }
func (this *VMessOutboundHandler) Dispatch(target v2net.Destination, payload *alloc.Buffer, ray ray.OutboundRay) error { func (this *VMessOutboundHandler) Dispatch(target v2net.Destination, payload *alloc.Buffer, ray ray.OutboundRay) error {
@ -42,7 +43,7 @@ func (this *VMessOutboundHandler) Dispatch(target v2net.Destination, payload *al
Option: protocol.RequestOptionChunkStream, Option: protocol.RequestOptionChunkStream,
} }
conn, err := hub.Dial(destination) conn, err := hub.Dial(this.sendThrough, destination)
if err != nil { if err != nil {
log.Error("Failed to open ", destination, ": ", err) log.Error("Failed to open ", destination, ": ", err)
return err return err
@ -142,10 +143,11 @@ func (this *VMessOutboundHandler) handleResponse(session *raw.ClientSession, con
func init() { func init() {
internal.MustRegisterOutboundHandlerCreator("vmess", internal.MustRegisterOutboundHandlerCreator("vmess",
func(space app.Space, rawConfig interface{}) (proxy.OutboundHandler, error) { func(space app.Space, rawConfig interface{}, sendThrough v2net.Address) (proxy.OutboundHandler, error) {
vOutConfig := rawConfig.(*Config) vOutConfig := rawConfig.(*Config)
return &VMessOutboundHandler{ return &VMessOutboundHandler{
receiverManager: NewReceiverManager(vOutConfig.Receivers), receiverManager: NewReceiverManager(vOutConfig.Receivers),
sendThrough: sendThrough,
}, nil }, nil
}) })
} }

View File

@ -38,25 +38,28 @@ func TestVMessInAndOut(t *testing.T) {
ConnOutput: ichConnOutput, ConnOutput: ichConnOutput,
} }
protocol, err := proxytesting.RegisterInboundConnectionHandlerCreator("mock_och", func(space app.Space, config interface{}) (proxy.InboundHandler, error) { protocol, err := proxytesting.RegisterInboundConnectionHandlerCreator("mock_ich",
ich.PacketDispatcher = space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher) func(space app.Space, config interface{}, listen v2net.Address, port v2net.Port) (proxy.InboundHandler, error) {
return ich, nil ich.ListeningAddress = listen
}) ich.ListeningPort = port
ich.PacketDispatcher = space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)
return ich, nil
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
configA := &point.Config{ configA := &point.Config{
Port: portA, Port: portA,
ListenOn: v2net.LocalHostIP,
DNSConfig: &dns.Config{ DNSConfig: &dns.Config{
NameServers: []v2net.Destination{ NameServers: []v2net.Destination{
v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)), v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
}, },
}, },
InboundConfig: &point.ConnectionConfig{ InboundConfig: &point.InboundConnectionConfig{
Protocol: protocol, Protocol: protocol,
ListenOn: v2net.LocalHostIP,
Settings: nil, Settings: nil,
}, },
OutboundConfig: &point.ConnectionConfig{ OutboundConfig: &point.OutboundConnectionConfig{
Protocol: "vmess", Protocol: "vmess",
Settings: []byte(`{ Settings: []byte(`{
"vnext": [ "vnext": [
@ -85,28 +88,29 @@ func TestVMessInAndOut(t *testing.T) {
ConnOutput: ochConnOutput, ConnOutput: ochConnOutput,
} }
protocol, err = proxytesting.RegisterOutboundConnectionHandlerCreator("mock_och", func(space app.Space, config interface{}) (proxy.OutboundHandler, error) { protocol, err = proxytesting.RegisterOutboundConnectionHandlerCreator("mock_och",
return och, nil func(space app.Space, config interface{}, sendThrough v2net.Address) (proxy.OutboundHandler, error) {
}) return och, nil
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
configB := &point.Config{ configB := &point.Config{
Port: portB, Port: portB,
ListenOn: v2net.LocalHostIP,
DNSConfig: &dns.Config{ DNSConfig: &dns.Config{
NameServers: []v2net.Destination{ NameServers: []v2net.Destination{
v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)), v2net.UDPDestination(v2net.DomainAddress("localhost"), v2net.Port(53)),
}, },
}, },
InboundConfig: &point.ConnectionConfig{ InboundConfig: &point.InboundConnectionConfig{
Protocol: "vmess", Protocol: "vmess",
ListenOn: v2net.LocalHostIP,
Settings: []byte(`{ Settings: []byte(`{
"clients": [ "clients": [
{"id": "` + testAccount.String() + `"} {"id": "` + testAccount.String() + `"}
] ]
}`), }`),
}, },
OutboundConfig: &point.ConnectionConfig{ OutboundConfig: &point.OutboundConnectionConfig{
Protocol: protocol, Protocol: protocol,
Settings: nil, Settings: nil,
}, },

View File

@ -1,9 +1,10 @@
{ {
"port": 1080,
"log": { "log": {
"access": "" "loglevel": "warning"
}, },
"inbound": { "inbound": {
"port": 1080,
"listen": "127.0.0.1",
"protocol": "socks", "protocol": "socks",
"settings": { "settings": {
"auth": "noauth", "auth": "noauth",

View File

@ -1,11 +1,11 @@
{ {
"port": 10086,
"log" : { "log" : {
"access": "/var/log/v2ray/access.log", "access": "/var/log/v2ray/access.log",
"error": "/var/log/v2ray/error.log", "error": "/var/log/v2ray/error.log",
"loglevel": "warning" "loglevel": "warning"
}, },
"inbound": { "inbound": {
"port": 10086,
"protocol": "vmess", "protocol": "vmess",
"settings": { "settings": {
"clients": [ "clients": [

View File

@ -8,11 +8,19 @@ import (
"github.com/v2ray/v2ray-core/transport" "github.com/v2ray/v2ray-core/transport"
) )
type ConnectionConfig struct { type InboundConnectionConfig struct {
Port v2net.Port
ListenOn v2net.Address
Protocol string Protocol string
Settings []byte Settings []byte
} }
type OutboundConnectionConfig struct {
Protocol string
SendThrough v2net.Address
Settings []byte
}
type LogConfig struct { type LogConfig struct {
AccessLog string AccessLog string
ErrorLog string ErrorLog string
@ -41,19 +49,19 @@ type InboundDetourConfig struct {
} }
type OutboundDetourConfig struct { type OutboundDetourConfig struct {
Protocol string Protocol string
Tag string SendThrough v2net.Address
Settings []byte Tag string
Settings []byte
} }
type Config struct { type Config struct {
Port v2net.Port Port v2net.Port
ListenOn v2net.Address
LogConfig *LogConfig LogConfig *LogConfig
RouterConfig *router.Config RouterConfig *router.Config
DNSConfig *dns.Config DNSConfig *dns.Config
InboundConfig *ConnectionConfig InboundConfig *InboundConnectionConfig
OutboundConfig *ConnectionConfig OutboundConfig *OutboundConnectionConfig
InboundDetours []*InboundDetourConfig InboundDetours []*InboundDetourConfig
OutboundDetours []*OutboundDetourConfig OutboundDetours []*OutboundDetourConfig
TransportConfig *transport.Config TransportConfig *transport.Config

View File

@ -22,29 +22,21 @@ const (
func (this *Config) UnmarshalJSON(data []byte) error { func (this *Config) UnmarshalJSON(data []byte) error {
type JsonConfig struct { type JsonConfig struct {
Port v2net.Port `json:"port"` // Port of this Point server. Port v2net.Port `json:"port"` // Port of this Point server.
ListenOn *v2net.AddressJson `json:"listen"` LogConfig *LogConfig `json:"log"`
LogConfig *LogConfig `json:"log"` RouterConfig *router.Config `json:"routing"`
RouterConfig *router.Config `json:"routing"` DNSConfig *dns.Config `json:"dns"`
DNSConfig *dns.Config `json:"dns"` InboundConfig *InboundConnectionConfig `json:"inbound"`
InboundConfig *ConnectionConfig `json:"inbound"` OutboundConfig *OutboundConnectionConfig `json:"outbound"`
OutboundConfig *ConnectionConfig `json:"outbound"` InboundDetours []*InboundDetourConfig `json:"inboundDetour"`
InboundDetours []*InboundDetourConfig `json:"inboundDetour"` OutboundDetours []*OutboundDetourConfig `json:"outboundDetour"`
OutboundDetours []*OutboundDetourConfig `json:"outboundDetour"` Transport *transport.Config `json:"transport"`
Transport *transport.Config `json:"transport"`
} }
jsonConfig := new(JsonConfig) jsonConfig := new(JsonConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil { if err := json.Unmarshal(data, jsonConfig); err != nil {
return err return err
} }
this.Port = jsonConfig.Port this.Port = jsonConfig.Port
this.ListenOn = v2net.AnyIP
if jsonConfig.ListenOn != nil {
if jsonConfig.ListenOn.Address.IsDomain() {
return errors.New("Point: Unable to listen on domain address: " + jsonConfig.ListenOn.Address.Domain())
}
this.ListenOn = jsonConfig.ListenOn.Address
}
this.LogConfig = jsonConfig.LogConfig this.LogConfig = jsonConfig.LogConfig
this.RouterConfig = jsonConfig.RouterConfig this.RouterConfig = jsonConfig.RouterConfig
this.InboundConfig = jsonConfig.InboundConfig this.InboundConfig = jsonConfig.InboundConfig
@ -63,10 +55,37 @@ func (this *Config) UnmarshalJSON(data []byte) error {
return nil return nil
} }
func (this *ConnectionConfig) UnmarshalJSON(data []byte) error { func (this *InboundConnectionConfig) UnmarshalJSON(data []byte) error {
type JsonConfig struct {
Port uint16 `json:"port"`
Listen *v2net.AddressJson `json:"listen"`
Protocol string `json:"protocol"`
Settings json.RawMessage `json:"settings"`
}
jsonConfig := new(JsonConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil {
return err
}
this.Port = v2net.Port(jsonConfig.Port)
this.ListenOn = v2net.AnyIP
if jsonConfig.Listen != nil {
if jsonConfig.Listen.Address.IsDomain() {
return errors.New("Point: Unable to listen on domain address: " + jsonConfig.Listen.Address.Domain())
}
this.ListenOn = jsonConfig.Listen.Address
}
this.Protocol = jsonConfig.Protocol
this.Settings = jsonConfig.Settings
return nil
}
func (this *OutboundConnectionConfig) UnmarshalJSON(data []byte) error {
type JsonConnectionConfig struct { type JsonConnectionConfig struct {
Protocol string `json:"protocol"` Protocol string `json:"protocol"`
Settings json.RawMessage `json:"settings"` SendThrough *v2net.AddressJson `json:"sendThrough"`
Settings json.RawMessage `json:"settings"`
} }
jsonConfig := new(JsonConnectionConfig) jsonConfig := new(JsonConnectionConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil { if err := json.Unmarshal(data, jsonConfig); err != nil {
@ -74,6 +93,14 @@ func (this *ConnectionConfig) UnmarshalJSON(data []byte) error {
} }
this.Protocol = jsonConfig.Protocol this.Protocol = jsonConfig.Protocol
this.Settings = jsonConfig.Settings this.Settings = jsonConfig.Settings
if jsonConfig.SendThrough != nil {
address := jsonConfig.SendThrough.Address
if address.IsDomain() {
return errors.New("Point: Unable to send through: " + address.String())
}
this.SendThrough = address
}
return nil return nil
} }
@ -173,9 +200,10 @@ func (this *InboundDetourConfig) UnmarshalJSON(data []byte) error {
func (this *OutboundDetourConfig) UnmarshalJSON(data []byte) error { func (this *OutboundDetourConfig) UnmarshalJSON(data []byte) error {
type JsonOutboundDetourConfig struct { type JsonOutboundDetourConfig struct {
Protocol string `json:"protocol"` Protocol string `json:"protocol"`
Tag string `json:"tag"` SendThrough *v2net.AddressJson `json:"sendThrough"`
Settings json.RawMessage `json:"settings"` Tag string `json:"tag"`
Settings json.RawMessage `json:"settings"`
} }
jsonConfig := new(JsonOutboundDetourConfig) jsonConfig := new(JsonOutboundDetourConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil { if err := json.Unmarshal(data, jsonConfig); err != nil {
@ -184,6 +212,14 @@ func (this *OutboundDetourConfig) UnmarshalJSON(data []byte) error {
this.Protocol = jsonConfig.Protocol this.Protocol = jsonConfig.Protocol
this.Tag = jsonConfig.Tag this.Tag = jsonConfig.Tag
this.Settings = jsonConfig.Settings this.Settings = jsonConfig.Settings
if jsonConfig.SendThrough != nil {
address := jsonConfig.SendThrough.Address
if address.IsDomain() {
return errors.New("Point: Unable to send through: " + address.String())
}
this.SendThrough = address
}
return nil return nil
} }

View File

@ -23,8 +23,8 @@ func TestClientSampleConfig(t *testing.T) {
pointConfig, err := LoadConfig(filepath.Join(baseDir, "vpoint_socks_vmess.json")) pointConfig, err := LoadConfig(filepath.Join(baseDir, "vpoint_socks_vmess.json"))
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.Port(pointConfig.Port).IsValid()
assert.Pointer(pointConfig.InboundConfig).IsNotNil() assert.Pointer(pointConfig.InboundConfig).IsNotNil()
assert.Port(pointConfig.InboundConfig.Port).IsValid()
assert.Pointer(pointConfig.OutboundConfig).IsNotNil() assert.Pointer(pointConfig.OutboundConfig).IsNotNil()
assert.String(pointConfig.InboundConfig.Protocol).Equals("socks") assert.String(pointConfig.InboundConfig.Protocol).Equals("socks")
@ -43,8 +43,8 @@ func TestServerSampleConfig(t *testing.T) {
pointConfig, err := LoadConfig(filepath.Join(baseDir, "vpoint_vmess_freedom.json")) pointConfig, err := LoadConfig(filepath.Join(baseDir, "vpoint_vmess_freedom.json"))
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.Port(pointConfig.Port).IsValid()
assert.Pointer(pointConfig.InboundConfig).IsNotNil() assert.Pointer(pointConfig.InboundConfig).IsNotNil()
assert.Port(pointConfig.InboundConfig.Port).IsValid()
assert.Pointer(pointConfig.OutboundConfig).IsNotNil() assert.Pointer(pointConfig.OutboundConfig).IsNotNil()
assert.String(pointConfig.InboundConfig.Protocol).Equals("vmess") assert.String(pointConfig.InboundConfig.Protocol).Equals("vmess")

View File

@ -32,7 +32,7 @@ func NewInboundDetourHandlerAlways(space app.Space, config *InboundDetourConfig)
handler.ich = make([]*InboundConnectionHandlerWithPort, 0, ports.To-ports.From+1) handler.ich = make([]*InboundConnectionHandlerWithPort, 0, ports.To-ports.From+1)
for i := ports.From; i <= ports.To; i++ { for i := ports.From; i <= ports.To; i++ {
ichConfig := config.Settings ichConfig := config.Settings
ich, err := proxyrepo.CreateInboundHandler(config.Protocol, space, ichConfig) ich, err := proxyrepo.CreateInboundHandler(config.Protocol, space, ichConfig, config.ListenOn, i)
if err != nil { if err != nil {
log.Error("Failed to create inbound connection handler: ", err) log.Error("Failed to create inbound connection handler: ", err)
return nil, err return nil, err
@ -61,7 +61,7 @@ func (this *InboundDetourHandlerAlways) Close() {
func (this *InboundDetourHandlerAlways) Start() error { func (this *InboundDetourHandlerAlways) Start() error {
for _, ich := range this.ich { for _, ich := range this.ich {
err := retry.Timed(100 /* times */, 100 /* ms */).On(func() error { err := retry.Timed(100 /* times */, 100 /* ms */).On(func() error {
err := ich.handler.Listen(ich.listen, ich.port) err := ich.handler.Start()
if err != nil { if err != nil {
log.Error("Failed to start inbound detour on port ", ich.port, ": ", err) log.Error("Failed to start inbound detour on port ", ich.port, ": ", err)
return err return err

View File

@ -8,7 +8,6 @@ import (
"github.com/v2ray/v2ray-core/common/dice" "github.com/v2ray/v2ray-core/common/dice"
"github.com/v2ray/v2ray-core/common/log" "github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net" v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/common/retry"
"github.com/v2ray/v2ray-core/proxy" "github.com/v2ray/v2ray-core/proxy"
proxyrepo "github.com/v2ray/v2ray-core/proxy/repo" proxyrepo "github.com/v2ray/v2ray-core/proxy/repo"
) )
@ -18,8 +17,7 @@ type InboundDetourHandlerDynamic struct {
space app.Space space app.Space
config *InboundDetourConfig config *InboundDetourConfig
portsInUse map[v2net.Port]bool portsInUse map[v2net.Port]bool
ichInUse []proxy.InboundHandler ichs []proxy.InboundHandler
ich2Recycle []proxy.InboundHandler
lastRefresh time.Time lastRefresh time.Time
} }
@ -29,18 +27,16 @@ func NewInboundDetourHandlerDynamic(space app.Space, config *InboundDetourConfig
config: config, config: config,
portsInUse: make(map[v2net.Port]bool), portsInUse: make(map[v2net.Port]bool),
} }
ichCount := config.Allocation.Concurrency handler.ichs = make([]proxy.InboundHandler, config.Allocation.Concurrency)
ichArray := make([]proxy.InboundHandler, ichCount*2)
for idx := range ichArray { // To test configuration
ich, err := proxyrepo.CreateInboundHandler(config.Protocol, space, config.Settings) ich, err := proxyrepo.CreateInboundHandler(config.Protocol, space, config.Settings, config.ListenOn, 0)
if err != nil { if err != nil {
log.Error("Point: Failed to create inbound connection handler: ", err) log.Error("Point: Failed to create inbound connection handler: ", err)
return nil, err return nil, err
}
ichArray[idx] = ich
} }
handler.ichInUse = ichArray[:ichCount] ich.Close()
handler.ich2Recycle = ichArray[ichCount:]
return handler, nil return handler, nil
} }
@ -59,7 +55,7 @@ func (this *InboundDetourHandlerDynamic) pickUnusedPort() v2net.Port {
func (this *InboundDetourHandlerDynamic) GetConnectionHandler() (proxy.InboundHandler, int) { func (this *InboundDetourHandlerDynamic) GetConnectionHandler() (proxy.InboundHandler, int) {
this.RLock() this.RLock()
defer this.RUnlock() defer this.RUnlock()
ich := this.ichInUse[dice.Roll(len(this.ichInUse))] ich := this.ichs[dice.Roll(len(this.ichs))]
until := this.config.Allocation.Refresh - int((time.Now().Unix()-this.lastRefresh.Unix())/60/1000) until := this.config.Allocation.Refresh - int((time.Now().Unix()-this.lastRefresh.Unix())/60/1000)
if until < 0 { if until < 0 {
until = 0 until = 0
@ -70,58 +66,68 @@ func (this *InboundDetourHandlerDynamic) GetConnectionHandler() (proxy.InboundHa
func (this *InboundDetourHandlerDynamic) Close() { func (this *InboundDetourHandlerDynamic) Close() {
this.Lock() this.Lock()
defer this.Unlock() defer this.Unlock()
for _, ich := range this.ichInUse { for _, ich := range this.ichs {
ich.Close() ich.Close()
} }
if this.ich2Recycle != nil {
for _, ich := range this.ich2Recycle {
if ich != nil {
ich.Close()
}
}
}
} }
func (this *InboundDetourHandlerDynamic) refresh() error { func (this *InboundDetourHandlerDynamic) refresh() error {
this.lastRefresh = time.Now() this.lastRefresh = time.Now()
for _, ich := range this.ich2Recycle { config := this.config
port2Delete := ich.Port() ich2Recycle := this.ichs
newIchs := make([]proxy.InboundHandler, config.Allocation.Concurrency)
ich.Close() for idx, _ := range newIchs {
err := retry.Timed(100 /* times */, 1000 /* ms */).On(func() error { port := this.pickUnusedPort()
port := this.pickUnusedPort() ich, err := proxyrepo.CreateInboundHandler(config.Protocol, this.space, config.Settings, config.ListenOn, port)
err := ich.Listen(this.config.ListenOn, port)
if err != nil {
log.Error("Point: Failed to start inbound detour on port ", port, ": ", err)
return err
}
this.portsInUse[port] = true
return nil
})
if err != nil { if err != nil {
continue log.Error("Point: Failed to create inbound connection handler: ", err)
return err
} }
err = ich.Start()
delete(this.portsInUse, port2Delete) if err != nil {
log.Error("Point: Failed to start inbound connection handler: ", err)
return err
}
this.portsInUse[port] = true
newIchs[idx] = ich
} }
this.Lock() this.Lock()
this.ich2Recycle, this.ichInUse = this.ichInUse, this.ich2Recycle this.ichs = newIchs
this.Unlock() this.Unlock()
go func() {
time.Sleep(time.Minute)
for _, ich := range ich2Recycle {
if ich == nil {
continue
}
port := ich.Port()
ich.Close()
delete(this.portsInUse, port)
}
ich2Recycle = nil
}()
return nil return nil
} }
func (this *InboundDetourHandlerDynamic) Start() error { func (this *InboundDetourHandlerDynamic) Start() error {
err := this.refresh() err := this.refresh()
if err != nil { if err != nil {
log.Error("Point: Failed to refresh dynamic allocations: ", err)
return err return err
} }
go func() { go func() {
for range time.Tick(time.Duration(this.config.Allocation.Refresh) * time.Minute) { for {
this.refresh() time.Sleep(time.Duration(this.config.Allocation.Refresh) * time.Minute)
err := this.refresh()
if err != nil {
log.Error("Point: Failed to refresh dynamic allocations: ", err)
}
} }
}() }()

View File

@ -35,8 +35,12 @@ type Point struct {
// The server is not started at this point. // The server is not started at this point.
func NewPoint(pConfig *Config) (*Point, error) { func NewPoint(pConfig *Config) (*Point, error) {
var vpoint = new(Point) var vpoint = new(Point)
vpoint.port = pConfig.Port vpoint.port = pConfig.InboundConfig.Port
vpoint.listen = pConfig.ListenOn if vpoint.port == 0 {
vpoint.port = pConfig.Port // Backward compatibility
}
vpoint.listen = pConfig.InboundConfig.ListenOn
if pConfig.TransportConfig != nil { if pConfig.TransportConfig != nil {
pConfig.TransportConfig.Apply() pConfig.TransportConfig.Apply()
@ -87,7 +91,7 @@ func NewPoint(pConfig *Config) (*Point, error) {
vpoint.space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(vpoint.space)) vpoint.space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(vpoint.space))
ichConfig := pConfig.InboundConfig.Settings ichConfig := pConfig.InboundConfig.Settings
ich, err := proxyrepo.CreateInboundHandler(pConfig.InboundConfig.Protocol, vpoint.space, ichConfig) ich, err := proxyrepo.CreateInboundHandler(pConfig.InboundConfig.Protocol, vpoint.space, ichConfig, pConfig.InboundConfig.ListenOn, vpoint.port)
if err != nil { if err != nil {
log.Error("Failed to create inbound connection handler: ", err) log.Error("Failed to create inbound connection handler: ", err)
return nil, err return nil, err
@ -95,7 +99,7 @@ func NewPoint(pConfig *Config) (*Point, error) {
vpoint.ich = ich vpoint.ich = ich
ochConfig := pConfig.OutboundConfig.Settings ochConfig := pConfig.OutboundConfig.Settings
och, err := proxyrepo.CreateOutboundHandler(pConfig.OutboundConfig.Protocol, vpoint.space, ochConfig) och, err := proxyrepo.CreateOutboundHandler(pConfig.OutboundConfig.Protocol, vpoint.space, ochConfig, pConfig.OutboundConfig.SendThrough)
if err != nil { if err != nil {
log.Error("Failed to create outbound connection handler: ", err) log.Error("Failed to create outbound connection handler: ", err)
return nil, err return nil, err
@ -140,7 +144,7 @@ func NewPoint(pConfig *Config) (*Point, error) {
if len(outboundDetours) > 0 { if len(outboundDetours) > 0 {
vpoint.odh = make(map[string]proxy.OutboundHandler) vpoint.odh = make(map[string]proxy.OutboundHandler)
for _, detourConfig := range outboundDetours { for _, detourConfig := range outboundDetours {
detourHandler, err := proxyrepo.CreateOutboundHandler(detourConfig.Protocol, vpoint.space, detourConfig.Settings) detourHandler, err := proxyrepo.CreateOutboundHandler(detourConfig.Protocol, vpoint.space, detourConfig.Settings, detourConfig.SendThrough)
if err != nil { if err != nil {
log.Error("Point: Failed to create detour outbound connection handler: ", err) log.Error("Point: Failed to create detour outbound connection handler: ", err)
return nil, err return nil, err
@ -173,7 +177,7 @@ func (this *Point) Start() error {
} }
err := retry.Timed(100 /* times */, 100 /* ms */).On(func() error { err := retry.Timed(100 /* times */, 100 /* ms */).On(func() error {
err := this.ich.Listen(this.listen, this.port) err := this.ich.Start()
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,7 +1,7 @@
{ {
"port": 50000,
"listen": "127.0.0.1",
"inbound": { "inbound": {
"port": 50000,
"listen": "127.0.0.1",
"protocol": "socks", "protocol": "socks",
"settings": { "settings": {
"auth": "noauth", "auth": "noauth",

View File

@ -1,10 +1,10 @@
{ {
"port": 50001, "port": 50001,
"listen": "127.0.0.1",
"log": { "log": {
"loglevel": "none" "loglevel": "none"
}, },
"inbound": { "inbound": {
"listen": "127.0.0.1",
"protocol": "vmess", "protocol": "vmess",
"settings": { "settings": {
"clients": [ "clients": [

View File

@ -1,7 +1,7 @@
{ {
"port": 50010, "port": 50010,
"listen": "127.0.0.1",
"inbound": { "inbound": {
"listen": "127.0.0.1",
"protocol": "socks", "protocol": "socks",
"settings": { "settings": {
"auth": "noauth", "auth": "noauth",

View File

@ -1,10 +1,10 @@
{ {
"port": 50017, "port": 50017,
"listen": "127.0.0.1",
"log": { "log": {
"loglevel": "none" "loglevel": "none"
}, },
"inbound": { "inbound": {
"listen": "127.0.0.1",
"protocol": "vmess", "protocol": "vmess",
"settings": { "settings": {
"clients": [ "clients": [

View File

@ -1,10 +1,10 @@
{ {
"port": 50020, "port": 50020,
"listen": "127.0.0.1",
"log": { "log": {
"loglevel": "none" "loglevel": "none"
}, },
"inbound": { "inbound": {
"listen": "127.0.0.1",
"protocol": "dokodemo-door", "protocol": "dokodemo-door",
"settings": { "settings": {
"address": "127.0.0.1", "address": "127.0.0.1",

View File

@ -1,7 +1,7 @@
{ {
"port": 50021, "port": 50021,
"listen": "127.0.0.1",
"inbound": { "inbound": {
"listen": "127.0.0.1",
"protocol": "vmess", "protocol": "vmess",
"settings": { "settings": {
"clients": [ "clients": [

View File

@ -1,10 +1,10 @@
{ {
"port": 50030, "port": 50030,
"listen": "127.0.0.1",
"log": { "log": {
"loglevel": "debug" "loglevel": "debug"
}, },
"inbound": { "inbound": {
"listen": "127.0.0.1",
"protocol": "dokodemo-door", "protocol": "dokodemo-door",
"settings": { "settings": {
"address": "127.0.0.1", "address": "127.0.0.1",

View File

@ -1,10 +1,10 @@
{ {
"port": 50031, "port": 50031,
"listen": "127.0.0.1",
"log": { "log": {
"loglevel": "debug" "loglevel": "debug"
}, },
"inbound": { "inbound": {
"listen": "127.0.0.1",
"protocol": "vmess", "protocol": "vmess",
"settings": { "settings": {
"clients": [ "clients": [

View File

@ -1,7 +1,7 @@
{ {
"port": 50040, "port": 50040,
"listen": "127.0.0.1",
"inbound": { "inbound": {
"listen": "127.0.0.1",
"protocol": "http", "protocol": "http",
"settings": {} "settings": {}
}, },

View File

@ -1,7 +1,7 @@
{ {
"port": 50041, "port": 50041,
"listen": "127.0.0.1",
"inbound": { "inbound": {
"listen": "127.0.0.1",
"protocol": "vmess", "protocol": "vmess",
"settings": { "settings": {
"clients": [ "clients": [

View File

@ -1,7 +1,7 @@
{ {
"port": 50051, "port": 50051,
"listen": "127.0.0.1",
"inbound": { "inbound": {
"listen": "127.0.0.1",
"protocol": "shadowsocks", "protocol": "shadowsocks",
"settings": { "settings": {
"method": "aes-256-cfb", "method": "aes-256-cfb",

View File

@ -1,12 +1,13 @@
package scenarios package scenarios
import ( import (
"io/ioutil"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
_ "github.com/v2ray/v2ray-core/app/router/rules" _ "github.com/v2ray/v2ray-core/app/router/rules"
"github.com/v2ray/v2ray-core/common/log" "github.com/v2ray/v2ray-core/common/log"
"github.com/v2ray/v2ray-core/shell/point"
// The following are necessary as they register handlers in their init functions. // The following are necessary as they register handlers in their init functions.
_ "github.com/v2ray/v2ray-core/proxy/blackhole" _ "github.com/v2ray/v2ray-core/proxy/blackhole"
@ -20,9 +21,25 @@ import (
) )
var ( var (
runningServers = make([]*point.Point, 0, 10) runningServers = make([]*exec.Cmd, 0, 10)
binaryPath string
) )
func BuildV2Ray() error {
if len(binaryPath) > 0 {
return nil
}
dir, err := ioutil.TempDir("", "v2ray")
if err != nil {
return err
}
binaryPath = filepath.Join(dir, "v2ray.exe")
cmd := exec.Command("go", "build", "-tags=json", "-o="+binaryPath, filepath.Join("github.com", "v2ray", "v2ray-core", "release", "server"))
return cmd.Run()
}
func TestFile(filename string) string { func TestFile(filename string) string {
return filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "v2ray", "v2ray-core", "testing", "scenarios", "data", filename) return filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "v2ray", "v2ray-core", "testing", "scenarios", "data", filename)
} }
@ -46,31 +63,30 @@ func InitializeServerClient(testcase string) error {
} }
func InitializeServer(configFile string) error { func InitializeServer(configFile string) error {
config, err := point.LoadConfig(configFile) err := BuildV2Ray()
if err != nil { if err != nil {
log.Error("Failed to read config file (", configFile, "): ", configFile, err)
return err return err
} }
vPoint, err := point.NewPoint(config) proc := exec.Command(binaryPath, "-config="+configFile)
proc.Stderr = os.Stderr
proc.Stdout = os.Stdout
err = proc.Start()
if err != nil { if err != nil {
log.Error("Failed to create Point server: ", err)
return err return err
} }
err = vPoint.Start() runningServers = append(runningServers, proc)
if err != nil {
log.Error("Error starting Point server: ", err)
return err
}
runningServers = append(runningServers, vPoint)
return nil return nil
} }
func CloseAllServers() { func CloseAllServers() {
log.Info("Closing all servers.")
for _, server := range runningServers { for _, server := range runningServers {
server.Close() server.Process.Kill()
} }
runningServers = make([]*point.Point, 0, 10) runningServers = make([]*exec.Cmd, 0, 10)
log.Info("All server closed.")
} }

View File

@ -19,7 +19,7 @@ func (o *Once) Do(f func()) {
o.m.Lock() o.m.Lock()
defer o.m.Unlock() defer o.m.Unlock()
if o.done == 0 { if o.done == 0 {
defer atomic.StoreUint32(&o.done, 1) atomic.StoreUint32(&o.done, 1)
f() f()
} }
} }

View File

@ -15,49 +15,50 @@ var (
globalCache = NewConnectionCache() globalCache = NewConnectionCache()
) )
func Dial(dest v2net.Destination) (*Connection, error) { func Dial(src v2net.Address, dest v2net.Destination) (*Connection, error) {
destStr := dest.String() if src == nil {
src = v2net.AnyIP
}
id := src.String() + "-" + dest.NetAddr()
var conn net.Conn var conn net.Conn
if transport.IsConnectionReusable() { if dest.IsTCP() && transport.IsConnectionReusable() {
conn = globalCache.Get(destStr) conn = globalCache.Get(id)
} }
if conn == nil { if conn == nil {
var err error var err error
conn, err = DialWithoutCache(dest) conn, err = DialWithoutCache(src, dest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
return &Connection{ return &Connection{
dest: destStr, dest: id,
conn: conn, conn: conn,
listener: globalCache, listener: globalCache,
}, nil }, nil
} }
func DialWithoutCache(dest v2net.Destination) (net.Conn, error) { func DialWithoutCache(src v2net.Address, dest v2net.Destination) (net.Conn, error) {
if dest.Address().IsDomain() { dialer := &net.Dialer{
dialer := &net.Dialer{ Timeout: time.Second * 60,
Timeout: time.Second * 60, DualStack: true,
DualStack: true,
}
network := "tcp"
if dest.IsUDP() {
network = "udp"
}
return dialer.Dial(network, dest.NetAddr())
} }
ip := dest.Address().IP() if src != nil && src != v2net.AnyIP {
if dest.IsTCP() { var addr net.Addr
return net.DialTCP("tcp", nil, &net.TCPAddr{ if dest.IsTCP() {
IP: ip, addr = &net.TCPAddr{
Port: int(dest.Port()), IP: src.IP(),
}) Port: 0,
}
} else {
addr = &net.UDPAddr{
IP: src.IP(),
Port: 0,
}
}
dialer.LocalAddr = addr
} }
return net.DialUDP("udp", nil, &net.UDPAddr{ return dialer.Dial(dest.Network().String(), dest.NetAddr())
IP: ip,
Port: int(dest.Port()),
})
} }

View File

@ -1,6 +1,7 @@
package hub_test package hub_test
import ( import (
"net"
"testing" "testing"
v2net "github.com/v2ray/v2ray-core/common/net" v2net "github.com/v2ray/v2ray-core/common/net"
@ -20,7 +21,35 @@ func TestDialDomain(t *testing.T) {
assert.Error(err).IsNil() assert.Error(err).IsNil()
defer server.Close() defer server.Close()
conn, err := Dial(v2net.TCPDestination(v2net.DomainAddress("local.v2ray.com"), dest.Port())) conn, err := Dial(nil, v2net.TCPDestination(v2net.DomainAddress("local.v2ray.com"), dest.Port()))
assert.Error(err).IsNil()
assert.String(conn.RemoteAddr().String()).Equals("127.0.0.1:" + dest.Port().String())
conn.Close()
}
func TestDialWithLocalAddr(t *testing.T) {
assert := assert.On(t)
server := &tcp.Server{
Port: v2nettesting.PickPort(),
}
dest, err := server.Start()
assert.Error(err).IsNil()
defer server.Close()
var localAddr net.IP
addrs, err := net.InterfaceAddrs()
assert.Error(err).IsNil()
for _, addr := range addrs {
str := addr.String()
ip := net.ParseIP(str)
if ip != nil && ip.To4() != nil {
localAddr = ip.To4()
}
}
assert.Pointer(localAddr).IsNotNil()
conn, err := Dial(v2net.IPAddress(localAddr), v2net.TCPDestination(v2net.LocalHostIP, dest.Port()))
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.String(conn.RemoteAddr().String()).Equals("127.0.0.1:" + dest.Port().String()) assert.String(conn.RemoteAddr().String()).Equals("127.0.0.1:" + dest.Port().String())
conn.Close() conn.Close()

View File

@ -130,7 +130,7 @@ func (this *UDPServer) locateExistingAndDispatch(name string, payload *alloc.Buf
} }
func (this *UDPServer) Dispatch(source v2net.Destination, destination v2net.Destination, payload *alloc.Buffer, callback UDPResponseCallback) { func (this *UDPServer) Dispatch(source v2net.Destination, destination v2net.Destination, payload *alloc.Buffer, callback UDPResponseCallback) {
destString := source.NetAddr() + "-" + destination.NetAddr() destString := source.String() + "-" + destination.String()
log.Debug("UDP Server: Dispatch request: ", destString) log.Debug("UDP Server: Dispatch request: ", destString)
if this.locateExistingAndDispatch(destString, payload) { if this.locateExistingAndDispatch(destString, payload) {
return return