|
@@ -0,0 +1,289 @@
|
|
|
|
+package main
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "fmt"
|
|
|
|
+ "io"
|
|
|
|
+ "log"
|
|
|
|
+ "net"
|
|
|
|
+ "os"
|
|
|
|
+ "regexp"
|
|
|
|
+ "strconv"
|
|
|
|
+ "strings"
|
|
|
|
+ "sync"
|
|
|
|
+ "time"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+const timeout = 5
|
|
|
|
+
|
|
|
|
+func main() {
|
|
|
|
+ //log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
|
|
|
|
+ log.SetFlags(log.Ldate | log.Lmicroseconds)
|
|
|
|
+
|
|
|
|
+ printWelcome()
|
|
|
|
+
|
|
|
|
+ args := os.Args
|
|
|
|
+ argc := len(os.Args)
|
|
|
|
+ if argc <= 2 {
|
|
|
|
+ printHelp()
|
|
|
|
+ os.Exit(0)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //TODO:support UDP protocol
|
|
|
|
+
|
|
|
|
+ /*var logFileError error
|
|
|
|
+ if argc > 5 && args[4] == "-log" {
|
|
|
|
+ logPath := args[5] + "/" + time.Now().Format("2006_01_02_15_04_05") // "2006-01-02 15:04:05"
|
|
|
|
+ logPath += args[1] + "-" + strings.Replace(args[2], ":", "_", -1) + "-" + args[3] + ".log"
|
|
|
|
+ logPath = strings.Replace(logPath, `\`, "/", -1)
|
|
|
|
+ logPath = strings.Replace(logPath, "//", "/", -1)
|
|
|
|
+ logFile, logFileError = os.OpenFile(logPath, os.O_APPEND|os.O_CREATE, 0666)
|
|
|
|
+ if logFileError != nil {
|
|
|
|
+ log.Fatalln("[x]", "log file path error.", logFileError.Error())
|
|
|
|
+ }
|
|
|
|
+ log.Println("[√]", "open test log file success. path:", logPath)
|
|
|
|
+ }*/
|
|
|
|
+
|
|
|
|
+ switch args[1] {
|
|
|
|
+ case "-listen":
|
|
|
|
+ if argc < 3 {
|
|
|
|
+ log.Fatalln(`-listen need two arguments, like "nb -listen 1997 2017".`)
|
|
|
|
+ }
|
|
|
|
+ port1 := checkPort(args[2])
|
|
|
|
+ port2 := checkPort(args[3])
|
|
|
|
+ log.Println("[√]", "start to listen port:", port1, "and port:", port2)
|
|
|
|
+ port2port(port1, port2)
|
|
|
|
+ break
|
|
|
|
+ case "-tran":
|
|
|
|
+ if argc < 3 {
|
|
|
|
+ log.Fatalln(`-tran need two arguments, like "nb -tran 1997 192.168.1.2:3389".`)
|
|
|
|
+ }
|
|
|
|
+ port := checkPort(args[2])
|
|
|
|
+ var remoteAddress string
|
|
|
|
+ if checkIp(args[3]) {
|
|
|
|
+ remoteAddress = args[3]
|
|
|
|
+ }
|
|
|
|
+ split := strings.SplitN(remoteAddress, ":", 2)
|
|
|
|
+ log.Println("[√]", "start to transmit address:", remoteAddress, "to address:", split[0]+":"+port)
|
|
|
|
+ port2host(port, remoteAddress)
|
|
|
|
+ break
|
|
|
|
+ case "-slave":
|
|
|
|
+ if argc < 3 {
|
|
|
|
+ log.Fatalln(`-slave need two arguments, like "nb -slave 127.0.0.1:3389 8.8.8.8:1997".`)
|
|
|
|
+ }
|
|
|
|
+ var address1, address2 string
|
|
|
|
+ checkIp(args[2])
|
|
|
|
+ if checkIp(args[2]) {
|
|
|
|
+ address1 = args[2]
|
|
|
|
+ }
|
|
|
|
+ checkIp(args[3])
|
|
|
|
+ if checkIp(args[3]) {
|
|
|
|
+ address2 = args[3]
|
|
|
|
+ }
|
|
|
|
+ log.Println("[√]", "start to connect address:", address1, "and address:", address2)
|
|
|
|
+ host2host(address1, address2)
|
|
|
|
+ break
|
|
|
|
+ default:
|
|
|
|
+ printHelp()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func printWelcome() {
|
|
|
|
+ fmt.Println("+----------------------------------------------------------------+")
|
|
|
|
+ fmt.Println("| Welcome to use NATBypass Ver1.0.0 . |")
|
|
|
|
+ fmt.Println("| Code by cw1997 at 2017-10-19 03:59:51 |")
|
|
|
|
+ fmt.Println("| If you have some problem when you use the tool, |")
|
|
|
|
+ fmt.Println("| please submit issue at : https://github.com/cw1997/NATBypass . |")
|
|
|
|
+ fmt.Println("+----------------------------------------------------------------+")
|
|
|
|
+ fmt.Println()
|
|
|
|
+ // sleep one second because the fmt is not thread-safety.
|
|
|
|
+ // if not to do this, fmt.Print will print after the log.Print.
|
|
|
|
+ time.Sleep(time.Second)
|
|
|
|
+}
|
|
|
|
+func printHelp() {
|
|
|
|
+ fmt.Println(`usage: "-listen port1 port2" example: "nb -listen 1997 2017" `)
|
|
|
|
+ fmt.Println(` "-tran port1 ip:port2" example: "nb -tran 1997 192.168.1.2:3389" `)
|
|
|
|
+ fmt.Println(` "-slave ip1:port1 ip2:port2" example: "nb -slave 127.0.0.1:3389 8.8.8.8:1997" `)
|
|
|
|
+ fmt.Println(`============================================================`)
|
|
|
|
+ fmt.Println(`optional argument: "-log logpath" . example: "nb -listen 1997 2017 -log d:/nb" `)
|
|
|
|
+ fmt.Println(`log filename format: Y_m_d_H_i_s-agrs1-args2-args3.log`)
|
|
|
|
+ fmt.Println(`============================================================`)
|
|
|
|
+ fmt.Println(`if you want more help, please read "README.md". `)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func checkPort(port string) string {
|
|
|
|
+ PortNum, err := strconv.Atoi(port)
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Fatalln("[x]", "port should be a number")
|
|
|
|
+ }
|
|
|
|
+ if PortNum < 1 || PortNum > 65535 {
|
|
|
|
+ log.Fatalln("[x]", "port should be a number and the range is [1,65536)")
|
|
|
|
+ }
|
|
|
|
+ return port
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func checkIp(address string) bool {
|
|
|
|
+ ipAndPort := strings.Split(address, ":")
|
|
|
|
+ if len(ipAndPort) != 2 {
|
|
|
|
+ log.Fatalln("[x]", "address error. should be a string like [ip:port]. ")
|
|
|
|
+ }
|
|
|
|
+ ip := ipAndPort[0]
|
|
|
|
+ port := ipAndPort[1]
|
|
|
|
+ checkPort(port)
|
|
|
|
+ pattern := `^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$`
|
|
|
|
+ ok, err := regexp.MatchString(pattern, ip)
|
|
|
|
+ if err != nil || !ok {
|
|
|
|
+ log.Fatalln("[x]", "ip error. ")
|
|
|
|
+ }
|
|
|
|
+ return ok
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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
|
|
|
|
+ /*defer server.Close()
|
|
|
|
+
|
|
|
|
+ for {
|
|
|
|
+ conn, err := server.Accept()
|
|
|
|
+ log.Println("accept a new client. remote address:[" + conn.RemoteAddr().String() +
|
|
|
|
+ "], local address:[" + conn.LocalAddr().String() + "]")
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println("accept a new client faild.", err.Error())
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ //go recvConnMsg(conn)
|
|
|
|
+ }*/
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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 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 connCopy(conn1 net.Conn, conn2 net.Conn, wg *sync.WaitGroup) {
|
|
|
|
+ //TODO:log, record the data from conn1 and conn2.
|
|
|
|
+ logFile := openLog(conn1.LocalAddr().String(), conn1.RemoteAddr().String(), conn2.LocalAddr().String(), conn2.RemoteAddr().String())
|
|
|
|
+ if logFile != nil {
|
|
|
|
+ w := io.MultiWriter(conn1, logFile)
|
|
|
|
+ io.Copy(w, conn2)
|
|
|
|
+ } else {
|
|
|
|
+ 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 openLog(address1, address2, address3, address4 string) *os.File {
|
|
|
|
+ args := os.Args
|
|
|
|
+ argc := len(os.Args)
|
|
|
|
+ var logFileError error
|
|
|
|
+ var logFile *os.File
|
|
|
|
+ if argc > 5 && args[4] == "-log" {
|
|
|
|
+ address1 = strings.Replace(address1, ":", "_", -1)
|
|
|
|
+ address2 = strings.Replace(address2, ":", "_", -1)
|
|
|
|
+ address3 = strings.Replace(address3, ":", "_", -1)
|
|
|
|
+ address4 = strings.Replace(address4, ":", "_", -1)
|
|
|
|
+ timeStr := time.Now().Format("2006_01_02_15_04_05") // "2006-01-02 15:04:05"
|
|
|
|
+ logPath := args[5] + "/" + timeStr + args[1] + "-" + address1 + "_" + address2 + "-" + address3 + "_" + address4 + ".log"
|
|
|
|
+ logPath = strings.Replace(logPath, `\`, "/", -1)
|
|
|
|
+ logPath = strings.Replace(logPath, "//", "/", -1)
|
|
|
|
+ logFile, logFileError = os.OpenFile(logPath, os.O_APPEND|os.O_CREATE, 0666)
|
|
|
|
+ if logFileError != nil {
|
|
|
|
+ log.Fatalln("[x]", "log file path error.", logFileError.Error())
|
|
|
|
+ }
|
|
|
|
+ log.Println("[√]", "open test log file success. path:", logPath)
|
|
|
|
+ }
|
|
|
|
+ return logFile
|
|
|
|
+}
|