diff --git a/app/point/config/config.go b/app/point/config/config.go index 650df370..b94b14f0 100644 --- a/app/point/config/config.go +++ b/app/point/config/config.go @@ -1,5 +1,9 @@ package config +import ( + v2net "github.com/v2ray/v2ray-core/common/net" +) + type DetourTag string type ConnectionConfig interface { @@ -11,14 +15,9 @@ type LogConfig interface { AccessLog() string } -type PortRange interface { - From() uint16 - To() uint16 -} - type InboundDetourConfig interface { Protocol() string - PortRange() PortRange + PortRange() v2net.PortRange Settings() interface{} } diff --git a/app/point/config/json/inbound_detour.go b/app/point/config/json/inbound_detour.go index f4963e9b..b9b012ba 100644 --- a/app/point/config/json/inbound_detour.go +++ b/app/point/config/json/inbound_detour.go @@ -3,21 +3,22 @@ package json import ( "encoding/json" - "github.com/v2ray/v2ray-core/app/point/config" + v2net "github.com/v2ray/v2ray-core/common/net" + v2netjson "github.com/v2ray/v2ray-core/common/net/json" proxyconfig "github.com/v2ray/v2ray-core/proxy/common/config" ) type InboundDetourConfig struct { - ProtocolValue string `json:"protocol"` - PortRangeValue *PortRange `json:"port"` - SettingsValue json.RawMessage `json:"settings"` + ProtocolValue string `json:"protocol"` + PortRangeValue *v2netjson.PortRange `json:"port"` + SettingsValue json.RawMessage `json:"settings"` } func (this *InboundDetourConfig) Protocol() string { return this.ProtocolValue } -func (this *InboundDetourConfig) PortRange() config.PortRange { +func (this *InboundDetourConfig) PortRange() v2net.PortRange { return this.PortRangeValue } diff --git a/app/point/config/testing/mocks/config.go b/app/point/config/testing/mocks/config.go index ad70577c..e0cbd083 100644 --- a/app/point/config/testing/mocks/config.go +++ b/app/point/config/testing/mocks/config.go @@ -2,6 +2,7 @@ package mocks import ( "github.com/v2ray/v2ray-core/app/point/config" + v2net "github.com/v2ray/v2ray-core/common/net" ) type ConnectionConfig struct { @@ -39,7 +40,7 @@ type InboundDetourConfig struct { PortRangeValue *PortRange } -func (this *InboundDetourConfig) PortRange() config.PortRange { +func (this *InboundDetourConfig) PortRange() v2net.PortRange { return this.PortRangeValue } diff --git a/app/router/rules/json/fieldrule_test.go b/app/router/rules/json/fieldrule_test.go new file mode 100644 index 00000000..5522c82d --- /dev/null +++ b/app/router/rules/json/fieldrule_test.go @@ -0,0 +1,32 @@ +package json + +import ( + "testing" + + v2net "github.com/v2ray/v2ray-core/common/net" + v2nettesting "github.com/v2ray/v2ray-core/common/net/testing" + "github.com/v2ray/v2ray-core/testing/unit" +) + +func TestDomainMatching(t *testing.T) { + assert := unit.Assert(t) + + rule := &FieldRule{ + Domain: "v2ray.com", + } + dest := v2net.NewTCPDestination(v2net.DomainAddress("www.v2ray.com", 80)) + assert.Bool(rule.Apply(dest)).IsTrue() +} + +func TestPortMatching(t *testing.T) { + assert := unit.Assert(t) + + rule := &FieldRule{ + Port: &v2nettesting.PortRange{ + FromValue: 0, + ToValue: 100, + }, + } + dest := v2net.NewTCPDestination(v2net.DomainAddress("www.v2ray.com", 80)) + assert.Bool(rule.Apply(dest)).IsTrue() +} diff --git a/app/router/rules/json/rules.go b/app/router/rules/json/rules.go new file mode 100644 index 00000000..1b86590b --- /dev/null +++ b/app/router/rules/json/rules.go @@ -0,0 +1,94 @@ +package json + +import ( + "encoding/json" + "errors" + "net" + "strings" + + "github.com/v2ray/v2ray-core/app/point/config" + v2net "github.com/v2ray/v2ray-core/common/net" + v2netjson "github.com/v2ray/v2ray-core/common/net/json" +) + +type Rule struct { + Type string `json:"type"` + OutboundTag string `json:"outboundTag"` +} + +func (this *Rule) Tag() *config.DetourTag { + detourTag := config.DetourTag(this.OutboundTag) + return &detourTag +} + +func (this *Rule) Apply(dest v2net.Destination) bool { + return false +} + +type FieldRule struct { + Rule + Domain string + IP *net.IPNet + Port v2net.PortRange + Network v2net.NetworkList +} + +func (this *FieldRule) Apply(dest v2net.Destination) bool { + address := dest.Address() + if len(this.Domain) > 0 && address.IsDomain() { + if !strings.Contains(address.Domain(), this.Domain) { + return false + } + } + + if this.IP != nil && (address.IsIPv4() || address.IsIPv6()) { + if !this.IP.Contains(address.IP()) { + return false + } + } + + if this.Port != nil { + port := address.Port() + if port < this.Port.From() || port > this.Port.To() { + return false + } + } + + if this.Network != nil { + if !this.Network.HasNetwork(v2net.Network(dest.Network())) { + return false + } + } + + return true +} + +func (this *FieldRule) UnmarshalJSON(data []byte) error { + type RawFieldRule struct { + Rule + Domain string `json:"domain"` + IP string `json:"ip"` + Port *v2netjson.PortRange + Network *v2netjson.NetworkList + } + rawFieldRule := RawFieldRule{} + err := json.Unmarshal(data, &rawFieldRule) + if err != nil { + return err + } + this.Type = rawFieldRule.Type + this.OutboundTag = rawFieldRule.OutboundTag + this.Domain = rawFieldRule.Domain + _, ipNet, err := net.ParseCIDR(rawFieldRule.IP) + if err != nil { + return errors.New("Invalid IP range in router rule: " + err.Error()) + } + this.IP = ipNet + if rawFieldRule.Port != nil { + this.Port = rawFieldRule.Port + } + if rawFieldRule.Network != nil { + this.Network = rawFieldRule.Network + } + return nil +} diff --git a/app/router/rules/rules.go b/app/router/rules/rules.go new file mode 100644 index 00000000..a7b98554 --- /dev/null +++ b/app/router/rules/rules.go @@ -0,0 +1,11 @@ +package rules + +import ( + "github.com/v2ray/v2ray-core/app/point/config" + v2net "github.com/v2ray/v2ray-core/common/net" +) + +type Rule interface { + Tag() *config.DetourTag + Apply(dest v2net.Destination) bool +} diff --git a/app/point/config/json/portrange.go b/common/net/json/portrange.go similarity index 100% rename from app/point/config/json/portrange.go rename to common/net/json/portrange.go diff --git a/app/point/config/json/portrange_test.go b/common/net/json/portrange_test.go similarity index 100% rename from app/point/config/json/portrange_test.go rename to common/net/json/portrange_test.go diff --git a/common/net/portrange.go b/common/net/portrange.go new file mode 100644 index 00000000..309ce1db --- /dev/null +++ b/common/net/portrange.go @@ -0,0 +1,6 @@ +package net + +type PortRange interface { + From() uint16 + To() uint16 +} diff --git a/common/net/testing/portrange.go b/common/net/testing/portrange.go new file mode 100644 index 00000000..5f78a8f8 --- /dev/null +++ b/common/net/testing/portrange.go @@ -0,0 +1,14 @@ +package testing + +type PortRange struct { + FromValue uint16 + ToValue uint16 +} + +func (this *PortRange) From() uint16 { + return this.FromValue +} + +func (this *PortRange) To() uint16 { + return this.ToValue +}