TCP/UDP 端口转发(Google Voice 可用)

自己写的tcp/udp 转发工具,附部分源码。原先使用haproxy转发流量,提供的功能很强大,性能也很好,后来用Google Volce的时候发现用不了,不支持udp流量转发,于是自己动手写一个简易转发工具,自测可用。

1.TCP部分源码

func handle(client net.Conn, server string, output string) {
   if client == nil {
      return
   }
   log.Println("TCP handle new connection.")
   defer client.Close()
   destConn, err := net.DialTimeout("tcp", server+output, time.Second*3)

   if err != nil {
      log.Println(err)
      return
   }

   defer destConn.Close()
   //将客户端的请求转发至服务端,将服务端的响应转发给客户端。io.Copy为阻塞函数,文件描述符不关闭就不停止
   relay(client, destConn)
   log.Println("TCP handle close connection.")
}

// relay copies between left and right bidirectionally
func relay(left, right net.Conn) error {
   var err, err1 error
   var wg sync.WaitGroup
   var wait = 5 * time.Second
   wg.Add(1)
   go func() {
      defer wg.Done()
      _, err1 = io.Copy(right, left)
      right.SetReadDeadline(time.Now().Add(wait)) // unblock read on right
   }()
   _, err = io.Copy(left, right)
   left.SetReadDeadline(time.Now().Add(wait)) // unblock read on left
   wg.Wait()
   if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) { // requires Go 1.15+
      return err1
   }
   if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) {
      return err
   }
   return nil
}


2.UDP部分源码

type UDPCap struct {
   ClientAddr *net.UDPAddr // Address of the client
   ServerConn *net.UDPConn // UDP connection to server
}

type UDPCapsLock struct {
   UDPCaps map[string]*UDPCap
   Lock    sync.Mutex
}

// Generate a new connection by opening a UDP connection to the server
func NewConnection(srvAddr, cliAddr *net.UDPAddr) *UDPCap {
   conn := new(UDPCap)
   conn.ClientAddr = cliAddr
   srvudp, err := net.DialUDP("udp", nil, srvAddr)
   if checkreport(1, err) {
      return nil
   }
   conn.ServerConn = srvudp
   return conn
}

func setup(hostport string, port int) {
   // Set up Proxy
   saddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
   if checkreport(1, err) {
   }
   localConn, err := net.ListenUDP("udp", saddr)
   if checkreport(1, err) {
   }
   logf("UDP Proxy serving on port %d\n", port)

   // Get server address
   ServerAddr, err := net.ResolveUDPAddr("udp", hostport)
   if checkreport(1, err) {
   }
   logf("UDP Connected to server at %s\n", hostport)
   RunProxy(localConn, ServerAddr)
}

// Go routine which manages connection from server to single client
func RunConnection(conn *UDPCap, udpcapsLock UDPCapsLock, localConn *net.UDPConn) {
   var buffer [1500]byte
   for {
      // Read from server
      conn.ServerConn.SetReadDeadline(time.Now().Add(time.Minute * 5))
      n, err := conn.ServerConn.Read(buffer[0:])
      if checkreport2(1, err) == 1 {
         //删除
         log.Println("udp delete timeout router")
         udpcapsLock.Lock.Lock()
         conn.ServerConn.Close()
         delete(udpcapsLock.UDPCaps, conn.ClientAddr.String())
         udpcapsLock.Lock.Unlock()
         break
      }
      // Relay it to client
      _, err = localConn.WriteToUDP(buffer[0:n], conn.ClientAddr)

   }
}

// Routine to handle inputs to Proxy port
func RunProxy(localConn *net.UDPConn, ServerAddr *net.UDPAddr) {
   var buffer [1500]byte
   log.Println("UDP start")
   var uncapsLock UDPCapsLock
   uncapsLock.UDPCaps = map[string]*UDPCap{}
   for {
      n, cliaddr, err := localConn.ReadFromUDP(buffer[0:])
      if checkreport(1, err) {
         continue
      }
      //Vlogf(3, "UDP Read sth. from client %s, routers length %d \n", cliaddr.String(), len(uncapsLock.UDPCaps))
      saddr := cliaddr.String()
      udpcap, found := uncapsLock.UDPCaps[saddr]
      if !found {
         udpcap = NewConnection(ServerAddr, cliaddr)
         if udpcap == nil {
            continue
         }
         uncapsLock.Lock.Lock()
         uncapsLock.UDPCaps[saddr] = udpcap
         uncapsLock.Lock.Unlock()
         logf("UDP Created new connection for client %s  routers length %d \n", saddr, len(uncapsLock.UDPCaps))
         // Fire up routine to manage new connection
         go RunConnection(udpcap, uncapsLock, localConn)
      }

      // Relay to server
      _, err = udpcap.ServerConn.Write(buffer[0:n])
      if checkreport(1, err) {
         continue
      }
   }
}

3.forward工具下载
提取码: zus5 复制这段内容后打开百度网盘手机App,操作更方便哦


4.configs.json

[
  {
    "inport": 13531,
    "outport": 13531,
    "server": "127.0.0.1"
  },
  {
    "inport": 13532,
    "outport": 13532,
    "server": "127.0.0.1"
  },
  {
    "inport": 13533,
    "outport": 13533,
    "server": "127.0.0.1"
  }
]


5.打开方式

./forward ./configs.json &