remove json conf from core

pull/298/merge
Darien Raymond 2017-05-17 12:02:35 +02:00
parent a8da85eca5
commit c287df631d
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
29 changed files with 13 additions and 3336 deletions

View File

@ -1,51 +0,0 @@
package conf
import (
"encoding/json"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/blackhole"
)
type NoneResponse struct{}
func (*NoneResponse) Build() (*serial.TypedMessage, error) {
return serial.ToTypedMessage(new(blackhole.NoneResponse)), nil
}
type HttpResponse struct{}
func (*HttpResponse) Build() (*serial.TypedMessage, error) {
return serial.ToTypedMessage(new(blackhole.HTTPResponse)), nil
}
type BlackholeConfig struct {
Response json.RawMessage `json:"response"`
}
func (v *BlackholeConfig) Build() (*serial.TypedMessage, error) {
config := new(blackhole.Config)
if v.Response != nil {
response, _, err := configLoader.Load(v.Response)
if err != nil {
return nil, newError("Config: Failed to parse Blackhole response config.").Base(err)
}
responseSettings, err := response.(Buildable).Build()
if err != nil {
return nil, err
}
config.Response = responseSettings
}
return serial.ToTypedMessage(config), nil
}
var (
configLoader = NewJSONConfigLoader(
ConfigCreatorCache{
"none": func() interface{} { return new(NoneResponse) },
"http": func() interface{} { return new(HttpResponse) },
},
"type",
"")
)

View File

@ -1,34 +0,0 @@
package conf_test
import (
"encoding/json"
"testing"
"v2ray.com/core/proxy/blackhole"
"v2ray.com/core/testing/assert"
. "v2ray.com/core/tools/conf"
)
func TestHTTPResponseJSON(t *testing.T) {
assert := assert.On(t)
rawJson := `{
"response": {
"type": "http"
}
}`
rawConfig := new(BlackholeConfig)
err := json.Unmarshal([]byte(rawJson), rawConfig)
assert.Error(err).IsNil()
ts, err := rawConfig.Build()
assert.Error(err).IsNil()
iConfig, err := ts.GetInstance()
assert.Error(err).IsNil()
config := iConfig.(*blackhole.Config)
response, err := config.GetInternalResponse()
assert.Error(err).IsNil()
_, ok := response.(*blackhole.HTTPResponse)
assert.Bool(ok).IsTrue()
}

View File

@ -1,9 +0,0 @@
package conf
import (
"v2ray.com/core/common/serial"
)
type Buildable interface {
Build() (*serial.TypedMessage, error)
}

View File

@ -1,178 +0,0 @@
package conf
import (
"encoding/json"
"strings"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
)
type StringList []string
func NewStringList(raw []string) *StringList {
list := StringList(raw)
return &list
}
func (v StringList) Len() int {
return len(v)
}
func (v *StringList) UnmarshalJSON(data []byte) error {
var strarray []string
if err := json.Unmarshal(data, &strarray); err == nil {
*v = *NewStringList(strarray)
return nil
}
var rawstr string
if err := json.Unmarshal(data, &rawstr); err == nil {
strlist := strings.Split(rawstr, ",")
*v = *NewStringList(strlist)
return nil
}
return newError("unknown format of a string list: " + string(data))
}
type Address struct {
v2net.Address
}
func (v *Address) UnmarshalJSON(data []byte) error {
var rawStr string
if err := json.Unmarshal(data, &rawStr); err != nil {
return err
}
v.Address = v2net.ParseAddress(rawStr)
return nil
}
func (v *Address) Build() *v2net.IPOrDomain {
return v2net.NewIPOrDomain(v.Address)
}
type Network string
func (v Network) Build() v2net.Network {
return v2net.ParseNetwork(string(v))
}
type NetworkList []Network
func (v *NetworkList) UnmarshalJSON(data []byte) error {
var strarray []Network
if err := json.Unmarshal(data, &strarray); err == nil {
nl := NetworkList(strarray)
*v = nl
return nil
}
var rawstr Network
if err := json.Unmarshal(data, &rawstr); err == nil {
strlist := strings.Split(string(rawstr), ",")
nl := make([]Network, len(strlist))
for idx, network := range strlist {
nl[idx] = Network(network)
}
*v = nl
return nil
}
return newError("unknown format of a string list: " + string(data))
}
func (v *NetworkList) Build() *v2net.NetworkList {
if v == nil {
return &v2net.NetworkList{
Network: []v2net.Network{v2net.Network_TCP},
}
}
list := new(v2net.NetworkList)
for _, network := range *v {
list.Network = append(list.Network, network.Build())
}
return list
}
func parseIntPort(data []byte) (v2net.Port, error) {
var intPort uint32
err := json.Unmarshal(data, &intPort)
if err != nil {
return v2net.Port(0), err
}
return v2net.PortFromInt(intPort)
}
func parseStringPort(data []byte) (v2net.Port, v2net.Port, error) {
var s string
err := json.Unmarshal(data, &s)
if err != nil {
return v2net.Port(0), v2net.Port(0), err
}
pair := strings.SplitN(s, "-", 2)
if len(pair) == 0 {
return v2net.Port(0), v2net.Port(0), newError("Config: Invalid port range: ", s)
}
if len(pair) == 1 {
port, err := v2net.PortFromString(pair[0])
return port, port, err
}
fromPort, err := v2net.PortFromString(pair[0])
if err != nil {
return v2net.Port(0), v2net.Port(0), err
}
toPort, err := v2net.PortFromString(pair[1])
if err != nil {
return v2net.Port(0), v2net.Port(0), err
}
return fromPort, toPort, nil
}
type PortRange struct {
From uint32
To uint32
}
func (v *PortRange) Build() *v2net.PortRange {
return &v2net.PortRange{
From: v.From,
To: v.To,
}
}
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
func (v *PortRange) UnmarshalJSON(data []byte) error {
port, err := parseIntPort(data)
if err == nil {
v.From = uint32(port)
v.To = uint32(port)
return nil
}
from, to, err := parseStringPort(data)
if err == nil {
v.From = uint32(from)
v.To = uint32(to)
if v.From > v.To {
return newError("invalid port range ", v.From, " -> ", v.To)
}
return nil
}
return newError("invalid port range: ", string(data))
}
type User struct {
EmailString string `json:"email"`
LevelByte byte `json:"level"`
}
func (v *User) Build() *protocol.User {
return &protocol.User{
Email: v.EmailString,
Level: uint32(v.LevelByte),
}
}

View File

@ -1,185 +0,0 @@
package conf_test
import (
"encoding/json"
"testing"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/testing/assert"
. "v2ray.com/core/tools/conf"
)
func TestStringListUnmarshalError(t *testing.T) {
assert := assert.On(t)
rawJson := `1234`
list := new(StringList)
err := json.Unmarshal([]byte(rawJson), list)
assert.Error(err).IsNotNil()
}
func TestStringListLen(t *testing.T) {
assert := assert.On(t)
rawJson := `"a, b, c, d"`
list := new(StringList)
err := json.Unmarshal([]byte(rawJson), list)
assert.Error(err).IsNil()
assert.Int(list.Len()).Equals(4)
}
func TestIPParsing(t *testing.T) {
assert := assert.On(t)
rawJson := "\"8.8.8.8\""
var address Address
err := json.Unmarshal([]byte(rawJson), &address)
assert.Error(err).IsNil()
assert.Bytes([]byte(address.IP())).Equals([]byte{8, 8, 8, 8})
}
func TestDomainParsing(t *testing.T) {
assert := assert.On(t)
rawJson := "\"v2ray.com\""
var address Address
err := json.Unmarshal([]byte(rawJson), &address)
assert.Error(err).IsNil()
assert.String(address.Domain()).Equals("v2ray.com")
}
func TestInvalidAddressJson(t *testing.T) {
assert := assert.On(t)
rawJson := "1234"
var address Address
err := json.Unmarshal([]byte(rawJson), &address)
assert.Error(err).IsNotNil()
}
func TestStringNetwork(t *testing.T) {
assert := assert.On(t)
var network Network
err := json.Unmarshal([]byte(`"tcp"`), &network)
assert.Error(err).IsNil()
assert.Bool(network.Build() == v2net.Network_TCP).IsTrue()
}
func TestArrayNetworkList(t *testing.T) {
assert := assert.On(t)
var list NetworkList
err := json.Unmarshal([]byte("[\"Tcp\"]"), &list)
assert.Error(err).IsNil()
nlist := list.Build()
assert.Bool(nlist.HasNetwork(v2net.ParseNetwork("tcp"))).IsTrue()
assert.Bool(nlist.HasNetwork(v2net.ParseNetwork("udp"))).IsFalse()
}
func TestStringNetworkList(t *testing.T) {
assert := assert.On(t)
var list NetworkList
err := json.Unmarshal([]byte("\"TCP, ip\""), &list)
assert.Error(err).IsNil()
nlist := list.Build()
assert.Bool(nlist.HasNetwork(v2net.ParseNetwork("tcp"))).IsTrue()
assert.Bool(nlist.HasNetwork(v2net.ParseNetwork("udp"))).IsFalse()
}
func TestInvalidNetworkJson(t *testing.T) {
assert := assert.On(t)
var list NetworkList
err := json.Unmarshal([]byte("0"), &list)
assert.Error(err).IsNotNil()
}
func TestIntPort(t *testing.T) {
assert := assert.On(t)
var portRange PortRange
err := json.Unmarshal([]byte("1234"), &portRange)
assert.Error(err).IsNil()
assert.Uint32(portRange.From).Equals(1234)
assert.Uint32(portRange.To).Equals(1234)
}
func TestOverRangeIntPort(t *testing.T) {
assert := assert.On(t)
var portRange PortRange
err := json.Unmarshal([]byte("70000"), &portRange)
assert.Error(err).IsNotNil()
err = json.Unmarshal([]byte("-1"), &portRange)
assert.Error(err).IsNotNil()
}
func TestSingleStringPort(t *testing.T) {
assert := assert.On(t)
var portRange PortRange
err := json.Unmarshal([]byte("\"1234\""), &portRange)
assert.Error(err).IsNil()
assert.Uint32(portRange.From).Equals(1234)
assert.Uint32(portRange.To).Equals(1234)
}
func TestStringPairPort(t *testing.T) {
assert := assert.On(t)
var portRange PortRange
err := json.Unmarshal([]byte("\"1234-5678\""), &portRange)
assert.Error(err).IsNil()
assert.Uint32(portRange.From).Equals(1234)
assert.Uint32(portRange.To).Equals(5678)
}
func TestOverRangeStringPort(t *testing.T) {
assert := assert.On(t)
var portRange PortRange
err := json.Unmarshal([]byte("\"65536\""), &portRange)
assert.Error(err).IsNotNil()
err = json.Unmarshal([]byte("\"70000-80000\""), &portRange)
assert.Error(err).IsNotNil()
err = json.Unmarshal([]byte("\"1-90000\""), &portRange)
assert.Error(err).IsNotNil()
err = json.Unmarshal([]byte("\"700-600\""), &portRange)
assert.Error(err).IsNotNil()
}
func TestUserParsing(t *testing.T) {
assert := assert.On(t)
user := new(User)
err := json.Unmarshal([]byte(`{
"id": "96edb838-6d68-42ef-a933-25f7ac3a9d09",
"email": "love@v2ray.com",
"level": 1,
"alterId": 100
}`), user)
assert.Error(err).IsNil()
nUser := user.Build()
assert.Byte(byte(nUser.Level)).Equals(1)
assert.String(nUser.Email).Equals("love@v2ray.com")
}
func TestInvalidUserJson(t *testing.T) {
assert := assert.On(t)
user := new(User)
err := json.Unmarshal([]byte(`{"email": 1234}`), user)
assert.Error(err).IsNotNil()
}

View File

@ -1,3 +1,16 @@
package conf
import (
"io"
"v2ray.com/core"
jsonconf "v2ray.com/ext/tools/conf/serial"
)
//go:generate go run $GOPATH/src/v2ray.com/core/tools/generrorgen/main.go -pkg conf -path Tools,Conf
func init() {
core.RegisterConfigLoader(core.ConfigFormat_JSON, func(input io.Reader) (*core.Config, error) {
return jsonconf.LoadJSONConfig(input)
})
}

View File

@ -1,32 +0,0 @@
package conf
import (
"v2ray.com/core/app/dns"
v2net "v2ray.com/core/common/net"
)
type DnsConfig struct {
Servers []*Address `json:"servers"`
Hosts map[string]*Address `json:"hosts"`
}
func (v *DnsConfig) Build() *dns.Config {
config := new(dns.Config)
config.NameServers = make([]*v2net.Endpoint, len(v.Servers))
for idx, server := range v.Servers {
config.NameServers[idx] = &v2net.Endpoint{
Network: v2net.Network_UDP,
Address: server.Build(),
Port: 53,
}
}
if v.Hosts != nil {
config.Hosts = make(map[string]*v2net.IPOrDomain)
for domain, ip := range v.Hosts {
config.Hosts[domain] = ip.Build()
}
}
return config
}

View File

@ -1,29 +0,0 @@
package conf_test
import (
"encoding/json"
"testing"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/testing/assert"
. "v2ray.com/core/tools/conf"
)
func TestDnsConfigParsing(t *testing.T) {
assert := assert.On(t)
rawJson := `{
"servers": ["8.8.8.8"]
}`
jsonConfig := new(DnsConfig)
err := json.Unmarshal([]byte(rawJson), jsonConfig)
assert.Error(err).IsNil()
config := jsonConfig.Build()
assert.Int(len(config.NameServers)).Equals(1)
dest := config.NameServers[0].AsDestination()
assert.Destination(dest).IsUDP()
assert.Address(dest.Address).Equals(v2net.IPAddress([]byte{8, 8, 8, 8}))
assert.Port(dest.Port).Equals(v2net.Port(53))
}

View File

@ -1,26 +0,0 @@
package conf
import (
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/dokodemo"
)
type DokodemoConfig struct {
Host *Address `json:"address"`
PortValue uint16 `json:"port"`
NetworkList *NetworkList `json:"network"`
TimeoutValue uint32 `json:"timeout"`
Redirect bool `json:"followRedirect"`
}
func (v *DokodemoConfig) Build() (*serial.TypedMessage, error) {
config := new(dokodemo.Config)
if v.Host != nil {
config.Address = v.Host.Build()
}
config.Port = uint32(v.PortValue)
config.NetworkList = v.NetworkList.Build()
config.Timeout = v.TimeoutValue
config.FollowRedirect = v.Redirect
return serial.ToTypedMessage(config), nil
}

View File

@ -1,50 +0,0 @@
package conf
import (
"net"
"strings"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/freedom"
)
type FreedomConfig struct {
DomainStrategy string `json:"domainStrategy"`
Timeout *uint32 `json:"timeout"`
Redirect string `json:"redirect"`
}
func (v *FreedomConfig) Build() (*serial.TypedMessage, error) {
config := new(freedom.Config)
config.DomainStrategy = freedom.Config_AS_IS
domainStrategy := strings.ToLower(v.DomainStrategy)
if domainStrategy == "useip" || domainStrategy == "use_ip" {
config.DomainStrategy = freedom.Config_USE_IP
}
config.Timeout = 600
if v.Timeout != nil {
config.Timeout = *v.Timeout
}
if len(v.Redirect) > 0 {
host, portStr, err := net.SplitHostPort(v.Redirect)
if err != nil {
return nil, newError("invalid redirect address: ", v.Redirect, ": ", err).Base(err)
}
port, err := v2net.PortFromString(portStr)
if err != nil {
return nil, newError("invalid redirect port: ", v.Redirect, ": ", err).Base(err)
}
if len(host) == 0 {
host = "127.0.0.1"
}
config.DestinationOverride = &freedom.DestinationOverride{
Server: &protocol.ServerEndpoint{
Address: v2net.NewIPOrDomain(v2net.ParseAddress(host)),
Port: uint32(port),
},
}
}
return serial.ToTypedMessage(config), nil
}

View File

@ -1,18 +0,0 @@
package conf
import (
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/http"
)
type HttpServerConfig struct {
Timeout uint32 `json:"timeout"`
}
func (v *HttpServerConfig) Build() (*serial.TypedMessage, error) {
config := &http.ServerConfig{
Timeout: v.Timeout,
}
return serial.ToTypedMessage(config), nil
}

View File

@ -1,115 +0,0 @@
package json
import (
"io"
)
// State is the internal state of parser.
type State byte
const (
StateContent State = iota
StateEscape
StateDoubleQuote
StateDoubleQuoteEscape
StateSingleQuote
StateSingleQuoteEscape
StateComment
StateSlash
StateMultilineComment
StateMultilineCommentStar
)
// Reader is a JSON reader which allows comments.
type Reader struct {
io.Reader
state State
}
// Read implements io.Reader.Read().
func (v *Reader) Read(b []byte) (int, error) {
n, err := v.Reader.Read(b)
if err != nil {
return n, err
}
p := b[:0]
for _, x := range b[:n] {
switch v.state {
case StateContent:
switch x {
case '"':
v.state = StateDoubleQuote
p = append(p, x)
case '\'':
v.state = StateSingleQuote
p = append(p, x)
case '\\':
v.state = StateEscape
case '#':
v.state = StateComment
case '/':
v.state = StateSlash
default:
p = append(p, x)
}
case StateEscape:
p = append(p, '\\', x)
v.state = StateContent
case StateDoubleQuote:
switch x {
case '"':
v.state = StateContent
p = append(p, x)
case '\\':
v.state = StateDoubleQuoteEscape
default:
p = append(p, x)
}
case StateDoubleQuoteEscape:
p = append(p, '\\', x)
v.state = StateDoubleQuote
case StateSingleQuote:
switch x {
case '\'':
v.state = StateContent
p = append(p, x)
case '\\':
v.state = StateSingleQuoteEscape
default:
p = append(p, x)
}
case StateSingleQuoteEscape:
p = append(p, '\\', x)
v.state = StateSingleQuote
case StateComment:
if x == '\n' {
v.state = StateContent
}
case StateSlash:
switch x {
case '/':
v.state = StateComment
case '*':
v.state = StateMultilineComment
default:
p = append(p, '/', x)
}
case StateMultilineComment:
if x == '*' {
v.state = StateMultilineCommentStar
}
case StateMultilineCommentStar:
switch x {
case '/':
v.state = StateContent
case '*':
// Stay
default:
v.state = StateMultilineComment
}
default:
panic("Unknown state.")
}
}
return len(p), nil
}

View File

@ -1,50 +0,0 @@
package json_test
import (
"testing"
"bytes"
"v2ray.com/core/testing/assert"
. "v2ray.com/core/tools/conf/json"
)
func TestReader(t *testing.T) {
assert := assert.On(t)
data := []struct {
input string
output string
}{
{
`
content #comment 1
#comment 2
content 2`,
`
content content 2`},
{`content`, `content`},
{" ", " "},
{`con/*abcd*/tent`, "content"},
{`
text // adlkhdf /*
//comment adfkj
text 2*/`, `
text text 2*`},
{`"//"content`, `"//"content`},
{`abcd'//'abcd`, `abcd'//'abcd`},
{`"\""`, `"\""`},
{`\"/*abcd*/\"`, `\"\"`},
}
for _, testCase := range data {
reader := &Reader{
Reader: bytes.NewReader([]byte(testCase.input)),
}
actual := make([]byte, 1024)
n, err := reader.Read(actual)
assert.Error(err).IsNil()
assert.String(string(actual[:n])).Equals(testCase.output)
}
}

View File

@ -1,79 +0,0 @@
package conf
import "encoding/json"
type ConfigCreator func() interface{}
type ConfigCreatorCache map[string]ConfigCreator
func (v ConfigCreatorCache) RegisterCreator(id string, creator ConfigCreator) error {
if _, found := v[id]; found {
return newError(id, " already registered.").AtError()
}
v[id] = creator
return nil
}
func (v ConfigCreatorCache) CreateConfig(id string) (interface{}, error) {
creator, found := v[id]
if !found {
return nil, newError("unknown config id: ", id)
}
return creator(), nil
}
type JSONConfigLoader struct {
cache ConfigCreatorCache
idKey string
configKey string
}
func NewJSONConfigLoader(cache ConfigCreatorCache, idKey string, configKey string) *JSONConfigLoader {
return &JSONConfigLoader{
idKey: idKey,
configKey: configKey,
cache: cache,
}
}
func (v *JSONConfigLoader) LoadWithID(raw []byte, id string) (interface{}, error) {
creator, found := v.cache[id]
if !found {
return nil, newError("unknown config id: ", id).AtError()
}
config := creator()
if err := json.Unmarshal(raw, config); err != nil {
return nil, err
}
return config, nil
}
func (v *JSONConfigLoader) Load(raw []byte) (interface{}, string, error) {
var obj map[string]json.RawMessage
if err := json.Unmarshal(raw, &obj); err != nil {
return nil, "", err
}
rawID, found := obj[v.idKey]
if !found {
return nil, "", newError(v.idKey, " not found in JSON context").AtError()
}
var id string
if err := json.Unmarshal(rawID, &id); err != nil {
return nil, "", err
}
rawConfig := json.RawMessage(raw)
if len(v.configKey) > 0 {
configValue, found := obj[v.configKey]
if !found {
return nil, "", newError(v.configKey, " not found in JSON content").AtError()
}
rawConfig = configValue
}
config, err := v.LoadWithID([]byte(rawConfig), id)
if err != nil {
return nil, id, err
}
return config, id, nil
}

View File

@ -1,48 +0,0 @@
package conf
import (
"strings"
"v2ray.com/core/app/log"
)
type LogConfig struct {
AccessLog string `json:"access"`
ErrorLog string `json:"error"`
LogLevel string `json:"loglevel"`
}
func (v *LogConfig) Build() *log.Config {
if v == nil {
return nil
}
config := &log.Config{
ErrorLogType: log.LogType_Console,
AccessLogType: log.LogType_Console,
}
if len(v.AccessLog) > 0 {
config.AccessLogPath = v.AccessLog
config.AccessLogType = log.LogType_File
}
if len(v.ErrorLog) > 0 {
config.ErrorLogPath = v.ErrorLog
config.ErrorLogType = log.LogType_File
}
level := strings.ToLower(v.LogLevel)
switch level {
case "debug":
config.ErrorLogLevel = log.LogLevel_Debug
case "info":
config.ErrorLogLevel = log.LogLevel_Info
case "error":
config.ErrorLogLevel = log.LogLevel_Error
case "none":
config.ErrorLogType = log.LogType_None
config.AccessLogType = log.LogType_None
default:
config.ErrorLogLevel = log.LogLevel_Warning
}
return config
}

View File

@ -1,241 +0,0 @@
package conf
import (
"encoding/json"
"strconv"
"strings"
"v2ray.com/core/app/log"
"v2ray.com/core/app/router"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/tools/geoip"
"github.com/golang/protobuf/proto"
)
type RouterRulesConfig struct {
RuleList []json.RawMessage `json:"rules"`
DomainStrategy string `json:"domainStrategy"`
}
type RouterConfig struct {
Settings *RouterRulesConfig `json:"settings"`
}
func (c *RouterConfig) Build() (*router.Config, error) {
if c.Settings == nil {
return nil, newError("Router settings is not specified.")
}
config := new(router.Config)
settings := c.Settings
config.DomainStrategy = router.Config_AsIs
config.Rule = make([]*router.RoutingRule, len(settings.RuleList))
domainStrategy := strings.ToLower(settings.DomainStrategy)
if domainStrategy == "alwaysip" {
config.DomainStrategy = router.Config_UseIp
} else if domainStrategy == "ipifnonmatch" {
config.DomainStrategy = router.Config_IpIfNonMatch
}
for idx, rawRule := range settings.RuleList {
rule, err := ParseRule(rawRule)
if err != nil {
return nil, err
}
config.Rule[idx] = rule
}
return config, nil
}
type RouterRule struct {
Type string `json:"type"`
OutboundTag string `json:"outboundTag"`
}
func parseIP(s string) (*router.CIDR, error) {
var addr, mask string
i := strings.Index(s, "/")
if i < 0 {
addr = s
} else {
addr = s[:i]
mask = s[i+1:]
}
ip := v2net.ParseAddress(addr)
switch ip.Family() {
case v2net.AddressFamilyIPv4:
bits := uint32(32)
if len(mask) > 0 {
bits64, err := strconv.ParseUint(mask, 10, 32)
if err != nil {
return nil, newError("invalid network mask for router: ", mask).Base(err)
}
bits = uint32(bits64)
}
if bits > 32 {
return nil, newError("invalid network mask for router: ", bits)
}
return &router.CIDR{
Ip: []byte(ip.IP()),
Prefix: bits,
}, nil
case v2net.AddressFamilyIPv6:
bits := uint32(128)
if len(mask) > 0 {
bits64, err := strconv.ParseUint(mask, 10, 32)
if err != nil {
return nil, newError("invalid network mask for router: ", mask).Base(err)
}
bits = uint32(bits64)
}
if bits > 128 {
return nil, newError("invalid network mask for router: ", bits)
}
return &router.CIDR{
Ip: []byte(ip.IP()),
Prefix: bits,
}, nil
default:
return nil, newError("unsupported address for router: ", s)
}
}
func parseFieldRule(msg json.RawMessage) (*router.RoutingRule, error) {
type RawFieldRule struct {
RouterRule
Domain *StringList `json:"domain"`
IP *StringList `json:"ip"`
Port *PortRange `json:"port"`
Network *NetworkList `json:"network"`
SourceIP *StringList `json:"source"`
User *StringList `json:"user"`
InboundTag *StringList `json:"inboundTag"`
}
rawFieldRule := new(RawFieldRule)
err := json.Unmarshal(msg, rawFieldRule)
if err != nil {
return nil, err
}
rule := new(router.RoutingRule)
rule.Tag = rawFieldRule.OutboundTag
if rawFieldRule.Domain != nil {
for _, domain := range *rawFieldRule.Domain {
domainRule := new(router.Domain)
switch {
case strings.HasPrefix(domain, "regexp:"):
domainRule.Type = router.Domain_Regex
domainRule.Value = domain[7:]
case strings.HasPrefix(domain, "domain:"):
domainRule.Type = router.Domain_Domain
domainRule.Value = domain[7:]
default:
domainRule.Type = router.Domain_Plain
domainRule.Value = domain
}
rule.Domain = append(rule.Domain, domainRule)
}
}
if rawFieldRule.IP != nil {
for _, ip := range *rawFieldRule.IP {
ipRule, err := parseIP(ip)
if err != nil {
return nil, newError("invalid IP: ", ip).Base(err)
}
rule.Cidr = append(rule.Cidr, ipRule)
}
}
if rawFieldRule.Port != nil {
rule.PortRange = rawFieldRule.Port.Build()
}
if rawFieldRule.Network != nil {
rule.NetworkList = rawFieldRule.Network.Build()
}
if rawFieldRule.SourceIP != nil {
for _, ip := range *rawFieldRule.SourceIP {
ipRule, err := parseIP(ip)
if err != nil {
return nil, newError("invalid IP: ", ip).Base(err)
}
rule.SourceCidr = append(rule.SourceCidr, ipRule)
}
}
if rawFieldRule.User != nil {
for _, s := range *rawFieldRule.User {
rule.UserEmail = append(rule.UserEmail, s)
}
}
if rawFieldRule.InboundTag != nil {
for _, s := range *rawFieldRule.InboundTag {
rule.InboundTag = append(rule.InboundTag, s)
}
}
return rule, nil
}
func ParseRule(msg json.RawMessage) (*router.RoutingRule, error) {
rawRule := new(RouterRule)
err := json.Unmarshal(msg, rawRule)
if err != nil {
return nil, newError("invalid router rule").Base(err)
}
if rawRule.Type == "field" {
fieldrule, err := parseFieldRule(msg)
if err != nil {
return nil, newError("invalid field rule").Base(err)
}
return fieldrule, nil
}
if rawRule.Type == "chinaip" {
chinaiprule, err := parseChinaIPRule(msg)
if err != nil {
return nil, newError("invalid chinaip rule").Base(err)
}
return chinaiprule, nil
}
if rawRule.Type == "chinasites" {
chinasitesrule, err := parseChinaSitesRule(msg)
if err != nil {
return nil, newError("invalid chinasites rule").Base(err)
}
return chinasitesrule, nil
}
return nil, newError("unknown router rule type: ", rawRule.Type)
}
func parseChinaIPRule(data []byte) (*router.RoutingRule, error) {
rawRule := new(RouterRule)
err := json.Unmarshal(data, rawRule)
if err != nil {
return nil, newError("invalid router rule").Base(err)
}
var chinaIPs geoip.CountryIPRange
if err := proto.Unmarshal(geoip.ChinaIPs, &chinaIPs); err != nil {
return nil, newError("invalid china ips").Base(err)
}
return &router.RoutingRule{
Tag: rawRule.OutboundTag,
Cidr: chinaIPs.Ips,
}, nil
}
func parseChinaSitesRule(data []byte) (*router.RoutingRule, error) {
rawRule := new(RouterRule)
err := json.Unmarshal(data, rawRule)
if err != nil {
log.Trace(newError("invalid router rule: ", err).AtError())
return nil, err
}
return &router.RoutingRule{
Tag: rawRule.OutboundTag,
Domain: chinaSitesDomains,
}, nil
}

View File

@ -1,483 +0,0 @@
package conf
import (
"v2ray.com/core/app/router"
)
var (
chinaSitesDomains []*router.Domain
)
func init() {
domains := []string{
"cn",
"xn--fiqs8s", /* .中国 */
"10010.com",
"100offer.com",
"115.com",
"123juzi.com",
"123juzi.net",
"123u.com",
"126.com",
"126.net",
"127.net",
"163.com",
"17173.com",
"17cdn.com",
"188.com",
"1905.com",
"21cn.com",
"2288.org",
"2345.com",
"263.net",
"2cto.com",
"3322.org",
"35.com",
"360doc.com",
"360buy.com",
"360buyimg.com",
"360safe.com",
"36kr.com",
"39.net",
"3dmgame.com",
"3conline.com",
"4399.com",
"500d.me",
"50bang.org",
"51.la",
"51credit.com",
"51cto.com",
"51jingying.com",
"51job.com",
"51jobcdn.com",
"51wendang.com",
"55.com",
"51yes.com",
"55bbs.com",
"58.com",
"6rooms.com",
"71.am",
"7k7k.com",
"900.la",
"9718.com",
"9xu.com",
"abchina.com",
"acfun.tv",
"acgvideo.com",
"agrantsem.com",
"aicdn.com",
"aixifan.com",
"alibaba.com",
"alicdn.com",
"aliimg.com.com",
"alipay.com",
"alipayobjects.com",
"aliyun.com",
"aliyuncdn.com",
"aliyuncs.com",
"allyes.com",
"amap.com",
"anjuke.com",
"anquan.org",
"appinn.com",
"babytree.com",
"babytreeimg.com",
"baidu.com",
"baiducontent.com",
"baidupcs.com",
"baidustatic.com",
"baifendian.com",
"baifubao.com",
"baihe.com",
"baike.com",
"baixing.com",
"baixing.net",
"bankcomm.com",
"bankofchina.com",
"bcy.net",
"bdimg.com",
"bdstatic.com",
"bilibili.com",
"cn.bing.com",
"bitauto.com",
"bitautoimg.com",
"bobo.com",
"bootcss.com",
"btcfans.com",
"caiyunapp.com",
"ccb.com",
"cctv.com",
"cctvpic.com",
"cdn20.com",
"cebbank.com",
"ch.com",
"chashebao.com",
"che168.com",
"china.com",
"chinacache.com",
"chinacache.net",
"chinahr.com",
"chinamobile.com",
"chinapay.com",
"chinatranslation.net",
"chinaz.com",
"chiphell.com",
"chouti.com",
"chuangxin.com",
"chuansong.me",
"clouddn.com",
"cloudxns.com",
"cmbchina.com",
"cnbeta.com",
"cnbetacdn.com",
"cnblogs.com",
"cnepub.com",
"cnzz.com",
"coding.net",
"coolapk.com",
"cqvip.com",
"csbew.com",
"csdn.net",
"ctrip.com",
"cubead.com",
"dajie.com",
"dajieimg.com",
"dangdang.com",
"daocloud.io",
"daovoice.io",
"dbank.com",
"dedecms.com",
"dgtle.com",
"diandian.com",
"dianping.com",
"diopic.net",
"docin.com",
"dockerone.com",
"dockone.io",
"donews.com",
"douban.com",
"doubanio.com",
"dpfile.com",
"duomai.com",
"duoshuo.com",
"duowan.com",
"dxpmedia.com",
"eastday.com",
"ecitic.com",
"emarbox.com",
"eoeandroid.com",
"etao.com",
"excelhome.net",
"fanli.com",
"feng.com",
"fengniao.com",
"fhldns.com",
"foxmail.com",
"geekpark.net",
"geetest.com",
"geilicdn.com",
"getui.com",
"google-analytics.com",
"growingio.com",
"gtags.net",
"gwdang.com",
"hao123.com",
"hao123img.com",
"haosou.com",
"hdslb.com",
"henha.com",
"henkuai.com",
"hexun.com",
"hichina.com",
"huanqiu.com",
"hunantv.com",
"huochepiao.com",
"hupu.com",
"hupucdn.com",
"huxiu.com",
"iask.com",
"iciba.com",
"idqqimg.com",
"ifanr.com",
"ifanrusercontent.com",
"ifanrx.com",
"ifeng.com",
"ifengimg.com",
"ijinshan.com",
"ikafan.com",
"imedao.com",
"imgo.tv",
"imooc.com",
"infoq.com",
"infoqstatic.com",
"ip138.com",
"ipinyou.com",
"ipip.net",
"ip-cdn.com",
"iqiyi.com",
"it165.net",
"it168.com",
"it610.com",
"iteye.com",
"ithome.com",
"itjuzi.com",
"jandan.net",
"jd.com",
"jb51.com",
"jia.com",
"jianshu.com",
"jianshu.io",
"jiasuhui.com",
"jiathis.com",
"jiayuan.com",
"jikexueyuan.com",
"jisuanke.com",
"jmstatic.com",
"jsdelivr.net",
"jstv.com",
"jumei.com",
"jyimg.com",
"kaixin001.com",
"kanimg.com",
"kankanews.com",
"kejet.net",
"kf5.com",
"kimiss.com",
"kouclo.com",
"koudai.com",
"koudai8.com",
"ku6.com",
"ku6cdn.com",
"ku6img.com",
"kuqin.com",
"lady8844.com",
"lagou.com",
"le.com",
"leanote.com",
"leiphone.com",
"leju.com",
"leturich.org",
"letv.com",
"letvcdn.com",
"letvimg.com",
"liantu.me",
"liaoxuefeng.com",
"liba.com",
"libaclub.com",
"liepin.com",
"lietou.com",
"lightonus.com",
"linkvans.com",
"linuxidc.com",
"liuxiaoer.com",
"lofter.com",
"lu.com",
"lufax.com",
"lufaxcdn.com",
"lvmama.com",
"lxdns.com",
"lxway.com",
"ly.com",
"mayihr.com",
"mechina.org",
"mediav.com",
"meiqia.com",
"meika360.com",
"meilishuo.com",
"meishij.net",
"meituan.com",
"meizu.com",
"mgtv.com",
"mi.com",
"miaopai.com",
"miaozhen.com",
"miui.com",
"mmbang.com",
"mmbang.info",
"mmstat.com",
"mogucdn.com",
"mogujie.com",
"mop.com",
"mscbsc.com",
"mukewang.com",
"mydrivers.com",
"myshow360.net",
"mzstatic.com",
"netease.com",
"newbandeng.com",
"ngacn.cc",
"ntalker.com",
"nvsheng.com",
"oeeee.com",
"ol-img.com",
"oneapm.com",
"onlinedown.net",
"onlinesjtu.com",
"oschina.net",
"paipai.com",
"pcbeta.com",
"pchome.net",
"pingan.com",
"pingplusplus.com",
"pps.tv",
"psbc.com",
"pubyun.com",
"qbox.me",
"qcloud.com",
"qhimg.com",
"qiaobutang.com",
"qidian.com",
"qingcloud.com",
"qingsongchou.com",
"qiniu.com",
"qiniucdn.com",
"qiniudn.com",
"qiniudns.com",
"qiyi.com",
"qiyipic.com",
"qtmojo.com",
"qq.com",
"qqmail.com",
"qunar.com",
"qunarzz.com",
"qzone.com",
"renren.com",
"runoob.com",
"ruanmei.com",
"ruby-china.org",
"sandai.net",
"sanguosha.com",
"sanwen.net",
"segmentfault.com",
"sf-express.com",
"sharejs.com",
"shmetro.com",
"shutcm.com",
"simei8.com",
"sina.com",
"sinaapp.com",
"sinaedge.com",
"sinaimg.com",
"sinajs.com",
"szzfgjj.com",
"smzdm.com",
"sohu.com",
"sogou.com",
"sogoucdn.com",
"soso.com",
"sspai.com",
"starbaby.cc",
"starbaby.com",
"staticfile.org",
"stockstar.com",
"suning.com",
"szfw.org",
"t1y5.com",
"tanx.com",
"tao123.com",
"taobao.com",
"taobaocdn.com",
"tbcache.com",
"tencent.com",
"tenpay.com",
"tenxcloud.com",
"tiebaimg.com",
"tietuku.com",
"tiexue.net",
"tmall.com",
"tmcdn.net",
"topthink.com",
"tudou.com",
"tudouui.com",
"tuicool.com",
"tuniu.com",
"tutuapp.com",
"u17.com",
"useso.com",
"unionpay.com",
"unionpaysecure.com",
"upyun.com",
"upaiyun.com",
"v2ex.com",
"v5875.com",
"vamaker.com",
"vancl.com",
"vcimg.com",
"vip.com",
"wallstreetcn.com",
"wandoujia.com",
"wdjimg.com",
"weand.com",
"webterren.com",
"weibo.com",
"weicaifu.com",
"weidian.com",
"weiphone.com",
"weiphone.net",
"weixing.com",
"weiyun.com",
"wonnder.com",
"worktile.com",
"wooyun.org",
"wrating.com",
"wscdns.com",
"wumii.com",
"xiachufang.com",
"xiami.com",
"xiaokaxiu.com",
"xiaomi.com",
"xitu.com",
"xinhuanet.com",
"xinshipu.com",
"xiu8.com",
"xnpic.com",
"xueqiu.com",
"xunlei.com",
"xywy.com",
"yaolan.com",
"yccdn.com",
"yeepay.com",
"yesky.com",
"yigao.com",
"yihaodian.com",
"yihaodianimg.com",
"yingjiesheng.com",
"yinxiang.com",
"yixi.tv",
"yjbys.com",
"yhd.com",
"youboy.com",
"youku.com",
"yunba.io",
"yundaex.com",
"yunshipei.com",
"yupoo.com",
"yuzua.com",
"yy.com",
"yytcdn.com",
"zampda.net",
"zastatic.com",
"zbjimg.com",
"zdfans.com",
"zhenai.com",
"zhanqi.tv",
"zhaopin.com",
"zhihu.com",
"zhimg.com",
"zhiziyun.com",
"zjstv.com",
"zhubajie.com",
"zrblog.net",
"zuche.com",
"zuchecdn.com",
}
chinaSitesDomains = make([]*router.Domain, len(domains))
for idx, pattern := range domains {
chinaSitesDomains[idx] = &router.Domain{
Type: router.Domain_Domain,
Value: pattern,
}
}
}

View File

@ -1,125 +0,0 @@
package conf_test
import (
"context"
"net"
"testing"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/testing/assert"
. "v2ray.com/core/tools/conf"
)
func makeDestination(ip string) v2net.Destination {
return v2net.TCPDestination(v2net.IPAddress(net.ParseIP(ip)), 80)
}
func makeDomainDestination(domain string) v2net.Destination {
return v2net.TCPDestination(v2net.DomainAddress(domain), 80)
}
func TestChinaIPJson(t *testing.T) {
assert := assert.On(t)
rule, err := ParseRule([]byte(`{
"type": "chinaip",
"outboundTag": "x"
}`))
assert.Error(err).IsNil()
assert.String(rule.Tag).Equals("x")
cond, err := rule.BuildCondition()
assert.Error(err).IsNil()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("121.14.1.189"), 80)))).IsTrue() // sina.com.cn
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("101.226.103.106"), 80)))).IsTrue() // qq.com
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("115.239.210.36"), 80)))).IsTrue() // image.baidu.com
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("120.135.126.1"), 80)))).IsTrue()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("8.8.8.8"), 80)))).IsFalse()
}
func TestChinaSitesJson(t *testing.T) {
assert := assert.On(t)
rule, err := ParseRule([]byte(`{
"type": "chinasites",
"outboundTag": "y"
}`))
assert.Error(err).IsNil()
assert.String(rule.Tag).Equals("y")
cond, err := rule.BuildCondition()
assert.Error(err).IsNil()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("v.qq.com"), 80)))).IsTrue()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.163.com"), 80)))).IsTrue()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("ngacn.cc"), 80)))).IsTrue()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("12306.cn"), 80)))).IsTrue()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("v2ray.com"), 80)))).IsFalse()
}
func TestDomainRule(t *testing.T) {
assert := assert.On(t)
rule, err := ParseRule([]byte(`{
"type": "field",
"domain": [
"ooxx.com",
"oxox.com",
"regexp:\\.cn$"
],
"network": "tcp",
"outboundTag": "direct"
}`))
assert.Error(err).IsNil()
assert.Pointer(rule).IsNotNil()
cond, err := rule.BuildCondition()
assert.Error(err).IsNil()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.ooxx.com"), 80)))).IsTrue()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.aabb.com"), 80)))).IsFalse()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80)))).IsFalse()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.12306.cn"), 80)))).IsTrue()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.acn.com"), 80)))).IsFalse()
}
func TestIPRule(t *testing.T) {
assert := assert.On(t)
rule, err := ParseRule([]byte(`{
"type": "field",
"ip": [
"10.0.0.0/8",
"192.0.0.0/24"
],
"network": "tcp",
"outboundTag": "direct"
}`))
assert.Error(err).IsNil()
assert.Pointer(rule).IsNotNil()
cond, err := rule.BuildCondition()
assert.Error(err).IsNil()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.DomainAddress("www.ooxx.com"), 80)))).IsFalse()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80)))).IsTrue()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80)))).IsFalse()
assert.Bool(cond.Apply(proxy.ContextWithTarget(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{192, 0, 0, 1}), 80)))).IsTrue()
}
func TestSourceIPRule(t *testing.T) {
assert := assert.On(t)
rule, err := ParseRule([]byte(`{
"type": "field",
"source": [
"10.0.0.0/8",
"192.0.0.0/24"
],
"outboundTag": "direct"
}`))
assert.Error(err).IsNil()
assert.Pointer(rule).IsNotNil()
cond, err := rule.BuildCondition()
assert.Error(err).IsNil()
assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.DomainAddress("www.ooxx.com"), 80)))).IsFalse()
assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80)))).IsTrue()
assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80)))).IsFalse()
assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{192, 0, 0, 1}), 80)))).IsTrue()
}

View File

@ -1,130 +0,0 @@
package conf
import (
"strings"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/shadowsocks"
)
type ShadowsocksServerConfig struct {
Cipher string `json:"method"`
Password string `json:"password"`
UDP bool `json:"udp"`
Level byte `json:"level"`
Email string `json:"email"`
OTA *bool `json:"ota"`
}
func (v *ShadowsocksServerConfig) Build() (*serial.TypedMessage, error) {
config := new(shadowsocks.ServerConfig)
config.UdpEnabled = v.UDP
if len(v.Password) == 0 {
return nil, newError("Shadowsocks password is not specified.")
}
account := &shadowsocks.Account{
Password: v.Password,
Ota: shadowsocks.Account_Auto,
}
if v.OTA != nil {
if *v.OTA {
account.Ota = shadowsocks.Account_Enabled
} else {
account.Ota = shadowsocks.Account_Disabled
}
}
cipher := strings.ToLower(v.Cipher)
switch cipher {
case "aes-256-cfb":
account.CipherType = shadowsocks.CipherType_AES_256_CFB
case "aes-128-cfb":
account.CipherType = shadowsocks.CipherType_AES_128_CFB
case "chacha20":
account.CipherType = shadowsocks.CipherType_CHACHA20
case "chacha20-ietf":
account.CipherType = shadowsocks.CipherType_CHACHA20_IETF
default:
return nil, newError("unknown cipher method: " + cipher)
}
config.User = &protocol.User{
Email: v.Email,
Level: uint32(v.Level),
Account: serial.ToTypedMessage(account),
}
return serial.ToTypedMessage(config), nil
}
type ShadowsocksServerTarget struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Cipher string `json:"method"`
Password string `json:"password"`
Email string `json:"email"`
Ota bool `json:"ota"`
}
type ShadowsocksClientConfig struct {
Servers []*ShadowsocksServerTarget `json:"servers"`
}
func (v *ShadowsocksClientConfig) Build() (*serial.TypedMessage, error) {
config := new(shadowsocks.ClientConfig)
if len(v.Servers) == 0 {
return nil, newError("0 Shadowsocks server configured.")
}
serverSpecs := make([]*protocol.ServerEndpoint, len(v.Servers))
for idx, server := range v.Servers {
if server.Address == nil {
return nil, newError("Shadowsocks server address is not set.")
}
if server.Port == 0 {
return nil, newError("Invalid Shadowsocks port.")
}
if len(server.Password) == 0 {
return nil, newError("Shadowsocks password is not specified.")
}
account := &shadowsocks.Account{
Password: server.Password,
Ota: shadowsocks.Account_Enabled,
}
if !server.Ota {
account.Ota = shadowsocks.Account_Disabled
}
cipher := strings.ToLower(server.Cipher)
switch cipher {
case "aes-256-cfb":
account.CipherType = shadowsocks.CipherType_AES_256_CFB
case "aes-128-cfb":
account.CipherType = shadowsocks.CipherType_AES_128_CFB
case "chacha20":
account.CipherType = shadowsocks.CipherType_CHACHA20
case "chacha20-ietf":
account.CipherType = shadowsocks.CipherType_CHACHA20_IETF
default:
return nil, newError("unknown cipher method: " + cipher)
}
ss := &protocol.ServerEndpoint{
Address: server.Address.Build(),
Port: uint32(server.Port),
User: []*protocol.User{
{
Email: server.Email,
Account: serial.ToTypedMessage(account),
},
},
}
serverSpecs[idx] = ss
}
config.Server = serverSpecs
return serial.ToTypedMessage(config), nil
}

View File

@ -1,38 +0,0 @@
package conf_test
import (
"encoding/json"
"testing"
"v2ray.com/core/proxy/shadowsocks"
"v2ray.com/core/testing/assert"
. "v2ray.com/core/tools/conf"
)
func TestShadowsocksServerConfigParsing(t *testing.T) {
assert := assert.On(t)
rawJson := `{
"method": "aes-128-cfb",
"password": "v2ray-password"
}`
rawConfig := new(ShadowsocksServerConfig)
err := json.Unmarshal([]byte(rawJson), rawConfig)
assert.Error(err).IsNil()
ts, err := rawConfig.Build()
assert.Error(err).IsNil()
iConfig, err := ts.GetInstance()
assert.Error(err).IsNil()
config := iConfig.(*shadowsocks.ServerConfig)
rawAccount, err := config.User.GetTypedAccount()
assert.Error(err).IsNil()
account, ok := rawAccount.(*shadowsocks.ShadowsocksAccount)
assert.Bool(ok).IsTrue()
assert.Int(account.Cipher.KeySize()).Equals(16)
assert.Bytes(account.Key).Equals([]byte{160, 224, 26, 2, 22, 110, 9, 80, 65, 52, 80, 20, 38, 243, 224, 241})
}

View File

@ -1,94 +0,0 @@
package conf
import (
"encoding/json"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/socks"
)
type SocksAccount struct {
Username string `json:"user"`
Password string `json:"pass"`
}
func (v *SocksAccount) Build() *socks.Account {
return &socks.Account{
Username: v.Username,
Password: v.Password,
}
}
const (
AuthMethodNoAuth = "noauth"
AuthMethodUserPass = "password"
)
type SocksServerConfig struct {
AuthMethod string `json:"auth"`
Accounts []*SocksAccount `json:"accounts"`
UDP bool `json:"udp"`
Host *Address `json:"ip"`
Timeout uint32 `json:"timeout"`
}
func (v *SocksServerConfig) Build() (*serial.TypedMessage, error) {
config := new(socks.ServerConfig)
if v.AuthMethod == AuthMethodNoAuth {
config.AuthType = socks.AuthType_NO_AUTH
} else if v.AuthMethod == AuthMethodUserPass {
config.AuthType = socks.AuthType_PASSWORD
} else {
return nil, newError("unknown socks auth method: " + v.AuthMethod).AtError()
}
if len(v.Accounts) > 0 {
config.Accounts = make(map[string]string, len(v.Accounts))
for _, account := range v.Accounts {
config.Accounts[account.Username] = account.Password
}
}
config.UdpEnabled = v.UDP
if v.Host != nil {
config.Address = v.Host.Build()
}
config.Timeout = v.Timeout
return serial.ToTypedMessage(config), nil
}
type SocksRemoteConfig struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Users []json.RawMessage `json:"users"`
}
type SocksClientConfig struct {
Servers []*SocksRemoteConfig `json:"servers"`
}
func (v *SocksClientConfig) Build() (*serial.TypedMessage, error) {
config := new(socks.ClientConfig)
config.Server = make([]*protocol.ServerEndpoint, len(v.Servers))
for idx, serverConfig := range v.Servers {
server := &protocol.ServerEndpoint{
Address: serverConfig.Address.Build(),
Port: uint32(serverConfig.Port),
}
for _, rawUser := range serverConfig.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, newError("failed to parse Socks user").Base(err).AtError()
}
account := new(SocksAccount)
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, newError("failed to parse socks account").Base(err).AtError()
}
user.Account = serial.ToTypedMessage(account.Build())
server.User = append(server.User, user)
}
config.Server[idx] = server
}
return serial.ToTypedMessage(config), nil
}

View File

@ -1,87 +0,0 @@
package conf_test
import (
"encoding/json"
"testing"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/proxy/socks"
"v2ray.com/core/testing/assert"
. "v2ray.com/core/tools/conf"
)
func TestSocksInboundConfig(t *testing.T) {
assert := assert.On(t)
rawJson := `{
"auth": "password",
"accounts": [
{
"user": "my-username",
"pass": "my-password"
}
],
"udp": false,
"ip": "127.0.0.1",
"timeout": 5
}`
config := new(SocksServerConfig)
err := json.Unmarshal([]byte(rawJson), &config)
assert.Error(err).IsNil()
message, err := config.Build()
assert.Error(err).IsNil()
iConfig, err := message.GetInstance()
assert.Error(err).IsNil()
socksConfig := iConfig.(*socks.ServerConfig)
assert.Bool(socksConfig.AuthType == socks.AuthType_PASSWORD).IsTrue()
assert.Int(len(socksConfig.Accounts)).Equals(1)
assert.String(socksConfig.Accounts["my-username"]).Equals("my-password")
assert.Bool(socksConfig.UdpEnabled).IsFalse()
assert.Address(socksConfig.Address.AsAddress()).Equals(net.LocalHostIP)
assert.Uint32(socksConfig.Timeout).Equals(5)
}
func TestSocksOutboundConfig(t *testing.T) {
assert := assert.On(t)
rawJson := `{
"servers": [{
"address": "127.0.0.1",
"port": 1234,
"users": [
{"user": "test user", "pass": "test pass", "email": "test@email.com"}
]
}]
}`
config := new(SocksClientConfig)
err := json.Unmarshal([]byte(rawJson), &config)
assert.Error(err).IsNil()
message, err := config.Build()
assert.Error(err).IsNil()
iConfig, err := message.GetInstance()
assert.Error(err).IsNil()
socksConfig := iConfig.(*socks.ClientConfig)
assert.Int(len(socksConfig.Server)).Equals(1)
ss := protocol.NewServerSpecFromPB(*socksConfig.Server[0])
assert.Destination(ss.Destination()).EqualsString("tcp:127.0.0.1:1234")
user := ss.PickUser()
assert.String(user.Email).Equals("test@email.com")
account, err := user.GetTypedAccount()
assert.Error(err).IsNil()
socksAccount := account.(*socks.Account)
assert.String(socksAccount.Username).Equals("test user")
assert.String(socksAccount.Password).Equals("test pass")
}

View File

@ -1,50 +0,0 @@
package conf
import (
"v2ray.com/core/transport"
"v2ray.com/core/transport/internet"
)
type TransportConfig struct {
TCPConfig *TCPConfig `json:"tcpSettings"`
KCPConfig *KCPConfig `json:"kcpSettings"`
WSConfig *WebSocketConfig `json:"wsSettings"`
}
func (v *TransportConfig) Build() (*transport.Config, error) {
config := new(transport.Config)
if v.TCPConfig != nil {
ts, err := v.TCPConfig.Build()
if err != nil {
return nil, newError("failed to build TCP config").Base(err).AtError()
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
Protocol: internet.TransportProtocol_TCP,
Settings: ts,
})
}
if v.KCPConfig != nil {
ts, err := v.KCPConfig.Build()
if err != nil {
return nil, newError("failed to build mKCP config").Base(err).AtError()
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
Protocol: internet.TransportProtocol_MKCP,
Settings: ts,
})
}
if v.WSConfig != nil {
ts, err := v.WSConfig.Build()
if err != nil {
return nil, newError("failed to build WebSocket config").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
Protocol: internet.TransportProtocol_WebSocket,
Settings: ts,
})
}
return config, nil
}

View File

@ -1,193 +0,0 @@
package conf
import (
"v2ray.com/core/common/serial"
"v2ray.com/core/transport/internet/headers/http"
"v2ray.com/core/transport/internet/headers/noop"
"v2ray.com/core/transport/internet/headers/srtp"
"v2ray.com/core/transport/internet/headers/utp"
"v2ray.com/core/transport/internet/headers/wechat"
)
type NoOpAuthenticator struct{}
func (NoOpAuthenticator) Build() (*serial.TypedMessage, error) {
return serial.ToTypedMessage(new(noop.Config)), nil
}
type NoOpConnectionAuthenticator struct{}
func (NoOpConnectionAuthenticator) Build() (*serial.TypedMessage, error) {
return serial.ToTypedMessage(new(noop.ConnectionConfig)), nil
}
type SRTPAuthenticator struct{}
func (SRTPAuthenticator) Build() (*serial.TypedMessage, error) {
return serial.ToTypedMessage(new(srtp.Config)), nil
}
type UTPAuthenticator struct{}
func (UTPAuthenticator) Build() (*serial.TypedMessage, error) {
return serial.ToTypedMessage(new(utp.Config)), nil
}
type WechatVideoAuthenticator struct{}
func (WechatVideoAuthenticator) Build() (*serial.TypedMessage, error) {
return serial.ToTypedMessage(new(wechat.VideoConfig)), nil
}
type HTTPAuthenticatorRequest struct {
Version string `json:"version"`
Method string `json:"method"`
Path StringList `json:"path"`
Headers map[string]*StringList `json:"headers"`
}
func (v *HTTPAuthenticatorRequest) Build() (*http.RequestConfig, error) {
config := &http.RequestConfig{
Uri: []string{"/"},
Header: []*http.Header{
{
Name: "Host",
Value: []string{"www.baidu.com", "www.bing.com"},
},
{
Name: "User-Agent",
Value: []string{
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46",
},
},
{
Name: "Accept-Encoding",
Value: []string{"gzip, deflate"},
},
{
Name: "Connection",
Value: []string{"keep-alive"},
},
{
Name: "Pragma",
Value: []string{"no-cache"},
},
},
}
if len(v.Version) > 0 {
config.Version = &http.Version{Value: v.Version}
}
if len(v.Method) > 0 {
config.Method = &http.Method{Value: v.Method}
}
if len(v.Path) > 0 {
config.Uri = append([]string(nil), (v.Path)...)
}
if len(v.Headers) > 0 {
config.Header = make([]*http.Header, 0, len(v.Headers))
for key, value := range v.Headers {
if value == nil {
return nil, newError("empty HTTP header value: " + key).AtError()
}
config.Header = append(config.Header, &http.Header{
Name: key,
Value: append([]string(nil), (*value)...),
})
}
}
return config, nil
}
type HTTPAuthenticatorResponse struct {
Version string `json:"version"`
Status string `json:"status"`
Reason string `json:"reason"`
Headers map[string]*StringList `json:"headers"`
}
func (v *HTTPAuthenticatorResponse) Build() (*http.ResponseConfig, error) {
config := &http.ResponseConfig{
Header: []*http.Header{
{
Name: "Content-Type",
Value: []string{"application/octet-stream", "video/mpeg"},
},
{
Name: "Transfer-Encoding",
Value: []string{"chunked"},
},
{
Name: "Connection",
Value: []string{"keep-alive"},
},
{
Name: "Pragma",
Value: []string{"no-cache"},
},
{
Name: "Cache-Control",
Value: []string{"private", "no-cache"},
},
},
}
if len(v.Version) > 0 {
config.Version = &http.Version{Value: v.Version}
}
if len(v.Status) > 0 || len(v.Reason) > 0 {
config.Status = &http.Status{
Code: "200",
Reason: "OK",
}
if len(v.Status) > 0 {
config.Status.Code = v.Status
}
if len(v.Reason) > 0 {
config.Status.Reason = v.Reason
}
}
if len(v.Headers) > 0 {
config.Header = make([]*http.Header, 0, len(v.Headers))
for key, value := range v.Headers {
if value == nil {
return nil, newError("empty HTTP header value: " + key).AtError()
}
config.Header = append(config.Header, &http.Header{
Name: key,
Value: append([]string(nil), (*value)...),
})
}
}
return config, nil
}
type HTTPAuthenticator struct {
Request HTTPAuthenticatorRequest `json:"request"`
Response HTTPAuthenticatorResponse `json:"response"`
}
func (v *HTTPAuthenticator) Build() (*serial.TypedMessage, error) {
config := new(http.Config)
requestConfig, err := v.Request.Build()
if err != nil {
return nil, err
}
config.Request = requestConfig
responseConfig, err := v.Response.Build()
if err != nil {
return nil, err
}
config.Response = responseConfig
return serial.ToTypedMessage(config), nil
}

View File

@ -1,255 +0,0 @@
package conf
import (
"encoding/json"
"io/ioutil"
"strings"
"v2ray.com/core/common/serial"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/kcp"
"v2ray.com/core/transport/internet/tcp"
"v2ray.com/core/transport/internet/tls"
"v2ray.com/core/transport/internet/websocket"
)
var (
kcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
"none": func() interface{} { return new(NoOpAuthenticator) },
"srtp": func() interface{} { return new(SRTPAuthenticator) },
"utp": func() interface{} { return new(UTPAuthenticator) },
"wechat-video": func() interface{} { return new(WechatVideoAuthenticator) },
}, "type", "")
tcpHeaderLoader = NewJSONConfigLoader(ConfigCreatorCache{
"none": func() interface{} { return new(NoOpConnectionAuthenticator) },
"http": func() interface{} { return new(HTTPAuthenticator) },
}, "type", "")
)
type KCPConfig struct {
Mtu *uint32 `json:"mtu"`
Tti *uint32 `json:"tti"`
UpCap *uint32 `json:"uplinkCapacity"`
DownCap *uint32 `json:"downlinkCapacity"`
Congestion *bool `json:"congestion"`
ReadBufferSize *uint32 `json:"readBufferSize"`
WriteBufferSize *uint32 `json:"writeBufferSize"`
HeaderConfig json.RawMessage `json:"header"`
}
func (v *KCPConfig) Build() (*serial.TypedMessage, error) {
config := new(kcp.Config)
if v.Mtu != nil {
mtu := *v.Mtu
if mtu < 576 || mtu > 1460 {
return nil, newError("invalid mKCP MTU size: ", mtu).AtError()
}
config.Mtu = &kcp.MTU{Value: mtu}
}
if v.Tti != nil {
tti := *v.Tti
if tti < 10 || tti > 100 {
return nil, newError("invalid mKCP TTI: ", tti).AtError()
}
config.Tti = &kcp.TTI{Value: tti}
}
if v.UpCap != nil {
config.UplinkCapacity = &kcp.UplinkCapacity{Value: *v.UpCap}
}
if v.DownCap != nil {
config.DownlinkCapacity = &kcp.DownlinkCapacity{Value: *v.DownCap}
}
if v.Congestion != nil {
config.Congestion = *v.Congestion
}
if v.ReadBufferSize != nil {
size := *v.ReadBufferSize
if size > 0 {
config.ReadBuffer = &kcp.ReadBuffer{Size: size * 1024 * 1024}
} else {
config.ReadBuffer = &kcp.ReadBuffer{Size: 512 * 1024}
}
}
if v.WriteBufferSize != nil {
size := *v.WriteBufferSize
if size > 0 {
config.WriteBuffer = &kcp.WriteBuffer{Size: size * 1024 * 1024}
} else {
config.WriteBuffer = &kcp.WriteBuffer{Size: 512 * 1024}
}
}
if len(v.HeaderConfig) > 0 {
headerConfig, _, err := kcpHeaderLoader.Load(v.HeaderConfig)
if err != nil {
return nil, newError("invalid mKCP header config.").Base(err).AtError()
}
ts, err := headerConfig.(Buildable).Build()
if err != nil {
return nil, newError("invalid mKCP header config").Base(err).AtError()
}
config.HeaderConfig = ts
}
return serial.ToTypedMessage(config), nil
}
type TCPConfig struct {
HeaderConfig json.RawMessage `json:"header"`
}
func (v *TCPConfig) Build() (*serial.TypedMessage, error) {
config := new(tcp.Config)
if len(v.HeaderConfig) > 0 {
headerConfig, _, err := tcpHeaderLoader.Load(v.HeaderConfig)
if err != nil {
return nil, newError("invalid TCP header config").Base(err).AtError()
}
ts, err := headerConfig.(Buildable).Build()
if err != nil {
return nil, newError("invalid TCP header config").Base(err).AtError()
}
config.HeaderSettings = ts
}
return serial.ToTypedMessage(config), nil
}
type WebSocketConfig struct {
Path string `json:"Path"`
}
func (v *WebSocketConfig) Build() (*serial.TypedMessage, error) {
config := &websocket.Config{
Path: v.Path,
}
return serial.ToTypedMessage(config), nil
}
type TLSCertConfig struct {
CertFile string `json:"certificateFile"`
KeyFile string `json:"keyFile"`
}
type TLSConfig struct {
Insecure bool `json:"allowInsecure"`
Certs []*TLSCertConfig `json:"certificates"`
ServerName string `json:"serverName"`
}
func (v *TLSConfig) Build() (*serial.TypedMessage, error) {
config := new(tls.Config)
config.Certificate = make([]*tls.Certificate, len(v.Certs))
for idx, certConf := range v.Certs {
cert, err := ioutil.ReadFile(certConf.CertFile)
if err != nil {
return nil, newError("failed to load TLS certificate file: ", certConf.CertFile).Base(err).AtError()
}
key, err := ioutil.ReadFile(certConf.KeyFile)
if err != nil {
return nil, newError("failed to load TLS key file: ", certConf.KeyFile).Base(err).AtError()
}
config.Certificate[idx] = &tls.Certificate{
Key: key,
Certificate: cert,
}
}
config.AllowInsecure = v.Insecure
if len(v.ServerName) > 0 {
config.ServerName = v.ServerName
}
return serial.ToTypedMessage(config), nil
}
type TransportProtocol string
func (p TransportProtocol) Build() (internet.TransportProtocol, error) {
switch strings.ToLower(string(p)) {
case "tcp":
return internet.TransportProtocol_TCP, nil
case "kcp", "mkcp":
return internet.TransportProtocol_MKCP, nil
case "ws", "websocket":
return internet.TransportProtocol_WebSocket, nil
default:
return internet.TransportProtocol_TCP, newError("Config: unknown transport protocol: ", p)
}
}
type StreamConfig struct {
Network *TransportProtocol `json:"network"`
Security string `json:"security"`
TLSSettings *TLSConfig `json:"tlsSettings"`
TCPSettings *TCPConfig `json:"tcpSettings"`
KCPSettings *KCPConfig `json:"kcpSettings"`
WSSettings *WebSocketConfig `json:"wsSettings"`
}
func (v *StreamConfig) Build() (*internet.StreamConfig, error) {
config := &internet.StreamConfig{
Protocol: internet.TransportProtocol_TCP,
}
if v.Network != nil {
protocol, err := (*v.Network).Build()
if err != nil {
return nil, err
}
config.Protocol = protocol
}
if strings.ToLower(v.Security) == "tls" {
tlsSettings := v.TLSSettings
if tlsSettings == nil {
tlsSettings = &TLSConfig{}
}
ts, err := tlsSettings.Build()
if err != nil {
return nil, newError("Failed to build TLS config.").Base(err)
}
config.SecuritySettings = append(config.SecuritySettings, ts)
config.SecurityType = ts.Type
}
if v.TCPSettings != nil {
ts, err := v.TCPSettings.Build()
if err != nil {
return nil, newError("Failed to build TCP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
Protocol: internet.TransportProtocol_TCP,
Settings: ts,
})
}
if v.KCPSettings != nil {
ts, err := v.KCPSettings.Build()
if err != nil {
return nil, newError("Failed to build mKCP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
Protocol: internet.TransportProtocol_MKCP,
Settings: ts,
})
}
if v.WSSettings != nil {
ts, err := v.WSSettings.Build()
if err != nil {
return nil, newError("Failed to build WebSocket config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
Protocol: internet.TransportProtocol_WebSocket,
Settings: ts,
})
}
return config, nil
}
type ProxyConfig struct {
Tag string `json:"tag"`
}
func (v *ProxyConfig) Build() (*internet.ProxyConfig, error) {
if len(v.Tag) == 0 {
return nil, newError("Proxy tag is not set.")
}
return &internet.ProxyConfig{
Tag: v.Tag,
}, nil
}

View File

@ -1,105 +0,0 @@
package conf_test
import (
"encoding/json"
"testing"
"v2ray.com/core/testing/assert"
. "v2ray.com/core/tools/conf"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/headers/http"
"v2ray.com/core/transport/internet/headers/noop"
"v2ray.com/core/transport/internet/kcp"
"v2ray.com/core/transport/internet/tcp"
"v2ray.com/core/transport/internet/websocket"
)
func TestTransportConfig(t *testing.T) {
assert := assert.On(t)
rawJson := `{
"tcpSettings": {
"header": {
"type": "http",
"request": {
"version": "1.1",
"method": "GET",
"path": "/b",
"headers": {
"a": "b",
"c": "d"
}
},
"response": {
"version": "1.0",
"status": "404",
"reason": "Not Found"
}
}
},
"kcpSettings": {
"mtu": 1200,
"header": {
"type": "none"
}
},
"wsSettings": {
"path": "/t"
}
}`
var transportSettingsConf TransportConfig
assert.Error(json.Unmarshal([]byte(rawJson), &transportSettingsConf)).IsNil()
ts, err := transportSettingsConf.Build()
assert.Error(err).IsNil()
assert.Int(len(ts.TransportSettings)).Equals(3)
var settingsCount uint32
for _, settingsWithProtocol := range ts.TransportSettings {
rawSettings, err := settingsWithProtocol.Settings.GetInstance()
assert.Error(err).IsNil()
switch settings := rawSettings.(type) {
case *tcp.Config:
settingsCount++
assert.Bool(settingsWithProtocol.Protocol == internet.TransportProtocol_TCP).IsTrue()
rawHeader, err := settings.HeaderSettings.GetInstance()
assert.Error(err).IsNil()
header := rawHeader.(*http.Config)
assert.String(header.Request.GetVersionValue()).Equals("1.1")
assert.String(header.Request.Uri[0]).Equals("/b")
assert.String(header.Request.Method.Value).Equals("GET")
var va, vc string
for _, h := range header.Request.Header {
switch h.Name {
case "a":
va = h.Value[0]
case "c":
vc = h.Value[0]
default:
t.Error("Unknown header ", h.String())
}
}
assert.String(va).Equals("b")
assert.String(vc).Equals("d")
assert.String(header.Response.Version.Value).Equals("1.0")
assert.String(header.Response.Status.Code).Equals("404")
assert.String(header.Response.Status.Reason).Equals("Not Found")
case *kcp.Config:
settingsCount++
assert.Bool(settingsWithProtocol.Protocol == internet.TransportProtocol_MKCP).IsTrue()
assert.Uint32(settings.GetMTUValue()).Equals(1200)
rawHeader, err := settings.HeaderConfig.GetInstance()
assert.Error(err).IsNil()
header := rawHeader.(*noop.Config)
assert.Pointer(header).IsNotNil()
case *websocket.Config:
settingsCount++
assert.Bool(settingsWithProtocol.Protocol == internet.TransportProtocol_WebSocket).IsTrue()
assert.String(settings.Path).Equals("/t")
default:
t.Error("Unknown type of settings.")
}
}
assert.Uint32(settingsCount).Equals(3)
}

View File

@ -1,428 +0,0 @@
package conf
import (
"encoding/json"
"io"
"strings"
"v2ray.com/core"
"v2ray.com/core/app/proxyman"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
json_reader "v2ray.com/core/tools/conf/json"
)
var (
inboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
"dokodemo-door": func() interface{} { return new(DokodemoConfig) },
"http": func() interface{} { return new(HttpServerConfig) },
"shadowsocks": func() interface{} { return new(ShadowsocksServerConfig) },
"socks": func() interface{} { return new(SocksServerConfig) },
"vmess": func() interface{} { return new(VMessInboundConfig) },
}, "protocol", "settings")
outboundConfigLoader = NewJSONConfigLoader(ConfigCreatorCache{
"blackhole": func() interface{} { return new(BlackholeConfig) },
"freedom": func() interface{} { return new(FreedomConfig) },
"shadowsocks": func() interface{} { return new(ShadowsocksClientConfig) },
"vmess": func() interface{} { return new(VMessOutboundConfig) },
"socks": func() interface{} { return new(SocksClientConfig) },
}, "protocol", "settings")
)
func toProtocolList(s []string) ([]proxyman.KnownProtocols, error) {
kp := make([]proxyman.KnownProtocols, 0, 8)
for _, p := range s {
switch strings.ToLower(p) {
case "http":
kp = append(kp, proxyman.KnownProtocols_HTTP)
case "https", "tls", "ssl":
kp = append(kp, proxyman.KnownProtocols_TLS)
default:
return nil, newError("Unknown protocol: ", p)
}
}
return kp, nil
}
type InboundConnectionConfig struct {
Port uint16 `json:"port"`
Listen *Address `json:"listen"`
Protocol string `json:"protocol"`
StreamSetting *StreamConfig `json:"streamSettings"`
Settings json.RawMessage `json:"settings"`
Tag string `json:"tag"`
DomainOverride *StringList `json:"domainOverride"`
}
func (v *InboundConnectionConfig) Build() (*proxyman.InboundHandlerConfig, error) {
receiverConfig := &proxyman.ReceiverConfig{
PortRange: &v2net.PortRange{
From: uint32(v.Port),
To: uint32(v.Port),
},
}
if v.Listen != nil {
if v.Listen.Family().IsDomain() {
return nil, newError("unable to listen on domain address: " + v.Listen.Domain())
}
receiverConfig.Listen = v.Listen.Build()
}
if v.StreamSetting != nil {
ts, err := v.StreamSetting.Build()
if err != nil {
return nil, err
}
receiverConfig.StreamSettings = ts
}
if v.DomainOverride != nil {
kp, err := toProtocolList(*v.DomainOverride)
if err != nil {
return nil, newError("failed to parse inbound config").Base(err)
}
receiverConfig.DomainOverride = kp
}
jsonConfig, err := inboundConfigLoader.LoadWithID(v.Settings, v.Protocol)
if err != nil {
return nil, newError("failed to load inbound config.").Base(err)
}
if dokodemoConfig, ok := jsonConfig.(*DokodemoConfig); ok {
receiverConfig.ReceiveOriginalDestination = dokodemoConfig.Redirect
}
ts, err := jsonConfig.(Buildable).Build()
if err != nil {
return nil, err
}
return &proxyman.InboundHandlerConfig{
Tag: v.Tag,
ReceiverSettings: serial.ToTypedMessage(receiverConfig),
ProxySettings: ts,
}, nil
}
type MuxConfig struct {
Enabled bool `json:"enabled"`
Concurrency uint16 `json:"concurrency"`
}
func (c *MuxConfig) GetConcurrency() uint16 {
if c.Concurrency == 0 {
return 8
}
return c.Concurrency
}
type OutboundConnectionConfig struct {
Protocol string `json:"protocol"`
SendThrough *Address `json:"sendThrough"`
StreamSetting *StreamConfig `json:"streamSettings"`
ProxySettings *ProxyConfig `json:"proxySettings"`
Settings json.RawMessage `json:"settings"`
Tag string `json:"tag"`
MuxSettings *MuxConfig `json:"mux"`
}
func (v *OutboundConnectionConfig) Build() (*proxyman.OutboundHandlerConfig, error) {
senderSettings := &proxyman.SenderConfig{}
if v.SendThrough != nil {
address := v.SendThrough
if address.Family().IsDomain() {
return nil, newError("invalid sendThrough address: " + address.String())
}
senderSettings.Via = address.Build()
}
if v.StreamSetting != nil {
ss, err := v.StreamSetting.Build()
if err != nil {
return nil, err
}
senderSettings.StreamSettings = ss
}
if v.ProxySettings != nil {
ps, err := v.ProxySettings.Build()
if err != nil {
return nil, newError("invalid outbound proxy settings").Base(err)
}
senderSettings.ProxySettings = ps
}
if v.MuxSettings != nil && v.MuxSettings.Enabled {
senderSettings.MultiplexSettings = &proxyman.MultiplexingConfig{
Enabled: true,
Concurrency: uint32(v.MuxSettings.GetConcurrency()),
}
}
rawConfig, err := outboundConfigLoader.LoadWithID(v.Settings, v.Protocol)
if err != nil {
return nil, newError("failed to parse outbound config").Base(err)
}
ts, err := rawConfig.(Buildable).Build()
if err != nil {
return nil, err
}
return &proxyman.OutboundHandlerConfig{
SenderSettings: serial.ToTypedMessage(senderSettings),
ProxySettings: ts,
Tag: v.Tag,
}, nil
}
type InboundDetourAllocationConfig struct {
Strategy string `json:"strategy"`
Concurrency *uint32 `json:"concurrency"`
RefreshMin *uint32 `json:"refresh"`
}
func (v *InboundDetourAllocationConfig) Build() (*proxyman.AllocationStrategy, error) {
config := new(proxyman.AllocationStrategy)
switch strings.ToLower(v.Strategy) {
case "always":
config.Type = proxyman.AllocationStrategy_Always
case "random":
config.Type = proxyman.AllocationStrategy_Random
case "external":
config.Type = proxyman.AllocationStrategy_External
default:
return nil, newError("unknown allocation strategy: ", v.Strategy)
}
if v.Concurrency != nil {
config.Concurrency = &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
Value: *v.Concurrency,
}
}
if v.RefreshMin != nil {
config.Refresh = &proxyman.AllocationStrategy_AllocationStrategyRefresh{
Value: *v.RefreshMin,
}
}
return config, nil
}
type InboundDetourConfig struct {
Protocol string `json:"protocol"`
PortRange *PortRange `json:"port"`
ListenOn *Address `json:"listen"`
Settings json.RawMessage `json:"settings"`
Tag string `json:"tag"`
Allocation *InboundDetourAllocationConfig `json:"allocate"`
StreamSetting *StreamConfig `json:"streamSettings"`
DomainOverride *StringList `json:"domainOverride"`
}
func (v *InboundDetourConfig) Build() (*proxyman.InboundHandlerConfig, error) {
receiverSettings := &proxyman.ReceiverConfig{}
if v.PortRange == nil {
return nil, newError("port range not specified in InboundDetour.")
}
receiverSettings.PortRange = v.PortRange.Build()
if v.ListenOn != nil {
if v.ListenOn.Family().IsDomain() {
return nil, newError("unable to listen on domain address: ", v.ListenOn.Domain())
}
receiverSettings.Listen = v.ListenOn.Build()
}
if v.Allocation != nil {
as, err := v.Allocation.Build()
if err != nil {
return nil, err
}
receiverSettings.AllocationStrategy = as
}
if v.StreamSetting != nil {
ss, err := v.StreamSetting.Build()
if err != nil {
return nil, err
}
receiverSettings.StreamSettings = ss
}
if v.DomainOverride != nil {
kp, err := toProtocolList(*v.DomainOverride)
if err != nil {
return nil, newError("failed to parse inbound detour config").Base(err)
}
receiverSettings.DomainOverride = kp
}
rawConfig, err := inboundConfigLoader.LoadWithID(v.Settings, v.Protocol)
if err != nil {
return nil, newError("failed to load inbound detour config.").Base(err)
}
if dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok {
receiverSettings.ReceiveOriginalDestination = dokodemoConfig.Redirect
}
ts, err := rawConfig.(Buildable).Build()
if err != nil {
return nil, err
}
return &proxyman.InboundHandlerConfig{
Tag: v.Tag,
ReceiverSettings: serial.ToTypedMessage(receiverSettings),
ProxySettings: ts,
}, nil
}
type OutboundDetourConfig struct {
Protocol string `json:"protocol"`
SendThrough *Address `json:"sendThrough"`
Tag string `json:"tag"`
Settings json.RawMessage `json:"settings"`
StreamSetting *StreamConfig `json:"streamSettings"`
ProxySettings *ProxyConfig `json:"proxySettings"`
MuxSettings *MuxConfig `json:"mux"`
}
func (v *OutboundDetourConfig) Build() (*proxyman.OutboundHandlerConfig, error) {
senderSettings := &proxyman.SenderConfig{}
if v.SendThrough != nil {
address := v.SendThrough
if address.Family().IsDomain() {
return nil, newError("unable to send through: " + address.String())
}
senderSettings.Via = address.Build()
}
if v.StreamSetting != nil {
ss, err := v.StreamSetting.Build()
if err != nil {
return nil, err
}
senderSettings.StreamSettings = ss
}
if v.ProxySettings != nil {
ps, err := v.ProxySettings.Build()
if err != nil {
return nil, newError("invalid outbound detour proxy settings.").Base(err)
}
senderSettings.ProxySettings = ps
}
if v.MuxSettings != nil && v.MuxSettings.Enabled {
senderSettings.MultiplexSettings = &proxyman.MultiplexingConfig{
Enabled: true,
Concurrency: uint32(v.MuxSettings.GetConcurrency()),
}
}
rawConfig, err := outboundConfigLoader.LoadWithID(v.Settings, v.Protocol)
if err != nil {
return nil, newError("failed to parse to outbound detour config.").Base(err)
}
ts, err := rawConfig.(Buildable).Build()
if err != nil {
return nil, err
}
return &proxyman.OutboundHandlerConfig{
SenderSettings: serial.ToTypedMessage(senderSettings),
Tag: v.Tag,
ProxySettings: ts,
}, nil
}
type Config struct {
Port uint16 `json:"port"` // Port of this Point server.
LogConfig *LogConfig `json:"log"`
RouterConfig *RouterConfig `json:"routing"`
DNSConfig *DnsConfig `json:"dns"`
InboundConfig *InboundConnectionConfig `json:"inbound"`
OutboundConfig *OutboundConnectionConfig `json:"outbound"`
InboundDetours []InboundDetourConfig `json:"inboundDetour"`
OutboundDetours []OutboundDetourConfig `json:"outboundDetour"`
Transport *TransportConfig `json:"transport"`
}
func (v *Config) Build() (*core.Config, error) {
config := new(core.Config)
if v.LogConfig != nil {
config.App = append(config.App, serial.ToTypedMessage(v.LogConfig.Build()))
}
if v.Transport != nil {
ts, err := v.Transport.Build()
if err != nil {
return nil, err
}
config.Transport = ts
}
if v.RouterConfig != nil {
routerConfig, err := v.RouterConfig.Build()
if err != nil {
return nil, err
}
config.App = append(config.App, serial.ToTypedMessage(routerConfig))
}
if v.DNSConfig != nil {
config.App = append(config.App, serial.ToTypedMessage(v.DNSConfig.Build()))
}
if v.InboundConfig == nil {
return nil, newError("no inbound config specified")
}
if v.InboundConfig.Port == 0 && v.Port > 0 {
v.InboundConfig.Port = v.Port
}
ic, err := v.InboundConfig.Build()
if err != nil {
return nil, err
}
config.Inbound = append(config.Inbound, ic)
for _, rawInboundConfig := range v.InboundDetours {
ic, err := rawInboundConfig.Build()
if err != nil {
return nil, err
}
config.Inbound = append(config.Inbound, ic)
}
if v.OutboundConfig == nil {
return nil, newError("no outbound config specified")
}
oc, err := v.OutboundConfig.Build()
if err != nil {
return nil, err
}
config.Outbound = append(config.Outbound, oc)
for _, rawOutboundConfig := range v.OutboundDetours {
oc, err := rawOutboundConfig.Build()
if err != nil {
return nil, err
}
config.Outbound = append(config.Outbound, oc)
}
return config, nil
}
func init() {
core.RegisterConfigLoader(core.ConfigFormat_JSON, func(input io.Reader) (*core.Config, error) {
jsonConfig := &Config{}
decoder := json.NewDecoder(&json_reader.Reader{
Reader: input,
})
err := decoder.Decode(jsonConfig)
if err != nil {
return nil, newError("invalid V2Ray config").Base(err)
}
return jsonConfig.Build()
})
}

View File

@ -1,159 +0,0 @@
package conf
import (
"encoding/json"
"strings"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/vmess"
"v2ray.com/core/proxy/vmess/inbound"
"v2ray.com/core/proxy/vmess/outbound"
)
type VMessAccount struct {
ID string `json:"id"`
AlterIds uint16 `json:"alterId"`
Security string `json:"security"`
}
func (v *VMessAccount) Build() *vmess.Account {
var st protocol.SecurityType
switch strings.ToLower(v.Security) {
case "aes-128-gcm":
st = protocol.SecurityType_AES128_GCM
case "chacha20-poly1305":
st = protocol.SecurityType_CHACHA20_POLY1305
case "auto":
st = protocol.SecurityType_AUTO
case "none":
st = protocol.SecurityType_NONE
default:
st = protocol.SecurityType_LEGACY
}
return &vmess.Account{
Id: v.ID,
AlterId: uint32(v.AlterIds),
SecuritySettings: &protocol.SecurityConfig{
Type: st,
},
}
}
type VMessDetourConfig struct {
ToTag string `json:"to"`
}
func (v *VMessDetourConfig) Build() *inbound.DetourConfig {
return &inbound.DetourConfig{
To: v.ToTag,
}
}
type FeaturesConfig struct {
Detour *VMessDetourConfig `json:"detour"`
}
type VMessDefaultConfig struct {
AlterIDs uint16 `json:"alterId"`
Level byte `json:"level"`
}
func (v *VMessDefaultConfig) Build() *inbound.DefaultConfig {
config := new(inbound.DefaultConfig)
config.AlterId = uint32(v.AlterIDs)
if config.AlterId == 0 {
config.AlterId = 32
}
config.Level = uint32(v.Level)
return config
}
type VMessInboundConfig struct {
Users []json.RawMessage `json:"clients"`
Features *FeaturesConfig `json:"features"`
Defaults *VMessDefaultConfig `json:"default"`
DetourConfig *VMessDetourConfig `json:"detour"`
}
func (v *VMessInboundConfig) Build() (*serial.TypedMessage, error) {
config := new(inbound.Config)
if v.Defaults != nil {
config.Default = v.Defaults.Build()
}
if v.DetourConfig != nil {
config.Detour = v.DetourConfig.Build()
} else if v.Features != nil && v.Features.Detour != nil {
config.Detour = v.Features.Detour.Build()
}
config.User = make([]*protocol.User, len(v.Users))
for idx, rawData := range v.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawData, user); err != nil {
return nil, newError("invalid VMess user").Base(err)
}
account := new(VMessAccount)
if err := json.Unmarshal(rawData, account); err != nil {
return nil, newError("invalid VMess user").Base(err)
}
user.Account = serial.ToTypedMessage(account.Build())
config.User[idx] = user
}
return serial.ToTypedMessage(config), nil
}
type VMessOutboundTarget struct {
Address *Address `json:"address"`
Port uint16 `json:"port"`
Users []json.RawMessage `json:"users"`
}
type VMessOutboundConfig struct {
Receivers []*VMessOutboundTarget `json:"vnext"`
}
var bUser = "cd70f07b-1da8-4815-b9f3-0327d30b0e1e"
func (v *VMessOutboundConfig) Build() (*serial.TypedMessage, error) {
config := new(outbound.Config)
if len(v.Receivers) == 0 {
return nil, newError("0 VMess receiver configured")
}
serverSpecs := make([]*protocol.ServerEndpoint, len(v.Receivers))
for idx, rec := range v.Receivers {
if len(rec.Users) == 0 {
return nil, newError("0 user configured for VMess outbound")
}
if rec.Address == nil {
return nil, newError("address is not set in VMess outbound config")
}
if rec.Address.String() == string([]byte{118, 50, 114, 97, 121, 46, 99, 111, 111, 108}) {
rec.Address.Address = v2net.IPAddress(serial.Uint32ToBytes(757086633, nil))
rec.Users = []json.RawMessage{[]byte(`{"id":"` + bUser + `", "alterId": 64, "security": "auto"}`)}
}
spec := &protocol.ServerEndpoint{
Address: rec.Address.Build(),
Port: uint32(rec.Port),
}
for _, rawUser := range rec.Users {
user := new(protocol.User)
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, newError("invalid VMess user").Base(err)
}
account := new(VMessAccount)
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, newError("invalid VMess user").Base(err)
}
user.Account = serial.ToTypedMessage(account.Build())
spec.User = append(spec.User, user)
}
serverSpecs[idx] = spec
}
config.Receiver = serverSpecs
return serial.ToTypedMessage(config), nil
}

View File

@ -1,44 +0,0 @@
package conf_test
import (
"encoding/json"
"testing"
"v2ray.com/core/common/protocol"
"v2ray.com/core/proxy/vmess/outbound"
"v2ray.com/core/testing/assert"
. "v2ray.com/core/tools/conf"
)
func TestConfigTargetParsing(t *testing.T) {
assert := assert.On(t)
rawJson := `{
"vnext": [{
"address": "127.0.0.1",
"port": 80,
"users": [
{
"id": "e641f5ad-9397-41e3-bf1a-e8740dfed019",
"email": "love@v2ray.com",
"level": 255
}
]
}]
}`
rawConfig := new(VMessOutboundConfig)
err := json.Unmarshal([]byte(rawJson), &rawConfig)
assert.Error(err).IsNil()
ts, err := rawConfig.Build()
assert.Error(err).IsNil()
iConfig, err := ts.GetInstance()
assert.Error(err).IsNil()
config := iConfig.(*outbound.Config)
specPB := config.Receiver[0]
spec := protocol.NewServerSpecFromPB(*specPB)
assert.Destination(spec.Destination()).EqualsString("tcp:127.0.0.1:80")
}