github.com/v2fly/v2ray-core/v4@v4.45.2/proxy/dokodemo/dokodemo.go (about)

     1  //go:build !confonly
     2  // +build !confonly
     3  
     4  package dokodemo
     5  
     6  //go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen
     7  
     8  import (
     9  	"context"
    10  	"sync/atomic"
    11  	"time"
    12  
    13  	core "github.com/v2fly/v2ray-core/v4"
    14  	"github.com/v2fly/v2ray-core/v4/common"
    15  	"github.com/v2fly/v2ray-core/v4/common/buf"
    16  	"github.com/v2fly/v2ray-core/v4/common/log"
    17  	"github.com/v2fly/v2ray-core/v4/common/net"
    18  	"github.com/v2fly/v2ray-core/v4/common/protocol"
    19  	"github.com/v2fly/v2ray-core/v4/common/session"
    20  	"github.com/v2fly/v2ray-core/v4/common/signal"
    21  	"github.com/v2fly/v2ray-core/v4/common/task"
    22  	"github.com/v2fly/v2ray-core/v4/features/policy"
    23  	"github.com/v2fly/v2ray-core/v4/features/routing"
    24  	"github.com/v2fly/v2ray-core/v4/transport/internet"
    25  )
    26  
    27  func init() {
    28  	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
    29  		d := new(Door)
    30  		err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
    31  			return d.Init(config.(*Config), pm, session.SockoptFromContext(ctx))
    32  		})
    33  		return d, err
    34  	}))
    35  }
    36  
    37  type Door struct {
    38  	policyManager policy.Manager
    39  	config        *Config
    40  	address       net.Address
    41  	port          net.Port
    42  	sockopt       *session.Sockopt
    43  }
    44  
    45  // Init initializes the Door instance with necessary parameters.
    46  func (d *Door) Init(config *Config, pm policy.Manager, sockopt *session.Sockopt) error {
    47  	if (config.NetworkList == nil || len(config.NetworkList.Network) == 0) && len(config.Networks) == 0 {
    48  		return newError("no network specified")
    49  	}
    50  	d.config = config
    51  	d.address = config.GetPredefinedAddress()
    52  	d.port = net.Port(config.Port)
    53  	d.policyManager = pm
    54  	d.sockopt = sockopt
    55  
    56  	return nil
    57  }
    58  
    59  // Network implements proxy.Inbound.
    60  func (d *Door) Network() []net.Network {
    61  	if len(d.config.Networks) > 0 {
    62  		return d.config.Networks
    63  	}
    64  
    65  	return d.config.NetworkList.Network
    66  }
    67  
    68  func (d *Door) policy() policy.Session {
    69  	config := d.config
    70  	p := d.policyManager.ForLevel(config.UserLevel)
    71  	if config.Timeout > 0 && config.UserLevel == 0 {
    72  		p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second
    73  	}
    74  	return p
    75  }
    76  
    77  type hasHandshakeAddress interface {
    78  	HandshakeAddress() net.Address
    79  }
    80  
    81  // Process implements proxy.Inbound.
    82  func (d *Door) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher routing.Dispatcher) error {
    83  	newError("processing connection from: ", conn.RemoteAddr()).AtDebug().WriteToLog(session.ExportIDToError(ctx))
    84  	dest := net.Destination{
    85  		Network: network,
    86  		Address: d.address,
    87  		Port:    d.port,
    88  	}
    89  
    90  	destinationOverridden := false
    91  	if d.config.FollowRedirect {
    92  		if outbound := session.OutboundFromContext(ctx); outbound != nil && outbound.Target.IsValid() {
    93  			dest = outbound.Target
    94  			destinationOverridden = true
    95  		} else if handshake, ok := conn.(hasHandshakeAddress); ok {
    96  			addr := handshake.HandshakeAddress()
    97  			if addr != nil {
    98  				dest.Address = addr
    99  				destinationOverridden = true
   100  			}
   101  		}
   102  	}
   103  	if !dest.IsValid() || dest.Address == nil {
   104  		return newError("unable to get destination")
   105  	}
   106  
   107  	if inbound := session.InboundFromContext(ctx); inbound != nil {
   108  		inbound.User = &protocol.MemoryUser{
   109  			Level: d.config.UserLevel,
   110  		}
   111  	}
   112  
   113  	ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
   114  		From:   conn.RemoteAddr(),
   115  		To:     dest,
   116  		Status: log.AccessAccepted,
   117  		Reason: "",
   118  	})
   119  	newError("received request for ", conn.RemoteAddr()).WriteToLog(session.ExportIDToError(ctx))
   120  
   121  	plcy := d.policy()
   122  	ctx, cancel := context.WithCancel(ctx)
   123  	timer := signal.CancelAfterInactivity(ctx, cancel, plcy.Timeouts.ConnectionIdle)
   124  
   125  	ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)
   126  	link, err := dispatcher.Dispatch(ctx, dest)
   127  	if err != nil {
   128  		return newError("failed to dispatch request").Base(err)
   129  	}
   130  
   131  	requestCount := int32(1)
   132  	requestDone := func() error {
   133  		defer func() {
   134  			if atomic.AddInt32(&requestCount, -1) == 0 {
   135  				timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
   136  			}
   137  		}()
   138  
   139  		var reader buf.Reader
   140  		if dest.Network == net.Network_UDP {
   141  			reader = buf.NewPacketReader(conn)
   142  		} else {
   143  			reader = buf.NewReader(conn)
   144  		}
   145  		if err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil {
   146  			return newError("failed to transport request").Base(err)
   147  		}
   148  
   149  		return nil
   150  	}
   151  
   152  	tproxyRequest := func() error {
   153  		return nil
   154  	}
   155  
   156  	var writer buf.Writer
   157  	if network == net.Network_TCP {
   158  		writer = buf.NewWriter(conn)
   159  	} else {
   160  		// if we are in TPROXY mode, use linux's udp forging functionality
   161  		if !destinationOverridden {
   162  			writer = &buf.SequentialWriter{Writer: conn}
   163  		} else {
   164  			sockopt := &internet.SocketConfig{
   165  				Tproxy: internet.SocketConfig_TProxy,
   166  			}
   167  			if dest.Address.Family().IsIP() {
   168  				sockopt.BindAddress = dest.Address.IP()
   169  				sockopt.BindPort = uint32(dest.Port)
   170  			}
   171  			if d.sockopt != nil {
   172  				sockopt.Mark = d.sockopt.Mark
   173  			}
   174  			tConn, err := internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt)
   175  			if err != nil {
   176  				return err
   177  			}
   178  			defer tConn.Close()
   179  
   180  			writer = &buf.SequentialWriter{Writer: tConn}
   181  			tReader := buf.NewPacketReader(tConn)
   182  			requestCount++
   183  			tproxyRequest = func() error {
   184  				defer func() {
   185  					if atomic.AddInt32(&requestCount, -1) == 0 {
   186  						timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
   187  					}
   188  				}()
   189  				if err := buf.Copy(tReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
   190  					return newError("failed to transport request (TPROXY conn)").Base(err)
   191  				}
   192  				return nil
   193  			}
   194  		}
   195  	}
   196  
   197  	responseDone := func() error {
   198  		defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
   199  
   200  		if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {
   201  			return newError("failed to transport response").Base(err)
   202  		}
   203  		return nil
   204  	}
   205  
   206  	if err := task.Run(ctx, task.OnSuccess(func() error {
   207  		return task.Run(ctx, requestDone, tproxyRequest)
   208  	}, task.Close(link.Writer)), responseDone); err != nil {
   209  		common.Interrupt(link.Reader)
   210  		common.Interrupt(link.Writer)
   211  		return newError("connection ends").Base(err)
   212  	}
   213  
   214  	return nil
   215  }