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 }