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

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