Apache Style Logging with HSL

Problem this snippet solves:

When SNATing to servers, the client IP is lost. This was information our security group and developers wanted to have available, so I created an iRule to use the HSL functionality in BigIP 10 to do that. Without cracking open the HTTP stream, I was unable to get the REMOTE_USER CGI variable, so I used that field to log the HTTP::host instead (since that information is lost with several VIPs logging to the same location).

Code :

# Apache: ClientIP - Username 10/Oct/2000
# iRule: ClientIP - Host 10/Oct/2000

   set hsl [HSL::open -proto UDP -pool syslog.example.com_syslog_pool]
   set clientip [IP::remote_addr]

   set method [HTTP::method]
   set uri [HTTP::uri]
   set host [HTTP::host]

   set now [clock format [clock seconds] -format "%d/%b/%Y:%H:%M:%S %z"]
   set contentlength [HTTP::header "Content-Length"]

   # Log HTTP request via syslog protocol as local7.info; see RFC 3164 for more info
   # local7 = 23; info = 6; 8*23 + 6 = 190
   HSL::send $hsl "<190> $clientip $host - $now \"$method $uri HTTP/[HTTP::version]\" [HTTP::status] $contentlength\n"
   #log local0. "<190> $clientip $host - $now \"$method $uri HTTP/[HTTP::version]\" [HTTP::status] $contentlength"

Tested this on version:

Published Jan 30, 2015
Version 1.0

Was this article helpful?


  • Would you mind elaborating on this a little? I'm pretty new, but I know how to apply this from a general view. However, I'm not sure what parts of this need to be tweaked to make this work for our setup. Does this log to the local syslog and rely on that being exported or does this require a pool of syslog servers to be set up? The part that I'm mainly unsure about is this: when CLIENT_ACCEPTED { set hsl [HSL::open -proto UDP -pool syslog.example.com_syslog_pool] set clientip [IP::remote_addr] }
  • Hi @hypercoyote (nice handle, btw), with HSL it will be sent to the log server defined in a pool you will need to set up. If you comment HSL out and uncomment the log statements, those will log to local file system. However, logging a lot of data traffic can be taxing on file i/o and slow things down, so you're better off logging remotely except for the design phase and troubleshooting.
  • Thanks Jason, I appreciate the info. I'll try to work that out. I appreciate your post though, this is something I know our security guys are going to want to be able to do.
  • Thanks Jason. This is working for our setup, providing exactly what we wanted to see. I appreciate the script, this has been immensely helpful. I'm still astounded this isn't a feature provided within the system itself. edit: One question though, the log only shows the source IP. Is there a way to show what IP it was SNAT'ed to?
  • After some messing around, I was able to produce the following that would grab the client's actual IP, their SNAT IP, the actual pool member IP, it's associated virtual server and the time of the initial connection. It will only log one entry when the connection to the server is torn down as opposed to multiple entries for every HTTP element that's accessed. The only concern I have with this setup is whether or not it will catch DDoS attempts. I'm not sure if the fact that it logs on SERVER_CLOSED means that it won't log when the server has too many open connections. when CLIENT_ACCEPTED { set now [clock format [clock seconds] -format "%Y/%b/%d:%H:%M:%S %z"] } when SERVER_CONNECTED { set view_clientip [IP::client_addr] set view_clientsnat [IP::local_addr] set view_serverip [IP::remote_addr] set view_servervip [clientside {IP::local_addr}] } when SERVER_CLOSED { set hsl [HSL::open -proto UDP -pool hsl_logging_servers] HSL::send $hsl "<190>snat_log: clientIP:$view_clientip {snat:$view_clientsnat} serverIP:$view_serverip {vip:$view_servervip} connected:$now\n" } The log entry looks like this: 2015-09-01 09:46:22Local7.Info10.10.0.3snat_log: clientIP: {snat:} serverIP: {vip:} connected:2015/Sep/01:09:45:50 -0500 edit: the comment formatting makes this look terrible.