From d48ac4418f7d4419fbc9190cc82502648e584880 Mon Sep 17 00:00:00 2001 From: V2Ray Date: Sat, 21 Nov 2015 21:43:40 +0100 Subject: [PATCH] config for rule based router --- app/point/config/config.go | 11 +-- app/point/config/json/inbound_detour.go | 11 ++- app/point/config/testing/mocks/config.go | 3 +- app/router/rules/json/fieldrule_test.go | 32 +++++++ app/router/rules/json/rules.go | 94 +++++++++++++++++++ app/router/rules/rules.go | 11 +++ .../config => common/net}/json/portrange.go | 0 .../net}/json/portrange_test.go | 0 common/net/portrange.go | 6 ++ common/net/testing/portrange.go | 14 +++ 10 files changed, 170 insertions(+), 12 deletions(-) create mode 100644 app/router/rules/json/fieldrule_test.go create mode 100644 app/router/rules/json/rules.go create mode 100644 app/router/rules/rules.go rename {app/point/config => common/net}/json/portrange.go (100%) rename {app/point/config => common/net}/json/portrange_test.go (100%) create mode 100644 common/net/portrange.go create mode 100644 common/net/testing/portrange.go diff --git a/app/point/config/config.go b/app/point/config/config.go index 650df3703..b94b14f0e 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 f4963e9b0..b9b012bab 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 ad70577c2..e0cbd0836 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 000000000..5522c82d1 --- /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 000000000..1b86590b2 --- /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 000000000..a7b98554d --- /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 000000000..309ce1db6 --- /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 000000000..5f78a8f86 --- /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 +}