Forum Discussion
Irule advice?
Hello,
I'm seeking advice on using an Irule to drop a connection when a certain condition is met in the URI. fid= followed by non numeric charectors. fid=1234 would pass. fid=13d4 would drop. Thanks!
when HTTP_REQUEST { if { [string tolower [HTTP::query]] contains "fld" } { if { ![string is digit [URI::query [HTTP::uri] "fld"]] } { log local0. "invalid fld value, rejecting from [IP::client_addr]" reject } } }
The following accounts for a POST request where the payload is URL encoded or XML:
when HTTP_REQUEST { if { [HTTP::method] eq "POST" } { ## Trigger collection for up to 1MB of data if { [HTTP::header exists "Content-Length"] && [HTTP::header "Content-Length"] <= 1048576 }{ set content_length [HTTP::header "Content-Length"] } else { set content_length 1048576 } ## Check if $content_length is not set to 0 if { $content_length > 0 } { HTTP::collect $content_length } } } when HTTP_REQUEST_DATA { set fld "" if { [HTTP::payload] contains "fld=" } { foreach x [split [HTTP::payload] "&"] { if { $x starts_with "fld=" } { set fld [lindex [split $x "="] 1] continue } } } elseif { [HTTP::payload] contains "<fld>" } { set fld [findstr [HTTP::payload] "<fld>" 5 "</fld>"] } if { $fld ne "" } { if { ![string is digit $fld] } { log local0. "invalid fld value, rejecting from [IP::client_addr]" HTTP::respond 400 content "Bad Request" "Content-Type" "text/html" "Connection" "close" } } }
- Kevin_Stewart
Employee
Try this:
when HTTP_REQUEST { if { [string tolower [HTTP::query]] contains "fld" } { if { ![string is digit [URI::query [HTTP::uri] "fld"]] } { log local0. "invalid char" } } }
- JD_Tomzak
Cirrus
That works well! Thanks
So the idea is to drop these connections and not send to the pool. Maybe send a 403 too. Thoughts?
-JD
- Kevin_Stewart
Employee
Just replace the log statement with whatever you want.
- Reject/drop
- HTTP response
- JD_Tomzak
Cirrus
Thanks for all of the help Kevin!
One last thought, any idea why the = is not in play? (fld=) Ignored? Also, how would this work if the digits were in front of fld instead of behind it? (12345=fld)
Just asking as I aim to get a better understanding of Irules in each of these engagements. Non programer, network guy...
- Kevin_Stewart
Employee
You're using URI::query and HTTP::query to get to the querystring values in an HTTP request. Example:
https://www.example.com/foo?fld=1234&bar=blah&this=that
The querystring is fld=1234&bar=blah&this=that. The above two commands conveniently let you pull apart the key-value pairs. I don't think there'd ever be a situation where you'd see 1234=fld, unless 1234 was the key. HTTP requires a specific format for querystrings where key=value (never value=key).
- JD_Tomzak
Cirrus
Reject works fine. Sorry I wasn't clear...I want the log entry and the reject.
Thanks,
- Kevin_Stewart
Employee
when HTTP_REQUEST { if { [string tolower [HTTP::query]] contains "fld" } { if { ![string is digit [URI::query [HTTP::uri] "fld"]] } { log local0. "invalid fld value, rejecting from [IP::client_addr]" reject } } }
- JD_Tomzak
Cirrus
Hi,
Sniffing the connection today, I see we send a rst-ack when the reject occurs. Possibe to respond with a 400 something and some verbage regarding the ivalid request data? Thanks,
- Kevin_Stewart
Employee
when HTTP_REQUEST { if { [string tolower [HTTP::query]] contains "fld" } { if { ![string is digit [URI::query [HTTP::uri] "fld"]] } { log local0. "invalid fld value, rejecting from [IP::client_addr]" HTTP::respond 400 content "Bad Request" "Content-Type" "text/html" "Connection" "close" } } }
- JD_Tomzak
Cirrus
Works perfect on port 80. Https not so much...thoughts? Thanks,
- Kevin_Stewart
Employee
You'd need to decrypt the HTTPS to trigger the HTTP iRule events, and insert HTTP responses. There wouldn't be any way to insert a HTTP 400 response without decrypting.
- JD_Tomzak
Cirrus
I am decrypting on that VIP. We also, re-encrypt on the wat to the poll members.
- Kevin_Stewart
Employee
Interesting. That iRule should work as long it's HTTP or you're decrypting HTTPS. Does the iRule event fire at all?
when HTTP_REQUEST { log local0. "here: [HTTP::uri]" if { [string tolower [HTTP::query]] contains "fld" } { if { ![string is digit [URI::query [HTTP::uri] "fld"]] } { log local0. "invalid fld value, rejecting from [IP::client_addr]" HTTP::respond 400 content "Bad Request" "Content-Type" "text/html" "Connection" "close" } } }
Do you get any odd messages in /var/log/ltm?
- JD_Tomzak
Cirrus
Yes, the Irule,fires, logs, etc.
When we do this on port 80, I see our error mesage and an orderly connection shutdown.
When https:, no message is returned and the connection ends with just us sending the rst-ack.
Thanks,
- Kevin_Stewart
Employee
Just tested and it appears to work fine for me with an HTTPS VIP (decrypting and re-encrypting).
If you tail the LTM log do you see anything unusual?
tail -f /var/log/ltm
- JD_Tomzak
Cirrus
So I solved the issue first thing this morning. I had left an expermintal Irule in the https version of the VIP that was impacting the test. Thanks again so much for your help on this. That revelation about Irule sytax follwoing HTTP request structure really cleared up a lot of confusion for me and I will continue to study this topic. -JD
- JD_Tomzak
Cirrus
So, still one issue. Can we make this work for POST as well. In this case the FID= is in the body, (x-www-for-urlencoded)
Thanks,
- Kevin_Stewart
Employee
Takes a little more work to get the HTTP payload from a POST request, but logic is mostly the same:
#} when HTTP_REQUEST { if { [HTTP::method] eq "POST" } { ## Trigger collection for up to 1MB of data if { [HTTP::header exists "Content-Length"] && [HTTP::header "Content-Length"] <= 1048576 }{ set content_length [HTTP::header "Content-Length"] } else { set content_length 1048576 } ## Check if $content_length is not set to 0 if { $content_length > 0 } { HTTP::collect $content_length } } } when HTTP_REQUEST_DATA { if { [HTTP::payload] contains "fld=" } { foreach x [split [HTTP::payload] "&"] { if { $x starts_with "fld=" } { if { ![string is digit [lindex [split $x "="] 1]] } { log local0. "invalid fld value, rejecting from [IP::client_addr]" HTTP::respond 400 content "Bad Request" "Content-Type" "text/html" "Connection" "close" } } } } }
- JD_Tomzak
Cirrus
Well the good news is most of this was already in place so it is working. Thanks!
The only thing missing is when they send it to me in XML sometimes instead of a key/value pair.
Not sure how often that comes up. But its not "fid =" in this case.
its <fid>1234a</fid><pw>test123</pw>
Thoughts?
- Kevin_Stewart
Employee
The following accounts for a POST request where the payload is URL encoded or XML:
when HTTP_REQUEST { if { [HTTP::method] eq "POST" } { ## Trigger collection for up to 1MB of data if { [HTTP::header exists "Content-Length"] && [HTTP::header "Content-Length"] <= 1048576 }{ set content_length [HTTP::header "Content-Length"] } else { set content_length 1048576 } ## Check if $content_length is not set to 0 if { $content_length > 0 } { HTTP::collect $content_length } } } when HTTP_REQUEST_DATA { set fld "" if { [HTTP::payload] contains "fld=" } { foreach x [split [HTTP::payload] "&"] { if { $x starts_with "fld=" } { set fld [lindex [split $x "="] 1] continue } } } elseif { [HTTP::payload] contains "<fld>" } { set fld [findstr [HTTP::payload] "<fld>" 5 "</fld>"] } if { $fld ne "" } { if { ![string is digit $fld] } { log local0. "invalid fld value, rejecting from [IP::client_addr]" HTTP::respond 400 content "Bad Request" "Content-Type" "text/html" "Connection" "close" } } }
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