Forum Discussion

krisnaseechurn's avatar
krisnaseechurn
Icon for Altostratus rankAltostratus
Jul 19, 2022
Solved

Error: read ECONNRESET error while using Postman for API calls after change to irule

Am getting connection resets after modifying irule. Error is below:

TCL error: /Common/irule_172.29.8.1 <HTTP_RESPONSE> - can't use non-numeric string as operand of "&&" while executing "if { [HTTP::status] == "404" && {![HTTP::header] contains "Content-Type:application/json" && ![HTTP::header] contains "Content-Type:application/xml" &..."

The extract from the irule is below.

if { [HTTP::status] starts_with "4" && {[HTTP::header] contains "Content-Type:application/json" || [HTTP::header] contains "Content-Type:application/xml" || [HTTP::header] contains "Content-Type:application/problem+json"} } {
set irule "Irule_Catch_404"
set http_status [HTTP::status]
set res_start_time [clock format [clock seconds] -format "%Y/%m/%d %H:%M:%S"]
set req_elapsed_time [expr {[clock clicks -milliseconds] - $tcp_start_time}]
if { [HTTP::header exists "Content-Length"] } {
set req_length [HTTP::header "Content-Length"]
} else {
set req_length 0
}

there is no syntax error as I can save the changes but F5 logs show that connection is being reset

 

  • StephanManthey's avatar
    StephanManthey
    Aug 15, 2022

    Hi krisnaseechurn, the HTTP::redirect command is used a couple of times in your iRule.

    It´s best practice, to use a "return" command afterwards and perhaps an "event disable" command to prevent the iRule from further execution.

    Personally I´m trying to avoid the HTTP::redirect. Instead I prefer to use HTTP::respond because it´s providing very granular control about the exact status code (maybe you prefer a 301 instead of 302?). It also allows to add a Connection Close header. Along with an "event disable" command followed by a "return" you will definitely avoid further execution of the iRule event where the command was fired.

    For debugging it would help to force an unwanted redirect and monitor the /var/log/ltm for log entries and TCL errors/warnings:

    tail -f /var/log/ltm

     

  • krisnaseechurn's avatar
    krisnaseechurn
    Aug 16, 2022

    thanks for all the input..

    the issue was it was missing an !

    if { !([HTTP::status]=="500") && \

5 Replies

  • Hi krisnaseechurn,

    Can you use parentheses( ) instead of braces{ } in if condition?

     

    when HTTP_RESPONSE {
    	if { [HTTP::status] == 404 && ([HTTP::header] contains "Content-Type:application/json" || [HTTP::header] contains "Content-Type:application/xml" || [HTTP::header] contains "Content-Type:application/problem+json") } {
    		set irule "Irule_Catch_404"
    ...

     

     

     

  • This one is working without errors:

    when CLIENT_ACCEPTED {
      set tcp_start_time [clock clicks -milliseconds]
    }
    when HTTP_RESPONSE {
      if { ([HTTP::status] starts_with "4") && \
           ([HTTP::header Content-Type] contains "application/json" || \
            [HTTP::header Content-Type] contains "application/xml" || \
            [HTTP::header Content-Type] contains "application/problem+json") } {
        set irule "Irule_Catch_404"
        set http_status [HTTP::status]
        set resp_start_time [clock format [clock seconds] -format "%Y/%m/%d %H:%M:%S"]
        set resp_elapsed_time [expr {[clock clicks -milliseconds] - $tcp_start_time}]
        if { [HTTP::header exists "Content-Length"] } {
          set resp_length [HTTP::header "Content-Length"]
        }
      } else {
        set resp_length 0
      }
      log local0. "$resp_length; $resp_elapsed_time"
    }

     

     

    • krisnaseechurn's avatar
      krisnaseechurn
      Icon for Altostratus rankAltostratus

      hi, the solution works but partly :(. F5 is now happy with the syntax however it is still triggering a 302. I have copied the whole irule here for guidance.

       

      #----------------------------------------------------------------------------------------------------
      #----------------------------------------------------------------------------------------------------


      when HTTP_REQUEST {
      # environment variables
      #default, to avoid problems when data-group Emergency_site is not available
      set maintenance "false"
      set maintenance [class match -value [IP::local_addr] equals "Emergency_site"]
      set env "DEV"
      set disasterurl "https://xxx
      set startpageurl "xxxxx"
      set errorpageurl "errorpage"
      set pagenotfoundurl "xxx"
      set serversslprofile "xxx"
      set debug_500_errors "true"

      # parameters for request logging to syslog/splunk (and client_address for ip restrictions)
      set tcp_start_time [clock clicks -milliseconds]
      set req_start_time [clock format [clock seconds] -format "%Y/%m/%d %H:%M:%S"]
      set http_host [HTTP::host]
      set http_port [TCP::local_port]
      set http_uri [HTTP::uri]
      set http_url $http_host$http_uri
      set http_method [HTTP::method]
      set http_version [HTTP::version]
      set http_user_agent [HTTP::header "User-Agent"]
      set http_content_type [HTTP::header "Content-Type"]
      set http_referrer [HTTP::header "Referer"]
      set user [HTTP::username]
      set virtual_server [LB::server]
      set client_address [IP::client_addr]
      set vip [IP::local_addr]
      set node "F5"
      set irule "Irule_redirect"
      set node_port "443"
      set http_status "302"
      set hsl [HSL::open -publisher /Common/syslog_HSL]

      # parameters for redirect
      # name parameter in datagroup is case sensitive, so use lowercase
      set url [string tolower [getfield [HTTP::host] : 1][HTTP::uri]]
      set url_path [string tolower [getfield [HTTP::host] : 1][HTTP::path]]

      set redirect_value_contains [class match -value $url_path contains https_redirects_list_contains]
      set redirect_name_contains [class match -name $url_path contains https_redirects_list_contains]
      set redirect_value_equals [class match -value $url_path equals https_redirects_list_equals]
      set redirect_name_equals [class match -name $url_path equals https_redirects_list_equals]
      set redirect_value_begins [class match -value $url_path starts_with https_redirects_list_begins]
      set redirect_name_begins [class match -name $url_path starts_with https_redirects_list_begins]

      set dest_url ""
      set sub_uri ""
      # set logic control flag variable (0 means not yet re-written)
      set uri_rewritten 0

      # parameters for proxy
      set static::uri [string tolower [HTTP::uri]]
      set value [class match -value [string tolower [HTTP::uri]] starts_with [getfield [HTTP::host] : 1]_uris]

      #----------------------------------------------------------------------------------------------------
      # Maintenance page: Change the "maintenance" variable to "true" to enable the redirect.
      if { $maintenance equals "true" } {
      # check is datagroup with allowed IP's exists
      if {! [class exists emergengy_site_allowed_ip]} {
      log local0.notice "Data group emergengy_site_allowed_ip not found."
      #set hsl [HSL::open -proto TCP -pool POOL-P-INT-OTH041-T601]

      # Irule Error 009
      HSL::send $hsl "<190>,f5_irule=Splunk-iRule-FAILED,irule_error=009,env=$env,message_type=\"notice\", message=\"Data group emergengy_site_allowed_ip not found.\"\r\n"
      }
      elseif {![class match $client_address equals emergengy_site_allowed_ip ]} {
      # IP not found, request redirected to emergency Site
      # Log http redirect to syslog(splunk)
      set uri_rewritten 1
      set irule "Irule_disaster_redirect"
      if { [HTTP::header Content-Length] > 0 } then {
      set req_length [HTTP::header "Content-Length"]
      }
      else {
      set req_length 0
      }
      set res_start_time [clock format [clock seconds] -format "%Y/%m/%d %H:%M:%S"]
      set req_elapsed_time [expr {[clock clicks -milliseconds] - $tcp_start_time}]
      if { [HTTP::header Content-Length] > 0 } then {
      set res_length [HTTP::header "Content-Length"]
      }
      else {
      set res_length 0
      }
      #set hsl [HSL::open -proto TCP -pool POOL-P-INT-OTH041-T601]


      HTTP::redirect $disasterurl
      HSL::send $hsl "<190>,f5_irule=Splunk-iRule-HTTP,env=$env,src_ip=$client_address,vip=$vip,irule=$irule,http_method=$http_method,http_host=$http_host,http_port=$http_port,http_dest=$dest_url,http_uri=$http_uri,http_url=$http_url,http_version=$http_version,http_user_agent=\"$http_user_agent\",http_content_type=$http_content_type,http_referrer=\"$http_referrer\",req_start_time=$req_start_time,virtual_server=\"$virtual_server\",bytes_in=$req_length,res_start_time=$res_start_time,node=$node,node_port=$node_port,http_status=$http_status,req_elapsed_time=$req_elapsed_time,bytes_out=$res_length\r\n"
      return
      }
      }
      #----------------------------------------------------------------------------------------------------
      # disable ASM on error page to avoid endless loop
      if {[string tolower [HTTP::path]] equals "/cia/identitystore.web.loginpages/main/error"} {
      ASM::disable
      }
      else {
      ASM::enable /Common/asm_iso_auth.sdworx.com
      }
      #----------------------------------------------------------------------------------------------------
      # lookup in datagourp for redirection configurations, parsing urls and build destination url and redirect
      # name parameter in datagroup is case sensitive, so use lowercase
      # the last char in value determine the type or redirect:
      # no special character --> all urls CONTAINING redirect_name will be redirect to redirect_value
      # * dynamic redirect, --> all urls CONTAINING redirect_name will be redirect to redirect_value + a part of the incomming URL (destination = value + (Org. url - name)

      if { $uri_rewritten equals 0 } {
      if { [catch {
      if { $redirect_value_equals ne "" } {
      # specific redirect found
      #set dest_url [string map [list "*" ""] $redirect_value_equals]
      set dest_url $redirect_value_equals
      } else {
      if { $redirect_value_begins ne "" } {
      # Begins with redirect found
      set dest_url [string map [list "*" ""] $redirect_value_begins]
      if {$redirect_value_begins ends_with "*" }{
      set sub_uri [string map [list $redirect_name_begins ""] $url]
      append dest_url $sub_uri
      }
      } else {
      # generic redirect
      if { $redirect_value_contains ne "" } {
      set dest_url [string map [list "*" ""] $redirect_value_contains]
      if {$redirect_value_contains ends_with "*" }{
      set sub_uri [string map [list $redirect_name_contains ""] $url]
      append dest_url $sub_uri
      }
      }
      }
      }
      if { $dest_url ne "" } {
      set dest_url "https://$dest_url"
      set uri_rewritten 1
      }
      # Log http redirect to syslog(splunk)
      if { $uri_rewritten equals 1 } {
      set res_start_time [clock format [clock seconds] -format "%Y/%m/%d %H:%M:%S"]
      set req_elapsed_time [expr {[clock clicks -milliseconds] - $tcp_start_time}]
      if { [HTTP::header Content-Length] > 0 } then {
      set res_length [HTTP::header "Content-Length"]
      }
      else {
      set res_length 0
      }
      #set hsl [HSL::open -proto TCP -pool POOL-P-INT-OTH041-T601]


      #actual redirect
      HTTP::redirect $dest_url
      HSL::send $hsl "<190>,f5_irule=Splunk-iRule-HTTP,env=$env,src_ip=$client_address,vip=$vip,irule=$irule,http_method=$http_method,http_host=$http_host,http_port=$http_port,http_dest=$dest_url,http_uri=$http_uri,http_url=$http_url,http_version=$http_version,http_user_agent=\"$http_user_agent\",http_content_type=$http_content_type,http_referrer=\"$http_referrer\",req_start_time=$req_start_time,virtual_server=\"$virtual_server\",bytes_in=$req_length,res_start_time=$res_start_time,node=$node,node_port=$node_port,http_status=$http_status,req_elapsed_time=$req_elapsed_time,bytes_out=$res_length\r\n"
      }
      }]}
      {
      # error catch to syslog(splunk)
      log local0.warn "redirection-failed: from: [IP::remote_addr] for request: [HTTP::host][HTTP::uri]"
      #set hsl [HSL::open -proto TCP -pool POOL-P-INT-OTH041-T601]

      # Irule Error 008
      HSL::send $hsl "<190>,f5_irule=Splunk-iRule-FAILED,irule_error=008,env=$env,message_type=\"warn\", message=\"redirection-failed: from: [IP::remote_addr] for request: [HTTP::host][HTTP::uri]\"\r\n"
      }
      }
      #----------------------------------------------------------------------------------------------------
      # Determine if sticky load balancing should be used or not based on the incoming uri
      # update by Joachim Hamers: for the new design with loginpages:
      # First IP in x-forwarde-for list is always the ip of the client, x-forwarded-for header is enabled on the VIP

      if { $static::uri contains "/idhub" }{
      #log local0.notice "IDHUB - X-Forwarded-For = [HTTP::header X-Forwarded-For] | remote = [IP::remote_addr]"
      #log local0.notice "IDHUB - 1st value X-.. = [lindex [ split [lindex [HTTP::header values X-Forwarded-For] 0] "," ] 0]"
      if { [HTTP::header exists "X-Forwarded-For"] }{
      persist uie [lindex [ split [lindex [HTTP::header values X-Forwarded-For] 0] "," ] 0]
      }
      else {
      persist source_addr 36000
      log local0.notice "IDHUB - X-Forwarded-For header not found (ERROR) "
      }
      }
      #----------------------------------------------------------------------------------------------------
      # Only internal content / accessable by internal ip's
      if { $uri_rewritten equals 0 } {
      #log local0.warn "redirection-onlyInternal: from: [IP::remote_addr] for request: [HTTP::host][HTTP::uri][IP::client_addr]"
      if {[class match [string tolower [HTTP::uri]] contains listInternalURLs]} {
      if {![class match [IP::client_addr] equals listInternalIPs]} {
      set uri_rewritten 1
      set irule "Irule_redirection-onlyInternal"
      set res_start_time [clock format [clock seconds] -format "%Y/%m/%d %H:%M:%S"]
      set req_elapsed_time [expr {[clock clicks -milliseconds] - $tcp_start_time}]

      if { [HTTP::header Content-Length] > 0 } then {
      set res_length [HTTP::header "Content-Length"]
      }
      else {
      set res_length 0
      }
      #set hsl [HSL::open -proto TCP -pool POOL-P-INT-OTH041-T601]


      HTTP::redirect "$errorpageurl?Code=notAllowed"
      HSL::send $hsl "<190>,f5_irule=Splunk-iRule-HTTP,env=$env,src_ip=$client_address,vip=$vip,irule=$irule,http_method=$http_method,http_host=$http_host,http_port=$http_port,http_dest=$dest_url,http_uri=$http_uri,http_url=$http_url,http_version=$http_version,http_user_agent=\"$http_user_agent\",http_content_type=$http_content_type,http_referrer=\"$http_referrer\",req_start_time=$req_start_time,virtual_server=\"$virtual_server\",bytes_in=$req_length,res_start_time=$res_start_time,node=$node,node_port=$node_port,http_status=$http_status,req_elapsed_time=$req_elapsed_time,bytes_out=$res_length\r\n"
      }
      }
      }

      #----------------------------------------------------------------------------------------------------
      # search server pool in datagroup based on uri
      if { $uri_rewritten equals 0 } {
      if { $static::uri equals "" || $static::uri equals "/" }{
      HTTP::redirect $startpageurl
      set uri_rewritten 1
      }
      else {
      if { $value ne "" } {
      if { [catch { pool $value } ] } {
      log local0.warn "uri-pool-selection-failed: from: [IP::remote_addr] for request: [HTTP::host][HTTP::uri] pool: $value"
      #set hsl [HSL::open -proto TCP -pool POOL-P-INT-OTH041-T601]

      # Irule Error 001
      HSL::send $hsl "<190>,f5_irule=Splunk-iRule-FAILED,irule_error=001,env=$env,message_type=\"warn\", message=\"uri-pool-selection-failed: from: [IP::remote_addr] for request: [HTTP::host][HTTP::uri] pool: $value\"\r\n"
      HTTP::redirect "$errorpageurl?Code=uripoolselectionfailed"
      set uri_rewritten 1
      }
      } else {
      log local0.notice "uri-pool-lookup-failed: from: [IP::remote_addr] for request: [HTTP::host][HTTP::uri]"
      #set hsl [HSL::open -proto TCP -pool POOL-P-INT-OTH041-T601]

      # Irule Error 002
      HSL::send $hsl "<190>,f5_irule=Splunk-iRule-FAILED,irule_error=002,env=$env,message_type=\"notice\", message=\"uri-pool-lookup-failed: from: [IP::remote_addr] for request: [HTTP::host][HTTP::uri]\"\r\n"
      HTTP::redirect "$pagenotfoundurl"
      set uri_rewritten 1
      }
      }
      }
      unset value
      }
      #****************************************************************************************************
      when HTTP_RESPONSE {
      set hsl [HSL::open -publisher /Common/syslog_HSL]
      # Catch backend errors and redirect to central page
      if { $uri_rewritten equals 0 } {
      if { ([HTTP::status]=="500") && \
      ([HTTP::header Content-Type] contains "application/json" || \
      [HTTP::header Content-Type] contains "application/xml" || \
      [HTTP::header Content-Type] contains "application/problem+json") } {
      set irule "Irule_Catch_500"
      set http_status [HTTP::status]
      #set content ""
      set res_start_time [clock format [clock seconds] -format "%Y/%m/%d %H:%M:%S"]
      set req_elapsed_time [expr {[clock clicks -milliseconds] - $tcp_start_time}]
      # Get the content length so we can request the data to be
      # processed in the HTTP_RESPONSE_DATA event.
      if { [HTTP::header exists "Content-Length"] } {
      set req_length [HTTP::header "Content-Length"]
      } else {
      set req_length 0
      }

      # dump HTML response to log if parameter debug_500_errors is true
      # content_length of 0 indicates chunked data (of unknown size)
      #set hsl [HSL::open -proto TCP -pool POOL-P-INT-OTH041-T601]

      if { $debug_500_errors equals "true" } {
      if { $req_length > 0 && $req_length < 1048577 } {
      set collect_length $req_length
      } else {
      set collect_length 1048576
      }
      if { $req_length > 0 } {
      HTTP::collect $req_length
      set content [b64encode [string map {"\n" "" "," "" "=" "" "\"" ""} [HTTP::payload]]]
      }
      HSL::send $hsl "<190>,f5_irule=Splunk-iRule-HTTP,env=$env,src_ip=$client_address,vip=$vip,irule=$irule,http_method=$http_method,http_host=$http_host,http_port=$http_port,http_dest=$dest_url,http_uri=$http_uri,http_url=$http_url,http_version=$http_version,http_user_agent=\"$http_user_agent\",http_content_type=$http_content_type,http_referrer=\"$http_referrer\",req_start_time=$req_start_time,virtual_server=\"$virtual_server\",bytes_in=$req_length,res_start_time=$res_start_time,node=$node,node_port=$node_port,http_status=$http_status,req_elapsed_time=$req_elapsed_time,bytes_out=$res_length,content=$content\r\n"
      } else {
      HSL::send $hsl "<190>,f5_irule=Splunk-iRule-HTTP,env=$env,src_ip=$client_address,vip=$vip,irule=$irule,http_method=$http_method,http_host=$http_host,http_port=$http_port,http_dest=$dest_url,http_uri=$http_uri,http_url=$http_url,http_version=$http_version,http_user_agent=\"$http_user_agent\",http_content_type=$http_content_type,http_referrer=\"$http_referrer\",req_start_time=$req_start_time,virtual_server=\"$virtual_server\",bytes_in=$req_length,res_start_time=$res_start_time,node=$node,node_port=$node_port,http_status=$http_status,req_elapsed_time=$req_elapsed_time,bytes_out=$res_length\r\n"
      }
      HTTP::redirect "$errorpageurl?HttpStatusCode=[HTTP::status]&Code=BackendHTTPCodeError"
      set uri_rewritten 1
      return
      }
      if { ([HTTP::status]== "404") && \
      ([HTTP::header Content-Type] contains "application/json" || \
      [HTTP::header Content-Type] contains "application/xml" || \
      [HTTP::header Content-Type] contains "application/problem+json") } {
      set irule "Irule_Catch_404"
      set http_status [HTTP::status]
      set res_start_time [clock format [clock seconds] -format "%Y/%m/%d %H:%M:%S"]
      set req_elapsed_time [expr {[clock clicks -milliseconds] - $tcp_start_time}]
      if { [HTTP::header exists "Content-Length"] } {
      set req_length [HTTP::header "Content-Length"]
      } else {
      set req_length 0
      }
      #set hsl [HSL::open -proto TCP -pool POOL-P-INT-OTH041-T601]

      HSL::send $hsl "<190>,f5_irule=Splunk-iRule-HTTP,env=$env,src_ip=$client_address,vip=$vip,irule=$irule,http_method=$http_method,http_host=$http_host,http_port=$http_port,http_dest=$dest_url,http_uri=$http_uri,http_url=$http_url,http_version=$http_version,http_user_agent=\"$http_user_agent\",http_content_type=$http_content_type,http_referrer=\"$http_referrer\",req_start_time=$req_start_time,virtual_server=\"$virtual_server\",bytes_in=$req_length,res_start_time=$res_start_time,node=$node,node_port=$node_port,http_status=$http_status,req_elapsed_time=$req_elapsed_time,bytes_out=$res_length\r\n"
      HTTP::redirect $pagenotfoundurl
      set uri_rewritten 1
      return
      }
      }

      #----------------------------------------------------------------------------------------------------
      # Remove all instances of the Server header
      HTTP::header remove Server
      # Remove all headers starting with x-
      foreach header_name [HTTP::header names] {
      if {[string match -nocase x-* $header_name]}{
      HTTP::header remove $header_name
      }
      }

      • StephanManthey's avatar
        StephanManthey
        Icon for MVP rankMVP

        Hi krisnaseechurn, the HTTP::redirect command is used a couple of times in your iRule.

        It´s best practice, to use a "return" command afterwards and perhaps an "event disable" command to prevent the iRule from further execution.

        Personally I´m trying to avoid the HTTP::redirect. Instead I prefer to use HTTP::respond because it´s providing very granular control about the exact status code (maybe you prefer a 301 instead of 302?). It also allows to add a Connection Close header. Along with an "event disable" command followed by a "return" you will definitely avoid further execution of the iRule event where the command was fired.

        For debugging it would help to force an unwanted redirect and monitor the /var/log/ltm for log entries and TCL errors/warnings:

        tail -f /var/log/ltm