Forum Discussion
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_StrathHistoric F5 Account
Since I am apparently not able to edit, there was a small point of clarification about assigning the apm policy to the virtual servers which would be called from this irule:
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. As above, you would then create and apply your APM policy to the appropriate virtuals and everything would be nicely published behind a single public IP.
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" } } } }
- Jeppe_KoefoedEmployeeThe SNI part can be done easier: when CLIENTSSL_HANDSHAKE { set sni_exists [SSL::extensions exists -type 0] log local0.info "SSL extension type 0 exists: $sni_exists" if {$sni_exists} { set scan [binary scan [SSL::extensions -type 0] S1S1@9A* ext_type ext_len sni] log local0.info "SSL extension type 0 (SNI): $sni" } }
- Sam_NovakAltostratus
Not sure if anyone will stumble across this, but I was recently trying to figure this out for a Edge client setup. I wanted a single VS hosting the sign in, but then the policy and connectivity assignment were throwing me for a loop.
What I ended up doing was using an iRule to check the landinguri the client was sending, and then I used branches on the iRule event to assign different Webtops and Network Access assignments based on the requested location.
when ACCESS_POLICY_AGENT_EVENT { if { [ACCESS::policy agent_id] eq "VPN_Resource_Check" } { log local0. "Current virtual server name: [virtual name]" log local0. "Current virtual server name: [HTTP::host]" log local0. "Current virtual server name: [SSL::sni name]" log local0. "[ACCESS::session data get session.server.landinguri]" switch [string tolower [ACCESS::session data get session.server.landinguri]] { "/nursing" { ACCESS::session data set session.custom.vpn "nursing" } } } }
Recent Discussions
Related Content
* 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