mirror of
				https://github.com/xjasonlyu/tun2socks.git
				synced 2025-10-31 20:12:41 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			122 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package d
 | |
| 
 | |
| import (
 | |
| 	"net"
 | |
| 	"strconv"
 | |
| 	"sync"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/xjasonlyu/tun2socks/common/log"
 | |
| 	"github.com/xjasonlyu/tun2socks/common/lsof"
 | |
| 	"github.com/xjasonlyu/tun2socks/core"
 | |
| )
 | |
| 
 | |
| type udpHandler struct {
 | |
| 	sync.Mutex
 | |
| 
 | |
| 	proxyHandler   core.UDPConnHandler
 | |
| 	exceptionApps  []string
 | |
| 	sendThrough    net.Addr
 | |
| 	exceptionConns map[core.UDPConn]*net.UDPConn
 | |
| 	timeout        time.Duration
 | |
| }
 | |
| 
 | |
| func (h *udpHandler) isExceptionApp(name string) bool {
 | |
| 	for _, app := range h.exceptionApps {
 | |
| 		if name == app {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func NewUDPHandler(proxyHandler core.UDPConnHandler, exceptionApps []string, sendThrough net.Addr, timeout time.Duration) core.UDPConnHandler {
 | |
| 	return &udpHandler{
 | |
| 		proxyHandler:   proxyHandler,
 | |
| 		exceptionApps:  exceptionApps,
 | |
| 		sendThrough:    sendThrough,
 | |
| 		exceptionConns: make(map[core.UDPConn]*net.UDPConn),
 | |
| 		timeout:        timeout,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (h *udpHandler) handleInput(conn core.UDPConn, pc *net.UDPConn) {
 | |
| 	buf := core.NewBytes(core.BufSize)
 | |
| 
 | |
| 	defer func() {
 | |
| 		h.Close(conn)
 | |
| 		core.FreeBytes(buf)
 | |
| 	}()
 | |
| 
 | |
| 	for {
 | |
| 		pc.SetDeadline(time.Now().Add(h.timeout))
 | |
| 		n, addr, err := pc.ReadFromUDP(buf)
 | |
| 		if err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		_, err = conn.WriteFrom(buf[:n], addr)
 | |
| 		if err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (h *udpHandler) Connect(conn core.UDPConn, target *net.UDPAddr) error {
 | |
| 	localHost, localPortStr, _ := net.SplitHostPort(conn.LocalAddr().String())
 | |
| 	localPortInt, _ := strconv.Atoi(localPortStr)
 | |
| 	cmd, err := lsof.GetCommandNameBySocket("udp", localHost, uint16(localPortInt))
 | |
| 	if err != nil {
 | |
| 		cmd = "unknown process"
 | |
| 	}
 | |
| 
 | |
| 	if h.isExceptionApp(cmd) {
 | |
| 		bindAddr, _ := net.ResolveUDPAddr(
 | |
| 			"udp",
 | |
| 			h.sendThrough.String(),
 | |
| 		)
 | |
| 		pc, err := net.ListenUDP("udp", bindAddr)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		h.Lock()
 | |
| 		h.exceptionConns[conn] = pc
 | |
| 		h.Unlock()
 | |
| 
 | |
| 		go h.handleInput(conn, pc)
 | |
| 
 | |
| 		log.Access(cmd, "direct", target.Network(), conn.LocalAddr().String(), target.String())
 | |
| 
 | |
| 		return nil
 | |
| 	} else {
 | |
| 		return h.proxyHandler.Connect(conn, target)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (h *udpHandler) ReceiveTo(conn core.UDPConn, data []byte, addr *net.UDPAddr) error {
 | |
| 	h.Lock()
 | |
| 	defer h.Unlock()
 | |
| 
 | |
| 	if pc, found := h.exceptionConns[conn]; found {
 | |
| 		_, err := pc.WriteTo(data, addr)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		return nil
 | |
| 	} else {
 | |
| 		return h.proxyHandler.ReceiveTo(conn, data, addr)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (h *udpHandler) Close(conn core.UDPConn) {
 | |
| 	conn.Close()
 | |
| 
 | |
| 	h.Lock()
 | |
| 	defer h.Unlock()
 | |
| 
 | |
| 	if pc, ok := h.exceptionConns[conn]; ok {
 | |
| 		pc.Close()
 | |
| 		delete(h.exceptionConns, conn)
 | |
| 	}
 | |
| }
 | 
