TCP Proxy
package main
import (
"io"
"log"
"net"
"sync"
)
type TCPProxy struct {
listenAddr string
targetAddr string
}
func NewTCPProxy(listenAddr, targetAddr string) *TCPProxy {
return &TCPProxy{
listenAddr: listenAddr,
targetAddr: targetAddr,
}
}
func (p *TCPProxy) Serve() error {
listener, err := net.Listen("tcp", p.listenAddr)
if err != nil {
return err
}
defer listener.Close()
log.Printf("tcp proxy listening at: %s\n", listener.Addr())
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("listener accept error: %s\n", err)
continue
}
go p.handleConnection(conn)
}
}
func (p *TCPProxy) handleConnection(conn net.Conn) {
defer conn.Close()
log.Printf("accepted new connection %s\n", conn.RemoteAddr())
targetConn, err := net.Dial("tcp", p.targetAddr)
if err != nil {
log.Printf("dial target addr: %s error: %s\n", p.targetAddr, err)
return
}
defer targetConn.Close()
log.Printf("tcp proxy client addr: %s\n", targetConn.LocalAddr())
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
n, err := io.Copy(conn, targetConn)
if err != nil {
log.Printf("copy bytes from %s to %s error: %s", conn.RemoteAddr(), targetConn.RemoteAddr(), err)
return
}
log.Printf("copied %d bytes from %s to %s", n, conn.RemoteAddr(), targetConn.RemoteAddr())
}()
go func() {
defer wg.Done()
n, err := io.Copy(targetConn, conn)
if err != nil {
log.Printf("copy bytes from %s to %s error: %s", targetConn.RemoteAddr(), conn.RemoteAddr(), err)
return
}
log.Printf("copied %d bytes from %s to %s", n, targetConn.RemoteAddr(), conn.RemoteAddr())
}()
wg.Wait()
}
func main() {
proxy := NewTCPProxy("127.0.0.1:8080", "127.0.0.1:8081")
if err := proxy.Serve(); err != nil {
log.Fatal(err)
}
}
Server
package main
import (
"bufio"
"log"
"net"
)
func handle(conn net.Conn) {
defer conn.Close()
reader := bufio.NewReader(conn)
for {
var buf [512]byte
n, err := reader.Read(buf[:])
if err != nil {
log.Printf("read from client err: %s\n", err)
break
}
log.Printf("read %d bytes from client\n", n)
recvStr := string(buf[:n])
log.Printf("received data from client: %s\n", recvStr)
n, err = conn.Write([]byte(recvStr))
if err != nil {
log.Printf("write data to client err: %s\n", err)
return
}
log.Printf("write %d bytes to client\n", n)
}
}
func main() {
listener, err := net.Listen("tcp", "127.0.0.1:8081")
if err != nil {
log.Fatal(err)
}
log.Printf("server listening at: %s\n", listener.Addr())
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("listener accept error: %s\n", err)
continue
}
go handle(conn)
}
}
Client
package main
import (
"bufio"
"log"
"net"
"os"
"strings"
)
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:8080")
if err != nil {
log.Fatal(err)
}
log.Printf("client addr: %s\n", conn.LocalAddr())
defer conn.Close()
inputReader := bufio.NewReader(os.Stdin)
for {
input, _ := inputReader.ReadString('\n')
inputInfo := strings.Trim(input, "\r\n")
if strings.ToUpper(inputInfo) == "Q" {
return
}
n, err := conn.Write([]byte(inputInfo))
if err != nil {
log.Printf("write data to server err: %s\n", err)
return
}
log.Printf("write %d bytes to server\n", n)
buf := [512]byte{}
n, err = conn.Read(buf[:])
if err != nil {
log.Printf("read data from server err: %s\n", err)
return
}
log.Printf("read %d bytes from server\n", n)
log.Printf("received data from server: %s\n", string(buf[:n]))
}
}