From dac1339d6e0ba83ffea3eff1fe80f20fcd1cf491 Mon Sep 17 00:00:00 2001 From: v2ray Date: Mon, 16 May 2016 00:25:34 -0700 Subject: [PATCH] Use dns in router --- app/dns/{internal => }/config.go | 2 +- app/dns/{internal => }/config_json.go | 2 +- app/dns/dns.go | 4 -- app/dns/{internal => }/nameserver.go | 2 +- app/dns/{internal/dns.go => server.go} | 12 +++--- .../{internal/dns_test.go => server_test.go} | 12 +++--- app/router/router.go | 7 ++-- app/router/router_test.go | 2 +- app/router/rules/config.go | 12 +++++- app/router/rules/config_json.go | 14 +++++-- app/router/rules/router.go | 41 +++++++++++++++++-- app/router/rules/router_test.go | 2 +- shell/point/config.go | 2 + shell/point/config_json.go | 3 ++ shell/point/point.go | 9 +++- 15 files changed, 92 insertions(+), 34 deletions(-) rename app/dns/{internal => }/config.go (87%) rename app/dns/{internal => }/config_json.go (96%) rename app/dns/{internal => }/nameserver.go (99%) rename app/dns/{internal/dns.go => server.go} (80%) rename app/dns/{internal/dns_test.go => server_test.go} (85%) diff --git a/app/dns/internal/config.go b/app/dns/config.go similarity index 87% rename from app/dns/internal/config.go rename to app/dns/config.go index 7d18323e..863a855a 100644 --- a/app/dns/internal/config.go +++ b/app/dns/config.go @@ -1,4 +1,4 @@ -package internal +package dns import ( v2net "github.com/v2ray/v2ray-core/common/net" diff --git a/app/dns/internal/config_json.go b/app/dns/config_json.go similarity index 96% rename from app/dns/internal/config_json.go rename to app/dns/config_json.go index 351cb0ec..8e869d25 100644 --- a/app/dns/internal/config_json.go +++ b/app/dns/config_json.go @@ -1,6 +1,6 @@ // +build json -package internal +package dns import ( "encoding/json" diff --git a/app/dns/dns.go b/app/dns/dns.go index b80bf4d3..1923e588 100644 --- a/app/dns/dns.go +++ b/app/dns/dns.go @@ -28,10 +28,6 @@ func (this *contextedDnsServer) Get(domain string) []net.IP { return this.dnsCache.Get(this.context, domain) } -func CreateDNSServer(rawConfig interface{}) (Server, error) { - return nil, nil -} - func init() { app.Register(APP_ID, func(context app.Context, obj interface{}) interface{} { dcContext := obj.(dnsServerWithContext) diff --git a/app/dns/internal/nameserver.go b/app/dns/nameserver.go similarity index 99% rename from app/dns/internal/nameserver.go rename to app/dns/nameserver.go index a8782669..38addb23 100644 --- a/app/dns/internal/nameserver.go +++ b/app/dns/nameserver.go @@ -1,4 +1,4 @@ -package internal +package dns import ( "math/rand" diff --git a/app/dns/internal/dns.go b/app/dns/server.go similarity index 80% rename from app/dns/internal/dns.go rename to app/dns/server.go index 817ed11e..4db5f03e 100644 --- a/app/dns/internal/dns.go +++ b/app/dns/server.go @@ -1,4 +1,4 @@ -package internal +package dns import ( "net" @@ -19,14 +19,14 @@ type DomainRecord struct { A *ARecord } -type Server struct { +type CacheServer struct { sync.RWMutex records map[string]*DomainRecord servers []NameServer } -func NewServer(space app.Space, config *Config) *Server { - server := &Server{ +func NewCacheServer(space app.Space, config *Config) *CacheServer { + server := &CacheServer{ records: make(map[string]*DomainRecord), servers: make([]NameServer, len(config.NameServers)), } @@ -38,7 +38,7 @@ func NewServer(space app.Space, config *Config) *Server { } //@Private -func (this *Server) GetCached(domain string) []net.IP { +func (this *CacheServer) GetCached(domain string) []net.IP { this.RLock() defer this.RUnlock() @@ -48,7 +48,7 @@ func (this *Server) GetCached(domain string) []net.IP { return nil } -func (this *Server) Get(context app.Context, domain string) []net.IP { +func (this *CacheServer) Get(context app.Context, domain string) []net.IP { domain = dns.Fqdn(domain) ips := this.GetCached(domain) if ips != nil { diff --git a/app/dns/internal/dns_test.go b/app/dns/server_test.go similarity index 85% rename from app/dns/internal/dns_test.go rename to app/dns/server_test.go index 111ec1a1..ba1f47d8 100644 --- a/app/dns/internal/dns_test.go +++ b/app/dns/server_test.go @@ -1,4 +1,4 @@ -package internal_test +package dns_test import ( "net" @@ -6,7 +6,7 @@ import ( "github.com/v2ray/v2ray-core/app" "github.com/v2ray/v2ray-core/app/dispatcher" - . "github.com/v2ray/v2ray-core/app/dns/internal" + . "github.com/v2ray/v2ray-core/app/dns" apptesting "github.com/v2ray/v2ray-core/app/testing" v2net "github.com/v2ray/v2ray-core/common/net" netassert "github.com/v2ray/v2ray-core/common/net/testing/assert" @@ -45,8 +45,8 @@ func TestDnsAdd(t *testing.T) { spaceController.Bind(dispatcher.APP_ID, d) space := spaceController.ForContext("test") - domain := "v2ray.com" - server := NewServer(space, &Config{ + domain := "local.v2ray.com" + server := NewCacheServer(space, &Config{ NameServers: []v2net.Destination{ v2net.UDPDestination(v2net.IPAddress([]byte{8, 8, 8, 8}), v2net.Port(53)), }, @@ -54,6 +54,6 @@ func TestDnsAdd(t *testing.T) { ips := server.Get(&apptesting.Context{ CallerTagValue: "a", }, domain) - assert.Int(len(ips)).Equals(2) - netassert.IP(ips[0].To4()).Equals(net.IP([]byte{104, 27, 154, 107})) + assert.Int(len(ips)).Equals(1) + netassert.IP(ips[0].To4()).Equals(net.IP([]byte{127, 0, 0, 1})) } diff --git a/app/router/router.go b/app/router/router.go index aaf729af..857e69c3 100644 --- a/app/router/router.go +++ b/app/router/router.go @@ -1,6 +1,7 @@ package router import ( + "github.com/v2ray/v2ray-core/app" v2net "github.com/v2ray/v2ray-core/common/net" ) @@ -9,7 +10,7 @@ type Router interface { } type RouterFactory interface { - Create(rawConfig interface{}) (Router, error) + Create(rawConfig interface{}, space app.Space) (Router, error) } var ( @@ -22,9 +23,9 @@ func RegisterRouter(name string, factory RouterFactory) error { return nil } -func CreateRouter(name string, rawConfig interface{}) (Router, error) { +func CreateRouter(name string, rawConfig interface{}, space app.Space) (Router, error) { if factory, found := routerCache[name]; found { - return factory.Create(rawConfig) + return factory.Create(rawConfig, space) } return nil, ErrorRouterNotFound } diff --git a/app/router/router_test.go b/app/router/router_test.go index 5f9b60a4..e70e039a 100644 --- a/app/router/router_test.go +++ b/app/router/router_test.go @@ -21,7 +21,7 @@ func TestRouter(t *testing.T) { pointConfig, err := point.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, nil) assert.Error(err).IsNil() dest := v2net.TCPDestination(v2net.IPAddress(net.ParseIP("120.135.126.1")), 80) diff --git a/app/router/rules/config.go b/app/router/rules/config.go index b90e1e8f..8204692a 100644 --- a/app/router/rules/config.go +++ b/app/router/rules/config.go @@ -13,7 +13,15 @@ func (this *Rule) Apply(dest v2net.Destination) bool { return this.Condition.Apply(dest) } +type DomainStrategy int + +var ( + DomainAsIs = DomainStrategy(0) + AlwaysUseIP = DomainStrategy(1) + UseIPIfNonMatch = DomainStrategy(2) +) + type RouterRuleConfig struct { - Rules []*Rule - ResolveDomain bool + Rules []*Rule + DomainStrategy DomainStrategy } diff --git a/app/router/rules/config_json.go b/app/router/rules/config_json.go index 3e7e5e8d..c87c388c 100644 --- a/app/router/rules/config_json.go +++ b/app/router/rules/config_json.go @@ -117,16 +117,22 @@ func ParseRule(msg json.RawMessage) *Rule { func init() { router.RegisterRouterConfig("rules", func(data []byte) (interface{}, error) { type JsonConfig struct { - RuleList []json.RawMessage `json:"rules"` - ResolveDomain bool `json:"resolveDomain"` + RuleList []json.RawMessage `json:"rules"` + DomainStrategy string `json:"domainStrategy"` } jsonConfig := new(JsonConfig) if err := json.Unmarshal(data, jsonConfig); err != nil { return nil, err } config := &RouterRuleConfig{ - Rules: make([]*Rule, len(jsonConfig.RuleList)), - ResolveDomain: jsonConfig.ResolveDomain, + Rules: make([]*Rule, len(jsonConfig.RuleList)), + DomainStrategy: DomainAsIs, + } + domainStrategy := serial.StringLiteral(jsonConfig.DomainStrategy).ToLower() + if domainStrategy.String() == "alwaysip" { + config.DomainStrategy = AlwaysUseIP + } else if domainStrategy.String() == "ipifnonmatch" { + config.DomainStrategy = UseIPIfNonMatch } for idx, rawRule := range jsonConfig.RuleList { rule := ParseRule(rawRule) diff --git a/app/router/rules/router.go b/app/router/rules/router.go index ea2f2424..8e755cb1 100644 --- a/app/router/rules/router.go +++ b/app/router/rules/router.go @@ -4,6 +4,8 @@ import ( "errors" "time" + "github.com/v2ray/v2ray-core/app" + "github.com/v2ray/v2ray-core/app/dns" "github.com/v2ray/v2ray-core/app/router" "github.com/v2ray/v2ray-core/common/collect" v2net "github.com/v2ray/v2ray-core/common/net" @@ -40,21 +42,54 @@ func (this *cacheEntry) Extend() { type Router struct { config *RouterRuleConfig cache *collect.ValidityMap + space app.Space } -func NewRouter(config *RouterRuleConfig) *Router { +func NewRouter(config *RouterRuleConfig, space app.Space) *Router { return &Router{ config: config, cache: collect.NewValidityMap(3600), + space: space, } } +// @Private +func (this *Router) ResolveIP(dest v2net.Destination) []v2net.Destination { + dnsServer := this.space.GetApp(dns.APP_ID).(dns.Server) + ips := dnsServer.Get(dest.Address().Domain()) + if len(ips) == 0 { + return nil + } + dests := make([]v2net.Destination, len(ips)) + for idx, ip := range ips { + if dest.IsTCP() { + dests[idx] = v2net.TCPDestination(v2net.IPAddress(ip), dest.Port()) + } else { + dests[idx] = v2net.UDPDestination(v2net.IPAddress(ip), dest.Port()) + } + } + return dests +} + func (this *Router) takeDetourWithoutCache(dest v2net.Destination) (string, error) { for _, rule := range this.config.Rules { if rule.Apply(dest) { return rule.Tag, nil } } + if this.config.DomainStrategy == UseIPIfNonMatch && dest.Address().IsDomain() { + ipDests := this.ResolveIP(dest) + if ipDests != nil { + for _, ipDest := range ipDests { + for _, rule := range this.config.Rules { + if rule.Apply(ipDest) { + return rule.Tag, nil + } + } + } + } + } + return "", ErrorNoRuleApplicable } @@ -72,8 +107,8 @@ func (this *Router) TakeDetour(dest v2net.Destination) (string, error) { type RouterFactory struct { } -func (this *RouterFactory) Create(rawConfig interface{}) (router.Router, error) { - return NewRouter(rawConfig.(*RouterRuleConfig)), nil +func (this *RouterFactory) Create(rawConfig interface{}, space app.Space) (router.Router, error) { + return NewRouter(rawConfig.(*RouterRuleConfig), space), nil } func init() { diff --git a/app/router/rules/router_test.go b/app/router/rules/router_test.go index 9503d489..e8f72e02 100644 --- a/app/router/rules/router_test.go +++ b/app/router/rules/router_test.go @@ -21,7 +21,7 @@ func TestSimpleRouter(t *testing.T) { }, } - router := NewRouter(config) + router := NewRouter(config, nil) tag, err := router.TakeDetour(v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80)) assert.Error(err).IsNil() diff --git a/shell/point/config.go b/shell/point/config.go index 0a0b28ed..eee982fd 100644 --- a/shell/point/config.go +++ b/shell/point/config.go @@ -1,6 +1,7 @@ package point import ( + "github.com/v2ray/v2ray-core/app/dns" "github.com/v2ray/v2ray-core/app/router" "github.com/v2ray/v2ray-core/common/log" v2net "github.com/v2ray/v2ray-core/common/net" @@ -47,6 +48,7 @@ type Config struct { Port v2net.Port LogConfig *LogConfig RouterConfig *router.Config + DNSConfig *dns.Config InboundConfig *ConnectionConfig OutboundConfig *ConnectionConfig InboundDetours []*InboundDetourConfig diff --git a/shell/point/config_json.go b/shell/point/config_json.go index 7a65d7cd..72ca2ca7 100644 --- a/shell/point/config_json.go +++ b/shell/point/config_json.go @@ -8,6 +8,7 @@ import ( "os" "strings" + "github.com/v2ray/v2ray-core/app/dns" "github.com/v2ray/v2ray-core/app/router" "github.com/v2ray/v2ray-core/common/log" v2net "github.com/v2ray/v2ray-core/common/net" @@ -22,6 +23,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { Port v2net.Port `json:"port"` // Port of this Point server. LogConfig *LogConfig `json:"log"` RouterConfig *router.Config `json:"routing"` + DNSConfig *dns.Config `json:"dns"` InboundConfig *ConnectionConfig `json:"inbound"` OutboundConfig *ConnectionConfig `json:"outbound"` InboundDetours []*InboundDetourConfig `json:"inboundDetour"` @@ -38,6 +40,7 @@ func (this *Config) UnmarshalJSON(data []byte) error { this.OutboundConfig = jsonConfig.OutboundConfig this.InboundDetours = jsonConfig.InboundDetours this.OutboundDetours = jsonConfig.OutboundDetours + this.DNSConfig = jsonConfig.DNSConfig return nil } diff --git a/shell/point/point.go b/shell/point/point.go index 0a784f87..d1141174 100644 --- a/shell/point/point.go +++ b/shell/point/point.go @@ -7,6 +7,7 @@ package point import ( "github.com/v2ray/v2ray-core/app" "github.com/v2ray/v2ray-core/app/dispatcher" + "github.com/v2ray/v2ray-core/app/dns" "github.com/v2ray/v2ray-core/app/proxyman" "github.com/v2ray/v2ray-core/app/router" "github.com/v2ray/v2ray-core/common/log" @@ -120,9 +121,15 @@ func NewPoint(pConfig *Config) (*Point, error) { } } + dnsConfig := pConfig.DNSConfig + if dnsConfig != nil { + dnsServer := dns.NewCacheServer(vpoint.space.ForContext("system.dns"), dnsConfig) + vpoint.space.Bind(dns.APP_ID, dnsServer) + } + routerConfig := pConfig.RouterConfig if routerConfig != nil { - r, err := router.CreateRouter(routerConfig.Strategy, routerConfig.Settings) + r, err := router.CreateRouter(routerConfig.Strategy, routerConfig.Settings, vpoint.space.ForContext("system.router")) if err != nil { log.Error("Failed to create router: ", err) return nil, ErrorBadConfiguration