2018-07-26 00:04:59 +08:00
package tunnel
import (
2020-06-12 23:39:03 +08:00
"errors"
2018-09-17 00:15:58 +08:00
"net"
2022-07-05 21:09:29 +08:00
"net/netip"
2018-09-21 11:33:29 +08:00
"time"
2018-07-26 00:04:59 +08:00
2023-01-16 10:50:31 +08:00
N "github.com/Dreamacro/clash/common/net"
2019-12-28 18:44:01 +08:00
C "github.com/Dreamacro/clash/constant"
2023-02-18 13:16:07 +08:00
"github.com/Dreamacro/clash/log"
2018-07-26 00:04:59 +08:00
)
2020-06-12 23:39:03 +08:00
func handleUDPToRemote ( packet C . UDPPacket , pc C . PacketConn , metadata * C . Metadata ) error {
addr := metadata . UDPAddr ( )
if addr == nil {
return errors . New ( "udp addr invalid" )
}
2021-02-26 10:40:55 +08:00
if _ , err := pc . WriteTo ( packet . Data ( ) , addr ) ; err != nil {
return err
}
// reset timeout
2022-07-05 21:09:29 +08:00
_ = pc . SetReadDeadline ( time . Now ( ) . Add ( udpTimeout ) )
2021-02-26 10:40:55 +08:00
return nil
2019-07-25 17:47:39 +08:00
}
2019-04-23 23:29:36 +08:00
2023-06-03 21:40:09 +08:00
func handleUDPToLocal ( writeBack C . WriteBack , pc N . EnhancePacketConn , key string , oAddrPort netip . AddrPort , fAddr netip . Addr ) {
2022-07-05 21:09:29 +08:00
defer func ( ) {
_ = pc . Close ( )
2023-02-17 16:31:15 +08:00
closeAllLocalCoon ( key )
2022-07-05 21:09:29 +08:00
natTable . Delete ( key )
} ( )
2019-04-23 23:29:36 +08:00
for {
2022-07-05 21:09:29 +08:00
_ = pc . SetReadDeadline ( time . Now ( ) . Add ( udpTimeout ) )
2023-05-11 13:47:51 +08:00
data , put , from , err := pc . WaitReadFrom ( )
2019-04-23 23:29:36 +08:00
if err != nil {
2019-07-25 17:47:39 +08:00
return
2019-04-23 23:29:36 +08:00
}
2023-05-27 13:43:41 +08:00
fromUDPAddr , isUDPAddr := from . ( * net . UDPAddr )
2023-07-16 10:35:10 +08:00
if ! isUDPAddr {
fromUDPAddr = net . UDPAddrFromAddrPort ( oAddrPort ) // oAddrPort was Unmapped
log . Warnln ( "server return a [%T](%s) which isn't a *net.UDPAddr, force replace to (%s), this may be caused by a wrongly implemented server" , from , from , oAddrPort )
} else if fromUDPAddr == nil {
fromUDPAddr = net . UDPAddrFromAddrPort ( oAddrPort ) // oAddrPort was Unmapped
log . Warnln ( "server return a nil *net.UDPAddr, force replace to (%s), this may be caused by a wrongly implemented server" , oAddrPort )
} else {
2023-05-27 13:43:41 +08:00
_fromUDPAddr := * fromUDPAddr
fromUDPAddr = & _fromUDPAddr // make a copy
if fromAddr , ok := netip . AddrFromSlice ( fromUDPAddr . IP ) ; ok {
fromAddr = fromAddr . Unmap ( )
if fAddr . IsValid ( ) && ( oAddrPort . Addr ( ) == fromAddr ) { // oAddrPort was Unmapped
fromAddr = fAddr . Unmap ( )
}
fromUDPAddr . IP = fromAddr . AsSlice ( )
if fromAddr . Is4 ( ) {
fromUDPAddr . Zone = "" // only ipv6 can have the zone
}
2022-07-05 21:09:29 +08:00
}
2020-03-10 20:36:24 +08:00
}
2023-06-03 21:40:09 +08:00
_ , err = writeBack . WriteBack ( data , fromUDPAddr )
2023-05-15 19:06:58 +08:00
if put != nil {
put ( )
}
2019-07-25 17:47:39 +08:00
if err != nil {
return
2019-04-23 23:29:36 +08:00
}
}
2019-07-25 17:47:39 +08:00
}
2019-04-23 23:29:36 +08:00
2023-02-17 16:31:15 +08:00
func closeAllLocalCoon ( lAddr string ) {
natTable . RangeLocalConn ( lAddr , func ( key , value any ) bool {
conn , ok := value . ( * net . UDPConn )
if ! ok || conn == nil {
log . Debugln ( "Value %#v unknown value when closing TProxy local conn..." , conn )
return true
}
conn . Close ( )
log . Debugln ( "Closing TProxy local conn... lAddr=%s rAddr=%s" , lAddr , key )
return true
} )
}
2021-01-23 14:49:46 +08:00
func handleSocket ( ctx C . ConnContext , outbound net . Conn ) {
2023-01-16 10:50:31 +08:00
N . Relay ( ctx . Conn ( ) , outbound )
2022-03-16 18:17:28 +08:00
}