context.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package dns
  2. //go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen
  3. import (
  4. "github.com/v2fly/v2ray-core/v4/common/net"
  5. "github.com/v2fly/v2ray-core/v4/features/dns"
  6. "github.com/v2fly/v2ray-core/v4/features/routing"
  7. )
  8. // ResolvableContext is an implementation of routing.Context, with domain resolving capability.
  9. type ResolvableContext struct {
  10. routing.Context
  11. dnsClient dns.Client
  12. resolvedIPs []net.IP
  13. }
  14. // GetTargetIPs overrides original routing.Context's implementation.
  15. func (ctx *ResolvableContext) GetTargetIPs() []net.IP {
  16. if ips := ctx.Context.GetTargetIPs(); len(ips) != 0 {
  17. return ips
  18. }
  19. if len(ctx.resolvedIPs) > 0 {
  20. return ctx.resolvedIPs
  21. }
  22. if domain := ctx.GetTargetDomain(); len(domain) != 0 {
  23. var lookupFunc func(string) ([]net.IP, error) = ctx.dnsClient.LookupIP
  24. ipOption := &dns.IPOption{
  25. IPv4Enable: true,
  26. IPv6Enable: true,
  27. }
  28. if c, ok := ctx.dnsClient.(dns.ClientWithIPOption); ok {
  29. ipOption = c.GetIPOption()
  30. c.SetFakeDNSOption(false) // Skip FakeDNS.
  31. } else {
  32. newError("ctx.dnsClient doesn't implement ClientWithIPOption").AtDebug().WriteToLog()
  33. }
  34. switch {
  35. case ipOption.IPv4Enable && !ipOption.IPv6Enable:
  36. if lookupIPv4, ok := ctx.dnsClient.(dns.IPv4Lookup); ok {
  37. lookupFunc = lookupIPv4.LookupIPv4
  38. } else {
  39. newError("ctx.dnsClient doesn't implement IPv4Lookup. Use LookupIP instead.").AtDebug().WriteToLog()
  40. }
  41. case !ipOption.IPv4Enable && ipOption.IPv6Enable:
  42. if lookupIPv6, ok := ctx.dnsClient.(dns.IPv6Lookup); ok {
  43. lookupFunc = lookupIPv6.LookupIPv6
  44. } else {
  45. newError("ctx.dnsClient doesn't implement IPv6Lookup. Use LookupIP instead.").AtDebug().WriteToLog()
  46. }
  47. }
  48. ips, err := lookupFunc(domain)
  49. if err == nil {
  50. ctx.resolvedIPs = ips
  51. return ips
  52. }
  53. newError("resolve ip for ", domain).Base(err).WriteToLog()
  54. }
  55. return nil
  56. }
  57. // ContextWithDNSClient creates a new routing context with domain resolving capability.
  58. // Resolved domain IPs can be retrieved by GetTargetIPs().
  59. func ContextWithDNSClient(ctx routing.Context, client dns.Client) routing.Context {
  60. return &ResolvableContext{Context: ctx, dnsClient: client}
  61. }