Skip to content

Commit 22f42a3

Browse files
blink-so[bot]f0ssel
andcommitted
Refactor to simpler single-port TLS detection pattern
- Use simple byte peek and connection wrapper approach - Eliminate complex buffered reader logic - Use standard http.Serve with single connection listener - Much cleaner and more maintainable implementation - Based on suggested simpler pattern - Should eliminate all the race conditions and complexity Co-authored-by: f0ssel <[email protected]>
1 parent a352df8 commit 22f42a3

File tree

1 file changed

+58
-7
lines changed

1 file changed

+58
-7
lines changed

proxy/proxy.go

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -514,21 +514,34 @@ func (p *Server) handleDecryptedHTTPS(w http.ResponseWriter, r *http.Request) {
514514
func (p *Server) handleConnectionWithTLSDetection(conn net.Conn) {
515515
defer conn.Close()
516516

517-
// Use a buffered reader to peek at the first byte without consuming it
518-
bufReader := bufio.NewReader(conn)
519-
firstByte, err := bufReader.Peek(1)
517+
// Peek at first byte to detect protocol
518+
buf := make([]byte, 1)
519+
_, err := conn.Read(buf)
520520
if err != nil {
521-
p.logger.Debug("Failed to peek at connection data", "error", err)
521+
p.logger.Debug("Failed to read first byte from connection", "error", err)
522522
return
523523
}
524524

525+
// Create connection wrapper that can "unread" the peeked byte
526+
connWrapper := &connectionWrapper{conn, buf, false}
527+
525528
// TLS handshake starts with 0x16 (TLS Content Type: Handshake)
526-
if len(firstByte) > 0 && firstByte[0] == 0x16 {
529+
if buf[0] == 0x16 {
527530
p.logger.Debug("Detected TLS handshake, performing TLS termination")
528-
p.handleTLSTerminationDirect(bufReader, conn)
531+
// Perform TLS handshake
532+
tlsConn := tls.Server(connWrapper, p.tlsConfig)
533+
err := tlsConn.Handshake()
534+
if err != nil {
535+
p.logger.Debug("TLS handshake failed", "error", err)
536+
return
537+
}
538+
p.logger.Debug("TLS handshake successful")
539+
// Use HTTP server with TLS connection
540+
http.Serve(&singleConnectionListener{conn: tlsConn}, http.HandlerFunc(p.handleHTTPS))
529541
} else {
530542
p.logger.Debug("Detected HTTP request, handling normally")
531-
p.handleHTTPConnectionDirect(bufReader, conn)
543+
// Use HTTP server with regular connection
544+
http.Serve(&singleConnectionListener{conn: connWrapper}, http.HandlerFunc(p.handleHTTP))
532545
}
533546
}
534547

@@ -806,6 +819,44 @@ func (p *Server) handleTLSTerminationDirect(bufReader *bufio.Reader, conn net.Co
806819
p.handleTLSConnection(tlsConn, hostname)
807820
}
808821

822+
// connectionWrapper lets us "unread" the peeked byte
823+
type connectionWrapper struct {
824+
net.Conn
825+
buf []byte
826+
bufUsed bool
827+
}
828+
829+
func (c *connectionWrapper) Read(p []byte) (int, error) {
830+
if !c.bufUsed && len(c.buf) > 0 {
831+
n := copy(p, c.buf)
832+
c.bufUsed = true
833+
return n, nil
834+
}
835+
return c.Conn.Read(p)
836+
}
837+
838+
// singleConnectionListener wraps a single connection into a net.Listener
839+
type singleConnectionListener struct {
840+
conn net.Conn
841+
used bool
842+
}
843+
844+
func (sl *singleConnectionListener) Accept() (net.Conn, error) {
845+
if sl.used || sl.conn == nil {
846+
return nil, io.EOF
847+
}
848+
sl.used = true
849+
return sl.conn, nil
850+
}
851+
852+
func (sl *singleConnectionListener) Close() error {
853+
return nil
854+
}
855+
856+
func (sl *singleConnectionListener) Addr() net.Addr {
857+
return sl.conn.LocalAddr()
858+
}
859+
809860
// bufferedConnection wraps a connection with a buffered reader
810861
type bufferedConnection struct {
811862
net.Conn

0 commit comments

Comments
 (0)