Skip to content

Instantly share code, notes, and snippets.

@howardjohn
Created September 11, 2023 18:55
Show Gist options
  • Save howardjohn/94b8b0acc9014517826e8df422f94ab7 to your computer and use it in GitHub Desktop.
Save howardjohn/94b8b0acc9014517826e8df422f94ab7 to your computer and use it in GitHub Desktop.
Trivial TLS proxy. Do not use, its neither tested nor secure.
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"flag"
syscall "golang.org/x/sys/unix"
"io"
"log"
"math/big"
"net"
"os"
"os/signal"
"sync"
"time"
)
var (
remote = flag.String("r", "127.0.0.1:8080", "remote addresses")
)
func main() {
flag.Parse()
go outbound()
go inbound()
WaitSignal()
}
func outbound() {
listener, err := net.Listen("tcp", "0.0.0.0:15001")
if err != nil {
panic(err)
}
for {
conn, err := listener.Accept()
if err != nil {
panic(err)
}
log.Println("accepted outbound connection")
go proxyConn(conn, *remote, true)
}
}
func inbound() {
listener, err := tls.Listen("tcp", "0.0.0.0:15006", generateTLSConfig())
if err != nil {
panic(err)
}
for {
conn, err := listener.Accept()
if err != nil {
panic(err)
}
log.Println("accepted inbound connection")
_, port, _ := net.SplitHostPort(*remote)
go proxyConn(conn, "127.0.0.1:"+port, false)
}
}
func WaitSignal() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
<-sigs
}
func proxyConn(incoming net.Conn, dstIP string, useTLS bool) {
var outgoing net.Conn
if useTLS {
c, err := tls.Dial("tcp", dstIP, generateTLSConfig())
if err != nil {
panic(err)
}
outgoing = c
} else {
c, err := net.Dial("tcp", dstIP)
if err != nil {
panic(err)
}
outgoing = c
}
log.Println("connected to upstream ", outgoing.RemoteAddr().String())
t0 := time.Now()
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
n, err := io.Copy(incoming, outgoing)
log.Printf("upstream complete, wrote=%v, err=%v", n, err)
incoming.Close()
outgoing.Close()
wg.Done()
}()
n, err := io.Copy(outgoing, incoming)
log.Printf("downstream complete, wrote=%v, err=%v", n, err)
incoming.Close()
outgoing.Close()
wg.Wait()
log.Println("connection closed in ", time.Since(t0))
}
func generateTLSConfig() *tls.Config {
key, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
panic(err)
}
template := x509.Certificate{SerialNumber: big.NewInt(1)}
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
if err != nil {
panic(err)
}
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
if err != nil {
panic(err)
}
return &tls.Config{
Certificates: []tls.Certificate{tlsCert},
InsecureSkipVerify: true,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment