Browse Source

added new API to support fakedns + other sniffer and IPv4 IPv6 dual stack fake dns

Shelikhoo 4 years ago
parent
commit
c6064452f0
4 changed files with 268 additions and 17 deletions
  1. 104 0
      app/dns/fakedns/fake.go
  2. 83 17
      app/dns/fakedns/fakedns.pb.go
  3. 4 0
      app/dns/fakedns/fakedns.proto
  4. 77 0
      app/dns/fakedns/fakedns_test.go

+ 104 - 0
app/dns/fakedns/fake.go

@@ -23,6 +23,18 @@ type Holder struct {
 	config *FakeDnsPool
 }
 
+func (fkdns *Holder) IsIPInIPPool(ip net.Address) bool {
+	return fkdns.ipRange.Contains(ip.IP())
+}
+
+func (fkdns *Holder) GetFakeIPForDomain3(domain string, IPv4, IPv6 bool) []net.Address {
+	isIPv6 := fkdns.ipRange.IP.To4() == nil
+	if (isIPv6 && IPv6) || (!isIPv6 && IPv4) {
+		return fkdns.GetFakeIPForDomain(domain)
+	}
+	return []net.Address{}
+}
+
 func (*Holder) Type() interface{} {
 	return (*dns.FakeDNSEngine)(nil)
 }
@@ -120,6 +132,89 @@ func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
 	return ""
 }
 
+type HolderMulti struct {
+	holders []*Holder
+
+	config *FakeDnsPoolMulti
+}
+
+func (h *HolderMulti) IsIPInIPPool(ip net.Address) bool {
+	for _, v := range h.holders {
+		if v.IsIPInIPPool(ip) {
+			return true
+		}
+	}
+	return false
+}
+
+func (h *HolderMulti) GetFakeIPForDomain3(domain string, IPv4, IPv6 bool) []net.Address {
+	var ret []net.Address
+	for _, v := range h.holders {
+		ret = append(ret, v.GetFakeIPForDomain3(domain, IPv4, IPv6)...)
+	}
+	return ret
+}
+
+func (h *HolderMulti) GetFakeIPForDomain(domain string) []net.Address {
+	var ret []net.Address
+	for _, v := range h.holders {
+		ret = append(ret, v.GetFakeIPForDomain(domain)...)
+	}
+	return ret
+}
+
+func (h *HolderMulti) GetDomainFromFakeDNS(ip net.Address) string {
+	for _, v := range h.holders {
+		if domain := v.GetDomainFromFakeDNS(ip); domain != "" {
+			return domain
+		}
+	}
+	return ""
+}
+
+func (h *HolderMulti) Type() interface{} {
+	return (*dns.FakeDNSEngine)(nil)
+}
+
+func (h *HolderMulti) Start() error {
+	for _, v := range h.holders {
+		err := v.Start()
+		if err != nil {
+			return newError("Cannot start all fake dns pools").Base(err)
+		}
+	}
+	return nil
+}
+
+func (h *HolderMulti) Close() error {
+	for _, v := range h.holders {
+		err := v.Start()
+		if err != nil {
+			return newError("Cannot close all fake dns pools").Base(err)
+		}
+	}
+	return nil
+}
+
+func (h *HolderMulti) createHolderGroups() error {
+	for _, v := range h.config.Pools {
+		holder, err := NewFakeDNSHolderConfigOnly(v)
+		if err != nil {
+			return err
+		}
+		h.holders = append(h.holders, holder)
+	}
+	return nil
+}
+
+func NewFakeDNSHolderMulti(conf *FakeDnsPoolMulti) (*HolderMulti, error) {
+	holderMulti := &HolderMulti{nil, conf}
+	if err := holderMulti.createHolderGroups(); err != nil {
+		return nil, err
+	}
+	return holderMulti, nil
+}
+
 func init() {
 	common.Must(common.RegisterConfig((*FakeDnsPool)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
 		var f *Holder
@@ -129,4 +224,13 @@ func init() {
 		}
 		return f, nil
 	}))
+
+	common.Must(common.RegisterConfig((*FakeDnsPoolMulti)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		var f *HolderMulti
+		var err error
+		if f, err = NewFakeDNSHolderMulti(config.(*FakeDnsPoolMulti)); err != nil {
+			return nil, err
+		}
+		return f, nil
+	}))
 }

+ 83 - 17
app/dns/fakedns/fakedns.pb.go

@@ -75,6 +75,53 @@ func (x *FakeDnsPool) GetLruSize() int64 {
 	return 0
 }
 
+type FakeDnsPoolMulti struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Pools []*FakeDnsPool `protobuf:"bytes,1,rep,name=pools,proto3" json:"pools,omitempty"`
+}
+
+func (x *FakeDnsPoolMulti) Reset() {
+	*x = FakeDnsPoolMulti{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FakeDnsPoolMulti) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FakeDnsPoolMulti) ProtoMessage() {}
+
+func (x *FakeDnsPoolMulti) ProtoReflect() protoreflect.Message {
+	mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FakeDnsPoolMulti.ProtoReflect.Descriptor instead.
+func (*FakeDnsPoolMulti) Descriptor() ([]byte, []int) {
+	return file_app_dns_fakedns_fakedns_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *FakeDnsPoolMulti) GetPools() []*FakeDnsPool {
+	if x != nil {
+		return x.Pools
+	}
+	return nil
+}
+
 var File_app_dns_fakedns_fakedns_proto protoreflect.FileDescriptor
 
 var file_app_dns_fakedns_fakedns_proto_rawDesc = []byte{
@@ -85,15 +132,20 @@ var file_app_dns_fakedns_fakedns_proto_rawDesc = []byte{
 	0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x70,
 	0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x70, 0x50,
 	0x6f, 0x6f, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x6f, 0x0a,
-	0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
-	0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x50,
-	0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32,
-	0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76,
-	0x34, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
-	0x73, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41,
-	0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x62, 0x06,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x51, 0x0a,
+	0x10, 0x46, 0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x4d, 0x75, 0x6c, 0x74,
+	0x69, 0x12, 0x3d, 0x0a, 0x05, 0x70, 0x6f, 0x6f, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x27, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
+	0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x2e, 0x46, 0x61,
+	0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x05, 0x70, 0x6f, 0x6f, 0x6c, 0x73,
+	0x42, 0x6f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
+	0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64,
+	0x6e, 0x73, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+	0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72,
+	0x65, 0x2f, 0x76, 0x34, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b,
+	0x65, 0x64, 0x6e, 0x73, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72,
+	0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x64, 0x6e,
+	0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -108,16 +160,18 @@ func file_app_dns_fakedns_fakedns_proto_rawDescGZIP() []byte {
 	return file_app_dns_fakedns_fakedns_proto_rawDescData
 }
 
-var file_app_dns_fakedns_fakedns_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_app_dns_fakedns_fakedns_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
 var file_app_dns_fakedns_fakedns_proto_goTypes = []interface{}{
-	(*FakeDnsPool)(nil), // 0: v2ray.core.app.dns.fakedns.FakeDnsPool
+	(*FakeDnsPool)(nil),      // 0: v2ray.core.app.dns.fakedns.FakeDnsPool
+	(*FakeDnsPoolMulti)(nil), // 1: v2ray.core.app.dns.fakedns.FakeDnsPoolMulti
 }
 var file_app_dns_fakedns_fakedns_proto_depIdxs = []int32{
-	0, // [0:0] is the sub-list for method output_type
-	0, // [0:0] is the sub-list for method input_type
-	0, // [0:0] is the sub-list for extension type_name
-	0, // [0:0] is the sub-list for extension extendee
-	0, // [0:0] is the sub-list for field type_name
+	0, // 0: v2ray.core.app.dns.fakedns.FakeDnsPoolMulti.pools:type_name -> v2ray.core.app.dns.fakedns.FakeDnsPool
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
 }
 
 func init() { file_app_dns_fakedns_fakedns_proto_init() }
@@ -138,6 +192,18 @@ func file_app_dns_fakedns_fakedns_proto_init() {
 				return nil
 			}
 		}
+		file_app_dns_fakedns_fakedns_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FakeDnsPoolMulti); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
@@ -145,7 +211,7 @@ func file_app_dns_fakedns_fakedns_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_app_dns_fakedns_fakedns_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   1,
+			NumMessages:   2,
 			NumExtensions: 0,
 			NumServices:   0,
 		},

+ 4 - 0
app/dns/fakedns/fakedns.proto

@@ -10,3 +10,7 @@ message FakeDnsPool{
   string ip_pool = 1; //CIDR of IP pool used as fake DNS IP
   int64  lruSize = 2; //Size of Pool for remembering relationship between domain name and IP address
 }
+
+message FakeDnsPoolMulti{
+  repeated FakeDnsPool pools = 1;
+}

+ 77 - 0
app/dns/fakedns/fakedns_test.go

@@ -3,6 +3,8 @@ package fakedns
 import (
 	"testing"
 
+	gonet "net"
+
 	"github.com/stretchr/testify/assert"
 
 	"github.com/v2fly/v2ray-core/v4/common"
@@ -113,3 +115,78 @@ func TestFakeDnsHolderCreateMappingAndRollOver(t *testing.T) {
 		}
 	}
 }
+
+func TestFakeDNSMulti(t *testing.T) {
+	fakeMulti, err := NewFakeDNSHolderMulti(&FakeDnsPoolMulti{
+		Pools: []*FakeDnsPool{&FakeDnsPool{
+			IpPool:  "240.0.0.0/12",
+			LruSize: 256,
+		}, &FakeDnsPool{
+			IpPool:  "fddd:c5b4:ff5f:f4f0::/64",
+			LruSize: 256,
+		}},
+	},
+	)
+
+	err = fakeMulti.Start()
+
+	common.Must(err)
+
+	assert.Nil(t, err, "Should not throw error")
+	_ = fakeMulti
+
+	t.Run("checkInRange", func(t *testing.T) {
+		t.Run("ipv4", func(t *testing.T) {
+			inPool := fakeMulti.IsIPInIPPool(net.IPAddress([]byte{240, 0, 0, 5}))
+			assert.True(t, inPool)
+		})
+		t.Run("ipv6", func(t *testing.T) {
+			ip, err := gonet.ResolveIPAddr("ip", "fddd:c5b4:ff5f:f4f0::5")
+			assert.Nil(t, err)
+			inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
+			assert.True(t, inPool)
+		})
+		t.Run("ipv4_inverse", func(t *testing.T) {
+			inPool := fakeMulti.IsIPInIPPool(net.IPAddress([]byte{241, 0, 0, 5}))
+			assert.False(t, inPool)
+		})
+		t.Run("ipv6_inverse", func(t *testing.T) {
+			ip, err := gonet.ResolveIPAddr("ip", "fcdd:c5b4:ff5f:f4f0::5")
+			assert.Nil(t, err)
+			inPool := fakeMulti.IsIPInIPPool(net.IPAddress(ip.IP))
+			assert.False(t, inPool)
+		})
+	})
+
+	t.Run("allocateTwoAddressForTwoPool", func(t *testing.T) {
+		address := fakeMulti.GetFakeIPForDomain("fakednstest.v2fly.org")
+		assert.Len(t, address, 2, "should be 2 address one for each pool")
+		t.Run("eachOfThemShouldResolve:0", func(t *testing.T) {
+			domain := fakeMulti.GetDomainFromFakeDNS(address[0])
+			assert.Equal(t, "fakednstest.v2fly.org", domain)
+		})
+		t.Run("eachOfThemShouldResolve:1", func(t *testing.T) {
+			domain := fakeMulti.GetDomainFromFakeDNS(address[1])
+			assert.Equal(t, "fakednstest.v2fly.org", domain)
+		})
+	})
+
+	t.Run("understandIPTypeSelector", func(t *testing.T) {
+		t.Run("ipv4", func(t *testing.T) {
+			address := fakeMulti.GetFakeIPForDomain3("fakednstestipv4.v2fly.org", true, false)
+			assert.Len(t, address, 1, "should be 1 address")
+			assert.True(t, address[0].Family().IsIPv4())
+		})
+		t.Run("ipv6", func(t *testing.T) {
+			address := fakeMulti.GetFakeIPForDomain3("fakednstestipv6.v2fly.org", false, true)
+			assert.Len(t, address, 1, "should be 1 address")
+			assert.True(t, address[0].Family().IsIPv6())
+		})
+		t.Run("ipv46", func(t *testing.T) {
+			address := fakeMulti.GetFakeIPForDomain3("fakednstestipv46.v2fly.org", true, true)
+			assert.Len(t, address, 2, "should be 2 address")
+			assert.True(t, address[0].Family().IsIPv4())
+			assert.True(t, address[1].Family().IsIPv6())
+		})
+	})
+}