package proxy import ( "net" "strconv" "time" "github.com/xjasonlyu/tun2socks/common/dns" "github.com/xjasonlyu/tun2socks/common/log" "github.com/xjasonlyu/tun2socks/common/lsof" "github.com/xjasonlyu/tun2socks/common/stats" "github.com/xjasonlyu/tun2socks/core" "github.com/xjasonlyu/tun2socks/proxy/socks" ) type tcpHandler struct { proxyHost string proxyPort int fakeDns dns.FakeDns sessionStater stats.SessionStater } func NewTCPHandler(proxyHost string, proxyPort int, fakeDns dns.FakeDns, sessionStater stats.SessionStater) core.TCPConnHandler { return &tcpHandler{ proxyHost: proxyHost, proxyPort: proxyPort, fakeDns: fakeDns, sessionStater: sessionStater, } } func (h *tcpHandler) Handle(localConn net.Conn, target *net.TCPAddr) error { // Replace with a domain name if target address IP is a fake IP. var targetHost = target.IP.String() if h.fakeDns != nil { if host, exist := h.fakeDns.IPToHost(target.IP); exist { targetHost = host } } proxyAddr := net.JoinHostPort(h.proxyHost, strconv.Itoa(h.proxyPort)) targetAddr := net.JoinHostPort(targetHost, strconv.Itoa(target.Port)) // Dial remoteConn, err := socks.Dial(proxyAddr, targetAddr) if err != nil { log.Warnf("Dial %v error: %v", proxyAddr, err) return err } // Get name of the process. var process = lsof.GetProcessName(localConn.LocalAddr()) if h.sessionStater != nil { sess := &stats.Session{ ProcessName: process, Network: localConn.LocalAddr().Network(), DialerAddr: remoteConn.LocalAddr().String(), ClientAddr: localConn.LocalAddr().String(), TargetAddr: targetAddr, UploadBytes: 0, DownloadBytes: 0, SessionStart: time.Now(), } h.sessionStater.AddSession(localConn, sess) remoteConn = stats.NewSessionConn(remoteConn, sess) } // set keepalive tcpKeepAlive(localConn) tcpKeepAlive(remoteConn) go func() { // relay connections tcpRelay(localConn, remoteConn) // remove session if h.sessionStater != nil { h.sessionStater.RemoveSession(localConn) } }() log.Access(process, "proxy", target.Network(), localConn.LocalAddr().String(), targetAddr) return nil }