From ab4f245313244ae4fce5beb9b378af90d8d69629 Mon Sep 17 00:00:00 2001 From: Darien Raymond Date: Tue, 19 Dec 2017 23:55:09 +0100 Subject: [PATCH] overrideable dns --- app/dns/dns.go | 20 ------------- app/dns/{server => }/nameserver.go | 5 ++-- app/dns/{server => }/server.go | 25 ++++++++-------- app/dns/server/errors.generated.go | 7 ----- app/dns/{server => }/server_test.go | 3 +- app/router/router.go | 23 ++++++--------- common/net/dns.go | 44 +++++++++++++++++++++++++++++ common/net/system.go | 1 - main/distro/all/all.go | 3 +- proxy/freedom/freedom.go | 13 +++------ v2ray.go | 15 ---------- 11 files changed, 74 insertions(+), 85 deletions(-) rename app/dns/{server => }/nameserver.go (98%) rename app/dns/{server => }/server.go (84%) delete mode 100644 app/dns/server/errors.generated.go rename app/dns/{server => }/server_test.go (97%) create mode 100644 common/net/dns.go diff --git a/app/dns/dns.go b/app/dns/dns.go index 6dfcabdd5..77633f5f8 100644 --- a/app/dns/dns.go +++ b/app/dns/dns.go @@ -1,23 +1,3 @@ package dns //go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg dns -path App,DNS - -import ( - "net" - - "v2ray.com/core/app" -) - -// A Server is a DNS server for responding DNS queries. -type Server interface { - Get(domain string) []net.IP -} - -// FromSpace fetches a DNS server from context. -func FromSpace(space app.Space) Server { - app := space.GetApplication((*Server)(nil)) - if app == nil { - return nil - } - return app.(Server) -} diff --git a/app/dns/server/nameserver.go b/app/dns/nameserver.go similarity index 98% rename from app/dns/server/nameserver.go rename to app/dns/nameserver.go index ea50c9fcd..18d299295 100644 --- a/app/dns/server/nameserver.go +++ b/app/dns/nameserver.go @@ -1,4 +1,4 @@ -package server +package dns import ( "context" @@ -203,7 +203,8 @@ func (*LocalNameServer) QueryA(domain string) <-chan *ARecord { go func() { defer close(response) - ips, err := net.LookupIP(domain) + resolver := net.SystemIPResolver() + ips, err := resolver.LookupIP(domain) if err != nil { newError("failed to lookup IPs for domain ", domain).Base(err).WriteToLog() return diff --git a/app/dns/server/server.go b/app/dns/server.go similarity index 84% rename from app/dns/server/server.go rename to app/dns/server.go index f97d5008e..f2d7f0643 100644 --- a/app/dns/server/server.go +++ b/app/dns/server.go @@ -1,4 +1,4 @@ -package server +package dns //go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg server -path App,DNS,Server @@ -10,7 +10,6 @@ import ( dnsmsg "github.com/miekg/dns" "v2ray.com/core/app" "v2ray.com/core/app/dispatcher" - "v2ray.com/core/app/dns" "v2ray.com/core/common" "v2ray.com/core/common/net" ) @@ -41,7 +40,7 @@ type CacheServer struct { servers []NameServer } -func NewCacheServer(ctx context.Context, config *dns.Config) (*CacheServer, error) { +func NewCacheServer(ctx context.Context, config *Config) (*CacheServer, error) { space := app.SpaceFromContext(ctx) if space == nil { return nil, newError("no space in context") @@ -79,10 +78,11 @@ func NewCacheServer(ctx context.Context, config *dns.Config) (*CacheServer, erro } func (*CacheServer) Interface() interface{} { - return (*dns.Server)(nil) + return (*CacheServer)(nil) } -func (*CacheServer) Start() error { +func (s *CacheServer) Start() error { + net.RegisterIPResolver(s) return nil } @@ -116,15 +116,15 @@ func (s *CacheServer) tryCleanup() { } } -func (s *CacheServer) Get(domain string) []net.IP { +func (s *CacheServer) LookupIP(domain string) ([]net.IP, error) { if ip, found := s.hosts[domain]; found { - return []net.IP{ip} + return []net.IP{ip}, nil } domain = dnsmsg.Fqdn(domain) ips := s.GetCached(domain) if ips != nil { - return ips + return ips, nil } s.tryCleanup() @@ -144,17 +144,16 @@ func (s *CacheServer) Get(domain string) []net.IP { } s.Unlock() newError("returning ", len(a.IPs), " IPs for domain ", domain).AtDebug().WriteToLog() - return a.IPs + return a.IPs, nil case <-time.After(QueryTimeout): } } - newError("returning nil for domain ", domain).AtDebug().WriteToLog() - return nil + return nil, newError("returning nil for domain ", domain) } func init() { - common.Must(common.RegisterConfig((*dns.Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { - return NewCacheServer(ctx, config.(*dns.Config)) + common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { + return NewCacheServer(ctx, config.(*Config)) })) } diff --git a/app/dns/server/errors.generated.go b/app/dns/server/errors.generated.go deleted file mode 100644 index e903f474b..000000000 --- a/app/dns/server/errors.generated.go +++ /dev/null @@ -1,7 +0,0 @@ -package server - -import "v2ray.com/core/common/errors" - -func newError(values ...interface{}) *errors.Error { - return errors.New(values...).Path("App", "DNS", "Server") -} diff --git a/app/dns/server/server_test.go b/app/dns/server_test.go similarity index 97% rename from app/dns/server/server_test.go rename to app/dns/server_test.go index daaae9db8..a22e5010b 100644 --- a/app/dns/server/server_test.go +++ b/app/dns/server_test.go @@ -1,4 +1,4 @@ -package server_test +package dns_test import ( "context" @@ -8,7 +8,6 @@ import ( "v2ray.com/core/app/dispatcher" _ "v2ray.com/core/app/dispatcher/impl" . "v2ray.com/core/app/dns" - _ "v2ray.com/core/app/dns/server" "v2ray.com/core/app/policy" _ "v2ray.com/core/app/policy/manager" "v2ray.com/core/app/proxyman" diff --git a/app/router/router.go b/app/router/router.go index b84175a45..17184a2d0 100644 --- a/app/router/router.go +++ b/app/router/router.go @@ -6,7 +6,6 @@ import ( "context" "v2ray.com/core/app" - "v2ray.com/core/app/dns" "v2ray.com/core/common" "v2ray.com/core/common/net" "v2ray.com/core/proxy" @@ -19,7 +18,6 @@ var ( type Router struct { domainStrategy Config_DomainStrategy rules []Rule - dnsServer dns.Server } func NewRouter(ctx context.Context, config *Config) (*Router, error) { @@ -41,21 +39,15 @@ func NewRouter(ctx context.Context, config *Config) (*Router, error) { } r.rules[idx].Condition = cond } - - r.dnsServer = dns.FromSpace(space) - if r.dnsServer == nil { - return newError("DNS is not found in the space") - } return nil }) return r, nil } type ipResolver struct { - ip []net.Address - domain string - resolved bool - dnsServer dns.Server + ip []net.Address + domain string + resolved bool } func (r *ipResolver) Resolve() []net.Address { @@ -65,7 +57,10 @@ func (r *ipResolver) Resolve() []net.Address { newError("looking for IP for domain: ", r.domain).WriteToLog() r.resolved = true - ips := r.dnsServer.Get(r.domain) + ips, err := net.LookupIP(r.domain) + if err != nil { + newError("failed to get IP address").Base(err).WriteToLog() + } if len(ips) == 0 { return nil } @@ -77,9 +72,7 @@ func (r *ipResolver) Resolve() []net.Address { } func (r *Router) TakeDetour(ctx context.Context) (string, error) { - resolver := &ipResolver{ - dnsServer: r.dnsServer, - } + resolver := &ipResolver{} if r.domainStrategy == Config_IpOnDemand { if dest, ok := proxy.TargetFromContext(ctx); ok && dest.Address.Family().IsDomain() { resolver.domain = dest.Address.Domain() diff --git a/common/net/dns.go b/common/net/dns.go new file mode 100644 index 000000000..52ef74364 --- /dev/null +++ b/common/net/dns.go @@ -0,0 +1,44 @@ +package net + +import ( + "net" + "sync/atomic" + "unsafe" +) + +// IPResolver is the interface to resolve host name to IPs. +type IPResolver interface { + LookupIP(host string) ([]net.IP, error) +} + +type systemIPResolver int + +func (s systemIPResolver) LookupIP(host string) ([]net.IP, error) { + return net.LookupIP(host) +} + +const ( + systemIPResolverInstance = systemIPResolver(0) +) + +// SystemIPResolver returns an IPResolver that resolves IP through underlying system. +func SystemIPResolver() IPResolver { + return systemIPResolverInstance +} + +var ( + ipResolver unsafe.Pointer +) + +func LookupIP(host string) ([]net.IP, error) { + r := (*IPResolver)(atomic.LoadPointer(&ipResolver)) + return (*r).LookupIP(host) +} + +func RegisterIPResolver(resolver IPResolver) { + atomic.StorePointer(&ipResolver, unsafe.Pointer(&resolver)) +} + +func init() { + RegisterIPResolver(systemIPResolverInstance) +} diff --git a/common/net/system.go b/common/net/system.go index 65d7b8bb0..33dc86b6a 100644 --- a/common/net/system.go +++ b/common/net/system.go @@ -13,7 +13,6 @@ var ListenUDP = net.ListenUDP var FileConn = net.FileConn -var LookupIP = net.LookupIP var ParseIP = net.ParseIP var SplitHostPort = net.SplitHostPort diff --git a/main/distro/all/all.go b/main/distro/all/all.go index 800853bb7..85380d04e 100644 --- a/main/distro/all/all.go +++ b/main/distro/all/all.go @@ -3,7 +3,8 @@ package all import ( // The following are necessary as they register handlers in their init functions. _ "v2ray.com/core/app/dispatcher/impl" - _ "v2ray.com/core/app/dns/server" + _ "v2ray.com/core/app/dns" + _ "v2ray.com/core/app/log" _ "v2ray.com/core/app/policy/manager" _ "v2ray.com/core/app/proxyman/inbound" _ "v2ray.com/core/app/proxyman/outbound" diff --git a/proxy/freedom/freedom.go b/proxy/freedom/freedom.go index d69c88220..c7294a527 100644 --- a/proxy/freedom/freedom.go +++ b/proxy/freedom/freedom.go @@ -6,7 +6,6 @@ import ( "context" "v2ray.com/core/app" - "v2ray.com/core/app/dns" "v2ray.com/core/app/policy" "v2ray.com/core/common" "v2ray.com/core/common/buf" @@ -23,7 +22,6 @@ import ( type Handler struct { domainStrategy Config_DomainStrategy timeout uint32 - dns dns.Server destOverride *DestinationOverride policy policy.Policy } @@ -40,12 +38,6 @@ func New(ctx context.Context, config *Config) (*Handler, error) { destOverride: config.DestinationOverride, } space.On(app.SpaceInitializing, func(interface{}) error { - if config.DomainStrategy == Config_USE_IP { - f.dns = dns.FromSpace(space) - if f.dns == nil { - return newError("DNS server is not found in the space") - } - } pm := policy.FromSpace(space) if pm == nil { return newError("Policy not found in space.") @@ -68,7 +60,10 @@ func (h *Handler) resolveIP(ctx context.Context, domain string) net.Address { return ips[dice.Roll(len(ips))] } - ips := h.dns.Get(domain) + ips, err := net.LookupIP(domain) + if err != nil { + newError("failed to get IP address for domain ", domain).Base(err).WriteToLog() + } if len(ips) == 0 { return nil } diff --git a/v2ray.go b/v2ray.go index 6d7bacb5a..f6fcb49ea 100644 --- a/v2ray.go +++ b/v2ray.go @@ -5,11 +5,9 @@ import ( "v2ray.com/core/app" "v2ray.com/core/app/dispatcher" - "v2ray.com/core/app/dns" "v2ray.com/core/app/policy" "v2ray.com/core/app/proxyman" "v2ray.com/core/common" - "v2ray.com/core/common/net" ) // Server is an instance of V2Ray. At any time, there must be at most one Server instance running. @@ -84,19 +82,6 @@ func newSimpleServer(config *Config) (*simpleServer, error) { inboundHandlerManager = o.(proxyman.InboundHandlerManager) } - if dns.FromSpace(space) == nil { - dnsConfig := &dns.Config{ - NameServers: []*net.Endpoint{{ - Address: net.NewIPOrDomain(net.LocalHostDomain), - }}, - } - d, err := app.CreateAppFromConfig(ctx, dnsConfig) - if err != nil { - return nil, err - } - common.Must(space.AddApplication(d)) - } - if disp := dispatcher.FromSpace(space); disp == nil { d, err := app.CreateAppFromConfig(ctx, new(dispatcher.Config)) if err != nil {