github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/proxy/freedom/freedom.go (about)

     1  // +build !confonly
     2  
     3  package freedom
     4  
     5  //go:generate go run v2ray.com/core/common/errors/errorgen
     6  
     7  import (
     8  	"context"
     9  	"time"
    10  
    11  	"v2ray.com/core"
    12  	"v2ray.com/core/common"
    13  	"v2ray.com/core/common/buf"
    14  	"v2ray.com/core/common/dice"
    15  	"v2ray.com/core/common/net"
    16  	"v2ray.com/core/common/retry"
    17  	"v2ray.com/core/common/session"
    18  	"v2ray.com/core/common/signal"
    19  	"v2ray.com/core/common/task"
    20  	"v2ray.com/core/features/dns"
    21  	"v2ray.com/core/features/policy"
    22  	"v2ray.com/core/transport"
    23  	"v2ray.com/core/transport/internet"
    24  )
    25  
    26  func init() {
    27  	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
    28  		h := new(Handler)
    29  		if err := core.RequireFeatures(ctx, func(pm policy.Manager, d dns.Client) error {
    30  			return h.Init(config.(*Config), pm, d)
    31  		}); err != nil {
    32  			return nil, err
    33  		}
    34  		return h, nil
    35  	}))
    36  }
    37  
    38  // Handler handles Freedom connections.
    39  type Handler struct {
    40  	policyManager policy.Manager
    41  	dns           dns.Client
    42  	config        *Config
    43  }
    44  
    45  // Init initializes the Handler with necessary parameters.
    46  func (h *Handler) Init(config *Config, pm policy.Manager, d dns.Client) error {
    47  	h.config = config
    48  	h.policyManager = pm
    49  	h.dns = d
    50  
    51  	return nil
    52  }
    53  
    54  func (h *Handler) policy() policy.Session {
    55  	p := h.policyManager.ForLevel(h.config.UserLevel)
    56  	if h.config.Timeout > 0 && h.config.UserLevel == 0 {
    57  		p.Timeouts.ConnectionIdle = time.Duration(h.config.Timeout) * time.Second
    58  	}
    59  	return p
    60  }
    61  
    62  func (h *Handler) resolveIP(ctx context.Context, domain string, localAddr net.Address) net.Address {
    63  	var lookupFunc func(string) ([]net.IP, error) = h.dns.LookupIP
    64  
    65  	if h.config.DomainStrategy == Config_USE_IP4 || (localAddr != nil && localAddr.Family().IsIPv4()) {
    66  		if lookupIPv4, ok := h.dns.(dns.IPv4Lookup); ok {
    67  			lookupFunc = lookupIPv4.LookupIPv4
    68  		}
    69  	} else if h.config.DomainStrategy == Config_USE_IP6 || (localAddr != nil && localAddr.Family().IsIPv6()) {
    70  		if lookupIPv6, ok := h.dns.(dns.IPv6Lookup); ok {
    71  			lookupFunc = lookupIPv6.LookupIPv6
    72  		}
    73  	}
    74  
    75  	ips, err := lookupFunc(domain)
    76  	if err != nil {
    77  		newError("failed to get IP address for domain ", domain).Base(err).WriteToLog(session.ExportIDToError(ctx))
    78  	}
    79  	if len(ips) == 0 {
    80  		return nil
    81  	}
    82  	return net.IPAddress(ips[dice.Roll(len(ips))])
    83  }
    84  
    85  func isValidAddress(addr *net.IPOrDomain) bool {
    86  	if addr == nil {
    87  		return false
    88  	}
    89  
    90  	a := addr.AsAddress()
    91  	return a != net.AnyIP
    92  }
    93  
    94  // Process implements proxy.Outbound.
    95  func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
    96  	outbound := session.OutboundFromContext(ctx)
    97  	if outbound == nil || !outbound.Target.IsValid() {
    98  		return newError("target not specified.")
    99  	}
   100  	destination := outbound.Target
   101  	if h.config.DestinationOverride != nil {
   102  		server := h.config.DestinationOverride.Server
   103  		if isValidAddress(server.Address) {
   104  			destination.Address = server.Address.AsAddress()
   105  		}
   106  		if server.Port != 0 {
   107  			destination.Port = net.Port(server.Port)
   108  		}
   109  	}
   110  	newError("opening connection to ", destination).WriteToLog(session.ExportIDToError(ctx))
   111  
   112  	input := link.Reader
   113  	output := link.Writer
   114  
   115  	var conn internet.Connection
   116  	err := retry.ExponentialBackoff(5, 100).On(func() error {
   117  		dialDest := destination
   118  		if h.config.useIP() && dialDest.Address.Family().IsDomain() {
   119  			ip := h.resolveIP(ctx, dialDest.Address.Domain(), dialer.Address())
   120  			if ip != nil {
   121  				dialDest = net.Destination{
   122  					Network: dialDest.Network,
   123  					Address: ip,
   124  					Port:    dialDest.Port,
   125  				}
   126  				newError("dialing to to ", dialDest).WriteToLog(session.ExportIDToError(ctx))
   127  			}
   128  		}
   129  
   130  		rawConn, err := dialer.Dial(ctx, dialDest)
   131  		if err != nil {
   132  			return err
   133  		}
   134  		conn = rawConn
   135  		return nil
   136  	})
   137  	if err != nil {
   138  		return newError("failed to open connection to ", destination).Base(err)
   139  	}
   140  	defer conn.Close() // nolint: errcheck
   141  
   142  	plcy := h.policy()
   143  	ctx, cancel := context.WithCancel(ctx)
   144  	timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)
   145  
   146  	requestDone := func() error {
   147  		defer timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
   148  
   149  		var writer buf.Writer
   150  		if destination.Network == net.Network_TCP {
   151  			writer = buf.NewWriter(conn)
   152  		} else {
   153  			writer = &buf.SequentialWriter{Writer: conn}
   154  		}
   155  
   156  		if err := buf.Copy(input, writer, buf.UpdateActivity(timer)); err != nil {
   157  			return newError("failed to process request").Base(err)
   158  		}
   159  
   160  		return nil
   161  	}
   162  
   163  	responseDone := func() error {
   164  		defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
   165  
   166  		var reader buf.Reader
   167  		if destination.Network == net.Network_TCP {
   168  			reader = buf.NewReader(conn)
   169  		} else {
   170  			reader = buf.NewPacketReader(conn)
   171  		}
   172  		if err := buf.Copy(reader, output, buf.UpdateActivity(timer)); err != nil {
   173  			return newError("failed to process response").Base(err)
   174  		}
   175  
   176  		return nil
   177  	}
   178  
   179  	if err := task.Run(ctx, requestDone, task.OnSuccess(responseDone, task.Close(output))); err != nil {
   180  		return newError("connection ends").Base(err)
   181  	}
   182  
   183  	return nil
   184  }