package main import ( "context" "crypto/tls" "io" "log" "net" ) type TCP struct { config *Config } func NewTCPServer(c *Config) TCP { return TCP{config: c} } func (tcp TCP) Listen() error { ln, err := net.Listen("tcp", tcp.config.Listen) if err != nil { return err } defer ln.Close() log.Println("accepting tcp on", tcp.config.Listen) for { conn, err := ln.Accept() if err != nil { return err } go func() { defer conn.Close() conn2, err := func() (net.Conn, error) { if tcp.config.TCPProxyTLS { return tls.Dial("tcp", tcp.config.TCPProxy, &tls.Config{}) } return net.Dial("tcp", tcp.config.TCPProxy) }() if err != nil { log.Println(err) return } defer conn2.Close() ctx, can := context.WithCancel(context.Background()) defer can() errc := make(chan error) go func() { _, err := io.Copy(conn, conn2) select { case errc <- err: case <-ctx.Done(): close(errc) } }() go func() { _, err := io.Copy(conn2, conn) select { case errc <- err: case <-ctx.Done(): close(errc) } }() <-errc }() } }