-
-
Save ego008/1884a840d09bd73027c7f19ea1cb00e3 to your computer and use it in GitHub Desktop.
Minimal TLS MITM transparent proxy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* tlsprox - minimal tls MITM transparent proxy... in go! | |
* by @tam7t | |
* | |
* Usage: | |
* If we want to MITM https://example.com first get example.com's ip address | |
* then add localhost to /etc/hosts: | |
* | |
* 127.0.0.1 example.com | |
* | |
* > go build tlsprox.go | |
* > sudo ./tlsprox.go -raddr=<example.com ip addr>:443 | |
*/ | |
package main | |
import ( | |
"crypto/tls" | |
"flag" | |
"io" | |
"log" | |
"net" | |
"os" | |
) | |
func main() { | |
var certFile, keyFile, listenAddr, remoteAddr string | |
flag.StringVar(&certFile, "cert", "cert.pem", "certificate") | |
flag.StringVar(&keyFile, "key", "key.pem", "key") | |
flag.StringVar(&listenAddr, "laddr", ":443", "listener address") | |
flag.StringVar(&remoteAddr, "raddr", "8.8.8.8:443", "remote address") | |
flag.Parse() | |
var cert, _ = tls.LoadX509KeyPair(certFile, keyFile) | |
var tlsConfig = tls.Config{ | |
Certificates: []tls.Certificate{cert}, | |
} | |
log.Println("starting server") | |
listener, err := tls.Listen("tcp", listenAddr, &tlsConfig) | |
if err != nil { | |
log.Printf("could not listen for connections: ", err.Error()) | |
os.Exit(1) | |
} | |
defer listener.Close() | |
for { | |
conn, err := listener.Accept() | |
conn.(*tls.Conn).Handshake() | |
if err != nil { | |
log.Printf("error accepting connection: %s", err) | |
} else { | |
log.Printf("accepted from %s", conn.RemoteAddr()) | |
go handleConnection(conn, remoteAddr) | |
} | |
} | |
} | |
func handleConnection(conn net.Conn, remote string) { | |
defer conn.Close() | |
// make connection to remote | |
// When using /etc/hosts to set host=localhost for MITM, you cannot make the | |
// remote connection by hostname. Using ip for the tls connection will fail on | |
// cert validation so InsecureSkipVerify is set to true | |
remoteConn, err := tls.Dial("tcp", remote, &tls.Config{InsecureSkipVerify: true}) | |
if err != nil { | |
log.Print("failed to connect to remote: " + err.Error()) | |
return | |
} | |
defer remoteConn.Close() | |
remoteConn.Handshake() | |
serverClosed := make(chan struct{}, 1) | |
clientClosed := make(chan struct{}, 1) | |
go broker(remoteConn, conn, clientClosed) // forward client to remote | |
go broker(conn, remoteConn, serverClosed) // forward remote to client | |
// wait for one side of the connection to close | |
// and then signal the other side of the connection to close | |
var waitFor chan struct{} | |
select { | |
case <-clientClosed: | |
remoteConn.Close() | |
waitFor = serverClosed | |
case <-serverClosed: | |
conn.Close() | |
waitFor = clientClosed | |
} | |
// wait for the other side to finish shutting down | |
<-waitFor | |
log.Println("server: conn: closed") | |
} | |
// modified from | |
// https://gist.github.com/jbardin/821d08cb64c01c84b81a | |
func broker(dst, src net.Conn, srcClosed chan struct{}) { | |
io.Copy(dst, src) // blocks until either EOF on src or an error occurs | |
src.Close() | |
srcClosed <- struct{}{} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment