github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/dns/fakedns_test.go (about) 1 package dns_test 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/google/go-cmp/cmp" 8 "github.com/miekg/dns" 9 "google.golang.org/protobuf/types/known/anypb" 10 11 core "github.com/v2fly/v2ray-core/v5" 12 "github.com/v2fly/v2ray-core/v5/app/dispatcher" 13 . "github.com/v2fly/v2ray-core/v5/app/dns" 14 "github.com/v2fly/v2ray-core/v5/app/dns/fakedns" 15 "github.com/v2fly/v2ray-core/v5/app/policy" 16 "github.com/v2fly/v2ray-core/v5/app/proxyman" 17 "github.com/v2fly/v2ray-core/v5/common" 18 "github.com/v2fly/v2ray-core/v5/common/net" 19 "github.com/v2fly/v2ray-core/v5/common/serial" 20 feature_dns "github.com/v2fly/v2ray-core/v5/features/dns" 21 "github.com/v2fly/v2ray-core/v5/proxy/freedom" 22 "github.com/v2fly/v2ray-core/v5/testing/servers/udp" 23 ) 24 25 func TestFakeDNS(t *testing.T) { 26 port := udp.PickPort() 27 28 dnsServer := dns.Server{ 29 Addr: "127.0.0.1:" + port.String(), 30 Net: "udp", 31 Handler: &staticHandler{}, 32 UDPSize: 1200, 33 } 34 35 go dnsServer.ListenAndServe() 36 time.Sleep(time.Second) 37 38 config := &core.Config{ 39 App: []*anypb.Any{ 40 serial.ToTypedMessage(&Config{ 41 NameServer: []*NameServer{ 42 { // "fakedns" 43 Address: &net.Endpoint{ 44 Network: net.Network_UDP, 45 Address: &net.IPOrDomain{ 46 Address: &net.IPOrDomain_Domain{ 47 Domain: "fakedns", 48 }, 49 }, 50 Port: uint32(53), 51 }, 52 }, 53 { // { "address": "127.0.0.1", "port": "<port>", "domains": ["domain:google.com"], "fakedns": "198.19.0.0/16", "fallbackStrategy": "disabled" } 54 Address: &net.Endpoint{ 55 Network: net.Network_UDP, 56 Address: &net.IPOrDomain{ 57 Address: &net.IPOrDomain_Ip{ 58 Ip: []byte{127, 0, 0, 1}, 59 }, 60 }, 61 Port: uint32(port), 62 }, 63 PrioritizedDomain: []*NameServer_PriorityDomain{ 64 {Type: DomainMatchingType_Subdomain, Domain: "google.com"}, 65 }, 66 FakeDns: &fakedns.FakeDnsPoolMulti{ 67 Pools: []*fakedns.FakeDnsPool{ 68 {IpPool: "198.19.0.0/16", LruSize: 256}, 69 }, 70 }, 71 FallbackStrategy: FallbackStrategy_Disabled.Enum(), 72 }, 73 }, 74 FakeDns: &fakedns.FakeDnsPoolMulti{ // "fakedns": "198.18.0.0/16" 75 Pools: []*fakedns.FakeDnsPool{ 76 {IpPool: "198.18.0.0/16", LruSize: 256}, 77 }, 78 }, 79 }), 80 serial.ToTypedMessage(&dispatcher.Config{}), 81 serial.ToTypedMessage(&proxyman.OutboundConfig{}), 82 serial.ToTypedMessage(&policy.Config{}), 83 }, 84 Outbound: []*core.OutboundHandlerConfig{ 85 { 86 ProxySettings: serial.ToTypedMessage(&freedom.Config{}), 87 }, 88 }, 89 } 90 91 v, err := core.New(config) 92 common.Must(err) 93 common.Must(v.Start()) 94 95 dnsClient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client) 96 fakeClient := dnsClient.(feature_dns.ClientWithFakeDNS).AsFakeDNSClient() 97 98 var fakeIPForFacebook net.IP 99 var fakeIPForGoogle net.IP 100 101 { // Lookup facebook.com with Fake Client will return 198.18.0.0/16 (global fake pool) 102 ips, err := fakeClient.LookupIP("facebook.com") 103 if err != nil { 104 t.Fatal("unexpected error: ", err) 105 } 106 for _, ip := range ips { 107 if !(&net.IPNet{IP: net.IP{198, 18, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip) { 108 t.Fatal("Lookup facebook.com with fake client not in global pool 198.18.0.0/16") 109 } 110 } 111 fakeIPForFacebook = ips[0] 112 } 113 { // Lookup facebook.com with Normal Client with return empty record (because UDP server matching "domain:google.com" are configured with fallback disabled) 114 _, err := dnsClient.LookupIP("facebook.com") 115 if err != feature_dns.ErrEmptyResponse { 116 t.Fatal("Lookup facebook.com with normal client not returning empty response") 117 } 118 } 119 { // Lookup google.com with Fake Client will return 198.19.0.0/16 (local fake pool) 120 ips, err := fakeClient.LookupIP("google.com") 121 if err != nil { 122 t.Fatal("unexpected error: ", err) 123 } 124 for _, ip := range ips { 125 if !(&net.IPNet{IP: net.IP{198, 19, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip) { 126 t.Fatal("Lookup google.com with fake client not in global pool 198.19.0.0/16") 127 } 128 } 129 fakeIPForGoogle = ips[0] 130 } 131 { // Lookup google.com with Normal Client will return 8.8.8.8 132 ips, err := dnsClient.LookupIP("google.com") 133 if err != nil { 134 t.Fatal("unexpected error: ", err) 135 } 136 if r := cmp.Diff(ips, []net.IP{{8, 8, 8, 8}}); r != "" { 137 t.Fatal("Lookup google.com with normal client not returning 8.8.8.8") 138 } 139 } 140 141 fakeEngine := dnsClient.(feature_dns.ClientWithFakeDNS).AsFakeDNSEngine().(feature_dns.FakeDNSEngineRev0) 142 { 143 if !fakeEngine.IsIPInIPPool(net.IPAddress(fakeIPForFacebook)) { 144 t.Fatal("Fake IP of domain facebook.com not in FakeDNSEngine's pool.") 145 } 146 if !fakeEngine.IsIPInIPPool(net.IPAddress(fakeIPForGoogle)) { 147 t.Fatal("Fake IP of domain google.com not in FakeDNSEngine's pool.") 148 } 149 } 150 { 151 if domain := fakeEngine.GetDomainFromFakeDNS(net.IPAddress(fakeIPForFacebook)); domain != "facebook.com" { 152 t.Fatal("Recover fake IP to get domain facebook.com failed.") 153 } 154 if domain := fakeEngine.GetDomainFromFakeDNS(net.IPAddress(fakeIPForGoogle)); domain != "google.com" { 155 t.Fatal("Recover fake IP to get domain google.com failed.") 156 } 157 } 158 { 159 ips := fakeEngine.GetFakeIPForDomain("api.google.com") 160 for _, ip := range ips { 161 if !(&net.IPNet{IP: net.IP{198, 19, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip.IP()) { 162 t.Fatal("Fake IP for api.google.com not in local pool 198.19.0.0/16") 163 } 164 } 165 } 166 { 167 ips := fakeEngine.GetFakeIPForDomain3("v2fly.org", true, false) 168 for _, ip := range ips { 169 if !(&net.IPNet{IP: net.IP{198, 18, 0, 0}, Mask: net.CIDRMask(16, 8*net.IPv4len)}).Contains(ip.IP()) { 170 t.Fatal("Fake IP for v2fly.org not in global pool 198.18.0.0/16") 171 } 172 } 173 } 174 } 175 176 func TestFakeDNSEmptyGlobalConfig(t *testing.T) { 177 config := &core.Config{ 178 App: []*anypb.Any{ 179 serial.ToTypedMessage(&Config{ 180 NameServer: []*NameServer{ 181 { // "fakedns" 182 Address: &net.Endpoint{ 183 Network: net.Network_UDP, 184 Address: &net.IPOrDomain{ 185 Address: &net.IPOrDomain_Domain{ 186 Domain: "fakedns", 187 }, 188 }, 189 }, 190 QueryStrategy: QueryStrategy_USE_IP4.Enum(), 191 }, 192 { // "localhost" 193 Address: &net.Endpoint{ 194 Network: net.Network_UDP, 195 Address: &net.IPOrDomain{ 196 Address: &net.IPOrDomain_Domain{ 197 Domain: "localhost", 198 }, 199 }, 200 }, 201 QueryStrategy: QueryStrategy_USE_IP6.Enum(), 202 PrioritizedDomain: []*NameServer_PriorityDomain{ 203 {Type: DomainMatchingType_Subdomain, Domain: "google.com"}, 204 }, 205 FakeDns: &fakedns.FakeDnsPoolMulti{Pools: []*fakedns.FakeDnsPool{}}, // "fakedns": true 206 }, 207 }, 208 }), 209 serial.ToTypedMessage(&dispatcher.Config{}), 210 serial.ToTypedMessage(&proxyman.OutboundConfig{}), 211 serial.ToTypedMessage(&policy.Config{}), 212 }, 213 Outbound: []*core.OutboundHandlerConfig{ 214 { 215 ProxySettings: serial.ToTypedMessage(&freedom.Config{}), 216 }, 217 }, 218 } 219 220 v, err := core.New(config) 221 common.Must(err) 222 common.Must(v.Start()) 223 224 dnsClient := v.GetFeature(feature_dns.ClientType()).(feature_dns.Client) 225 fakeClient := dnsClient.(feature_dns.ClientWithFakeDNS).AsFakeDNSClient() 226 227 { // Lookup facebook.com will return 198.18.0.0/15 (default IPv4 pool) 228 ips, err := fakeClient.LookupIP("facebook.com") 229 if err != nil { 230 t.Fatal("unexpected error: ", err) 231 } 232 for _, ip := range ips { 233 if !(&net.IPNet{IP: net.IP{198, 18, 0, 0}, Mask: net.CIDRMask(15, 8*net.IPv4len)}).Contains(ip) { 234 t.Fatal("Lookup facebook.com with fake client not in default IPv4 pool 198.18.0.0/15") 235 } 236 } 237 } 238 { // Lookup google.com will return fc00::/18 (default IPv6 pool) 239 ips, err := fakeClient.LookupIP("google.com") 240 if err != nil { 241 t.Fatal("unexpected error: ", err) 242 } 243 for _, ip := range ips { 244 if !(&net.IPNet{IP: net.IP{0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Mask: net.CIDRMask(18, 8*net.IPv6len)}).Contains(ip) { 245 t.Fatal("Lookup google.com with fake client not in default IPv6 pool fc00::/18") 246 } 247 } 248 } 249 }