I got a working example. It listens on port 12345. When it detects plain http, it forwards to port 12346, where a regular server is listening. Otherwise, it forwards to port 12347 where a TLS server is listening.
At the moment, I check for GET and POST to detect regular http. That is not sufficient. I would like to check for SSH/TLS. TLS starts with byte 0x16. But what starts SSH with?
package main
import (
"fmt"
"log"
"io"
"net"
"net/http"
)
func main() {
go forwarder()
http.HandleFunc("/", hello)
go http.ListenAndServe(":12346", Http(http.DefaultServeMux))
go http.ListenAndServeTLS(":12347", "cert.pem", "key.pem", Https(http.DefaultServeMux))
select{}
}
func forwarder() {
listener, err := net.Listen("tcp", ":12345")
if err != nil {
log.Fatal(err)
}
for {
local, err := listener.Accept()
if err != nil {
log.Fatal(err)
}
sniff := make([]byte, 3)
n, err := local.Read(sniff)
if err != nil && err != io.EOF {
log.Fatal(err)
}
s := string(sniff[:n])
var addr string
if s == "GET"[:n] || s == "POS"[:n] {
addr = ":12346"
} else {
addr = ":12347"
}
remote, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
}
go io.Copy(local, remote)
go func() {
remote.Write(sniff[:n])
io.Copy(remote, local)
}()
}
}
func Http(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "HTTP")
handler.ServeHTTP(w, r)})
}
func Https(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "HTTPS")
handler.ServeHTTP(w, r)})
}
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello world!")
}