mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-12-21 09:36:34 -05:00
remove json packages in app folder
This commit is contained in:
parent
48f1d34ca5
commit
ae8121e633
@ -1,6 +1,6 @@
|
||||
package router
|
||||
|
||||
type Config interface {
|
||||
Strategy() string
|
||||
Settings() interface{}
|
||||
type Config struct {
|
||||
Strategy string
|
||||
Settings interface{}
|
||||
}
|
||||
|
@ -1,9 +1,15 @@
|
||||
package json
|
||||
package router
|
||||
|
||||
type ConfigObjectCreator func() interface{}
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type ConfigObjectCreator func([]byte) (interface{}, error)
|
||||
|
||||
var (
|
||||
configCache map[string]ConfigObjectCreator
|
||||
|
||||
ErrorRouterNotFound = errors.New("Router not found.")
|
||||
)
|
||||
|
||||
func RegisterRouterConfig(strategy string, creator ConfigObjectCreator) error {
|
||||
@ -12,12 +18,12 @@ func RegisterRouterConfig(strategy string, creator ConfigObjectCreator) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateRouterConfig(strategy string) interface{} {
|
||||
func CreateRouterConfig(strategy string, data []byte) (interface{}, error) {
|
||||
creator, found := configCache[strategy]
|
||||
if !found {
|
||||
return nil
|
||||
return nil, ErrorRouterNotFound
|
||||
}
|
||||
return creator()
|
||||
return creator(data)
|
||||
}
|
||||
|
||||
func init() {
|
28
app/router/config_json.go
Normal file
28
app/router/config_json.go
Normal file
@ -0,0 +1,28 @@
|
||||
// +build json
|
||||
|
||||
package router
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
)
|
||||
|
||||
func (this *Config) UnmarshalJSON(data []byte) error {
|
||||
type JsonConfig struct {
|
||||
Strategy string `json:"strategy"`
|
||||
Settings json.RawMessage `json:"settings"`
|
||||
}
|
||||
jsonConfig := new(JsonConfig)
|
||||
if err := json.Unmarshal(data, jsonConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
settings, err := CreateRouterConfig(jsonConfig.Strategy, []byte(jsonConfig.Settings))
|
||||
if err != nil {
|
||||
log.Error("Router: Failed to load router settings: %v", err)
|
||||
return err
|
||||
}
|
||||
this.Strategy = jsonConfig.Strategy
|
||||
this.Settings = settings
|
||||
return nil
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
)
|
||||
|
||||
type RouterConfig struct {
|
||||
StrategyValue string `json:"strategy"`
|
||||
SettingsValue json.RawMessage `json:"settings"`
|
||||
}
|
||||
|
||||
func (this *RouterConfig) Strategy() string {
|
||||
return this.StrategyValue
|
||||
}
|
||||
|
||||
func (this *RouterConfig) Settings() interface{} {
|
||||
settings := CreateRouterConfig(this.Strategy())
|
||||
err := json.Unmarshal(this.SettingsValue, settings)
|
||||
if err != nil {
|
||||
log.Error("Failed to load router settings: %v", err)
|
||||
return nil
|
||||
}
|
||||
return settings
|
||||
}
|
@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
. "github.com/v2ray/v2ray-core/app/router"
|
||||
_ "github.com/v2ray/v2ray-core/app/router/rules/json"
|
||||
_ "github.com/v2ray/v2ray-core/app/router/rules"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
"github.com/v2ray/v2ray-core/shell/point/json"
|
||||
v2testing "github.com/v2ray/v2ray-core/testing"
|
||||
@ -21,7 +21,7 @@ func TestRouter(t *testing.T) {
|
||||
pointConfig, err := json.LoadConfig(filepath.Join(baseDir, "vpoint_socks_vmess.json"))
|
||||
assert.Error(err).IsNil()
|
||||
|
||||
router, err := CreateRouter(pointConfig.RouterConfig().Strategy(), pointConfig.RouterConfig().Settings())
|
||||
router, err := CreateRouter(pointConfig.RouterConfig().Strategy, pointConfig.RouterConfig().Settings)
|
||||
assert.Error(err).IsNil()
|
||||
|
||||
dest := v2net.TCPDestination(v2net.IPAddress(net.ParseIP("120.135.126.1")), 80)
|
||||
|
@ -1,23 +1,25 @@
|
||||
package json
|
||||
// +build json
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
)
|
||||
|
||||
type ChinaIPRule struct {
|
||||
Rule
|
||||
}
|
||||
|
||||
func (this *ChinaIPRule) Apply(dest v2net.Destination) bool {
|
||||
address := dest.Address()
|
||||
if address.IsDomain() {
|
||||
return false
|
||||
func parseChinaIPRule(data []byte) (*Rule, error) {
|
||||
rawRule := new(JsonRule)
|
||||
err := json.Unmarshal(data, rawRule)
|
||||
if err != nil {
|
||||
log.Error("Router: Invalid router rule: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
if address.IsIPv6() {
|
||||
return false
|
||||
}
|
||||
ip := address.IP()
|
||||
return chinaIPNet.Contains(ip)
|
||||
return &Rule{
|
||||
Tag: rawRule.OutboundTag,
|
||||
Condition: NewIPv4Matcher(chinaIPNet),
|
||||
}, nil
|
||||
}
|
||||
|
||||
var (
|
@ -1,4 +1,4 @@
|
||||
package json
|
||||
package rules
|
||||
|
||||
import (
|
||||
"net"
|
||||
@ -16,7 +16,7 @@ func makeDestination(ip string) v2net.Destination {
|
||||
func TestChinaIP(t *testing.T) {
|
||||
v2testing.Current(t)
|
||||
|
||||
rule := &ChinaIPRule{}
|
||||
rule := NewIPv4Matcher(chinaIPNet)
|
||||
assert.Bool(rule.Apply(makeDestination("121.14.1.189"))).IsTrue() // sina.com.cn
|
||||
assert.Bool(rule.Apply(makeDestination("101.226.103.106"))).IsTrue() // qq.com
|
||||
assert.Bool(rule.Apply(makeDestination("115.239.210.36"))).IsTrue() // image.baidu.com
|
@ -1,29 +1,38 @@
|
||||
package json
|
||||
// +build json
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"encoding/json"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
)
|
||||
|
||||
type ChinaSitesRule struct {
|
||||
Rule
|
||||
type ChinaSitesCondition struct {
|
||||
}
|
||||
|
||||
func (this *ChinaSitesRule) Apply(dest v2net.Destination) bool {
|
||||
address := dest.Address()
|
||||
if !address.IsDomain() {
|
||||
return false
|
||||
}
|
||||
domain := strings.ToLower(address.Domain())
|
||||
for _, matcher := range compiledMatchers {
|
||||
if matcher.Match(domain) {
|
||||
func (this *ChinaSitesCondition) Apply(dest v2net.Destination) bool {
|
||||
for _, cond := range chinaSitesConds {
|
||||
if cond.Apply(dest) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func parseChinaSitesRule(data []byte) (*Rule, error) {
|
||||
rawRule := new(JsonRule)
|
||||
err := json.Unmarshal(data, rawRule)
|
||||
if err != nil {
|
||||
log.Error("Router: Invalid router rule: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return &Rule{
|
||||
Tag: rawRule.OutboundTag,
|
||||
Condition: &ChinaSitesCondition{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
const (
|
||||
anySubDomain = "^(.*\\.)?"
|
||||
dotAm = "\\.am$"
|
||||
@ -39,12 +48,10 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
compiledMatchers []*RegexpDomainMatcher
|
||||
chinaSitesConds []Condition
|
||||
)
|
||||
|
||||
func init() {
|
||||
compiledMatchers = make([]*RegexpDomainMatcher, 0, 1024)
|
||||
|
||||
regexpDomains := []string{
|
||||
dotCn,
|
||||
"\\.xn--fiqs8s$", /* .中国 */
|
||||
@ -353,11 +360,12 @@ func init() {
|
||||
anySubDomain + "zhubajie" + dotCom,
|
||||
}
|
||||
|
||||
for _, pattern := range regexpDomains {
|
||||
chinaSitesConds = make([]Condition, len(regexpDomains))
|
||||
for idx, pattern := range regexpDomains {
|
||||
matcher, err := NewRegexpDomainMatcher(pattern)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
compiledMatchers = append(compiledMatchers, matcher)
|
||||
chinaSitesConds[idx] = matcher
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
package json
|
||||
// +build json
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@ -15,7 +17,7 @@ func makeDomainDestination(domain string) v2net.Destination {
|
||||
func TestChinaSites(t *testing.T) {
|
||||
v2testing.Current(t)
|
||||
|
||||
rule := &ChinaSitesRule{}
|
||||
rule := new(ChinaSitesCondition)
|
||||
assert.Bool(rule.Apply(makeDomainDestination("v.qq.com"))).IsTrue()
|
||||
assert.Bool(rule.Apply(makeDomainDestination("www.163.com"))).IsTrue()
|
||||
assert.Bool(rule.Apply(makeDomainDestination("ngacn.cc"))).IsTrue()
|
144
app/router/rules/condition.go
Normal file
144
app/router/rules/condition.go
Normal file
@ -0,0 +1,144 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"net"
|
||||
"regexp"
|
||||
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
"github.com/v2ray/v2ray-core/common/serial"
|
||||
)
|
||||
|
||||
type Condition interface {
|
||||
Apply(dest v2net.Destination) bool
|
||||
}
|
||||
|
||||
type ConditionChan []Condition
|
||||
|
||||
func NewConditionChan() *ConditionChan {
|
||||
var condChan ConditionChan = make([]Condition, 0, 8)
|
||||
return &condChan
|
||||
}
|
||||
|
||||
func (this *ConditionChan) Add(cond Condition) *ConditionChan {
|
||||
*this = append(*this, cond)
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *ConditionChan) Apply(dest v2net.Destination) bool {
|
||||
for _, cond := range *this {
|
||||
if !cond.Apply(dest) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *ConditionChan) Len() int {
|
||||
return len(*this)
|
||||
}
|
||||
|
||||
type PlainDomainMatcher struct {
|
||||
pattern serial.StringLiteral
|
||||
}
|
||||
|
||||
func NewPlainDomainMatcher(pattern string) *PlainDomainMatcher {
|
||||
return &PlainDomainMatcher{
|
||||
pattern: serial.StringLiteral(pattern),
|
||||
}
|
||||
}
|
||||
|
||||
func (this *PlainDomainMatcher) Apply(dest v2net.Destination) bool {
|
||||
if !dest.Address().IsDomain() {
|
||||
return false
|
||||
}
|
||||
domain := serial.StringLiteral(dest.Address().Domain())
|
||||
return domain.Contains(this.pattern)
|
||||
}
|
||||
|
||||
type RegexpDomainMatcher struct {
|
||||
pattern *regexp.Regexp
|
||||
}
|
||||
|
||||
func NewRegexpDomainMatcher(pattern string) (*RegexpDomainMatcher, error) {
|
||||
r, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RegexpDomainMatcher{
|
||||
pattern: r,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (this *RegexpDomainMatcher) Apply(dest v2net.Destination) bool {
|
||||
if !dest.Address().IsDomain() {
|
||||
return false
|
||||
}
|
||||
domain := serial.StringLiteral(dest.Address().Domain())
|
||||
return this.pattern.MatchString(domain.ToLower().String())
|
||||
}
|
||||
|
||||
type CIDRMatcher struct {
|
||||
cidr *net.IPNet
|
||||
}
|
||||
|
||||
func NewCIDRMatcher(ipnet string) (*CIDRMatcher, error) {
|
||||
_, cidr, err := net.ParseCIDR(ipnet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &CIDRMatcher{
|
||||
cidr: cidr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (this *CIDRMatcher) Apply(dest v2net.Destination) bool {
|
||||
if !dest.Address().IsIPv4() && !dest.Address().IsIPv6() {
|
||||
return false
|
||||
}
|
||||
return this.cidr.Contains(dest.Address().IP())
|
||||
}
|
||||
|
||||
type IPv4Matcher struct {
|
||||
ipv4net *v2net.IPNet
|
||||
}
|
||||
|
||||
func NewIPv4Matcher(ipnet *v2net.IPNet) *IPv4Matcher {
|
||||
return &IPv4Matcher{
|
||||
ipv4net: ipnet,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *IPv4Matcher) Apply(dest v2net.Destination) bool {
|
||||
if !dest.Address().IsIPv4() {
|
||||
return false
|
||||
}
|
||||
return this.ipv4net.Contains(dest.Address().IP())
|
||||
}
|
||||
|
||||
type PortMatcher struct {
|
||||
port v2net.PortRange
|
||||
}
|
||||
|
||||
func NewPortMatcher(portRange v2net.PortRange) *PortMatcher {
|
||||
return &PortMatcher{
|
||||
port: portRange,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *PortMatcher) Apply(dest v2net.Destination) bool {
|
||||
return this.port.Contains(dest.Port())
|
||||
}
|
||||
|
||||
type NetworkMatcher struct {
|
||||
network *v2net.NetworkList
|
||||
}
|
||||
|
||||
func NewNetworkMatcher(network *v2net.NetworkList) *NetworkMatcher {
|
||||
return &NetworkMatcher{
|
||||
network: network,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *NetworkMatcher) Apply(dest v2net.Destination) bool {
|
||||
return this.network.HasNetwork(v2net.Network(dest.Network()))
|
||||
}
|
@ -4,11 +4,30 @@ import (
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
)
|
||||
|
||||
type Rule interface {
|
||||
Tag() string
|
||||
Apply(dest v2net.Destination) bool
|
||||
type Rule struct {
|
||||
Tag string
|
||||
Condition Condition
|
||||
}
|
||||
|
||||
type RouterRuleConfig interface {
|
||||
Rules() []Rule
|
||||
func (this *Rule) Apply(dest v2net.Destination) bool {
|
||||
return this.Condition.Apply(dest)
|
||||
}
|
||||
|
||||
type RouterRuleConfig struct {
|
||||
rules []*Rule
|
||||
}
|
||||
|
||||
func NewRouterRuleConfig() *RouterRuleConfig {
|
||||
return &RouterRuleConfig{
|
||||
rules: make([]*Rule, 0, 16),
|
||||
}
|
||||
}
|
||||
|
||||
func (this *RouterRuleConfig) Add(rule *Rule) *RouterRuleConfig {
|
||||
this.rules = append(this.rules, rule)
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *RouterRuleConfig) Rules() []*Rule {
|
||||
return this.rules
|
||||
}
|
||||
|
@ -1,166 +0,0 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
"github.com/v2ray/v2ray-core/common/serial"
|
||||
)
|
||||
|
||||
type DomainMatcher interface {
|
||||
Match(domain string) bool
|
||||
}
|
||||
|
||||
type PlainDomainMatcher struct {
|
||||
pattern string
|
||||
}
|
||||
|
||||
func NewPlainDomainMatcher(pattern string) *PlainDomainMatcher {
|
||||
return &PlainDomainMatcher{
|
||||
pattern: strings.ToLower(pattern),
|
||||
}
|
||||
}
|
||||
|
||||
func (this *PlainDomainMatcher) Match(domain string) bool {
|
||||
return strings.Contains(strings.ToLower(domain), this.pattern)
|
||||
}
|
||||
|
||||
type RegexpDomainMatcher struct {
|
||||
pattern *regexp.Regexp
|
||||
}
|
||||
|
||||
func NewRegexpDomainMatcher(pattern string) (*RegexpDomainMatcher, error) {
|
||||
r, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RegexpDomainMatcher{
|
||||
pattern: r,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (this *RegexpDomainMatcher) Match(domain string) bool {
|
||||
return this.pattern.MatchString(strings.ToLower(domain))
|
||||
}
|
||||
|
||||
type FieldRule struct {
|
||||
Rule
|
||||
Domain []DomainMatcher
|
||||
IP []*net.IPNet
|
||||
Port *v2net.PortRange
|
||||
Network *v2net.NetworkList
|
||||
}
|
||||
|
||||
func (this *FieldRule) Apply(dest v2net.Destination) bool {
|
||||
address := dest.Address()
|
||||
if len(this.Domain) > 0 {
|
||||
if !address.IsDomain() {
|
||||
return false
|
||||
}
|
||||
foundMatch := false
|
||||
for _, domain := range this.Domain {
|
||||
if domain.Match(address.Domain()) {
|
||||
foundMatch = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundMatch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if this.IP != nil && len(this.IP) > 0 {
|
||||
if !(address.IsIPv4() || address.IsIPv6()) {
|
||||
return false
|
||||
}
|
||||
foundMatch := false
|
||||
for _, ipnet := range this.IP {
|
||||
if ipnet.Contains(address.IP()) {
|
||||
foundMatch = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundMatch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if this.Port != nil {
|
||||
port := dest.Port()
|
||||
if port.Value() < this.Port.From.Value() || port.Value() > this.Port.To.Value() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if this.Network != nil {
|
||||
if !this.Network.HasNetwork(v2net.Network(dest.Network())) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *FieldRule) UnmarshalJSON(data []byte) error {
|
||||
type RawFieldRule struct {
|
||||
Rule
|
||||
Domain *serial.StringLiteralList `json:"domain"`
|
||||
IP *serial.StringLiteralList `json:"ip"`
|
||||
Port *v2net.PortRange `json:"port"`
|
||||
Network *v2net.NetworkList `json:"network"`
|
||||
}
|
||||
rawFieldRule := RawFieldRule{}
|
||||
err := json.Unmarshal(data, &rawFieldRule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.Type = rawFieldRule.Type
|
||||
this.OutboundTag = rawFieldRule.OutboundTag
|
||||
|
||||
hasField := false
|
||||
if rawFieldRule.Domain != nil && rawFieldRule.Domain.Len() > 0 {
|
||||
this.Domain = make([]DomainMatcher, rawFieldRule.Domain.Len())
|
||||
for idx, rawDomain := range *(rawFieldRule.Domain) {
|
||||
var matcher DomainMatcher
|
||||
if strings.HasPrefix(rawDomain.String(), "regexp:") {
|
||||
rawMatcher, err := NewRegexpDomainMatcher(rawDomain.String()[7:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
matcher = rawMatcher
|
||||
} else {
|
||||
matcher = NewPlainDomainMatcher(rawDomain.String())
|
||||
}
|
||||
this.Domain[idx] = matcher
|
||||
}
|
||||
hasField = true
|
||||
}
|
||||
|
||||
if rawFieldRule.IP != nil && rawFieldRule.IP.Len() > 0 {
|
||||
this.IP = make([]*net.IPNet, 0, rawFieldRule.IP.Len())
|
||||
for _, ipStr := range *(rawFieldRule.IP) {
|
||||
_, ipNet, err := net.ParseCIDR(ipStr.String())
|
||||
if err != nil {
|
||||
return errors.New("Invalid IP range in router rule: " + err.Error())
|
||||
}
|
||||
this.IP = append(this.IP, ipNet)
|
||||
}
|
||||
hasField = true
|
||||
}
|
||||
if rawFieldRule.Port != nil {
|
||||
this.Port = rawFieldRule.Port
|
||||
hasField = true
|
||||
}
|
||||
if rawFieldRule.Network != nil {
|
||||
this.Network = rawFieldRule.Network
|
||||
hasField = true
|
||||
}
|
||||
if !hasField {
|
||||
return errors.New("This rule has no effective fields.")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
v2testing "github.com/v2ray/v2ray-core/testing"
|
||||
"github.com/v2ray/v2ray-core/testing/assert"
|
||||
)
|
||||
|
||||
func TestDomainMatching(t *testing.T) {
|
||||
v2testing.Current(t)
|
||||
|
||||
rawJson := `{
|
||||
"type": "field",
|
||||
"domain": ["google.com", "regexp:v2ray.com$"],
|
||||
"tag": "test"
|
||||
}`
|
||||
rule := parseRule([]byte(rawJson))
|
||||
dest := v2net.TCPDestination(v2net.DomainAddress("www.v2ray.com"), 80)
|
||||
assert.Bool(rule.Apply(dest)).IsTrue()
|
||||
}
|
||||
|
||||
func TestPortMatching(t *testing.T) {
|
||||
v2testing.Current(t)
|
||||
|
||||
rule := &FieldRule{
|
||||
Port: &v2net.PortRange{
|
||||
From: 0,
|
||||
To: 100,
|
||||
},
|
||||
}
|
||||
dest := v2net.TCPDestination(v2net.DomainAddress("www.v2ray.com"), 80)
|
||||
assert.Bool(rule.Apply(dest)).IsTrue()
|
||||
}
|
||||
|
||||
func TestIPMatching(t *testing.T) {
|
||||
v2testing.Current(t)
|
||||
|
||||
rawJson := `{
|
||||
"type": "field",
|
||||
"ip": "10.0.0.0/8",
|
||||
"tag": "test"
|
||||
}`
|
||||
rule := parseRule([]byte(rawJson))
|
||||
dest := v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80)
|
||||
assert.Bool(rule.Apply(dest)).IsTrue()
|
||||
}
|
||||
|
||||
func TestIPListMatching(t *testing.T) {
|
||||
v2testing.Current(t)
|
||||
|
||||
rawJson := `{
|
||||
"type": "field",
|
||||
"ip": ["10.0.0.0/8", "192.168.0.0/16"],
|
||||
"tag": "test"
|
||||
}`
|
||||
rule := parseRule([]byte(rawJson))
|
||||
dest := v2net.TCPDestination(v2net.IPAddress([]byte{192, 168, 1, 1}), 80)
|
||||
assert.Bool(rule.Apply(dest)).IsTrue()
|
||||
}
|
||||
|
||||
func TestPortNotMatching(t *testing.T) {
|
||||
v2testing.Current(t)
|
||||
|
||||
rawJson := `{
|
||||
"type": "field",
|
||||
"port": "80-100",
|
||||
"tag": "test"
|
||||
}`
|
||||
rule := parseRule([]byte(rawJson))
|
||||
dest := v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 79)
|
||||
assert.Bool(rule.Apply(dest)).IsFalse()
|
||||
}
|
||||
|
||||
func TestDomainNotMatching(t *testing.T) {
|
||||
v2testing.Current(t)
|
||||
|
||||
rawJson := `{
|
||||
"type": "field",
|
||||
"domain": ["google.com", "v2ray.com"],
|
||||
"tag": "test"
|
||||
}`
|
||||
rule := parseRule([]byte(rawJson))
|
||||
dest := v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80)
|
||||
assert.Bool(rule.Apply(dest)).IsFalse()
|
||||
}
|
||||
|
||||
func TestDomainNotMatchingDomain(t *testing.T) {
|
||||
v2testing.Current(t)
|
||||
|
||||
rawJson := `{
|
||||
"type": "field",
|
||||
"domain": ["google.com", "v2ray.com"],
|
||||
"tag": "test"
|
||||
}`
|
||||
rule := parseRule([]byte(rawJson))
|
||||
dest := v2net.TCPDestination(v2net.DomainAddress("baidu.com"), 80)
|
||||
assert.Bool(rule.Apply(dest)).IsFalse()
|
||||
|
||||
dest = v2net.TCPDestination(v2net.DomainAddress("www.google.com"), 80)
|
||||
assert.Bool(rule.Apply(dest)).IsTrue()
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
v2routerjson "github.com/v2ray/v2ray-core/app/router/json"
|
||||
"github.com/v2ray/v2ray-core/app/router/rules"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
)
|
||||
|
||||
type RouterRuleConfig struct {
|
||||
RuleList []json.RawMessage `json:"rules"`
|
||||
}
|
||||
|
||||
func parseRule(msg json.RawMessage) rules.Rule {
|
||||
rule := new(Rule)
|
||||
err := json.Unmarshal(msg, rule)
|
||||
if err != nil {
|
||||
log.Error("Invalid router rule: %v", err)
|
||||
return nil
|
||||
}
|
||||
if rule.Type == "field" {
|
||||
fieldrule := new(FieldRule)
|
||||
err = json.Unmarshal(msg, fieldrule)
|
||||
if err != nil {
|
||||
log.Error("Invalid field rule: %v", err)
|
||||
return nil
|
||||
}
|
||||
return fieldrule
|
||||
}
|
||||
if rule.Type == "chinaip" {
|
||||
chinaiprule := new(ChinaIPRule)
|
||||
if err := json.Unmarshal(msg, chinaiprule); err != nil {
|
||||
log.Error("Invalid chinaip rule: %v", err)
|
||||
return nil
|
||||
}
|
||||
return chinaiprule
|
||||
}
|
||||
if rule.Type == "chinasites" {
|
||||
chinasitesrule := new(ChinaSitesRule)
|
||||
if err := json.Unmarshal(msg, chinasitesrule); err != nil {
|
||||
log.Error("Invalid chinasites rule: %v", err)
|
||||
return nil
|
||||
}
|
||||
return chinasitesrule
|
||||
}
|
||||
log.Error("Unknown router rule type: %s", rule.Type)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *RouterRuleConfig) Rules() []rules.Rule {
|
||||
rules := make([]rules.Rule, len(this.RuleList))
|
||||
for idx, rawRule := range this.RuleList {
|
||||
rules[idx] = parseRule(rawRule)
|
||||
}
|
||||
return rules
|
||||
}
|
||||
|
||||
func init() {
|
||||
v2routerjson.RegisterRouterConfig("rules", func() interface{} {
|
||||
return new(RouterRuleConfig)
|
||||
})
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
Type string `json:"type"`
|
||||
OutboundTag string `json:"outboundTag"`
|
||||
}
|
||||
|
||||
func (this *Rule) Tag() string {
|
||||
return this.OutboundTag
|
||||
}
|
||||
|
||||
func (this *Rule) Apply(dest v2net.Destination) bool {
|
||||
return false
|
||||
}
|
@ -38,18 +38,18 @@ func (this *cacheEntry) Extend() {
|
||||
}
|
||||
|
||||
type Router struct {
|
||||
rules []Rule
|
||||
rules []*Rule
|
||||
cache *collect.ValidityMap
|
||||
}
|
||||
|
||||
func NewRouter() *Router {
|
||||
return &Router{
|
||||
rules: make([]Rule, 0, 16),
|
||||
rules: make([]*Rule, 0, 16),
|
||||
cache: collect.NewValidityMap(3600),
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Router) AddRule(rule Rule) *Router {
|
||||
func (this *Router) AddRule(rule *Rule) *Router {
|
||||
this.rules = append(this.rules, rule)
|
||||
return this
|
||||
}
|
||||
@ -57,7 +57,7 @@ func (this *Router) AddRule(rule Rule) *Router {
|
||||
func (this *Router) takeDetourWithoutCache(dest v2net.Destination) (string, error) {
|
||||
for _, rule := range this.rules {
|
||||
if rule.Apply(dest) {
|
||||
return rule.Tag(), nil
|
||||
return rule.Tag, nil
|
||||
}
|
||||
}
|
||||
return "", NoRuleApplicable
|
||||
@ -78,7 +78,7 @@ type RouterFactory struct {
|
||||
}
|
||||
|
||||
func (this *RouterFactory) Create(rawConfig interface{}) (router.Router, error) {
|
||||
config := rawConfig.(RouterRuleConfig)
|
||||
config := rawConfig.(*RouterRuleConfig)
|
||||
rules := config.Rules()
|
||||
router := NewRouter()
|
||||
for _, rule := range rules {
|
||||
|
129
app/router/rules/router_config.go
Normal file
129
app/router/rules/router_config.go
Normal file
@ -0,0 +1,129 @@
|
||||
// +build json
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
router "github.com/v2ray/v2ray-core/app/router"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
"github.com/v2ray/v2ray-core/common/serial"
|
||||
)
|
||||
|
||||
type JsonRule struct {
|
||||
Type string `json:"type"`
|
||||
OutboundTag string `json:"outboundTag"`
|
||||
}
|
||||
|
||||
func parseFieldRule(msg json.RawMessage) (*Rule, error) {
|
||||
type RawFieldRule struct {
|
||||
JsonRule
|
||||
Domain *serial.StringLiteralList `json:"domain"`
|
||||
IP *serial.StringLiteralList `json:"ip"`
|
||||
Port *v2net.PortRange `json:"port"`
|
||||
Network *v2net.NetworkList `json:"network"`
|
||||
}
|
||||
rawFieldRule := new(RawFieldRule)
|
||||
err := json.Unmarshal(msg, rawFieldRule)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conds := NewConditionChan()
|
||||
|
||||
if rawFieldRule.Domain != nil && rawFieldRule.Domain.Len() > 0 {
|
||||
for _, rawDomain := range *(rawFieldRule.Domain) {
|
||||
var matcher Condition
|
||||
if strings.HasPrefix(rawDomain.String(), "regexp:") {
|
||||
rawMatcher, err := NewRegexpDomainMatcher(rawDomain.String()[7:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
matcher = rawMatcher
|
||||
} else {
|
||||
matcher = NewPlainDomainMatcher(rawDomain.String())
|
||||
}
|
||||
conds.Add(matcher)
|
||||
}
|
||||
}
|
||||
|
||||
if rawFieldRule.IP != nil && rawFieldRule.IP.Len() > 0 {
|
||||
for _, ipStr := range *(rawFieldRule.IP) {
|
||||
cidrMatcher, err := NewCIDRMatcher(ipStr.String())
|
||||
if err != nil {
|
||||
log.Error("Router: Invalid IP range in router rule: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
conds.Add(cidrMatcher)
|
||||
}
|
||||
}
|
||||
if rawFieldRule.Port != nil {
|
||||
conds.Add(NewPortMatcher(*rawFieldRule.Port))
|
||||
}
|
||||
if rawFieldRule.Network != nil {
|
||||
conds.Add(NewNetworkMatcher(rawFieldRule.Network))
|
||||
}
|
||||
if conds.Len() == 0 {
|
||||
return nil, errors.New("Router: This rule has no effective fields.")
|
||||
}
|
||||
return &Rule{
|
||||
Tag: rawFieldRule.OutboundTag,
|
||||
Condition: conds,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseRule(msg json.RawMessage) *Rule {
|
||||
rawRule := new(JsonRule)
|
||||
err := json.Unmarshal(msg, rawRule)
|
||||
if err != nil {
|
||||
log.Error("Router: Invalid router rule: %v", err)
|
||||
return nil
|
||||
}
|
||||
if rawRule.Type == "field" {
|
||||
|
||||
fieldrule, err := parseFieldRule(msg)
|
||||
if err != nil {
|
||||
log.Error("Invalid field rule: %v", err)
|
||||
return nil
|
||||
}
|
||||
return fieldrule
|
||||
}
|
||||
if rawRule.Type == "chinaip" {
|
||||
chinaiprule, err := parseChinaIPRule(msg)
|
||||
if err != nil {
|
||||
log.Error("Router: Invalid chinaip rule: %v", err)
|
||||
return nil
|
||||
}
|
||||
return chinaiprule
|
||||
}
|
||||
if rawRule.Type == "chinasites" {
|
||||
chinasitesrule, err := parseChinaSitesRule(msg)
|
||||
if err != nil {
|
||||
log.Error("Invalid chinasites rule: %v", err)
|
||||
return nil
|
||||
}
|
||||
return chinasitesrule
|
||||
}
|
||||
log.Error("Unknown router rule type: %s", rawRule.Type)
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
router.RegisterRouterConfig("rules", func(data []byte) (interface{}, error) {
|
||||
type JsonConfig struct {
|
||||
RuleList []json.RawMessage `json:"rules"`
|
||||
}
|
||||
jsonConfig := new(JsonConfig)
|
||||
if err := json.Unmarshal(data, jsonConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config := NewRouterRuleConfig()
|
||||
for _, rawRule := range jsonConfig.RuleList {
|
||||
rule := parseRule(rawRule)
|
||||
config.Add(rule)
|
||||
}
|
||||
return config, nil
|
||||
})
|
||||
}
|
@ -4,7 +4,6 @@ import (
|
||||
"testing"
|
||||
|
||||
. "github.com/v2ray/v2ray-core/app/router/rules"
|
||||
testinconfig "github.com/v2ray/v2ray-core/app/router/rules/testing"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
v2testing "github.com/v2ray/v2ray-core/testing"
|
||||
"github.com/v2ray/v2ray-core/testing/assert"
|
||||
@ -14,11 +13,9 @@ func TestSimpleRouter(t *testing.T) {
|
||||
v2testing.Current(t)
|
||||
|
||||
router := NewRouter().AddRule(
|
||||
&testinconfig.TestRule{
|
||||
TagValue: "test",
|
||||
Function: func(dest v2net.Destination) bool {
|
||||
return dest.IsTCP()
|
||||
},
|
||||
&Rule{
|
||||
Tag: "test",
|
||||
Condition: NewNetworkMatcher(v2net.Network("tcp").AsList()),
|
||||
})
|
||||
|
||||
tag, err := router.TakeDetour(v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80))
|
||||
|
@ -1,17 +0,0 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"github.com/v2ray/v2ray-core/app/router/rules"
|
||||
)
|
||||
|
||||
type RouterRuleConfig struct {
|
||||
RuleList []*TestRule
|
||||
}
|
||||
|
||||
func (this *RouterRuleConfig) Rules() []rules.Rule {
|
||||
rules := make([]rules.Rule, len(this.RuleList))
|
||||
for idx, rule := range this.RuleList {
|
||||
rules[idx] = rule
|
||||
}
|
||||
return rules
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
)
|
||||
|
||||
type TestRule struct {
|
||||
Function func(v2net.Destination) bool
|
||||
TagValue string
|
||||
}
|
||||
|
||||
func (this *TestRule) Apply(dest v2net.Destination) bool {
|
||||
return this.Function(dest)
|
||||
}
|
||||
|
||||
func (this *TestRule) Tag() string {
|
||||
return this.TagValue
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package testing
|
||||
|
||||
type RouterConfig struct {
|
||||
StrategyValue string
|
||||
SettingsValue interface{}
|
||||
}
|
||||
|
||||
func (this *RouterConfig) Strategy() string {
|
||||
return this.StrategyValue
|
||||
}
|
||||
|
||||
func (this *RouterConfig) Settings() interface{} {
|
||||
return this.SettingsValue
|
||||
}
|
@ -11,6 +11,11 @@ const (
|
||||
|
||||
type Network serial.StringLiteral
|
||||
|
||||
func (this Network) AsList() *NetworkList {
|
||||
list := NetworkList([]Network{this})
|
||||
return &list
|
||||
}
|
||||
|
||||
type NetworkList []Network
|
||||
|
||||
func NewNetworkList(networks serial.StringLiteralList) NetworkList {
|
||||
|
@ -26,3 +26,7 @@ type PortRange struct {
|
||||
From Port
|
||||
To Port
|
||||
}
|
||||
|
||||
func (this PortRange) Contains(port Port) bool {
|
||||
return this.From <= port && port <= this.To
|
||||
}
|
||||
|
@ -15,6 +15,10 @@ func NewStringLiteral(str String) StringLiteral {
|
||||
return StringLiteral(str.String())
|
||||
}
|
||||
|
||||
func (this StringLiteral) Contains(str String) bool {
|
||||
return strings.Contains(this.String(), str.String())
|
||||
}
|
||||
|
||||
func (this StringLiteral) String() string {
|
||||
return string(this)
|
||||
}
|
||||
|
@ -7,9 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/v2ray/v2ray-core"
|
||||
_ "github.com/v2ray/v2ray-core/app/router/json"
|
||||
_ "github.com/v2ray/v2ray-core/app/router/rules"
|
||||
_ "github.com/v2ray/v2ray-core/app/router/rules/json"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
"github.com/v2ray/v2ray-core/shell/point"
|
||||
pointjson "github.com/v2ray/v2ray-core/shell/point/json"
|
||||
|
@ -52,7 +52,7 @@ type OutboundDetourConfig interface {
|
||||
type PointConfig interface {
|
||||
Port() v2net.Port
|
||||
LogConfig() LogConfig
|
||||
RouterConfig() router.Config
|
||||
RouterConfig() *router.Config
|
||||
InboundConfig() ConnectionConfig
|
||||
OutboundConfig() ConnectionConfig
|
||||
InboundDetours() []InboundDetourConfig
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/v2ray/v2ray-core/app/router"
|
||||
routerjson "github.com/v2ray/v2ray-core/app/router/json"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
"github.com/v2ray/v2ray-core/shell/point"
|
||||
@ -14,13 +13,13 @@ import (
|
||||
|
||||
// Config is the config for Point server.
|
||||
type Config struct {
|
||||
PortValue v2net.Port `json:"port"` // Port of this Point server.
|
||||
LogConfigValue *LogConfig `json:"log"`
|
||||
RouterConfigValue *routerjson.RouterConfig `json:"routing"`
|
||||
InboundConfigValue *ConnectionConfig `json:"inbound"`
|
||||
OutboundConfigValue *ConnectionConfig `json:"outbound"`
|
||||
InboundDetoursValue []*InboundDetourConfig `json:"inboundDetour"`
|
||||
OutboundDetoursValue []*OutboundDetourConfig `json:"outboundDetour"`
|
||||
PortValue v2net.Port `json:"port"` // Port of this Point server.
|
||||
LogConfigValue *LogConfig `json:"log"`
|
||||
RouterConfigValue *router.Config `json:"routing"`
|
||||
InboundConfigValue *ConnectionConfig `json:"inbound"`
|
||||
OutboundConfigValue *ConnectionConfig `json:"outbound"`
|
||||
InboundDetoursValue []*InboundDetourConfig `json:"inboundDetour"`
|
||||
OutboundDetoursValue []*OutboundDetourConfig `json:"outboundDetour"`
|
||||
}
|
||||
|
||||
func (config *Config) Port() v2net.Port {
|
||||
@ -34,7 +33,7 @@ func (config *Config) LogConfig() point.LogConfig {
|
||||
return config.LogConfigValue
|
||||
}
|
||||
|
||||
func (this *Config) RouterConfig() router.Config {
|
||||
func (this *Config) RouterConfig() *router.Config {
|
||||
if this.RouterConfigValue == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
_ "github.com/v2ray/v2ray-core/app/router/rules"
|
||||
netassert "github.com/v2ray/v2ray-core/common/net/testing/assert"
|
||||
_ "github.com/v2ray/v2ray-core/proxy/dokodemo"
|
||||
_ "github.com/v2ray/v2ray-core/proxy/freedom"
|
||||
|
@ -102,7 +102,7 @@ func NewPoint(pConfig PointConfig) (*Point, error) {
|
||||
|
||||
routerConfig := pConfig.RouterConfig()
|
||||
if routerConfig != nil {
|
||||
r, err := router.CreateRouter(routerConfig.Strategy(), routerConfig.Settings())
|
||||
r, err := router.CreateRouter(routerConfig.Strategy, routerConfig.Settings)
|
||||
if err != nil {
|
||||
log.Error("Failed to create router: %v", err)
|
||||
return nil, BadConfiguration
|
||||
|
@ -2,7 +2,6 @@ package mocks
|
||||
|
||||
import (
|
||||
"github.com/v2ray/v2ray-core/app/router"
|
||||
routertesting "github.com/v2ray/v2ray-core/app/router/testing"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
v2net "github.com/v2ray/v2ray-core/common/net"
|
||||
"github.com/v2ray/v2ray-core/shell/point"
|
||||
@ -88,7 +87,7 @@ func (this *OutboundDetourConfig) Tag() string {
|
||||
type Config struct {
|
||||
PortValue v2net.Port
|
||||
LogConfigValue *LogConfig
|
||||
RouterConfigValue *routertesting.RouterConfig
|
||||
RouterConfigValue *router.Config
|
||||
InboundConfigValue *ConnectionConfig
|
||||
OutboundConfigValue *ConnectionConfig
|
||||
InboundDetoursValue []*InboundDetourConfig
|
||||
@ -106,7 +105,7 @@ func (config *Config) LogConfig() point.LogConfig {
|
||||
return config.LogConfigValue
|
||||
}
|
||||
|
||||
func (this *Config) RouterConfig() router.Config {
|
||||
func (this *Config) RouterConfig() *router.Config {
|
||||
if this.RouterConfigValue == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -4,9 +4,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
_ "github.com/v2ray/v2ray-core/app/router/json"
|
||||
_ "github.com/v2ray/v2ray-core/app/router/rules"
|
||||
_ "github.com/v2ray/v2ray-core/app/router/rules/json"
|
||||
"github.com/v2ray/v2ray-core/common/log"
|
||||
"github.com/v2ray/v2ray-core/shell/point"
|
||||
pointjson "github.com/v2ray/v2ray-core/shell/point/json"
|
||||
|
Loading…
Reference in New Issue
Block a user