This is important, goddammit! This is a true story!
"I want you to have all the background. This is a very ominous assignment with overtones of extreme personal danger."
Every iptables aficionado on the Internet has an idea. Namely, this idea is that if you have the notion to track individual connections through a NAT router, you need a unique kernel module per protocol. Want to use FTP? Use ip_conntrack_ftp.o and ip_nat_ftp.o. Sometimes you'll luck out and get a twofer module that does conntracking and natting.
Either way, if you want to use XYZ protocol, everyone — I mean everyone — says you need ip_nat_XYZ.o. You need the kernel sources, you need to grab patch-o-matic, you need luck, and you need the skill to know how to not fuck up your entire Linux system when you install your new kernel. Every single iptables page and archived mailing list thread on this subject says so.
Every single list thread but one. This lone thread over at netfilter.org countermands every other piece of documentation on the subject on the Internet.
The thread pretty much negates the idea that you need a kernel module to manage (in this case) PPTP connections through iptables.
So what do you do? What underrated magic does Harald Welte put forth? What wonderful bit of TCP/IP arcana do you need to circumvent an entire, even risky, kernel compilation process?
DROP your packets.
You heard me. DROP them.
The idea is so amazingly simple it takes a genius to understand that simplicity.
- Every NAT router requires an explicit port redirect in order for external connections to reach your internal hosts. This is why you can have a web server on your Windows box and not worry about it getting hacked. If your router isn't forwarding connections to it from external hosts, then external hosts will never be able to reach it.
- A NAT router will take incoming requests from the hosts in its internal subnet and translate them. If you're behind a NAT router and you send your browser to www.cnn.com, the CNN servers aren't seeing the requests come from your machine. They see them come from your NAT router, and they send their responses to it. The NAT router has to be smart enough to say "Hey, thanks for the packets, CNN, but this isn't for me. This is for a host in the network behind me. I remember which one, so I can successfully deliver it for you. No problem."
- If you're using a dual-channel protocol like PPTP or FTP, you're going to have two connections going between each client-server pair. One handles the control instructions ("get me this file, delete that directory") and one handles the data ("here's that file you asked for: 010101001110101010..."). iptables has a helluva hard time associating these two connections to the same client-server pair because of the inherent port-blocking power of the NAT router. The client behind your NAT router can connect to the server, but when the server attempts to establish that second connection, the NAT router says "Sorry, Bub. You're sending me packets on another port and I have no clue why you're doing it." End result? Failed connection. People don't get their data.
- Let's say, for the sake of argument, that you just flat-out drop that connection attempt when it comes in from the server. You don't reject it. You don't forward it with an explicit redirect rule. (In iptables, it's a "DNAT" rule. In PF, it's "rdr".) You just...ignore it.
- The server waits patiently for you to respond to the packet it just sent you, but since that packet was doomed to begin with, it's waiting for a response it will never get.
- Instead, the client behind the NAT router realizes it hasn't gotten the packet it was supposed to receive by now, so instead it tries to establish the connection. This packet goes out through the NAT router and is automatically translated correctly. The NAT router now realizes that responses coming from the server should be redirected to the host behind the NAT router and the connection is completed without trouble.
So for PPTP, which uses TCP and GRE packets, you need to configure iptables accordingly:
# iptables -t nat -A PREROUTING -p 47 -s remote_server_ip -d your_nat_ip -m state --state NEW -j DROP
# iptables -t nat -A PREROUTING -p 47 -s remote_server_ip -d your_nat_ip -m state --state ESTABLISHED,RELATED -j ACCEPT
Brilliant.
No comments:
Post a Comment