Technical Forum
Ask questions. Discover Answers.
cancel
Showing results for 
Search instead for 
Did you mean: 

iRule TCL error - no such variable

Philip_Jonsson_
Altostratus
Altostratus

Hey everyone!

I have a previous thread regarding an iRule used to exclude TLS 1.3 cipher suites and certain FQDNs and IP addresses. In that thread we managed to get the iRule fully functioning.

The complete iRule is posted in the comment below.

Now though, we are seeing the following in the LTM log:

err tmm[20996]: 01220001:3: TCL error: /SWG_Proxy/TLS_Exclusion_Clients_v2  - can't read "content": no such variable     while executing "class match $content contains "DG_TLS_1_3_Hex_List""

I understand that the content variable, which is created by the following lines:

Exclude tls 1.3 ciphers
binary scan [TCP::payload] H300 content

is for some reason not present in some occasions. First I thought it was because we matched the IP address against the Datagroup list DG_SWG_SSL_Passthrough_Clients_IP in the following part:

        if { [class match [IP::local_addr] equals DG_SWG_SSL_Passthrough_Clients_IP] } {
                if {$static::tls_iR_debug and [IP::client_addr] equals $static::tls_iR_sourceIP}{log local0. "ir181017-1 - Client IP: {[IP::client_addr]} Server IP: {[IP::local_addr]} - Match DataGroup IP!!"}
         If Destination IP address matches Data Group - turn off HTTP and SSL Profiles  
        } else {
   Collect TCP DATA for SNI analysis in the CLIENT_DATA event
                if {$static::tls_iR_debug and [IP::client_addr] equals $static::tls_iR_sourceIP}{log local0. "ir181017-2 - Client IP: {[IP::client_addr]} Server IP: {[IP::local_addr]} - No Match DataGroup IP"}
        TCP::collect

Which should mean we do not run the TCP::collect command and this will cause the binary scan to fail? Or am I wrong about that?

I tried to replicate that by adding some IP addresses to the exclude list but the TCL error never shows. In fact, I have never been able to replicate the error message. I also tried to lower my SSL handshake down to SSLv3 but that did not trigger it either.

Do you guys have any idea?

3 REPLIES 3

Philip_Jonsson_
Altostratus
Altostratus

Here is the complete iRule:

when RULE_INIT {
  set 1 to enable logging, 0 to disable
    set static::tls_iR_debug 0
    set static::tls_iR_sourceIP 10.10.10.112
}
when CLIENT_ACCEPTED {
        HTTP::disable
        SSL::disable clientside
        SSL::disable serverside
            if { [class match [IP::local_addr] equals DG_SWG_SSL_Passthrough_Clients_IP] } {
                    if {$static::tls_iR_debug and [IP::client_addr] equals $static::tls_iR_sourceIP}{log local0. "ir181017-1 - Client IP: {[IP::client_addr]} Server IP: {[IP::local_addr]} - Match DataGroup IP!!"}
             If Destination IP address matches Data Group - turn off HTTP and SSL Profiles  
            } else {
       Collect TCP DATA for SNI analysis in the CLIENT_DATA event
                    if {$static::tls_iR_debug and [IP::client_addr] equals $static::tls_iR_sourceIP}{log local0. "ir181017-2 - Client IP: {[IP::client_addr]} Server IP: {[IP::local_addr]} - No Match DataGroup IP"}
            TCP::collect
            set tls_servername ""
    }
}
when CLIENT_DATA {
     Store TCP Payload up to 2^14 + 5 bytes (Handshake length is up to 2^14)
    set payload [TCP::payload 16389]
    set payloadlen [TCP::payload length]
     If valid TLS 1.X CLIENT_HELLO handshake packet
    if { [binary scan $payload cH4Scx3H4x32c tls_record_content_type tls_version tls_recordlen tls_handshake_action tls_handshake_version tls_handshake_sessidlen] == 6 && \
        ($tls_record_content_type == 22) && ([string match {030[1-3]} $tls_version]) && \
        ($tls_handshake_action == 1) && ($payloadlen == $tls_recordlen+5)} {
         skip past the session id
        set record_offset [expr {44 + $tls_handshake_sessidlen}]

         Exclude tls 1.3 ciphers
        binary scan [TCP::payload] H300 content

         skip past the cipher list
        binary scan $payload @${record_offset}S tls_ciphlen
        set record_offset [expr {$record_offset + 2 + $tls_ciphlen}]

         skip past the compression list
        binary scan $payload @${record_offset}c tls_complen
        set record_offset [expr {$record_offset + 1 + $tls_complen}]

         check for the existence of ssl extensions
        if { ($payloadlen > $record_offset) } {
             skip to the start of the first extension
            binary scan $payload @${record_offset}S tls_extension_length
            set record_offset [expr {$record_offset + 2}]
             Check if extension length + offset equals payload length
            if {$record_offset + $tls_extension_length == $payloadlen} {
                 for each extension
                while { $record_offset < $payloadlen } {
                    binary scan $payload @${record_offset}SS tls_extension_type tls_extension_record_length
                    if { $tls_extension_type == 0 } {
                         if it's a servername extension read the servername
                         SNI record value start after extension type (2 bytes), extension record length (2 bytes), record type (2 bytes), record type (1 byte), record value length (2 bytes) = 9 bytes
                        binary scan $payload @[expr {$record_offset + 9}]A[expr {$tls_extension_record_length - 5}] tls_servername
                        set record_offset [expr {$record_offset + $tls_extension_record_length + 4}]

                    } else {
                         skip over other extensions
                        set record_offset [expr {$record_offset + $tls_extension_record_length + 4}]
                    }
                }
            }
        }
    }
    unset -nocomplain payload payloadlen tls_record_content_type tls_recordlen tls_handshake_action tls_handshake_sessidlen record_offset tls_ciphlen tls_complen tls_extension_length tls_extension_type tls_extension_record_length tls_supported_versions_length tls_supported_versions  
        if {$tls_servername equals "" || [class match $tls_servername contains "DG_SWG_SSL_Passthrough_Clients_FQDN"] || [class match $content contains "DG_TLS_1_3_Hex_List"] == 0} {
        HTTP::enable
        SSL::enable clientside
        SSL::enable serverside
        if {$static::tls_iR_debug and [IP::client_addr] equals $static::tls_iR_sourceIP}{log local0. "ir181017-3 - Client IP: {[IP::client_addr]} Server IP: {[IP::local_addr]} SNI: {$tls_servername} - No Match DataGroups"}
        }
        elseif {$static::tls_iR_debug and [IP::client_addr] equals $static::tls_iR_sourceIP}{log local0. "ir181017-4 - Client IP: {[IP::client_addr]} Server IP: {[IP::local_addr]} SNI: {$tls_servername} - Matched DataGroups - Disable SSL"}
    TCP::release
}

Andy_McGrath
Cumulonimbus
Cumulonimbus

Your variable

content
is set inside of the
if
statement starting on line 25, so if the
if
statement returns false for one of the 5 elements you are checking then the line
binary scan [TCP::payload] H300 content
will now be executed and so no
content
variable.

You can check to see if the

content
variable exists before the
class match
command by using the following line for your
if
statement on line 67:

if {($tls_servername equals "") || ([class match $tls_servername contains "DG_SWG_SSL_Passthrough_Clients_FQDN"]) || ([info exists content] && [class match $content contains "DG_TLS_1_3_Hex_List"] == 0)} {

Stanislas_Piro2
Cumulonimbus
Cumulonimbus

Hi,

 

Supported version attribute is only inserted in TLS 1.3! If you want to detect this TLS version, check if this attribute exists in CLIENT HELLO packet!