我让 Varnish 在反向代理后面运行(在 localhost 上运行,用于 SSL 卸载)。代理设置 X-Forwarded-For 标头,如果标头已存在,则将其自身添加到其中。
当我进行 ACL 检查时,我当然想检查原始客户端的 IP,而不是我的代理的 IP,所以我不能使用该client.ip
字段。使用std
vmod 我可以执行以下操作:
vcl 4.0;
import std;
sub vcl_recv {
if (std.ip(regsub(req.http.X-Forwarded-For, ", 127.0.0.1$", ""), "0.0.0.0") ~ my_acl) {
...do stuff...
}
}
换句话说,在运行它std.ip
并将其与我的 ACL 进行比较之前,我从标头中修剪了代理的 IP (127.0.0.1)。这工作正常,除了...
当 X-Forwarded-For 标头在到达我的代理之前已经设置时,这将失败。在这种情况下,XFF 标头包含三个或更多 IP 地址。修剪最后一个仍然会留下不止一个并std.ip
因此而窒息,将请求延迟几秒钟,当然也无法检查 ACL。
在我关闭代理后,我需要确保 XFF 标头仅包含一个 IP(IPv4 或 IPv6)。这应该是客户端的 IP。
例如:
X-Forwarded-For: 10.10.1.1, 10.10.2.2, 2001:a031:100a:dead:beef:1234:1234:1234, 127.0.0.1
应该成为
X-Forwarded-For: 2001:a031:100a:dead:beef:1234:1234:1234, 127.0.0.1
由于我不能信任从外部传入的任何 XFF 标头,因此我想丢弃除代理看到的客户端 IP 之外的任何内容。我的代理不支持修改 XFF 标头,所以我需要在 Varnish 中进行。
当我可以与标题交互时,Varnish 流程中的第一个点是 in vcl_recv()
,此时 Varnish 已经将 添加client.ip
到列表的末尾。
我希望使用正则表达式将最后两项(IPv4 或 IPv6)捕获到带编号的捕获组($1)中,并简单地将标头替换为捕获组。像这样:
vcl 4.0;
import std;
sub vcl_recv {
set req.http.X-Forwarded-For = regsub(req.http.X-Forwarded-For, "([a-f0-9:.]+, [a-f0-9:.]+)$", "\1");
}
第三个参数(替换正则表达式匹配的字符的字符串)不起作用。生成的标头与以前完全相同,即使正则表达式仅捕获最后两个 IP 地址。
除了 XFF 标头中的最后两个 IP 地址之外,我如何丢弃其他任何内容?