Skip to content

Instantly share code, notes, and snippets.

@whiler
Created August 28, 2020 10:26
Show Gist options
  • Save whiler/8f36fc052c128c78047e2829f05cb902 to your computer and use it in GitHub Desktop.
Save whiler/8f36fc052c128c78047e2829f05cb902 to your computer and use it in GitHub Desktop.
sniff TLS hello information
package main
import (
"bytes"
"crypto/tls"
"io"
"net"
"time"
)
type bufferedConn struct {
conn net.Conn
reader io.Reader
}
func (buffered *bufferedConn) Read(b []byte) (n int, err error) { return buffered.reader.Read(b) }
func (buffered *bufferedConn) Write(b []byte) (n int, err error) { return buffered.conn.Write(b) }
func (buffered *bufferedConn) Close() error { return buffered.conn.Close() }
func (buffered *bufferedConn) LocalAddr() net.Addr { return buffered.conn.LocalAddr() }
func (buffered *bufferedConn) RemoteAddr() net.Addr { return buffered.conn.RemoteAddr() }
func (buffered *bufferedConn) SetDeadline(t time.Time) error { return buffered.conn.SetDeadline(t) }
func (buffered *bufferedConn) SetReadDeadline(t time.Time) error {
return buffered.conn.SetReadDeadline(t)
}
func (buffered *bufferedConn) SetWriteDeadline(t time.Time) error {
return buffered.conn.SetWriteDeadline(t)
}
type readOnlyConn struct {
reader io.Reader
}
func (conn *readOnlyConn) Read(p []byte) (int, error) { return conn.reader.Read(p) }
func (conn *readOnlyConn) Write(p []byte) (int, error) { return 0, io.ErrClosedPipe }
func (conn *readOnlyConn) Close() error { return nil }
func (conn *readOnlyConn) LocalAddr() net.Addr { return nil }
func (conn *readOnlyConn) RemoteAddr() net.Addr { return nil }
func (conn *readOnlyConn) SetDeadline(t time.Time) error { return nil }
func (conn *readOnlyConn) SetReadDeadline(t time.Time) error { return nil }
func (conn *readOnlyConn) SetWriteDeadline(t time.Time) error { return nil }
func SniffTLS(conn net.Conn, peek int, timeout time.Duration) (net.Conn, *tls.ClientHelloInfo, error) {
var (
err error
peeked []byte = make([]byte, peek)
n int
clientHelloInfo *tls.ClientHelloInfo
readSeeker io.ReadSeeker
)
if err = conn.SetReadDeadline(time.Now().Add(timeout)); nil != err {
return conn, nil, err
}
if n, err = conn.Read(peeked); nil != err {
if ne, ok := err.(net.Error); !ok || !ne.Timeout() {
return conn, nil, err
}
}
if err = conn.SetReadDeadline(time.Time{}); nil != err {
return conn, nil, err
}
readSeeker = bytes.NewReader(peeked[0:n])
tls.Server(&readOnlyConn{reader: readSeeker}, &tls.Config{
GetConfigForClient: func(info *tls.ClientHelloInfo) (*tls.Config, error) {
clientHelloInfo = info
return nil, nil
},
}).Handshake()
readSeeker.Seek(0, io.SeekStart)
return &bufferedConn{
conn: conn,
reader: io.MultiReader(readSeeker, conn),
}, clientHelloInfo, err
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment