Forum Discussion
Chris_Day_10331
Nimbostratus
Oct 04, 2005iRule for Server Testing
Good morning,
Please see attached doc.
Essentially, what we are trying to achieve is to be able to validate that a single server behind a VS is responding correctly. Ideally, we could rewrite both the request and the response to make the client "think" that it is receiving content from the URL to which they connected, when in fact it has been cloaked to the server and back to the client via header rewrite.
I'm assuming this must be possible, but have not seen this done before. Perhaps there are some other alternatives on how this could be done differently?
I could not attach the word document ("Invalid file type or exceeds max size(60kb)" even though the file is 28k) but here is the guts of the content:
RE: BIG-IP 1500
SN: bip071410s / bip071401s
Version: 9.0.5
Environment:
- 4 web servers: web001, web002, web003, web004
- front-ended by single VS on BIG-IP
Requirements:
1) Each web server runs multiple sites via HTTP/1.1 host headers:
companyA.pnimedia.com
companyB.pnimedia.com
companyC.pnimedia.com
2) Sites are accessed via virtual server on BIG-IP from front end and back end (via VPN)
3) We would like to be able to test (connect and verify) each web server independently, ideally through iRules processing.
Desired functionality:
http://companyA.test.pnimedia.com/web001
- use node web001 AND rewrite request/response to companyA.pnimedia.com
http://companyB.test.pnimedia.com/web003
- use node web003 AND rewrite request/response to companyB.pnimedia.com
Ideally, if the above could be specified in some sort of matrix/which statements like this:
web001 = 10.10.10.101
web003 = 10.10.10.113 (etc.)
I appreciate any comments, recommendations and/or sample iRules!
Thanks,
Chris
9 Replies
- Chris, I moved your post over to the iRules forum. Next time, if you could post iRules questions over there that would help you get a better response.
Also, the forums weren't configured to allow uploads of .doc files. I've modified that so you should be able to post your attachment (and I've bumped the size limit up to 100k).
Now, on to your question:
As for monitoring, iRules does not have the ability to test an application directly in the code. You will have to rely on either external monitors (if your errors are detected via HTTP content or network connectivity).
As for having iRules do some manipulation of the request uri then that has been covered many times here on the forum. Here's a sample on how you can build 2 classes, one for the host mapping and another for the node mapping.*** String data groups *** class host_mapping { companyA.test.pnimedia.com companyA.pnimedia.com companyB.test.pnimedia.com companyB.pnimedia.com companyC.test.pnimedia.com companyC.pnimedia.com } class node_mapping { web001 10.10.10.1 web002 10.10.10.2 web003 10.10.10.3 } *** Begin iRule *** when HTTP_REQUEST { Search for host mapping in the lookup list set new_host [findclass [HTTP::host] $::host_mapping " "] if { "" ne $new_host } { if mapping is found, replace the Host header log local0. "Replacing host from [HTTP::host] to $new_host" HTTP::header replace "Host" $new_host" Pull out the node name as the first element of the uri ie. /web001/foo/bar -> web001 set node_name [lindex [split [HTTP::uri] "/"] 1] if { "" ne $node_name } { Now look for the node address in the lookup list log local0. "Searching for node: $node_name" set node_addr [findclass $node_name $::node_mapping " "] if { "" ne $node_addr } { log local0. "Routing to node: $node_addr " node $node_addr } else { log local0. "Didn't find node '$node_name' in lookup class" } } else { log local0. "No node name passed in URI" } } else { log local0. "Didn't find [HTTP::host] in lookup class" } }
There may be more elegant ways to extract the node out of the uri without making a list. I'll leave it to you to figure that optimization out.
Good luck!
-Joe - Chris_Day_10331
Nimbostratus
Hey Joe,
Thanks a bunch! That is great! One problem I get trying to compile this rule under 9.0.5 is:
01070151:3: Rule [PNI_TestProcessor] error:
line 3: [undefined procedure: class] [class host_mapping {
companyA.test.pnimedia.com companyA.pnimedia.com
companyB.test.pnimedia.com companyB.pnimedia.com
companyC.test.pnimedia.com companyC.pnimedia.com
}]
Since I am relatively new to this, do you know if I am doing something wrong? I did not see any feature enhancements since 9.0.5 that seem to apply.
Also, if you have any whiz bang ideas on how to extract the node out of the URI I am all ears and will owe you a beer or 12.
Thanks,
Chris
FYI - I am an ex-F5 SE (worked with Vilnis) now working with a reseller (Pro-Data) up in Western Canada. - Colin_Walker_12Historic F5 AccountOh, and about the node name out of the URI, Joe's rule example does that already.
This section here is the part that performs the lookup:... Pull out the node name as the first element of the uri ie. /web001/foo/bar -> web001 set node_name [lindex [split [HTTP::uri] "/"] 1] if { "" ne $node_name } { Now look for the node address in the lookup list log local0. "Searching for node: $node_name" set node_addr [findclass $node_name $::node_mapping " "] if { "" ne $node_addr } { log local0. "Routing to node: $node_addr " node $node_addr ...
It does a lookup in this class to relate the "web001" or whatever the hostname is in the URI, to the actual IP of the node:class node_mapping { web001 10.10.10.1 web002 10.10.10.2 web003 10.10.10.3 }
So, for a request with web001 in the URI, it will be forwarded to 10.10.10.1.
Hopefully that helps clarify a bit.
-Colin - Chris_Day_10331
Nimbostratus
Hi Guys,
Thanks for replying - this is truly a big help. I now have a better understanding of how this all works and have been analyzing the results captured with tcpdump. Here is what I am seeing:
If I issue the following (via telnet):telnet blacks.test.pnimedia.com GET / HTTP/1.1 HOST: blacks.pnimedia.com
Everything works fine and I get the expected content.
*However*, via the rule I have created according to your posts everything seems to be correct. Is it possible that the HTTP/1.1 header is not being included in the request down to the node? I am seeing this (as expected) in the 'ltm' logs:Rule PNI_TestProcessor : Replacing host from blacks.test.pnimedia.com to blacks.pnimedia.com Rule PNI_TestProcessor : Searching for node: web002 Rule PNI_TestProcessor : Routing to node: 10.10.20.51
Which is correct!
Tcpdumps, however, reveal a different story. The external dump captured was as follows:tcpdump -w /var/tmp/external.dump -ni external port 80 and host 64.85.47.204
The internal dump captured was as follows:tcpdump -w /var/tmp/internal.dump -ni internal port 80 and host 64.85.47.204
Both of these are attached, but as a summary it looks like request is malformed.
For reference, here is what is in the rule "PNI_TestProcessor" which I have attached to the VS in question:when HTTP_REQUEST { Search for host mapping in the lookup list set new_host [findclass [HTTP::host] $::host_mapping " "] if { "" ne $new_host } { if mapping is found, replace the Host header log local0. "Replacing host from [HTTP::host] to $new_host" HTTP::header replace "Host" $new_host" Pull out the node name as the first element of the uri ie. /web001/foo/bar -> web001 set node_name [lindex [split [HTTP::uri] "/"] 1] if { "" ne $node_name } { Now look for the node address in the lookup list log local0. "Searching for node: $node_name" set node_addr [findclass $node_name $::node_mapping " "] if { "" ne $node_addr } { log local0. "Routing to node: $node_addr " node $node_addr } else { log local0. "Didn't find node '$node_name' in lookup class" } } else { log local0. "No node name passed in URI" } } else { log local0. "Didn't find [HTTP::host] in lookup class" } }
Do you guys have any ideas on this? - It doesn't look like your dumps were added. I've just added ".txt" as a valid attachment extension to the forums so if you could repost them with a .txt extension that would be great.
Also, in looking at your post, you are telnetting to the host but are not specifying port 80 so telnet should be defaulting to the default telnet port of 23 which shouldn't route to your web server. You said you received the correct response so I'm a bit confused how you did.
Also, if you could specify why you believe the request is invalid even though it returned a correct response that would help us out.
-Joe - Chris_Day_10331
Nimbostratus
My bad, the "80" for TCP/80 was on the end of that telnet string. I'll save you the output of that command ;-) I believe that the problem might be that this part:
GET / HTTP/1.1
HOST: blacks.pnimedia.com
...is not getting passed through to the host. Please see attached dumps, now as .txt.
Cheers,
Chris - In looking at your traces, they contain the following:
13:45:35.179821 64-85-47-204.ip.van.radiant.net.46721 > 10.10.10.100.http: P 1:421(420) ack 1 win 5840 (DF) 0x0000 4500 01d8 6996 4000 3906 51fb 4055 2fcc E...i.@.9.Q.@U/. 0x0010 0a0a 0a64 b681 0050 db6d cd96 3ea3 4800 ...d...P.m..>.H. 0x0020 8018 16d0 bf12 0000 0101 080a 01a4 06bc ................ 0x0030 af8c 12ea 4745 5420 2f77 6562 3030 322f ....GET./web002/ 0x0040 6465 6661 756c 742e 6173 7078 2048 5454 default.aspx.HTT 0x0050 502f P/ 13:45:35.180389 10.10.10.100.http > 64-85-47-204.ip.van.radiant.net.46721: P 1:169(168) ack 421 win 4800 (DF) 0x0000 4500 00dc e46b 4000 ff06 1221 0a0a 0a64 E....k@....!...d 0x0010 4055 2fcc 0050 b681 3ea3 4800 db6d cf3a @U/..P..>.H..m.: 0x0020 8018 12c0 60d4 0000 0101 080a af8c 1300 ....`........... 0x0030 01a4 06bc 4854 5450 2f31 2e31 2034 3030 ....HTTP/1.1.400 0x0040 2042 6164 2052 6571 7565 7374 0d0a 436f .Bad.Request..Co 0x0050 6e74 nt
This shows a request for "GET /web002/default.aspx HTTP/" and a server response of "HTTP/1.1 400 Bad Request".
This doesn't seem to line up with the commands you were issuing from telnet. Are you sure this is the trace from that session?
-Joe - Chris_Day_10331
Nimbostratus
Hi Joe,
You are correct. This was the trace from an actual request from IE, not the raw telnet GET request I illustrated above. The telnet command I did was only to verify that if indeed I requested the REAL header (blacks.pnimedia.com) the request would work through that VS. Have a look at these samples, which you can try (this site is publically available):
Using a masked hostname (blacks.test.pnimedia.com):telnet blacks.test.pnimedia.com 80 GET /web002/default.aspx HTTP/1.1 Host: blacks.test.pnimedia.com HTTP/1.1 400 Bad Request Content-Type: text/html Date: Wed, 05 Oct 2005 18:49:39 GMT Connection: close Content-Length: 39Bad Request (Invalid Hostname)
Using a real hostname (blacks.pnimedia.com):
- A HTTP 302 is returned, which is fine with me!telnet blacks.test.pnimedia.com 80 GET /web002/default.aspx HTTP/1.1 Host: blacks.pnimedia.com HTTP/1.1 302 Found Date: Wed, 05 Oct 2005 18:50:34 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 1.1.4322 Transfer-Encoding: chunked Location: /error.aspx Cache-Control: private Content-Type: text/html; charset=utf-8 80Object movedObject moved to . - My bad, In my original code I posted I had an extra quote at the end of the HTTP::header replace command:
HTTP::header replace "Host" $new_host"
This will basically add a \" to the $new_host value which obviously isn't what you want. Try changing the line to this:HTTP::header replace "Host" $new_host
and you should be all set.
-Joe
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
DevCentral Quicklinks
* 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
Discover DevCentral Connects