APM Portal Access for SNI Targets

Problem this snippet solves:

Background.

A portal Access link is designed to proxy access to another webserver. This might be internal to the network and thus not directly available to the client. It might be an external server such as mail or an externally hosted intranet.

The Problem.

An external server should be using https. However the hosting company may be using SNI to operate name based hosting. This is where the client offers the name of the target server as part of the TLS CLIENT_HELLO. The server will then present the correct certificate to the client.

But if the client does not, the server may well terminate the connection. It may offer a handshake failure, or just RST the tcp connection.

When a portal access link is clicked for a https server, the connection is established by the VIP using the Server-SSL profile attached to it.. This does not have a "Server Name" (SNI) field set so a SNI requiring destination will drop the connection.

The simple solution of adding a Server Name field does not work because:

  • Its shared across all Portal Access links, so it won't be right if there are more that one.
  • A site might start going to www.example.com but multiple connections will be established to other servers. doubleclick, facebook, google analytics, so the SNI connection will be wrong.

As of version 13.1, there is no official F5 "one tick" solution for this.

How to use this snippet:

The Solution.

We need to pick the hostname that the re-writer is going to use and patch the Server SSL connection to have that as the SNI name. We need to add 2 irules to our VIP. One to get the hostname and then to patch the outgoing TLS connection with that name. They must be in that order.

If you are wondering about set ext_exists [SSL::extensions exists -type 0]

This will work on all V11.2 or later systems. In V12 and later we can test for SSL::SNI name directly. We wont use that.

Credits to whomever wrote the SSL::extensions insert command!

Code :

ltm rule /Common/rewrite_get_host {
    when REWRITE_REQUEST_DONE {
  set sni_name [HTTP::host]
}
}


ltm rule /Common/rewrite_set_SNI {
    when SERVERSSL_CLIENTHELLO_SEND {
# cant add if already there.

set ext_exists [SSL::extensions exists -type 0]

if {$ext_exists eq 0 } {
# log  -noname local0.info  "No Server SNI, adding"
if { $sni_name ne "" } {
SSL::extensions insert [binary format SSScSa* 0 [expr { [set sni_length [string length $sni_name]] + 5 }] [expr { $sni_length + 3 }] 0 $sni_length $sni_name]
# log -noname local0. "added SNI $sni_name"
return
}
log -noname local0. "sni_name was empty, not adding to SERVERSSL_CLIENTHELLO"
return
}

# Some optional debug logging.
#log -noname local0.info "SSL extension type 0 (SNI) exists"
#set scan [binary scan [SSL::extensions -type 0] S1S1S1c1S1H* ext_type ext_len list_length ext_type2 name_length sni_name_hex]
#set sni_name [binary format H* $sni_name_hex]
#log -noname local0.info "SSL extension type 0: (scan: $scan, type: $ext_type, ext_len: $ext_len, list_length: $list_length, ext_type2: $ext_type2, name_length: $name_length, sni_name, $sni_name)"
}
}

Tested this on version:

11.4
Published Apr 09, 2018
Version 1.0

Was this article helpful?

3 Comments

  • This is part of ID653495 Inappropriate SNI hostname attached to serverside connections

     

    K05411532: The BIG-IP system fails to rewrite the SNI host name to the server name specified in the Server SSL profile https://support.f5.com/csp/article/K05411532

     

    So hopefully this is not needed with versions 13.1 and later.

     

  • As of 15.0.0 this behavior still occurs in my environment and this solution still works properly. Saved the day.

  • Hi Lapsio, Glad it helped.

    https://support.f5.com/csp/article/K05411532

    says its fixed, but portal rewrite does odd things!

     

    Regards, John