Scott_Wozny_894
Jun 13, 2012Nimbostratus
Find and replace hostname strings in http payload
Dear iRule gurus,
First and foremost, I apologize for the length of this post. I've done a bunch of work on my own to get to this point and I just want to be sure all the relevant details are included. If, based upon the summary, you think you have a suggestion on multiple string replace in response payload, please feel free to post and I'll take it from there. :)
From the beginning, I have a situation where we need to upgrade our RSA server to 7.1. There is a web-based token management app on that server on TCP/7004 and I need to grant access over the Internet to my business partners and end users for token approval, deployment and activation. As I can’t rely on my business partners or users IT departments to allow Internet connections over a non-standard port, I have set up an externally accessible VS that responds over HTTPS with the public name’s cert and key installed and the pool member (the RSA server) is set to service TCP/7004. This works to get to the server itself and when I send a request for an invalid URL the 404 I get back is just fine so I know I’m getting through to the server. However, when I use the external name to get to one of the server’s applicaiton pages, the server immediately sends me a redirect to another page but uses the internal server name in the redirect which is not resolvable to the outside world and the connection breaks. BTW, I have begged RSA to let me install my publicly available cert/key on the server and change the name to the publicly resolvable name so I could do this all with a simple port translation but they have told me it’s not a supported configuration so now I need something to proxy the connections which is what I want to use the F5 for.
So, the next step was to fix the headers and switch out the external for internal names in each direction. I wrote an iRule that, on requests, swaps out the external for internal name and custom port (I tried it originally with just swapping out the name, but some pages wouldn’t load and when I tested internally, it looks like some requests need the port so I put it on all inbound requests whether it needs it or not and this seems to work fine). Then I wrote 2 additional events to replace the location in a redirect with my external name, allowing the browser to turn the request back around using the external name and letting the F5 switch that name back out for the internal name by the time it gets back to the RSA server. I look for locations with the port number in them first and then the ones with no port number. If I were to do it in the other order, the redirect location on some responses would include the TCP/7004 port number and the page load would break. Also, as there are no Location elements in a 200/OK (that I can see) I think I’ve done all I need to do with the headers.
Now here is the problem and why I’m reaching out to the forums to see if anyone else has gotten around this. When the RSA server produces the pages, inside the page payload many times the HREFs only refer to the URI with no server name and that works just fine, but there are also many locations in the payload where the internal name is referred in the HTML being sent back to the browser (terrible coding practice, I know, but RSA won't let me touch the code). When anything that refers to that name is clicked on, the browser returns a PNF because it can’t resolve that name. What I need is a way in iRules to replace every instance of the internal server name and port in a response (the responses never exceed 1MB) with the external server name before returning it to the user’s browser. I have found documentation showing how to replace the entire payload with some static data, or portions of the payload past a certain point, but I can’t find any way to do string based replacements on multiple instances inside the payload.
Has anyone run into this before? I can’t imagine I’m the first but I’ve dug through as much of the iRule documentation and these forums as I can find, but I can’t find a way to do this. I’ve included the iRule code I’ve written / borrowed thus far to handle the headers in case it’s relevant. Any suggestions would be appreciated. Also, this server is not worked very hard (on the order of about 10 sessions a day on a busy day) so efficiency is not a high priority. I just need something that works.
Thanks,
Scott
-----BEGIN CODE HERE-----
Translate the hostname of inbound requests from external name to
internal name and port
when HTTP_REQUEST {
if { [HTTP::host] equals "rsa.tst.publicdomain.com"} {
log local0. "Replacing Host header [HTTP::host] with internalservername.internaldomain.com:7004"
HTTP::header replace "Host" "internalservername.internaldomain.com:7004"
}
}
Translate the redirect location from internal name and port to
external name
This one goes first because doing the name and not the port (if
it's there) breaks the session
when HTTP_RESPONSE priority 100 {
if { [HTTP::header is_redirect]} {
HTTP::header replace Location [string map -nocase {internalservername.internaldomain.com:7004 rsa.tst.publicdomain.com} [HTTP::header value Location]]
log local0. "Replacing Location header internalservername.internaldomain.com:7004 with rsa.tst.publicdomain.com"
}
}
Translate the redirect location from internal name to external name
if no port is indicated
This one goes second to catch any Locations that don't have the port
number included
when HTTP_RESPONSE priority 200 {
if { [HTTP::header is_redirect]} {
HTTP::header replace Location [string map -nocase {internalservername.internaldomain.com rsa.tst.publicdomain.com} [HTTP::header value Location]]
log local0. "Replacing Location header internalservername.internaldomain.com with rsa.tst.publicdomain.com"
}
}
-----END CODE HERE-----