Score:0

iptables not working with "x-forwarded-for" (behind Cloudflare)

jm flag

I have a webserver (Ubuntu with Apache) running behind Cloudflare. I want to block a user using the iptables. Here I want to implement the string match extension of iptables and drop the connection if x-forwarded-for matched. I am adding the rule with following command:

iptables -I INPUT -m string --string "x-forwarded-for: 216.244.66.205" --algo bm --to 65535 -j DROP

After adding this rule the client is still able to hit the server.

I know about Cloudflare's specific header for client IP that is cf-connecting-ip. If I add a rule with the following command it works as expected. Here is the rule which works fine:

iptables -I INPUT -m string --string "cf-connecting-ip: 216.244.66.205" --algo bm --to 65535 -j DROP

Why I want to use XFF instead of cf-connecting-ip:

I have a separate load-balancer (haproxy) and some of the domains are running through this instead of Cloudflare. That is why I want to use XFF because cf-connecting-ip is specific to Cloudflare and XFF is supported by both.

The traffic from Cloudflare to the Web server is HTTP (port 80) so http data is visible to the iptables.

I can see Cloudflare is properly attaching both cf-connecting-ip and XFF headers. Here is the output of tcpdump among multiple requests:

tcpdump -A -s 65535 'tcp port 80' | grep 216.244.66.205
x-forwarded-for: 216.244.66.205
cf-connecting-ip: 216.244.66.205
x-forwarded-for: 216.244.66.205
cf-connecting-ip: 216.244.66.205
x-forwarded-for: 216.244.66.205
cf-connecting-ip: 216.244.66.205
x-forwarded-for: 216.244.66.205
cf-connecting-ip: 216.244.66.205

Somehow the iptables are able to detect the cf-connecting-ip but not x-forwarded-for.

What am i doing wrong here?

Alex avatar
in flag
This looks related - https://serverfault.com/a/980916/802321
Ajaib Singh avatar
jm flag
@Alex this is not related. I am using the string-match extension instead of blocking the connecting IP. I know the connecting IP belongs to Cloudflare, that's why I am trying with XFF.
Score:1
us flag

The string match operates on the payload of single IP packet.

Therefore one possible reason is that the location of x-forwarded-for: header happens to be on a boundary of two TCP segments. Therefore first IP packet might contain x-forw and second IP packet arded-for:. Then the string match module doesn't match either packet.

To check if this is the reason, look into the different IP packet payloads belonging to the connection and see how the TCP segment is split into IP packets.

It is best to implement block features like this on HTTP level.

Ajaib Singh avatar
jm flag
How to look into packet payloads? Is it possible with tcpdump?
us flag
You can use tcpdump or Wireshark to inspect payloads. I don't have exact instructions to tell you how to do it though.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.