add ip match feature for dns

pull/2037/head
weaving118 2019-11-18 23:46:56 +08:00
parent 7f40be7567
commit 101f5d32fa
No known key found for this signature in database
GPG Key ID: 3F65EFFA44207ADD
5 changed files with 268 additions and 45 deletions

View File

@ -4,6 +4,7 @@ import (
fmt "fmt" fmt "fmt"
proto "github.com/golang/protobuf/proto" proto "github.com/golang/protobuf/proto"
math "math" math "math"
router "v2ray.com/core/app/router"
net "v2ray.com/core/common/net" net "v2ray.com/core/common/net"
) )
@ -52,6 +53,7 @@ func (DomainMatchingType) EnumDescriptor() ([]byte, []int) {
type NameServer struct { type NameServer struct {
Address *net.Endpoint `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` Address *net.Endpoint `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"` PrioritizedDomain []*NameServer_PriorityDomain `protobuf:"bytes,2,rep,name=prioritized_domain,json=prioritizedDomain,proto3" json:"prioritized_domain,omitempty"`
Geoip []*router.GeoIP `protobuf:"bytes,3,rep,name=geoip,proto3" json:"geoip,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -96,6 +98,13 @@ func (m *NameServer) GetPrioritizedDomain() []*NameServer_PriorityDomain {
return nil return nil
} }
func (m *NameServer) GetGeoip() []*router.GeoIP {
if m != nil {
return m.Geoip
}
return nil
}
type NameServer_PriorityDomain struct { type NameServer_PriorityDomain struct {
Type DomainMatchingType `protobuf:"varint,1,opt,name=type,proto3,enum=v2ray.core.app.dns.DomainMatchingType" json:"type,omitempty"` Type DomainMatchingType `protobuf:"varint,1,opt,name=type,proto3,enum=v2ray.core.app.dns.DomainMatchingType" json:"type,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"` Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
@ -310,40 +319,42 @@ func init() {
} }
var fileDescriptor_ed5695198e3def8f = []byte{ var fileDescriptor_ed5695198e3def8f = []byte{
// 552 bytes of a gzipped FileDescriptorProto // 583 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0xd1, 0x6e, 0xd3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xdf, 0x6e, 0xd3, 0x3e,
0x14, 0x25, 0x49, 0xdb, 0xad, 0x37, 0x5d, 0x55, 0xfc, 0x30, 0x45, 0x45, 0x82, 0x32, 0xb4, 0x51, 0x18, 0xfd, 0x25, 0xfd, 0xb3, 0xf5, 0xcb, 0x56, 0xf5, 0xe7, 0x8b, 0x29, 0x2a, 0x08, 0xc6, 0xd0,
0x81, 0x70, 0xa4, 0x80, 0x04, 0xec, 0x65, 0x62, 0x5b, 0x11, 0x15, 0x1a, 0x54, 0x1e, 0xe2, 0x01, 0x46, 0x05, 0xc2, 0x91, 0x02, 0x12, 0xb0, 0x9b, 0x89, 0x6d, 0x05, 0x2a, 0x34, 0xa8, 0x3c, 0xc4,
0x90, 0x2a, 0x2f, 0x31, 0x9d, 0x45, 0x63, 0x5b, 0x8e, 0x5b, 0x16, 0x7e, 0x81, 0x1f, 0xe0, 0x1b, 0x05, 0x20, 0x55, 0x5e, 0x62, 0x32, 0x8b, 0xc6, 0xb6, 0x1c, 0x77, 0x2c, 0x3c, 0x09, 0xcf, 0xc0,
0xf8, 0x0d, 0x7e, 0x0c, 0xd5, 0xee, 0x68, 0x61, 0x1d, 0xf0, 0xb2, 0xb7, 0xf8, 0xfa, 0x9c, 0x7b, 0x4b, 0x70, 0xc1, 0x8b, 0xa1, 0xda, 0x19, 0xed, 0xb6, 0x0e, 0xb8, 0xe1, 0xce, 0x7f, 0xce, 0xf9,
0x8e, 0xcf, 0xbd, 0x81, 0x3b, 0xd3, 0x44, 0xd3, 0x12, 0xa7, 0x32, 0x8f, 0x53, 0xa9, 0x59, 0x4c, 0xce, 0xf9, 0x8e, 0xbf, 0x04, 0x6e, 0x9f, 0xc4, 0x9a, 0x96, 0x38, 0x91, 0x79, 0x94, 0x48, 0xcd,
0x95, 0x8a, 0x33, 0x51, 0xc4, 0xa9, 0x14, 0x1f, 0xf9, 0x08, 0x2b, 0x2d, 0x8d, 0x44, 0xe8, 0x1c, 0x22, 0xaa, 0x54, 0x94, 0x8a, 0x22, 0x4a, 0xa4, 0xf8, 0xc8, 0x33, 0xac, 0xb4, 0x34, 0x12, 0xa1,
0xa4, 0x19, 0xa6, 0x4a, 0xe1, 0x4c, 0x14, 0xed, 0xbb, 0x7f, 0x10, 0x53, 0x99, 0xe7, 0x52, 0xc4, 0x33, 0x90, 0x66, 0x98, 0x2a, 0x85, 0x53, 0x51, 0x74, 0xef, 0x5c, 0x20, 0x26, 0x32, 0xcf, 0xa5,
0x82, 0x99, 0x98, 0x66, 0x99, 0x66, 0x45, 0xe1, 0xc8, 0xed, 0xfb, 0x97, 0x03, 0x33, 0x56, 0x18, 0x88, 0x04, 0x33, 0x11, 0x4d, 0x53, 0xcd, 0x8a, 0xc2, 0x91, 0xbb, 0xf7, 0xae, 0x06, 0xa6, 0xac,
0x2e, 0xa8, 0xe1, 0x52, 0x38, 0xf0, 0xd6, 0x57, 0x1f, 0xe0, 0x15, 0xcd, 0xd9, 0x31, 0xd3, 0x53, 0x30, 0x5c, 0x50, 0xc3, 0xa5, 0xa8, 0xc0, 0x5b, 0x0b, 0xec, 0x68, 0x39, 0x31, 0x4c, 0x9f, 0x73,
0xa6, 0xd1, 0x53, 0x58, 0x9b, 0x37, 0x8b, 0xbc, 0x8e, 0xd7, 0x0d, 0x93, 0x5b, 0x78, 0xc9, 0x8a, 0xb4, 0xf1, 0xdd, 0x07, 0x78, 0x45, 0x73, 0x76, 0xc8, 0xf4, 0x09, 0xd3, 0xe8, 0x09, 0x2c, 0x55,
0xeb, 0x84, 0x05, 0x33, 0xb8, 0x27, 0x32, 0x25, 0xb9, 0x30, 0xe4, 0x1c, 0x8f, 0x3e, 0x00, 0x52, 0xa2, 0xa1, 0xb7, 0xee, 0xf5, 0x82, 0xf8, 0x26, 0x9e, 0xb3, 0xec, 0x14, 0xb1, 0x60, 0x06, 0xf7,
0x9a, 0x4b, 0xcd, 0x0d, 0xff, 0xc2, 0xb2, 0x61, 0x26, 0x73, 0xca, 0x45, 0xe4, 0x77, 0x82, 0x6e, 0x45, 0xaa, 0x24, 0x17, 0x86, 0x9c, 0xe1, 0xd1, 0x07, 0x40, 0x4a, 0x73, 0xa9, 0xb9, 0xe1, 0x5f,
0x98, 0x3c, 0xc0, 0x17, 0x1f, 0x84, 0x17, 0xb2, 0x78, 0xe0, 0x88, 0xe5, 0xa1, 0x25, 0x91, 0xeb, 0x58, 0x3a, 0x4a, 0x65, 0x4e, 0xb9, 0x08, 0xfd, 0xf5, 0x5a, 0x2f, 0x88, 0xef, 0xe3, 0xcb, 0x8d,
0x4b, 0x8d, 0x5c, 0xa9, 0x9d, 0x41, 0xf3, 0x77, 0x10, 0xda, 0x85, 0x8a, 0x29, 0x15, 0xb3, 0x3e, 0xe3, 0x99, 0x2c, 0x1e, 0x3a, 0x62, 0xb9, 0x6f, 0x49, 0xe4, 0xff, 0xb9, 0x42, 0xee, 0x08, 0xc5,
0x9b, 0xc9, 0xce, 0x2a, 0x05, 0x87, 0x3c, 0xa2, 0x26, 0x3d, 0xe5, 0x62, 0xf4, 0xa6, 0x54, 0x8c, 0xd0, 0xc8, 0x98, 0xe4, 0x2a, 0xac, 0xd9, 0x82, 0xd7, 0x2f, 0x16, 0x74, 0xbd, 0xe1, 0xe7, 0x4c,
0x58, 0x0e, 0xda, 0x84, 0xda, 0x2f, 0x7f, 0x5e, 0xb7, 0x4e, 0xe6, 0xa7, 0xad, 0x1f, 0x15, 0xa8, 0x0e, 0x86, 0xc4, 0x41, 0xbb, 0x29, 0xb4, 0xcf, 0x17, 0x46, 0xdb, 0x50, 0x37, 0xa5, 0x62, 0xb6,
0x1d, 0xd8, 0x41, 0xa0, 0x1e, 0x84, 0x0b, 0x83, 0xb3, 0x34, 0x82, 0xff, 0x48, 0x63, 0xdf, 0x8f, 0xb7, 0x76, 0xbc, 0xb5, 0xc8, 0x95, 0x43, 0x1e, 0x50, 0x93, 0x1c, 0x73, 0x91, 0xbd, 0x29, 0x15,
0x3c, 0xb2, 0xcc, 0x43, 0x7b, 0x10, 0x0a, 0x9a, 0xb3, 0x61, 0x61, 0xcf, 0x51, 0xd5, 0xb6, 0xb9, 0x23, 0x96, 0x83, 0xd6, 0xa0, 0xf9, 0xab, 0x27, 0xaf, 0xd7, 0x22, 0xd5, 0x6e, 0xe3, 0x47, 0x1d,
0xf9, 0xf7, 0x38, 0x08, 0x88, 0xc5, 0x44, 0xf6, 0xa0, 0xfa, 0x42, 0x16, 0xa6, 0x98, 0x27, 0xb9, 0x9a, 0x7b, 0x36, 0x52, 0xd4, 0x87, 0x60, 0xd6, 0xd4, 0x34, 0xc1, 0xda, 0x5f, 0x24, 0xb8, 0xeb,
0xbd, 0x8a, 0xea, 0x2c, 0x63, 0x8b, 0xeb, 0x09, 0xa3, 0x4b, 0xeb, 0xc3, 0xf1, 0xd0, 0x0d, 0xa8, 0x87, 0x1e, 0x99, 0xe7, 0xa1, 0x1d, 0x08, 0x04, 0xcd, 0xd9, 0xa8, 0xb0, 0xfb, 0xb0, 0x61, 0xcb,
0xa7, 0x63, 0xce, 0x84, 0x19, 0x72, 0x15, 0x05, 0x1d, 0xaf, 0xdb, 0x20, 0xeb, 0xae, 0xd0, 0x57, 0xdc, 0xf8, 0x7d, 0x84, 0x04, 0xc4, 0xec, 0x15, 0x77, 0xa0, 0xf1, 0x42, 0x16, 0xa6, 0xa8, 0xd2,
0xa8, 0x0f, 0x8d, 0xc2, 0x50, 0xc3, 0xd3, 0xe1, 0xa9, 0x15, 0xa9, 0x58, 0x91, 0x9d, 0x7f, 0x88, 0xdf, 0x5c, 0x44, 0x75, 0x96, 0xb1, 0xc5, 0xf5, 0x85, 0xd1, 0xa5, 0xf5, 0xe1, 0x78, 0xe8, 0x1a,
0x1c, 0x51, 0xa5, 0xb8, 0x18, 0x91, 0xd0, 0x71, 0x9d, 0x4e, 0x0b, 0x02, 0x43, 0x47, 0x51, 0xcd, 0xb4, 0x92, 0x31, 0x67, 0xc2, 0x8c, 0x6c, 0xe2, 0x5e, 0x6f, 0x85, 0x2c, 0xbb, 0x83, 0x81, 0x42,
0x06, 0x3a, 0xfb, 0x6c, 0xbf, 0x07, 0x58, 0x58, 0x9a, 0xdd, 0x7f, 0x62, 0xa5, 0x1d, 0x57, 0x9d, 0x03, 0x58, 0x29, 0x0c, 0x35, 0x3c, 0x19, 0x1d, 0x5b, 0x91, 0xba, 0x15, 0xd9, 0xfa, 0x83, 0xc8,
0xcc, 0x3e, 0xd1, 0x63, 0xa8, 0x4e, 0xe9, 0x78, 0xc2, 0xec, 0x10, 0xc2, 0xe4, 0xf6, 0x25, 0xe1, 0x01, 0x55, 0x8a, 0x8b, 0x8c, 0x04, 0x8e, 0xeb, 0x74, 0x3a, 0x50, 0x33, 0x34, 0x0b, 0x9b, 0x36,
0xf6, 0x07, 0xaf, 0xf5, 0x7c, 0x31, 0x1c, 0x7e, 0xd7, 0x7f, 0xe2, 0xb5, 0xbf, 0x79, 0x10, 0x2e, 0xd0, 0xe9, 0xb2, 0xfb, 0x1e, 0x60, 0x66, 0x69, 0x7a, 0xff, 0x89, 0x95, 0xf6, 0xb9, 0x5a, 0x64,
0x79, 0xb9, 0x8a, 0x75, 0x40, 0x4d, 0xf0, 0x6d, 0x66, 0x41, 0xb7, 0x41, 0x7c, 0xae, 0xd0, 0x36, 0xba, 0x44, 0x8f, 0xa0, 0x71, 0x42, 0xc7, 0x13, 0x66, 0x1f, 0x21, 0x88, 0x6f, 0x5d, 0x11, 0xee,
0x34, 0x95, 0x96, 0x67, 0x7c, 0xb1, 0xde, 0x15, 0x8b, 0xdf, 0x98, 0x57, 0x9d, 0xc0, 0xbd, 0x1e, 0x60, 0xf8, 0x5a, 0x57, 0xc3, 0xe4, 0xf0, 0xdb, 0xfe, 0x63, 0xaf, 0xfb, 0xd5, 0x83, 0x60, 0xce,
0xa0, 0x8b, 0x52, 0x68, 0x1d, 0x2a, 0xcf, 0x27, 0xe3, 0x71, 0xeb, 0x1a, 0xda, 0x80, 0xfa, 0xf1, 0xcb, 0xbf, 0x18, 0x07, 0xd4, 0x06, 0xbf, 0x9a, 0xd2, 0x15, 0xe2, 0x73, 0x85, 0x36, 0xa1, 0xad,
0xe4, 0xc4, 0x75, 0x68, 0x79, 0x28, 0x84, 0xb5, 0x97, 0xac, 0xfc, 0x2c, 0x75, 0xd6, 0xf2, 0x51, 0xb4, 0x3c, 0xe5, 0xb3, 0x4f, 0xa2, 0x6e, 0xf1, 0xab, 0xd5, 0xa9, 0x13, 0xb8, 0xdb, 0x07, 0x74,
0x1d, 0xaa, 0x84, 0x8d, 0xd8, 0x59, 0x2b, 0xd8, 0x7f, 0x04, 0x9b, 0xa9, 0xcc, 0x57, 0x3c, 0x64, 0x59, 0x0a, 0x2d, 0x43, 0xfd, 0xd9, 0x64, 0x3c, 0xee, 0xfc, 0x87, 0x56, 0xa1, 0x75, 0x38, 0x39,
0xe0, 0xbd, 0x0b, 0x32, 0x51, 0x7c, 0xf7, 0xd1, 0xdb, 0x84, 0xd0, 0x12, 0x1f, 0xcc, 0xee, 0x9e, 0x72, 0x15, 0x3a, 0x1e, 0x0a, 0x60, 0xe9, 0x25, 0x2b, 0x3f, 0x4b, 0x9d, 0x76, 0x7c, 0xd4, 0x82,
0x29, 0x85, 0x0f, 0x45, 0x71, 0x52, 0xb3, 0xff, 0xf5, 0xc3, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x06, 0x61, 0x19, 0x3b, 0xed, 0xd4, 0x76, 0x1f, 0xc2, 0x5a, 0x22, 0xf3, 0x05, 0x8d, 0x0c, 0xbd,
0x15, 0xed, 0x7b, 0x41, 0x68, 0x04, 0x00, 0x00, 0x77, 0xb5, 0x54, 0x14, 0xdf, 0x7c, 0xf4, 0x36, 0x26, 0xb4, 0xc4, 0x7b, 0xd3, 0xbb, 0xa7, 0x4a,
0xe1, 0x7d, 0x51, 0x1c, 0x35, 0xed, 0xbf, 0xe0, 0xc1, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4c,
0x2a, 0x66, 0x8a, 0xc4, 0x04, 0x00, 0x00,
} }

View File

@ -8,6 +8,7 @@ option java_multiple_files = true;
import "v2ray.com/core/common/net/address.proto"; import "v2ray.com/core/common/net/address.proto";
import "v2ray.com/core/common/net/destination.proto"; import "v2ray.com/core/common/net/destination.proto";
import "v2ray.com/core/app/router/config.proto";
message NameServer { message NameServer {
v2ray.core.common.net.Endpoint address = 1; v2ray.core.common.net.Endpoint address = 1;
@ -18,6 +19,7 @@ message NameServer {
} }
repeated PriorityDomain prioritized_domain = 2; repeated PriorityDomain prioritized_domain = 2;
repeated v2ray.core.app.router.GeoIP geoip = 3;
} }
enum DomainMatchingType { enum DomainMatchingType {

View File

@ -10,6 +10,7 @@ import (
"time" "time"
"v2ray.com/core" "v2ray.com/core"
"v2ray.com/core/app/router"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/session" "v2ray.com/core/common/session"
@ -28,9 +29,33 @@ type Server struct {
clientIP net.IP clientIP net.IP
domainMatcher strmatcher.IndexMatcher domainMatcher strmatcher.IndexMatcher
domainIndexMap map[uint32]uint32 domainIndexMap map[uint32]uint32
ipIndexMap map[uint32]*MultiGeoIPMatcher
tag string tag string
} }
// MultiGeoIPMatcher for match
type MultiGeoIPMatcher struct {
matchers []*router.GeoIPMatcher
}
// Match for
func (c *MultiGeoIPMatcher) Match(ip net.IP) bool {
for _, matcher := range c.matchers {
if matcher.Match(ip) {
return true
}
}
return false
}
// HasMatcher f
func (c *MultiGeoIPMatcher) HasMatcher() bool {
if len(c.matchers) > 0 {
return true
}
return false
}
func generateRandomTag() string { func generateRandomTag() string {
id := uuid.New() id := uuid.New()
return "v2ray.system." + id.String() return "v2ray.system." + id.String()
@ -87,9 +112,12 @@ func New(ctx context.Context, config *Config) (*Server, error) {
addNameServer(destPB) addNameServer(destPB)
} }
var geoIPMatcherContainer router.GeoIPMatcherContainer
if len(config.NameServer) > 0 { if len(config.NameServer) > 0 {
domainMatcher := &strmatcher.MatcherGroup{} domainMatcher := &strmatcher.MatcherGroup{}
domainIndexMap := make(map[uint32]uint32) domainIndexMap := make(map[uint32]uint32)
ipIndexMap := make(map[uint32]*MultiGeoIPMatcher)
for _, ns := range config.NameServer { for _, ns := range config.NameServer {
idx := addNameServer(ns.Address) idx := addNameServer(ns.Address)
@ -102,10 +130,23 @@ func New(ctx context.Context, config *Config) (*Server, error) {
midx := domainMatcher.Add(matcher) midx := domainMatcher.Add(matcher)
domainIndexMap[midx] = uint32(idx) domainIndexMap[midx] = uint32(idx)
} }
var matchers []*router.GeoIPMatcher
for _, geoip := range ns.Geoip {
matcher, err := geoIPMatcherContainer.Add(geoip)
if err != nil {
return nil, newError("failed to create ip matcher").Base(err).AtWarning()
}
matchers = append(matchers, matcher)
}
matcher := &MultiGeoIPMatcher{matchers: matchers}
ipIndexMap[uint32(idx)] = matcher
} }
server.domainMatcher = domainMatcher server.domainMatcher = domainMatcher
server.domainIndexMap = domainIndexMap server.domainIndexMap = domainIndexMap
server.ipIndexMap = ipIndexMap
} }
if len(server.clients) == 0 { if len(server.clients) == 0 {
@ -135,7 +176,40 @@ func (s *Server) IsOwnLink(ctx context.Context) bool {
return inbound != nil && inbound.Tag == s.tag return inbound != nil && inbound.Tag == s.tag
} }
func (s *Server) queryIPTimeout(client Client, domain string, option IPOption) ([]net.IP, error) { // Match check dns ip match geoip
func (s *Server) Match(idx uint32, client Client, domain string, ips []net.IP) ([]net.IP, error) {
if len(ips) == 0 {
newError("domain ", domain, " has empty response at server ", client.Name(), " idx:", idx).AtDebug().WriteToLog()
return nil, context.Canceled
}
matcher, exist := s.ipIndexMap[idx]
if exist == false {
newError("domain ", domain, " server not in ipIndexMap: ", client.Name(), " idx:", idx, " just return").AtDebug().WriteToLog()
return ips, nil
}
if matcher.HasMatcher() == false {
newError("domain ", domain, "server has not valid matcher: ", client.Name(), " idx:", idx, " just return").AtDebug().WriteToLog()
return ips, nil
}
newIps := []net.IP{}
for _, ip := range ips {
if matcher.Match(ip) {
newIps = append(newIps, ip)
newError("domain ", domain, " ip ", ip, " is match at server ", client.Name(), " idx:", idx).AtDebug().WriteToLog()
} else {
newError("domain ", domain, " ip ", ip, " is not match at server ", client.Name(), " idx:", idx).AtDebug().WriteToLog()
}
}
if len(newIps) == 0 {
return nil, context.Canceled
}
return newIps, nil
}
func (s *Server) queryIPTimeout(idx uint32, client Client, domain string, option IPOption) ([]net.IP, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*4) ctx, cancel := context.WithTimeout(context.Background(), time.Second*4)
if len(s.tag) > 0 { if len(s.tag) > 0 {
ctx = session.ContextWithInbound(ctx, &session.Inbound{ ctx = session.ContextWithInbound(ctx, &session.Inbound{
@ -143,6 +217,7 @@ func (s *Server) queryIPTimeout(client Client, domain string, option IPOption) (
}) })
} }
ips, err := client.QueryIP(ctx, domain, option) ips, err := client.QueryIP(ctx, domain, option)
ips, err = s.Match(idx, client, domain, ips)
cancel() cancel()
return ips, err return ips, err
} }
@ -221,8 +296,8 @@ func (s *Server) lookupIPInternal(domain string, option IPOption) ([]net.IP, err
idx := s.domainMatcher.Match(domain) idx := s.domainMatcher.Match(domain)
if idx > 0 { if idx > 0 {
ns := s.clients[s.domainIndexMap[idx]] ns := s.clients[s.domainIndexMap[idx]]
newError("querying domain ", domain, " at ", ns.Name()).WriteToLog() newError("domain matched, direct lookup ip for domain ", domain, " at ", ns.Name()).WriteToLog()
ips, err := s.queryIPTimeout(ns, domain, option) ips, err := s.queryIPTimeout(s.domainIndexMap[idx], ns, domain, option)
if len(ips) > 0 { if len(ips) > 0 {
return ips, nil return ips, nil
} }
@ -236,11 +311,15 @@ func (s *Server) lookupIPInternal(domain string, option IPOption) ([]net.IP, err
} }
} }
for _, client := range s.clients { for idx, client := range s.clients {
ips, err := s.queryIPTimeout(client, domain, option) newError("try to lookup ip for domain ", domain, " at server ", client.Name(), " idx:", idx).AtDebug().WriteToLog()
ips, err := s.queryIPTimeout(uint32(idx), client, domain, option)
if len(ips) > 0 { if len(ips) > 0 {
newError("lookup ip for domain ", domain, " success: ", ips, " at server ", client.Name(), " idx:", idx).AtDebug().WriteToLog()
return ips, nil return ips, nil
} }
if err != nil { if err != nil {
newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog() newError("failed to lookup ip for domain ", domain, " at server ", client.Name()).Base(err).WriteToLog()
lastErr = err lastErr = err

View File

@ -13,6 +13,7 @@ import (
"v2ray.com/core/app/policy" "v2ray.com/core/app/policy"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
_ "v2ray.com/core/app/proxyman/outbound" _ "v2ray.com/core/app/proxyman/outbound"
"v2ray.com/core/app/router"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/serial" "v2ray.com/core/common/serial"
@ -426,3 +427,124 @@ func TestStaticHostDomain(t *testing.T) {
dnsServer.Shutdown() dnsServer.Shutdown()
} }
func TestIPMatch(t *testing.T) {
port := udp.PickPort()
dnsServer := dns.Server{
Addr: "127.0.0.1:" + port.String(),
Net: "udp",
Handler: &staticHandler{},
UDPSize: 1200,
}
go dnsServer.ListenAndServe()
time.Sleep(time.Second)
config := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&Config{
NameServers: []*net.Endpoint{
{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: 9999, /* unreachable */
},
},
NameServer: []*NameServer{
// private dns, not match
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
Geoip: []*router.GeoIP{
{
CountryCode: "local",
Cidr: []*router.CIDR{
{
// inner ip, will not match
Ip: []byte{192, 168, 11, 1},
Prefix: 32,
},
},
},
},
},
// second dns, match ip
{
Address: &net.Endpoint{
Network: net.Network_UDP,
Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
},
Geoip: []*router.GeoIP{
{
CountryCode: "test",
Cidr: []*router.CIDR{
{
Ip: []byte{8, 8, 8, 8},
Prefix: 32,
},
},
},
{
CountryCode: "test",
Cidr: []*router.CIDR{
{
Ip: []byte{8, 8, 8, 4},
Prefix: 32,
},
},
},
},
},
},
}),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
v, err := core.New(config)
common.Must(err)
client := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client)
startTime := time.Now()
{
ips, err := client.LookupIP("google.com")
if err != nil {
t.Fatal("unexpected error: ", err)
}
if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" {
t.Fatal(r)
}
}
endTime := time.Now()
if startTime.After(endTime.Add(time.Second * 2)) {
t.Error("DNS query doesn't finish in 2 seconds.")
}
}

View File

@ -14,6 +14,7 @@ type NameServerConfig struct {
Address *Address Address *Address
Port uint16 Port uint16
Domains []string Domains []string
IP StringList
} }
func (c *NameServerConfig) UnmarshalJSON(data []byte) error { func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
@ -28,11 +29,13 @@ func (c *NameServerConfig) UnmarshalJSON(data []byte) error {
Address *Address `json:"address"` Address *Address `json:"address"`
Port uint16 `json:"port"` Port uint16 `json:"port"`
Domains []string `json:"domains"` Domains []string `json:"domains"`
IP StringList `json:"ip"`
} }
if err := json.Unmarshal(data, &advanced); err == nil { if err := json.Unmarshal(data, &advanced); err == nil {
c.Address = advanced.Address c.Address = advanced.Address
c.Port = advanced.Port c.Port = advanced.Port
c.Domains = advanced.Domains c.Domains = advanced.Domains
c.IP = advanced.IP
return nil return nil
} }
@ -75,6 +78,11 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
} }
} }
geoipList, err := toCidrList(c.IP)
if err != nil {
return nil, newError("invalid ip rule: ", c.IP).Base(err)
}
return &dns.NameServer{ return &dns.NameServer{
Address: &net.Endpoint{ Address: &net.Endpoint{
Network: net.Network_UDP, Network: net.Network_UDP,
@ -82,6 +90,7 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
Port: uint32(c.Port), Port: uint32(c.Port),
}, },
PrioritizedDomain: domains, PrioritizedDomain: domains,
Geoip: geoipList,
}, nil }, nil
} }