Use dns in router

pull/168/head
v2ray 2016-05-16 00:25:34 -07:00
parent 3b545abe02
commit dac1339d6e
15 changed files with 92 additions and 34 deletions

View File

@ -1,4 +1,4 @@
package internal package dns
import ( import (
v2net "github.com/v2ray/v2ray-core/common/net" v2net "github.com/v2ray/v2ray-core/common/net"

View File

@ -1,6 +1,6 @@
// +build json // +build json
package internal package dns
import ( import (
"encoding/json" "encoding/json"

View File

@ -28,10 +28,6 @@ func (this *contextedDnsServer) Get(domain string) []net.IP {
return this.dnsCache.Get(this.context, domain) return this.dnsCache.Get(this.context, domain)
} }
func CreateDNSServer(rawConfig interface{}) (Server, error) {
return nil, nil
}
func init() { func init() {
app.Register(APP_ID, func(context app.Context, obj interface{}) interface{} { app.Register(APP_ID, func(context app.Context, obj interface{}) interface{} {
dcContext := obj.(dnsServerWithContext) dcContext := obj.(dnsServerWithContext)

View File

@ -1,4 +1,4 @@
package internal package dns
import ( import (
"math/rand" "math/rand"

View File

@ -1,4 +1,4 @@
package internal package dns
import ( import (
"net" "net"
@ -19,14 +19,14 @@ type DomainRecord struct {
A *ARecord A *ARecord
} }
type Server struct { type CacheServer struct {
sync.RWMutex sync.RWMutex
records map[string]*DomainRecord records map[string]*DomainRecord
servers []NameServer servers []NameServer
} }
func NewServer(space app.Space, config *Config) *Server { func NewCacheServer(space app.Space, config *Config) *CacheServer {
server := &Server{ server := &CacheServer{
records: make(map[string]*DomainRecord), records: make(map[string]*DomainRecord),
servers: make([]NameServer, len(config.NameServers)), servers: make([]NameServer, len(config.NameServers)),
} }
@ -38,7 +38,7 @@ func NewServer(space app.Space, config *Config) *Server {
} }
//@Private //@Private
func (this *Server) GetCached(domain string) []net.IP { func (this *CacheServer) GetCached(domain string) []net.IP {
this.RLock() this.RLock()
defer this.RUnlock() defer this.RUnlock()
@ -48,7 +48,7 @@ func (this *Server) GetCached(domain string) []net.IP {
return nil 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) domain = dns.Fqdn(domain)
ips := this.GetCached(domain) ips := this.GetCached(domain)
if ips != nil { if ips != nil {

View File

@ -1,4 +1,4 @@
package internal_test package dns_test
import ( import (
"net" "net"
@ -6,7 +6,7 @@ import (
"github.com/v2ray/v2ray-core/app" "github.com/v2ray/v2ray-core/app"
"github.com/v2ray/v2ray-core/app/dispatcher" "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" apptesting "github.com/v2ray/v2ray-core/app/testing"
v2net "github.com/v2ray/v2ray-core/common/net" v2net "github.com/v2ray/v2ray-core/common/net"
netassert "github.com/v2ray/v2ray-core/common/net/testing/assert" 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) spaceController.Bind(dispatcher.APP_ID, d)
space := spaceController.ForContext("test") space := spaceController.ForContext("test")
domain := "v2ray.com" domain := "local.v2ray.com"
server := NewServer(space, &Config{ server := NewCacheServer(space, &Config{
NameServers: []v2net.Destination{ NameServers: []v2net.Destination{
v2net.UDPDestination(v2net.IPAddress([]byte{8, 8, 8, 8}), v2net.Port(53)), 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{ ips := server.Get(&apptesting.Context{
CallerTagValue: "a", CallerTagValue: "a",
}, domain) }, domain)
assert.Int(len(ips)).Equals(2) assert.Int(len(ips)).Equals(1)
netassert.IP(ips[0].To4()).Equals(net.IP([]byte{104, 27, 154, 107})) netassert.IP(ips[0].To4()).Equals(net.IP([]byte{127, 0, 0, 1}))
} }

View File

@ -1,6 +1,7 @@
package router package router
import ( import (
"github.com/v2ray/v2ray-core/app"
v2net "github.com/v2ray/v2ray-core/common/net" v2net "github.com/v2ray/v2ray-core/common/net"
) )
@ -9,7 +10,7 @@ type Router interface {
} }
type RouterFactory interface { type RouterFactory interface {
Create(rawConfig interface{}) (Router, error) Create(rawConfig interface{}, space app.Space) (Router, error)
} }
var ( var (
@ -22,9 +23,9 @@ func RegisterRouter(name string, factory RouterFactory) error {
return nil 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 { if factory, found := routerCache[name]; found {
return factory.Create(rawConfig) return factory.Create(rawConfig, space)
} }
return nil, ErrorRouterNotFound return nil, ErrorRouterNotFound
} }

View File

@ -21,7 +21,7 @@ func TestRouter(t *testing.T) {
pointConfig, err := point.LoadConfig(filepath.Join(baseDir, "vpoint_socks_vmess.json")) pointConfig, err := point.LoadConfig(filepath.Join(baseDir, "vpoint_socks_vmess.json"))
assert.Error(err).IsNil() 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() assert.Error(err).IsNil()
dest := v2net.TCPDestination(v2net.IPAddress(net.ParseIP("120.135.126.1")), 80) dest := v2net.TCPDestination(v2net.IPAddress(net.ParseIP("120.135.126.1")), 80)

View File

@ -13,7 +13,15 @@ func (this *Rule) Apply(dest v2net.Destination) bool {
return this.Condition.Apply(dest) return this.Condition.Apply(dest)
} }
type DomainStrategy int
var (
DomainAsIs = DomainStrategy(0)
AlwaysUseIP = DomainStrategy(1)
UseIPIfNonMatch = DomainStrategy(2)
)
type RouterRuleConfig struct { type RouterRuleConfig struct {
Rules []*Rule Rules []*Rule
ResolveDomain bool DomainStrategy DomainStrategy
} }

View File

@ -117,16 +117,22 @@ func ParseRule(msg json.RawMessage) *Rule {
func init() { func init() {
router.RegisterRouterConfig("rules", func(data []byte) (interface{}, error) { router.RegisterRouterConfig("rules", func(data []byte) (interface{}, error) {
type JsonConfig struct { type JsonConfig struct {
RuleList []json.RawMessage `json:"rules"` RuleList []json.RawMessage `json:"rules"`
ResolveDomain bool `json:"resolveDomain"` DomainStrategy string `json:"domainStrategy"`
} }
jsonConfig := new(JsonConfig) jsonConfig := new(JsonConfig)
if err := json.Unmarshal(data, jsonConfig); err != nil { if err := json.Unmarshal(data, jsonConfig); err != nil {
return nil, err return nil, err
} }
config := &RouterRuleConfig{ config := &RouterRuleConfig{
Rules: make([]*Rule, len(jsonConfig.RuleList)), Rules: make([]*Rule, len(jsonConfig.RuleList)),
ResolveDomain: jsonConfig.ResolveDomain, 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 { for idx, rawRule := range jsonConfig.RuleList {
rule := ParseRule(rawRule) rule := ParseRule(rawRule)

View File

@ -4,6 +4,8 @@ import (
"errors" "errors"
"time" "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/app/router"
"github.com/v2ray/v2ray-core/common/collect" "github.com/v2ray/v2ray-core/common/collect"
v2net "github.com/v2ray/v2ray-core/common/net" v2net "github.com/v2ray/v2ray-core/common/net"
@ -40,21 +42,54 @@ func (this *cacheEntry) Extend() {
type Router struct { type Router struct {
config *RouterRuleConfig config *RouterRuleConfig
cache *collect.ValidityMap cache *collect.ValidityMap
space app.Space
} }
func NewRouter(config *RouterRuleConfig) *Router { func NewRouter(config *RouterRuleConfig, space app.Space) *Router {
return &Router{ return &Router{
config: config, config: config,
cache: collect.NewValidityMap(3600), 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) { func (this *Router) takeDetourWithoutCache(dest v2net.Destination) (string, error) {
for _, rule := range this.config.Rules { for _, rule := range this.config.Rules {
if rule.Apply(dest) { if rule.Apply(dest) {
return rule.Tag, nil 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 return "", ErrorNoRuleApplicable
} }
@ -72,8 +107,8 @@ func (this *Router) TakeDetour(dest v2net.Destination) (string, error) {
type RouterFactory struct { type RouterFactory struct {
} }
func (this *RouterFactory) Create(rawConfig interface{}) (router.Router, error) { func (this *RouterFactory) Create(rawConfig interface{}, space app.Space) (router.Router, error) {
return NewRouter(rawConfig.(*RouterRuleConfig)), nil return NewRouter(rawConfig.(*RouterRuleConfig), space), nil
} }
func init() { func init() {

View File

@ -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)) tag, err := router.TakeDetour(v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80))
assert.Error(err).IsNil() assert.Error(err).IsNil()

View File

@ -1,6 +1,7 @@
package point package point
import ( import (
"github.com/v2ray/v2ray-core/app/dns"
"github.com/v2ray/v2ray-core/app/router" "github.com/v2ray/v2ray-core/app/router"
"github.com/v2ray/v2ray-core/common/log" "github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net" v2net "github.com/v2ray/v2ray-core/common/net"
@ -47,6 +48,7 @@ type Config struct {
Port v2net.Port Port v2net.Port
LogConfig *LogConfig LogConfig *LogConfig
RouterConfig *router.Config RouterConfig *router.Config
DNSConfig *dns.Config
InboundConfig *ConnectionConfig InboundConfig *ConnectionConfig
OutboundConfig *ConnectionConfig OutboundConfig *ConnectionConfig
InboundDetours []*InboundDetourConfig InboundDetours []*InboundDetourConfig

View File

@ -8,6 +8,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/v2ray/v2ray-core/app/dns"
"github.com/v2ray/v2ray-core/app/router" "github.com/v2ray/v2ray-core/app/router"
"github.com/v2ray/v2ray-core/common/log" "github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net" 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. Port v2net.Port `json:"port"` // Port of this Point server.
LogConfig *LogConfig `json:"log"` LogConfig *LogConfig `json:"log"`
RouterConfig *router.Config `json:"routing"` RouterConfig *router.Config `json:"routing"`
DNSConfig *dns.Config `json:"dns"`
InboundConfig *ConnectionConfig `json:"inbound"` InboundConfig *ConnectionConfig `json:"inbound"`
OutboundConfig *ConnectionConfig `json:"outbound"` OutboundConfig *ConnectionConfig `json:"outbound"`
InboundDetours []*InboundDetourConfig `json:"inboundDetour"` InboundDetours []*InboundDetourConfig `json:"inboundDetour"`
@ -38,6 +40,7 @@ func (this *Config) UnmarshalJSON(data []byte) error {
this.OutboundConfig = jsonConfig.OutboundConfig this.OutboundConfig = jsonConfig.OutboundConfig
this.InboundDetours = jsonConfig.InboundDetours this.InboundDetours = jsonConfig.InboundDetours
this.OutboundDetours = jsonConfig.OutboundDetours this.OutboundDetours = jsonConfig.OutboundDetours
this.DNSConfig = jsonConfig.DNSConfig
return nil return nil
} }

View File

@ -7,6 +7,7 @@ package point
import ( import (
"github.com/v2ray/v2ray-core/app" "github.com/v2ray/v2ray-core/app"
"github.com/v2ray/v2ray-core/app/dispatcher" "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/proxyman"
"github.com/v2ray/v2ray-core/app/router" "github.com/v2ray/v2ray-core/app/router"
"github.com/v2ray/v2ray-core/common/log" "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 routerConfig := pConfig.RouterConfig
if routerConfig != nil { 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 { if err != nil {
log.Error("Failed to create router: ", err) log.Error("Failed to create router: ", err)
return nil, ErrorBadConfiguration return nil, ErrorBadConfiguration