فهرست منبع

allow outbound to be proxied

Darien Raymond 9 سال پیش
والد
کامیت
5dc05d6352

+ 1 - 0
all.go

@@ -3,6 +3,7 @@ package core
 import (
 	// The following are necessary as they register handlers in their init functions.
 	_ "v2ray.com/core/app/dns"
+	_ "v2ray.com/core/app/proxy"
 	_ "v2ray.com/core/app/router"
 
 	_ "v2ray.com/core/proxy/blackhole"

+ 7 - 5
app/proxy/proxy.go

@@ -36,18 +36,20 @@ func NewOutboundProxy(space app.Space) *OutboundProxy {
 	return proxy
 }
 
+func (this *OutboundProxy) RegisterDialer() {
+	internet.ProxyDialer = this.Dial
+}
+
 func (this *OutboundProxy) Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (internet.Connection, error) {
-	handler := this.outboundManager.GetHandler(options.ProxyTag)
+	handler := this.outboundManager.GetHandler(options.Proxy.Tag)
 	if handler == nil {
-		log.Warning("Proxy: Failed to get outbound handler with tag: ", options.ProxyTag)
+		log.Warning("Proxy: Failed to get outbound handler with tag: ", options.Proxy.Tag)
 		return internet.Dial(src, dest, internet.DialerOptions{
 			Stream: options.Stream,
 		})
 	}
 	stream := ray.NewRay()
-	if err := handler.Dispatch(dest, alloc.NewLocalBuffer(32).Clear(), stream); err != nil {
-		return nil, err
-	}
+	go handler.Dispatch(dest, alloc.NewLocalBuffer(32).Clear(), stream)
 	return NewProxyConnection(src, dest, stream), nil
 }
 

+ 68 - 0
app/proxy/proxy_test.go

@@ -0,0 +1,68 @@
+package proxy_test
+
+import (
+	"testing"
+
+	"v2ray.com/core/app"
+	. "v2ray.com/core/app/proxy"
+	"v2ray.com/core/app/proxyman"
+	v2net "v2ray.com/core/common/net"
+	"v2ray.com/core/proxy"
+	"v2ray.com/core/proxy/freedom"
+	"v2ray.com/core/testing/assert"
+	"v2ray.com/core/testing/servers/tcp"
+	"v2ray.com/core/transport/internet"
+)
+
+func TestProxyDial(t *testing.T) {
+	assert := assert.On(t)
+
+	space := app.NewSpace()
+	outboundManager := proxyman.NewDefaultOutboundHandlerManager()
+	outboundManager.SetHandler("tag", freedom.NewFreedomConnection(&freedom.Config{}, space, &proxy.OutboundHandlerMeta{
+		Tag: "tag",
+		StreamSettings: &internet.StreamConfig{
+			Network: v2net.Network_RawTCP,
+		},
+	}))
+	space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundManager)
+
+	proxy := NewOutboundProxy(space)
+	space.BindApp(APP_ID, proxy)
+
+	assert.Error(space.Initialize()).IsNil()
+
+	xor := func(b []byte) []byte {
+		for idx, x := range b {
+			b[idx] = x ^ 'c'
+		}
+		return b
+	}
+	tcpServer := &tcp.Server{
+		MsgProcessor: xor,
+	}
+	dest, err := tcpServer.Start()
+	assert.Error(err).IsNil()
+
+	conn, err := proxy.Dial(v2net.LocalHostIP, dest, internet.DialerOptions{
+		Stream: &internet.StreamConfig{
+			Network: v2net.Network_RawTCP,
+		},
+		Proxy: &internet.ProxyConfig{
+			Tag: "tag",
+		},
+	})
+	assert.Error(err).IsNil()
+
+	_, err = conn.Write([]byte{'a', 'b', 'c', 'd'})
+	assert.Error(err).IsNil()
+
+	b := make([]byte, 10)
+	nBytes, err := conn.Read(b)
+	assert.Error(err).IsNil()
+
+	assert.Bytes(xor(b[:nBytes])).Equals([]byte{'a', 'b', 'c', 'd'})
+
+	conn.Close()
+	tcpServer.Close()
+}

+ 1 - 3
common/io/chan_reader.go

@@ -15,11 +15,9 @@ type ChanReader struct {
 }
 
 func NewChanReader(stream Reader) *ChanReader {
-	this := &ChanReader{
+	return &ChanReader{
 		stream: stream,
 	}
-	this.Fill()
-	return this
 }
 
 // Private: Visible for testing.

+ 54 - 45
config.pb.go

@@ -196,6 +196,7 @@ type OutboundConnectionConfig struct {
 	// IP address to send data through. 0.0.0.0 if unset.
 	SendThrough    *v2ray_core_common_net1.IPOrDomain          `protobuf:"bytes,2,opt,name=send_through,json=sendThrough" json:"send_through,omitempty"`
 	StreamSettings *v2ray_core_transport_internet.StreamConfig `protobuf:"bytes,3,opt,name=stream_settings,json=streamSettings" json:"stream_settings,omitempty"`
+	ProxySettings  *v2ray_core_transport_internet.ProxyConfig  `protobuf:"bytes,5,opt,name=proxy_settings,json=proxySettings" json:"proxy_settings,omitempty"`
 	Tag            string                                      `protobuf:"bytes,4,opt,name=tag" json:"tag,omitempty"`
 }
 
@@ -225,6 +226,13 @@ func (m *OutboundConnectionConfig) GetStreamSettings() *v2ray_core_transport_int
 	return nil
 }
 
+func (m *OutboundConnectionConfig) GetProxySettings() *v2ray_core_transport_internet.ProxyConfig {
+	if m != nil {
+		return m.ProxySettings
+	}
+	return nil
+}
+
 type Config struct {
 	// Inbound handler configurations. Must have at least one item.
 	Inbound []*InboundConnectionConfig `protobuf:"bytes,1,rep,name=inbound" json:"inbound,omitempty"`
@@ -290,49 +298,50 @@ func init() {
 func init() { proto.RegisterFile("v2ray.com/core/config.proto", fileDescriptor0) }
 
 var fileDescriptor0 = []byte{
-	// 697 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x94, 0xdd, 0x6e, 0xd3, 0x3e,
-	0x18, 0xc6, 0x97, 0xb6, 0xeb, 0xda, 0xb7, 0xfb, 0xef, 0x5f, 0x19, 0x04, 0x61, 0x30, 0x54, 0xba,
-	0xaf, 0xf2, 0xa1, 0x54, 0x14, 0x21, 0x3e, 0x24, 0x18, 0x5b, 0x07, 0xd2, 0x40, 0xa2, 0x95, 0xbb,
-	0x23, 0x4e, 0x2a, 0x2f, 0xf5, 0xb2, 0x48, 0x89, 0x1d, 0x39, 0xee, 0x46, 0x2f, 0x81, 0x03, 0x2e,
-	0x86, 0x5b, 0xe1, 0x8a, 0x90, 0x1d, 0x37, 0xcd, 0x68, 0x33, 0x26, 0x21, 0xce, 0x9c, 0xf8, 0xf9,
-	0xbd, 0xb6, 0x9f, 0xe7, 0xb5, 0xe1, 0xee, 0x79, 0x47, 0x90, 0x89, 0xe3, 0xf2, 0xb0, 0xed, 0x72,
-	0x41, 0xdb, 0x2e, 0x67, 0xa7, 0xbe, 0xe7, 0x44, 0x82, 0x4b, 0x8e, 0x60, 0x3a, 0x29, 0xe8, 0xfa,
-	0xee, 0x9c, 0x30, 0x0c, 0x39, 0x6b, 0x07, 0x9c, 0x8c, 0xa8, 0x68, 0xcb, 0x49, 0x44, 0x13, 0x68,
-	0x7d, 0x6b, 0xb1, 0x90, 0x51, 0xd9, 0x8e, 0xb8, 0x90, 0x46, 0xb5, 0x9b, 0xaf, 0x22, 0xa3, 0x91,
-	0xa0, 0x71, 0x6c, 0x84, 0x3b, 0x79, 0xeb, 0x7a, 0x97, 0xf6, 0xba, 0xee, 0xfc, 0xa6, 0x93, 0x82,
-	0xb0, 0x58, 0x2d, 0xd8, 0xf6, 0x99, 0xa4, 0x42, 0x15, 0xbe, 0xa4, 0xdf, 0xce, 0xd5, 0x67, 0x65,
-	0xcd, 0xe7, 0xb0, 0xb1, 0x1f, 0x04, 0xdc, 0x25, 0xd2, 0xe7, 0x6c, 0x20, 0x05, 0x91, 0xd4, 0x9b,
-	0x74, 0x39, 0x73, 0xc7, 0x42, 0x50, 0xe6, 0x4e, 0xd0, 0x4d, 0x58, 0x3e, 0x27, 0xc1, 0x98, 0xda,
-	0x56, 0xc3, 0x6a, 0xfd, 0x87, 0x93, 0x8f, 0xe6, 0x53, 0xb8, 0x33, 0x8f, 0x61, 0x7a, 0x2a, 0x68,
-	0x7c, 0x96, 0x83, 0x7c, 0x2b, 0x00, 0x9a, 0x67, 0xd0, 0x0b, 0x28, 0x29, 0x73, 0xb5, 0x76, 0xad,
-	0xb3, 0xe9, 0xcc, 0x22, 0x71, 0xe6, 0xd5, 0xce, 0xf1, 0x24, 0xa2, 0x58, 0x03, 0xe8, 0x13, 0xd4,
-	0xdc, 0xd9, 0x3e, 0xed, 0x42, 0xc3, 0x6a, 0xd5, 0x3a, 0x0f, 0xaf, 0xe6, 0x33, 0x07, 0xc3, 0x59,
-	0x1a, 0xed, 0xc1, 0x8a, 0x48, 0x76, 0x6f, 0x17, 0x75, 0xa1, 0xed, 0xab, 0x0b, 0x99, 0xa3, 0xe2,
-	0x29, 0xd5, 0x7c, 0x02, 0x25, 0xb5, 0x37, 0x04, 0x50, 0xde, 0x0f, 0x2e, 0xc8, 0x24, 0xae, 0x2f,
-	0xa9, 0x31, 0x26, 0x6c, 0xc4, 0xc3, 0xba, 0x85, 0x56, 0xa1, 0xf2, 0xfe, 0xab, 0xca, 0x89, 0x04,
-	0xf5, 0x42, 0xf3, 0x67, 0x11, 0x6e, 0x1f, 0xb1, 0x13, 0x3e, 0x66, 0xa3, 0x2e, 0x67, 0x8c, 0xba,
-	0xaa, 0x76, 0x57, 0xe7, 0x82, 0xba, 0x50, 0x89, 0xa9, 0x94, 0x3e, 0xf3, 0x62, 0x6d, 0x4a, 0xad,
-	0xb3, 0x9b, 0xdd, 0x4b, 0xd2, 0x1f, 0x4e, 0xd2, 0x97, 0xda, 0x8f, 0xd1, 0xc0, 0xc8, 0x71, 0x0a,
-	0xa2, 0x3d, 0x00, 0x95, 0xf5, 0x50, 0x10, 0xe6, 0x51, 0xe3, 0x4d, 0x63, 0x41, 0x19, 0x46, 0xa5,
-	0xd3, 0xe7, 0x42, 0x62, 0xa5, 0xc3, 0xd5, 0x68, 0x3a, 0x44, 0x6f, 0xa1, 0x1a, 0xf8, 0xb1, 0xa4,
-	0x6c, 0xc8, 0x99, 0xb1, 0xe4, 0x41, 0x0e, 0x7f, 0xd4, 0xef, 0x89, 0x43, 0x1e, 0x12, 0x9f, 0xe1,
-	0x4a, 0xc2, 0xf4, 0x18, 0xaa, 0x43, 0x51, 0x12, 0xcf, 0x2e, 0x35, 0xac, 0x56, 0x15, 0xab, 0x21,
-	0xea, 0xc1, 0x0d, 0x92, 0xfa, 0x38, 0x8c, 0x8d, 0x91, 0xf6, 0xb2, 0xae, 0x7d, 0xff, 0x0f, 0x76,
-	0x23, 0x32, 0xdf, 0x39, 0xc7, 0xf0, 0x7f, 0x2c, 0x05, 0x25, 0xe1, 0x30, 0xf5, 0xab, 0xac, 0x8b,
-	0x3d, 0xce, 0x16, 0x4b, 0xfb, 0xde, 0x99, 0xde, 0x13, 0x67, 0xa0, 0xa9, 0xc4, 0x6e, 0xbc, 0x96,
-	0xd4, 0x98, 0x7a, 0x88, 0x5e, 0x82, 0xad, 0xd6, 0xba, 0x18, 0x46, 0x24, 0x8e, 0xfd, 0x73, 0x3a,
-	0x74, 0xd3, 0x80, 0xec, 0x95, 0x86, 0xd5, 0xaa, 0xe0, 0x5b, 0x7a, 0xbe, 0x9f, 0x4c, 0xcf, 0xe2,
-	0x6b, 0x7e, 0x2f, 0x80, 0xdd, 0x1b, 0xcb, 0x7f, 0x98, 0xea, 0x21, 0xac, 0xc6, 0x94, 0x8d, 0x86,
-	0xf2, 0x4c, 0xf0, 0xb1, 0x77, 0x66, 0x72, 0xbd, 0x46, 0x2e, 0x35, 0x85, 0x1d, 0x27, 0xd4, 0x22,
-	0xdf, 0x8a, 0x7f, 0xef, 0xdb, 0x5c, 0xe0, 0xcd, 0x1f, 0x05, 0x28, 0x9b, 0xd3, 0xbf, 0x81, 0x15,
-	0x3f, 0x69, 0x77, 0xdb, 0x6a, 0x14, 0x5b, 0xb5, 0xcb, 0xf7, 0x3c, 0xe7, 0x26, 0xe0, 0x29, 0x83,
-	0xde, 0x41, 0x85, 0x1b, 0x63, 0xed, 0x82, 0xe6, 0xb7, 0xb2, 0x7c, 0x9e, 0xe9, 0x38, 0xa5, 0x50,
-	0x1b, 0x8a, 0x01, 0xf7, 0xcc, 0x39, 0x37, 0x16, 0x3a, 0xef, 0x39, 0x86, 0x52, 0x4a, 0xf4, 0x0a,
-	0x8a, 0x24, 0x8a, 0xec, 0x92, 0x5e, 0xed, 0xda, 0x51, 0x29, 0x06, 0xbd, 0x86, 0x6a, 0x6a, 0x9e,
-	0x69, 0xef, 0x7b, 0x8b, 0x9d, 0x35, 0x0b, 0xce, 0xe4, 0x8f, 0x76, 0x60, 0x35, 0xf9, 0xf9, 0x81,
-	0x8b, 0x90, 0x48, 0xf5, 0x6c, 0xf4, 0xd5, 0x3b, 0x7d, 0x32, 0x3e, 0xad, 0x2f, 0xa1, 0x0a, 0x94,
-	0x3e, 0x0e, 0x7a, 0x9f, 0xeb, 0xd6, 0xc1, 0x26, 0xac, 0xb9, 0x3c, 0xcc, 0x54, 0x3d, 0xa8, 0x25,
-	0x9c, 0x56, 0x7f, 0x29, 0xa9, 0x5f, 0x27, 0x65, 0xfd, 0xc4, 0x3f, 0xfb, 0x15, 0x00, 0x00, 0xff,
-	0xff, 0x1c, 0xfa, 0xca, 0xe6, 0x04, 0x07, 0x00, 0x00,
+	// 719 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x95, 0xdd, 0x6e, 0xd3, 0x30,
+	0x1c, 0xc5, 0x97, 0xb6, 0xeb, 0xda, 0x7f, 0xb7, 0x52, 0x19, 0x04, 0x61, 0x30, 0x54, 0xba, 0xaf,
+	0x32, 0x50, 0x2a, 0x8a, 0x10, 0x1f, 0x12, 0x8c, 0xad, 0x03, 0x69, 0x20, 0xd1, 0xe2, 0xee, 0x8a,
+	0x9b, 0xca, 0x4b, 0xbd, 0x2c, 0x52, 0x62, 0x47, 0x8e, 0xbb, 0xad, 0x8f, 0xc0, 0xe3, 0xf0, 0x2a,
+	0x3c, 0x01, 0x8f, 0x82, 0xec, 0xb8, 0x69, 0x47, 0xdb, 0x6d, 0x12, 0xe2, 0x2e, 0x8d, 0xcf, 0xef,
+	0xd8, 0x39, 0xc7, 0x76, 0xe1, 0xc1, 0x59, 0x53, 0x90, 0xa1, 0xe3, 0xf2, 0xb0, 0xe1, 0x72, 0x41,
+	0x1b, 0x2e, 0x67, 0x27, 0xbe, 0xe7, 0x44, 0x82, 0x4b, 0x8e, 0x60, 0x34, 0x28, 0xe8, 0xea, 0xf6,
+	0x94, 0x30, 0x0c, 0x39, 0x6b, 0x04, 0x9c, 0xf4, 0xa9, 0x68, 0xc8, 0x61, 0x44, 0x13, 0x68, 0x75,
+	0x63, 0xb6, 0x90, 0x51, 0xd9, 0x88, 0xb8, 0x90, 0x46, 0xb5, 0x3d, 0x5f, 0x45, 0xfa, 0x7d, 0x41,
+	0xe3, 0xd8, 0x08, 0xb7, 0xe6, 0xcd, 0xeb, 0x5d, 0x5a, 0xeb, 0xaa, 0xf3, 0x97, 0x4e, 0x0a, 0xc2,
+	0x62, 0x35, 0x61, 0xc3, 0x67, 0x92, 0x0a, 0x65, 0x7c, 0x49, 0xbf, 0x39, 0x57, 0x3f, 0x29, 0xab,
+	0xbd, 0x84, 0xb5, 0xbd, 0x20, 0xe0, 0x2e, 0x91, 0x3e, 0x67, 0x5d, 0x29, 0x88, 0xa4, 0xde, 0xb0,
+	0xc5, 0x99, 0x3b, 0x10, 0x82, 0x32, 0x77, 0x88, 0xee, 0xc0, 0xe2, 0x19, 0x09, 0x06, 0xd4, 0xb6,
+	0xaa, 0x56, 0x7d, 0x05, 0x27, 0x3f, 0x6a, 0xcf, 0xe1, 0xfe, 0x34, 0x86, 0xe9, 0x89, 0xa0, 0xf1,
+	0xe9, 0x1c, 0xe4, 0x47, 0x06, 0xd0, 0x34, 0x83, 0x5e, 0x41, 0x4e, 0x85, 0xab, 0xb5, 0xe5, 0xe6,
+	0xba, 0x33, 0xae, 0xc4, 0x99, 0x56, 0x3b, 0x47, 0xc3, 0x88, 0x62, 0x0d, 0xa0, 0x2f, 0x50, 0x72,
+	0xc7, 0xeb, 0xb4, 0x33, 0x55, 0xab, 0x5e, 0x6a, 0x3e, 0xb9, 0x9a, 0x9f, 0xf8, 0x30, 0x3c, 0x49,
+	0xa3, 0x5d, 0x58, 0x12, 0xc9, 0xea, 0xed, 0xac, 0x36, 0xda, 0xbc, 0xda, 0xc8, 0x7c, 0x2a, 0x1e,
+	0x51, 0xb5, 0x67, 0x90, 0x53, 0x6b, 0x43, 0x00, 0xf9, 0xbd, 0xe0, 0x9c, 0x0c, 0xe3, 0xca, 0x82,
+	0x7a, 0xc6, 0x84, 0xf5, 0x79, 0x58, 0xb1, 0xd0, 0x32, 0x14, 0x3e, 0x5e, 0xa8, 0x9e, 0x48, 0x50,
+	0xc9, 0xd4, 0x7e, 0x65, 0xe1, 0xde, 0x21, 0x3b, 0xe6, 0x03, 0xd6, 0x6f, 0x71, 0xc6, 0xa8, 0xab,
+	0xbc, 0x5b, 0xba, 0x17, 0xd4, 0x82, 0x42, 0x4c, 0xa5, 0xf4, 0x99, 0x17, 0xeb, 0x50, 0x4a, 0xcd,
+	0xed, 0xc9, 0xb5, 0x24, 0xfb, 0xc3, 0x49, 0xf6, 0xa5, 0xce, 0xa3, 0xdf, 0x35, 0x72, 0x9c, 0x82,
+	0x68, 0x17, 0x40, 0x75, 0xdd, 0x13, 0x84, 0x79, 0xd4, 0x64, 0x53, 0x9d, 0x61, 0xc3, 0xa8, 0x74,
+	0x3a, 0x5c, 0x48, 0xac, 0x74, 0xb8, 0x18, 0x8d, 0x1e, 0xd1, 0x7b, 0x28, 0x06, 0x7e, 0x2c, 0x29,
+	0xeb, 0x71, 0x66, 0x22, 0x79, 0x3c, 0x87, 0x3f, 0xec, 0xb4, 0xc5, 0x01, 0x0f, 0x89, 0xcf, 0x70,
+	0x21, 0x61, 0xda, 0x0c, 0x55, 0x20, 0x2b, 0x89, 0x67, 0xe7, 0xaa, 0x56, 0xbd, 0x88, 0xd5, 0x23,
+	0x6a, 0xc3, 0x6d, 0x92, 0xe6, 0xd8, 0x8b, 0x4d, 0x90, 0xf6, 0xa2, 0xf6, 0x7e, 0x74, 0x4d, 0xdc,
+	0x88, 0x4c, 0xef, 0x9c, 0x23, 0xb8, 0x15, 0x4b, 0x41, 0x49, 0xd8, 0x4b, 0xf3, 0xca, 0x6b, 0xb3,
+	0xa7, 0x93, 0x66, 0xe9, 0xbe, 0x77, 0x46, 0xe7, 0xc4, 0xe9, 0x6a, 0x2a, 0x89, 0x1b, 0x97, 0x13,
+	0x8f, 0x51, 0x86, 0xe8, 0x35, 0xd8, 0x6a, 0xae, 0xf3, 0x5e, 0x44, 0xe2, 0xd8, 0x3f, 0xa3, 0x3d,
+	0x37, 0x2d, 0xc8, 0x5e, 0xaa, 0x5a, 0xf5, 0x02, 0xbe, 0xab, 0xc7, 0x3b, 0xc9, 0xf0, 0xb8, 0xbe,
+	0xda, 0xef, 0x0c, 0xd8, 0xed, 0x81, 0xfc, 0x8f, 0xad, 0x1e, 0xc0, 0x72, 0x4c, 0x59, 0xbf, 0x27,
+	0x4f, 0x05, 0x1f, 0x78, 0xa7, 0xa6, 0xd7, 0x1b, 0xf4, 0x52, 0x52, 0xd8, 0x51, 0x42, 0xcd, 0xca,
+	0x2d, 0xfb, 0xef, 0xb9, 0x7d, 0x83, 0x72, 0x24, 0xf8, 0xc5, 0x70, 0x6c, 0x9a, 0x34, 0xbb, 0x73,
+	0x8d, 0x69, 0x47, 0x41, 0xc6, 0x73, 0x45, 0x3b, 0xa4, 0x96, 0x53, 0x7b, 0xa8, 0xf6, 0x33, 0x03,
+	0x79, 0x13, 0xe8, 0x3b, 0x58, 0xf2, 0x93, 0x13, 0x64, 0x5b, 0xd5, 0x6c, 0xbd, 0x74, 0xf9, 0xea,
+	0x98, 0x73, 0xb8, 0xf0, 0x88, 0x41, 0x1f, 0xa0, 0xc0, 0x4d, 0x57, 0x76, 0x46, 0xf3, 0x1b, 0x93,
+	0xfc, 0xbc, 0x1e, 0x71, 0x4a, 0xa1, 0x06, 0x64, 0x03, 0xee, 0x99, 0xe8, 0xd6, 0x66, 0x96, 0xe9,
+	0x39, 0x86, 0x52, 0x4a, 0xf4, 0x06, 0xb2, 0x24, 0x8a, 0xec, 0x9c, 0x9e, 0xed, 0xc6, 0xed, 0x2b,
+	0x06, 0xbd, 0x85, 0x62, 0x1a, 0x9d, 0xc9, 0xf5, 0xe1, 0xec, 0x5c, 0xcd, 0x84, 0x63, 0xf9, 0xce,
+	0x16, 0x2c, 0x27, 0x2f, 0x3f, 0x71, 0x11, 0x12, 0xa9, 0x6e, 0xa2, 0x8e, 0xba, 0xfa, 0x8f, 0x07,
+	0x27, 0x95, 0x05, 0x54, 0x80, 0xdc, 0xe7, 0x6e, 0xfb, 0x6b, 0xc5, 0xda, 0x5f, 0x87, 0xb2, 0xcb,
+	0xc3, 0x09, 0xd7, 0xfd, 0x52, 0xc2, 0x69, 0xf5, 0xf7, 0x9c, 0x7a, 0x75, 0x9c, 0xd7, 0xff, 0x1a,
+	0x2f, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0xe4, 0x6f, 0x70, 0x9e, 0x57, 0x07, 0x00, 0x00,
 }

+ 1 - 0
config.proto

@@ -77,6 +77,7 @@ message OutboundConnectionConfig {
   // IP address to send data through. 0.0.0.0 if unset.
   v2ray.core.common.net.IPOrDomain send_through = 2;
   v2ray.core.transport.internet.StreamConfig stream_settings = 3;
+  v2ray.core.transport.internet.ProxyConfig proxy_settings = 5;
   string tag = 4;
 }
 

+ 1 - 3
proxy/freedom/freedom.go

@@ -80,9 +80,7 @@ func (this *FreedomConnection) Dispatch(destination v2net.Destination, payload *
 		destination = this.ResolveIP(destination)
 	}
 	err := retry.Timed(5, 100).On(func() error {
-		rawConn, err := internet.Dial(this.meta.Address, destination, internet.DialerOptions{
-			Stream: this.meta.StreamSettings,
-		})
+		rawConn, err := internet.Dial(this.meta.Address, destination, this.meta.GetDialerOptions())
 		if err != nil {
 			return err
 		}

+ 8 - 0
proxy/proxy.go

@@ -34,6 +34,14 @@ type OutboundHandlerMeta struct {
 	Tag            string
 	Address        v2net.Address
 	StreamSettings *internet.StreamConfig
+	ProxySettings  *internet.ProxyConfig
+}
+
+func (this *OutboundHandlerMeta) GetDialerOptions() internet.DialerOptions {
+	return internet.DialerOptions{
+		Stream: this.StreamSettings,
+		Proxy:  this.ProxySettings,
+	}
 }
 
 // An InboundHandler handles inbound network connections to V2Ray.

+ 1 - 3
proxy/shadowsocks/client.go

@@ -48,9 +48,7 @@ func (this *Client) Dispatch(destination v2net.Destination, payload *alloc.Buffe
 		server = this.serverPicker.PickServer()
 		dest := server.Destination()
 		dest.Network = network
-		rawConn, err := internet.Dial(this.meta.Address, dest, internet.DialerOptions{
-			Stream: this.meta.StreamSettings,
-		})
+		rawConn, err := internet.Dial(this.meta.Address, dest, this.meta.GetDialerOptions())
 		if err != nil {
 			return err
 		}

+ 1 - 1
testing/servers/tcp/tcp.go

@@ -36,7 +36,7 @@ func (server *Server) acceptConnections(listener *net.TCPListener) {
 	for server.accepting {
 		conn, err := listener.Accept()
 		if err != nil {
-			fmt.Printf("Failed accept TCP connection: %v", err)
+			fmt.Printf("Failed accept TCP connection: %v\n", err)
 			continue
 		}
 

+ 13 - 0
tools/conf/transport_internet.go

@@ -230,3 +230,16 @@ func (this *StreamConfig) Build() (*internet.StreamConfig, error) {
 	}
 	return config, nil
 }
+
+type ProxyConfig struct {
+	Tag string `json:"tag"`
+}
+
+func (this *ProxyConfig) Build() (*internet.ProxyConfig, error) {
+	if len(this.Tag) == 0 {
+		return nil, errors.New("Proxy tag is not set.")
+	}
+	return &internet.ProxyConfig{
+		Tag: this.Tag,
+	}, nil
+}

+ 17 - 0
tools/conf/v2ray.go

@@ -74,6 +74,7 @@ type OutboundConnectionConfig struct {
 	Protocol      string          `json:"protocol"`
 	SendThrough   *Address        `json:"sendThrough"`
 	StreamSetting *StreamConfig   `json:"streamSettings"`
+	ProxySettings *ProxyConfig    `json:"proxySettings"`
 	Settings      json.RawMessage `json:"settings"`
 }
 
@@ -103,6 +104,13 @@ func (this *OutboundConnectionConfig) Build() (*core.OutboundConnectionConfig, e
 		}
 		config.StreamSettings = ss
 	}
+	if this.ProxySettings != nil {
+		ps, err := this.ProxySettings.Build()
+		if err != nil {
+			return nil, errors.New("Outbound: invalid proxy settings: " + err.Error())
+		}
+		config.ProxySettings = ps
+	}
 	return config, nil
 }
 
@@ -198,6 +206,7 @@ type OutboundDetourConfig struct {
 	Tag           string          `json:"tag"`
 	Settings      json.RawMessage `json:"settings"`
 	StreamSetting *StreamConfig   `json:"streamSettings"`
+	ProxySettings *ProxyConfig    `json:"proxySettings"`
 }
 
 func (this *OutboundDetourConfig) Build() (*core.OutboundConnectionConfig, error) {
@@ -228,6 +237,14 @@ func (this *OutboundDetourConfig) Build() (*core.OutboundConnectionConfig, error
 	if err != nil {
 		return nil, err
 	}
+
+	if this.ProxySettings != nil {
+		ps, err := this.ProxySettings.Build()
+		if err != nil {
+			return nil, errors.New("OutboundDetour: invalid proxy settings: " + err.Error())
+		}
+		config.ProxySettings = ps
+	}
 	config.Settings = ts
 	return config, nil
 }

+ 4 - 0
transport/internet/config.go

@@ -68,3 +68,7 @@ func ApplyGlobalNetworkSettings(settings []*NetworkSettings) error {
 	globalNetworkSettings = settings
 	return nil
 }
+
+func (this *ProxyConfig) HasTag() bool {
+	return this != nil && len(this.Tag) > 0
+}

+ 32 - 20
transport/internet/config.pb.go

@@ -11,6 +11,7 @@ It is generated from these files:
 It has these top-level messages:
 	NetworkSettings
 	StreamConfig
+	ProxyConfig
 */
 package internet
 
@@ -78,32 +79,43 @@ func (m *StreamConfig) GetSecuritySettings() []*v2ray_core_common_loader.TypedSe
 	return nil
 }
 
+type ProxyConfig struct {
+	Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"`
+}
+
+func (m *ProxyConfig) Reset()                    { *m = ProxyConfig{} }
+func (m *ProxyConfig) String() string            { return proto.CompactTextString(m) }
+func (*ProxyConfig) ProtoMessage()               {}
+func (*ProxyConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
+
 func init() {
 	proto.RegisterType((*NetworkSettings)(nil), "v2ray.core.transport.internet.NetworkSettings")
 	proto.RegisterType((*StreamConfig)(nil), "v2ray.core.transport.internet.StreamConfig")
+	proto.RegisterType((*ProxyConfig)(nil), "v2ray.core.transport.internet.ProxyConfig")
 }
 
 func init() { proto.RegisterFile("v2ray.com/core/transport/internet/config.proto", fileDescriptor0) }
 
 var fileDescriptor0 = []byte{
-	// 296 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x91, 0x4f, 0x4b, 0xc3, 0x40,
-	0x10, 0xc5, 0x49, 0x2b, 0x5a, 0xb7, 0xd5, 0xd6, 0x9c, 0x82, 0xa0, 0xc4, 0x7a, 0x68, 0x2e, 0xce,
-	0x42, 0xbc, 0x78, 0xb6, 0x77, 0x0f, 0x69, 0x2f, 0x7a, 0x29, 0x71, 0x3b, 0x96, 0xa0, 0xd9, 0x0d,
-	0x93, 0x51, 0xc9, 0xb7, 0xf0, 0x13, 0xf8, 0x59, 0x25, 0x7f, 0x36, 0x94, 0xa0, 0x45, 0xe8, 0x6d,
-	0x18, 0xde, 0xfb, 0xed, 0x9b, 0xb7, 0x02, 0x3e, 0x42, 0x8a, 0x0b, 0x50, 0x26, 0x95, 0xca, 0x10,
-	0x4a, 0xa6, 0x58, 0xe7, 0x99, 0x21, 0x96, 0x89, 0x66, 0x24, 0x8d, 0x2c, 0x95, 0xd1, 0x2f, 0xc9,
-	0x06, 0x32, 0x32, 0x6c, 0xdc, 0x0b, 0xab, 0x27, 0x84, 0x56, 0x0b, 0x56, 0x7b, 0x3e, 0xeb, 0xe0,
-	0x94, 0x49, 0x53, 0xa3, 0x65, 0x89, 0xd1, 0xc8, 0x9f, 0x86, 0x5e, 0x6b, 0xce, 0x5f, 0xc2, 0x37,
-	0x13, 0xaf, 0x91, 0x24, 0x17, 0x19, 0xd6, 0xc2, 0xe9, 0x97, 0x23, 0xc6, 0x0f, 0xb5, 0x75, 0x81,
-	0xcc, 0x89, 0xde, 0xe4, 0xee, 0x9d, 0x38, 0x6a, 0x68, 0x9e, 0xe3, 0x3b, 0xc1, 0x69, 0x78, 0x09,
-	0x5b, 0xb1, 0x6a, 0x14, 0x68, 0x64, 0x68, 0x8c, 0x91, 0x95, 0xbb, 0x73, 0x31, 0xc8, 0x1b, 0x8a,
-	0xd7, 0xf3, 0x9d, 0x60, 0x18, 0xce, 0x7e, 0xb1, 0xd6, 0x29, 0x60, 0x59, 0x64, 0xb8, 0xb6, 0x8f,
-	0x46, 0xad, 0x71, 0xfa, 0xdd, 0x13, 0xa3, 0x05, 0x13, 0xc6, 0xe9, 0xbc, 0xaa, 0x66, 0x8f, 0x3c,
-	0x8f, 0x62, 0xd2, 0x8c, 0xab, 0xad, 0x5c, 0xfd, 0x60, 0x18, 0x02, 0xec, 0x6c, 0x1a, 0x3a, 0x9d,
-	0x44, 0x63, 0xdd, 0x29, 0xe9, 0x5a, 0x9c, 0xe4, 0xa8, 0xde, 0x29, 0xe1, 0x62, 0x55, 0xf6, 0xe9,
-	0xf5, 0x7d, 0x27, 0x38, 0x8e, 0x46, 0x76, 0x59, 0x5e, 0xe7, 0x2e, 0xc5, 0x59, 0x2b, 0x6a, 0x03,
-	0x1c, 0x54, 0x01, 0xfe, 0x5d, 0xcc, 0xc4, 0x12, 0xec, 0xe6, 0xfe, 0x46, 0x5c, 0x29, 0x93, 0xee,
-	0x3e, 0xe0, 0x69, 0x60, 0xa7, 0xe7, 0xc3, 0xea, 0xa7, 0x6f, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff,
-	0xf6, 0x3d, 0x07, 0x73, 0x8c, 0x02, 0x00, 0x00,
+	// 317 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x92, 0xcd, 0x4a, 0xfb, 0x50,
+	0x10, 0xc5, 0x49, 0xfb, 0xe7, 0x6f, 0x7b, 0x5b, 0x6d, 0xcd, 0xaa, 0x08, 0x6a, 0xad, 0x8b, 0x66,
+	0xe3, 0x04, 0xe2, 0xc6, 0xb5, 0xdd, 0x8b, 0xa4, 0xdd, 0xe8, 0xa6, 0xc4, 0xdb, 0xb1, 0x04, 0xcd,
+	0x9d, 0x30, 0x19, 0x3f, 0xf2, 0x16, 0x3e, 0x81, 0xcf, 0x2a, 0xf9, 0xb8, 0xa1, 0x14, 0x2d, 0x82,
+	0xbb, 0x61, 0x38, 0xe7, 0xdc, 0x33, 0x3f, 0xae, 0x82, 0xd7, 0x80, 0xa3, 0x1c, 0x34, 0x25, 0xbe,
+	0x26, 0x46, 0x5f, 0x38, 0x32, 0x59, 0x4a, 0x2c, 0x7e, 0x6c, 0x04, 0xd9, 0xa0, 0xf8, 0x9a, 0xcc,
+	0x63, 0xbc, 0x86, 0x94, 0x49, 0xc8, 0x3d, 0xb6, 0x7a, 0x46, 0x68, 0xb4, 0x60, 0xb5, 0x47, 0xd3,
+	0xad, 0x38, 0x4d, 0x49, 0x42, 0xc6, 0x2f, 0x62, 0x0c, 0xca, 0x1b, 0xf1, 0x53, 0x95, 0xf3, 0x93,
+	0xf0, 0x99, 0xa2, 0x15, 0xb2, 0x2f, 0x79, 0x8a, 0x95, 0x70, 0xf2, 0xe1, 0xa8, 0xc1, 0x4d, 0x65,
+	0x9d, 0xa3, 0x48, 0x6c, 0xd6, 0x99, 0x7b, 0xa5, 0xf6, 0xea, 0xb4, 0x91, 0x33, 0x76, 0xbc, 0x83,
+	0xe0, 0x04, 0x36, 0x6a, 0x55, 0x51, 0x60, 0x50, 0xa0, 0x36, 0x86, 0x56, 0xee, 0xce, 0x54, 0x27,
+	0xab, 0x53, 0x46, 0xad, 0xb1, 0xe3, 0xf5, 0x82, 0xe9, 0x37, 0xd6, 0xaa, 0x05, 0x2c, 0xf2, 0x14,
+	0x57, 0xf6, 0xd1, 0xb0, 0x31, 0x4e, 0x3e, 0x5b, 0xaa, 0x3f, 0x17, 0xc6, 0x28, 0x99, 0x95, 0x68,
+	0xfe, 0xd0, 0xe7, 0x4e, 0x0d, 0xeb, 0x71, 0xb9, 0xd1, 0xab, 0xed, 0xf5, 0x02, 0x80, 0x9d, 0xa4,
+	0x61, 0x8b, 0x49, 0x38, 0x30, 0x5b, 0x90, 0xce, 0xd5, 0x7e, 0x86, 0xfa, 0x85, 0x63, 0xc9, 0x97,
+	0x05, 0xcf, 0x51, 0x7b, 0xec, 0x78, 0xdd, 0xb0, 0x6f, 0x97, 0xc5, 0x75, 0xee, 0x42, 0x1d, 0x36,
+	0xa2, 0xa6, 0xc0, 0xbf, 0xb2, 0xc0, 0xaf, 0xc1, 0x0c, 0x6d, 0x82, 0xdd, 0x4c, 0x4e, 0x55, 0xef,
+	0x96, 0xe9, 0x3d, 0xaf, 0xf1, 0x0c, 0x55, 0x5b, 0xa2, 0x75, 0x89, 0xa6, 0x1b, 0x16, 0xe3, 0xf5,
+	0x85, 0x3a, 0xd3, 0x94, 0xec, 0xbe, 0xf0, 0xbe, 0x63, 0xa7, 0x87, 0xff, 0xe5, 0x57, 0xb8, 0xfc,
+	0x0a, 0x00, 0x00, 0xff, 0xff, 0xa6, 0xb6, 0x2f, 0xcf, 0xad, 0x02, 0x00, 0x00,
 }

+ 4 - 0
transport/internet/config.proto

@@ -25,4 +25,8 @@ message StreamConfig {
   string security_type = 3;
   
   repeated v2ray.core.common.loader.TypedSettings security_settings = 4;
+}
+
+message ProxyConfig {
+  string tag = 1;
 }

+ 3 - 3
transport/internet/dialer.go

@@ -12,8 +12,8 @@ var (
 )
 
 type DialerOptions struct {
-	Stream   *StreamConfig
-	ProxyTag string
+	Stream *StreamConfig
+	Proxy  *ProxyConfig
 }
 
 type Dialer func(src v2net.Address, dest v2net.Destination, options DialerOptions) (Connection, error)
@@ -28,7 +28,7 @@ var (
 )
 
 func Dial(src v2net.Address, dest v2net.Destination, options DialerOptions) (Connection, error) {
-	if len(options.ProxyTag) > 0 && ProxyDialer != nil {
+	if options.Proxy.HasTag() && ProxyDialer != nil {
 		return ProxyDialer(src, dest, options)
 	}
 

+ 6 - 0
v2ray.go

@@ -5,6 +5,7 @@ import (
 	"v2ray.com/core/app/dispatcher"
 	dispatchers "v2ray.com/core/app/dispatcher/impl"
 	"v2ray.com/core/app/dns"
+	proxydialer "v2ray.com/core/app/proxy"
 	"v2ray.com/core/app/proxyman"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/log"
@@ -44,6 +45,10 @@ func NewPoint(pConfig *Config) (*Point, error) {
 	outboundHandlerManager := proxyman.NewDefaultOutboundHandlerManager()
 	vpoint.space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundHandlerManager)
 
+	proxyDialer := proxydialer.NewOutboundProxy(space)
+	proxyDialer.RegisterDialer()
+	space.BindApp(proxydialer.APP_ID, proxyDialer)
+
 	for _, app := range pConfig.App {
 		settings, err := app.GetInstance()
 		if err != nil {
@@ -113,6 +118,7 @@ func NewPoint(pConfig *Config) (*Point, error) {
 				Tag:            outbound.Tag,
 				Address:        outbound.GetSendThroughValue(),
 				StreamSettings: outbound.StreamSettings,
+				ProxySettings:  outbound.ProxySettings,
 			})
 		if err != nil {
 			log.Error("Point: Failed to create detour outbound connection handler: ", err)