github.com/xraypb/Xray-core@v1.8.1/proxy/dokodemo/dokodemo.go (about)

     1  package dokodemo
     2  
     3  //go:generate go run github.com/xraypb/Xray-core/common/errors/errorgen
     4  
     5  import (
     6  	"context"
     7  	"sync/atomic"
     8  	"time"
     9  
    10  	"github.com/xraypb/Xray-core/common"
    11  	"github.com/xraypb/Xray-core/common/buf"
    12  	"github.com/xraypb/Xray-core/common/log"
    13  	"github.com/xraypb/Xray-core/common/net"
    14  	"github.com/xraypb/Xray-core/common/protocol"
    15  	"github.com/xraypb/Xray-core/common/session"
    16  	"github.com/xraypb/Xray-core/common/signal"
    17  	"github.com/xraypb/Xray-core/common/task"
    18  	"github.com/xraypb/Xray-core/core"
    19  	"github.com/xraypb/Xray-core/features/policy"
    20  	"github.com/xraypb/Xray-core/features/routing"
    21  	"github.com/xraypb/Xray-core/transport/internet/stat"
    22  )
    23  
    24  func init() {
    25  	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
    26  		d := new(DokodemoDoor)
    27  		err := core.RequireFeatures(ctx, func(pm policy.Manager) error {
    28  			return d.Init(config.(*Config), pm, session.SockoptFromContext(ctx))
    29  		})
    30  		return d, err
    31  	}))
    32  }
    33  
    34  type DokodemoDoor struct {
    35  	policyManager policy.Manager
    36  	config        *Config
    37  	address       net.Address
    38  	port          net.Port
    39  	sockopt       *session.Sockopt
    40  }
    41  
    42  // Init initializes the DokodemoDoor instance with necessary parameters.
    43  func (d *DokodemoDoor) Init(config *Config, pm policy.Manager, sockopt *session.Sockopt) error {
    44  	if (config.NetworkList == nil || len(config.NetworkList.Network) == 0) && len(config.Networks) == 0 {
    45  		return newError("no network specified")
    46  	}
    47  	d.config = config
    48  	d.address = config.GetPredefinedAddress()
    49  	d.port = net.Port(config.Port)
    50  	d.policyManager = pm
    51  	d.sockopt = sockopt
    52  
    53  	return nil
    54  }
    55  
    56  // Network implements proxy.Inbound.
    57  func (d *DokodemoDoor) Network() []net.Network {
    58  	if len(d.config.Networks) > 0 {
    59  		return d.config.Networks
    60  	}
    61  
    62  	return d.config.NetworkList.Network
    63  }
    64  
    65  func (d *DokodemoDoor) policy() policy.Session {
    66  	config := d.config
    67  	p := d.policyManager.ForLevel(config.UserLevel)
    68  	if config.Timeout > 0 && config.UserLevel == 0 {
    69  		p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second
    70  	}
    71  	return p
    72  }
    73  
    74  type hasHandshakeAddress interface {
    75  	HandshakeAddress() net.Address
    76  }
    77  
    78  // Process implements proxy.Inbound.
    79  func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {
    80  	newError("processing connection from: ", conn.RemoteAddr()).AtDebug().WriteToLog(session.ExportIDToError(ctx))
    81  	dest := net.Destination{
    82  		Network: network,
    83  		Address: d.address,
    84  		Port:    d.port,
    85  	}
    86  
    87  	destinationOverridden := false
    88  	if d.config.FollowRedirect {
    89  		if outbound := session.OutboundFromContext(ctx); outbound != nil && outbound.Target.IsValid() {
    90  			dest = outbound.Target
    91  			destinationOverridden = true
    92  		} else if handshake, ok := conn.(hasHandshakeAddress); ok {
    93  			addr := handshake.HandshakeAddress()
    94  			if addr != nil {
    95  				dest.Address = addr
    96  				destinationOverridden = true
    97  			}
    98  		}
    99  	}
   100  	if !dest.IsValid() || dest.Address == nil {
   101  		return newError("unable to get destination")
   102  	}
   103  
   104  	inbound := session.InboundFromContext(ctx)
   105  	if inbound != nil {
   106  		inbound.Name = "dokodemo-door"
   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  	if inbound != nil {
   125  		inbound.Timer = timer
   126  	}
   127  
   128  	ctx = policy.ContextWithBufferPolicy(ctx, plcy.Buffer)
   129  	link, err := dispatcher.Dispatch(ctx, dest)
   130  	if err != nil {
   131  		return newError("failed to dispatch request").Base(err)
   132  	}
   133  
   134  	requestCount := int32(1)
   135  	requestDone := func() error {
   136  		defer func() {
   137  			if atomic.AddInt32(&requestCount, -1) == 0 {
   138  				timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
   139  			}
   140  		}()
   141  
   142  		var reader buf.Reader
   143  		if dest.Network == net.Network_UDP {
   144  			reader = buf.NewPacketReader(conn)
   145  		} else {
   146  			reader = buf.NewReader(conn)
   147  		}
   148  		if err := buf.Copy(reader, link.Writer, buf.UpdateActivity(timer)); err != nil {
   149  			return newError("failed to transport request").Base(err)
   150  		}
   151  
   152  		return nil
   153  	}
   154  
   155  	tproxyRequest := func() error {
   156  		return nil
   157  	}
   158  
   159  	var writer buf.Writer
   160  	if network == net.Network_TCP {
   161  		writer = buf.NewWriter(conn)
   162  	} else {
   163  		// if we are in TPROXY mode, use linux's udp forging functionality
   164  		if !destinationOverridden {
   165  			writer = &buf.SequentialWriter{Writer: conn}
   166  		} else {
   167  			back := conn.RemoteAddr().(*net.UDPAddr)
   168  			if !dest.Address.Family().IsIP() {
   169  				if len(back.IP) == 4 {
   170  					dest.Address = net.AnyIP
   171  				} else {
   172  					dest.Address = net.AnyIPv6
   173  				}
   174  			}
   175  			addr := &net.UDPAddr{
   176  				IP:   dest.Address.IP(),
   177  				Port: int(dest.Port),
   178  			}
   179  			var mark int
   180  			if d.sockopt != nil {
   181  				mark = int(d.sockopt.Mark)
   182  			}
   183  			pConn, err := FakeUDP(addr, mark)
   184  			if err != nil {
   185  				return err
   186  			}
   187  			writer = NewPacketWriter(pConn, &dest, mark, back)
   188  			defer writer.(*PacketWriter).Close()
   189  			/*
   190  				sockopt := &internet.SocketConfig{
   191  					Tproxy: internet.SocketConfig_TProxy,
   192  				}
   193  				if dest.Address.Family().IsIP() {
   194  					sockopt.BindAddress = dest.Address.IP()
   195  					sockopt.BindPort = uint32(dest.Port)
   196  				}
   197  				if d.sockopt != nil {
   198  					sockopt.Mark = d.sockopt.Mark
   199  				}
   200  				tConn, err := internet.DialSystem(ctx, net.DestinationFromAddr(conn.RemoteAddr()), sockopt)
   201  				if err != nil {
   202  					return err
   203  				}
   204  				defer tConn.Close()
   205  
   206  				writer = &buf.SequentialWriter{Writer: tConn}
   207  				tReader := buf.NewPacketReader(tConn)
   208  				requestCount++
   209  				tproxyRequest = func() error {
   210  					defer func() {
   211  						if atomic.AddInt32(&requestCount, -1) == 0 {
   212  							timer.SetTimeout(plcy.Timeouts.DownlinkOnly)
   213  						}
   214  					}()
   215  					if err := buf.Copy(tReader, link.Writer, buf.UpdateActivity(timer)); err != nil {
   216  						return newError("failed to transport request (TPROXY conn)").Base(err)
   217  					}
   218  					return nil
   219  				}
   220  			*/
   221  		}
   222  	}
   223  
   224  	responseDone := func() error {
   225  		defer timer.SetTimeout(plcy.Timeouts.UplinkOnly)
   226  
   227  		if err := buf.Copy(link.Reader, writer, buf.UpdateActivity(timer)); err != nil {
   228  			return newError("failed to transport response").Base(err)
   229  		}
   230  		return nil
   231  	}
   232  
   233  	if err := task.Run(ctx, task.OnSuccess(func() error {
   234  		return task.Run(ctx, requestDone, tproxyRequest)
   235  	}, task.Close(link.Writer)), responseDone); err != nil {
   236  		common.Interrupt(link.Reader)
   237  		common.Interrupt(link.Writer)
   238  		return newError("connection ends").Base(err)
   239  	}
   240  
   241  	return nil
   242  }
   243  
   244  func NewPacketWriter(conn net.PacketConn, d *net.Destination, mark int, back *net.UDPAddr) buf.Writer {
   245  	writer := &PacketWriter{
   246  		conn:  conn,
   247  		conns: make(map[net.Destination]net.PacketConn),
   248  		mark:  mark,
   249  		back:  back,
   250  	}
   251  	writer.conns[*d] = conn
   252  	return writer
   253  }
   254  
   255  type PacketWriter struct {
   256  	conn  net.PacketConn
   257  	conns map[net.Destination]net.PacketConn
   258  	mark  int
   259  	back  *net.UDPAddr
   260  }
   261  
   262  func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
   263  	for {
   264  		mb2, b := buf.SplitFirst(mb)
   265  		mb = mb2
   266  		if b == nil {
   267  			break
   268  		}
   269  		var err error
   270  		if b.UDP != nil && b.UDP.Address.Family().IsIP() {
   271  			conn := w.conns[*b.UDP]
   272  			if conn == nil {
   273  				conn, err = FakeUDP(
   274  					&net.UDPAddr{
   275  						IP:   b.UDP.Address.IP(),
   276  						Port: int(b.UDP.Port),
   277  					},
   278  					w.mark,
   279  				)
   280  				if err != nil {
   281  					newError(err).WriteToLog()
   282  					b.Release()
   283  					continue
   284  				}
   285  				w.conns[*b.UDP] = conn
   286  			}
   287  			_, err = conn.WriteTo(b.Bytes(), w.back)
   288  			if err != nil {
   289  				newError(err).WriteToLog()
   290  				w.conns[*b.UDP] = nil
   291  				conn.Close()
   292  			}
   293  			b.Release()
   294  		} else {
   295  			_, err = w.conn.WriteTo(b.Bytes(), w.back)
   296  			b.Release()
   297  			if err != nil {
   298  				buf.ReleaseMulti(mb)
   299  				return err
   300  			}
   301  		}
   302  	}
   303  	return nil
   304  }
   305  
   306  func (w *PacketWriter) Close() error {
   307  	for _, conn := range w.conns {
   308  		if conn != nil {
   309  			conn.Close()
   310  		}
   311  	}
   312  	return nil
   313  }