Forum Discussion

minnkhank12_304's avatar
minnkhank12_304
Icon for Nimbostratus rankNimbostratus
Jan 03, 2017

Solution For O365 SSL forward Proxy ByPass

May i ask you a question?

  { I want to know how can i get only ssl 443 traffic O365 going pass through directly to internet and all other traffic http & https going pass through to pool(bluecoat) for proxy internet. 

So, how can i write irule for this issue. Please can you help me.}

  • The answer here depends on how you're doing the forward proxy. Are you doing SSL forward proxy, where you're decrypting, sending decrypted data to the Blue Coat devices, and the re-encrypting? Or simply load balancing encrypted traffic to the Blue Coat?

     

    If the latter, then you're generally limited to destination addresses, though you could conceivably make the decision based on the ClientHello SNI value.

     

  • Dear Kevin Stewart,

     Thank you for your support. As our diagram, all traffic pass through the blue coat proxy expect office 365 traffic. The green line is a bypass traffic directly to internet. Our solution want only O365 traffic go through from bypass to reduced the load on blue coat. Please can you help me as well as you can.
    
  • So minimally you'd have two pools:

     

    1. The pool of BC proxies
    2. The pool of routers on the other side of the BCs

    Based on some criteria, you'd select the BC or router (bypass) pool. The question then becomes what criteria to use. If you know the destination IP addresses for O365 resources, then it's super easy to switch pools based on the destination IP. If you don't know the IPs, and because you're not decrypting at the F5, you may have to collect and use the ClientHello SNI value (for encrypted traffic) or the HTTP host header (for unencrypted traffic).

     

  • Since you're grabbing the ClientHello SNI without decrypting the packet, you'll be doing it at OSI layer 4. Here's what that iRule would look like.

    when CLIENT_ACCEPTED priority 300 {
        set detect_handshake 1
        TCP::collect
    }
    when CLIENT_DATA priority 200 {
        binary scan [TCP::payload] H* orig
        if { [binary scan [TCP::payload] cSS tls_xacttype tls_version tls_recordlen] < 3 } {
            reject
            return
        }
    
         768 SSLv3.0
         769 TLSv1.0
         770 TLSv1.1
         771 TLSv1.2
        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
                    }
                }
            }
            "768" {
                set detect_handshake 0
            }
            default {
                set detect_handshake 0
            }
        }
    
        if { ($detect_handshake) } {
             skip past the session id
            set record_offset 43
            binary scan [TCP::payload] @${record_offset}c tls_sessidlen
            set record_offset [expr {$record_offset + 1 + $tls_sessidlen}]
    
             skip past the cipher list
            binary scan [TCP::payload] @${record_offset}S tls_ciphlen
            set record_offset [expr {$record_offset + 2 + $tls_ciphlen}]
    
             skip past the compression list
            binary scan [TCP::payload] @${record_offset}c tls_complen
            set record_offset [expr {$record_offset + 1 + $tls_complen}]
    
             check for the existence of ssl extensions
            if { ([TCP::payload length] > $record_offset) } {
                 skip to the start of the first extension
                binary scan [TCP::payload] @${record_offset}S tls_extenlen
                set record_offset [expr {$record_offset + 2}]
                 read all the extensions into a variable
                binary scan [TCP::payload] @${record_offset}a* tls_extensions
    
                 for each extension
                for { set ext_offset 0 } { $ext_offset < $tls_extenlen } { incr ext_offset 4 } {
                    binary scan $tls_extensions @${ext_offset}SS etype elen
                    if { ($etype == 0) } {
                         if it's a servername extension read the servername
                        set grabstart [expr {$ext_offset + 9}]
                        set grabend [expr {$elen - 5}]
                        binary scan $tls_extensions @${grabstart}A${grabend} tls_servername_orig
                        set tls_servername [string tolower ${tls_servername_orig}]
                        set ext_offset [expr {$ext_offset + $elen}]
                        break
                    } else {
                         skip over other extensions
                        set ext_offset [expr {$ext_offset + $elen}]
                    }
                }
            }
        }
    
        if { ![info exists tls_servername] } {
             This isn't TLS so we can't decrypt it anyway
            SSL::disable clientside
            SSL::disable serverside
        } else {
            log local0. "tls_servername = ${tls_servername}"
    
             This is where you'd check the SNI and do something useful
             So for example:
            if { ${tls_servername} contains "o365.com" } {
                pool outer_router_pool
            } else {
                pool bluecoat_pool
            }        
    
        }
    
        TCP::release
    }
    
  • I'm a little confused. You started by describing a scenario where you don't decrypt the SSL and the F5 is simply load balancing to, or around a Blue Coat ProxySG. The iApp "airgap" template I believe you're referring to is designed to decrypt the SSL, send it to security services, and then re-encrypt. That's not what you were originally asking for.