Forum Discussion
Kuerten_772
Feb 13, 2014Nimbostratus
APM Irule multiple access profile for one virtual server
Hello F5 Team,
i was asking if is possible to create irule to use multiple profile for one virtual, currently i have one access profile for one vs apm .
Thank you for your help.
Ahmed
Baron_of_Strath
May 22, 2015Historic F5 Account
What you are asking is quite easy to do. I cannot take full credit for it completely. I took the SNI irule published by Joel Moses a few years back and changed it to simply extract the SNI and put that info into the variable called "tls_servername"
If you look at the very bottom, you will see some generic logic to make a virtual call to the value of tls_servername and if that is unsuccessful, to look up the mapping in a datagroup called "Content_Switch_dg" which is simply a mapping of requested hostname to virtualserver name.
when CLIENT_ACCEPTED {
We have a clientssl profile attached to this VIP but we need
to find an SNI record in the client handshake. To do so, we'll
disable SSL processing and collect the initial TCP payload.
set default_tls_pool [LB::server pool]
set detect_handshake 1
TCP::collect
}
when CLIENT_DATA {
set detect_handshake 1
TCP::collect
if { ($detect_handshake) } {
If we're in a handshake detection, look for an SSL/TLS header.
binary scan [TCP::payload] cSS tls_xacttype tls_version tls_recordlen
TLS is the only thing we want to process because it's the only
version that allows the servername extension to be present. When we
find a supported TLS version, we'll check to make sure we're getting
only a Client Hello transaction -- those are the only ones we can pull
the servername from prior to connection establishment.
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 we made it this far, we're still processing a TLS client hello.
Skip the TLS header (43 bytes in) and process the record body. For TLS/1.0 we
expect this to contain only the session ID, cipher list, and compression
list. All but the cipher list will be null since we're handling a new transaction
(client hello) here. We have to determine how far out to parse the initial record
so we can find the TLS extensions if they exist.
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 we're in TLS and we've not parsed all the payload in the record
at this point, then we have TLS extensions to process. We will detect
the TLS extension package and parse each record individually.
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
Loop through the TLS extension data looking for a type 00 extension
record. This is the IANA code for server_name in the TLS transaction.
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") } {
A servername record is present. Pull this value out of the packet data
and save it for later use. We start 9 bytes into the record to bypass
type, length, and SNI encoding header (which is itself 5 bytes long), and
capture the servername text (minus the header).
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 {
Bypass all other TLS extensions.
set start [expr {$start + $elen}]
}
set x $start
}
Check to see whether we got a servername indication from TLS. If so,
make the appropriate changes.
if { ([info exists tls_servername] ) } {
log local0. "Requested host: $tls_servername"
if { [catch { virtual $tls_servername } ]} {
if { $::DEBUG == 1 } { log local0. "Virtual Server $tls_servername doesn't exist...Searching Datagroup"}
if { [class match $tls_servername equals Content_Switch_dg]} {
if { $::DEBUG == 1 } { log local0. "Server found in Datagroup" }
virtual [class lookup $tls_servername Content_Switch_dg]
TCP::release
}
} else {
if { $::DEBUG == 1 } { log local0. "switching to virtual server $tls_servername" }
virtual $tls_servername
TCP::release
}
}
} else {
Servername not found
log local0. "Servername could not be determined"
}
}
}
}
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects