1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-21 09:36:34 -05:00

protobuf for stream settings

This commit is contained in:
Darien Raymond 2016-10-02 23:43:58 +02:00
parent 5ec948f690
commit 1d13f47f9c
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
59 changed files with 1243 additions and 323 deletions

View File

@ -28,8 +28,8 @@ func TestDnsAdd(t *testing.T) {
space, space,
&proxy.OutboundHandlerMeta{ &proxy.OutboundHandlerMeta{
Address: v2net.AnyIP, Address: v2net.AnyIP,
StreamSettings: &internet.StreamSettings{ StreamSettings: &internet.StreamConfig{
Type: internet.StreamConnectionTypeRawTCP, Network: v2net.Network_RawTCP,
}, },
})) }))
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundHandlerManager) space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundHandlerManager)

View File

@ -68,7 +68,7 @@ func NewNetworkList(networks collect.StringList) *NetworkList {
} }
// HashNetwork returns true if the given network is in this NetworkList. // HashNetwork returns true if the given network is in this NetworkList.
func (this *NetworkList) HasNetwork(network Network) bool { func (this NetworkList) HasNetwork(network Network) bool {
for _, value := range this.Network { for _, value := range this.Network {
if string(value) == string(network) { if string(value) == string(network) {
return true return true
@ -76,3 +76,7 @@ func (this *NetworkList) HasNetwork(network Network) bool {
} }
return false return false
} }
func (this NetworkList) Get(idx int) Network {
return this.Network[idx]
}

View File

@ -8,6 +8,15 @@ import (
"v2ray.com/core/common/collect" "v2ray.com/core/common/collect"
) )
func (this *Network) UnmarshalJSON(data []byte) error {
var str string
if err := json.Unmarshal(data, &str); err != nil {
return err
}
*this = ParseNetwork(str)
return nil
}
func (this *NetworkList) UnmarshalJSON(data []byte) error { func (this *NetworkList) UnmarshalJSON(data []byte) error {
var strlist collect.StringList var strlist collect.StringList
if err := json.Unmarshal(data, &strlist); err != nil { if err := json.Unmarshal(data, &strlist); err != nil {

View File

@ -10,6 +10,15 @@ import (
"v2ray.com/core/testing/assert" "v2ray.com/core/testing/assert"
) )
func TestStringNetwork(t *testing.T) {
assert := assert.On(t)
var network Network
err := json.Unmarshal([]byte(`"tcp"`), &network)
assert.Error(err).IsNil()
assert.Bool(network == Network_TCP).IsTrue()
}
func TestArrayNetworkList(t *testing.T) { func TestArrayNetworkList(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)

View File

@ -6,7 +6,6 @@ import (
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
"v2ray.com/core/proxy/registry" "v2ray.com/core/proxy/registry"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/ray" "v2ray.com/core/transport/ray"
) )
@ -40,8 +39,10 @@ func (this *BlackHole) Dispatch(destination v2net.Destination, payload *alloc.Bu
type Factory struct{} type Factory struct{}
func (this *Factory) StreamCapability() internet.StreamConnectionType { func (this *Factory) StreamCapability() v2net.NetworkList {
return internet.StreamConnectionTypeRawTCP return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
} }
func (this *Factory) Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) { func (this *Factory) Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {

View File

@ -194,8 +194,10 @@ func (this *DokodemoDoor) HandleTCPConnection(conn internet.Connection) {
type Factory struct{} type Factory struct{}
func (this *Factory) StreamCapability() internet.StreamConnectionType { func (this *Factory) StreamCapability() v2net.NetworkList {
return internet.StreamConnectionTypeRawTCP return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
} }
func (this *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { func (this *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {

View File

@ -44,8 +44,8 @@ func TestDokodemoTCP(t *testing.T) {
space, space,
&proxy.OutboundHandlerMeta{ &proxy.OutboundHandlerMeta{
Address: v2net.LocalHostIP, Address: v2net.LocalHostIP,
StreamSettings: &internet.StreamSettings{ StreamSettings: &internet.StreamConfig{
Type: internet.StreamConnectionTypeRawTCP, Network: v2net.Network_RawTCP,
}, },
})) }))
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm) space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm)
@ -65,8 +65,8 @@ func TestDokodemoTCP(t *testing.T) {
}, space, &proxy.InboundHandlerMeta{ }, space, &proxy.InboundHandlerMeta{
Address: v2net.LocalHostIP, Address: v2net.LocalHostIP,
Port: port, Port: port,
StreamSettings: &internet.StreamSettings{ StreamSettings: &internet.StreamConfig{
Type: internet.StreamConnectionTypeRawTCP, Network: v2net.Network_RawTCP,
}}) }})
defer dokodemo.Close() defer dokodemo.Close()
@ -119,8 +119,8 @@ func TestDokodemoUDP(t *testing.T) {
space, space,
&proxy.OutboundHandlerMeta{ &proxy.OutboundHandlerMeta{
Address: v2net.AnyIP, Address: v2net.AnyIP,
StreamSettings: &internet.StreamSettings{ StreamSettings: &internet.StreamConfig{
Type: internet.StreamConnectionTypeRawTCP, Network: v2net.Network_RawTCP,
}})) }}))
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm) space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm)
@ -139,8 +139,8 @@ func TestDokodemoUDP(t *testing.T) {
}, space, &proxy.InboundHandlerMeta{ }, space, &proxy.InboundHandlerMeta{
Address: v2net.LocalHostIP, Address: v2net.LocalHostIP,
Port: port, Port: port,
StreamSettings: &internet.StreamSettings{ StreamSettings: &internet.StreamConfig{
Type: internet.StreamConnectionTypeRawTCP, Network: v2net.Network_RawTCP,
}}) }})
defer dokodemo.Close() defer dokodemo.Close()

View File

@ -129,8 +129,10 @@ func (this *FreedomConnection) Dispatch(destination v2net.Destination, payload *
type FreedomFactory struct{} type FreedomFactory struct{}
func (this *FreedomFactory) StreamCapability() internet.StreamConnectionType { func (this *FreedomFactory) StreamCapability() v2net.NetworkList {
return internet.StreamConnectionTypeRawTCP return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
} }
func (this *FreedomFactory) Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) { func (this *FreedomFactory) Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {

View File

@ -40,8 +40,8 @@ func TestSinglePacket(t *testing.T) {
space, space,
&proxy.OutboundHandlerMeta{ &proxy.OutboundHandlerMeta{
Address: v2net.AnyIP, Address: v2net.AnyIP,
StreamSettings: &internet.StreamSettings{ StreamSettings: &internet.StreamConfig{
Type: internet.StreamConnectionTypeRawTCP, Network: v2net.Network_RawTCP,
}, },
}) })
space.Initialize() space.Initialize()
@ -68,8 +68,8 @@ func TestUnreachableDestination(t *testing.T) {
app.NewSpace(), app.NewSpace(),
&proxy.OutboundHandlerMeta{ &proxy.OutboundHandlerMeta{
Address: v2net.AnyIP, Address: v2net.AnyIP,
StreamSettings: &internet.StreamSettings{ StreamSettings: &internet.StreamConfig{
Type: internet.StreamConnectionTypeRawTCP, Network: v2net.Network_RawTCP,
}, },
}) })
traffic := ray.NewRay() traffic := ray.NewRay()
@ -104,8 +104,8 @@ func TestIPResolution(t *testing.T) {
space, space,
&proxy.OutboundHandlerMeta{ &proxy.OutboundHandlerMeta{
Address: v2net.AnyIP, Address: v2net.AnyIP,
StreamSettings: &internet.StreamSettings{ StreamSettings: &internet.StreamConfig{
Type: internet.StreamConnectionTypeRawTCP, Network: v2net.Network_RawTCP,
}, },
}) })

View File

@ -264,8 +264,10 @@ func (this *Server) handlePlainHTTP(request *http.Request, session *proxy.Sessio
type ServerFactory struct{} type ServerFactory struct{}
func (this *ServerFactory) StreamCapability() internet.StreamConnectionType { func (this *ServerFactory) StreamCapability() v2net.NetworkList {
return internet.StreamConnectionTypeRawTCP return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
} }
func (this *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { func (this *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {

View File

@ -63,8 +63,8 @@ func TestNormalGetRequest(t *testing.T) {
&proxy.InboundHandlerMeta{ &proxy.InboundHandlerMeta{
Address: v2net.LocalHostIP, Address: v2net.LocalHostIP,
Port: port, Port: port,
StreamSettings: &internet.StreamSettings{ StreamSettings: &internet.StreamConfig{
Type: internet.StreamConnectionTypeRawTCP, Network: v2net.Network_RawTCP,
}}) }})
defer httpProxy.Close() defer httpProxy.Close()

View File

@ -27,13 +27,13 @@ type InboundHandlerMeta struct {
Address v2net.Address Address v2net.Address
Port v2net.Port Port v2net.Port
AllowPassiveConnection bool AllowPassiveConnection bool
StreamSettings *internet.StreamSettings StreamSettings *internet.StreamConfig
} }
type OutboundHandlerMeta struct { type OutboundHandlerMeta struct {
Tag string Tag string
Address v2net.Address Address v2net.Address
StreamSettings *internet.StreamSettings StreamSettings *internet.StreamConfig
} }
// An InboundHandler handles inbound network connections to V2Ray. // An InboundHandler handles inbound network connections to V2Ray.

View File

@ -2,16 +2,16 @@ package registry
import ( import (
"v2ray.com/core/app" "v2ray.com/core/app"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
"v2ray.com/core/transport/internet"
) )
type InboundHandlerFactory interface { type InboundHandlerFactory interface {
StreamCapability() internet.StreamConnectionType StreamCapability() v2net.NetworkList
Create(space app.Space, config interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) Create(space app.Space, config interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error)
} }
type OutboundHandlerFactory interface { type OutboundHandlerFactory interface {
StreamCapability() internet.StreamConnectionType StreamCapability() v2net.NetworkList
Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error)
} }

View File

@ -1,6 +1,8 @@
package registry package registry
import ( import (
"errors"
"v2ray.com/core/app" "v2ray.com/core/app"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
@ -46,11 +48,13 @@ func CreateInboundHandler(name string, space app.Space, rawConfig []byte, meta *
return nil, common.ErrObjectNotFound return nil, common.ErrObjectNotFound
} }
if meta.StreamSettings == nil { if meta.StreamSettings == nil {
meta.StreamSettings = &internet.StreamSettings{ meta.StreamSettings = &internet.StreamConfig{
Type: creator.StreamCapability(), Network: creator.StreamCapability().Get(0),
} }
} else { } else {
meta.StreamSettings.Type &= creator.StreamCapability() if !creator.StreamCapability().HasNetwork(meta.StreamSettings.Network) {
return nil, errors.New("Proxy|Registry: Invalid network: " + meta.StreamSettings.Network.String())
}
} }
if len(rawConfig) > 0 { if len(rawConfig) > 0 {
@ -69,11 +73,13 @@ func CreateOutboundHandler(name string, space app.Space, rawConfig []byte, meta
return nil, common.ErrObjectNotFound return nil, common.ErrObjectNotFound
} }
if meta.StreamSettings == nil { if meta.StreamSettings == nil {
meta.StreamSettings = &internet.StreamSettings{ meta.StreamSettings = &internet.StreamConfig{
Type: creator.StreamCapability(), Network: creator.StreamCapability().Get(0),
} }
} else { } else {
meta.StreamSettings.Type &= creator.StreamCapability() if !creator.StreamCapability().HasNetwork(meta.StreamSettings.Network) {
return nil, errors.New("Proxy|Registry: Invalid network: " + meta.StreamSettings.Network.String())
}
} }
if len(rawConfig) > 0 { if len(rawConfig) > 0 {

View File

@ -278,8 +278,10 @@ func (this *Server) handleConnection(conn internet.Connection) {
type ServerFactory struct{} type ServerFactory struct{}
func (this *ServerFactory) StreamCapability() internet.StreamConnectionType { func (this *ServerFactory) StreamCapability() v2net.NetworkList {
return internet.StreamConnectionTypeRawTCP return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
} }
func (this *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { func (this *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {

View File

@ -315,8 +315,10 @@ func (this *Server) transport(reader io.Reader, writer io.Writer, session *proxy
type ServerFactory struct{} type ServerFactory struct{}
func (this *ServerFactory) StreamCapability() internet.StreamConnectionType { func (this *ServerFactory) StreamCapability() v2net.NetworkList {
return internet.StreamConnectionTypeRawTCP return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_RawTCP},
}
} }
func (this *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { func (this *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {

View File

@ -249,8 +249,10 @@ func (this *VMessInboundHandler) HandleConnection(connection internet.Connection
type Factory struct{} type Factory struct{}
func (this *Factory) StreamCapability() internet.StreamConnectionType { func (this *Factory) StreamCapability() v2net.NetworkList {
return internet.StreamConnectionTypeRawTCP | internet.StreamConnectionTypeTCP | internet.StreamConnectionTypeKCP | internet.StreamConnectionTypeWebSocket return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_TCP, v2net.Network_KCP, v2net.Network_WebSocket},
}
} }
func (this *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) { func (this *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {

View File

@ -160,8 +160,10 @@ func (this *VMessOutboundHandler) handleResponse(session *encoding.ClientSession
type Factory struct{} type Factory struct{}
func (this *Factory) StreamCapability() internet.StreamConnectionType { func (this *Factory) StreamCapability() v2net.NetworkList {
return internet.StreamConnectionTypeRawTCP | internet.StreamConnectionTypeTCP | internet.StreamConnectionTypeKCP | internet.StreamConnectionTypeWebSocket return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_TCP, v2net.Network_KCP, v2net.Network_WebSocket},
}
} }
func (this *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) { func (this *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {

View File

@ -13,7 +13,7 @@ import (
type InboundConnectionConfig struct { type InboundConnectionConfig struct {
Port v2net.Port Port v2net.Port
ListenOn v2net.Address ListenOn v2net.Address
StreamSettings *internet.StreamSettings StreamSettings *internet.StreamConfig
Protocol string Protocol string
Settings []byte Settings []byte
AllowPassiveConnection bool AllowPassiveConnection bool
@ -22,7 +22,7 @@ type InboundConnectionConfig struct {
type OutboundConnectionConfig struct { type OutboundConnectionConfig struct {
Protocol string Protocol string
SendThrough v2net.Address SendThrough v2net.Address
StreamSettings *internet.StreamSettings StreamSettings *internet.StreamConfig
Settings []byte Settings []byte
} }
@ -50,7 +50,7 @@ type InboundDetourConfig struct {
ListenOn v2net.Address ListenOn v2net.Address
Tag string Tag string
Allocation *InboundDetourAllocationConfig Allocation *InboundDetourAllocationConfig
StreamSettings *internet.StreamSettings StreamSettings *internet.StreamConfig
Settings []byte Settings []byte
AllowPassiveConnection bool AllowPassiveConnection bool
} }
@ -58,7 +58,7 @@ type InboundDetourConfig struct {
type OutboundDetourConfig struct { type OutboundDetourConfig struct {
Protocol string Protocol string
SendThrough v2net.Address SendThrough v2net.Address
StreamSettings *internet.StreamSettings StreamSettings *internet.StreamConfig
Tag string Tag string
Settings []byte Settings []byte
} }

View File

@ -73,12 +73,12 @@ func (this *Config) UnmarshalJSON(data []byte) error {
func (this *InboundConnectionConfig) UnmarshalJSON(data []byte) error { func (this *InboundConnectionConfig) UnmarshalJSON(data []byte) error {
type JsonConfig struct { type JsonConfig struct {
Port uint16 `json:"port"` Port uint16 `json:"port"`
Listen *v2net.AddressPB `json:"listen"` Listen *v2net.AddressPB `json:"listen"`
Protocol string `json:"protocol"` Protocol string `json:"protocol"`
StreamSetting *internet.StreamSettings `json:"streamSettings"` StreamSetting *internet.StreamConfig `json:"streamSettings"`
Settings json.RawMessage `json:"settings"` Settings json.RawMessage `json:"settings"`
AllowPassive bool `json:"allowPassive"` AllowPassive bool `json:"allowPassive"`
} }
jsonConfig := new(JsonConfig) jsonConfig := new(JsonConfig)
@ -105,10 +105,10 @@ func (this *InboundConnectionConfig) UnmarshalJSON(data []byte) error {
func (this *OutboundConnectionConfig) UnmarshalJSON(data []byte) error { func (this *OutboundConnectionConfig) UnmarshalJSON(data []byte) error {
type JsonConnectionConfig struct { type JsonConnectionConfig struct {
Protocol string `json:"protocol"` Protocol string `json:"protocol"`
SendThrough *v2net.AddressPB `json:"sendThrough"` SendThrough *v2net.AddressPB `json:"sendThrough"`
StreamSetting *internet.StreamSettings `json:"streamSettings"` StreamSetting *internet.StreamConfig `json:"streamSettings"`
Settings json.RawMessage `json:"settings"` 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 {
@ -194,7 +194,7 @@ func (this *InboundDetourConfig) UnmarshalJSON(data []byte) error {
Settings json.RawMessage `json:"settings"` Settings json.RawMessage `json:"settings"`
Tag string `json:"tag"` Tag string `json:"tag"`
Allocation *InboundDetourAllocationConfig `json:"allocate"` Allocation *InboundDetourAllocationConfig `json:"allocate"`
StreamSetting *internet.StreamSettings `json:"streamSettings"` StreamSetting *internet.StreamConfig `json:"streamSettings"`
AllowPassive bool `json:"allowPassive"` AllowPassive bool `json:"allowPassive"`
} }
jsonConfig := new(JsonInboundDetourConfig) jsonConfig := new(JsonInboundDetourConfig)
@ -232,11 +232,11 @@ 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"`
SendThrough *v2net.AddressPB `json:"sendThrough"` SendThrough *v2net.AddressPB `json:"sendThrough"`
Tag string `json:"tag"` Tag string `json:"tag"`
Settings json.RawMessage `json:"settings"` Settings json.RawMessage `json:"settings"`
StreamSetting *internet.StreamSettings `json:"streamSettings"` StreamSetting *internet.StreamConfig `json:"streamSettings"`
} }
jsonConfig := new(JsonOutboundDetourConfig) jsonConfig := new(JsonOutboundDetourConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil { if err := json.Unmarshal(data, jsonConfig); err != nil {

View File

@ -1,26 +1,11 @@
package transport package transport
import ( import (
"v2ray.com/core/transport/internet/kcp" "v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/tcp"
"v2ray.com/core/transport/internet/ws"
) )
// Config for V2Ray transport layer.
type Config struct {
tcpConfig *tcp.Config
kcpConfig kcp.Config
wsConfig *ws.Config
}
// Apply applies this Config. // Apply applies this Config.
func (this *Config) Apply() error { func (this *Config) Apply() error {
if this.tcpConfig != nil { internet.ApplyGlobalNetworkSettings(this.NetworkSettings)
this.tcpConfig.Apply()
}
this.kcpConfig.Apply()
if this.wsConfig != nil {
this.wsConfig.Apply()
}
return nil return nil
} }

67
transport/config.pb.go Normal file
View File

@ -0,0 +1,67 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/transport/config.proto
// DO NOT EDIT!
/*
Package transport is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/transport/config.proto
It has these top-level messages:
Config
*/
package transport
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import v2ray_core_transport_internet "v2ray.com/core/transport/internet"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Config struct {
NetworkSettings []*v2ray_core_transport_internet.NetworkSettings `protobuf:"bytes,1,rep,name=network_settings,json=networkSettings" json:"network_settings,omitempty"`
}
func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Config) GetNetworkSettings() []*v2ray_core_transport_internet.NetworkSettings {
if m != nil {
return m.NetworkSettings
}
return nil
}
func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.transport.Config")
}
func init() { proto.RegisterFile("v2ray.com/core/transport/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 165 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x2d, 0x33, 0x2a, 0x4a,
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x2f, 0x29, 0x4a, 0xcc, 0x2b,
0x2e, 0xc8, 0x2f, 0x2a, 0xd1, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x2b, 0x28, 0xca, 0x2f,
0xc9, 0x17, 0x12, 0x81, 0x29, 0x2b, 0x4a, 0xd5, 0x83, 0x2b, 0x91, 0xd2, 0xc3, 0xa9, 0x39, 0x33,
0xaf, 0x24, 0xb5, 0x28, 0x2f, 0x15, 0xd5, 0x14, 0xa5, 0x64, 0x2e, 0x36, 0x67, 0x30, 0x5f, 0x28,
0x92, 0x4b, 0x20, 0x2f, 0xb5, 0xa4, 0x3c, 0xbf, 0x28, 0x3b, 0xbe, 0x38, 0xb5, 0xa4, 0x24, 0x33,
0x2f, 0xbd, 0x58, 0x82, 0x51, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x4f, 0x0f, 0x9b, 0x55, 0x7a, 0x30,
0x03, 0xf5, 0xfc, 0x20, 0xda, 0x82, 0xa1, 0xba, 0x82, 0xf8, 0xf3, 0x50, 0x05, 0x9c, 0x8c, 0xb8,
0x24, 0x92, 0xf3, 0x73, 0xb1, 0x9a, 0xe2, 0xc4, 0x0d, 0xb1, 0x3e, 0x00, 0xe4, 0x9a, 0x28, 0x4e,
0xb8, 0x78, 0x12, 0x1b, 0xd8, 0x7d, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0c, 0xfb, 0x2d,
0x01, 0x0e, 0x01, 0x00, 0x00,
}

View File

@ -5,6 +5,8 @@ option go_package = "transport";
option java_package = "com.v2ray.core.transport"; option java_package = "com.v2ray.core.transport";
option java_outer_classname = "ConfigProto"; option java_outer_classname = "ConfigProto";
import "v2ray.com/core/transport/internet/config.proto";
message Config { message Config {
repeated v2ray.core.transport.internet.NetworkSettings network_settings = 1;
} }

View File

@ -5,23 +5,57 @@ package transport
import ( import (
"encoding/json" "encoding/json"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/kcp" "v2ray.com/core/transport/internet/kcp"
"v2ray.com/core/transport/internet/tcp" "v2ray.com/core/transport/internet/tcp"
"v2ray.com/core/transport/internet/ws" "v2ray.com/core/transport/internet/ws"
"github.com/golang/protobuf/ptypes"
) )
func (this *Config) UnmarshalJSON(data []byte) error { func (this *Config) UnmarshalJSON(data []byte) error {
type JsonConfig struct { type JsonConfig struct {
TCPConfig *tcp.Config `json:"tcpSettings"` TCPConfig *tcp.Config `json:"tcpSettings"`
KCPConfig kcp.Config `json:"kcpSettings"` KCPConfig *kcp.Config `json:"kcpSettings"`
WSConfig *ws.Config `json:"wsSettings"` WSConfig *ws.Config `json:"wsSettings"`
} }
jsonConfig := &JsonConfig{} jsonConfig := &JsonConfig{}
if err := json.Unmarshal(data, jsonConfig); err != nil { if err := json.Unmarshal(data, jsonConfig); err != nil {
return err return err
} }
this.tcpConfig = jsonConfig.TCPConfig
this.kcpConfig = jsonConfig.KCPConfig if jsonConfig.TCPConfig != nil {
this.wsConfig = jsonConfig.WSConfig any, err := ptypes.MarshalAny(jsonConfig.TCPConfig)
if err != nil {
return err
}
this.NetworkSettings = append(this.NetworkSettings, &internet.NetworkSettings{
Network: v2net.Network_TCP,
Settings: any,
})
}
if jsonConfig.KCPConfig != nil {
any, err := ptypes.MarshalAny(jsonConfig.KCPConfig)
if err != nil {
return err
}
this.NetworkSettings = append(this.NetworkSettings, &internet.NetworkSettings{
Network: v2net.Network_KCP,
Settings: any,
})
}
if jsonConfig.WSConfig != nil {
any, err := ptypes.MarshalAny(jsonConfig.WSConfig)
if err != nil {
return err
}
this.NetworkSettings = append(this.NetworkSettings, &internet.NetworkSettings{
Network: v2net.Network_WebSocket,
Settings: any,
})
}
return nil return nil
} }

View File

@ -7,9 +7,13 @@ Package internet is a generated protocol buffer package.
It is generated from these files: It is generated from these files:
v2ray.com/core/transport/internet/authenticator.proto v2ray.com/core/transport/internet/authenticator.proto
v2ray.com/core/transport/internet/config.proto
It has these top-level messages: It has these top-level messages:
AuthenticatorConfig AuthenticatorConfig
SecuritySettings
NetworkSettings
StreamConfig
*/ */
package internet package internet

View File

@ -0,0 +1,108 @@
package internet
import (
"errors"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
v2tls "v2ray.com/core/transport/internet/tls"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
)
type NetworkConfigCreator func() proto.Message
var (
globalNetworkConfigCreatorCache = make(map[v2net.Network]NetworkConfigCreator)
globalSecurityConfigCreatorCache = make(map[SecurityType]NetworkConfigCreator)
globalNetworkSettings []*NetworkSettings
ErrUnconfiguredNetwork = errors.New("Network config creator not set.")
)
func RegisterNetworkConfigCreator(network v2net.Network, creator NetworkConfigCreator) error {
// TODO: check duplicate
globalNetworkConfigCreatorCache[network] = creator
return nil
}
func CreateNetworkConfig(network v2net.Network) (proto.Message, error) {
creator, ok := globalNetworkConfigCreatorCache[network]
if !ok {
log.Warning("Internet: Network config creator not found: ", network)
return nil, ErrUnconfiguredNetwork
}
return creator(), nil
}
func RegisterSecurityConfigCreator(securityType SecurityType, creator NetworkConfigCreator) error {
globalSecurityConfigCreatorCache[securityType] = creator
return nil
}
func CreateSecurityConfig(securityType SecurityType) (proto.Message, error) {
creator, ok := globalSecurityConfigCreatorCache[securityType]
if !ok {
log.Warning("Internet: Security config creator not found: ", securityType)
return nil, ErrUnconfiguredNetwork
}
return creator(), nil
}
func (this *NetworkSettings) GetTypedSettings() (interface{}, error) {
message, err := CreateNetworkConfig(this.Network)
if err != nil {
return nil, err
}
if err := ptypes.UnmarshalAny(this.Settings, message); err != nil {
return nil, err
}
return message, nil
}
func (this *SecuritySettings) GetTypeSettings() (interface{}, error) {
message, err := CreateSecurityConfig(this.Type)
if err != nil {
return nil, err
}
if err := ptypes.UnmarshalAny(this.Settings, message); err != nil {
return nil, err
}
return message, nil
}
func (this *StreamConfig) GetEffectiveNetworkSettings() (interface{}, error) {
for _, settings := range this.NetworkSettings {
if settings.Network == this.Network {
return settings.GetTypedSettings()
}
}
for _, settings := range globalNetworkSettings {
if settings.Network == this.Network {
return settings.GetTypedSettings()
}
}
return CreateNetworkConfig(this.Network)
}
func (this *StreamConfig) GetEffectiveSecuritySettings() (interface{}, error) {
for _, settings := range this.SecuritySettings {
if settings.Type == this.SecurityType {
return settings.GetTypeSettings()
}
}
return CreateSecurityConfig(this.SecurityType)
}
func ApplyGlobalNetworkSettings(settings []*NetworkSettings) error {
globalNetworkSettings = settings
return nil
}
func init() {
RegisterSecurityConfigCreator(SecurityType_TLS, func() proto.Message {
return new(v2tls.Config)
})
}

View File

@ -0,0 +1,132 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/transport/internet/config.proto
// DO NOT EDIT!
package internet
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import v2ray_core_common_net "v2ray.com/core/common/net"
import google_protobuf "github.com/golang/protobuf/ptypes/any"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type SecurityType int32
const (
SecurityType_None SecurityType = 0
SecurityType_TLS SecurityType = 1
)
var SecurityType_name = map[int32]string{
0: "None",
1: "TLS",
}
var SecurityType_value = map[string]int32{
"None": 0,
"TLS": 1,
}
func (x SecurityType) String() string {
return proto.EnumName(SecurityType_name, int32(x))
}
func (SecurityType) EnumDescriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
type SecuritySettings struct {
Type SecurityType `protobuf:"varint,1,opt,name=type,enum=v2ray.core.transport.internet.SecurityType" json:"type,omitempty"`
Settings *google_protobuf.Any `protobuf:"bytes,2,opt,name=settings" json:"settings,omitempty"`
}
func (m *SecuritySettings) Reset() { *m = SecuritySettings{} }
func (m *SecuritySettings) String() string { return proto.CompactTextString(m) }
func (*SecuritySettings) ProtoMessage() {}
func (*SecuritySettings) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} }
func (m *SecuritySettings) GetSettings() *google_protobuf.Any {
if m != nil {
return m.Settings
}
return nil
}
type NetworkSettings struct {
Network v2ray_core_common_net.Network `protobuf:"varint,1,opt,name=network,enum=v2ray.core.common.net.Network" json:"network,omitempty"`
Settings *google_protobuf.Any `protobuf:"bytes,2,opt,name=settings" json:"settings,omitempty"`
}
func (m *NetworkSettings) Reset() { *m = NetworkSettings{} }
func (m *NetworkSettings) String() string { return proto.CompactTextString(m) }
func (*NetworkSettings) ProtoMessage() {}
func (*NetworkSettings) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} }
func (m *NetworkSettings) GetSettings() *google_protobuf.Any {
if m != nil {
return m.Settings
}
return nil
}
type StreamConfig struct {
Network v2ray_core_common_net.Network `protobuf:"varint,1,opt,name=network,enum=v2ray.core.common.net.Network" json:"network,omitempty"`
NetworkSettings []*NetworkSettings `protobuf:"bytes,2,rep,name=network_settings,json=networkSettings" json:"network_settings,omitempty"`
SecurityType SecurityType `protobuf:"varint,3,opt,name=security_type,json=securityType,enum=v2ray.core.transport.internet.SecurityType" json:"security_type,omitempty"`
SecuritySettings []*SecuritySettings `protobuf:"bytes,4,rep,name=security_settings,json=securitySettings" json:"security_settings,omitempty"`
}
func (m *StreamConfig) Reset() { *m = StreamConfig{} }
func (m *StreamConfig) String() string { return proto.CompactTextString(m) }
func (*StreamConfig) ProtoMessage() {}
func (*StreamConfig) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} }
func (m *StreamConfig) GetNetworkSettings() []*NetworkSettings {
if m != nil {
return m.NetworkSettings
}
return nil
}
func (m *StreamConfig) GetSecuritySettings() []*SecuritySettings {
if m != nil {
return m.SecuritySettings
}
return nil
}
func init() {
proto.RegisterType((*SecuritySettings)(nil), "v2ray.core.transport.internet.SecuritySettings")
proto.RegisterType((*NetworkSettings)(nil), "v2ray.core.transport.internet.NetworkSettings")
proto.RegisterType((*StreamConfig)(nil), "v2ray.core.transport.internet.StreamConfig")
proto.RegisterEnum("v2ray.core.transport.internet.SecurityType", SecurityType_name, SecurityType_value)
}
func init() { proto.RegisterFile("v2ray.com/core/transport/internet/config.proto", fileDescriptor1) }
var fileDescriptor1 = []byte{
// 347 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xa4, 0x91, 0x4f, 0x4b, 0xc3, 0x40,
0x10, 0xc5, 0x4d, 0x5b, 0x6c, 0x99, 0x56, 0x1b, 0x83, 0x87, 0x5a, 0x50, 0xda, 0x5e, 0x0c, 0x8a,
0xbb, 0x12, 0x2f, 0xde, 0x44, 0xbd, 0x4a, 0x91, 0xa4, 0x17, 0x45, 0x28, 0x69, 0x98, 0x86, 0xa0,
0xd9, 0x09, 0x9b, 0xad, 0x92, 0x83, 0x47, 0x3f, 0xa1, 0x5f, 0x48, 0x9a, 0x7f, 0x84, 0x1c, 0xea,
0xbf, 0xdb, 0x6e, 0xf2, 0xe6, 0xcd, 0x6f, 0xdf, 0x03, 0xf6, 0x6a, 0x49, 0x37, 0x61, 0x1e, 0x85,
0xdc, 0x23, 0x89, 0x5c, 0x49, 0x57, 0xc4, 0x11, 0x49, 0xc5, 0x03, 0xa1, 0x50, 0x0a, 0x54, 0xdc,
0x23, 0xb1, 0x0c, 0x7c, 0x16, 0x49, 0x52, 0x64, 0x1c, 0x16, 0x7a, 0x89, 0xac, 0xd4, 0xb2, 0x42,
0x3b, 0x3c, 0xae, 0xd9, 0x79, 0x14, 0x86, 0x24, 0xf8, 0xda, 0x46, 0xa0, 0x7a, 0x23, 0xf9, 0x9c,
0xf9, 0x0c, 0x0f, 0x7c, 0x22, 0xff, 0x05, 0x79, 0x7a, 0x5b, 0xac, 0x96, 0xdc, 0x15, 0x49, 0xf6,
0x6b, 0xf2, 0xa1, 0x81, 0xee, 0xa0, 0xb7, 0x92, 0x81, 0x4a, 0x1c, 0x54, 0x2a, 0x10, 0x7e, 0x6c,
0x5c, 0x41, 0x4b, 0x25, 0x11, 0x0e, 0xb4, 0x91, 0x66, 0xee, 0x5a, 0xa7, 0x6c, 0x23, 0x06, 0x2b,
0xc6, 0x67, 0x49, 0x84, 0x76, 0x3a, 0x68, 0x9c, 0x43, 0x27, 0xce, 0xcd, 0x06, 0x8d, 0x91, 0x66,
0x76, 0xad, 0x7d, 0x96, 0x31, 0xb0, 0x82, 0x81, 0x5d, 0x8b, 0xc4, 0x2e, 0x55, 0x93, 0x77, 0xe8,
0x4f, 0x33, 0xe6, 0x92, 0xe2, 0x12, 0xda, 0xf9, 0x33, 0x72, 0x90, 0xa3, 0x2a, 0x48, 0xf6, 0x58,
0xb6, 0x06, 0xc8, 0x07, 0xed, 0x42, 0xfe, 0x87, 0xf5, 0x9f, 0x0d, 0xe8, 0x39, 0x4a, 0xa2, 0x1b,
0xde, 0xa6, 0x05, 0xfc, 0x63, 0xf9, 0x03, 0xe8, 0xf9, 0x71, 0x5e, 0x81, 0x68, 0x9a, 0x5d, 0x8b,
0x7d, 0x13, 0x64, 0x2d, 0x00, 0xbb, 0x2f, 0x6a, 0x89, 0xdc, 0xc3, 0x4e, 0x9c, 0x87, 0x3d, 0x4f,
0x0b, 0x6a, 0xfe, 0xbe, 0xa0, 0x5e, 0x5c, 0xb9, 0x19, 0x4f, 0xb0, 0x57, 0x3a, 0x96, 0xb4, 0xad,
0x94, 0x96, 0xff, 0xd0, 0xb5, 0xc4, 0xd5, 0xe3, 0xda, 0x97, 0x93, 0x31, 0xf4, 0xaa, 0xbb, 0x8d,
0x0e, 0xb4, 0xa6, 0x24, 0x50, 0xdf, 0x32, 0xda, 0xd0, 0x9c, 0xdd, 0x39, 0xba, 0x76, 0x73, 0x06,
0x63, 0x8f, 0xc2, 0xcd, 0xab, 0x1e, 0x3b, 0xc5, 0x69, 0xb1, 0x9d, 0xf6, 0x77, 0xf1, 0x15, 0x00,
0x00, 0xff, 0xff, 0xb2, 0x2e, 0x36, 0x52, 0x4a, 0x03, 0x00, 0x00,
}

View File

@ -0,0 +1,31 @@
syntax = "proto3";
package v2ray.core.transport.internet;
option go_package = "internet";
option java_package = "com.v2ray.core.transport.internet";
import "v2ray.com/core/common/net/network.proto";
import "google/protobuf/any.proto";
enum SecurityType {
None = 0;
TLS = 1;
}
message SecuritySettings {
SecurityType type = 1;
google.protobuf.Any settings = 2;
}
message NetworkSettings {
v2ray.core.common.net.Network network = 1;
google.protobuf.Any settings = 2;
}
message StreamConfig {
v2ray.core.common.net.Network network = 1;
repeated NetworkSettings network_settings = 2;
SecurityType security_type = 3;
repeated SecuritySettings security_settings = 4;
}

View File

@ -1,7 +1,6 @@
package internet package internet
import ( import (
"crypto/tls"
"net" "net"
) )
@ -12,56 +11,6 @@ type Reusable interface {
SetReusable(reuse bool) SetReusable(reuse bool)
} }
type StreamConnectionType int
const (
StreamConnectionTypeRawTCP StreamConnectionType = 1
StreamConnectionTypeTCP StreamConnectionType = 2
StreamConnectionTypeKCP StreamConnectionType = 4
StreamConnectionTypeWebSocket StreamConnectionType = 8
)
type StreamSecurityType int
const (
StreamSecurityTypeNone StreamSecurityType = 0
StreamSecurityTypeTLS StreamSecurityType = 1
)
var (
globalSessionCache = tls.NewLRUClientSessionCache(128)
)
type TLSSettings struct {
AllowInsecure bool
Certs []tls.Certificate
}
func (this *TLSSettings) GetTLSConfig() *tls.Config {
config := &tls.Config{
ClientSessionCache: globalSessionCache,
}
if this == nil {
return config
}
config.InsecureSkipVerify = this.AllowInsecure
config.Certificates = this.Certs
config.BuildNameToCertificate()
return config
}
type StreamSettings struct {
Type StreamConnectionType
Security StreamSecurityType
TLSSettings *TLSSettings
}
func (this *StreamSettings) IsCapableOf(streamType StreamConnectionType) bool {
return (this.Type & streamType) == streamType
}
type Connection interface { type Connection interface {
net.Conn net.Conn
Reusable Reusable

View File

@ -3,65 +3,42 @@
package internet package internet
import ( import (
"crypto/tls"
"encoding/json" "encoding/json"
"errors"
"strings" "strings"
"errors"
"github.com/golang/protobuf/ptypes"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
v2tls "v2ray.com/core/transport/internet/tls"
) )
func (this *TLSSettings) UnmarshalJSON(data []byte) error { func (this *StreamConfig) UnmarshalJSON(data []byte) error {
type JSONCertConfig struct {
CertFile string `json:"certificateFile"`
KeyFile string `json:"keyFile"`
}
type JSONConfig struct { type JSONConfig struct {
Insecure bool `json:"allowInsecure"` Network *v2net.Network `json:"network"`
Certs []*JSONCertConfig `json:"certificates"` Security string `json:"security"`
TLSSettings *v2tls.Config `json:"tlsSettings"`
} }
this.Network = v2net.Network_RawTCP
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.Certs = make([]tls.Certificate, len(jsonConfig.Certs)) if jsonConfig.Network != nil {
for idx, certConf := range jsonConfig.Certs { this.Network = *jsonConfig.Network
cert, err := tls.LoadX509KeyPair(certConf.CertFile, certConf.KeyFile)
if err != nil {
return errors.New("Internet|TLS: Failed to load certificate file: " + err.Error())
}
this.Certs[idx] = cert
} }
this.AllowInsecure = jsonConfig.Insecure this.SecurityType = SecurityType_None
return nil
}
func (this *StreamSettings) UnmarshalJSON(data []byte) error {
type JSONConfig struct {
Network v2net.NetworkList `json:"network"`
Security string `json:"security"`
TLSSettings *TLSSettings `json:"tlsSettings"`
}
this.Type = StreamConnectionTypeRawTCP
jsonConfig := new(JSONConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil {
return err
}
if jsonConfig.Network.HasNetwork(v2net.Network_KCP) {
this.Type |= StreamConnectionTypeKCP
}
if jsonConfig.Network.HasNetwork(v2net.Network_WebSocket) {
this.Type |= StreamConnectionTypeWebSocket
}
if jsonConfig.Network.HasNetwork(v2net.Network_TCP) {
this.Type |= StreamConnectionTypeTCP
}
this.Security = StreamSecurityTypeNone
if strings.ToLower(jsonConfig.Security) == "tls" { if strings.ToLower(jsonConfig.Security) == "tls" {
this.Security = StreamSecurityTypeTLS this.SecurityType = SecurityType_TLS
} }
if jsonConfig.TLSSettings != nil { if jsonConfig.TLSSettings != nil {
this.TLSSettings = jsonConfig.TLSSettings anyTLSSettings, err := ptypes.MarshalAny(jsonConfig.TLSSettings)
if err != nil {
return errors.New("Internet: Failed to parse TLS settings: " + err.Error())
}
this.SecuritySettings = append(this.SecuritySettings, &SecuritySettings{
Type: SecurityType_TLS,
Settings: anyTLSSettings,
})
} }
return nil return nil
} }

View File

@ -12,7 +12,7 @@ var (
) )
type DialerOptions struct { type DialerOptions struct {
Stream *StreamSettings Stream *StreamConfig
} }
type Dialer func(src v2net.Address, dest v2net.Destination, options DialerOptions) (Connection, error) type Dialer func(src v2net.Address, dest v2net.Destination, options DialerOptions) (Connection, error)
@ -25,7 +25,7 @@ var (
WSDialer Dialer WSDialer Dialer
) )
func Dial(src v2net.Address, dest v2net.Destination, settings *StreamSettings) (Connection, error) { func Dial(src v2net.Address, dest v2net.Destination, settings *StreamConfig) (Connection, error) {
var connection Connection var connection Connection
var err error var err error
@ -33,16 +33,16 @@ func Dial(src v2net.Address, dest v2net.Destination, settings *StreamSettings) (
Stream: settings, Stream: settings,
} }
if dest.Network == v2net.Network_TCP { if dest.Network == v2net.Network_TCP {
switch { switch settings.Network {
case settings.IsCapableOf(StreamConnectionTypeTCP): case v2net.Network_TCP:
connection, err = TCPDialer(src, dest, dialerOptions) connection, err = TCPDialer(src, dest, dialerOptions)
case settings.IsCapableOf(StreamConnectionTypeKCP): case v2net.Network_KCP:
connection, err = KCPDialer(src, dest, dialerOptions) connection, err = KCPDialer(src, dest, dialerOptions)
case settings.IsCapableOf(StreamConnectionTypeWebSocket): case v2net.Network_WebSocket:
connection, err = WSDialer(src, dest, dialerOptions) connection, err = WSDialer(src, dest, dialerOptions)
// This check has to be the last one. // This check has to be the last one.
case settings.IsCapableOf(StreamConnectionTypeRawTCP): case v2net.Network_RawTCP:
connection, err = RawTCPDialer(src, dest, dialerOptions) connection, err = RawTCPDialer(src, dest, dialerOptions)
default: default:
return nil, ErrUnsupportedStreamType return nil, ErrUnsupportedStreamType

View File

@ -1,7 +1,10 @@
package kcp package kcp
import ( import (
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
"github.com/golang/protobuf/proto"
) )
func (this *MTU) GetValue() uint32 { func (this *MTU) GetValue() uint32 {
@ -46,10 +49,6 @@ func (this *ReadBuffer) GetSize() uint32 {
return this.Size return this.Size
} }
func (this *Config) Apply() {
effectiveConfig = *this
}
func (this *Config) GetAuthenticator() (internet.Authenticator, error) { func (this *Config) GetAuthenticator() (internet.Authenticator, error) {
auth := NewSimpleAuthenticator() auth := NewSimpleAuthenticator()
if this.HeaderConfig != nil { if this.HeaderConfig != nil {
@ -86,6 +85,8 @@ func (this *Config) GetReceivingBufferSize() uint32 {
return this.GetReceivingInFlightSize() + this.ReadBuffer.GetSize()/this.Mtu.GetValue() return this.GetReceivingInFlightSize() + this.ReadBuffer.GetSize()/this.Mtu.GetValue()
} }
var ( func init() {
effectiveConfig Config internet.RegisterNetworkConfigCreator(v2net.Network_KCP, func() proto.Message {
) return new(Config)
})
}

View File

@ -129,6 +129,7 @@ type Connection struct {
since int64 since int64
dataInputCond *sync.Cond dataInputCond *sync.Cond
dataOutputCond *sync.Cond dataOutputCond *sync.Cond
Config *Config
conv uint16 conv uint16
state State state State
@ -149,7 +150,7 @@ type Connection struct {
} }
// NewConnection create a new KCP connection between local and remote. // NewConnection create a new KCP connection between local and remote.
func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr, remote *net.UDPAddr, block internet.Authenticator) *Connection { func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr, remote *net.UDPAddr, block internet.Authenticator, config *Config) *Connection {
log.Info("KCP|Connection: creating connection ", conv) log.Info("KCP|Connection: creating connection ", conv)
conn := new(Connection) conn := new(Connection)
@ -160,10 +161,12 @@ func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr,
conn.since = nowMillisec() conn.since = nowMillisec()
conn.dataInputCond = sync.NewCond(new(sync.Mutex)) conn.dataInputCond = sync.NewCond(new(sync.Mutex))
conn.dataOutputCond = sync.NewCond(new(sync.Mutex)) conn.dataOutputCond = sync.NewCond(new(sync.Mutex))
conn.Config = config
authWriter := &AuthenticationWriter{ authWriter := &AuthenticationWriter{
Authenticator: block, Authenticator: block,
Writer: writerCloser, Writer: writerCloser,
Config: config,
} }
conn.conv = conv conn.conv = conv
conn.output = NewSegmentWriter(authWriter) conn.output = NewSegmentWriter(authWriter)
@ -171,12 +174,12 @@ func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr,
conn.mss = authWriter.Mtu() - DataSegmentOverhead conn.mss = authWriter.Mtu() - DataSegmentOverhead
conn.roundTrip = &RoundTripInfo{ conn.roundTrip = &RoundTripInfo{
rto: 100, rto: 100,
minRtt: effectiveConfig.Tti.GetValue(), minRtt: config.Tti.GetValue(),
} }
conn.interval = effectiveConfig.Tti.GetValue() conn.interval = config.Tti.GetValue()
conn.receivingWorker = NewReceivingWorker(conn) conn.receivingWorker = NewReceivingWorker(conn)
conn.fastresend = 2 conn.fastresend = 2
conn.congestionControl = effectiveConfig.Congestion conn.congestionControl = config.Congestion
conn.sendingWorker = NewSendingWorker(conn) conn.sendingWorker = NewSendingWorker(conn)
go conn.updateTask() go conn.updateTask()
@ -366,7 +369,7 @@ func (this *Connection) updateTask() {
for this.State() != StateTerminated { for this.State() != StateTerminated {
this.flush() this.flush()
interval := time.Duration(effectiveConfig.Tti.GetValue()) * time.Millisecond interval := time.Duration(this.Config.Tti.GetValue()) * time.Millisecond
if this.State() == StateTerminating { if this.State() == StateTerminating {
interval = time.Second interval = time.Second
} }

View File

@ -27,7 +27,7 @@ func (this *NoOpWriteCloser) Close() error {
func TestConnectionReadTimeout(t *testing.T) { func TestConnectionReadTimeout(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
conn := NewConnection(1, &NoOpWriteCloser{}, nil, nil, NewSimpleAuthenticator()) conn := NewConnection(1, &NoOpWriteCloser{}, nil, nil, NewSimpleAuthenticator(), &Config{})
conn.SetReadDeadline(time.Now().Add(time.Second)) conn.SetReadDeadline(time.Now().Add(time.Second))
b := make([]byte, 1024) b := make([]byte, 1024)
@ -44,10 +44,10 @@ func TestConnectionReadWrite(t *testing.T) {
auth := internet.NewAuthenticatorChain(srtp.SRTPFactory{}.Create(nil), NewSimpleAuthenticator()) auth := internet.NewAuthenticatorChain(srtp.SRTPFactory{}.Create(nil), NewSimpleAuthenticator())
connClient := NewConnection(1, upWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, auth) connClient := NewConnection(1, upWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, auth, &Config{})
connClient.FetchInputFrom(downReader) connClient.FetchInputFrom(downReader)
connServer := NewConnection(1, downWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, auth) connServer := NewConnection(1, downWriter, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 2}, &net.UDPAddr{IP: v2net.LocalHostIP.IP(), Port: 1}, auth, &Config{})
connServer.FetchInputFrom(upReader) connServer.FetchInputFrom(upReader)
totalWritten := 1024 * 1024 totalWritten := 1024 * 1024

View File

@ -25,20 +25,32 @@ func DialKCP(src v2net.Address, dest v2net.Destination, options internet.DialerO
return nil, err return nil, err
} }
cpip, err := effectiveConfig.GetAuthenticator() networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
log.Error("KCP|Dialer: Failed to get KCP settings: ", err)
return nil, err
}
kcpSettings := networkSettings.(*Config)
cpip, err := kcpSettings.GetAuthenticator()
if err != nil { if err != nil {
log.Error("KCP|Dialer: Failed to create authenticator: ", err) log.Error("KCP|Dialer: Failed to create authenticator: ", err)
return nil, err return nil, err
} }
conv := uint16(atomic.AddUint32(&globalConv, 1)) conv := uint16(atomic.AddUint32(&globalConv, 1))
session := NewConnection(conv, conn, conn.LocalAddr().(*net.UDPAddr), conn.RemoteAddr().(*net.UDPAddr), cpip) session := NewConnection(conv, conn, conn.LocalAddr().(*net.UDPAddr), conn.RemoteAddr().(*net.UDPAddr), cpip, kcpSettings)
session.FetchInputFrom(conn) session.FetchInputFrom(conn)
var iConn internet.Connection var iConn internet.Connection
iConn = session iConn = session
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS { if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
config := options.Stream.TLSSettings.GetTLSConfig() securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("KCP|Dialer: Failed to apply TLS config: ", err)
return nil, err
}
config := securitySettings.(*v2tls.Config).GetTLSConfig()
if dest.Address.Family().IsDomain() { if dest.Address.Family().IsDomain() {
config.ServerName = dest.Address.Domain() config.ServerName = dest.Address.Domain()
} }

View File

@ -12,12 +12,28 @@ import (
"v2ray.com/core/testing/assert" "v2ray.com/core/testing/assert"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
. "v2ray.com/core/transport/internet/kcp" . "v2ray.com/core/transport/internet/kcp"
"github.com/golang/protobuf/ptypes"
) )
func TestDialAndListen(t *testing.T) { func TestDialAndListen(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
listerner, err := NewListener(v2net.LocalHostIP, v2net.Port(0), internet.ListenOptions{}) kcpSettings := new(Config)
anySettings, err := ptypes.MarshalAny(kcpSettings)
assert.Error(err).IsNil()
listerner, err := NewListener(v2net.LocalHostIP, v2net.Port(0), internet.ListenOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_KCP,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_KCP,
Settings: anySettings,
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
port := v2net.Port(listerner.Addr().(*net.UDPAddr).Port) port := v2net.Port(listerner.Addr().(*net.UDPAddr).Port)
@ -46,7 +62,17 @@ func TestDialAndListen(t *testing.T) {
wg := new(sync.WaitGroup) wg := new(sync.WaitGroup)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
clientConn, err := DialKCP(v2net.LocalHostIP, v2net.UDPDestination(v2net.LocalHostIP, port), internet.DialerOptions{}) clientConn, err := DialKCP(v2net.LocalHostIP, v2net.UDPDestination(v2net.LocalHostIP, port), internet.DialerOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_KCP,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_KCP,
Settings: anySettings,
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
wg.Add(1) wg.Add(1)

View File

@ -25,10 +25,18 @@ type Listener struct {
awaitingConns chan *Connection awaitingConns chan *Connection
hub *udp.UDPHub hub *udp.UDPHub
tlsConfig *tls.Config tlsConfig *tls.Config
config *Config
} }
func NewListener(address v2net.Address, port v2net.Port, options internet.ListenOptions) (*Listener, error) { func NewListener(address v2net.Address, port v2net.Port, options internet.ListenOptions) (*Listener, error) {
auth, err := effectiveConfig.GetAuthenticator() networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
log.Error("KCP|Listener: Failed to get KCP settings: ", err)
return nil, err
}
kcpSettings := networkSettings.(*Config)
auth, err := kcpSettings.GetAuthenticator()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -37,9 +45,15 @@ func NewListener(address v2net.Address, port v2net.Port, options internet.Listen
sessions: make(map[string]*Connection), sessions: make(map[string]*Connection),
awaitingConns: make(chan *Connection, 64), awaitingConns: make(chan *Connection, 64),
running: true, running: true,
config: kcpSettings,
} }
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS { if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
l.tlsConfig = options.Stream.TLSSettings.GetTLSConfig() securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("KCP|Listener: Failed to apply TLS config: ", err)
return nil, err
}
l.tlsConfig = securitySettings.(*v2tls.Config).GetTLSConfig()
} }
hub, err := udp.ListenUDP(address, port, udp.ListenOption{Callback: l.OnReceive}) hub, err := udp.ListenUDP(address, port, udp.ListenOption{Callback: l.OnReceive})
if err != nil { if err != nil {
@ -89,11 +103,11 @@ func (this *Listener) OnReceive(payload *alloc.Buffer, session *proxy.SessionInf
IP: src.Address.IP(), IP: src.Address.IP(),
Port: int(src.Port), Port: int(src.Port),
} }
auth, err := effectiveConfig.GetAuthenticator() auth, err := this.config.GetAuthenticator()
if err != nil { if err != nil {
log.Error("KCP|Listener: Failed to create authenticator: ", err) log.Error("KCP|Listener: Failed to create authenticator: ", err)
} }
conn = NewConnection(conv, writer, this.Addr().(*net.UDPAddr), srcAddr, auth) conn = NewConnection(conv, writer, this.Addr().(*net.UDPAddr), srcAddr, auth, this.config)
select { select {
case this.awaitingConns <- conn: case this.awaitingConns <- conn:
case <-time.After(time.Second * 5): case <-time.After(time.Second * 5):

View File

@ -62,6 +62,7 @@ func (this *BufferedSegmentWriter) Flush() {
type AuthenticationWriter struct { type AuthenticationWriter struct {
Authenticator internet.Authenticator Authenticator internet.Authenticator
Writer io.Writer Writer io.Writer
Config *Config
} }
func (this *AuthenticationWriter) Write(payload *alloc.Buffer) error { func (this *AuthenticationWriter) Write(payload *alloc.Buffer) error {
@ -75,5 +76,5 @@ func (this *AuthenticationWriter) Write(payload *alloc.Buffer) error {
func (this *AuthenticationWriter) Release() {} func (this *AuthenticationWriter) Release() {}
func (this *AuthenticationWriter) Mtu() uint32 { func (this *AuthenticationWriter) Mtu() uint32 {
return effectiveConfig.Mtu.GetValue() - uint32(this.Authenticator.Overhead()) return this.Config.Mtu.GetValue() - uint32(this.Authenticator.Overhead())
} }

View File

@ -124,8 +124,8 @@ type ReceivingWorker struct {
func NewReceivingWorker(kcp *Connection) *ReceivingWorker { func NewReceivingWorker(kcp *Connection) *ReceivingWorker {
worker := &ReceivingWorker{ worker := &ReceivingWorker{
conn: kcp, conn: kcp,
window: NewReceivingWindow(effectiveConfig.GetReceivingBufferSize()), window: NewReceivingWindow(kcp.Config.GetReceivingBufferSize()),
windowSize: effectiveConfig.GetReceivingInFlightSize(), windowSize: kcp.Config.GetReceivingInFlightSize(),
} }
worker.acklist = NewAckList(worker) worker.acklist = NewAckList(worker)
return worker return worker

View File

@ -185,9 +185,9 @@ func NewSendingWorker(kcp *Connection) *SendingWorker {
conn: kcp, conn: kcp,
fastResend: 2, fastResend: 2,
remoteNextNumber: 32, remoteNextNumber: 32,
controlWindow: effectiveConfig.GetSendingInFlightSize(), controlWindow: kcp.Config.GetSendingInFlightSize(),
} }
worker.window = NewSendingWindow(effectiveConfig.GetSendingBufferSize(), worker, worker.OnPacketLoss) worker.window = NewSendingWindow(kcp.Config.GetSendingBufferSize(), worker, worker.OnPacketLoss)
return worker return worker
} }
@ -291,7 +291,7 @@ func (this *SendingWorker) Write(seg Segment) {
} }
func (this *SendingWorker) OnPacketLoss(lossRate uint32) { func (this *SendingWorker) OnPacketLoss(lossRate uint32) {
if !effectiveConfig.Congestion || this.conn.roundTrip.Timeout() == 0 { if !this.conn.Config.Congestion || this.conn.roundTrip.Timeout() == 0 {
return return
} }
@ -303,8 +303,8 @@ func (this *SendingWorker) OnPacketLoss(lossRate uint32) {
if this.controlWindow < 16 { if this.controlWindow < 16 {
this.controlWindow = 16 this.controlWindow = 16
} }
if this.controlWindow > 2*effectiveConfig.GetSendingInFlightSize() { if this.controlWindow > 2*this.conn.Config.GetSendingInFlightSize() {
this.controlWindow = 2 * effectiveConfig.GetSendingInFlightSize() this.controlWindow = 2 * this.conn.Config.GetSendingInFlightSize()
} }
} }
@ -312,11 +312,11 @@ func (this *SendingWorker) Flush(current uint32) {
this.Lock() this.Lock()
defer this.Unlock() defer this.Unlock()
cwnd := this.firstUnacknowledged + effectiveConfig.GetSendingInFlightSize() cwnd := this.firstUnacknowledged + this.conn.Config.GetSendingInFlightSize()
if cwnd > this.remoteNextNumber { if cwnd > this.remoteNextNumber {
cwnd = this.remoteNextNumber cwnd = this.remoteNextNumber
} }
if effectiveConfig.Congestion && cwnd > this.firstUnacknowledged+this.controlWindow { if this.conn.Config.Congestion && cwnd > this.firstUnacknowledged+this.controlWindow {
cwnd = this.firstUnacknowledged + this.controlWindow cwnd = this.firstUnacknowledged + this.controlWindow
} }

View File

@ -1,15 +1,14 @@
package tcp package tcp
type Config struct { import (
ConnectionReuse bool v2net "v2ray.com/core/common/net"
} "v2ray.com/core/transport/internet"
func (this *Config) Apply() { "github.com/golang/protobuf/proto"
effectiveConfig = this
}
var (
effectiveConfig = &Config{
ConnectionReuse: true,
}
) )
func init() {
internet.RegisterNetworkConfigCreator(v2net.Network_TCP, func() proto.Message {
return new(Config)
})
}

View File

@ -0,0 +1,58 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/transport/internet/tcp/config.proto
// DO NOT EDIT!
/*
Package tcp is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/transport/internet/tcp/config.proto
It has these top-level messages:
Config
*/
package tcp
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Config struct {
ConnectionReuse bool `protobuf:"varint,1,opt,name=connection_reuse,json=connectionReuse" json:"connection_reuse,omitempty"`
}
func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.transport.internet.tcp.Config")
}
func init() { proto.RegisterFile("v2ray.com/core/transport/internet/tcp/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 158 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x8e, 0xb1, 0x0a, 0xc2, 0x50,
0x0c, 0x45, 0x29, 0x42, 0x91, 0xe7, 0xa0, 0x74, 0x72, 0x54, 0x41, 0xd0, 0x25, 0x0f, 0xda, 0xc9,
0xb5, 0xfe, 0x80, 0x74, 0x74, 0x91, 0x1a, 0xa2, 0x74, 0x68, 0x12, 0xd2, 0x28, 0xf8, 0xf7, 0xd2,
0x4a, 0x75, 0x74, 0xbd, 0xdc, 0x73, 0x38, 0x21, 0x7f, 0xe6, 0x56, 0xbf, 0x00, 0xa5, 0x8d, 0x28,
0x46, 0xd1, 0xad, 0xe6, 0x4e, 0xc5, 0x3c, 0x36, 0xec, 0x64, 0x4c, 0x1e, 0x1d, 0x35, 0xa2, 0xf0,
0xad, 0xb9, 0x83, 0x9a, 0xb8, 0x64, 0xeb, 0x91, 0x31, 0x82, 0xef, 0x1f, 0xc6, 0x3f, 0x38, 0xea,
0xa6, 0x08, 0xe9, 0x71, 0x40, 0xb2, 0x7d, 0x58, 0xa0, 0x30, 0x13, 0x7a, 0x23, 0x7c, 0x31, 0x7a,
0x74, 0xb4, 0x4c, 0x56, 0xc9, 0x6e, 0x5a, 0xcd, 0x7f, 0x7b, 0xd5, 0xcf, 0xe5, 0x21, 0x6c, 0x51,
0x5a, 0xf8, 0x6b, 0x2f, 0x67, 0x1f, 0xf7, 0xa9, 0xaf, 0x39, 0x4f, 0x1c, 0xf5, 0x9a, 0x0e, 0x65,
0xc5, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x00, 0xa0, 0xa8, 0x3f, 0xcf, 0x00, 0x00, 0x00,
}

View File

@ -0,0 +1,10 @@
syntax = "proto3";
package v2ray.core.transport.internet.tcp;
option go_package = "tcp";
option java_package = "com.v2ray.core.transport.internet.tcp";
option java_outer_classname = "ConfigProto";
message Config {
bool connection_reuse = 1;
}

View File

@ -31,14 +31,16 @@ type Connection struct {
conn net.Conn conn net.Conn
listener ConnectionManager listener ConnectionManager
reusable bool reusable bool
config *Config
} }
func NewConnection(dest string, conn net.Conn, manager ConnectionManager) *Connection { func NewConnection(dest string, conn net.Conn, manager ConnectionManager, config *Config) *Connection {
return &Connection{ return &Connection{
dest: dest, dest: dest,
conn: conn, conn: conn,
listener: manager, listener: manager,
reusable: effectiveConfig.ConnectionReuse, reusable: config.ConnectionReuse,
config: config,
} }
} }
@ -91,7 +93,7 @@ func (this *Connection) SetWriteDeadline(t time.Time) error {
} }
func (this *Connection) SetReusable(reusable bool) { func (this *Connection) SetReusable(reusable bool) {
if !effectiveConfig.ConnectionReuse { if !this.config.ConnectionReuse {
return return
} }
this.reusable = reusable this.reusable = reusable

View File

@ -7,6 +7,7 @@ import (
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
v2tls "v2ray.com/core/transport/internet/tls"
) )
var ( var (
@ -18,9 +19,15 @@ func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOpti
if src == nil { if src == nil {
src = v2net.AnyIP src = v2net.AnyIP
} }
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
return nil, err
}
tcpSettings := networkSettings.(*Config)
id := src.String() + "-" + dest.NetAddr() id := src.String() + "-" + dest.NetAddr()
var conn net.Conn var conn net.Conn
if dest.Network == v2net.Network_TCP && effectiveConfig.ConnectionReuse { if dest.Network == v2net.Network_TCP && tcpSettings.ConnectionReuse {
conn = globalCache.Get(id) conn = globalCache.Get(id)
} }
if conn == nil { if conn == nil {
@ -30,14 +37,19 @@ func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOpti
return nil, err return nil, err
} }
} }
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS { if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
config := options.Stream.TLSSettings.GetTLSConfig() securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("TCP: Failed to apply TLS config: ", err)
return nil, err
}
config := securitySettings.(*v2tls.Config).GetTLSConfig()
if dest.Address.Family().IsDomain() { if dest.Address.Family().IsDomain() {
config.ServerName = dest.Address.Domain() config.ServerName = dest.Address.Domain()
} }
conn = tls.Client(conn, config) conn = tls.Client(conn, config)
} }
return NewConnection(id, conn, globalCache), nil return NewConnection(id, conn, globalCache, tcpSettings), nil
} }
func DialRaw(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (internet.Connection, error) { func DialRaw(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (internet.Connection, error) {

View File

@ -7,8 +7,10 @@ import (
"sync" "sync"
"time" "time"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
v2tls "v2ray.com/core/transport/internet/tls"
) )
var ( var (
@ -26,6 +28,7 @@ type TCPListener struct {
listener *net.TCPListener listener *net.TCPListener
awaitingConns chan *ConnectionWithError awaitingConns chan *ConnectionWithError
tlsConfig *tls.Config tlsConfig *tls.Config
config *Config
} }
func ListenTCP(address v2net.Address, port v2net.Port, options internet.ListenOptions) (internet.Listener, error) { func ListenTCP(address v2net.Address, port v2net.Port, options internet.ListenOptions) (internet.Listener, error) {
@ -36,13 +39,25 @@ func ListenTCP(address v2net.Address, port v2net.Port, options internet.ListenOp
if err != nil { if err != nil {
return nil, err return nil, err
} }
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
return nil, err
}
tcpSettings := networkSettings.(*Config)
l := &TCPListener{ l := &TCPListener{
acccepting: true, acccepting: true,
listener: listener, listener: listener,
awaitingConns: make(chan *ConnectionWithError, 32), awaitingConns: make(chan *ConnectionWithError, 32),
config: tcpSettings,
} }
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS { if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
l.tlsConfig = options.Stream.TLSSettings.GetTLSConfig() securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("TCP: Failed to apply TLS config: ", err)
return nil, err
}
l.tlsConfig = securitySettings.(*v2tls.Config).GetTLSConfig()
} }
go l.KeepAccepting() go l.KeepAccepting()
return l, nil return l, nil
@ -62,7 +77,7 @@ func (this *TCPListener) Accept() (internet.Connection, error) {
if this.tlsConfig != nil { if this.tlsConfig != nil {
conn = tls.Server(conn, this.tlsConfig) conn = tls.Server(conn, this.tlsConfig)
} }
return NewConnection("", conn, this), nil return NewConnection("", conn, this, this.config), nil
case <-time.After(time.Second * 2): case <-time.After(time.Second * 2):
} }
} }

View File

@ -20,7 +20,7 @@ var (
type ListenFunc func(address v2net.Address, port v2net.Port, options ListenOptions) (Listener, error) type ListenFunc func(address v2net.Address, port v2net.Port, options ListenOptions) (Listener, error)
type ListenOptions struct { type ListenOptions struct {
Stream *StreamSettings Stream *StreamConfig
} }
type Listener interface { type Listener interface {
@ -36,23 +36,23 @@ type TCPHub struct {
accepting bool accepting bool
} }
func ListenTCP(address v2net.Address, port v2net.Port, callback ConnectionHandler, settings *StreamSettings) (*TCPHub, error) { func ListenTCP(address v2net.Address, port v2net.Port, callback ConnectionHandler, settings *StreamConfig) (*TCPHub, error) {
var listener Listener var listener Listener
var err error var err error
options := ListenOptions{ options := ListenOptions{
Stream: settings, Stream: settings,
} }
switch { switch settings.Network {
case settings.IsCapableOf(StreamConnectionTypeTCP): case v2net.Network_TCP:
listener, err = TCPListenFunc(address, port, options) listener, err = TCPListenFunc(address, port, options)
case settings.IsCapableOf(StreamConnectionTypeKCP): case v2net.Network_KCP:
listener, err = KCPListenFunc(address, port, options) listener, err = KCPListenFunc(address, port, options)
case settings.IsCapableOf(StreamConnectionTypeWebSocket): case v2net.Network_WebSocket:
listener, err = WSListenFunc(address, port, options) listener, err = WSListenFunc(address, port, options)
case settings.IsCapableOf(StreamConnectionTypeRawTCP): case v2net.Network_RawTCP:
listener, err = RawTCPListenFunc(address, port, options) listener, err = RawTCPListenFunc(address, port, options)
default: default:
log.Error("Internet|Listener: Unknown stream type: ", settings.Type) log.Error("Internet|Listener: Unknown stream type: ", settings.Network)
err = ErrUnsupportedStreamType err = ErrUnsupportedStreamType
} }

View File

@ -0,0 +1,39 @@
package tls
import (
"crypto/tls"
"v2ray.com/core/common/log"
)
var (
globalSessionCache = tls.NewLRUClientSessionCache(128)
)
func (this *Config) BuildCertificates() []tls.Certificate {
certs := make([]tls.Certificate, 0, len(this.Certificate))
for _, entry := range this.Certificate {
keyPair, err := tls.X509KeyPair(entry.Certificate, entry.Key)
if err != nil {
log.Warning("TLS: ignoring invalid X509 key pair: ", err)
continue
}
certs = append(certs, keyPair)
}
return certs
}
func (this *Config) GetTLSConfig() *tls.Config {
config := &tls.Config{
ClientSessionCache: globalSessionCache,
}
if this == nil {
return config
}
config.InsecureSkipVerify = this.AllowInsecure
config.Certificates = this.BuildCertificates()
config.BuildNameToCertificate()
return config
}

View File

@ -0,0 +1,82 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/transport/internet/tls/config.proto
// DO NOT EDIT!
/*
Package tls is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/transport/internet/tls/config.proto
It has these top-level messages:
Certificate
Config
*/
package tls
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Certificate struct {
Certificate []byte `protobuf:"bytes,1,opt,name=Certificate,json=certificate,proto3" json:"Certificate,omitempty"`
Key []byte `protobuf:"bytes,2,opt,name=Key,json=key,proto3" json:"Key,omitempty"`
}
func (m *Certificate) Reset() { *m = Certificate{} }
func (m *Certificate) String() string { return proto.CompactTextString(m) }
func (*Certificate) ProtoMessage() {}
func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type Config struct {
AllowInsecure bool `protobuf:"varint,1,opt,name=allow_insecure,json=allowInsecure" json:"allow_insecure,omitempty"`
Certificate []*Certificate `protobuf:"bytes,2,rep,name=certificate" json:"certificate,omitempty"`
}
func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *Config) GetCertificate() []*Certificate {
if m != nil {
return m.Certificate
}
return nil
}
func init() {
proto.RegisterType((*Certificate)(nil), "v2ray.core.transport.internet.tls.Certificate")
proto.RegisterType((*Config)(nil), "v2ray.core.transport.internet.tls.Config")
}
func init() { proto.RegisterFile("v2ray.com/core/transport/internet/tls/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 219 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x84, 0x90, 0xb1, 0x4b, 0x43, 0x31,
0x10, 0xc6, 0x79, 0x0d, 0x14, 0x49, 0x54, 0x24, 0xd3, 0x1b, 0x9f, 0x85, 0x42, 0xa7, 0x0b, 0x3c,
0x27, 0x47, 0xdb, 0x49, 0x5c, 0x4a, 0x47, 0x17, 0x89, 0xe1, 0x2a, 0xc1, 0x34, 0x57, 0x2e, 0xa7,
0xf2, 0x46, 0xff, 0x73, 0x31, 0xb5, 0xf2, 0x3a, 0x75, 0xbc, 0xef, 0xbe, 0xfb, 0xee, 0xc7, 0xa7,
0xfb, 0xcf, 0x9e, 0xfd, 0x00, 0x81, 0x76, 0x2e, 0x10, 0xa3, 0x13, 0xf6, 0xb9, 0xec, 0x89, 0xc5,
0xc5, 0x2c, 0xc8, 0x19, 0xc5, 0x49, 0x2a, 0x2e, 0x50, 0xde, 0xc6, 0x37, 0xd8, 0x33, 0x09, 0xd9,
0xdb, 0xe3, 0x0d, 0x23, 0xfc, 0xfb, 0xe1, 0xe8, 0x07, 0x49, 0x65, 0xf6, 0xa0, 0xcd, 0x0a, 0x59,
0xe2, 0x36, 0x06, 0x2f, 0x68, 0xbb, 0x93, 0xb1, 0x6d, 0xba, 0x66, 0x71, 0xb9, 0x31, 0x61, 0xe4,
0xb8, 0xd1, 0xea, 0x09, 0x87, 0x76, 0x52, 0x37, 0xea, 0x1d, 0x87, 0xd9, 0x77, 0xa3, 0xa7, 0xab,
0xfa, 0xd6, 0xce, 0xf5, 0xb5, 0x4f, 0x89, 0xbe, 0x5e, 0x62, 0x2e, 0x18, 0x3e, 0xf8, 0x90, 0x70,
0xb1, 0xb9, 0xaa, 0xea, 0xe3, 0x9f, 0x68, 0xd7, 0x7a, 0x1c, 0xd9, 0x4e, 0x3a, 0xb5, 0x30, 0x3d,
0xc0, 0x59, 0x5a, 0x18, 0xb1, 0x9d, 0x50, 0x2d, 0xef, 0xf5, 0x3c, 0xd0, 0xee, 0x7c, 0xc2, 0xd2,
0x1c, 0x48, 0xd7, 0xbf, 0xfd, 0x3c, 0x2b, 0x49, 0xe5, 0x75, 0x5a, 0xbb, 0xba, 0xfb, 0x09, 0x00,
0x00, 0xff, 0xff, 0xbb, 0x82, 0x9d, 0x49, 0x61, 0x01, 0x00, 0x00,
}

View File

@ -0,0 +1,16 @@
syntax = "proto3";
package v2ray.core.transport.internet.tls;
option go_package = "tls";
option java_package = "com.v2ray.core.transport.internet.tls";
option java_outer_classname = "ConfigProto";
message Certificate {
bytes Certificate = 1;
bytes Key = 2;
}
message Config {
bool allow_insecure = 1;
repeated Certificate certificate = 2;
}

View File

@ -0,0 +1,41 @@
// +build json
package tls
import (
"encoding/json"
"errors"
"io/ioutil"
)
func (this *Config) UnmarshalJSON(data []byte) error {
type JSONCertConfig struct {
CertFile string `json:"certificateFile"`
KeyFile string `json:"keyFile"`
}
type JSONConfig struct {
Insecure bool `json:"allowInsecure"`
Certs []*JSONCertConfig `json:"certificates"`
}
jsonConfig := new(JSONConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil {
return err
}
this.Certificate = make([]*Certificate, len(jsonConfig.Certs))
for idx, certConf := range jsonConfig.Certs {
cert, err := ioutil.ReadFile(certConf.CertFile)
if err != nil {
return errors.New("TLS: Failed to load certificate file: " + err.Error())
}
key, err := ioutil.ReadFile(certConf.KeyFile)
if err != nil {
return errors.New("TLS: Failed to load key file: " + err.Error())
}
this.Certificate[idx] = &Certificate{
Key: key,
Certificate: cert,
}
}
this.AllowInsecure = jsonConfig.Insecure
return nil
}

View File

@ -1,17 +1,14 @@
package ws package ws
type Config struct { import (
ConnectionReuse bool v2net "v2ray.com/core/common/net"
Path string "v2ray.com/core/transport/internet"
}
func (this *Config) Apply() { "github.com/golang/protobuf/proto"
effectiveConfig = this
}
var (
effectiveConfig = &Config{
ConnectionReuse: true,
Path: "",
}
) )
func init() {
internet.RegisterNetworkConfigCreator(v2net.Network_WebSocket, func() proto.Message {
return new(Config)
})
}

View File

@ -0,0 +1,60 @@
// Code generated by protoc-gen-go.
// source: v2ray.com/core/transport/internet/ws/config.proto
// DO NOT EDIT!
/*
Package ws is a generated protocol buffer package.
It is generated from these files:
v2ray.com/core/transport/internet/ws/config.proto
It has these top-level messages:
Config
*/
package ws
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Config struct {
ConnectionReuse bool `protobuf:"varint,1,opt,name=connection_reuse,json=connectionReuse" json:"connection_reuse,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"`
}
func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.transport.internet.ws.Config")
}
func init() { proto.RegisterFile("v2ray.com/core/transport/internet/ws/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 174 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x32, 0x2c, 0x33, 0x2a, 0x4a,
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x2f, 0x29, 0x4a, 0xcc, 0x2b,
0x2e, 0xc8, 0x2f, 0x2a, 0xd1, 0xcf, 0xcc, 0x2b, 0x49, 0x2d, 0xca, 0x4b, 0x2d, 0xd1, 0x2f, 0x2f,
0xd6, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x52, 0x80,
0x69, 0x29, 0x4a, 0xd5, 0x83, 0x2b, 0xd7, 0x83, 0x29, 0xd7, 0x2b, 0x2f, 0x56, 0x72, 0xe7, 0x62,
0x73, 0x06, 0xeb, 0x10, 0xd2, 0xe4, 0x12, 0x48, 0xce, 0xcf, 0xcb, 0x4b, 0x4d, 0x2e, 0xc9, 0xcc,
0xcf, 0x8b, 0x2f, 0x4a, 0x2d, 0x2d, 0x4e, 0x95, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x08, 0xe2, 0x47,
0x88, 0x07, 0x81, 0x84, 0x85, 0x84, 0xb8, 0x58, 0x0a, 0x12, 0x4b, 0x32, 0x24, 0x98, 0x14, 0x18,
0x35, 0x38, 0x83, 0xc0, 0x6c, 0x27, 0x73, 0x2e, 0x95, 0xe4, 0xfc, 0x5c, 0x3d, 0x42, 0x16, 0x3a,
0x71, 0x43, 0xac, 0x0b, 0x00, 0xb9, 0x2f, 0x8a, 0xa9, 0xbc, 0x38, 0x89, 0x0d, 0xec, 0x54, 0x63,
0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf1, 0x69, 0xf5, 0xaf, 0xdf, 0x00, 0x00, 0x00,
}

View File

@ -0,0 +1,11 @@
syntax = "proto3";
package v2ray.core.transport.internet.ws;
option go_package = "ws";
option java_package = "com.v2ray.core.transport.internet.ws";
option java_outer_classname = "ConfigProto";
message Config {
bool connection_reuse = 1;
string path = 2;
}

View File

@ -20,14 +20,16 @@ type Connection struct {
conn *wsconn conn *wsconn
listener ConnectionManager listener ConnectionManager
reusable bool reusable bool
config *Config
} }
func NewConnection(dest string, conn *wsconn, manager ConnectionManager) *Connection { func NewConnection(dest string, conn *wsconn, manager ConnectionManager, config *Config) *Connection {
return &Connection{ return &Connection{
dest: dest, dest: dest,
conn: conn, conn: conn,
listener: manager, listener: manager,
reusable: effectiveConfig.ConnectionReuse, reusable: config.ConnectionReuse,
config: config,
} }
} }
@ -80,7 +82,7 @@ func (this *Connection) SetWriteDeadline(t time.Time) error {
} }
func (this *Connection) SetReusable(reusable bool) { func (this *Connection) SetReusable(reusable bool) {
if !effectiveConfig.ConnectionReuse { if !this.config.ConnectionReuse {
return return
} }
this.reusable = reusable this.reusable = reusable

View File

@ -9,6 +9,7 @@ import (
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
v2tls "v2ray.com/core/transport/internet/tls"
) )
var ( var (
@ -20,9 +21,15 @@ func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOpti
if src == nil { if src == nil {
src = v2net.AnyIP src = v2net.AnyIP
} }
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
return nil, err
}
wsSettings := networkSettings.(*Config)
id := src.String() + "-" + dest.NetAddr() id := src.String() + "-" + dest.NetAddr()
var conn *wsconn var conn *wsconn
if dest.Network == v2net.Network_TCP && effectiveConfig.ConnectionReuse { if dest.Network == v2net.Network_TCP && wsSettings.ConnectionReuse {
connt := globalCache.Get(id) connt := globalCache.Get(id)
if connt != nil { if connt != nil {
conn = connt.(*wsconn) conn = connt.(*wsconn)
@ -36,7 +43,7 @@ func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOpti
return nil, err return nil, err
} }
} }
return NewConnection(id, conn, globalCache), nil return NewConnection(id, conn, globalCache, wsSettings), nil
} }
func init() { func init() {
@ -44,6 +51,12 @@ func init() {
} }
func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (*wsconn, error) { func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (*wsconn, error) {
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
return nil, err
}
wsSettings := networkSettings.(*Config)
commonDial := func(network, addr string) (net.Conn, error) { commonDial := func(network, addr string) (net.Conn, error) {
return internet.DialToDest(src, dest) return internet.DialToDest(src, dest)
} }
@ -56,9 +69,14 @@ func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOp
protocol := "ws" protocol := "ws"
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS { if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
protocol = "wss" protocol = "wss"
dialer.TLSClientConfig = options.Stream.TLSSettings.GetTLSConfig() securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("WebSocket: Failed to create apply TLS config: ", err)
return nil, err
}
dialer.TLSClientConfig = securitySettings.(*v2tls.Config).GetTLSConfig()
if dest.Address.Family().IsDomain() { if dest.Address.Family().IsDomain() {
dialer.TLSClientConfig.ServerName = dest.Address.Domain() dialer.TLSClientConfig.ServerName = dest.Address.Domain()
} }
@ -66,7 +84,7 @@ func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOp
uri := func(dst v2net.Destination, pto string, path string) string { uri := func(dst v2net.Destination, pto string, path string) string {
return fmt.Sprintf("%v://%v/%v", pto, dst.NetAddr(), path) return fmt.Sprintf("%v://%v/%v", pto, dst.NetAddr(), path)
}(dest, protocol, effectiveConfig.Path) }(dest, protocol, wsSettings.Path)
conn, resp, err := dialer.Dial(uri, nil) conn, resp, err := dialer.Dial(uri, nil)
if err != nil { if err != nil {
@ -77,7 +95,11 @@ func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOp
return nil, err return nil, err
} }
return func() internet.Connection { return func() internet.Connection {
connv2ray := &wsconn{wsc: conn, connClosing: false} connv2ray := &wsconn{
wsc: conn,
connClosing: false,
config: wsSettings,
}
connv2ray.setup() connv2ray.setup()
return connv2ray return connv2ray
}().(*wsconn), nil }().(*wsconn), nil

View File

@ -13,6 +13,7 @@ import (
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
v2tls "v2ray.com/core/transport/internet/tls"
) )
var ( var (
@ -30,26 +31,37 @@ type WSListener struct {
awaitingConns chan *ConnectionWithError awaitingConns chan *ConnectionWithError
listener *StoppableListener listener *StoppableListener
tlsConfig *tls.Config tlsConfig *tls.Config
config *Config
} }
func ListenWS(address v2net.Address, port v2net.Port, options internet.ListenOptions) (internet.Listener, error) { func ListenWS(address v2net.Address, port v2net.Port, options internet.ListenOptions) (internet.Listener, error) {
networkSettings, err := options.Stream.GetEffectiveNetworkSettings()
if err != nil {
return nil, err
}
wsSettings := networkSettings.(*Config)
l := &WSListener{ l := &WSListener{
acccepting: true, acccepting: true,
awaitingConns: make(chan *ConnectionWithError, 32), awaitingConns: make(chan *ConnectionWithError, 32),
config: wsSettings,
} }
if options.Stream != nil && options.Stream.Security == internet.StreamSecurityTypeTLS { if options.Stream != nil && options.Stream.SecurityType == internet.SecurityType_TLS {
l.tlsConfig = options.Stream.TLSSettings.GetTLSConfig() securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("WebSocket: Failed to create apply TLS config: ", err)
return nil, err
}
l.tlsConfig = securitySettings.(*v2tls.Config).GetTLSConfig()
} }
err := l.listenws(address, port) err = l.listenws(address, port)
return l, err return l, err
} }
func (wsl *WSListener) listenws(address v2net.Address, port v2net.Port) error { func (wsl *WSListener) listenws(address v2net.Address, port v2net.Port) error {
http.HandleFunc("/"+wsl.config.Path, func(w http.ResponseWriter, r *http.Request) {
http.HandleFunc("/"+effectiveConfig.Path, func(w http.ResponseWriter, r *http.Request) {
con, err := wsl.converttovws(w, r) con, err := wsl.converttovws(w, r)
if err != nil { if err != nil {
log.Warning("WebSocket|Listener: Failed to convert connection: ", err) log.Warning("WebSocket|Listener: Failed to convert connection: ", err)
@ -140,7 +152,7 @@ func (this *WSListener) Accept() (internet.Connection, error) {
if connErr.err != nil { if connErr.err != nil {
return nil, connErr.err return nil, connErr.err
} }
return NewConnection("", connErr.conn.(*wsconn), this), nil return NewConnection("", connErr.conn.(*wsconn), this, this.config), nil
case <-time.After(time.Second * 2): case <-time.After(time.Second * 2):
} }
} }

View File

@ -1,20 +1,43 @@
package ws_test package ws_test
import ( import (
"crypto/tls" "io/ioutil"
"testing" "testing"
"time" "time"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/testing/assert" "v2ray.com/core/testing/assert"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
v2tls "v2ray.com/core/transport/internet/tls"
. "v2ray.com/core/transport/internet/ws" . "v2ray.com/core/transport/internet/ws"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/any"
) )
func MarshalSettings(config *Config, assert *assert.Assert) *any.Any {
anySettings, err := ptypes.MarshalAny(config)
assert.Error(err).IsNil()
return anySettings
}
func Test_Connect_ws(t *testing.T) { func Test_Connect_ws(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
(&Config{Path: ""}).Apply()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 80), internet.DialerOptions{}) conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 80), internet.DialerOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
conn.Write([]byte("echo")) conn.Write([]byte("echo"))
s := make(chan int) s := make(chan int)
@ -33,10 +56,18 @@ func Test_Connect_ws(t *testing.T) {
func Test_Connect_wss(t *testing.T) { func Test_Connect_wss(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
(&Config{Path: ""}).Apply()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{ conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{
Stream: &internet.StreamSettings{ Stream: &internet.StreamConfig{
Security: internet.StreamSecurityTypeTLS, Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
SecurityType: internet.SecurityType_TLS,
}, },
}) })
assert.Error(err).IsNil() assert.Error(err).IsNil()
@ -57,10 +88,18 @@ func Test_Connect_wss(t *testing.T) {
func Test_Connect_wss_1_nil(t *testing.T) { func Test_Connect_wss_1_nil(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
(&Config{Path: ""}).Apply()
conn, err := Dial(nil, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{ conn, err := Dial(nil, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{
Stream: &internet.StreamSettings{ Stream: &internet.StreamConfig{
Security: internet.StreamSecurityTypeTLS, Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
SecurityType: internet.SecurityType_TLS,
}, },
}) })
assert.Error(err).IsNil() assert.Error(err).IsNil()
@ -81,8 +120,19 @@ func Test_Connect_wss_1_nil(t *testing.T) {
func Test_Connect_ws_guess(t *testing.T) { func Test_Connect_ws_guess(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
(&Config{Path: ""}).Apply() conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 80), internet.DialerOptions{
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 80), internet.DialerOptions{}) Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
conn.Write([]byte("echo")) conn.Write([]byte("echo"))
s := make(chan int) s := make(chan int)
@ -101,10 +151,18 @@ func Test_Connect_ws_guess(t *testing.T) {
func Test_Connect_wss_guess(t *testing.T) { func Test_Connect_wss_guess(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
(&Config{Path: ""}).Apply()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{ conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{
Stream: &internet.StreamSettings{ Stream: &internet.StreamConfig{
Security: internet.StreamSecurityTypeTLS, Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
SecurityType: internet.SecurityType_TLS,
}, },
}) })
assert.Error(err).IsNil() assert.Error(err).IsNil()
@ -125,10 +183,18 @@ func Test_Connect_wss_guess(t *testing.T) {
func Test_Connect_wss_guess_fail(t *testing.T) { func Test_Connect_wss_guess_fail(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
(&Config{Path: ""}).Apply()
_, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("static.kkdev.org"), 443), internet.DialerOptions{ _, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("static.kkdev.org"), 443), internet.DialerOptions{
Stream: &internet.StreamSettings{ Stream: &internet.StreamConfig{
Security: internet.StreamSecurityTypeTLS, Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
}, assert),
},
},
SecurityType: internet.SecurityType_TLS,
}, },
}) })
assert.Error(err).IsNotNil() assert.Error(err).IsNotNil()
@ -136,12 +202,21 @@ func Test_Connect_wss_guess_fail(t *testing.T) {
func Test_Connect_wss_guess_reuse(t *testing.T) { func Test_Connect_wss_guess_reuse(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
(&Config{Path: "", ConnectionReuse: true}).Apply()
i := 3 i := 3
for i != 0 { for i != 0 {
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{ conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("echo.websocket.org"), 443), internet.DialerOptions{
Stream: &internet.StreamSettings{ Stream: &internet.StreamConfig{
Security: internet.StreamSecurityTypeTLS, Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "",
ConnectionReuse: true,
}, assert),
},
},
SecurityType: internet.SecurityType_TLS,
}, },
}) })
assert.Error(err).IsNil() assert.Error(err).IsNil()
@ -170,8 +245,19 @@ func Test_Connect_wss_guess_reuse(t *testing.T) {
func Test_listenWSAndDial(t *testing.T) { func Test_listenWSAndDial(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
(&Config{Path: "ws"}).Apply() listen, err := ListenWS(v2net.DomainAddress("localhost"), 13142, internet.ListenOptions{
listen, err := ListenWS(v2net.DomainAddress("localhost"), 13142, internet.ListenOptions{}) Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "ws",
}, assert),
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
go func() { go func() {
conn, err := listen.Accept() conn, err := listen.Accept()
@ -185,15 +271,51 @@ func Test_listenWSAndDial(t *testing.T) {
conn.Close() conn.Close()
listen.Close() listen.Close()
}() }()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{}) conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "ws",
}, assert),
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
conn.Close() conn.Close()
<-time.After(time.Second * 5) <-time.After(time.Second * 5)
conn, err = Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{}) conn, err = Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "ws",
}, assert),
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
conn.Close() conn.Close()
<-time.After(time.Second * 15) <-time.After(time.Second * 15)
conn, err = Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{}) conn, err = Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13142), internet.DialerOptions{
Stream: &internet.StreamConfig{
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "ws",
}, assert),
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
conn.Close() conn.Close()
} }
@ -204,14 +326,34 @@ func Test_listenWSAndDial_TLS(t *testing.T) {
<-time.After(time.Second * 5) <-time.After(time.Second * 5)
assert.Fail("Too slow") assert.Fail("Too slow")
}() }()
(&Config{Path: "wss", ConnectionReuse: true}).Apply() tlsSettings := &v2tls.Config{
AllowInsecure: true,
Certificate: []*v2tls.Certificate{
{
Certificate: ReadFile("./../../../testing/tls/cert.pem", assert),
Key: ReadFile("./../../../testing/tls/key.pem", assert),
},
},
}
anyTlsSettings, err := ptypes.MarshalAny(tlsSettings)
assert.Error(err).IsNil()
listen, err := ListenWS(v2net.DomainAddress("localhost"), 13143, internet.ListenOptions{ listen, err := ListenWS(v2net.DomainAddress("localhost"), 13143, internet.ListenOptions{
Stream: &internet.StreamSettings{ Stream: &internet.StreamConfig{
Security: internet.StreamSecurityTypeTLS, SecurityType: internet.SecurityType_TLS,
TLSSettings: &internet.TLSSettings{ SecuritySettings: []*internet.SecuritySettings{{
AllowInsecure: true, Type: internet.SecurityType_TLS,
Certs: LoadTestCert(assert), Settings: anyTlsSettings,
}},
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "wss",
ConnectionReuse: true,
}, assert),
},
}, },
}, },
}) })
@ -223,11 +365,21 @@ func Test_listenWSAndDial_TLS(t *testing.T) {
listen.Close() listen.Close()
}() }()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13143), internet.DialerOptions{ conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13143), internet.DialerOptions{
Stream: &internet.StreamSettings{ Stream: &internet.StreamConfig{
Security: internet.StreamSecurityTypeTLS, SecurityType: internet.SecurityType_TLS,
TLSSettings: &internet.TLSSettings{ SecuritySettings: []*internet.SecuritySettings{{
AllowInsecure: true, Type: internet.SecurityType_TLS,
Certs: LoadTestCert(assert), Settings: anyTlsSettings,
}},
Network: v2net.Network_WebSocket,
NetworkSettings: []*internet.NetworkSettings{
{
Network: v2net.Network_WebSocket,
Settings: MarshalSettings(&Config{
Path: "wss",
ConnectionReuse: true,
}, assert),
},
}, },
}, },
}) })
@ -235,8 +387,8 @@ func Test_listenWSAndDial_TLS(t *testing.T) {
conn.Close() conn.Close()
} }
func LoadTestCert(assert *assert.Assert) []tls.Certificate { func ReadFile(file string, assert *assert.Assert) []byte {
cert, err := tls.LoadX509KeyPair("./../../../testing/tls/cert.pem", "./../../../testing/tls/key.pem") b, err := ioutil.ReadFile(file)
assert.Error(err).IsNil() assert.Error(err).IsNil()
return []tls.Certificate{cert} return b
} }

View File

@ -18,6 +18,7 @@ type wsconn struct {
reusable bool reusable bool
rlock *sync.Mutex rlock *sync.Mutex
wlock *sync.Mutex wlock *sync.Mutex
config *Config
} }
func (ws *wsconn) Read(b []byte) (n int, err error) { func (ws *wsconn) Read(b []byte) (n int, err error) {
@ -164,7 +165,7 @@ func (ws *wsconn) Reusable() bool {
} }
func (ws *wsconn) SetReusable(reusable bool) { func (ws *wsconn) SetReusable(reusable bool) {
if !effectiveConfig.ConnectionReuse { if !ws.config.ConnectionReuse {
return return
} }
ws.reusable = reusable ws.reusable = reusable