package tcpprox import ( "io" "log" "net" "sync" "time" ) func isValidIP(ip string) bool { parsedIP := net.ParseIP(ip) return parsedIP != nil } /* Connection Copy Copy between two connections, and accumlate the copied bytes in the accumulator number */ func connCopy(conn1 net.Conn, conn2 net.Conn, wg *sync.WaitGroup, accumulator *int64) { io.Copy(conn1, conn2) conn1.Close() log.Println("[←]", "close the connect at local:["+conn1.LocalAddr().String()+"] and remote:["+conn1.RemoteAddr().String()+"]") //conn2.Close() //log.Println("[←]", "close the connect at local:["+conn2.LocalAddr().String()+"] and remote:["+conn2.RemoteAddr().String()+"]") wg.Done() } func forward(conn1 net.Conn, conn2 net.Conn) { log.Printf("[+] start transmit. [%s],[%s] <-> [%s],[%s] \n", conn1.LocalAddr().String(), conn1.RemoteAddr().String(), conn2.LocalAddr().String(), conn2.RemoteAddr().String()) var wg sync.WaitGroup // wait tow goroutines wg.Add(2) go connCopy(conn1, conn2, &wg) go connCopy(conn2, conn1, &wg) //blocking when the wg is locked wg.Wait() } func accept(listener net.Listener) net.Conn { conn, err := listener.Accept() if err != nil { log.Println("[x]", "accept connect ["+conn.RemoteAddr().String()+"] faild.", err.Error()) return nil } log.Println("[√]", "accept a new client. remote address:["+conn.RemoteAddr().String()+"], local address:["+conn.LocalAddr().String()+"]") return conn } func start_server(address string) net.Listener { log.Println("[+]", "try to start server on:["+address+"]") server, err := net.Listen("tcp", address) if err != nil { log.Fatalln("[x]", "listen address ["+address+"] faild.") } log.Println("[√]", "start listen at address:["+address+"]") return server } func port2port(port1 string, port2 string) { listen1 := start_server("0.0.0.0:" + port1) listen2 := start_server("0.0.0.0:" + port2) log.Println("[√]", "listen port:", port1, "and", port2, "success. waiting for client...") for { conn1 := accept(listen1) conn2 := accept(listen2) if conn1 == nil || conn2 == nil { log.Println("[x]", "accept client faild. retry in ", timeout, " seconds. ") time.Sleep(timeout * time.Second) continue } forward(conn1, conn2) } } func port2host(allowPort string, targetAddress string) { server := start_server("0.0.0.0:" + allowPort) for { conn := accept(server) if conn == nil { continue } //println(targetAddress) go func(targetAddress string) { log.Println("[+]", "start connect host:["+targetAddress+"]") target, err := net.Dial("tcp", targetAddress) if err != nil { // temporarily unavailable, don't use fatal. log.Println("[x]", "connect target address ["+targetAddress+"] faild. retry in ", timeout, "seconds. ") conn.Close() log.Println("[←]", "close the connect at local:["+conn.LocalAddr().String()+"] and remote:["+conn.RemoteAddr().String()+"]") time.Sleep(timeout * time.Second) return } log.Println("[→]", "connect target address ["+targetAddress+"] success.") forward(target, conn) }(targetAddress) } } func host2host(address1, address2 string) { for { log.Println("[+]", "try to connect host:["+address1+"] and ["+address2+"]") var host1, host2 net.Conn var err error for { host1, err = net.Dial("tcp", address1) if err == nil { log.Println("[→]", "connect ["+address1+"] success.") break } else { log.Println("[x]", "connect target address ["+address1+"] faild. retry in ", timeout, " seconds. ") time.Sleep(timeout * time.Second) } } for { host2, err = net.Dial("tcp", address2) if err == nil { log.Println("[→]", "connect ["+address2+"] success.") break } else { log.Println("[x]", "connect target address ["+address2+"] faild. retry in ", timeout, " seconds. ") time.Sleep(timeout * time.Second) } } forward(host1, host2) } }