HTTP Get and POST Flood (Layer 7 DDoS) Mitigation with iRule

HTTP Get and POST Flood Mitigation with iRule
        At the present time, Security Concerns have become inevitable for companies and also rises day by day. This article was written to find a solution for HTTP Flood which is one of those Security Concerns. HTTP Flood is a technique used to make a company out of service. In this technique, attackers take advantage of limited capacity of the company’s servers. To cope with that, first of all, we have to stop attackers before their requests reach to server by using much more capable devices like Application Delivery Products. In ongoing parts of this article, you can find a solution using the following iRule codes. ` <https://clouddocs.f5.com/api/irules/.html>`__
HTTP Flood Mitigation Logic HTTP Flood Mitigation Logic

        There are several ways to mitigate HTTP Get and POST Flood(shortly HTTP Flood). Two of them are most effective ways. Firstly, after exceeding your prime time HTTP Requests Per Second(X Rps), all client requesting something must be checked whether It is a browser or a robot(like Botnet). This can be accomplished by several ways. In our example, this is done by responding a javascript to set encrypted client ip cookie. In this method, normal clients are not affected and feel nothing.Here is the HTML code for javascript in order to use in iRule(I put it into iFile named javascript-with-cookie_html):
<html>
    <head>
        <title> Please one second you are redirected The Site</title>
    </head>
    <body>
        < script type='text/javascript'>
            document.cookie = 'this-is-human=$encrypted;path=/;Domain=.$domainName;';
            location.reload(true);
        </script>
        <noscript>(c) Faruk AYDIN </noscript>
    </body>
<html>

        And this is the iRule code that uses javascript-with-cookie_html:

when RULE_INIT {
...
 # get javascript HTML page template from ifile
    set static::humanResponse "\"[ifile get javascript-with-cookie_html]\""
}
when HTTP_REQUEST {
...
    # decrypt this-is-human cookie and get the IP address inside It
set decrypted [findstr [subst [AES::decrypt $static::encrytionKey [b64decode [HTTP::cookie "this-is-human"]]]] "IP" 3 " "]
    # if encrypted IP address in the cookie does not equal to client ip, this request may have been done from a robot
    if { ! ($decrypted equals [IP::client_addr]) } {
    ...
        HTTP::respond 200 content $humanResponse
        return
    }
...
}

` <https://clouddocs.f5.com/api/irules/.html>`__

Google reCAPTCHA Google reCAPTCHA

        If client is able to run this script and set its cookie, then this means It passed the test. This test usually is passed by normal client browser, not a robot. 80-90% of HTTP flood attacks can be stopped using this method.If the attack cannot be stopped by this technique, again, you have to stop before the server becomes to out of service(Y Rps). At this situation, you can use Google reCAPTCHA service to mitigate the attackers’ requests. Here is the HTML code for reCAPTCHA in order to use in iRule(I put it into iFile named google-recaptcha_html) :
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>&#169; Faruk AYDIN | reCAPTCHA Page</title>
        <meta name="Description" content="&#169; Faruk AYDIN | reCAPTCHA | F5 iRule" />
        <style type="text/css">
            BODY, DIV, SPAN, P, TD { font: 18px "Lucida Sans Unicode", "Lucida Grande", sans-serif; color: #000; }
            #content { position: relative; width: 100%; height: 395px; }
            #content .headx { height: 50px; padding: 0px 0px 0px 0px; display: block; }
            #content .headx ul { margin: 0; padding: 0; }
            #content .headx li { margin: 7px 12px 0 0; font-size: 18px; list-style: none; float: center; color: #0055a4;}
        </style>
    </head>
    <body>
        <div id="content" align="center">
            <div class="headx" align="center">
                <ul>
                    <li >Devam etmek i&#231;in l&#252;tfen resimde g&#246;rd&#252;klerinizi girebilir misiniz !</li>
                    <li >To continue, please enter what you see in the picture ! </li>
                </ul>
            </div>
            <br>
            <div class="headx" align="center">
                <form action="/verify_recaptcha" method="GET">
                    <script type="text/javascript"
                            src="https://www.google.com/recaptcha/api/challenge?k=6LfgPcwSBBBBBMkV3pSUbbuocTC_2UROlZqMo365">
                    </script>
                    <noscript>
                            <iframe src="https://www.google.com/recaptcha/api/noscript?k=6LfgPcwSBBBBBMkV3pSUbbuocTC_2UROlZqMo365"
                        height="300" width="500" frameborder="0"></iframe>
                            <textarea name="recaptcha_challenge_field" rows="3" cols="40">
                            </textarea>
                            <input type="hidden" name="recaptcha_response_field" value="manual_challenge">
                    </noscript>
                    <input type="submit" value="Send / G&#246;nder">
                </form>
            </div>
        </div>
    </body>
</html>

        reCAPTCHA iRule code adopted from Google-reCAPTCHA-Challenge-iRule. session_identifier is renamed with requestNumber and sent it with encrypted cookie to client. In addition, session_identifier was composed of Client IP and Source Port, requestNumber is only composed of last Request NumberreCAPTCHA will be in service if request rate exceeds Y after request rate passes level 1.

when RULE_INIT {
...
    # this defines AES key for encryption of client cookie
    set static::encrytionKey "AES 128 43237ec78871FAACEbc8b98de6d36fc8"
# set private reCAPTCHA key (obtain from www.recaptcha.com)
    set static::recaptcha_private_key "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    # This defines level 1 http RequestPerSecond limit
    set static::maxRateForJs 25
    # This defines level 2 http RequestPerSecond limit
    set static::maxRateForReCaptcha 35
    # This defines how long is the sliding life to count the requests.
    set static::lifetime 1
    set static::tableNameForJs "ReqPerSecForJs"
    set static::tableNameForReCaptcha "ReqPerSecForReCaptcha"
    # set DNS server address to resolve www.google.com
    set static::dns_server 10.11.91.11


    # set name of table to track reCAPTCHA approvals
    set static::recaptcha_approval_table "recaptcha_approvals"

    # set name of table to track last requested URL
    set static::recaptcha_redirect_table "recaptcha_redirects"

    # timeout and/or lifetime for reCAPTCHA approval
    set static::recaptcha_approval_timeout 3600
    set static::recaptcha_approval_lifetime 3600


    # get reCAPTCHA HTML form page from ifile
    set static::recaptcha_challenge_form    [ifile get google-recaptcha_html]
...
}
when HTTP_REQUEST {
...
} elseif { $getCountForReCaptcha >= $static::maxRateForReCaptcha and not ([HTTP::path] equals "/verify_recaptcha")} {
    # if encrypted IP address in the cookie equals to client ip and also number of request exceeds the maxRateForCaptcha, then response to client with reCaptcha
    ...
    set requestNumber [AES::decrypt $static::encrytionKey [b64decode [HTTP::cookie "requestNumber"]]]
    if { [table lookup -subtable $static::recaptcha_approval_table $requestNumber] eq "" } {
        set requestNumber [b64encode [AES::encrypt $static::encrytionKey $ReqNumForJs]]
        if { [TCP::local_port] != 443 } {
            table add -subtable $static::recaptcha_redirect_table $ReqNumForJs "http://[HTTP::host][HTTP::uri]" 3600 600
        } else {
            table add -subtable $static::recaptcha_redirect_table $ReqNumForJs "https://[HTTP::host][HTTP::uri]" 3600 600
        }
        # add request number into this-is-human cookie and encrypt it
        set encrypted [b64encode [AES::encrypt $static::encrytionKey "IP:$decrypted requestNumber:$ReqNumForJs "]]
        # response with recaptcha html page
        HTTP::respond 200 content $static::recaptcha_challenge_form Set-Cookie "this-is-human=$encrypted;Domain=$domainName"
        return
    }
}
...
}

` <https://clouddocs.f5.com/api/irules/.html>`__

HTTP Request Statistics HTTP Request Statistics

        Lastly, you might want to see current state, I prepared a template for this named requestStats_html and put it into iFile named requestStats_html.
<html>
<head><title>&#169; Faruk AYDIN | HTTP Request Per Second and Values</title></head>
<META http-equiv=refresh content='3;URL=[HTTP::uri]'>
<body>
<div style='margin-right:auto;margin-left:auto;width:500px;'>
        <div id='header' style='background-color:$bgColor;width:500px;'>
        <h4 style='margin-bottom:0;'>$header</h4></div>
            <div id='menu' style='background-color:Gold;height:400px;width:100px;float:left;'>
                <table>
                    <tbody>
                        <tr style='height:50px'><td>Time</td></tr>
                        <tr style='height:2px'><td><hr style='color:Gold;'></hr></td></tr>
                        <tr style='height:25px'><td>Level 1</td></tr>
                        <tr style='height:25px'><td>JS+Cookie</td></tr>
                        <tr style='height:25px'><td></td></tr>
                        <tr style='height:2px'><td><hr style='color:Gold;'></hr></td></tr>
                        <tr style='height:25px'><td>Level 2</td></tr>
                        <tr style='height:25px'><td>reCAPTCHA</td></tr>
                        <tr style='height:25px'><td></td></tr>
                        <tr style='height:2px'><td><hr style='color:Gold;'></hr></td></tr>
                        <tr style='height:25px'><td>Client INFO</td></tr>
                    </tbody>
                </table>
            </div>
            <div id='content' style='background-color:LightGrey;height:400px;width:400px;float:left;'>
                <table>
                    <tbody>
                        <tr style='height:50px'><td>CurrentTime</td><td>: $cur_second</td></tr>
                        <tr style='height:2px'><td><hr style='color:LightGrey;'></hr></td><td><hr style='color:LightGrey;'></hr></td></tr>
                        <tr style='height:25px'><td>CurRpsForJs</td><td>: $getCountForJs</td></tr>
                        <tr style='height:25px'><td>MaxRateForJs</td><td>: $maxRateForJs</td></tr>
                        <tr style='height:25px'><td>ReqNumForJs</td><td>: $ReqNumForJs<td></tr>
                        <tr style='height:2px'><td><hr style='color:LightGrey;'></hr></td><td><hr style='color:LightGrey;'></hr></td></tr>
                        <tr style='height:25px'><td>CurRpsForReCaptcha</td><td>: $getCountForReCaptcha</td> </tr>
                        <tr style='height:25px'><td>MaxRateForReCaptcha</td><td>: $maxRateForReCaptcha</td>
                        <tr style='height:25px'><td>ReqNumForReCaptcha</td><td>: $ReqNumForReCaptcha</td></tr>
                        <tr><td><hr style='color:LightGrey;'></hr></td><td><hr style='color:LightGrey;'></hr></td></tr>
                        <tr style='height:25px'><td>ClientIP</td><td>: [IP::client_addr]</td></tr>
                        <tr style='height:25px'><td>Host</td><td>: [HTTP::host]</td></tr>
                        <tr style='height:25px'><td>URL</td><td>: [HTTP::path]</td></tr>
                        <tr style='height:25px'><td>Virtual Server</td><td>: $vsname</td></tr>
                    </tbody>
                </table>
            </div>
            <div id='footer' style='background-color:Orange;clear:both;width:500px;text-align:center;'> Copyright &#169; Faruk AYDIN</div>
        </div>
    </div>
</body>
</html>

        And this is the iRule code for requestStats page:

when RULE_INIT {
...
    # get javascript HTML page template from ifile
    set static::humanResponse "\"[ifile get javascript-with-cookie_html]\""
}
when HTTP_REQUEST {
...

if { [HTTP::path] eq "/requestStats" and [IP::addr 10.0.0.0/8 equals [IP::client_addr]] }
    {

        if { $getCountForReCaptcha >= $static::maxRateForReCaptcha } {
            set bgColor "red"
            set header "Request Per Second Statistics | Severity: Level 2 (reCAPTCHA)"

        } else  {
            if { $getCountForJs >= $static::maxRateForJs } {
                set bgColor "yellow"
                set header "Request Per Second Statistics | Severity: Level 1 (JS + Cookie)"
            } else {
                set bgColor "YellowGreen"
                set header "Request Per Second Statistics | Severity: Normal"
            }
        }
        # this evaluates dynamic parameters for requestStats page
        eval "set requestStats $static::requestStats"
        HTTP::respond 200 content $requestStats "Content-Type" "text/html"
            return
    }
....
}

Conclusion

        As a result, attackers who use HTTP GET or POST Flood have to be stopped before their attacks reach to servers. You can use these two level technique to mitigate these types of attacks.

iRule Source

Link to Full Source of iRule_HTTP_Flood_Mitigation

# (c) Copyright Faruk AYDIN
# Faruk AYDIN <farukaydin @ yahoo.com>
# Version 6.0, Jan 3, 2013
# This iRule is written to minimize effect of an HTTP Flood
# There are two mitigation level, level 1 and level 2.
# level 1 comes into mitigation after exceeding your prime time http request rate(static::maxRateForJs)
# level 2 comes into mitigation after exceeding your server top acceptable http request rate(static::maxRateForReCaptcha) for requests passed level 1 mitigation
# Version History
# v1.0 started with checking the client whether a robot or a browser by using javascript and cookie
# v2.0 added google reCAPTCHA code (reCAPTCHA irule code adopted from https://devcentral.f5.com/s/articles/google-recaptcha-challenge-irule)
# v3.0 Request Count of JS(level 1 mitigation) is seperated from of reCAPTCHA(level 2 mitigation) and requestStats code is added
# v4.0 in order to minimize the iRule code reCAPTCHA html page moved to iFile
# v5.0 in order to minimize the iRule requestStats and JS response page moved to iFile
# v6.0 iRule code is reorganized in order to optimize mitigation
when RULE_INIT {
    # this defines AES key for encryption of client cookie
    set static::encrytionKey "AES 128 43237ec78871FAACEbc8b98de6d36fc8"
    # set private reCAPTCHA key (obtain from www.recaptcha.com)
    set static::recaptcha_private_key "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    # This defines level 1 http RequestPerSecond limit
    set static::maxRateForJs 25
    # This defines level 2 http RequestPerSecond limit
    set static::maxRateForReCaptcha 35
    # This defines how long is the sliding life to count the requests.
    set static::lifetime 1
    set static::tableNameForJs "ReqPerSecForJs"
    set static::tableNameForReCaptcha "ReqPerSecForReCaptcha"
    # set DNS server address to resolve www.google.com
    set static::dns_server 10.11.91.11


    # set name of table to track reCAPTCHA approvals
    set static::recaptcha_approval_table "recaptcha_approvals"

    # set name of table to track last requested URL
    set static::recaptcha_redirect_table "recaptcha_redirects"

    # timeout and/or lifetime for reCAPTCHA approval
    set static::recaptcha_approval_timeout 3600
    set static::recaptcha_approval_lifetime 3600


    # get reCAPTCHA HTML form page from ifile
    set static::recaptcha_challenge_form    [ifile get google-recaptcha_html]
    # get request Statistics HTML page template from ifile
    set static::requestStats "\"[ifile get requestStats_html]\""
    # get javascript HTML page template from ifile
    set static::humanResponse "\"[ifile get javascript-with-cookie_html]\""

}
when HTTP_REQUEST {
    # get and set current second
    set cur_second [clock format [clock seconds] -format "%d/%m/%Y %H:%M:%S %z"]
    # get level 1 (JS and cookie) Request Number
    set ReqNumForJs [table lookup "ReqNumForJs"]
    # get level 2 (reCAPTCHA) Request Number
    set ReqNumForReCaptcha [table lookup "ReqNumForReCaptcha"]

    # count level 1 (JS and cookie) Request Per Second value
    set getCountForJs [table keys -subtable $static::tableNameForJs -count]
    # count level 2 (reCAPTCHA) Request Per Second value
    set getCountForReCaptcha [table keys -subtable $static::tableNameForReCaptcha -count]
    # get and log the current values
    if { [HTTP::path] eq "/requestStats" and [IP::addr 10.0.0.0/8 equals [IP::client_addr]] }
    {

        if { $getCountForReCaptcha >= $static::maxRateForReCaptcha } {
            set bgColor "red"
            set header "Request Per Second Statistics | Severity: Level 2 (reCAPTCHA)"

        } else  {
            if { $getCountForJs >= $static::maxRateForJs } {
                set bgColor "yellow"
                set header "Request Per Second Statistics | Severity: Level 1 (JS + Cookie)"
            } else {
                set bgColor "YellowGreen"
                set header "Request Per Second Statistics | Severity: Normal"
            }
        }
        # this evaluates dynamic parameters for requestStats page
        eval "set requestStats $static::requestStats"
        HTTP::respond 200 content $requestStats "Content-Type" "text/html"
        #log local0. "Cur_Sec:$cur_second | CurRpsForJs:$getCountForJs MaxRateForJs:$static::maxRateForJs ReqNumForJs:$ReqNumForJs | CurRpsForReCaptcha:$getCountForReCaptcha MaxRateForReCaptcha:$static::maxRateForReCaptcha ReqNumForReCaptcha:$ReqNumForReCaptcha | [IP::client_addr] [HTTP::path]"
        return
    } else {
        # increase level 1 (JS and cookie) Request Number
        table incr "ReqNumForJs"
        if { $ReqNumForJs > 100000 } {
            # reset when ReqNumForJs reaches large number
            table set "ReqNumForJs" 1
        }
        if { $ReqNumForReCaptcha > 100000 } {
            # reset when ReqNumForReCaptcha reaches large number
            table set "ReqNumForReCaptcha" 1
        }
        # add a request for level 2 table
        table set -subtable $static::tableNameForJs $ReqNumForJs "ignored" indef $static::lifetime
    }
        # check whether RequestPerSecond exceeds level 1 limit
    if { $getCountForJs < $static::maxRateForJs } {
        if { $debugSeverity > 7 }
        {
            set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[HTTP::path]],<Info : Severity:Normal CurRpsForJs:$getCountForJs MaxRateForJs:$static::maxRateForJs Cur_Sec:$cur_second ReqNumForJs:$ReqNumForJs >"
            log $debugSyslog $debugFacility $debug_log_line
        }
    } else {
        # this checks whether client ip address is in the exclusion
        if { (![IP::addr 10.10.10.0/24 equals [IP::client_addr]] or  ![IP::addr 192.168.0.0/16 equals [IP::client_addr]])} {
            if { $debugSeverity > 6 }
            {
                set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[HTTP::path],<Info : Severity:JS-Cookie CurRpsForJs:$getCountForJs MaxRateForJs:$static::maxRateForJs Cur_Sec:$cur_second ReqNumForJs:$ReqNumForJs  >"
                log $debugSyslog $debugFacility $debug_log_line
            }
            # this finds the requested domain name of host
            set domainName [domain [HTTP::host] 2]
            # this encrypts client ip address
            set encrypted [b64encode [AES::encrypt $static::encrytionKey "IP:[IP::client_addr] "]]
            # this evaluates dynamic parameters (encrypted client ip cookie, domain ..) for javascript html page
            eval "set humanResponse $static::humanResponse"
            # if this-is-human exists, check it, it may have been cloned or copied to other Botnet clients
            if { [HTTP::cookie exists "this-is-human"] } {
                if { ! [catch {b64decode [HTTP::cookie "this-is-human"]}] }
                {
                    # decrypt this-is-human cookie and get the IP address inside It
                    set decrypted [findstr [subst [AES::decrypt $static::encrytionKey [b64decode [HTTP::cookie "this-is-human"]]]] "IP" 3 " "]
                    # if encrypted IP address in the cookie does not equal to client ip, this request may have been done from a robot
                    if { ! ($decrypted equals [IP::client_addr]) } {
                            if { $debugSeverity > 5 }
                                {
                                    set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[substr [string tolower [HTTP::uri]] 1 "/"],<Info : This is Robot, Cookie Client IP $decrypted>"
                                    log $debugSyslog $debugFacility $debug_log_line
                                }
                        HTTP::respond 200 content $humanResponse
                        return
                    } elseif { $getCountForReCaptcha >= $static::maxRateForReCaptcha and not ([HTTP::path] equals "/verify_recaptcha")} {
                            # if encrypted IP address in the cookie equals to client ip and also number of request exceeds the maxRateForCaptcha, then response to client with reCaptcha
                            if { $debugSeverity > 3 }
                            {
                                set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[HTTP::path]],<Info : Severity:Captcha CurRpsForReCaptcha:$getCountForReCaptcha MaxRateForReCaptcha:$static::maxRateForReCaptcha Cur_Sec:$cur_second ReqNumForReCaptcha:$ReqNumForReCaptcha requestNumber:$ReqNumForJs >"
                                log $debugSyslog $debugFacility $debug_log_line
                            }
                            set requestNumber [AES::decrypt $static::encrytionKey [b64decode [HTTP::cookie "requestNumber"]]]
                            #log local0. "Cur_Sec:$cur_second CurRpsForReCaptcha:$getCountForReCaptcha MaxRateForReCaptcha:$static::maxRateForReCaptcha [IP::client_addr] [HTTP::path] ReqNumForReCaptcha:$ReqNumForReCaptcha Severity:Captcha"
                            if { [table lookup -subtable $static::recaptcha_approval_table $requestNumber] eq "" } {
                                set requestNumber [b64encode [AES::encrypt $static::encrytionKey $ReqNumForJs]]
                                if { [TCP::local_port] != 443 } {
                                    table add -subtable $static::recaptcha_redirect_table $ReqNumForJs "http://[HTTP::host][HTTP::uri]" 3600 600
                                } else {
                                    table add -subtable $static::recaptcha_redirect_table $ReqNumForJs "https://[HTTP::host][HTTP::uri]" 3600 600
                                }
                                # add request number into this-is-human cookie and encrypt it
                                set encrypted [b64encode [AES::encrypt $static::encrytionKey "IP:$decrypted requestNumber:$ReqNumForJs "]]
                                # response with recaptcha html page
                                HTTP::respond 200 content $static::recaptcha_challenge_form Set-Cookie "this-is-human=$encrypted;Domain=$domainName"
                                return
                            }
                    }

                } else {
                    if { $debugSeverity > 7 }
                        {
                            set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[substr [string tolower [HTTP::uri]] 1 "/"],<Info : Check For Robot >"
                            log $debugSyslog $debugFacility $debug_log_line
                        }
                    # this responses with a html page including javascript and encrypted client ip cookie
                    HTTP::respond 200 content $humanResponse "Content-Type" "text/html"
                    #event disable
                    return
                }
            } else {
                if { $debugSeverity > 7 }
                    {
                        set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[substr [string tolower [HTTP::uri]] 1 "/"],<Info : Check For Robot >"
                        log $debugSyslog $debugFacility $debug_log_line
                    }
                # this responses with a html page including javascript and encrypted client ip cookie
                HTTP::respond 200 content $humanResponse "Content-Type" "text/html"
                #event disable
                return
            }
        }
    }
    if { [HTTP::path] equals "/verify_recaptcha" } {
        set recaptcha_challenge_field [URI::query [HTTP::uri] "recaptcha_challenge_field"]
        set recaptcha_response_field [URI::query [HTTP::uri] "recaptcha_response_field"]
        if { [HTTP::cookie exists "this-is-human"] } {
            if { ! [catch {b64decode [HTTP::cookie "this-is-human"]}] }
            {
                set requestNumber [findstr [subst [AES::decrypt $static::encrytionKey [b64decode [HTTP::cookie "this-is-human"]]]] "requestNumber" 14 " "]
            }
        } else {
            return
        }
        if { $debugSeverity > 5 }
        {
            set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[HTTP::path]],<Info : Session \"$requestNumber\": user responded with \"$recaptcha_response_field\" >"
            log $debugSyslog $debugFacility $debug_log_line
        }
        # assemble body of reCAPTCHA verification POST
        set recaptcha_post_data "privatekey=$static::recaptcha_private_key&"
        append recaptcha_post_data "remoteip=[IP::remote_addr]&"
        append recaptcha_post_data "challenge=$recaptcha_challenge_field&"
        append recaptcha_post_data "response=$recaptcha_response_field"

        # calculate Content-length header value
        set recaptcha_post_content_length [string length $recaptcha_post_data]

        # assemble reCAPTCHA verification POST request
        set recaptcha_verify_request "POST /recaptcha/api/verify HTTP/1.1\r\n"
        append recaptcha_verify_request "Host: www.google.com\r\n"
        append recaptcha_verify_request "Accept: */*\r\n"
        append recaptcha_verify_request "Content-length: $recaptcha_post_content_length\r\n"
        append recaptcha_verify_request "Content-type: application/x-www-form-urlencoded\r\n\r\n"
        append recaptcha_verify_request "$recaptcha_post_data"

        # resolve Google's IP address and stuff it into a variable
        set google_ip [lindex [RESOLV::lookup @$static::dns_server -a "www.google.com"] 0]

        # establish connection to Google
        set conn [connect -timeout 1000 -idle 30 $google_ip:80]
        if { $debugSeverity > 7 }
        {
            set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[HTTP::path]],<Info : Google reCAPTCHA IP Adresi : $google_ip >"
            log $debugSyslog $debugFacility $debug_log_line
        }

        # send reCATPCHA verification request to Google
        send -timeout 1000 -status send_status $conn $recaptcha_verify_request

        if { $debugSeverity > 5 }
        {
            set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[HTTP::path]],<Info : Session \"$requestNumber\": sending reCAPTCHA verification to Google: \"$recaptcha_verify_request\" >"
            log $debugSyslog $debugFacility $debug_log_line
        }
        # receive reCAPTCHA verification response from Google
        set recaptcha_verify_response [recv -timeout 1000 -status recv_info $conn]
        if { $debugSeverity > 5 }
        {
            set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[HTTP::path]],<Info : Session \"$requestNumber\": received verification response from Google: \"$recaptcha_verify_response\" >"
            log $debugSyslog $debugFacility $debug_log_line
        }

        close $conn

        # process reCAPTCHA verification response and remove user session from trigger table if successful
        if { $recaptcha_verify_response contains "success" } {
            set redirect_url [table lookup -subtable $static::recaptcha_redirect_table $requestNumber]

            table add -subtable $static::recaptcha_approval_table $requestNumber 1 \
            $static::recaptcha_approval_timeout $static::recaptcha_approval_lifetime
            if { $debugSeverity > 5 }
            {
                set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[HTTP::path]],<Info : Session \"$requestNumber\": passed captcha and was added to approval table and redirecting to \"$redirect_url\" >"
                log $debugSyslog $debugFacility $debug_log_line
            }
            HTTP::redirect $redirect_url
            return
        } else {
            HTTP::respond 200 content $static::recaptcha_challenge_form
            return

            if { $debugSeverity > 5 }
            {
                set debug_log_line "falog,$vsname,[IP::client_addr],[HTTP::method],[HTTP::host],[HTTP::path]],<Info : Session \"$requestNumber\": failed captcha  >"
                log $debugSyslog $debugFacility $debug_log_line
            }
        }
    }

    # increase level 2 (reCAPTCHA) Request Number
    table incr "ReqNumForReCaptcha"
    # add a request for level 2 table
    table set -subtable $static::tableNameForReCaptcha $ReqNumForReCaptcha "ignored" indef $static::lifetime
}

when CLIENT_ACCEPTED priority 100 {
    # this defines debug level
    set debugSeverity 6
    # this defines syslog server
    set debugSyslog "127.0.0.1"
    # this defines log facility level
    set debugFacility "local0.info"
    # this gets only virtual server name seprated from partition name
    set vsname [string range [virtual name] [expr {[string last / [virtual name] end] + 1}] end]
    if { $debugSeverity > 7 }
    {
        set debug_log_line "falog,$vsname,[IP::client_addr],,,,,<info : [IP::client_addr]:[TCP::client_port] -> [IP::local_addr]:[TCP::local_port],\
            ethernet [string range [LINK::lasthop] 0 16] -> [string range [LINK::nexthop] 0 16] tag [LINK::vlan_id]>"
        log $debugSyslog $debugFacility $debug_log_line
    }
}

The BIG-IP API Reference documentation contains community-contributed content. F5 does not monitor or control community code contributions. We make no guarantees or warranties regarding the available code, and it may contain errors, defects, bugs, inaccuracies, or security vulnerabilities. Your access to and use of any code available in the BIG-IP API reference guides is solely at your own risk.