Eu tenho o Varnish rodando atrás de um proxy reverso (rodando no host local, para descarregamento de SSL). O proxy define o cabeçalho X-Forwarded-For ou se adiciona a ele se o cabeçalho já existir.
Quando faço verificações de ACL, é claro que quero verificar o IP do cliente original, não o IP do meu proxy, portanto, não posso usar o client.ip
campo. Com o std
vmod posso fazer o seguinte:
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...
}
}
Em outras palavras, eu corto o IP do proxy (127.0.0.1) do cabeçalho antes de executá-lo std.ip
e compará-lo com minha ACL. Isso funciona bem, exceto...
Isso falha quando o cabeçalho X-Forwarded-For já está definido antes de atingir meu proxy. Nesse caso, o cabeçalho XFF contém três ou mais endereços IP. Aparar o último ainda deixa mais de um e std.ip
engasga com isso, atrasando a solicitação por vários segundos e, claro, falhando em verificar o ACL.
Preciso garantir que o cabeçalho XFF contenha apenas um IP (IPv4 ou IPv6) depois de cortar o proxy. Este deve ser o IP do cliente.
Por exemplo:
X-Forwarded-For: 10.10.1.1, 10.10.2.2, 2001:a031:100a:dead:beef:1234:1234:1234, 127.0.0.1
Deve se tornar
X-Forwarded-For: 2001:a031:100a:dead:beef:1234:1234:1234, 127.0.0.1
Como não posso confiar em nenhum cabeçalho XFF que venha de fora, gostaria de descartar qualquer coisa, exceto o ip do cliente que meu proxy viu. Meu proxy não suporta a modificação do cabeçalho XFF, então precisarei fazer isso no Varnish.
O primeiro ponto no fluxo do Varnish em que posso interagir com os cabeçalhos é dentro vcl_recv()
e, nesse ponto, o Varnish já adicionou o client.ip
ao final da lista.
Eu esperava usar uma expressão regular para capturar os dois últimos itens (IPv4 ou IPv6) em um grupo de captura numerado ($ 1) e simplesmente substituir o cabeçalho pelo grupo de captura. Assim:
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");
}
O terceiro argumento (a string que substitui os caracteres correspondentes ao regex) não funciona. O cabeçalho resultante é exatamente o mesmo de antes, embora o regex capture apenas os dois últimos endereços IP.
Como posso jogar fora qualquer coisa além dos dois últimos endereços IP do cabeçalho XFF?
Seu regex parece bom. A única coisa que vejo é que você solicita a substituição do grupo por si só.
Deve funcionar se você adicionar
^(.*)
no inÃcio do seu regex e substituir o segundo argumento por\2
}
Dito isso, não acho uma boa ideia alterar o cabeçalho XFF. Deve ser mais padrão adicionar um cabeçalho em vez de alterar as informações de exclusão que foram transmitidas por proxies intermediários.