Search code examples
proxyiphaproxyx-forwarded-for

HAProxy: Take the middle IP from X-Forwarded-For into a new header


In haproxy.cfg I'm trying to extract the proper IP address from x-forwarded-for header into a new custom header.

my input request header would be something like

X-Forwarded-For: 1.2.3.4, 2.3.4.5, 3.4.5.6

And my expected new header would be something like:

X-Custom-IP: 2.3.4.5

thanks


Solution

  • Original answer:

    You can use the field sample-fetcher transformation keyword: https://cbonte.github.io/haproxy-dconv/configuration-1.6.html#7.3.1-field

    Since there's no way to count fields in the current haproxy, I'd write a several simple ACLs with a regexp over the X-Forwarded-For header that detect 0, 1, 2, 3, 4, 5 different IPs (or actually, comma separator) and based on that, select the proper field to put in the X-Custom-IP.

    E.g. (not tested)

    acl x_forwarded_for_1_ips hdr(x-forwarded-for) -i (?:[0-9]{1,3}\.){3}[0-9]{1,3}
    acl x_forwarded_for_2_ips hdr(x-forwarded-for) -i ((?:[0-9]{1,3}\.){3}[0-9]{1,3},){1}(?:[0-9]{1,3}\.){3}[0-9]{1,3}
    acl x_forwarded_for_3_ips hdr(x-forwarded-for) -i ((?:[0-9]{1,3}\.){3}[0-9]{1,3},){2}(?:[0-9]{1,3}\.){3}[0-9]{1,3}
    acl x_forwarded_for_4_ips hdr(x-forwarded-for) -i ((?:[0-9]{1,3}\.){3}[0-9]{1,3},){3}(?:[0-9]{1,3}\.){3}[0-9]{1,3}
    acl x_forwarded_for_5_ips hdr(x-forwarded-for) -i ((?:[0-9]{1,3}\.){3}[0-9]{1,3},){4}(?:[0-9]{1,3}\.){3}[0-9]{1,3}
    
    http-request add-header X-Custom-Ip %[hdr(x-forwarded-for)] if x_forwarded_for_1_ips
    http-request add-header X-Custom-Ip %[hdr(x-forwarded-for),field(2,\,)] if x_forwarded_for_2_ips
    http-request add-header X-Custom-Ip %[hdr(x-forwarded-for),field(2,\,)] if x_forwarded_for_3_ips
    http-request add-header X-Custom-Ip %[hdr(x-forwarded-for),field(3,\,)] if x_forwarded_for_4_ips
    http-request add-header X-Custom-Ip %[hdr(x-forwarded-for),field(3,\,)] if x_forwarded_for_5_ips
    

    Let me know if it works for you, or you found a different better solution :)


    Edit: funny, it didn't even take 5 minutes for me to find a better solution.

    Use the hdr_ip sample-fetcher: https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#7.3.6-hdr_ip

    You'd still need the ACLs to count the IPs, but you can use hdr_ip(x-forwarded-for,2) and hdr_ip(x-forwarded-for,3) directly, no need for Field().