2018-07-26 00:04:59 +08:00
package tunnel
import (
2024-09-26 11:21:07 +08:00
"context"
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
2024-09-26 22:21:59 +08:00
"github.com/metacubex/mihomo/common/lru"
2023-11-03 21:01:45 +08:00
N "github.com/metacubex/mihomo/common/net"
2024-09-26 22:21:59 +08:00
"github.com/metacubex/mihomo/component/resolver"
2023-11-03 21:01:45 +08:00
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/log"
2018-07-26 00:04:59 +08:00
)
2024-09-26 11:21:07 +08:00
type packetSender struct {
ctx context . Context
cancel context . CancelFunc
ch chan C . PacketAdapter
2024-09-26 22:21:59 +08:00
cache * lru . LruCache [ string , netip . Addr ]
2024-09-26 11:21:07 +08:00
}
// newPacketSender return a chan based C.PacketSender
// It ensures that packets can be sent sequentially and without blocking
func newPacketSender ( ) C . PacketSender {
ctx , cancel := context . WithCancel ( context . Background ( ) )
ch := make ( chan C . PacketAdapter , senderCapacity )
return & packetSender {
ctx : ctx ,
cancel : cancel ,
ch : ch ,
2024-09-26 22:21:59 +08:00
cache : lru . New [ string , netip . Addr ] ( lru . WithSize [ string , netip . Addr ] ( senderCapacity ) ) ,
2024-09-26 11:21:07 +08:00
}
}
func ( s * packetSender ) Process ( pc C . PacketConn , proxy C . WriteBackProxy ) {
for {
select {
case <- s . ctx . Done ( ) :
return // sender closed
case packet := <- s . ch :
if proxy != nil {
proxy . UpdateWriteBack ( packet )
}
2024-09-26 22:21:59 +08:00
if err := s . ResolveUDP ( packet . Metadata ( ) ) ; err != nil {
log . Warnln ( "[UDP] Resolve Ip error: %s" , err )
} else {
_ = handleUDPToRemote ( packet , pc , packet . Metadata ( ) )
}
2024-09-26 11:21:07 +08:00
packet . Drop ( )
}
}
}
func ( s * packetSender ) dropAll ( ) {
for {
select {
case data := <- s . ch :
data . Drop ( ) // drop all data still in chan
default :
return // no data, exit goroutine
}
}
}
func ( s * packetSender ) Send ( packet C . PacketAdapter ) {
select {
case <- s . ctx . Done ( ) :
packet . Drop ( ) // sender closed before Send()
return
default :
}
select {
case s . ch <- packet :
// put ok, so don't drop packet, will process by other side of chan
case <- s . ctx . Done ( ) :
packet . Drop ( ) // sender closed when putting data to chan
default :
packet . Drop ( ) // chan is full
}
}
func ( s * packetSender ) Close ( ) {
s . cancel ( )
s . dropAll ( )
}
2024-09-26 22:21:59 +08:00
func ( s * packetSender ) ResolveUDP ( metadata * C . Metadata ) ( err error ) {
// local resolve UDP dns
if ! metadata . Resolved ( ) {
ip , ok := s . cache . Get ( metadata . Host )
if ! ok {
ip , err = resolver . ResolveIP ( s . ctx , metadata . Host )
if err != nil {
return err
}
s . cache . Set ( metadata . Host , ip )
}
metadata . DstIP = ip
2024-09-26 11:21:07 +08:00
}
2024-09-26 22:21:59 +08:00
return nil
}
2024-09-26 11:21:07 +08:00
2024-09-26 22:21:59 +08:00
func handleUDPToRemote ( packet C . UDPPacket , pc C . PacketConn , metadata * C . Metadata ) error {
2020-06-12 23:39:03 +08:00
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
2024-09-26 11:21:07 +08:00
func handleUDPToLocal ( writeBack C . WriteBack , pc N . EnhancePacketConn , sender C . PacketSender , key string , oAddrPort netip . AddrPort , fAddr netip . Addr ) {
2022-07-05 21:09:29 +08:00
defer func ( ) {
2024-09-26 11:21:07 +08:00
sender . Close ( )
2022-07-05 21:09:29 +08:00
_ = 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 ) {
2023-09-02 16:54:35 +08:00
natTable . RangeForLocalConn ( lAddr , func ( key string , value * net . UDPConn ) bool {
conn := value
2023-02-17 16:31:15 +08:00
conn . Close ( )
log . Debugln ( "Closing TProxy local conn... lAddr=%s rAddr=%s" , lAddr , key )
return true
} )
}
2024-01-02 18:26:45 +08:00
func handleSocket ( inbound , outbound net . Conn ) {
N . Relay ( inbound , outbound )
2022-03-16 18:17:28 +08:00
}