Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
# CHANGELOG

## v1.20.5 (31 January 2026)

- Fixed HTTP/2 compatibility issue with MITM connections in transparent proxy mode
- MITM connections now bypass early SNI extraction to avoid connection wrapper issues

## v1.20.4 (31 January 2026)

- Fix transparent HTTPS mode showing IP addresses instead of domain names
- Fixed SNI extraction to enable domain-based rule matching in transparent proxy mode
- Fixed multiple SNI parsing bugs in TLS Client Hello parser (length calculation and data extraction)
- Fixed connection handling in transparent proxy to properly forward TLS handshake data
- Improved error handling: fall back to direct tunnel instead of closing connection when ClientHello parsing fails
- Added diagnostic logging for SNI extraction failures

## v1.20.3 (31 January 2026)

- Fixed connection handling in transparent proxy to properly forward TLS handshake data

## v1.20.2 (31 January 2026)

- Fixed multiple SNI parsing bugs in TLS Client Hello parser (length calculation and data extraction)

## v1.20.1 (31 January 2026)

- Fix transparent HTTPS mode showing IP addresses instead of domain names
- Fixed SNI extraction to enable domain-based rule matching in transparent proxy mode

## v1.20.0 (31 January 2026)

- Fix transparent mode not picking up rules or logging traffic.
Expand Down
72 changes: 27 additions & 45 deletions gatesentryproxy/transparent_listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,20 +175,33 @@ func (l *TransparentProxyListener) handleTransparentHTTPS(conn net.Conn, origina

passthru := NewGSProxyPassthru()

// Get the underlying real connection from the prependConn
// First, check if MITM is enabled for this destination (using IP-based check initially)
shouldMitm := false
if IProxy != nil && IProxy.DoMitm != nil {
shouldMitm = IProxy.DoMitm(serverAddr)
}

// For MITM connections, pass directly to SSLBump which handles SNI extraction internally
// This avoids connection wrapper issues with HTTP/2
if shouldMitm {
if DebugLogging {
log.Printf("[Transparent] Performing SSL Bump for %s", serverAddr)
}
SSLBump(conn, serverAddr, user, "", nil, passthru, l.ProxyHandler.Iproxy)
return
}

// For non-MITM connections, read ClientHello to extract SNI for logging and rules
var realConn net.Conn
if pc, ok := conn.(*prependConn); ok {
realConn = pc.Conn
} else {
realConn = conn
}

// Read the TLS Client Hello to extract SNI (domain name) BEFORE rule matching
clientHello, err := gsClientHello.ReadClientHello(conn)
if err != nil {
log.Printf("[Transparent] Error reading client hello for %s: %v, falling back to direct tunnel", serverAddr, err)
// Fall back to direct tunnel with whatever data we got
// Create a fresh prependConn with the partial data we read
if len(clientHello) > 0 {
freshConn := &prependConn{
Conn: realConn,
Expand All @@ -198,7 +211,6 @@ func (l *TransparentProxyListener) handleTransparentHTTPS(conn net.Conn, origina
LogProxyAction("https://"+serverAddr, user, ProxyActionSSLDirect)
ConnectDirect(freshConn, serverAddr, nil, passthru)
} else {
// No data read at all, just close
conn.Close()
}
return
Expand All @@ -224,13 +236,9 @@ func (l *TransparentProxyListener) handleTransparentHTTPS(conn net.Conn, origina
ruleMatchHost = serverName
}

// Check proxy rules using the domain name (SNI) instead of IP
shouldBlock, ruleMatch, ruleShouldMitm := CheckProxyRules(ruleMatchHost, user)
// Check proxy rules
shouldBlock, ruleMatch, _ := CheckProxyRules(ruleMatchHost, user)
if shouldBlock {
if DebugLogging {
log.Printf("[Transparent] Blocking HTTPS connection to %s (SNI: %s) by rule", serverAddr, serverName)
}
// Log with domain name if available
logUrl := "https://" + serverAddr
if serverName != "" {
logUrl = "https://" + serverName
Expand All @@ -240,54 +248,28 @@ func (l *TransparentProxyListener) handleTransparentHTTPS(conn net.Conn, origina
return
}

// Store rule match data for later use (MITM decision, URL regex checking)
if ruleMatch != nil {
passthru.UserData = ruleMatch
}

shouldMitm := false
if IProxy != nil && IProxy.DoMitm != nil {
// Use domain for MITM decision if available
mitmCheckHost := serverAddr
if serverName != "" {
mitmCheckHost = net.JoinHostPort(serverName, port)
}
shouldMitm = IProxy.DoMitm(mitmCheckHost)
}

// If rule matched and specified MITM setting, use it
if ruleMatch != nil {
shouldMitm = ruleShouldMitm
}

// Use domain name for logging if available
// Log with domain name if available
logUrl := "https://" + serverAddr
if serverName != "" {
logUrl = "https://" + serverName
}

// Create a fresh prependConn with the clientHello data and the real underlying connection
// This reconstructs the connection state as if clientHello wasn't read yet
if DebugLogging {
log.Printf("[Transparent] Direct tunnel for %s (SNI: %s)", serverAddr, serverName)
}
LogProxyAction(logUrl, user, ProxyActionSSLDirect)

// Create fresh connection with clientHello for tunneling
freshConn := &prependConn{
Conn: realConn,
buf: clientHello,
offset: 0,
}

if shouldMitm {
if DebugLogging {
log.Printf("[Transparent] Performing SSL Bump for %s (SNI: %s)", serverAddr, serverName)
}
SSLBump(freshConn, serverAddr, user, "", nil, passthru, l.ProxyHandler.Iproxy)
} else {
if DebugLogging {
log.Printf("[Transparent] Direct tunnel for %s (SNI: %s)", serverAddr, serverName)
}
LogProxyAction(logUrl, user, ProxyActionSSLDirect)
// Pass freshConn with nil extraData - io.Copy will read clientHello from buffer
// This matches the original behavior before SNI extraction was added
ConnectDirect(freshConn, serverAddr, nil, passthru)
}
ConnectDirect(freshConn, serverAddr, nil, passthru)
}

type prependConn struct {
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var GSPROXYPORT = "10413"
var GSWEBADMINPORT = "10786"
var GSBASEDIR = ""
var Baseendpointv2 = "https://www.gatesentryfilter.com/api/"
var GATESENTRY_VERSION = "1.20.4"
var GATESENTRY_VERSION = "1.20.5"
var GS_BOUND_ADDRESS = ":"
var R *application.GSRuntime

Expand Down
Loading