Forum Discussion

Rostislav_Zatol's avatar
Rostislav_Zatol
Icon for Nimbostratus rankNimbostratus
Nov 20, 2009

replace IP in POST body with source IPaddr

Hello,

 

 

I am searching for possibility to replace in xml formated HTTP POST body an IPaddress with TCP source IP address.

 

 

I sure have to use STREAM. So something like this:

 

 

 

when HTTP_REQUEST {

 

STREAM::disable

 

if {[HTTP::header value Content-Type] contains "text" && [HTTP::method eq "POST"]}

 

{

 

 

STREAM::expression "@string\">\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}@IP::addr@"

 

 

STREAM::enable

 

}

 

}

 

 

Any suggestions else?

 

 

BR

 

RZ

6 Replies

  • Hi RZ,

     

     

    There isn't a way to update the content-length header in an HTTP request, so unless the original and replacement strings are the same length, I don't think you can use a stream profile and iRule to replace content in the request payload. You'd be better off collecting the payload using HTTP::collect and modifying it with HTTP::payload.

     

     

    You can check the HTTP::collect wiki page for examples (Click here). Make sure you add a check to the collection logic so that if the content-length is over 4Mb, you only collect 4Mb. If you're applying regexes to the payload, you might want to lower the collection amount to 1Mb. Failing to do so will result in a TMM crash and a complete loss of service through LTM. See the note on the wiki page for details:

     

     

    Note that although any size payload can theoretically be collected, the maximum size of a Tcl variable is 4MB with a smaller functional maximum after charset expansion of approximately 1MB. Any payload manipulation outside of calls to HTTP::payload should obey that limit. The 2nd example below includes the best practice logic to enforce that limit, including the suppression of response chunking to allow more accurate determination of collect length.

     

     

     

    Also, if it's only a small percentage of POST requests that you need to rewrite, you should try to restrict the payload collection to specific requests (either by URI, client IP, Host header, etc).

     

     

    Aaron
  • Hello,

     

     

    Trying to proceed with my idea, but have found following problem:

     

     

     

    If I user REGEX to search for IP adress format string, I have to use {} brackets.

     

    STREAM::expression {@\"xsd:string\">\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}@"xsd:string">[IP::client_addr]@}

     

    But it seems in this case variable [IP::client_addr] is nor available for replacement.

     

     

    Have tryed with "", the REGEXP doese not match.

     

     

    If I dont use REGEXP and try to match to test device with hardcoded IP, it works:

     

    STREAM::expression "@\"xsd:string">10.0.0.139@\"xsd:string\">[IP::client_addr]@"

     

     

    Any Ideas to bring both cases together? I dont want to search with *.*.*.* for IP address.

     

     

    BR

     

    RZ
  • Hi RZ,

     

     

    As I mentioned before, I don't think a stream profile/iRule will work for rewriting request payloads where the search and replace string are different lengths. The reason for this is that there is no way to update the Content-Length header. So the rewritten request payload won't be valid.

     

     

    If you use HTTP::collect and HTTP::payload, LTM will update the Content-Length header for you.

     

     

    Also, the reason [IP::client_addr] isn't working is that the curly braces prevent interpretation of variables and commands. This would allow variable expansion:

     

     

    set client_ip [IP::client_addr]

     

    STREAM::expression [subst -nocommands {@\"xsd:string\">\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}@"xsd:string">$client_ip@}]

     

     

    Aaron
  • It seems that I really have problem with content-Length. AP server denies if it doese not match :-(

     

     

    So I am trying to replace payload now

     

     

    With fix mapping it works:

     

    HTTP::payload replace 0 [HTTP::payload length] [string map -nocase "10.0.0.139 $client_ip" [HTTP::payload]]

     

     

    But folliowing case doese not match. Its mandatory to match whole strings including newline and space :-(

     

     

    set client_ip [IP::client_addr]

     

    HTTP::payload replace 0 [HTTP::payload length] [string map -nocase {"IPAddress\n*.*.*.*" "IPAddress\n$client_ip"} [HTTP::payload]]

     

     

    damn...

     

     

    BR

     

    RZ
  • You can use subst with HTTP::payload like I did for the STREAM::expression example.

     

     

    Aaron
  • ie, can you try this?

     

     

    HTTP::payload replace 0 [HTTP::payload length] [string map -nocase [subst {"IPAddress\n*.*.*.*" "IPAddress\n$client_ip"}] [HTTP::payload]]

     

     

    Aaron