Below is my simple static "SSL Proxy" that listens on port 8000, and connects to another machine 10.3.0.124:443, and the proxy logs traffic both ways on screen.
To generate key.pem and cert.pem, you can use openssl, or use go team's simple program included in go package: http://golang.org/src/pkg/crypto/tls/generate_cert.go
package main
import (
"io"
"log"
"net"
"fmt"
"os"
"crypto/tls"
"crypto/rand"
)
func checkError(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
}
/* slower, by we can print/log everything */
func myrawcopy(dst,src net.Conn) (written int64, err error) {
buf := make([]byte, 32*1024)
for {
nr, er := src.Read(buf)
if nr > 0 {
fmt.Printf("%s",string(buf[0:nr]));
nw, ew := dst.Write(buf[0:nr])
if nw > 0 {
written += int64(nw)
}
if ew != nil {
err = ew
break
}
if nr != nw {
err = io.ErrShortWrite
break
}
}
if er == io.EOF {
break
}
if er != nil {
err = er
break
}
}
return written, err
}
func myiocopy(dst net.Conn, src net.Conn){
myrawcopy(dst, src)
//io.Copy(dst,src);
dst.Close();
src.Close();
}
func handleclient(c net.Conn){
config := tls.Config{InsecureSkipVerify: true}
conn, err := tls.Dial("tcp", "10.3.0.124:443", &config)
checkError(err)
go myiocopy(conn,c)
//io.Copy(c, conn)
myrawcopy(c, conn)
c.Close()
conn.Close();
}
func main() {
cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
if err != nil {
log.Fatalf("server: loadkeys: %s", err)
}
config := tls.Config{Certificates: []tls.Certificate{cert}}
config.Rand = rand.Reader
service := "0.0.0.0:8000"
listener, err := tls.Listen("tcp", service, &config)
if err != nil {
log.Fatalf("server: listen: %s", err)
}
log.Printf("server: listening on %s for https, connects to https://10.3.0.124:443",service)
for {
conn, err := listener.Accept()
if err != nil {
log.Printf("server: accept: %s", err)
break
}
defer conn.Close()
log.Printf("server: accepted from %s", conn.RemoteAddr())
go handleclient(conn)
}
}
Why are you initializing config.Rand? The default is fine.
ReplyDeleteActually it is the same, by default it's using rand.Rand, but that's an implementation detail: http://golang.org/src/pkg/crypto/tls/common.go Line 277
DeleteHello, I stumbled up on your blog while tryign to find solution of my question at http://stackoverflow.com/questions/21562269/golang-how-to-specify-certificate-in-tls-config-for-http-client can you help me to find out as how can I achieve what I am looking for?
ReplyDeletedmwm2 has this patch:
ReplyDeleteI've got the Windows client connecting through your proxy, which is
useful. It actually receives the certificate MD5 *from* the server,
which is kind of pointless, and requires the following hack (replace
cert hashes as appropriate, of course):
@@ -18,12 +20,15 @@ func checkError(err error) {
}
/* slower, by we can print/log everything */
-func myrawcopy(dst,src net.Conn) (written int64, err error) {
+func myrawcopy(dst,src net.Conn, direction string) (written int64, err error) {
buf := make([]byte, 32*1024)
+ realcert := []byte("cert_md5=90ab8294b0c3fe0b84af563bb4adf37c")
+ mycert := []byte("cert_md5=be9ac5a0dac73483037315ac51b81beb")
for {
nr, er := src.Read(buf)
if nr > 0 {
- fmt.Printf("%s",string(buf[0:nr]));
+ buf := bytes.Replace(buf, realcert, mycert, 1)
+ fmt.Printf("Packet %s:\n%s",direction, hex.Dump(buf[0:nr]));
nw, ew := dst.Write(buf[0:nr])
if nw > 0 {
written += int64(nw)
You might want to remove 'defer conn.Close()' in the main function. It will cause memory leak.
ReplyDeleteHi All,
ReplyDeleteCan someone help explaining how can we use proxy IP & port for below code.
tls.Dial("tcp", "10.3.0.124:443", &config)
Assume that I want to connect to 10.3.0.124 on port 443 but my network has proxy in IE setting.
Thanks in Advance.