Compare commits

...

76 Commits

Author SHA1 Message Date
V2Ray
869cd46450 Rename to routing 2015-11-23 00:19:23 +01:00
V2Ray
790f6c038c Fix field rule 2015-11-22 22:14:27 +01:00
V2Ray
1cdd3e6647 test case for ip rule 2015-11-22 21:16:28 +01:00
V2Ray
fb1dda5a19 Update config files 2015-11-22 21:05:16 +01:00
V2Ray
46b81b7e98 Update version for next release 2015-11-22 17:45:42 +01:00
V2Ray
12e72509a5 code ready for selective routing 2015-11-22 17:41:52 +01:00
V2Ray
f4ec19625e Implementation of rules router 2015-11-22 12:05:21 +01:00
V2Ray
d48ac4418f config for rule based router 2015-11-21 21:43:40 +01:00
V2Ray
794b5081e3 Simplify swap 2015-11-17 14:26:13 +01:00
V2Ray
1b8e100879 validation reader for vmess 2015-11-15 21:54:28 +01:00
V2Ray
57dc6c69f1 Router config 2015-11-14 14:24:56 +01:00
V2Ray
1d4b98ab9a Outbound detour config 2015-11-13 23:43:58 +01:00
V2Ray
8597642002 UDP support for dokodemo door 2015-11-11 00:08:43 +01:00
V2Ray
b6cebd127d fuzz test for socks udp 2015-11-10 18:16:13 +01:00
V2Ray
3a6844f482 reduce number of iterations of vmess fuzzing test. 2015-11-10 12:25:26 +01:00
V2Ray
bd48556b98 Smarter reader generator 2015-11-10 12:13:01 +01:00
V2Ray
2a6f4740c1 fuzzing test for vmess protocol 2015-11-10 00:05:25 +01:00
V2Ray
d34678d9a6 fuzzing test for socks protocol 2015-11-09 23:52:31 +01:00
V2Ray
da1b428bb4 Fix default config file 2015-11-09 22:31:19 +01:00
V2Ray
a3a51b7b30 Update coverall 2015-11-06 13:56:33 +01:00
V2Ray
5347673e00 test case for socks udp 2015-11-06 13:45:41 +01:00
V2Ray
6ce1539bca Update coverall script 2015-11-06 13:28:34 +01:00
V2Ray
e60fcba4b3 Test cases for Socks end 2 end. 2015-11-06 13:08:20 +01:00
V2Ray
fdc72ed8c9 Move mocked userset to vmess/protocol/user 2015-11-04 23:04:00 +01:00
V2Ray
1d4b541d2f Move mock config to app/config 2015-11-04 23:01:04 +01:00
V2Ray
346b6125f4 test cases for Destination 2015-11-04 22:48:54 +01:00
V2Ray
31fb65b3d8 Remove VMess UDP 2015-11-04 21:52:48 +01:00
V2Ray
581e6b7104 More test case for building 2015-11-04 21:20:06 +01:00
V2Ray
8204c9923d typo 2015-11-04 17:57:11 +01:00
V2Ray
602afca3e3 Test case for macos building 2015-11-04 17:52:59 +01:00
V2Ray
0a8e283e55 function to create router 2015-11-03 23:24:56 +01:00
V2Ray
0d06561b7e More test case 2015-11-03 22:27:26 +01:00
V2Ray
c144e77eb3 Refactor socks config 2015-11-03 22:23:50 +01:00
V2Ray
654cdf18d9 Refactor socks json config 2015-11-03 22:09:07 +01:00
V2Ray
a46db069fb Refactor AES encryption/decryption 2015-11-03 21:26:16 +01:00
V2Ray
3f884ed924 More test case for stream logger 2015-11-03 20:30:14 +01:00
V2Ray
144141b3c3 test case for stream logger 2015-11-03 20:24:29 +01:00
V2Ray
cb19e4613f Update port range test 2015-11-03 20:07:46 +01:00
V2Ray
6faff6d514 test case for socks udp protocol 2015-11-03 18:33:58 +01:00
V2Ray
d9ebd008d3 Check lenth of the udp packet before parsing 2015-11-03 18:20:28 +01:00
V2Ray
d58384ced0 One more test case for retry 2015-11-03 00:12:25 +01:00
V2Ray
f080f36372 format code 2015-11-03 00:07:19 +01:00
V2Ray
60b116fbde Test case for retry 2015-11-03 00:07:15 +01:00
V2Ray
1edd0e660e Remove redunent code 2015-11-02 23:55:10 +01:00
V2Ray
8fbb9762db typo 2015-11-02 23:54:11 +01:00
V2Ray
1a4405dbe1 Remove redunent code 2015-11-02 23:52:22 +01:00
V2Ray
f2cf4a1f89 Test case for too-short request 2015-11-02 23:48:47 +01:00
V2Ray
dcdce6696b Update version for next release 2015-11-02 00:07:28 +01:00
V2Ray
e70c02f768 Fix test break 2015-11-02 00:06:56 +01:00
V2Ray
bbac647656 Update user id 2015-11-02 00:05:32 +01:00
V2Ray
590699fc7b Update ports 2015-11-02 00:04:11 +01:00
V2Ray
fae78683f9 Update DNS port 2015-11-02 00:02:46 +01:00
V2Ray
1cec5ac643 Test case for inbound detour network 2015-11-01 23:01:15 +01:00
V2Ray
1c6b66eacf Test case for dokodemo 2015-11-01 22:17:49 +01:00
V2Ray
03b8c8f9e8 Port picker 2015-11-01 21:32:08 +01:00
V2Ray
192960b711 Move mocked connection handlers to proxy/testing/mocks 2015-11-01 21:15:08 +01:00
V2Ray
f983d285b8 detour handler 2015-11-01 00:11:41 +01:00
V2Ray
3c43268898 inbound detour 2015-10-31 22:22:43 +01:00
V2Ray
1708c48f5b Port range 2015-10-31 21:43:26 +01:00
V2Ray
1c09b70931 format code 2015-10-31 14:08:13 +01:00
V2Ray
3765826602 Test case for config cache. 2015-10-31 14:08:09 +01:00
V2Ray
46c0d457d9 User settings for trusted user 2015-10-31 09:39:45 +01:00
V2Ray
b44098d752 Introduce user level 2015-10-31 00:38:31 +01:00
V2Ray
d585ec0593 Move config to app/point 2015-10-30 22:50:45 +01:00
V2Ray
2b45e63607 Move config cache to proxy/common 2015-10-30 22:42:24 +01:00
V2Ray
c56e17fff9 Dokodemo proxy 2015-10-30 15:56:46 +01:00
V2Ray
f93b29993b Move connection handler interfaces to proxy/common/connhandler 2015-10-30 00:11:29 +01:00
V2Ray
361a22d74d Move proxy errors to proxy/common/errors 2015-10-29 23:59:57 +01:00
V2Ray
ce07ea9769 Split json config files 2015-10-29 23:41:37 +01:00
V2Ray
6e8425b23a Remove config type in connection settings() 2015-10-29 23:35:54 +01:00
V2Ray
fdb41bbd50 Remove call to UTC() which is not necessary. 2015-10-29 12:04:14 +01:00
V2Ray
d0ae47e2ce Router interface 2015-10-28 23:18:07 +01:00
V2Ray
9b8632d01a BlackHole proxy 2015-10-28 17:41:14 +01:00
V2Ray
fdb952fb01 Merge branch 'master' of https://github.com/v2ray/v2ray-core 2015-10-28 12:13:43 +01:00
V2Ray
08328d23fa beginning of http proxy 2015-10-28 12:13:27 +01:00
V2 Ray
65bc306ba7 Update README.md 2015-10-27 12:50:25 +01:00
106 changed files with 3286 additions and 917 deletions

View File

@@ -9,25 +9,7 @@
V2Ray 是一个模块化的代理软件包,它的目标是提供常用的代理软件模块,简化网络代理软件的开发。
## 联系方式
* 聊天室https://gitter.im/v2ray/v2ray-core
* Twitterhttps://twitter.com/projectv2ray
* 私下联系love@v2ray.com
* [捐赠](https://github.com/v2ray/v2ray-core/blob/master/spec/donate.md)
## 使用说明
* [简明教程](https://github.com/V2Ray/v2ray-core/blob/master/spec/guide.md)
* [建议或意见](https://github.com/v2ray/v2ray-core/issues)
* [Issue 指引](https://github.com/V2Ray/v2ray-core/blob/master/spec/issue.md)
* [当前状态](https://github.com/V2Ray/v2ray-core/blob/master/spec/status.md)
* [错误信息](https://github.com/V2Ray/v2ray-core/blob/master/spec/errors.md)
* [性能测试](https://github.com/V2Ray/v2ray-core/blob/master/spec/benchmark.md)
## 开发人员相关
* [概要设计](https://github.com/V2Ray/v2ray-core/blob/master/spec/design.md)
* [开发计划](https://github.com/V2Ray/v2ray-core/blob/master/spec/roadmap.md)
* [Help Wanted](https://github.com/v2ray/v2ray-core/labels/help%20wanted)所有被标记为“Help Wanted”的 Issue 都接受 Pull Request如果你对本项目感兴趣并想做点贡献请挑选其中之一完善之不甚感激。
* [开发指引](https://github.com/V2Ray/v2ray-core/blob/master/spec/develop.md)
[官方网站](https://www.v2ray.com/)
## License
[The MIT License (MIT)](https://raw.githubusercontent.com/v2ray/v2ray-core/master/LICENSE)

View File

@@ -0,0 +1,39 @@
package config
import (
routerconfig "github.com/v2ray/v2ray-core/app/router/config"
v2net "github.com/v2ray/v2ray-core/common/net"
)
type DetourTag string
type ConnectionConfig interface {
Protocol() string
Settings() interface{}
}
type LogConfig interface {
AccessLog() string
}
type InboundDetourConfig interface {
Protocol() string
PortRange() v2net.PortRange
Settings() interface{}
}
type OutboundDetourConfig interface {
Protocol() string
Tag() DetourTag
Settings() interface{}
}
type PointConfig interface {
Port() uint16
LogConfig() LogConfig
RouterConfig() routerconfig.RouterConfig
InboundConfig() ConnectionConfig
OutboundConfig() ConnectionConfig
InboundDetours() []InboundDetourConfig
OutboundDetours() []OutboundDetourConfig
}

View File

@@ -0,0 +1,36 @@
package json
import (
"encoding/json"
"github.com/v2ray/v2ray-core/common/log"
proxyconfig "github.com/v2ray/v2ray-core/proxy/common/config"
proxyjson "github.com/v2ray/v2ray-core/proxy/common/config/json"
)
type ConnectionConfig struct {
ProtocolString string `json:"protocol"`
SettingsMessage json.RawMessage `json:"settings"`
Type proxyconfig.Type `json:"-"`
}
func (c *ConnectionConfig) Protocol() string {
return c.ProtocolString
}
func (c *ConnectionConfig) Settings() interface{} {
return loadConnectionConfig(c.SettingsMessage, c.Protocol(), c.Type)
}
func loadConnectionConfig(message json.RawMessage, protocol string, cType proxyconfig.Type) interface{} {
configObj := proxyjson.CreateConfig(protocol, cType)
if configObj == nil {
panic("Unknown protocol " + protocol)
}
err := json.Unmarshal(message, configObj)
if err != nil {
log.Error("Unable to parse connection config: %v", err)
panic("Failed to parse connection config.")
}
return configObj
}

View File

@@ -0,0 +1,27 @@
package json
import (
"encoding/json"
v2net "github.com/v2ray/v2ray-core/common/net"
v2netjson "github.com/v2ray/v2ray-core/common/net/json"
proxyconfig "github.com/v2ray/v2ray-core/proxy/common/config"
)
type InboundDetourConfig struct {
ProtocolValue string `json:"protocol"`
PortRangeValue *v2netjson.PortRange `json:"port"`
SettingsValue json.RawMessage `json:"settings"`
}
func (this *InboundDetourConfig) Protocol() string {
return this.ProtocolValue
}
func (this *InboundDetourConfig) PortRange() v2net.PortRange {
return this.PortRangeValue
}
func (this *InboundDetourConfig) Settings() interface{} {
return loadConnectionConfig(this.SettingsValue, this.ProtocolValue, proxyconfig.TypeInbound)
}

View File

@@ -0,0 +1,93 @@
package json
import (
"encoding/json"
"io/ioutil"
"os"
"github.com/v2ray/v2ray-core/app/point/config"
routerconfig "github.com/v2ray/v2ray-core/app/router/config"
routerconfigjson "github.com/v2ray/v2ray-core/app/router/config/json"
"github.com/v2ray/v2ray-core/common/log"
proxyconfig "github.com/v2ray/v2ray-core/proxy/common/config"
)
// Config is the config for Point server.
type Config struct {
PortValue uint16 `json:"port"` // Port of this Point server.
LogConfigValue *LogConfig `json:"log"`
RouterConfigValue *routerconfigjson.RouterConfig `json:"routing"`
InboundConfigValue *ConnectionConfig `json:"inbound"`
OutboundConfigValue *ConnectionConfig `json:"outbound"`
InboundDetoursValue []*InboundDetourConfig `json:"inboundDetour"`
OutboundDetoursValue []*OutboundDetourConfig `json:"outboundDetour"`
}
func (config *Config) Port() uint16 {
return config.PortValue
}
func (config *Config) LogConfig() config.LogConfig {
if config.LogConfigValue == nil {
return nil
}
return config.LogConfigValue
}
func (this *Config) RouterConfig() routerconfig.RouterConfig {
if this.RouterConfigValue == nil {
return nil
}
return this.RouterConfigValue
}
func (config *Config) InboundConfig() config.ConnectionConfig {
if config.InboundConfigValue == nil {
return nil
}
return config.InboundConfigValue
}
func (config *Config) OutboundConfig() config.ConnectionConfig {
if config.OutboundConfigValue == nil {
return nil
}
return config.OutboundConfigValue
}
func (this *Config) InboundDetours() []config.InboundDetourConfig {
detours := make([]config.InboundDetourConfig, len(this.InboundDetoursValue))
for idx, detour := range this.InboundDetoursValue {
detours[idx] = detour
}
return detours
}
func (this *Config) OutboundDetours() []config.OutboundDetourConfig {
detours := make([]config.OutboundDetourConfig, len(this.OutboundDetoursValue))
for idx, detour := range this.OutboundDetoursValue {
detours[idx] = detour
}
return detours
}
func LoadConfig(file string) (*Config, error) {
fixedFile := os.ExpandEnv(file)
rawConfig, err := ioutil.ReadFile(fixedFile)
if err != nil {
log.Error("Failed to read server config file (%s): %v", file, err)
return nil, err
}
jsonConfig := &Config{}
err = json.Unmarshal(rawConfig, jsonConfig)
if err != nil {
log.Error("Failed to load server config: %v", err)
return nil, err
}
jsonConfig.InboundConfigValue.Type = proxyconfig.TypeInbound
jsonConfig.OutboundConfigValue.Type = proxyconfig.TypeOutbound
return jsonConfig, err
}

View File

@@ -4,8 +4,8 @@ import (
"path/filepath"
"testing"
"github.com/v2ray/v2ray-core/config"
"github.com/v2ray/v2ray-core/config/json"
"github.com/v2ray/v2ray-core/app/point/config/json"
_ "github.com/v2ray/v2ray-core/proxy/dokodemo/config/json"
_ "github.com/v2ray/v2ray-core/proxy/freedom/config/json"
_ "github.com/v2ray/v2ray-core/proxy/socks/config/json"
_ "github.com/v2ray/v2ray-core/proxy/vmess/config/json"
@@ -27,10 +27,10 @@ func TestClientSampleConfig(t *testing.T) {
assert.Pointer(pointConfig.OutboundConfig()).IsNotNil()
assert.String(pointConfig.InboundConfig().Protocol()).Equals("socks")
assert.Pointer(pointConfig.InboundConfig().Settings(config.TypeInbound)).IsNotNil()
assert.Pointer(pointConfig.InboundConfig().Settings()).IsNotNil()
assert.String(pointConfig.OutboundConfig().Protocol()).Equals("vmess")
assert.Pointer(pointConfig.OutboundConfig().Settings(config.TypeOutbound)).IsNotNil()
assert.Pointer(pointConfig.OutboundConfig().Settings()).IsNotNil()
}
func TestServerSampleConfig(t *testing.T) {
@@ -47,8 +47,27 @@ func TestServerSampleConfig(t *testing.T) {
assert.Pointer(pointConfig.OutboundConfig()).IsNotNil()
assert.String(pointConfig.InboundConfig().Protocol()).Equals("vmess")
assert.Pointer(pointConfig.InboundConfig().Settings(config.TypeInbound)).IsNotNil()
assert.Pointer(pointConfig.InboundConfig().Settings()).IsNotNil()
assert.String(pointConfig.OutboundConfig().Protocol()).Equals("freedom")
assert.Pointer(pointConfig.OutboundConfig().Settings(config.TypeOutbound)).IsNotNil()
assert.Pointer(pointConfig.OutboundConfig().Settings()).IsNotNil()
}
func TestDetourConfig(t *testing.T) {
assert := unit.Assert(t)
// TODO: fix for Windows
baseDir := "$GOPATH/src/github.com/v2ray/v2ray-core/release/config"
pointConfig, err := json.LoadConfig(filepath.Join(baseDir, "vpoint_dns_detour.json"))
assert.Error(err).IsNil()
detours := pointConfig.InboundDetours()
assert.Int(len(detours)).Equals(1)
detour := detours[0]
assert.String(detour.Protocol()).Equals("dokodemo-door")
assert.Uint16(detour.PortRange().From()).Equals(uint16(28394))
assert.Uint16(detour.PortRange().To()).Equals(uint16(28394))
assert.Pointer(detour.Settings()).IsNotNil()
}

View File

@@ -0,0 +1,9 @@
package json
type LogConfig struct {
AccessLogValue string `json:"access"`
}
func (config *LogConfig) AccessLog() string {
return config.AccessLogValue
}

View File

@@ -0,0 +1,26 @@
package json
import (
"encoding/json"
"github.com/v2ray/v2ray-core/app/point/config"
proxyconfig "github.com/v2ray/v2ray-core/proxy/common/config"
)
type OutboundDetourConfig struct {
ProtocolValue string `json:"protocol"`
TagValue string `json:"tag"`
SettingsValue json.RawMessage `json:"settings"`
}
func (this *OutboundDetourConfig) Protocol() string {
return this.ProtocolValue
}
func (this *OutboundDetourConfig) Tag() config.DetourTag {
return config.DetourTag(this.TagValue)
}
func (this *OutboundDetourConfig) Settings() interface{} {
return loadConnectionConfig(this.SettingsValue, this.ProtocolValue, proxyconfig.TypeOutbound)
}

View File

@@ -0,0 +1,105 @@
package mocks
import (
"github.com/v2ray/v2ray-core/app/point/config"
routerconfig "github.com/v2ray/v2ray-core/app/router/config"
v2net "github.com/v2ray/v2ray-core/common/net"
)
type ConnectionConfig struct {
ProtocolValue string
SettingsValue interface{}
}
func (config *ConnectionConfig) Protocol() string {
return config.ProtocolValue
}
func (config *ConnectionConfig) Settings() interface{} {
return config.SettingsValue
}
type LogConfig struct {
AccessLogValue string
}
type PortRange struct {
FromValue uint16
ToValue uint16
}
func (this *PortRange) From() uint16 {
return this.FromValue
}
func (this *PortRange) To() uint16 {
return this.ToValue
}
type InboundDetourConfig struct {
ConnectionConfig
PortRangeValue *PortRange
}
func (this *InboundDetourConfig) PortRange() v2net.PortRange {
return this.PortRangeValue
}
type OutboundDetourConfig struct {
ConnectionConfig
TagValue config.DetourTag
}
func (this *OutboundDetourConfig) Tag() config.DetourTag {
return this.TagValue
}
func (config *LogConfig) AccessLog() string {
return config.AccessLogValue
}
type Config struct {
PortValue uint16
LogConfigValue *LogConfig
RouterConfigValue routerconfig.RouterConfig
InboundConfigValue *ConnectionConfig
OutboundConfigValue *ConnectionConfig
InboundDetoursValue []*InboundDetourConfig
OutboundDetoursValue []*OutboundDetourConfig
}
func (config *Config) Port() uint16 {
return config.PortValue
}
func (config *Config) LogConfig() config.LogConfig {
return config.LogConfigValue
}
func (this *Config) RouterConfig() routerconfig.RouterConfig {
return this.RouterConfigValue
}
func (config *Config) InboundConfig() config.ConnectionConfig {
return config.InboundConfigValue
}
func (config *Config) OutboundConfig() config.ConnectionConfig {
return config.OutboundConfigValue
}
func (this *Config) InboundDetours() []config.InboundDetourConfig {
detours := make([]config.InboundDetourConfig, len(this.InboundDetoursValue))
for idx, detour := range this.InboundDetoursValue {
detours[idx] = detour
}
return detours
}
func (this *Config) OutboundDetours() []config.OutboundDetourConfig {
detours := make([]config.OutboundDetourConfig, len(this.OutboundDetoursValue))
for idx, detour := range this.OutboundDetoursValue {
detours[idx] = detour
}
return detours
}

View File

@@ -0,0 +1,56 @@
package point
import (
"github.com/v2ray/v2ray-core/app/point/config"
"github.com/v2ray/v2ray-core/common/log"
"github.com/v2ray/v2ray-core/common/retry"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
)
type InboundConnectionHandlerWithPort struct {
port uint16
handler connhandler.InboundConnectionHandler
}
type InboundDetourHandler struct {
point *Point
config config.InboundDetourConfig
ich []*InboundConnectionHandlerWithPort
}
func (this *InboundDetourHandler) Initialize() error {
ichFactory := connhandler.GetInboundConnectionHandlerFactory(this.config.Protocol())
if ichFactory == nil {
log.Error("Unknown inbound connection handler factory %s", this.config.Protocol())
return config.BadConfiguration
}
ports := this.config.PortRange()
this.ich = make([]*InboundConnectionHandlerWithPort, 0, ports.From()-ports.To()+1)
for i := ports.From(); i <= ports.To(); i++ {
ichConfig := this.config.Settings()
ich, err := ichFactory.Create(this.point, ichConfig)
if err != nil {
log.Error("Failed to create inbound connection handler: %v", err)
return err
}
this.ich = append(this.ich, &InboundConnectionHandlerWithPort{
port: i,
handler: ich,
})
}
return nil
}
func (this *InboundDetourHandler) Start() error {
for _, ich := range this.ich {
return retry.Timed(100 /* times */, 100 /* ms */).On(func() error {
err := ich.handler.Listen(ich.port)
if err != nil {
return err
}
return nil
})
}
return nil
}

View File

@@ -1,19 +1,23 @@
package point
import (
"github.com/v2ray/v2ray-core/app/point/config"
"github.com/v2ray/v2ray-core/app/router"
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/common/retry"
"github.com/v2ray/v2ray-core/config"
"github.com/v2ray/v2ray-core/proxy"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
"github.com/v2ray/v2ray-core/transport/ray"
)
// Point is an single server in V2Ray system.
type Point struct {
port uint16
ich proxy.InboundConnectionHandler
och proxy.OutboundConnectionHandler
port uint16
ich connhandler.InboundConnectionHandler
och connhandler.OutboundConnectionHandler
idh []*InboundDetourHandler
odh map[config.DetourTag]connhandler.OutboundConnectionHandler
router router.Router
}
// NewPoint returns a new Point server based on given configuration.
@@ -22,12 +26,12 @@ func NewPoint(pConfig config.PointConfig) (*Point, error) {
var vpoint = new(Point)
vpoint.port = pConfig.Port()
ichFactory := proxy.GetInboundConnectionHandlerFactory(pConfig.InboundConfig().Protocol())
ichFactory := connhandler.GetInboundConnectionHandlerFactory(pConfig.InboundConfig().Protocol())
if ichFactory == nil {
log.Error("Unknown inbound connection handler factory %s", pConfig.InboundConfig().Protocol())
return nil, config.BadConfiguration
}
ichConfig := pConfig.InboundConfig().Settings(config.TypeInbound)
ichConfig := pConfig.InboundConfig().Settings()
ich, err := ichFactory.Create(vpoint, ichConfig)
if err != nil {
log.Error("Failed to create inbound connection handler: %v", err)
@@ -35,12 +39,12 @@ func NewPoint(pConfig config.PointConfig) (*Point, error) {
}
vpoint.ich = ich
ochFactory := proxy.GetOutboundConnectionHandlerFactory(pConfig.OutboundConfig().Protocol())
ochFactory := connhandler.GetOutboundConnectionHandlerFactory(pConfig.OutboundConfig().Protocol())
if ochFactory == nil {
log.Error("Unknown outbound connection handler factory %s", pConfig.OutboundConfig().Protocol())
return nil, config.BadConfiguration
}
ochConfig := pConfig.OutboundConfig().Settings(config.TypeOutbound)
ochConfig := pConfig.OutboundConfig().Settings()
och, err := ochFactory.Create(ochConfig)
if err != nil {
log.Error("Failed to create outbound connection handler: %v", err)
@@ -48,6 +52,50 @@ func NewPoint(pConfig config.PointConfig) (*Point, error) {
}
vpoint.och = och
detours := pConfig.InboundDetours()
if len(detours) > 0 {
vpoint.idh = make([]*InboundDetourHandler, len(detours))
for idx, detourConfig := range detours {
detourHandler := &InboundDetourHandler{
point: vpoint,
config: detourConfig,
}
err := detourHandler.Initialize()
if err != nil {
return nil, err
}
vpoint.idh[idx] = detourHandler
}
}
outboundDetours := pConfig.OutboundDetours()
if len(outboundDetours) > 0 {
vpoint.odh = make(map[config.DetourTag]connhandler.OutboundConnectionHandler)
for _, detourConfig := range outboundDetours {
detourFactory := connhandler.GetOutboundConnectionHandlerFactory(detourConfig.Protocol())
if detourFactory == nil {
log.Error("Unknown detour outbound connection handler factory %s", detourConfig.Protocol())
return nil, config.BadConfiguration
}
detourHandler, err := detourFactory.Create(detourConfig.Settings())
if err != nil {
log.Error("Failed to create detour outbound connection handler: %v", err)
return nil, err
}
vpoint.odh[detourConfig.Tag()] = detourHandler
}
}
routerConfig := pConfig.RouterConfig()
if routerConfig != nil {
r, err := router.CreateRouter(routerConfig.Strategy(), routerConfig.Settings())
if err != nil {
log.Error("Failed to create router: %v", err)
return nil, config.BadConfiguration
}
vpoint.router = r
}
return vpoint, nil
}
@@ -59,18 +107,43 @@ func (vp *Point) Start() error {
return config.BadConfiguration
}
return retry.Timed(100 /* times */, 100 /* ms */).On(func() error {
err := retry.Timed(100 /* times */, 100 /* ms */).On(func() error {
err := vp.ich.Listen(vp.port)
if err == nil {
log.Warning("Point server started on port %d", vp.port)
return nil
if err != nil {
return err
}
return err
log.Warning("Point server started on port %d", vp.port)
return nil
})
if err != nil {
return err
}
for _, detourHandler := range vp.idh {
err := detourHandler.Start()
if err != nil {
return err
}
}
return nil
}
func (p *Point) DispatchToOutbound(packet v2net.Packet) ray.InboundRay {
direct := ray.NewRay()
dest := packet.Destination()
if p.router != nil {
tag, err := p.router.TakeDetour(dest)
if err == nil {
handler, found := p.odh[tag]
if found {
go handler.Dispatch(packet, direct)
return direct
}
}
}
go p.och.Dispatch(packet, direct)
return direct
}

View File

@@ -0,0 +1,6 @@
package config
type RouterConfig interface {
Strategy() string
Settings() interface{}
}

View File

@@ -0,0 +1,25 @@
package json
type ConfigObjectCreator func() interface{}
var (
configCache map[string]ConfigObjectCreator
)
func RegisterRouterConfig(strategy string, creator ConfigObjectCreator) error {
// TODO: check strategy
configCache[strategy] = creator
return nil
}
func CreateRouterConfig(strategy string) interface{} {
creator, found := configCache[strategy]
if !found {
return nil
}
return creator()
}
func init() {
configCache = make(map[string]ConfigObjectCreator)
}

View File

@@ -0,0 +1,26 @@
package json
import (
"encoding/json"
"github.com/v2ray/v2ray-core/common/log"
)
type RouterConfig struct {
StrategyValue string `json:"strategy"`
SettingsValue json.RawMessage `json:"settings"`
}
func (this *RouterConfig) Strategy() string {
return this.StrategyValue
}
func (this *RouterConfig) Settings() interface{} {
settings := CreateRouterConfig(this.Strategy())
err := json.Unmarshal(this.SettingsValue, settings)
if err != nil {
log.Error("Failed to load router settings: %v", err)
return nil
}
return settings
}

37
app/router/router.go Normal file
View File

@@ -0,0 +1,37 @@
package router
import (
"errors"
"github.com/v2ray/v2ray-core/app/point/config"
v2net "github.com/v2ray/v2ray-core/common/net"
)
var (
RouterNotFound = errors.New("Router not found.")
)
type Router interface {
TakeDetour(v2net.Destination) (config.DetourTag, error)
}
type RouterFactory interface {
Create(rawConfig interface{}) (Router, error)
}
var (
routerCache = make(map[string]RouterFactory)
)
func RegisterRouter(name string, factory RouterFactory) error {
// TODO: check name
routerCache[name] = factory
return nil
}
func CreateRouter(name string, rawConfig interface{}) (Router, error) {
if factory, found := routerCache[name]; found {
return factory.Create(rawConfig)
}
return nil, RouterNotFound
}

View File

@@ -0,0 +1,93 @@
package json
import (
"encoding/json"
"errors"
"net"
"strings"
v2net "github.com/v2ray/v2ray-core/common/net"
v2netjson "github.com/v2ray/v2ray-core/common/net/json"
)
type FieldRule struct {
Rule
Domain string
IP *net.IPNet
Port v2net.PortRange
Network v2net.NetworkList
}
func (this *FieldRule) Apply(dest v2net.Destination) bool {
address := dest.Address()
if len(this.Domain) > 0 {
if !address.IsDomain() || !strings.Contains(address.Domain(), this.Domain) {
return false
}
}
if this.IP != nil {
if !(address.IsIPv4() || address.IsIPv6()) || !this.IP.Contains(address.IP()) {
return false
}
}
if this.Port != nil {
port := address.Port()
if port < this.Port.From() || port > this.Port.To() {
return false
}
}
if this.Network != nil {
if !this.Network.HasNetwork(v2net.Network(dest.Network())) {
return false
}
}
return true
}
func (this *FieldRule) UnmarshalJSON(data []byte) error {
type RawFieldRule struct {
Rule
Domain string `json:"domain"`
IP string `json:"ip"`
Port *v2netjson.PortRange `json:"port"`
Network *v2netjson.NetworkList `json:"network"`
}
rawFieldRule := RawFieldRule{}
err := json.Unmarshal(data, &rawFieldRule)
if err != nil {
return err
}
this.Type = rawFieldRule.Type
this.OutboundTag = rawFieldRule.OutboundTag
hasField := false
if len(rawFieldRule.Domain) > 0 {
this.Domain = rawFieldRule.Domain
hasField = true
}
if len(rawFieldRule.IP) > 0 {
_, ipNet, err := net.ParseCIDR(rawFieldRule.IP)
if err != nil {
return errors.New("Invalid IP range in router rule: " + err.Error())
}
this.IP = ipNet
hasField = true
}
if rawFieldRule.Port != nil {
this.Port = rawFieldRule.Port
hasField = true
}
if rawFieldRule.Network != nil {
this.Network = rawFieldRule.Network
hasField = true
}
if !hasField {
return errors.New("This rule has no effective fields.")
}
return nil
}

View File

@@ -0,0 +1,71 @@
package json
import (
"testing"
v2net "github.com/v2ray/v2ray-core/common/net"
v2nettesting "github.com/v2ray/v2ray-core/common/net/testing"
"github.com/v2ray/v2ray-core/testing/unit"
)
func TestDomainMatching(t *testing.T) {
assert := unit.Assert(t)
rule := &FieldRule{
Domain: "v2ray.com",
}
dest := v2net.NewTCPDestination(v2net.DomainAddress("www.v2ray.com", 80))
assert.Bool(rule.Apply(dest)).IsTrue()
}
func TestPortMatching(t *testing.T) {
assert := unit.Assert(t)
rule := &FieldRule{
Port: &v2nettesting.PortRange{
FromValue: 0,
ToValue: 100,
},
}
dest := v2net.NewTCPDestination(v2net.DomainAddress("www.v2ray.com", 80))
assert.Bool(rule.Apply(dest)).IsTrue()
}
func TestIPMatching(t *testing.T) {
assert := unit.Assert(t)
rawJson := `{
"type": "field",
"ip": "10.0.0.0/8",
"tag": "test"
}`
rule := parseRule([]byte(rawJson))
dest := v2net.NewTCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}, 80))
assert.Bool(rule.Apply(dest)).IsTrue()
}
func TestPortNotMatching(t *testing.T) {
assert := unit.Assert(t)
rawJson := `{
"type": "field",
"port": "80-100",
"tag": "test"
}`
rule := parseRule([]byte(rawJson))
dest := v2net.NewTCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}, 79))
assert.Bool(rule.Apply(dest)).IsFalse()
}
func TestDomainNotMatching(t *testing.T) {
assert := unit.Assert(t)
rawJson := `{
"type": "field",
"domain": "google.com",
"tag": "test"
}`
rule := parseRule([]byte(rawJson))
dest := v2net.NewTCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}, 79))
assert.Bool(rule.Apply(dest)).IsFalse()
}

View File

@@ -0,0 +1,47 @@
package json
import (
"encoding/json"
v2routerconfigjson "github.com/v2ray/v2ray-core/app/router/config/json"
"github.com/v2ray/v2ray-core/app/router/rules/config"
"github.com/v2ray/v2ray-core/common/log"
)
type RouterRuleConfig struct {
RuleList []json.RawMessage `json:"rules"`
}
func parseRule(msg json.RawMessage) config.Rule {
rule := new(Rule)
err := json.Unmarshal(msg, rule)
if err != nil {
log.Error("Invalid router rule: %v", err)
return nil
}
if rule.Type == "field" {
fieldrule := new(FieldRule)
err = json.Unmarshal(msg, fieldrule)
if err != nil {
log.Error("Invalid field rule: %v", err)
return nil
}
return fieldrule
}
log.Error("Unknown router rule type: %s", rule.Type)
return nil
}
func (this *RouterRuleConfig) Rules() []config.Rule {
rules := make([]config.Rule, len(this.RuleList))
for idx, rawRule := range this.RuleList {
rules[idx] = parseRule(rawRule)
}
return rules
}
func init() {
v2routerconfigjson.RegisterRouterConfig("rules", func() interface{} {
return new(RouterRuleConfig)
})
}

View File

@@ -0,0 +1,19 @@
package json
import (
"github.com/v2ray/v2ray-core/app/point/config"
v2net "github.com/v2ray/v2ray-core/common/net"
)
type Rule struct {
Type string `json:"type"`
OutboundTag string `json:"outboundTag"`
}
func (this *Rule) Tag() config.DetourTag {
return config.DetourTag(this.OutboundTag)
}
func (this *Rule) Apply(dest v2net.Destination) bool {
return false
}

View File

@@ -0,0 +1,5 @@
package config
type RouterRuleConfig interface {
Rules() []Rule
}

View File

@@ -0,0 +1,11 @@
package config
import (
"github.com/v2ray/v2ray-core/app/point/config"
v2net "github.com/v2ray/v2ray-core/common/net"
)
type Rule interface {
Tag() config.DetourTag
Apply(dest v2net.Destination) bool
}

View File

@@ -0,0 +1,51 @@
package rules
import (
"errors"
pointconfig "github.com/v2ray/v2ray-core/app/point/config"
"github.com/v2ray/v2ray-core/app/router"
"github.com/v2ray/v2ray-core/app/router/rules/config"
"github.com/v2ray/v2ray-core/app/router/rules/config/json"
v2net "github.com/v2ray/v2ray-core/common/net"
)
var (
InvalidRule = errors.New("Invalid Rule")
NoRuleApplicable = errors.New("No rule applicable")
EmptyTag = pointconfig.DetourTag("")
)
type Router struct {
rules []config.Rule
}
func (this *Router) TakeDetour(dest v2net.Destination) (pointconfig.DetourTag, error) {
for _, rule := range this.rules {
if rule.Apply(dest) {
return rule.Tag(), nil
}
}
return EmptyTag, NoRuleApplicable
}
type RouterFactory struct {
}
func (this *RouterFactory) Create(rawConfig interface{}) (router.Router, error) {
config := rawConfig.(*json.RouterRuleConfig)
rules := config.Rules()
for _, rule := range rules {
if rule == nil {
return nil, InvalidRule
}
}
return &Router{
rules: rules,
}, nil
}
func init() {
router.RegisterRouter("rules", &RouterFactory{})
}

View File

@@ -22,9 +22,7 @@ func (queue timedQueueImpl) Less(i, j int) bool {
}
func (queue timedQueueImpl) Swap(i, j int) {
tmp := queue[i]
queue[i] = queue[j]
queue[j] = tmp
queue[i], queue[j] = queue[j], queue[i]
}
func (queue *timedQueueImpl) Push(value interface{}) {
@@ -72,7 +70,7 @@ func (queue *TimedQueue) RemovedEntries() <-chan interface{} {
func (queue *TimedQueue) cleanup(tick <-chan time.Time) {
for now := range tick {
nowSec := now.UTC().Unix()
nowSec := now.Unix()
for {
queue.access.RLock()
queueLen := queue.queue.Len()

View File

@@ -12,7 +12,7 @@ func TestTimedQueue(t *testing.T) {
removed := make(map[string]bool)
nowSec := time.Now().UTC().Unix()
nowSec := time.Now().Unix()
q := NewTimedQueue(2)
go func() {
@@ -51,7 +51,7 @@ func TestTimedQueue(t *testing.T) {
<-tick
assert.Bool(removed["Values"]).IsFalse()
q.Add("Value1", time.Now().UTC().Unix()+10)
q.Add("Value1", time.Now().Unix()+10)
<-tick
v1, ok = removed["Value1"]

62
common/crypto/aes.go Normal file
View File

@@ -0,0 +1,62 @@
package crypto
import (
"crypto/aes"
"crypto/cipher"
"io"
)
func NewAesDecryptionStream(key []byte, iv []byte) (cipher.Stream, error) {
aesBlock, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return cipher.NewCFBDecrypter(aesBlock, iv), nil
}
func NewAesEncryptionStream(key []byte, iv []byte) (cipher.Stream, error) {
aesBlock, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return cipher.NewCFBEncrypter(aesBlock, iv), nil
}
type cryptionReader struct {
stream cipher.Stream
reader io.Reader
}
func NewCryptionReader(stream cipher.Stream, reader io.Reader) io.Reader {
return &cryptionReader{
stream: stream,
reader: reader,
}
}
func (this *cryptionReader) Read(data []byte) (int, error) {
nBytes, err := this.reader.Read(data)
if nBytes > 0 {
this.stream.XORKeyStream(data[:nBytes], data[:nBytes])
}
return nBytes, err
}
type cryptionWriter struct {
stream cipher.Stream
writer io.Writer
}
func NewCryptionWriter(stream cipher.Stream, writer io.Writer) io.Writer {
return &cryptionWriter{
stream: stream,
writer: writer,
}
}
func (this *cryptionWriter) Write(data []byte) (int, error) {
this.stream.XORKeyStream(data, data)
return this.writer.Write(data)
}

View File

@@ -1,27 +0,0 @@
package io
import (
"crypto/aes"
"crypto/cipher"
"io"
)
func NewAesDecryptReader(key []byte, iv []byte, reader io.Reader) (*CryptionReader, error) {
aesBlock, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aesStream := cipher.NewCFBDecrypter(aesBlock, iv)
return NewCryptionReader(aesStream, reader), nil
}
func NewAesEncryptWriter(key []byte, iv []byte, writer io.Writer) (*CryptionWriter, error) {
aesBlock, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aesStream := cipher.NewCFBEncrypter(aesBlock, iv)
return NewCryptionWriter(aesStream, writer), nil
}

View File

@@ -1,54 +0,0 @@
package io
import (
"crypto/cipher"
"io"
)
// CryptionReader is a general purpose reader that applies a stream cipher on top of a regular reader.
type CryptionReader struct {
stream cipher.Stream
reader io.Reader
}
// NewCryptionReader creates a new CryptionReader instance from given stream cipher and reader.
func NewCryptionReader(stream cipher.Stream, reader io.Reader) *CryptionReader {
return &CryptionReader{
stream: stream,
reader: reader,
}
}
// Read reads blocks from underlying reader, and crypt it. The content of blocks is modified in place.
func (reader CryptionReader) Read(blocks []byte) (int, error) {
nBytes, err := reader.reader.Read(blocks)
if nBytes > 0 {
reader.stream.XORKeyStream(blocks[:nBytes], blocks[:nBytes])
}
return nBytes, err
}
// Cryption writer is a general purpose of byte stream writer that applies a stream cipher on top of a regular writer.
type CryptionWriter struct {
stream cipher.Stream
writer io.Writer
}
// NewCryptionWriter creates a new CryptionWriter from given stream cipher and writer.
func NewCryptionWriter(stream cipher.Stream, writer io.Writer) *CryptionWriter {
return &CryptionWriter{
stream: stream,
writer: writer,
}
}
// Crypt crypts the content of blocks without writing them into the underlying writer.
func (writer CryptionWriter) Crypt(blocks []byte) {
writer.stream.XORKeyStream(blocks, blocks)
}
// Write crypts the content of blocks in place, and then writes the give blocks to underlying writer.
func (writer CryptionWriter) Write(blocks []byte) (int, error) {
writer.Crypt(blocks)
return writer.writer.Write(blocks)
}

View File

@@ -1,6 +1,7 @@
package log
import (
"bytes"
"testing"
"github.com/v2ray/v2ray-core/testing/unit"
@@ -17,3 +18,18 @@ func TestLogLevelSetting(t *testing.T) {
assert.Pointer(debugLogger).Equals(noOpLoggerInstance)
assert.Pointer(infoLogger).Equals(streamLoggerInstance)
}
func TestStreamLogger(t *testing.T) {
assert := unit.Assert(t)
buffer := bytes.NewBuffer(make([]byte, 0, 1024))
logger := &streamLogger{
writer: buffer,
}
logger.WriteLog("TestPrefix: ", "Test %s Format", "Stream Logger")
assert.Bytes(buffer.Bytes()).Equals([]byte("TestPrefix: Test Stream Logger Format\n"))
buffer.Reset()
logger.WriteLog("TestPrefix: ", "Test No Format")
assert.Bytes(buffer.Bytes()).Equals([]byte("TestPrefix: Test No Format\n"))
}

View File

@@ -0,0 +1,25 @@
package net
import (
"testing"
"github.com/v2ray/v2ray-core/testing/unit"
)
func TestTCPDestination(t *testing.T) {
assert := unit.Assert(t)
dest := NewTCPDestination(IPAddress([]byte{1, 2, 3, 4}, 80))
assert.Bool(dest.IsTCP()).IsTrue()
assert.Bool(dest.IsUDP()).IsFalse()
assert.String(dest.String()).Equals("tcp:1.2.3.4:80")
}
func TestUDPDestination(t *testing.T) {
assert := unit.Assert(t)
dest := NewUDPDestination(IPAddress([]byte{0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88}, 53))
assert.Bool(dest.IsTCP()).IsFalse()
assert.Bool(dest.IsUDP()).IsTrue()
assert.String(dest.String()).Equals("udp:[2001:4860:4860::8888]:53")
}

View File

@@ -0,0 +1,46 @@
package json
import (
"encoding/json"
"errors"
"strings"
v2net "github.com/v2ray/v2ray-core/common/net"
)
type NetworkList []string
func NewNetworkList(networks []string) NetworkList {
list := NetworkList(make([]string, len(networks)))
for idx, network := range networks {
list[idx] = strings.ToLower(strings.TrimSpace(network))
}
return list
}
func (this *NetworkList) UnmarshalJSON(data []byte) error {
var strList []string
err := json.Unmarshal(data, &strList)
if err == nil {
*this = NewNetworkList(strList)
return nil
}
var str string
err = json.Unmarshal(data, &str)
if err == nil {
strList := strings.Split(str, ",")
*this = NewNetworkList(strList)
return nil
}
return errors.New("Unknown format of network list: " + string(data))
}
func (this *NetworkList) HasNetwork(network v2net.Network) bool {
for _, value := range *this {
if value == string(network) {
return true
}
}
return false
}

View File

@@ -0,0 +1,28 @@
package json
import (
"encoding/json"
"testing"
"github.com/v2ray/v2ray-core/testing/unit"
)
func TestArrayNetworkList(t *testing.T) {
assert := unit.Assert(t)
var list NetworkList
err := json.Unmarshal([]byte("[\"Tcp\"]"), &list)
assert.Error(err).IsNil()
assert.Bool(list.HasNetwork("tcp")).IsTrue()
assert.Bool(list.HasNetwork("udp")).IsFalse()
}
func TestStringNetworkList(t *testing.T) {
assert := unit.Assert(t)
var list NetworkList
err := json.Unmarshal([]byte("\"TCP, ip\""), &list)
assert.Error(err).IsNil()
assert.Bool(list.HasNetwork("tcp")).IsTrue()
assert.Bool(list.HasNetwork("udp")).IsFalse()
}

View File

@@ -0,0 +1,79 @@
package json
import (
"encoding/json"
"errors"
"strconv"
"strings"
"github.com/v2ray/v2ray-core/common/log"
)
var (
InvalidPortRange = errors.New("Invalid port range.")
)
type PortRange struct {
from uint16
to uint16
}
func (this *PortRange) From() uint16 {
return this.from
}
func (this *PortRange) To() uint16 {
return this.to
}
func (this *PortRange) UnmarshalJSON(data []byte) error {
var maybeint int
err := json.Unmarshal(data, &maybeint)
if err == nil {
if maybeint <= 0 || maybeint >= 65535 {
log.Error("Invalid port [%s]", string(data))
return InvalidPortRange
}
this.from = uint16(maybeint)
this.to = uint16(maybeint)
return nil
}
var maybestring string
err = json.Unmarshal(data, &maybestring)
if err == nil {
pair := strings.SplitN(maybestring, "-", 2)
if len(pair) == 1 {
value, err := strconv.Atoi(pair[0])
if err != nil || value <= 0 || value >= 65535 {
log.Error("Invalid from port %s", pair[0])
return InvalidPortRange
}
this.from = uint16(value)
this.to = uint16(value)
return nil
} else if len(pair) == 2 {
from, err := strconv.Atoi(pair[0])
if err != nil || from <= 0 || from >= 65535 {
log.Error("Invalid from port %s", pair[0])
return InvalidPortRange
}
this.from = uint16(from)
to, err := strconv.Atoi(pair[1])
if err != nil || to <= 0 || to >= 65535 {
log.Error("Invalid to port %s", pair[1])
return InvalidPortRange
}
this.to = uint16(to)
if this.from > this.to {
log.Error("Invalid port range %d -> %d", this.from, this.to)
return InvalidPortRange
}
return nil
}
}
return InvalidPortRange
}

View File

@@ -0,0 +1,69 @@
package json
import (
"encoding/json"
"testing"
"github.com/v2ray/v2ray-core/testing/unit"
)
func TestIntPort(t *testing.T) {
assert := unit.Assert(t)
var portRange PortRange
err := json.Unmarshal([]byte("1234"), &portRange)
assert.Error(err).IsNil()
assert.Uint16(portRange.from).Equals(uint16(1234))
assert.Uint16(portRange.to).Equals(uint16(1234))
}
func TestOverRangeIntPort(t *testing.T) {
assert := unit.Assert(t)
var portRange PortRange
err := json.Unmarshal([]byte("70000"), &portRange)
assert.Error(err).Equals(InvalidPortRange)
err = json.Unmarshal([]byte("-1"), &portRange)
assert.Error(err).Equals(InvalidPortRange)
}
func TestSingleStringPort(t *testing.T) {
assert := unit.Assert(t)
var portRange PortRange
err := json.Unmarshal([]byte("\"1234\""), &portRange)
assert.Error(err).IsNil()
assert.Uint16(portRange.from).Equals(uint16(1234))
assert.Uint16(portRange.to).Equals(uint16(1234))
}
func TestStringPairPort(t *testing.T) {
assert := unit.Assert(t)
var portRange PortRange
err := json.Unmarshal([]byte("\"1234-5678\""), &portRange)
assert.Error(err).IsNil()
assert.Uint16(portRange.from).Equals(uint16(1234))
assert.Uint16(portRange.to).Equals(uint16(5678))
}
func TestOverRangeStringPort(t *testing.T) {
assert := unit.Assert(t)
var portRange PortRange
err := json.Unmarshal([]byte("\"65536\""), &portRange)
assert.Error(err).Equals(InvalidPortRange)
err = json.Unmarshal([]byte("\"70000-80000\""), &portRange)
assert.Error(err).Equals(InvalidPortRange)
err = json.Unmarshal([]byte("\"1-90000\""), &portRange)
assert.Error(err).Equals(InvalidPortRange)
err = json.Unmarshal([]byte("\"700-600\""), &portRange)
assert.Error(err).Equals(InvalidPortRange)
}

12
common/net/network.go Normal file
View File

@@ -0,0 +1,12 @@
package net
const (
TCPNetwork = Network("tcp")
UDPNetwork = Network("udp")
)
type Network string
type NetworkList interface {
HasNetwork(Network) bool
}

6
common/net/portrange.go Normal file
View File

@@ -0,0 +1,6 @@
package net
type PortRange interface {
From() uint16
To() uint16
}

View File

@@ -0,0 +1,13 @@
package testing
import (
"sync/atomic"
)
var (
port = int32(30000)
)
func PickPort() uint16 {
return uint16(atomic.AddInt32(&port, 1))
}

View File

@@ -0,0 +1,14 @@
package testing
type PortRange struct {
FromValue uint16
ToValue uint16
}
func (this *PortRange) From() uint16 {
return this.FromValue
}
func (this *PortRange) To() uint16 {
return this.ToValue
}

View File

@@ -1,6 +1,7 @@
package net
import (
"io"
"net"
"time"
)
@@ -12,21 +13,19 @@ var (
type TimeOutReader struct {
timeout int
connection net.Conn
worker io.Reader
}
func NewTimeOutReader(timeout int, connection net.Conn) *TimeOutReader {
return &TimeOutReader{
timeout: timeout,
reader := &TimeOutReader{
connection: connection,
}
reader.SetTimeOut(timeout)
return reader
}
func (reader *TimeOutReader) Read(p []byte) (n int, err error) {
deadline := time.Duration(reader.timeout) * time.Second
reader.connection.SetReadDeadline(time.Now().Add(deadline))
n, err = reader.connection.Read(p)
reader.connection.SetReadDeadline(emptyTime)
return
func (reader *TimeOutReader) Read(p []byte) (int, error) {
return reader.worker.Read(p)
}
func (reader *TimeOutReader) GetTimeOut() int {
@@ -35,4 +34,35 @@ func (reader *TimeOutReader) GetTimeOut() int {
func (reader *TimeOutReader) SetTimeOut(value int) {
reader.timeout = value
if value > 0 {
reader.worker = &timedReaderWorker{
timeout: value,
connection: reader.connection,
}
} else {
reader.worker = &noOpReaderWorker{
connection: reader.connection,
}
}
}
type timedReaderWorker struct {
timeout int
connection net.Conn
}
func (this *timedReaderWorker) Read(p []byte) (int, error) {
deadline := time.Duration(this.timeout) * time.Second
this.connection.SetReadDeadline(time.Now().Add(deadline))
nBytes, err := this.connection.Read(p)
this.connection.SetReadDeadline(emptyTime)
return nBytes, err
}
type noOpReaderWorker struct {
connection net.Conn
}
func (this *noOpReaderWorker) Read(p []byte) (int, error) {
return this.connection.Read(p)
}

View File

@@ -0,0 +1,80 @@
package retry
import (
"errors"
"testing"
"time"
"github.com/v2ray/v2ray-core/testing/unit"
)
var (
TestError = errors.New("This is a fake error.")
)
func TestNoRetry(t *testing.T) {
assert := unit.Assert(t)
startTime := time.Now().Unix()
err := Timed(10, 100000).On(func() error {
return nil
})
endTime := time.Now().Unix()
assert.Error(err).IsNil()
assert.Int64(endTime - startTime).AtLeast(0)
}
func TestRetryOnce(t *testing.T) {
assert := unit.Assert(t)
startTime := time.Now()
called := 0
err := Timed(10, 1000).On(func() error {
if called == 0 {
called++
return TestError
}
return nil
})
duration := time.Since(startTime)
assert.Error(err).IsNil()
assert.Int64(int64(duration / time.Millisecond)).AtLeast(900)
}
func TestRetryMultiple(t *testing.T) {
assert := unit.Assert(t)
startTime := time.Now()
called := 0
err := Timed(10, 1000).On(func() error {
if called < 5 {
called++
return TestError
}
return nil
})
duration := time.Since(startTime)
assert.Error(err).IsNil()
assert.Int64(int64(duration / time.Millisecond)).AtLeast(4900)
}
func TestRetryExhausted(t *testing.T) {
assert := unit.Assert(t)
startTime := time.Now()
called := 0
err := Timed(2, 1000).On(func() error {
if called < 5 {
called++
return TestError
}
return nil
})
duration := time.Since(startTime)
assert.Error(err).Equals(RetryFailed)
assert.Int64(int64(duration / time.Millisecond)).AtLeast(1900)
}

View File

@@ -1,24 +0,0 @@
package config
type Type string
const (
TypeInbound = Type("inbound")
TypeOutbound = Type("outbound")
)
type ConnectionConfig interface {
Protocol() string
Settings(configType Type) interface{}
}
type LogConfig interface {
AccessLog() string
}
type PointConfig interface {
Port() uint16
LogConfig() LogConfig
InboundConfig() ConnectionConfig
OutboundConfig() ConnectionConfig
}

View File

@@ -1,20 +0,0 @@
package json
import (
"github.com/v2ray/v2ray-core/config"
)
type ConfigObjectCreator func() interface{}
var (
configCache = make(map[string]ConfigObjectCreator)
)
func getConfigKey(protocol string, cType config.Type) string {
return protocol + "_" + string(cType)
}
func RegisterConfigType(protocol string, cType config.Type, creator ConfigObjectCreator) {
// TODO: check name
configCache[getConfigKey(protocol, cType)] = creator
}

View File

@@ -1,92 +0,0 @@
package json
import (
"encoding/json"
"io/ioutil"
"os"
"github.com/v2ray/v2ray-core/common/log"
"github.com/v2ray/v2ray-core/config"
)
type ConnectionConfig struct {
ProtocolString string `json:"protocol"`
SettingsMessage json.RawMessage `json:"settings"`
}
func (config *ConnectionConfig) Protocol() string {
return config.ProtocolString
}
func (config *ConnectionConfig) Settings(configType config.Type) interface{} {
creator, found := configCache[getConfigKey(config.Protocol(), configType)]
if !found {
panic("Unknown protocol " + config.Protocol())
}
configObj := creator()
err := json.Unmarshal(config.SettingsMessage, configObj)
if err != nil {
log.Error("Unable to parse connection config: %v", err)
panic("Failed to parse connection config.")
}
return configObj
}
type LogConfig struct {
AccessLogValue string `json:"access"`
}
func (config *LogConfig) AccessLog() string {
return config.AccessLogValue
}
// Config is the config for Point server.
type Config struct {
PortValue uint16 `json:"port"` // Port of this Point server.
LogConfigValue *LogConfig `json:"log"`
InboundConfigValue *ConnectionConfig `json:"inbound"`
OutboundConfigValue *ConnectionConfig `json:"outbound"`
}
func (config *Config) Port() uint16 {
return config.PortValue
}
func (config *Config) LogConfig() config.LogConfig {
if config.LogConfigValue == nil {
return nil
}
return config.LogConfigValue
}
func (config *Config) InboundConfig() config.ConnectionConfig {
if config.InboundConfigValue == nil {
return nil
}
return config.InboundConfigValue
}
func (config *Config) OutboundConfig() config.ConnectionConfig {
if config.OutboundConfigValue == nil {
return nil
}
return config.OutboundConfigValue
}
func LoadConfig(file string) (*Config, error) {
fixedFile := os.ExpandEnv(file)
rawConfig, err := ioutil.ReadFile(fixedFile)
if err != nil {
log.Error("Failed to read server config file (%s): %v", file, err)
return nil, err
}
jsonConfig := &Config{}
err = json.Unmarshal(rawConfig, jsonConfig)
if err != nil {
log.Error("Failed to load server config: %v", err)
return nil, err
}
return jsonConfig, err
}

View File

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

View File

@@ -0,0 +1,40 @@
package blackhole
import (
"io/ioutil"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
"github.com/v2ray/v2ray-core/transport/ray"
)
// BlackHole is an outbound connection that sliently swallow the entire payload.
type BlackHole struct {
}
func NewBlackHole() *BlackHole {
return &BlackHole{}
}
func (bh *BlackHole) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) error {
if chunk := firstPacket.Chunk(); chunk != nil {
chunk.Release()
}
close(ray.OutboundOutput())
if firstPacket.MoreChunks() {
v2net.ChanToWriter(ioutil.Discard, ray.OutboundInput())
}
return nil
}
type BlackHoleFactory struct {
}
func (factory BlackHoleFactory) Create(config interface{}) (connhandler.OutboundConnectionHandler, error) {
return NewBlackHole(), nil
}
func init() {
connhandler.RegisterOutboundConnectionHandlerFactory("blackhole", BlackHoleFactory{})
}

View File

@@ -0,0 +1,14 @@
package json
import (
"github.com/v2ray/v2ray-core/proxy/common/config/json"
)
type BlackHoleConfig struct {
}
func init() {
json.RegisterOutboundConnectionConfig("blackhole", func() interface{} {
return new(BlackHoleConfig)
})
}

View File

@@ -0,0 +1,9 @@
package config
import (
"errors"
)
var (
BadConfiguration = errors.New("Bad proxy configuration.")
)

View File

@@ -0,0 +1,45 @@
package json
import (
"github.com/v2ray/v2ray-core/proxy/common/config"
)
type ConfigObjectCreator func() interface{}
var (
configCache map[string]ConfigObjectCreator
)
func getConfigKey(protocol string, cType config.Type) string {
return protocol + "_" + string(cType)
}
func registerConfigType(protocol string, cType config.Type, creator ConfigObjectCreator) error {
// TODO: check name
configCache[getConfigKey(protocol, cType)] = creator
return nil
}
func RegisterInboundConnectionConfig(protocol string, creator ConfigObjectCreator) error {
return registerConfigType(protocol, config.TypeInbound, creator)
}
func RegisterOutboundConnectionConfig(protocol string, creator ConfigObjectCreator) error {
return registerConfigType(protocol, config.TypeOutbound, creator)
}
func CreateConfig(protocol string, cType config.Type) interface{} {
creator, found := configCache[getConfigKey(protocol, cType)]
if !found {
return nil
}
return creator()
}
func initializeConfigCache() {
configCache = make(map[string]ConfigObjectCreator)
}
func init() {
initializeConfigCache()
}

View File

@@ -0,0 +1,46 @@
package json
import (
"testing"
"github.com/v2ray/v2ray-core/proxy/common/config"
"github.com/v2ray/v2ray-core/testing/unit"
)
func TestRegisterInboundConfig(t *testing.T) {
assert := unit.Assert(t)
initializeConfigCache()
protocol := "test_protocol"
creator := func() interface{} {
return true
}
err := RegisterInboundConnectionConfig(protocol, creator)
assert.Error(err).IsNil()
configObj := CreateConfig(protocol, config.TypeInbound)
assert.Bool(configObj.(bool)).IsTrue()
configObj = CreateConfig(protocol, config.TypeOutbound)
assert.Pointer(configObj).IsNil()
}
func TestRegisterOutboundConfig(t *testing.T) {
assert := unit.Assert(t)
initializeConfigCache()
protocol := "test_protocol"
creator := func() interface{} {
return true
}
err := RegisterOutboundConnectionConfig(protocol, creator)
assert.Error(err).IsNil()
configObj := CreateConfig(protocol, config.TypeOutbound)
assert.Bool(configObj.(bool)).IsTrue()
configObj = CreateConfig(protocol, config.TypeInbound)
assert.Pointer(configObj).IsNil()
}

View File

@@ -0,0 +1,8 @@
package config
type Type string
const (
TypeInbound = Type("inbound")
TypeOutbound = Type("outbound")
)

View File

@@ -1,4 +1,4 @@
package proxy
package connhandler
import (
"github.com/v2ray/v2ray-core/app"

View File

@@ -1,4 +1,4 @@
package proxy
package connhandler
import (
v2net "github.com/v2ray/v2ray-core/common/net"

View File

@@ -1,4 +1,4 @@
package proxy
package connhandler
var (
inboundFactories = make(map[string]InboundConnectionHandlerFactory)

View File

@@ -1,4 +1,4 @@
package proxy
package errors
import (
"errors"

View File

@@ -0,0 +1,19 @@
package json
import (
v2netjson "github.com/v2ray/v2ray-core/common/net/json"
"github.com/v2ray/v2ray-core/proxy/common/config/json"
)
type DokodemoConfig struct {
Host string `json:"address"`
Port int `json:"port"`
Network *v2netjson.NetworkList `json:"network"`
Timeout int `json:"timeout"`
}
func init() {
json.RegisterInboundConnectionConfig("dokodemo-door", func() interface{} {
return new(DokodemoConfig)
})
}

145
proxy/dokodemo/dokodemo.go Normal file
View File

@@ -0,0 +1,145 @@
package dokodemo
import (
"io"
"net"
"sync"
"github.com/v2ray/v2ray-core/app"
"github.com/v2ray/v2ray-core/common/alloc"
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/common/retry"
"github.com/v2ray/v2ray-core/proxy/dokodemo/config/json"
)
type DokodemoDoor struct {
config *json.DokodemoConfig
accepting bool
address v2net.Address
dispatcher app.PacketDispatcher
}
func NewDokodemoDoor(dispatcher app.PacketDispatcher, config *json.DokodemoConfig) *DokodemoDoor {
d := &DokodemoDoor{
config: config,
dispatcher: dispatcher,
}
ip := net.ParseIP(config.Host)
if ip != nil {
d.address = v2net.IPAddress(ip, uint16(config.Port))
} else {
d.address = v2net.DomainAddress(config.Host, uint16(config.Port))
}
return d
}
func (this *DokodemoDoor) Listen(port uint16) error {
this.accepting = true
if this.config.Network.HasNetwork(v2net.TCPNetwork) {
err := this.ListenTCP(port)
if err != nil {
return err
}
}
if this.config.Network.HasNetwork(v2net.UDPNetwork) {
err := this.ListenUDP(port)
if err != nil {
return err
}
}
return nil
}
func (this *DokodemoDoor) ListenUDP(port uint16) error {
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{
IP: []byte{0, 0, 0, 0},
Port: int(port),
Zone: "",
})
if err != nil {
log.Error("Dokodemo failed to listen on port %d: %v", port, err)
return err
}
go this.handleUDPPackets(udpConn)
return nil
}
func (this *DokodemoDoor) handleUDPPackets(udpConn *net.UDPConn) {
defer udpConn.Close()
for this.accepting {
buffer := alloc.NewBuffer()
nBytes, addr, err := udpConn.ReadFromUDP(buffer.Value)
buffer.Slice(0, nBytes)
if err != nil {
buffer.Release()
log.Error("Dokodemo failed to read from UDP: %v", err)
return
}
packet := v2net.NewPacket(v2net.NewUDPDestination(this.address), buffer, false)
ray := this.dispatcher.DispatchToOutbound(packet)
close(ray.InboundInput())
for payload := range ray.InboundOutput() {
udpConn.WriteToUDP(payload.Value, addr)
}
}
}
func (this *DokodemoDoor) ListenTCP(port uint16) error {
tcpListener, err := net.ListenTCP("tcp", &net.TCPAddr{
IP: []byte{0, 0, 0, 0},
Port: int(port),
Zone: "",
})
if err != nil {
log.Error("Dokodemo failed to listen on port %d: %v", port, err)
return err
}
go this.AcceptTCPConnections(tcpListener)
return nil
}
func (this *DokodemoDoor) AcceptTCPConnections(tcpListener *net.TCPListener) {
for this.accepting {
retry.Timed(100, 100).On(func() error {
connection, err := tcpListener.AcceptTCP()
if err != nil {
log.Error("Dokodemo failed to accept new connections: %v", err)
return err
}
go this.HandleTCPConnection(connection)
return nil
})
}
}
func (this *DokodemoDoor) HandleTCPConnection(conn *net.TCPConn) {
defer conn.Close()
packet := v2net.NewPacket(v2net.NewTCPDestination(this.address), nil, true)
ray := this.dispatcher.DispatchToOutbound(packet)
var inputFinish, outputFinish sync.Mutex
inputFinish.Lock()
outputFinish.Lock()
reader := v2net.NewTimeOutReader(this.config.Timeout, conn)
go dumpInput(reader, ray.InboundInput(), &inputFinish)
go dumpOutput(conn, ray.InboundOutput(), &outputFinish)
outputFinish.Lock()
}
func dumpInput(reader io.Reader, input chan<- *alloc.Buffer, finish *sync.Mutex) {
v2net.ReaderToChan(input, reader)
finish.Unlock()
close(input)
}
func dumpOutput(writer io.Writer, output <-chan *alloc.Buffer, finish *sync.Mutex) {
v2net.ChanToWriter(writer, output)
finish.Unlock()
}

View File

@@ -0,0 +1,19 @@
package dokodemo
import (
"github.com/v2ray/v2ray-core/app"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
"github.com/v2ray/v2ray-core/proxy/dokodemo/config/json"
)
type DokodemoDoorFactory struct {
}
func (this DokodemoDoorFactory) Create(dispatcher app.PacketDispatcher, rawConfig interface{}) (connhandler.InboundConnectionHandler, error) {
config := rawConfig.(*json.DokodemoConfig)
return NewDokodemoDoor(dispatcher, config), nil
}
func init() {
connhandler.RegisterInboundConnectionHandlerFactory("dokodemo-door", DokodemoDoorFactory{})
}

View File

@@ -0,0 +1,139 @@
package dokodemo
import (
"net"
"testing"
"github.com/v2ray/v2ray-core/app/point"
"github.com/v2ray/v2ray-core/app/point/config/testing/mocks"
v2netjson "github.com/v2ray/v2ray-core/common/net/json"
v2nettesting "github.com/v2ray/v2ray-core/common/net/testing"
"github.com/v2ray/v2ray-core/proxy/dokodemo/config/json"
_ "github.com/v2ray/v2ray-core/proxy/freedom"
"github.com/v2ray/v2ray-core/testing/servers/tcp"
"github.com/v2ray/v2ray-core/testing/servers/udp"
"github.com/v2ray/v2ray-core/testing/unit"
)
func TestDokodemoTCP(t *testing.T) {
assert := unit.Assert(t)
port := v2nettesting.PickPort()
data2Send := "Data to be sent to remote."
tcpServer := &tcp.Server{
Port: port,
MsgProcessor: func(data []byte) []byte {
buffer := make([]byte, 0, 2048)
buffer = append(buffer, []byte("Processed: ")...)
buffer = append(buffer, data...)
return buffer
},
}
_, err := tcpServer.Start()
assert.Error(err).IsNil()
pointPort := v2nettesting.PickPort()
networkList := v2netjson.NetworkList([]string{"tcp"})
config := mocks.Config{
PortValue: pointPort,
InboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "dokodemo-door",
SettingsValue: &json.DokodemoConfig{
Host: "127.0.0.1",
Port: int(port),
Network: &networkList,
Timeout: 0,
},
},
OutboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "freedom",
SettingsValue: nil,
},
}
point, err := point.NewPoint(&config)
assert.Error(err).IsNil()
err = point.Start()
assert.Error(err).IsNil()
tcpClient, err := net.DialTCP("tcp", nil, &net.TCPAddr{
IP: []byte{127, 0, 0, 1},
Port: int(pointPort),
Zone: "",
})
assert.Error(err).IsNil()
tcpClient.Write([]byte(data2Send))
tcpClient.CloseWrite()
response := make([]byte, 1024)
nBytes, err := tcpClient.Read(response)
assert.Error(err).IsNil()
tcpClient.Close()
assert.String("Processed: " + data2Send).Equals(string(response[:nBytes]))
}
func TestDokodemoUDP(t *testing.T) {
assert := unit.Assert(t)
port := v2nettesting.PickPort()
data2Send := "Data to be sent to remote."
udpServer := &udp.Server{
Port: port,
MsgProcessor: func(data []byte) []byte {
buffer := make([]byte, 0, 2048)
buffer = append(buffer, []byte("Processed: ")...)
buffer = append(buffer, data...)
return buffer
},
}
_, err := udpServer.Start()
assert.Error(err).IsNil()
pointPort := v2nettesting.PickPort()
networkList := v2netjson.NetworkList([]string{"udp"})
config := mocks.Config{
PortValue: pointPort,
InboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "dokodemo-door",
SettingsValue: &json.DokodemoConfig{
Host: "127.0.0.1",
Port: int(port),
Network: &networkList,
Timeout: 0,
},
},
OutboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "freedom",
SettingsValue: nil,
},
}
point, err := point.NewPoint(&config)
assert.Error(err).IsNil()
err = point.Start()
assert.Error(err).IsNil()
udpClient, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: []byte{127, 0, 0, 1},
Port: int(pointPort),
Zone: "",
})
assert.Error(err).IsNil()
udpClient.Write([]byte(data2Send))
response := make([]byte, 1024)
nBytes, err := udpClient.Read(response)
assert.Error(err).IsNil()
udpClient.Close()
assert.String("Processed: " + data2Send).Equals(string(response[:nBytes]))
}

View File

@@ -1,15 +1,14 @@
package json
import (
"github.com/v2ray/v2ray-core/config"
"github.com/v2ray/v2ray-core/config/json"
"github.com/v2ray/v2ray-core/proxy/common/config/json"
)
type FreedomConfiguration struct {
}
func init() {
json.RegisterConfigType("freedom", config.TypeOutbound, func() interface{} {
json.RegisterOutboundConnectionConfig("freedom", func() interface{} {
return &FreedomConfiguration{}
})
}

View File

@@ -2,6 +2,7 @@ package freedom
import (
"bytes"
"fmt"
"io/ioutil"
"net"
"testing"
@@ -9,12 +10,14 @@ import (
"golang.org/x/net/proxy"
"github.com/v2ray/v2ray-core/app/point"
"github.com/v2ray/v2ray-core/app/point/config/testing/mocks"
"github.com/v2ray/v2ray-core/common/alloc"
v2net "github.com/v2ray/v2ray-core/common/net"
v2proxy "github.com/v2ray/v2ray-core/proxy"
v2nettesting "github.com/v2ray/v2ray-core/common/net/testing"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
_ "github.com/v2ray/v2ray-core/proxy/socks"
"github.com/v2ray/v2ray-core/proxy/socks/config/json"
"github.com/v2ray/v2ray-core/testing/mocks"
proxymocks "github.com/v2ray/v2ray-core/proxy/testing/mocks"
"github.com/v2ray/v2ray-core/testing/servers/tcp"
"github.com/v2ray/v2ray-core/testing/servers/udp"
"github.com/v2ray/v2ray-core/testing/unit"
@@ -38,14 +41,15 @@ func TestUDPSend(t *testing.T) {
udpServerAddr, err := udpServer.Start()
assert.Error(err).IsNil()
ich := &mocks.InboundConnectionHandler{
Data2Send: []byte("Not Used"),
DataReturned: bytes.NewBuffer(make([]byte, 0, 1024)),
connOutput := bytes.NewBuffer(make([]byte, 0, 1024))
ich := &proxymocks.InboundConnectionHandler{
ConnInput: bytes.NewReader([]byte("Not Used")),
ConnOutput: connOutput,
}
v2proxy.RegisterInboundConnectionHandlerFactory("mock_ich", ich)
connhandler.RegisterInboundConnectionHandlerFactory("mock_ich", ich)
pointPort := uint16(38724)
pointPort := v2nettesting.PickPort()
config := mocks.Config{
PortValue: pointPort,
InboundConfigValue: &mocks.ConnectionConfig{
@@ -64,17 +68,16 @@ func TestUDPSend(t *testing.T) {
err = point.Start()
assert.Error(err).IsNil()
data2SendBuffer := alloc.NewBuffer()
data2SendBuffer.Clear()
data2SendBuffer := alloc.NewBuffer().Clear()
data2SendBuffer.Append([]byte(data2Send))
dest := v2net.NewUDPDestination(udpServerAddr)
ich.Communicate(v2net.NewPacket(dest, data2SendBuffer, false))
assert.Bytes(ich.DataReturned.Bytes()).Equals([]byte("Processed: Data to be sent to remote"))
assert.Bytes(connOutput.Bytes()).Equals([]byte("Processed: Data to be sent to remote"))
}
func TestSocksTcpConnect(t *testing.T) {
assert := unit.Assert(t)
port := uint16(38293)
port := v2nettesting.PickPort()
data2Send := "Data to be sent to remote"
@@ -90,7 +93,7 @@ func TestSocksTcpConnect(t *testing.T) {
_, err := tcpServer.Start()
assert.Error(err).IsNil()
pointPort := uint16(38724)
pointPort := v2nettesting.PickPort()
config := mocks.Config{
PortValue: pointPort,
InboundConfigValue: &mocks.ConnectionConfig{
@@ -111,10 +114,10 @@ func TestSocksTcpConnect(t *testing.T) {
err = point.Start()
assert.Error(err).IsNil()
socks5Client, err := proxy.SOCKS5("tcp", "127.0.0.1:38724", nil, proxy.Direct)
socks5Client, err := proxy.SOCKS5("tcp", fmt.Sprintf("127.0.0.1:%d", pointPort), nil, proxy.Direct)
assert.Error(err).IsNil()
targetServer := "127.0.0.1:38293"
targetServer := fmt.Sprintf("127.0.0.1:%d", port)
conn, err := socks5Client.Dial("tcp", targetServer)
assert.Error(err).IsNil()

View File

@@ -1,16 +1,16 @@
package freedom
import (
"github.com/v2ray/v2ray-core/proxy"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
)
type FreedomFactory struct {
}
func (factory FreedomFactory) Create(config interface{}) (proxy.OutboundConnectionHandler, error) {
func (factory FreedomFactory) Create(config interface{}) (connhandler.OutboundConnectionHandler, error) {
return NewFreedomConnection(), nil
}
func init() {
proxy.RegisterOutboundConnectionHandlerFactory("freedom", FreedomFactory{})
connhandler.RegisterOutboundConnectionHandlerFactory("freedom", FreedomFactory{})
}

View File

@@ -0,0 +1,14 @@
package json
import (
"github.com/v2ray/v2ray-core/proxy/common/config/json"
)
type HttpProxyConfig struct {
}
func init() {
json.RegisterInboundConnectionConfig("http", func() interface{} {
return new(HttpProxyConfig)
})
}

36
proxy/http/http.go Normal file
View File

@@ -0,0 +1,36 @@
package http
import (
"net"
// "net/http"
"github.com/v2ray/v2ray-core/app"
"github.com/v2ray/v2ray-core/common/log"
jsonconfig "github.com/v2ray/v2ray-core/proxy/http/config/json"
)
type HttpProxyServer struct {
accepting bool
dispatcher app.PacketDispatcher
config *jsonconfig.HttpProxyConfig
}
func NewHttpProxyServer(dispatcher app.PacketDispatcher, config *jsonconfig.HttpProxyConfig) *HttpProxyServer {
return &HttpProxyServer{
dispatcher: dispatcher,
config: config,
}
}
func (server *HttpProxyServer) Listen(port uint16) error {
_, err := net.ListenTCP("tcp", &net.TCPAddr{
IP: []byte{0, 0, 0, 0},
Port: int(port),
Zone: "",
})
if err != nil {
log.Error("HTTP Proxy failed to listen on port %d: %v", port, err)
return err
}
return nil
}

View File

@@ -1,10 +1,11 @@
package json
import (
"encoding/json"
"errors"
"net"
"github.com/v2ray/v2ray-core/config"
"github.com/v2ray/v2ray-core/config/json"
jsonconfig "github.com/v2ray/v2ray-core/proxy/common/config/json"
)
const (
@@ -17,28 +18,49 @@ type SocksAccount struct {
Password string `json:"pass"`
}
type SocksConfig struct {
AuthMethod string `json:"auth"`
Accounts []SocksAccount `json:"accounts"`
UDPEnabled bool `json:"udp"`
HostIP string `json:"ip"`
type SocksAccountMap map[string]string
accountMap map[string]string
ip net.IP
func (this *SocksAccountMap) UnmarshalJSON(data []byte) error {
var accounts []SocksAccount
err := json.Unmarshal(data, &accounts)
if err != nil {
return err
}
*this = make(map[string]string)
for _, account := range accounts {
(*this)[account.Username] = account.Password
}
return nil
}
func (sc *SocksConfig) Initialize() {
sc.accountMap = make(map[string]string)
for _, account := range sc.Accounts {
sc.accountMap[account.Username] = account.Password
func (this *SocksAccountMap) HasAccount(user, pass string) bool {
if actualPass, found := (*this)[user]; found {
return actualPass == pass
}
return false
}
if len(sc.HostIP) > 0 {
sc.ip = net.ParseIP(sc.HostIP)
if sc.ip == nil {
sc.ip = net.IPv4(127, 0, 0, 1)
}
type IPAddress net.IP
func (this *IPAddress) UnmarshalJSON(data []byte) error {
var ipStr string
err := json.Unmarshal(data, &ipStr)
if err != nil {
return err
}
ip := net.ParseIP(ipStr)
if ip == nil {
return errors.New("Unknown IP format: " + ipStr)
}
*this = IPAddress(ip)
return nil
}
type SocksConfig struct {
AuthMethod string `json:"auth"`
Accounts SocksAccountMap `json:"accounts"`
UDPEnabled bool `json:"udp"`
HostIP IPAddress `json:"ip"`
}
func (sc *SocksConfig) IsNoAuth() bool {
@@ -50,18 +72,17 @@ func (sc *SocksConfig) IsPassword() bool {
}
func (sc *SocksConfig) HasAccount(user, pass string) bool {
if actualPass, found := sc.accountMap[user]; found {
return actualPass == pass
}
return false
return sc.Accounts.HasAccount(user, pass)
}
func (sc *SocksConfig) IP() net.IP {
return sc.ip
return net.IP(sc.HostIP)
}
func init() {
json.RegisterConfigType("socks", config.TypeInbound, func() interface{} {
return new(SocksConfig)
jsonconfig.RegisterInboundConnectionConfig("socks", func() interface{} {
return &SocksConfig{
HostIP: IPAddress(net.IPv4(127, 0, 0, 1)),
}
})
}

View File

@@ -0,0 +1,64 @@
package json
import (
"encoding/json"
"net"
"testing"
"github.com/v2ray/v2ray-core/proxy/common/config"
jsonconfig "github.com/v2ray/v2ray-core/proxy/common/config/json"
"github.com/v2ray/v2ray-core/testing/unit"
)
func TestAccountMapParsing(t *testing.T) {
assert := unit.Assert(t)
var accountMap SocksAccountMap
err := json.Unmarshal([]byte("[{\"user\": \"a\", \"pass\":\"b\"}, {\"user\": \"c\", \"pass\":\"d\"}]"), &accountMap)
assert.Error(err).IsNil()
assert.Bool(accountMap.HasAccount("a", "b")).IsTrue()
assert.Bool(accountMap.HasAccount("a", "c")).IsFalse()
assert.Bool(accountMap.HasAccount("c", "d")).IsTrue()
assert.Bool(accountMap.HasAccount("e", "d")).IsFalse()
}
func TestDefaultIPAddress(t *testing.T) {
assert := unit.Assert(t)
socksConfig := jsonconfig.CreateConfig("socks", config.TypeInbound).(*SocksConfig)
assert.String(socksConfig.IP().String()).Equals("127.0.0.1")
}
func TestIPAddressParsing(t *testing.T) {
assert := unit.Assert(t)
var ipAddress IPAddress
err := json.Unmarshal([]byte("\"1.2.3.4\""), &ipAddress)
assert.Error(err).IsNil()
assert.String(net.IP(ipAddress).String()).Equals("1.2.3.4")
}
func TestNoAuthConfig(t *testing.T) {
assert := unit.Assert(t)
var config SocksConfig
err := json.Unmarshal([]byte("{\"auth\":\"noauth\", \"ip\":\"8.8.8.8\"}"), &config)
assert.Error(err).IsNil()
assert.Bool(config.IsNoAuth()).IsTrue()
assert.Bool(config.IsPassword()).IsFalse()
assert.String(config.IP().String()).Equals("8.8.8.8")
assert.Bool(config.UDPEnabled).IsFalse()
}
func TestUserPassConfig(t *testing.T) {
assert := unit.Assert(t)
var config SocksConfig
err := json.Unmarshal([]byte("{\"auth\":\"password\", \"accounts\":[{\"user\":\"x\", \"pass\":\"y\"}], \"udp\":true}"), &config)
assert.Error(err).IsNil()
assert.Bool(config.IsNoAuth()).IsFalse()
assert.Bool(config.IsPassword()).IsTrue()
assert.Bool(config.HasAccount("x", "y")).IsTrue()
assert.Bool(config.UDPEnabled).IsTrue()
}

View File

@@ -7,7 +7,7 @@ import (
"github.com/v2ray/v2ray-core/common/alloc"
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy"
proxyerrors "github.com/v2ray/v2ray-core/proxy/common/errors"
"github.com/v2ray/v2ray-core/transport"
)
@@ -66,7 +66,7 @@ func ReadAuthentication(reader io.Reader) (auth Socks5AuthenticationRequest, aut
auth.version = buffer.Value[0]
if auth.version != socksVersion {
log.Warning("Unknown protocol version %d", auth.version)
err = proxy.InvalidProtocolVersion
err = proxyerrors.InvalidProtocolVersion
return
}

View File

@@ -28,11 +28,7 @@ func TestSocks4AuthenticationRequestRead(t *testing.T) {
func TestSocks4AuthenticationResponseToBytes(t *testing.T) {
assert := unit.Assert(t)
response := &Socks4AuthenticationResponse{
result: byte(0x10),
port: 443,
ip: []byte{1, 2, 3, 4},
}
response := NewSocks4AuthenticationResponse(byte(0x10), 443, []byte{1, 2, 3, 4})
buffer := alloc.NewSmallBuffer().Clear()
defer buffer.Release()

View File

@@ -0,0 +1,35 @@
package protocol
import (
"testing"
"github.com/v2ray/v2ray-core/testing/fuzzing"
)
const (
Iterations = int(500000)
)
func TestReadAuthentication(t *testing.T) {
for i := 0; i < Iterations; i++ {
ReadAuthentication(fuzzing.RandomReader())
}
}
func TestReadUserPassRequest(t *testing.T) {
for i := 0; i < Iterations; i++ {
ReadUserPassRequest(fuzzing.RandomReader())
}
}
func TestReadRequest(t *testing.T) {
for i := 0; i < Iterations; i++ {
ReadRequest(fuzzing.RandomReader())
}
}
func TestReadUDPRequest(t *testing.T) {
for i := 0; i < Iterations; i++ {
ReadUDPRequest(fuzzing.RandomBytes())
}
}

View File

@@ -2,10 +2,12 @@ package protocol
import (
"bytes"
"io"
"testing"
"github.com/v2ray/v2ray-core/common/alloc"
"github.com/v2ray/v2ray-core/testing/unit"
"github.com/v2ray/v2ray-core/transport"
)
func TestHasAuthenticationMethod(t *testing.T) {
@@ -94,3 +96,17 @@ func TestResponseWrite(t *testing.T) {
}
assert.Bytes(buffer.Value).Named("raw response").Equals(expectedBytes)
}
func TestEOF(t *testing.T) {
assert := unit.Assert(t)
_, _, err := ReadAuthentication(bytes.NewReader(make([]byte, 0)))
assert.Error(err).Equals(io.EOF)
}
func TestSignleByte(t *testing.T) {
assert := unit.Assert(t)
_, _, err := ReadAuthentication(bytes.NewReader(make([]byte, 1)))
assert.Error(err).Equals(transport.CorruptedPacket)
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/v2ray/v2ray-core/common/alloc"
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/transport"
)
var (
@@ -37,7 +38,12 @@ func (request *Socks5UDPRequest) Write(buffer *alloc.Buffer) {
buffer.Append(request.Data.Value)
}
func ReadUDPRequest(packet []byte) (request Socks5UDPRequest, err error) {
func ReadUDPRequest(packet []byte) (*Socks5UDPRequest, error) {
if len(packet) < 5 {
return nil, transport.CorruptedPacket
}
request := new(Socks5UDPRequest)
// packet[0] and packet[1] are reserved
request.Fragment = packet[2]
@@ -46,28 +52,38 @@ func ReadUDPRequest(packet []byte) (request Socks5UDPRequest, err error) {
switch addrType {
case AddrTypeIPv4:
if len(packet) < 10 {
return nil, transport.CorruptedPacket
}
ip := packet[4:8]
port := binary.BigEndian.Uint16(packet[8:10])
request.Address = v2net.IPAddress(ip, port)
dataBegin = 10
case AddrTypeIPv6:
if len(packet) < 22 {
return nil, transport.CorruptedPacket
}
ip := packet[4:20]
port := binary.BigEndian.Uint16(packet[20:22])
request.Address = v2net.IPAddress(ip, port)
dataBegin = 22
case AddrTypeDomain:
domainLength := int(packet[4])
if len(packet) < 5+domainLength+2 {
return nil, transport.CorruptedPacket
}
domain := string(packet[5 : 5+domainLength])
port := binary.BigEndian.Uint16(packet[5+domainLength : 5+domainLength+2])
request.Address = v2net.DomainAddress(domain, port)
dataBegin = 5 + domainLength + 2
default:
log.Warning("Unknown address type %d", addrType)
err = ErrorUnknownAddressType
return
return nil, ErrorUnknownAddressType
}
request.Data = alloc.NewBuffer().Clear().Append(packet[dataBegin:])
if len(packet) > dataBegin {
request.Data = alloc.NewBuffer().Clear().Append(packet[dataBegin:])
}
return
return request, nil
}

View File

@@ -0,0 +1,35 @@
package protocol
import (
"testing"
"github.com/v2ray/v2ray-core/testing/unit"
"github.com/v2ray/v2ray-core/transport"
)
func TestSingleByteRequest(t *testing.T) {
assert := unit.Assert(t)
request, err := ReadUDPRequest(make([]byte, 1))
if request != nil {
t.Fail()
}
assert.Error(err).Equals(transport.CorruptedPacket)
}
func TestDomainAddressRequest(t *testing.T) {
assert := unit.Assert(t)
payload := make([]byte, 0, 1024)
payload = append(payload, 0, 0, 1, AddrTypeDomain, byte(len("v2ray.com")))
payload = append(payload, []byte("v2ray.com")...)
payload = append(payload, 0, 80)
payload = append(payload, []byte("Actual payload")...)
request, err := ReadUDPRequest(payload)
assert.Error(err).IsNil()
assert.Byte(request.Fragment).Equals(1)
assert.String(request.Address.String()).Equals("v2ray.com:80")
assert.Bytes(request.Data.Value).Equals([]byte("Actual payload"))
}

View File

@@ -12,7 +12,7 @@ import (
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/common/retry"
"github.com/v2ray/v2ray-core/proxy"
proxyerrors "github.com/v2ray/v2ray-core/proxy/common/errors"
jsonconfig "github.com/v2ray/v2ray-core/proxy/socks/config/json"
"github.com/v2ray/v2ray-core/proxy/socks/protocol"
)
@@ -128,7 +128,7 @@ func (server *SocksServer) handleSocks5(reader *v2net.TimeOutReader, writer io.W
}
if status != byte(0) {
log.Warning("Invalid user account: %s", upRequest.AuthDetail())
return proxy.InvalidAuthentication
return proxyerrors.InvalidAuthentication
}
}
@@ -145,6 +145,8 @@ func (server *SocksServer) handleSocks5(reader *v2net.TimeOutReader, writer io.W
if request.Command == protocol.CmdBind || request.Command == protocol.CmdUdpAssociate {
response := protocol.NewSocks5Response()
response.Error = protocol.ErrorCommandNotSupported
response.Port = uint16(0)
response.SetIPv4([]byte{0, 0, 0, 0})
responseBuffer := alloc.NewSmallBuffer().Clear()
response.Write(responseBuffer)
@@ -163,11 +165,7 @@ func (server *SocksServer) handleSocks5(reader *v2net.TimeOutReader, writer io.W
// Some SOCKS software requires a value other than dest. Let's fake one:
response.Port = uint16(1717)
response.AddrType = protocol.AddrTypeIPv4
response.IPv4[0] = 0
response.IPv4[1] = 0
response.IPv4[2] = 0
response.IPv4[3] = 0
response.SetIPv4([]byte{0, 0, 0, 0})
responseBuffer := alloc.NewSmallBuffer().Clear()
response.Write(responseBuffer)
@@ -198,14 +196,11 @@ func (server *SocksServer) handleUDP(reader *v2net.TimeOutReader, writer io.Writ
response.Port = udpAddr.Port()
switch {
case udpAddr.IsIPv4():
response.AddrType = protocol.AddrTypeIPv4
copy(response.IPv4[:], udpAddr.IP())
response.SetIPv4(udpAddr.IP())
case udpAddr.IsIPv6():
response.AddrType = protocol.AddrTypeIPv6
copy(response.IPv6[:], udpAddr.IP())
response.SetIPv6(udpAddr.IP())
case udpAddr.IsDomain():
response.AddrType = protocol.AddrTypeDomain
response.Domain = udpAddr.Domain()
response.SetDomain(udpAddr.Domain())
}
responseBuffer := alloc.NewSmallBuffer().Clear()

View File

@@ -2,6 +2,7 @@ package socks
import (
"bytes"
"fmt"
"io/ioutil"
"net"
"testing"
@@ -9,22 +10,26 @@ import (
"golang.org/x/net/proxy"
"github.com/v2ray/v2ray-core/app/point"
v2proxy "github.com/v2ray/v2ray-core/proxy"
"github.com/v2ray/v2ray-core/app/point/config/testing/mocks"
v2nettesting "github.com/v2ray/v2ray-core/common/net/testing"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
"github.com/v2ray/v2ray-core/proxy/socks/config/json"
"github.com/v2ray/v2ray-core/testing/mocks"
proxymocks "github.com/v2ray/v2ray-core/proxy/testing/mocks"
"github.com/v2ray/v2ray-core/testing/unit"
)
func TestSocksTcpConnect(t *testing.T) {
assert := unit.Assert(t)
port := uint16(12385)
port := v2nettesting.PickPort()
och := &mocks.OutboundConnectionHandler{
Data2Send: bytes.NewBuffer(make([]byte, 0, 1024)),
Data2Return: []byte("The data to be returned to socks server."),
connInput := []byte("The data to be returned to socks server.")
connOutput := bytes.NewBuffer(make([]byte, 0, 1024))
och := &proxymocks.OutboundConnectionHandler{
ConnOutput: connOutput,
ConnInput: bytes.NewReader(connInput),
}
v2proxy.RegisterOutboundConnectionHandlerFactory("mock_och", och)
connhandler.RegisterOutboundConnectionHandlerFactory("mock_och", och)
config := mocks.Config{
PortValue: port,
@@ -46,7 +51,7 @@ func TestSocksTcpConnect(t *testing.T) {
err = point.Start()
assert.Error(err).IsNil()
socks5Client, err := proxy.SOCKS5("tcp", "127.0.0.1:12385", nil, proxy.Direct)
socks5Client, err := proxy.SOCKS5("tcp", fmt.Sprintf("127.0.0.1:%d", port), nil, proxy.Direct)
assert.Error(err).IsNil()
targetServer := "google.com:80"
@@ -63,21 +68,23 @@ func TestSocksTcpConnect(t *testing.T) {
assert.Error(err).IsNil()
conn.Close()
assert.Bytes([]byte(data2Send)).Equals(och.Data2Send.Bytes())
assert.Bytes(dataReturned).Equals(och.Data2Return)
assert.Bytes([]byte(data2Send)).Equals(connOutput.Bytes())
assert.Bytes(dataReturned).Equals(connInput)
assert.String(targetServer).Equals(och.Destination.Address().String())
}
func TestSocksTcpConnectWithUserPass(t *testing.T) {
assert := unit.Assert(t)
port := uint16(12386)
port := v2nettesting.PickPort()
och := &mocks.OutboundConnectionHandler{
Data2Send: bytes.NewBuffer(make([]byte, 0, 1024)),
Data2Return: []byte("The data to be returned to socks server."),
connInput := []byte("The data to be returned to socks server.")
connOutput := bytes.NewBuffer(make([]byte, 0, 1024))
och := &proxymocks.OutboundConnectionHandler{
ConnInput: bytes.NewReader(connInput),
ConnOutput: connOutput,
}
v2proxy.RegisterOutboundConnectionHandlerFactory("mock_och", och)
connhandler.RegisterOutboundConnectionHandlerFactory("mock_och", och)
config := mocks.Config{
PortValue: port,
@@ -85,11 +92,8 @@ func TestSocksTcpConnectWithUserPass(t *testing.T) {
ProtocolValue: "socks",
SettingsValue: &json.SocksConfig{
AuthMethod: "password",
Accounts: []json.SocksAccount{
json.SocksAccount{
Username: "userx",
Password: "passy",
},
Accounts: json.SocksAccountMap{
"userx": "passy",
},
},
},
@@ -105,7 +109,7 @@ func TestSocksTcpConnectWithUserPass(t *testing.T) {
err = point.Start()
assert.Error(err).IsNil()
socks5Client, err := proxy.SOCKS5("tcp", "127.0.0.1:12386", &proxy.Auth{"userx", "passy"}, proxy.Direct)
socks5Client, err := proxy.SOCKS5("tcp", fmt.Sprintf("127.0.0.1:%d", port), &proxy.Auth{"userx", "passy"}, proxy.Direct)
assert.Error(err).IsNil()
targetServer := "1.2.3.4:443"
@@ -122,21 +126,23 @@ func TestSocksTcpConnectWithUserPass(t *testing.T) {
assert.Error(err).IsNil()
conn.Close()
assert.Bytes([]byte(data2Send)).Equals(och.Data2Send.Bytes())
assert.Bytes(dataReturned).Equals(och.Data2Return)
assert.Bytes([]byte(data2Send)).Equals(connOutput.Bytes())
assert.Bytes(dataReturned).Equals(connInput)
assert.String(targetServer).Equals(och.Destination.Address().String())
}
func TestSocksTcpConnectWithWrongUserPass(t *testing.T) {
assert := unit.Assert(t)
port := uint16(12389)
port := v2nettesting.PickPort()
och := &mocks.OutboundConnectionHandler{
Data2Send: bytes.NewBuffer(make([]byte, 0, 1024)),
Data2Return: []byte("The data to be returned to socks server."),
connInput := []byte("The data to be returned to socks server.")
connOutput := bytes.NewBuffer(make([]byte, 0, 1024))
och := &proxymocks.OutboundConnectionHandler{
ConnInput: bytes.NewReader(connInput),
ConnOutput: connOutput,
}
v2proxy.RegisterOutboundConnectionHandlerFactory("mock_och", och)
connhandler.RegisterOutboundConnectionHandlerFactory("mock_och", och)
config := mocks.Config{
PortValue: port,
@@ -144,11 +150,8 @@ func TestSocksTcpConnectWithWrongUserPass(t *testing.T) {
ProtocolValue: "socks",
SettingsValue: &json.SocksConfig{
AuthMethod: "password",
Accounts: []json.SocksAccount{
json.SocksAccount{
Username: "userx",
Password: "passy",
},
Accounts: json.SocksAccountMap{
"userx": "passy",
},
},
},
@@ -164,7 +167,7 @@ func TestSocksTcpConnectWithWrongUserPass(t *testing.T) {
err = point.Start()
assert.Error(err).IsNil()
socks5Client, err := proxy.SOCKS5("tcp", "127.0.0.1:12389", &proxy.Auth{"userx", "passz"}, proxy.Direct)
socks5Client, err := proxy.SOCKS5("tcp", fmt.Sprintf("127.0.0.1:%d", port), &proxy.Auth{"userx", "passz"}, proxy.Direct)
assert.Error(err).IsNil()
targetServer := "1.2.3.4:443"
@@ -174,14 +177,16 @@ func TestSocksTcpConnectWithWrongUserPass(t *testing.T) {
func TestSocksTcpConnectWithWrongAuthMethod(t *testing.T) {
assert := unit.Assert(t)
port := uint16(38405)
port := v2nettesting.PickPort()
och := &mocks.OutboundConnectionHandler{
Data2Send: bytes.NewBuffer(make([]byte, 0, 1024)),
Data2Return: []byte("The data to be returned to socks server."),
connInput := []byte("The data to be returned to socks server.")
connOutput := bytes.NewBuffer(make([]byte, 0, 1024))
och := &proxymocks.OutboundConnectionHandler{
ConnInput: bytes.NewReader(connInput),
ConnOutput: connOutput,
}
v2proxy.RegisterOutboundConnectionHandlerFactory("mock_och", och)
connhandler.RegisterOutboundConnectionHandlerFactory("mock_och", och)
config := mocks.Config{
PortValue: port,
@@ -189,11 +194,8 @@ func TestSocksTcpConnectWithWrongAuthMethod(t *testing.T) {
ProtocolValue: "socks",
SettingsValue: &json.SocksConfig{
AuthMethod: "password",
Accounts: []json.SocksAccount{
json.SocksAccount{
Username: "userx",
Password: "passy",
},
Accounts: json.SocksAccountMap{
"userx": "passy",
},
},
},
@@ -209,7 +211,7 @@ func TestSocksTcpConnectWithWrongAuthMethod(t *testing.T) {
err = point.Start()
assert.Error(err).IsNil()
socks5Client, err := proxy.SOCKS5("tcp", "127.0.0.1:38405", nil, proxy.Direct)
socks5Client, err := proxy.SOCKS5("tcp", fmt.Sprintf("127.0.0.1:%d", port), nil, proxy.Direct)
assert.Error(err).IsNil()
targetServer := "1.2.3.4:443"
@@ -219,14 +221,16 @@ func TestSocksTcpConnectWithWrongAuthMethod(t *testing.T) {
func TestSocksUdpSend(t *testing.T) {
assert := unit.Assert(t)
port := uint16(12372)
port := v2nettesting.PickPort()
och := &mocks.OutboundConnectionHandler{
Data2Send: bytes.NewBuffer(make([]byte, 0, 1024)),
Data2Return: []byte("The data to be returned to socks server."),
connInput := []byte("The data to be returned to socks server.")
connOutput := bytes.NewBuffer(make([]byte, 0, 1024))
och := &proxymocks.OutboundConnectionHandler{
ConnInput: bytes.NewReader(connInput),
ConnOutput: connOutput,
}
v2proxy.RegisterOutboundConnectionHandlerFactory("mock_och", och)
connhandler.RegisterOutboundConnectionHandlerFactory("mock_och", och)
config := mocks.Config{
PortValue: port,
@@ -270,7 +274,7 @@ func TestSocksUdpSend(t *testing.T) {
nBytes, err := conn.Read(response)
assert.Error(err).IsNil()
assert.Bytes(response[10:nBytes]).Equals(och.Data2Return)
assert.Bytes(data2Send).Equals(och.Data2Send.Bytes())
assert.Bytes(response[10:nBytes]).Equals(connInput)
assert.Bytes(data2Send).Equals(connOutput.Bytes())
assert.String(och.Destination.String()).Equals("udp:8.8.4.4:53")
}

View File

@@ -2,19 +2,17 @@ package socks
import (
"github.com/v2ray/v2ray-core/app"
"github.com/v2ray/v2ray-core/proxy"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
"github.com/v2ray/v2ray-core/proxy/socks/config/json"
)
type SocksServerFactory struct {
}
func (factory SocksServerFactory) Create(dispatcher app.PacketDispatcher, rawConfig interface{}) (proxy.InboundConnectionHandler, error) {
config := rawConfig.(*json.SocksConfig)
config.Initialize()
return NewSocksServer(dispatcher, config), nil
func (factory SocksServerFactory) Create(dispatcher app.PacketDispatcher, rawConfig interface{}) (connhandler.InboundConnectionHandler, error) {
return NewSocksServer(dispatcher, rawConfig.(*json.SocksConfig)), nil
}
func init() {
proxy.RegisterInboundConnectionHandlerFactory("socks", SocksServerFactory{})
connhandler.RegisterInboundConnectionHandlerFactory("socks", SocksServerFactory{})
}

View File

@@ -46,7 +46,9 @@ func (server *SocksServer) AcceptPackets(conn *net.UDPConn) error {
buffer.Release()
if err != nil {
log.Error("Socks failed to parse UDP request: %v", err)
request.Data.Release()
continue
}
if request.Data == nil || request.Data.Len() == 0 {
continue
}
if request.Fragment != 0 {

View File

@@ -0,0 +1,55 @@
package mocks
import (
"io"
"sync"
"github.com/v2ray/v2ray-core/app"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
)
type InboundConnectionHandler struct {
Port uint16
Dispatcher app.PacketDispatcher
ConnInput io.Reader
ConnOutput io.Writer
}
func (this *InboundConnectionHandler) Listen(port uint16) error {
this.Port = port
return nil
}
func (this *InboundConnectionHandler) Communicate(packet v2net.Packet) error {
ray := this.Dispatcher.DispatchToOutbound(packet)
input := ray.InboundInput()
output := ray.InboundOutput()
readFinish := &sync.Mutex{}
writeFinish := &sync.Mutex{}
readFinish.Lock()
writeFinish.Lock()
go func() {
v2net.ReaderToChan(input, this.ConnInput)
close(input)
readFinish.Unlock()
}()
go func() {
v2net.ChanToWriter(this.ConnOutput, output)
writeFinish.Unlock()
}()
readFinish.Lock()
writeFinish.Lock()
return nil
}
func (this *InboundConnectionHandler) Create(dispatcher app.PacketDispatcher, config interface{}) (connhandler.InboundConnectionHandler, error) {
this.Dispatcher = dispatcher
return this, nil
}

View File

@@ -0,0 +1,49 @@
package mocks
import (
"io"
"sync"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
"github.com/v2ray/v2ray-core/transport/ray"
)
type OutboundConnectionHandler struct {
Destination v2net.Destination
ConnInput io.Reader
ConnOutput io.Writer
}
func (this *OutboundConnectionHandler) Dispatch(packet v2net.Packet, ray ray.OutboundRay) error {
input := ray.OutboundInput()
output := ray.OutboundOutput()
this.Destination = packet.Destination()
if packet.Chunk() != nil {
this.ConnOutput.Write(packet.Chunk().Value)
packet.Chunk().Release()
}
if packet.MoreChunks() {
writeFinish := &sync.Mutex{}
writeFinish.Lock()
go func() {
v2net.ChanToWriter(this.ConnOutput, input)
writeFinish.Unlock()
}()
writeFinish.Lock()
}
v2net.ReaderToChan(output, this.ConnInput)
close(output)
return nil
}
func (this *OutboundConnectionHandler) Create(config interface{}) (connhandler.OutboundConnectionHandler, error) {
return this, nil
}

View File

@@ -2,5 +2,4 @@ package config
type Inbound interface {
AllowedUsers() []User
UDPEnabled() bool
}

View File

@@ -1,14 +1,12 @@
package json
import (
"github.com/v2ray/v2ray-core/config"
"github.com/v2ray/v2ray-core/config/json"
"github.com/v2ray/v2ray-core/proxy/common/config/json"
vmessconfig "github.com/v2ray/v2ray-core/proxy/vmess/config"
)
type Inbound struct {
AllowedClients []*ConfigUser `json:"clients"`
UDP bool `json:"udp"`
}
func (c *Inbound) AllowedUsers() []vmessconfig.User {
@@ -19,12 +17,8 @@ func (c *Inbound) AllowedUsers() []vmessconfig.User {
return users
}
func (c *Inbound) UDPEnabled() bool {
return c.UDP
}
func init() {
json.RegisterConfigType("vmess", config.TypeInbound, func() interface{} {
json.RegisterInboundConnectionConfig("vmess", func() interface{} {
return new(Inbound)
})
}

View File

@@ -3,12 +3,11 @@ package json
import (
"encoding/json"
"net"
"strings"
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/config"
jsonconfig "github.com/v2ray/v2ray-core/config/json"
proxyconfig "github.com/v2ray/v2ray-core/proxy/common/config"
jsonconfig "github.com/v2ray/v2ray-core/proxy/common/config/json"
vmessconfig "github.com/v2ray/v2ray-core/proxy/vmess/config"
)
@@ -16,18 +15,11 @@ type RawConfigTarget struct {
Address string `json:"address"`
Port uint16 `json:"port"`
Users []*ConfigUser `json:"users"`
Network string `json:"network"`
}
func (config RawConfigTarget) HasNetwork(network string) bool {
return strings.Contains(config.Network, network)
}
type ConfigTarget struct {
Address v2net.Address
Users []*ConfigUser
TCPEnabled bool
UDPEnabled bool
Address v2net.Address
Users []*ConfigUser
}
func (t *ConfigTarget) UnmarshalJSON(data []byte) error {
@@ -39,15 +31,9 @@ func (t *ConfigTarget) UnmarshalJSON(data []byte) error {
ip := net.ParseIP(rawConfig.Address)
if ip == nil {
log.Error("Unable to parse IP: %s", rawConfig.Address)
return config.BadConfiguration
return proxyconfig.BadConfiguration
}
t.Address = v2net.IPAddress(ip, rawConfig.Port)
if rawConfig.HasNetwork("tcp") {
t.TCPEnabled = true
}
if rawConfig.HasNetwork("udp") {
t.UDPEnabled = true
}
return nil
}
@@ -62,24 +48,16 @@ func (o *Outbound) Targets() []*vmessconfig.OutboundTarget {
for _, rawUser := range rawTarget.Users {
users = append(users, rawUser)
}
if rawTarget.TCPEnabled {
targets = append(targets, &vmessconfig.OutboundTarget{
Destination: v2net.NewTCPDestination(rawTarget.Address),
Accounts: users,
})
}
if rawTarget.UDPEnabled {
targets = append(targets, &vmessconfig.OutboundTarget{
Destination: v2net.NewUDPDestination(rawTarget.Address),
Accounts: users,
})
}
targets = append(targets, &vmessconfig.OutboundTarget{
Destination: v2net.NewTCPDestination(rawTarget.Address),
Accounts: users,
})
}
return targets
}
func init() {
jsonconfig.RegisterConfigType("vmess", config.TypeOutbound, func() interface{} {
jsonconfig.RegisterOutboundConnectionConfig("vmess", func() interface{} {
return new(Outbound)
})
}

View File

@@ -8,14 +8,16 @@ import (
// ConfigUser is an user account in VMess configuration.
type ConfigUser struct {
Id *config.ID
Email string
Id *config.ID
Email string
LevelValue config.UserLevel
}
func (u *ConfigUser) UnmarshalJSON(data []byte) error {
type rawUser struct {
IdString string `json:"id"`
EmailString string `json:"email"`
LevelInt int `json:"level"`
}
var rawUserValue rawUser
if err := json.Unmarshal(data, &rawUserValue); err != nil {
@@ -27,9 +29,14 @@ func (u *ConfigUser) UnmarshalJSON(data []byte) error {
}
u.Id = id
u.Email = rawUserValue.EmailString
u.LevelValue = config.UserLevel(rawUserValue.LevelInt)
return nil
}
func (u *ConfigUser) ID() *config.ID {
return u.Id
}
func (this *ConfigUser) Level() config.UserLevel {
return this.LevelValue
}

View File

@@ -1,5 +1,27 @@
package config
type UserLevel int
const (
UserLevelAdmin = UserLevel(999)
UserLevelUntrusted = UserLevel(0)
)
type User interface {
ID() *ID
Level() UserLevel
}
type UserSettings struct {
PayloadReadTimeout int
}
func GetUserSettings(level UserLevel) UserSettings {
settings := UserSettings{
PayloadReadTimeout: 120,
}
if level > 0 {
settings.PayloadReadTimeout = 0
}
return settings
}

View File

@@ -0,0 +1,75 @@
package io
import (
"errors"
"hash/fnv"
"io"
"github.com/v2ray/v2ray-core/common/alloc"
"github.com/v2ray/v2ray-core/transport"
)
var (
TruncatedPayload = errors.New("Truncated payload.")
)
type ValidationReader struct {
reader io.Reader
buffer *alloc.Buffer
}
func NewValidationReader(reader io.Reader) *ValidationReader {
return &ValidationReader{
reader: reader,
buffer: alloc.NewLargeBuffer().Clear(),
}
}
func (this *ValidationReader) Read(data []byte) (int, error) {
nBytes, err := this.reader.Read(data)
if err != nil {
return nBytes, err
}
nBytesActual := 0
dataActual := data[:]
for {
payload, rest, err := parsePayload(data)
if err != nil {
return nBytesActual, err
}
copy(dataActual, payload)
nBytesActual += len(payload)
dataActual = dataActual[nBytesActual:]
if len(rest) == 0 {
break
}
data = rest
}
return nBytesActual, nil
}
func parsePayload(data []byte) (payload []byte, rest []byte, err error) {
dataLen := len(data)
if dataLen < 6 {
err = TruncatedPayload
return
}
payloadLen := int(data[0])<<8 + int(data[1])
if dataLen < payloadLen+6 {
err = TruncatedPayload
return
}
payload = data[6 : 6+payloadLen]
rest = data[6+payloadLen:]
fnv1a := fnv.New32a()
fnv1a.Write(payload)
actualHash := fnv1a.Sum32()
expectedHash := uint32(data[2])<<24 + uint32(data[3])<<16 + uint32(data[4])<<8 + uint32(data[5])
if actualHash != expectedHash {
err = transport.CorruptedPacket
return
}
return
}

View File

@@ -5,20 +5,20 @@ import (
)
type MockUserSet struct {
UserIds []*config.ID
Users []config.User
UserHashes map[string]int
Timestamps map[string]int64
}
func (us *MockUserSet) AddUser(user config.User) error {
us.UserIds = append(us.UserIds, user.ID())
us.Users = append(us.Users, user)
return nil
}
func (us *MockUserSet) GetUser(userhash []byte) (*config.ID, int64, bool) {
func (us *MockUserSet) GetUser(userhash []byte) (config.User, int64, bool) {
idx, found := us.UserHashes[string(userhash)]
if found {
return us.UserIds[idx], us.Timestamps[string(userhash)], true
return us.Users[idx], us.Timestamps[string(userhash)], true
}
return nil, 0, false
}

View File

@@ -0,0 +1,29 @@
package mocks
import (
"github.com/v2ray/v2ray-core/proxy/vmess/config"
)
type StaticUser struct {
id *config.ID
}
func (this *StaticUser) ID() *config.ID {
return this.id
}
func (this *StaticUser) Level() config.UserLevel {
return config.UserLevelUntrusted
}
type StaticUserSet struct {
}
func (us *StaticUserSet) AddUser(user config.User) error {
return nil
}
func (us *StaticUserSet) GetUser(userhash []byte) (config.User, int64, bool) {
id, _ := config.NewID("703e9102-eb57-499c-8b59-faf4f371bb21")
return &StaticUser{id: id}, 0, true
}

View File

@@ -15,11 +15,11 @@ const (
type UserSet interface {
AddUser(user config.User) error
GetUser(timeHash []byte) (*config.ID, int64, bool)
GetUser(timeHash []byte) (config.User, int64, bool)
}
type TimedUserSet struct {
validUserIds []*config.ID
validUsers []config.User
userHash map[string]indexTimePair
userHashDeleteQueue *collect.TimedQueue
access sync.RWMutex
@@ -32,7 +32,7 @@ type indexTimePair struct {
func NewTimedUserSet() UserSet {
tus := &TimedUserSet{
validUserIds: make([]*config.ID, 0, 16),
validUsers: make([]config.User, 0, 16),
userHash: make(map[string]indexTimePair, 512),
userHashDeleteQueue: collect.NewTimedQueue(updateIntervalSec),
access: sync.RWMutex{},
@@ -63,12 +63,12 @@ func (us *TimedUserSet) generateNewHashes(lastSec, nowSec int64, idx int, id *co
}
func (us *TimedUserSet) updateUserHash(tick <-chan time.Time) {
lastSec := time.Now().UTC().Unix() - cacheDurationSec
lastSec := time.Now().Unix() - cacheDurationSec
for now := range tick {
nowSec := now.UTC().Unix() + cacheDurationSec
for idx, id := range us.validUserIds {
us.generateNewHashes(lastSec, nowSec, idx, id)
nowSec := now.Unix() + cacheDurationSec
for idx, user := range us.validUsers {
us.generateNewHashes(lastSec, nowSec, idx, user.ID())
}
lastSec = nowSec
}
@@ -76,22 +76,22 @@ func (us *TimedUserSet) updateUserHash(tick <-chan time.Time) {
func (us *TimedUserSet) AddUser(user config.User) error {
id := user.ID()
idx := len(us.validUserIds)
us.validUserIds = append(us.validUserIds, id)
idx := len(us.validUsers)
us.validUsers = append(us.validUsers, user)
nowSec := time.Now().UTC().Unix()
nowSec := time.Now().Unix()
lastSec := nowSec - cacheDurationSec
us.generateNewHashes(lastSec, nowSec+cacheDurationSec, idx, id)
return nil
}
func (us TimedUserSet) GetUser(userHash []byte) (*config.ID, int64, bool) {
func (us TimedUserSet) GetUser(userHash []byte) (config.User, int64, bool) {
defer us.access.RUnlock()
us.access.RLock()
pair, found := us.userHash[string(userHash)]
if found {
return us.validUserIds[pair.index], pair.timeSec, true
return us.validUsers[pair.index], pair.timeSec, true
}
return nil, 0, false
}

View File

@@ -2,18 +2,16 @@
package protocol
import (
"crypto/aes"
"crypto/cipher"
"encoding/binary"
"hash/fnv"
"io"
"time"
"github.com/v2ray/v2ray-core/common/alloc"
v2io "github.com/v2ray/v2ray-core/common/io"
v2crypto "github.com/v2ray/v2ray-core/common/crypto"
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy"
proxyerrors "github.com/v2ray/v2ray-core/proxy/common/errors"
"github.com/v2ray/v2ray-core/proxy/vmess/config"
"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
"github.com/v2ray/v2ray-core/transport"
@@ -37,7 +35,7 @@ const (
// streaming.
type VMessRequest struct {
Version byte
UserId config.ID
User config.User
RequestIV []byte
RequestKey []byte
ResponseHeader []byte
@@ -75,21 +73,17 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
return nil, err
}
userId, timeSec, valid := r.vUserSet.GetUser(buffer.Value[:nBytes])
userObj, timeSec, valid := r.vUserSet.GetUser(buffer.Value[:nBytes])
if !valid {
return nil, proxy.InvalidAuthentication
return nil, proxyerrors.InvalidAuthentication
}
aesCipher, err := aes.NewCipher(userId.CmdKey())
aesStream, err := v2crypto.NewAesDecryptionStream(userObj.ID().CmdKey(), user.Int64Hash(timeSec))
if err != nil {
return nil, err
}
aesStream := cipher.NewCFBDecrypter(aesCipher, user.Int64Hash(timeSec))
decryptor := v2io.NewCryptionReader(aesStream, reader)
if err != nil {
return nil, err
}
decryptor := v2crypto.NewCryptionReader(aesStream, reader)
nBytes, err = v2net.ReadAllBytes(decryptor, buffer.Value[:41])
if err != nil {
@@ -98,13 +92,13 @@ func (r *VMessRequestReader) Read(reader io.Reader) (*VMessRequest, error) {
bufferLen := nBytes
request := &VMessRequest{
UserId: *userId,
User: userObj,
Version: buffer.Value[0],
}
if request.Version != Version {
log.Warning("Invalid protocol version %d", request.Version)
return nil, proxy.InvalidProtocolVersion
return nil, proxyerrors.InvalidProtocolVersion
}
request.RequestIV = buffer.Value[1:17] // 16 bytes
@@ -166,8 +160,8 @@ func (request *VMessRequest) ToBytes(idHash user.CounterHash, randomRangeInt64 u
buffer = alloc.NewSmallBuffer().Clear()
}
counter := randomRangeInt64(time.Now().UTC().Unix(), 30)
hash := idHash.Hash(request.UserId.Bytes[:], counter)
counter := randomRangeInt64(time.Now().Unix(), 30)
hash := idHash.Hash(request.User.ID().Bytes[:], counter)
buffer.Append(hash)
@@ -201,11 +195,10 @@ func (request *VMessRequest) ToBytes(idHash user.CounterHash, randomRangeInt64 u
buffer.AppendBytes(byte(fnvHash>>24), byte(fnvHash>>16), byte(fnvHash>>8), byte(fnvHash))
encryptionEnd += 4
aesCipher, err := aes.NewCipher(request.UserId.CmdKey())
aesStream, err := v2crypto.NewAesEncryptionStream(request.User.ID().CmdKey(), user.Int64Hash(counter))
if err != nil {
return nil, err
}
aesStream := cipher.NewCFBEncrypter(aesCipher, user.Int64Hash(counter))
aesStream.XORKeyStream(buffer.Value[encryptionBegin:encryptionEnd], buffer.Value[encryptionBegin:encryptionEnd])
return buffer, nil

View File

@@ -0,0 +1,15 @@
package protocol
import (
"testing"
"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user/testing/mocks"
"github.com/v2ray/v2ray-core/testing/fuzzing"
)
func TestVMessRequestReader(t *testing.T) {
reader := NewVMessRequestReader(&mocks.StaticUserSet{})
for i := 0; i < 1000000; i++ {
reader.Read(fuzzing.RandomReader())
}
}

View File

@@ -3,23 +3,29 @@ package protocol
import (
"bytes"
"crypto/rand"
"io"
"testing"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy/vmess/config"
"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
"github.com/v2ray/v2ray-core/testing/mocks"
"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user/testing/mocks"
"github.com/v2ray/v2ray-core/testing/unit"
)
type TestUser struct {
id *config.ID
id *config.ID
level config.UserLevel
}
func (u *TestUser) ID() *config.ID {
return u.id
}
func (this *TestUser) Level() config.UserLevel {
return this.level
}
func TestVMessSerialization(t *testing.T) {
assert := unit.Assert(t)
@@ -28,12 +34,16 @@ func TestVMessSerialization(t *testing.T) {
t.Fatal(err)
}
userSet := mocks.MockUserSet{[]*config.ID{}, make(map[string]int), make(map[string]int64)}
userSet.AddUser(&TestUser{userId})
testUser := &TestUser{
id: userId,
}
userSet := mocks.MockUserSet{[]config.User{}, make(map[string]int), make(map[string]int64)}
userSet.AddUser(testUser)
request := new(VMessRequest)
request.Version = byte(0x01)
request.UserId = *userId
request.User = testUser
randBytes := make([]byte, 36)
_, err = rand.Read(randBytes)
@@ -62,7 +72,7 @@ func TestVMessSerialization(t *testing.T) {
}
assert.Byte(actualRequest.Version).Named("Version").Equals(byte(0x01))
assert.String(actualRequest.UserId.String).Named("UserId").Equals(request.UserId.String)
assert.String(actualRequest.User.ID().String).Named("UserId").Equals(request.User.ID().String)
assert.Bytes(actualRequest.RequestIV).Named("RequestIV").Equals(request.RequestIV[:])
assert.Bytes(actualRequest.RequestKey).Named("RequestKey").Equals(request.RequestKey[:])
assert.Bytes(actualRequest.ResponseHeader).Named("ResponseHeader").Equals(request.ResponseHeader[:])
@@ -70,14 +80,26 @@ func TestVMessSerialization(t *testing.T) {
assert.String(actualRequest.Address.String()).Named("Address").Equals(request.Address.String())
}
func TestReadSingleByte(t *testing.T) {
assert := unit.Assert(t)
reader := NewVMessRequestReader(nil)
_, err := reader.Read(bytes.NewReader(make([]byte, 1)))
assert.Error(err).Equals(io.EOF)
}
func BenchmarkVMessRequestWriting(b *testing.B) {
userId, _ := config.NewID("2b2966ac-16aa-4fbf-8d81-c5f172a3da51")
userSet := mocks.MockUserSet{[]*config.ID{}, make(map[string]int), make(map[string]int64)}
userSet.AddUser(&TestUser{userId})
userSet := mocks.MockUserSet{[]config.User{}, make(map[string]int), make(map[string]int64)}
testUser := &TestUser{
id: userId,
}
userSet.AddUser(testUser)
request := new(VMessRequest)
request.Version = byte(0x01)
request.UserId = *userId
request.User = testUser
randBytes := make([]byte, 36)
rand.Read(randBytes)

View File

@@ -5,29 +5,33 @@ import (
"testing"
"github.com/v2ray/v2ray-core/app/point"
"github.com/v2ray/v2ray-core/common/alloc"
"github.com/v2ray/v2ray-core/app/point/config/testing/mocks"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy"
v2nettesting "github.com/v2ray/v2ray-core/common/net/testing"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
proxymocks "github.com/v2ray/v2ray-core/proxy/testing/mocks"
"github.com/v2ray/v2ray-core/proxy/vmess/config"
"github.com/v2ray/v2ray-core/proxy/vmess/config/json"
"github.com/v2ray/v2ray-core/testing/mocks"
"github.com/v2ray/v2ray-core/testing/unit"
)
func TestVMessInAndOut(t *testing.T) {
assert := unit.Assert(t)
data2Send := "The data to be send to outbound server."
testAccount, err := config.NewID("ad937d9d-6e23-4a5a-ba23-bce5092a7c51")
assert.Error(err).IsNil()
portA := uint16(17392)
ich := &mocks.InboundConnectionHandler{
Data2Send: []byte(data2Send),
DataReturned: bytes.NewBuffer(make([]byte, 0, 1024)),
portA := v2nettesting.PickPort()
portB := v2nettesting.PickPort()
ichConnInput := []byte("The data to be send to outbound server.")
ichConnOutput := bytes.NewBuffer(make([]byte, 0, 1024))
ich := &proxymocks.InboundConnectionHandler{
ConnInput: bytes.NewReader(ichConnInput),
ConnOutput: ichConnOutput,
}
proxy.RegisterInboundConnectionHandlerFactory("mock_ich", ich)
connhandler.RegisterInboundConnectionHandlerFactory("mock_ich", ich)
configA := mocks.Config{
PortValue: portA,
@@ -40,8 +44,7 @@ func TestVMessInAndOut(t *testing.T) {
SettingsValue: &json.Outbound{
[]*json.ConfigTarget{
&json.ConfigTarget{
Address: v2net.IPAddress([]byte{127, 0, 0, 1}, 13829),
TCPEnabled: true,
Address: v2net.IPAddress([]byte{127, 0, 0, 1}, portB),
Users: []*json.ConfigUser{
&json.ConfigUser{Id: testAccount},
},
@@ -57,14 +60,14 @@ func TestVMessInAndOut(t *testing.T) {
err = pointA.Start()
assert.Error(err).IsNil()
portB := uint16(13829)
och := &mocks.OutboundConnectionHandler{
Data2Send: bytes.NewBuffer(make([]byte, 0, 1024)),
Data2Return: []byte("The data to be returned to inbound server."),
ochConnInput := []byte("The data to be returned to inbound server.")
ochConnOutput := bytes.NewBuffer(make([]byte, 0, 1024))
och := &proxymocks.OutboundConnectionHandler{
ConnInput: bytes.NewReader(ochConnInput),
ConnOutput: ochConnOutput,
}
proxy.RegisterOutboundConnectionHandlerFactory("mock_och", och)
connhandler.RegisterOutboundConnectionHandlerFactory("mock_och", och)
configB := mocks.Config{
PortValue: portB,
@@ -90,90 +93,6 @@ func TestVMessInAndOut(t *testing.T) {
dest := v2net.NewTCPDestination(v2net.IPAddress([]byte{1, 2, 3, 4}, 80))
ich.Communicate(v2net.NewPacket(dest, nil, true))
assert.Bytes([]byte(data2Send)).Equals(och.Data2Send.Bytes())
assert.Bytes(ich.DataReturned.Bytes()).Equals(och.Data2Return)
}
func TestVMessInAndOutUDP(t *testing.T) {
assert := unit.Assert(t)
data2Send := "The data to be send to outbound server."
testAccount, err := config.NewID("ad937d9d-6e23-4a5a-ba23-bce5092a7c51")
assert.Error(err).IsNil()
portA := uint16(17394)
ich := &mocks.InboundConnectionHandler{
Data2Send: []byte(data2Send),
DataReturned: bytes.NewBuffer(make([]byte, 0, 1024)),
}
proxy.RegisterInboundConnectionHandlerFactory("mock_ich", ich)
configA := mocks.Config{
PortValue: portA,
InboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "mock_ich",
SettingsValue: nil,
},
OutboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "vmess",
SettingsValue: &json.Outbound{
[]*json.ConfigTarget{
&json.ConfigTarget{
Address: v2net.IPAddress([]byte{127, 0, 0, 1}, 13841),
UDPEnabled: true,
Users: []*json.ConfigUser{
&json.ConfigUser{Id: testAccount},
},
},
},
},
},
}
pointA, err := point.NewPoint(&configA)
assert.Error(err).IsNil()
err = pointA.Start()
assert.Error(err).IsNil()
portB := uint16(13841)
och := &mocks.OutboundConnectionHandler{
Data2Send: bytes.NewBuffer(make([]byte, 0, 1024)),
Data2Return: []byte("The data to be returned to inbound server."),
}
proxy.RegisterOutboundConnectionHandlerFactory("mock_och", och)
configB := mocks.Config{
PortValue: portB,
InboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "vmess",
SettingsValue: &json.Inbound{
AllowedClients: []*json.ConfigUser{
&json.ConfigUser{Id: testAccount},
},
UDP: true,
},
},
OutboundConfigValue: &mocks.ConnectionConfig{
ProtocolValue: "mock_och",
SettingsValue: nil,
},
}
pointB, err := point.NewPoint(&configB)
assert.Error(err).IsNil()
err = pointB.Start()
assert.Error(err).IsNil()
data2SendBuffer := alloc.NewBuffer()
data2SendBuffer.Clear()
data2SendBuffer.Append([]byte(data2Send))
dest := v2net.NewUDPDestination(v2net.IPAddress([]byte{1, 2, 3, 4}, 80))
ich.Communicate(v2net.NewPacket(dest, data2SendBuffer, false))
assert.Bytes([]byte(data2Send)).Equals(och.Data2Send.Bytes())
assert.Bytes(ich.DataReturned.Bytes()).Equals(och.Data2Return)
assert.Bytes(ichConnInput).Equals(ochConnOutput.Bytes())
assert.Bytes(ichConnOutput.Bytes()).Equals(ochConnInput)
}

View File

@@ -8,11 +8,11 @@ import (
"github.com/v2ray/v2ray-core/app"
"github.com/v2ray/v2ray-core/common/alloc"
v2io "github.com/v2ray/v2ray-core/common/io"
v2crypto "github.com/v2ray/v2ray-core/common/crypto"
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/common/retry"
"github.com/v2ray/v2ray-core/proxy"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
"github.com/v2ray/v2ray-core/proxy/vmess/config"
"github.com/v2ray/v2ray-core/proxy/vmess/protocol"
"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
@@ -22,14 +22,12 @@ type VMessInboundHandler struct {
dispatcher app.PacketDispatcher
clients user.UserSet
accepting bool
udpEnabled bool
}
func NewVMessInboundHandler(dispatcher app.PacketDispatcher, clients user.UserSet, udpEnabled bool) *VMessInboundHandler {
func NewVMessInboundHandler(dispatcher app.PacketDispatcher, clients user.UserSet) *VMessInboundHandler {
return &VMessInboundHandler{
dispatcher: dispatcher,
clients: clients,
udpEnabled: udpEnabled,
}
}
@@ -45,11 +43,6 @@ func (handler *VMessInboundHandler) Listen(port uint16) error {
}
handler.accepting = true
go handler.AcceptConnections(listener)
if handler.udpEnabled {
handler.ListenUDP(port)
}
return nil
}
@@ -91,18 +84,21 @@ func (handler *VMessInboundHandler) HandleConnection(connection *net.TCPConn) er
readFinish.Lock()
writeFinish.Lock()
connReader.SetTimeOut(120)
userSettings := config.GetUserSettings(request.User.Level())
connReader.SetTimeOut(userSettings.PayloadReadTimeout)
go handleInput(request, connReader, input, &readFinish)
responseKey := md5.Sum(request.RequestKey)
responseIV := md5.Sum(request.RequestIV)
responseWriter, err := v2io.NewAesEncryptWriter(responseKey[:], responseIV[:], connection)
aesStream, err := v2crypto.NewAesEncryptionStream(responseKey[:], responseIV[:])
if err != nil {
log.Error("VMessIn: Failed to create encrypt writer: %v", err)
log.Error("VMessIn: Failed to create AES decryption stream: %v", err)
return err
}
responseWriter := v2crypto.NewCryptionWriter(aesStream, connection)
// Optimize for small response packet
buffer := alloc.NewLargeBuffer().Clear()
buffer.Append(request.ResponseHeader)
@@ -126,12 +122,12 @@ func handleInput(request *protocol.VMessRequest, reader io.Reader, input chan<-
defer close(input)
defer finish.Unlock()
requestReader, err := v2io.NewAesDecryptReader(request.RequestKey, request.RequestIV, reader)
aesStream, err := v2crypto.NewAesDecryptionStream(request.RequestKey, request.RequestIV)
if err != nil {
log.Error("VMessIn: Failed to create decrypt reader: %v", err)
log.Error("VMessIn: Failed to create AES decryption stream: %v", err)
return
}
requestReader := v2crypto.NewCryptionReader(aesStream, reader)
v2net.ReaderToChan(input, requestReader)
}
@@ -143,7 +139,7 @@ func handleOutput(request *protocol.VMessRequest, writer io.Writer, output <-cha
type VMessInboundHandlerFactory struct {
}
func (factory *VMessInboundHandlerFactory) Create(dispatcher app.PacketDispatcher, rawConfig interface{}) (proxy.InboundConnectionHandler, error) {
func (factory *VMessInboundHandlerFactory) Create(dispatcher app.PacketDispatcher, rawConfig interface{}) (connhandler.InboundConnectionHandler, error) {
config := rawConfig.(config.Inbound)
allowedClients := user.NewTimedUserSet()
@@ -151,9 +147,9 @@ func (factory *VMessInboundHandlerFactory) Create(dispatcher app.PacketDispatche
allowedClients.AddUser(user)
}
return NewVMessInboundHandler(dispatcher, allowedClients, config.UDPEnabled()), nil
return NewVMessInboundHandler(dispatcher, allowedClients), nil
}
func init() {
proxy.RegisterInboundConnectionHandlerFactory("vmess", &VMessInboundHandlerFactory{})
connhandler.RegisterInboundConnectionHandlerFactory("vmess", &VMessInboundHandlerFactory{})
}

View File

@@ -1,108 +0,0 @@
package vmess
import (
"bytes"
"crypto/md5"
"net"
"github.com/v2ray/v2ray-core/common/alloc"
v2io "github.com/v2ray/v2ray-core/common/io"
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy/vmess/protocol"
)
const (
bufferSize = 2 * 1024
)
func (handler *VMessInboundHandler) ListenUDP(port uint16) error {
addr := &net.UDPAddr{
IP: net.IP{0, 0, 0, 0},
Port: int(port),
Zone: "",
}
conn, err := net.ListenUDP("udp", addr)
if err != nil {
log.Error("VMessIn failed to listen UDP on port %d: %v", port, err)
return err
}
go handler.AcceptPackets(conn)
return nil
}
func (handler *VMessInboundHandler) AcceptPackets(conn *net.UDPConn) {
for {
buffer := alloc.NewBuffer()
nBytes, addr, err := conn.ReadFromUDP(buffer.Value)
if err != nil {
log.Error("VMessIn failed to read UDP packets: %v", err)
buffer.Release()
continue
}
reader := bytes.NewReader(buffer.Value[:nBytes])
requestReader := protocol.NewVMessRequestReader(handler.clients)
request, err := requestReader.Read(reader)
if err != nil {
log.Access(addr.String(), "", log.AccessRejected, err.Error())
log.Warning("VMessIn: Invalid request from (%s): %v", addr.String(), err)
buffer.Release()
continue
}
log.Access(addr.String(), request.Address.String(), log.AccessAccepted, "")
cryptReader, err := v2io.NewAesDecryptReader(request.RequestKey, request.RequestIV, reader)
if err != nil {
log.Error("VMessIn: Failed to create decrypt reader: %v", err)
buffer.Release()
continue
}
data := alloc.NewBuffer()
nBytes, err = cryptReader.Read(data.Value)
buffer.Release()
if err != nil {
log.Warning("VMessIn: Unable to decrypt data: %v", err)
data.Release()
continue
}
data.Slice(0, nBytes)
packet := v2net.NewPacket(request.Destination(), data, false)
go handler.handlePacket(conn, request, packet, addr)
}
}
func (handler *VMessInboundHandler) handlePacket(conn *net.UDPConn, request *protocol.VMessRequest, packet v2net.Packet, clientAddr *net.UDPAddr) {
ray := handler.dispatcher.DispatchToOutbound(packet)
close(ray.InboundInput())
responseKey := md5.Sum(request.RequestKey)
responseIV := md5.Sum(request.RequestIV)
buffer := alloc.NewBuffer().Clear()
defer buffer.Release()
responseWriter, err := v2io.NewAesEncryptWriter(responseKey[:], responseIV[:], buffer)
if err != nil {
log.Error("VMessIn: Failed to create encrypt writer: %v", err)
return
}
responseWriter.Write(request.ResponseHeader)
hasData := false
if data, ok := <-ray.InboundOutput(); ok {
hasData = true
responseWriter.Write(data.Value)
data.Release()
}
if hasData {
conn.WriteToUDP(buffer.Value, clientAddr)
log.Info("VMessIn sending %d bytes to %s", buffer.Len(), clientAddr.String())
}
}

View File

@@ -9,10 +9,10 @@ import (
"sync"
"github.com/v2ray/v2ray-core/common/alloc"
v2io "github.com/v2ray/v2ray-core/common/io"
v2crypto "github.com/v2ray/v2ray-core/common/crypto"
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/proxy"
"github.com/v2ray/v2ray-core/proxy/common/connhandler"
"github.com/v2ray/v2ray-core/proxy/vmess/config"
"github.com/v2ray/v2ray-core/proxy/vmess/protocol"
"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
@@ -20,14 +20,12 @@ import (
)
type VMessOutboundHandler struct {
vNextList []*config.OutboundTarget
vNextListUDP []*config.OutboundTarget
vNextList []*config.OutboundTarget
}
func NewVMessOutboundHandler(vNextList, vNextListUDP []*config.OutboundTarget) *VMessOutboundHandler {
func NewVMessOutboundHandler(vNextList []*config.OutboundTarget) *VMessOutboundHandler {
return &VMessOutboundHandler{
vNextList: vNextList,
vNextListUDP: vNextListUDP,
vNextList: vNextList,
}
}
@@ -56,9 +54,6 @@ func pickVNext(serverList []*config.OutboundTarget) (v2net.Destination, config.U
func (handler *VMessOutboundHandler) Dispatch(firstPacket v2net.Packet, ray ray.OutboundRay) error {
vNextList := handler.vNextList
if firstPacket.Destination().IsUDP() {
vNextList = handler.vNextListUDP
}
vNextAddress, vNextUser := pickVNext(vNextList)
command := protocol.CmdTCP
@@ -67,7 +62,7 @@ func (handler *VMessOutboundHandler) Dispatch(firstPacket v2net.Packet, ray ray.
}
request := &protocol.VMessRequest{
Version: protocol.Version,
UserId: *vNextUser.ID(),
User: vNextUser,
Command: command,
Address: firstPacket.Destination().Address(),
}
@@ -114,11 +109,12 @@ func startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ra
func handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2net.Packet, input <-chan *alloc.Buffer, finish *sync.Mutex) {
defer finish.Unlock()
encryptRequestWriter, err := v2io.NewAesEncryptWriter(request.RequestKey[:], request.RequestIV[:], conn)
aesStream, err := v2crypto.NewAesEncryptionStream(request.RequestKey[:], request.RequestIV[:])
if err != nil {
log.Error("VMessOut: Failed to create encrypt writer: %v", err)
log.Error("VMessOut: Failed to create AES encryption stream: %v", err)
return
}
encryptRequestWriter := v2crypto.NewCryptionWriter(aesStream, conn)
buffer := alloc.NewBuffer().Clear()
buffer, err = request.ToBytes(user.NewTimeHash(user.HMACHash{}), user.GenerateRandomInt64InRange, buffer)
@@ -136,7 +132,7 @@ func handleRequest(conn net.Conn, request *protocol.VMessRequest, firstPacket v2
}
if firstChunk != nil {
encryptRequestWriter.Crypt(firstChunk.Value)
aesStream.XORKeyStream(firstChunk.Value, firstChunk.Value)
buffer.Append(firstChunk.Value)
firstChunk.Release()
@@ -160,11 +156,12 @@ func handleResponse(conn net.Conn, request *protocol.VMessRequest, output chan<-
responseKey := md5.Sum(request.RequestKey[:])
responseIV := md5.Sum(request.RequestIV[:])
decryptResponseReader, err := v2io.NewAesDecryptReader(responseKey[:], responseIV[:], conn)
aesStream, err := v2crypto.NewAesDecryptionStream(responseKey[:], responseIV[:])
if err != nil {
log.Error("VMessOut: Failed to create decrypt reader: %v", err)
log.Error("VMessOut: Failed to create AES encryption stream: %v", err)
return
}
decryptResponseReader := v2crypto.NewCryptionReader(aesStream, conn)
buffer, err := v2net.ReadFrom(decryptResponseReader, nil)
if err != nil {
@@ -190,21 +187,11 @@ func handleResponse(conn net.Conn, request *protocol.VMessRequest, output chan<-
type VMessOutboundHandlerFactory struct {
}
func (factory *VMessOutboundHandlerFactory) Create(rawConfig interface{}) (proxy.OutboundConnectionHandler, error) {
func (factory *VMessOutboundHandlerFactory) Create(rawConfig interface{}) (connhandler.OutboundConnectionHandler, error) {
vOutConfig := rawConfig.(config.Outbound)
servers := make([]*config.OutboundTarget, 0, 16)
udpServers := make([]*config.OutboundTarget, 0, 16)
for _, target := range vOutConfig.Targets() {
if target.Destination.IsTCP() {
servers = append(servers, target)
}
if target.Destination.IsUDP() {
udpServers = append(udpServers, target)
}
}
return NewVMessOutboundHandler(servers, udpServers), nil
return NewVMessOutboundHandler(vOutConfig.Targets()), nil
}
func init() {
proxy.RegisterOutboundConnectionHandlerFactory("vmess", &VMessOutboundHandlerFactory{})
connhandler.RegisterOutboundConnectionHandlerFactory("vmess", &VMessOutboundHandlerFactory{})
}

View File

@@ -0,0 +1,40 @@
{
"port": 1080,
"log": {
"access": ""
},
"inbound": {
"protocol": "socks",
"settings": {
"auth": "noauth",
"udp": false,
"ip": "127.0.0.1"
}
},
"outbound": {
"protocol": "vmess",
"settings": {
"vnext": [
{
"address": "127.0.0.1",
"port": 37192,
"users": [
{"id": "27848739-7e62-4138-9fd3-098a63964b6b"}
]
}
]
}
},
"inboundDetour": [
{
"protocol": "dokodemo-door",
"port": 28394,
"settings": {
"address": "8.8.8.8",
"port": 53,
"network": "tcp",
"timeout": 0
}
}
]
}

View File

@@ -17,11 +17,100 @@
"vnext": [
{
"address": "127.0.0.1",
"port": 27183,
"port": 37192,
"users": [
{"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"}
],
"network": "tcp"
{"id": "27848739-7e62-4138-9fd3-098a63964b6b"},
{"id": "3b129dec-72a3-4d28-aeee-028a0fe86e22"}
]
}
]
}
},
"outboundDetour": [
{
"protocol": "freedom",
"settings": {},
"tag": "direct"
}
],
"routing": {
"strategy": "rules",
"settings": {
"rules": [
{
"type": "field",
"ip": "0.0.0.0/8",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "10.0.0.0/8",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "100.64.0.0/10",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "127.0.0.0/8",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "169.254.0.0/16",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "172.16.0.0/12",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "192.0.0.0/24",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "192.0.2.0/24",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "192.168.0.0/16",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "198.18.0.0/15",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "198.51.100.0/24",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "203.0.113.0/24",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "::1/128",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "fc00::/7",
"outboundTag": "direct"
},
{
"type": "field",
"ip": "fe80::/10",
"outboundTag": "direct"
}
]
}

View File

@@ -1,5 +1,5 @@
{
"port": 27183,
"port": 37192,
"log" : {
"access": "access.log"
},
@@ -7,13 +7,108 @@
"protocol": "vmess",
"settings": {
"clients": [
{"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"}
],
"udp": false
{
"id": "27848739-7e62-4138-9fd3-098a63964b6b",
"level": 0
},
{
"id": "3b129dec-72a3-4d28-aeee-028a0fe86e22",
"level": 1
}
]
}
},
"outbound": {
"protocol": "freedom",
"settings": {}
},
"outboundDetour": [
{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}
],
"routing": {
"strategy": "rules",
"settings": {
"rules": [
{
"type": "field",
"ip": "0.0.0.0/8",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "10.0.0.0/8",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "100.64.0.0/10",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "127.0.0.0/8",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "169.254.0.0/16",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "172.16.0.0/12",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "192.0.0.0/24",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "192.0.2.0/24",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "192.168.0.0/16",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "198.18.0.0/15",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "198.51.100.0/24",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "203.0.113.0/24",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "::1/128",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "fc00::/7",
"outboundTag": "blocked"
},
{
"type": "field",
"ip": "fe80::/10",
"outboundTag": "blocked"
}
]
}
}
}

View File

@@ -8,10 +8,17 @@ import (
"github.com/v2ray/v2ray-core"
"github.com/v2ray/v2ray-core/app/point"
jsonconf "github.com/v2ray/v2ray-core/app/point/config/json"
_ "github.com/v2ray/v2ray-core/app/router/config/json"
_ "github.com/v2ray/v2ray-core/app/router/rules"
_ "github.com/v2ray/v2ray-core/app/router/rules/config/json"
"github.com/v2ray/v2ray-core/common/log"
jsonconf "github.com/v2ray/v2ray-core/config/json"
// The following are neccesary as they register handlers in their init functions.
_ "github.com/v2ray/v2ray-core/proxy/blackhole"
_ "github.com/v2ray/v2ray-core/proxy/blackhole/config/json"
_ "github.com/v2ray/v2ray-core/proxy/dokodemo"
_ "github.com/v2ray/v2ray-core/proxy/dokodemo/config/json"
_ "github.com/v2ray/v2ray-core/proxy/freedom"
_ "github.com/v2ray/v2ray-core/proxy/freedom/config/json"
_ "github.com/v2ray/v2ray-core/proxy/socks"

View File

@@ -27,7 +27,7 @@ for DIR in $(find * -type d -not -path "*.git*"); do
fi
done
cat coverall.out | sort -t: -k1 > coverallsorted.out
cat coverall.out | sort -t: -k1 | grep -vw "testing" > coverallsorted.out
echo "mode: set" | cat - coverallsorted.out > coverall.out
rm coverallsorted.out

View File

@@ -0,0 +1,17 @@
package fuzzing
import (
"bytes"
"crypto/rand"
"io"
)
func RandomBytes() []byte {
buffer := make([]byte, 256)
rand.Read(buffer)
return buffer[1 : 1+int(buffer[0])]
}
func RandomReader() io.Reader {
return bytes.NewReader(RandomBytes())
}

View File

@@ -1,49 +0,0 @@
package mocks
import (
"github.com/v2ray/v2ray-core/config"
)
type ConnectionConfig struct {
ProtocolValue string
SettingsValue interface{}
}
func (config *ConnectionConfig) Protocol() string {
return config.ProtocolValue
}
func (config *ConnectionConfig) Settings(config.Type) interface{} {
return config.SettingsValue
}
type LogConfig struct {
AccessLogValue string
}
func (config *LogConfig) AccessLog() string {
return config.AccessLogValue
}
type Config struct {
PortValue uint16
LogConfigValue *LogConfig
InboundConfigValue *ConnectionConfig
OutboundConfigValue *ConnectionConfig
}
func (config *Config) Port() uint16 {
return config.PortValue
}
func (config *Config) LogConfig() config.LogConfig {
return config.LogConfigValue
}
func (config *Config) InboundConfig() config.ConnectionConfig {
return config.InboundConfigValue
}
func (config *Config) OutboundConfig() config.ConnectionConfig {
return config.OutboundConfigValue
}

Some files were not shown because too many files have changed in this diff Show More