mirror of https://github.com/v2ray/v2ray-core
remove json conf from core
parent
a8da85eca5
commit
c287df631d
|
@ -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",
|
||||
"")
|
||||
)
|
|
@ -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()
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"v2ray.com/core/common/serial"
|
||||
)
|
||||
|
||||
type Buildable interface {
|
||||
Build() (*serial.TypedMessage, error)
|
||||
}
|
|
@ -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),
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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})
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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()
|
||||
})
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
}
|
Loading…
Reference in New Issue