Skip to content

Instantly share code, notes, and snippets.

@AlperRehaYAZGAN
Last active December 27, 2022 17:15
Show Gist options
  • Save AlperRehaYAZGAN/b6ebadb1c05aae851d61ba6cf1df3c66 to your computer and use it in GitHub Desktop.
Save AlperRehaYAZGAN/b6ebadb1c05aae851d61ba6cf1df3c66 to your computer and use it in GitHub Desktop.
Golang TCP Proxy with sni support
package main
import (
"crypto/tls"
"fmt"
"io"
"log"
"net"
"strings"
)
func InitTCPSniProxy() {
// Create a listener for incoming connections.
listener, err := net.Listen("tcp", ":8888")
if err != nil {
log.Fatal(err)
}
defer listener.Close()
// Accept incoming connections and handle them concurrently.
for {
conn, err := listener.Accept()
if err != nil {
log.Println(err)
continue
}
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
// Create an SSL/TLS-encrypted socket for the client.
tlsConn := tls.Server(conn, &tls.Config{
// Set the SNI callback to determine the target host and port.
GetConfigForClient: func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
// Retrieve the SNI value from the client's SSL/TLS handshake.
sni := clientHello.ServerName
log.Printf("SNI: %s\n", sni)
// Determine the target host and port based on the SNI value.
var target string
if strings.HasSuffix(sni, "db.mydomain.com") {
target = "192.168.1.2:3306"
} else if strings.HasSuffix(sni, "redis.mydomain.com") {
target = "192.168.1.3:6379"
} else {
// Return an error if the SNI value is not recognized.
return nil, fmt.Errorf("unrecognized SNI: %s", sni)
}
// Return a new tls.Config with the target host and port.
return &tls.Config{
ServerName: target,
}, nil
},
})
defer tlsConn.Close()
// Connect to the target host and port.
target, err := net.Dial("tcp", tlsConn.ConnectionState().ServerName)
if err != nil {
log.Println(err)
return
}
defer target.Close()
// Transfer data between the client and target.
done := make(chan struct{})
go func() {
_, err := io.Copy(target, tlsConn)
if err != nil {
log.Println(err)
}
target.Close()
done <- struct{}{}
}()
go func() {
_, err := io.Copy(tlsConn, target)
if err != nil {
log.Println(err)
}
tlsConn.Close()
done <- struct{}{}
}()
<-done
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment