HAProxy 1.4:如何用自定义 IP 替换 X-Forwarded-For

HAProxy 1.4: how to replace X-Forwarded-For with custom IP

我在 AWS ELB 后面有一个 HAProxy 1.4 服务器。逻辑上,ELB 在 X-Forwarded-For header 中发送用户 IP。我的应用读取 header 并根据 IP(国家/地区)表现不同。

我想测试使用自定义 IP 覆盖 X-Forwarded-For 的行为,但 AWS ELB 将我的自定义值附加到我当前的 IP (X-Forwarded-For: 1.2.3.4, 200.1.130.2)

我一直试图做的是发送另一个自定义 header X-Force-IP,一旦它进入 HAproxy,删除 X-Forwarded-For headers 并使用 reqirep 将名称 X-Force-IP 更改为 X-Forwarded-For

这是我的配置块的样子

acl custom-ip hdr_cnt(X-Force-IP) 1
reqidel ^X-Forwarded-For:.* if custom-ip
reqrep X-Force-IP X-Forwarded-For if custom-ip

但是当它进入我的应用程序时,应用程序服务器 (lighttpd) 以 "HTTP 400 Bad Request" 拒绝它,就好像它格式不正确一样。

[ec2-user@haproxy-stage]$ curl -I -H "X-Forwarded-For: 123.456.7.12" "http://www.example.com"
HTTP/1.1 200 OK
Set-Cookie: PHPSESSID=mcs0tqlsg31haiavqopdvm02i6; path=/; domain=www.example.com
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Type: text/html; charset=UTF-8
Date: Sun, 11 Jan 2015 02:57:34 GMT
Server: beta

[ec2-user@haproxy-stage]$ curl -I -H "X-Forwarded-For: 123.456.7.12" -H "X-Force-IP: 321.456.7.12" "http://www.example.com"
HTTP/1.1 400 Bad Request
Content-Type: text/html
Content-Length: 349
Date: Sun, 11 Jan 2015 02:57:44 GMT
Server: beta

从之前的情况来看,ACL 似乎正在运行。 我在应用程序服务器中检查了 tcpdump,它似乎删除了 X-Forwarded-For header 但也删除了 X-Force-IP 而不是替换它。

[ec2-user@beta ~]# sudo tcpdump -A -s 20240 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' | egrep --line-buffered "^........(GET |HTTP\/|POST |HEAD )|^[A-Za-z0-9-]+: " | sed -r 's/^........(GET |HTTP\/|POST |HEAD )/\n/g' 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 20240 bytes

GET / HTTP/1.1
User-Agent: curl/7.38.0
Host: www.example.com
Accept: */*
Connection: close

HTTP/1.1 400 Bad Request
Content-Type: text/html
Content-Length: 349
Connection: close
Date: Sun, 11 Jan 2015 02:56:50 GMT
Server: beta

前一个有X-Force-IP,下一个没有

GET / HTTP/1.1
User-Agent: curl/7.38.0
Host: www.example.com
Accept: */*
X-Forwarded-For: 123.456.7.12
Connection: close

HTTP/1.1 200 OK
X-Powered-By: PHP/5.3.4
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Type: text/html; charset=UTF-8
Connection: close
Transfer-Encoding: chunked
Date: Sun, 11 Jan 2015 02:57:02 GMT
Server: beta

^C71 packets captured
71 packets received by filter
0 packets dropped by kernel

有什么帮助吗? 我期待 "X-Force-IP: 321.456.7.12" 转换为 "X-Forwarded-For: 321.456.7.12"

谢谢! 伊格纳西奥

此处提供的正则表达式匹配不进行简单替换。还是比较厉害的,一定要好好利用。

reqrep ^X-Force-IP:(.*) X-Forwarded-For: if custom-ip

reqrep(区分大小写的请求正则表达式替换)和reqirep(不区分大小写的请求正则表达式替换)指令在单个请求 header 级别运行,替换 header name and its value with the 2nd argument, if the 1st argument matches... 所以如果有你想保留的信息(比如值)你需要一个或多个捕获组,例如第一个参数中的 (.*),以及第二个参数中的占位符 </code>,以便保留数据。</p> <p>您当前的配置确实通过创建 malformed/incomplete header 行使请求无效。</p> <p>此外,您应该使用 <code>^ 将模式固定在 header 名称的左侧。否则,表达式可能会匹配比预期更多的 header。