A couple of things to consider:
1. SNI is a method for selecting different client SSL profiles based on the TLS v1.0 server name extension. As the description implies, you need at least one client SSL profile applied to the virtual server (decrypting the traffic). If you can't decrypt the traffic with a client SSL profile, then you cannot use the SNI feature in the client SSL profile.
2. SNI is an extension to TLS v1.0, so a client that didn't support this extension would be sent the "default" option (client SSL profile certificate or default pool selection in this case).
Assuming you cannot terminate the SSL, and that you're okay with limitations in 2 above, have a look at Joel Moses' most-excellent SNI iRule on DevCentral (
https://devcentral.f5.com/wiki/iRules.TLS-ServerNameIndication.ashx). I've taken the liberty of boiling this iRule down to something that might work for you. The below doesn't require a client SSL profile. Assign a "default" pool to the virtual server, this iRule, and create a string data group. Adjust the static::SERVERNAME_GROUP variable to match your data group's name.
server name := pool name
I've stripped out all of the client SSL profile selection stuff and simply added a pool selection based on the returned tls_servername variable and data group match. If the client supports the extension, and the requested server name is in the data group, they'll be pooled accordingly. Otherwise the client will go to the default pool. You might consider using a local web server in the default pool that tells the client to use the name (versus IP address) and a browser that supports TLS v1.0 (and higher).
when RULE_INIT {
User-defined: server name to pool matching data group
set static::SERVERNAME_GROUP "my_sni_group"
}
when CLIENT_ACCEPTED {
TCP::collect
}
when CLIENT_DATA {
set detect_handshake 1
binary scan [TCP::payload] cSS tls_xacttype tls_version tls_recordlen
switch $tls_version {
"769" -
"770" -
"771" {
if { ($tls_xacttype == 22) } {
binary scan [TCP::payload] @5c tls_action
if { not (($tls_action == 1) && ([TCP::payload length] > $tls_recordlen)) } {
set detect_handshake 0
}
}
}
default {
set detect_handshake 0
}
}
if { ($detect_handshake) } {
if { [catch {
set record_offset 43
binary scan [TCP::payload] @${record_offset}c tls_sessidlen
set record_offset [expr {$record_offset + 1 + $tls_sessidlen}]
binary scan [TCP::payload] @${record_offset}S tls_ciphlen
set record_offset [expr {$record_offset + 2 + $tls_ciphlen}]
binary scan [TCP::payload] @${record_offset}c tls_complen
set record_offset [expr {$record_offset + 1 + $tls_complen}]
if { ([TCP::payload length] >= $record_offset) } {
binary scan [TCP::payload] @${record_offset}S tls_extenlen
set record_offset [expr {$record_offset + 2}]
binary scan [TCP::payload] @${record_offset}a* tls_extensions
for { set x 0 } { $x < $tls_extenlen } { incr x 4 } {
set start [expr {$x}]
binary scan $tls_extensions @${start}SS etype elen
if { ($etype == "00") } {
set grabstart [expr {$start + 9}]
set grabend [expr {$elen - 5}]
binary scan $tls_extensions @${grabstart}A${grabend} tls_servername
set start [expr {$start + $elen}]
} else {
set start [expr {$start + $elen}]
}
set x $start
}
if { ([info exists tls_servername] ) } {
If tls_servername exists then the client supports the TLS server name extension.
Otherwise send traffic to the default pool
if { [class match $tls_servername equals $static::SERVERNAME_GROUP] } {
log local0. "Server name match - sending to: [class match -value $tls_servername equals $static::SERVERNAME_GROUP]"
pool [class match -value $tls_servername equals $static::SERVERNAME_GROUP]
} else {
server name doesn't exist in data group - send to default pool
log local0. "No server name match - using default pool"
}
} else {
log local0. "No server name support - using default pool"
}
}
set detect_handshake 0
TCP::release
} fid] } {
log local0. "Error: probably not supporting TLS server name extension - using default pool"
set detect_handshake 0
TCP::release
}
} else {
log local0. "Not a handshake"
set detect_handshake 0
TCP::release
}
}