github.com/chwjbn/xclash@v0.2.0/tunnel/connection.go (about)

     1  package tunnel
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"net"
     7  	"time"
     8  
     9  	N "github.com/chwjbn/xclash/common/net"
    10  	"github.com/chwjbn/xclash/common/pool"
    11  	"github.com/chwjbn/xclash/component/resolver"
    12  	C "github.com/chwjbn/xclash/constant"
    13  )
    14  
    15  func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error {
    16  	defer packet.Drop()
    17  
    18  	// local resolve UDP dns
    19  	if !metadata.Resolved() {
    20  		ip, err := resolver.ResolveIP(metadata.Host)
    21  		if err != nil {
    22  			return err
    23  		}
    24  		metadata.DstIP = ip
    25  	}
    26  
    27  	addr := metadata.UDPAddr()
    28  	if addr == nil {
    29  		return errors.New("udp addr invalid")
    30  	}
    31  
    32  	if _, err := pc.WriteTo(packet.Data(), addr); err != nil {
    33  		return err
    34  	}
    35  	// reset timeout
    36  	pc.SetReadDeadline(time.Now().Add(udpTimeout))
    37  
    38  	return nil
    39  }
    40  
    41  func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, fAddr net.Addr) {
    42  	buf := pool.Get(pool.UDPBufferSize)
    43  	defer pool.Put(buf)
    44  	defer natTable.Delete(key)
    45  	defer pc.Close()
    46  
    47  	for {
    48  		pc.SetReadDeadline(time.Now().Add(udpTimeout))
    49  		n, from, err := pc.ReadFrom(buf)
    50  		if err != nil {
    51  			return
    52  		}
    53  
    54  		if fAddr != nil {
    55  			from = fAddr
    56  		}
    57  
    58  		_, err = packet.WriteBack(buf[:n], from)
    59  		if err != nil {
    60  			return
    61  		}
    62  	}
    63  }
    64  
    65  func handleSocket(ctx C.ConnContext, outbound net.Conn) {
    66  	relay(ctx.Conn(), outbound)
    67  }
    68  
    69  // relay copies between left and right bidirectionally.
    70  func relay(leftConn, rightConn net.Conn) {
    71  	ch := make(chan error)
    72  
    73  	go func() {
    74  		buf := pool.Get(pool.RelayBufferSize)
    75  		// Wrapping to avoid using *net.TCPConn.(ReadFrom)
    76  		// See also https://github.com/chwjbn/xclash/pull/1209
    77  		_, err := io.CopyBuffer(N.WriteOnlyWriter{Writer: leftConn}, N.ReadOnlyReader{Reader: rightConn}, buf)
    78  		pool.Put(buf)
    79  		leftConn.SetReadDeadline(time.Now())
    80  		ch <- err
    81  	}()
    82  
    83  	buf := pool.Get(pool.RelayBufferSize)
    84  	io.CopyBuffer(N.WriteOnlyWriter{Writer: rightConn}, N.ReadOnlyReader{Reader: leftConn}, buf)
    85  	pool.Put(buf)
    86  	rightConn.SetReadDeadline(time.Now())
    87  	<-ch
    88  }