Overriding the X-Forwarded-For header in haproxy?

In my HAProxy load balancer, I have the following config chunks:

defaults
    mode                    http
    log                     global
    option                  httplog clf
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch

frontend  main_http *:80
    option forwardfor except 127.0.0.1
    option httpclose
    default_backend         backend_http

backend backend_http
    balance     roundrobin
    option httpchk
    server  node1 10.0.0.64:80 check port 80
    server  node2 10.0.0.65:80 check port 80
    server  node3 10.0.0.66:80 check port 80

On the nodes (Tomcat), I'm logging requests in this format (combined with x-forwarded-for in the first field and the real REMOTE_ADDR tacked onto the end):

pattern='%{X-Forwarded-For}i - %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %a'

This seems to work well for most requests, but in some cases, I assume in which the clients are behind proxies themselves, I'm seeing requests where the first field contains these values (each line represents one real request, I mangled the real IPs for privacy):

10.83.103.44, 10.83.103.44 
10.83.198.52, 10.83.198.52 
10.53.109.36, 10.53.109.36 
unknown, unknown 
192.168.1.43, 127.0.0.1 
192.168.11.189, 127.0.0.1 
10.1.6.3, 216.x.y.194, 10.37.52.202 
192.168.50.250, 38.x.y.5, 10.37.31.201 

According to the HAproxy docs, the last X-Forwarded-For should be the correct one that it appended, but this doesn't appear to be the case. My application uses the client IP for a geo lookup, so this isn't just a logging issue, it's actually screwing things up.

What I'd like to do is: instead of having HAproxy append the client's IP to the existing X-Forwarded-For header it receives, simply overwrite it. So if it receives X-Forwarded-For: 10.1.2.3 from IP addres 98.76.54.32, what it would send to the clients is just X-Forwarded-For: 98.76.54.32. Is there any way to do this? I'd like to know why such obvious junk is making it to the nodes - unknown, unknown is clearly junk info - but I'll settle for a workaround if one exists.

Thanks in advance.


Solution 1:

Tear it off the request header, before HAProxy adds its own:

reqidel ^X-Forwarded-For:.*

The risk to this change is that you'll lose your information about the "real" client IP address - your logs will then be showing the IP of the proxy server that the client is using. Sounds like you're ok with that!

As an aside, see this question for some interesting info on confusion over the append order of the X-Forwarded-For header.

Solution 2:

For anyone who is still puzzled, you can use one of these two snippets directly:

First:

backend forward_real_ip
    mode http
    reqidel ^X-Forwarded-For:.*
    option forwardfor

Second:

backend forward_real_ip
   mode http
   http-request set-header X-Forwarded-For %[src]

See the HAProxy docs:

  • Rewriting HTTP Protocol
  • reqidel