Skip to content

Race condition during SNI extraction when TLS ClientHello is fragmented leading to ssl-passthrough being "ignored" #11491

@alshain

Description

@alshain

I believe I stumbled over a problem related to tldr.fail, where SNI extraction might fail with large TLS ClientHellos and SSL-passthrough.

Due to a race condition when reading the buffer used for the SNI extraction, the extraction fails but the failure is ignored and we default to the default proxy target.

length, err := conn.Read(data)

func (p *TCPProxy) Handle(conn net.Conn) {
	defer conn.Close()
	// See: https://www.ibm.com/docs/en/ztpf/1.1.0.15?topic=sessions-ssl-record-format
	data := make([]byte, 16384)

	// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
        // suppose the ClientHello is fragmented over multiple packets, 
        // data might only contain a partial ClientHello where the SNI data isn't present yet
	length, err := conn.Read(data)  
	if err != nil {
		klog.V(4).ErrorS(err, "Error reading data from the connection")
		return
	}

	proxy := p.Default  
	hostname, err := parser.GetHostname(data)
	// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	if err == nil {  // <--- err will not be nill, so we skip this, proxy remains p.Default
		klog.V(4).InfoS("TLS Client Hello", "host", hostname)
		proxy = p.Get(hostname)
	}

	// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	if proxy == nil {   // because we have p.Default, we skip this
		klog.V(4).InfoS("There is no configured proxy for SSL connections.")
		return
	}
	// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
        // now we forward traffic to NGINX instead of the proper passthrough target

	hostPort := net.JoinHostPort(proxy.IP, fmt.Sprintf("%v", proxy.Port))

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugCategorizes issue or PR as related to a bug.lifecycle/frozenIndicates that an issue or PR should not be auto-closed due to staleness.needs-priorityneeds-triageIndicates an issue or PR lacks a `triage/foo` label and requires one.

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions