Ignoring out-of-band network policy systems with iptables

I’ve been working on parental controls using an out-of-band policy engine. It is easy to subvert, if you care to, since the controls it implements are very light, and it is not actually part of the conversation between you and the remote server.

Out of band policy engines are used for:

  • Transparent HTTP acceleration (we have a better and faster copy of what you want)
  • Network policy enforcement (we have a better idea of what you should be doing than you do)

The way these animals work is that they receive a copy of all the traffic on the network, and occasionally, when they are in the mood, they interfere with the traffic to provide helpful (or unhelpful) hints, namely:

  • TCP RST (the server you were talking to said sorry, we’re done)
  • HTTP redirects (the HTTP server you were talking to said please try another URL).

These tips are not provided by the server you are talking to, but by an intermediate server that sees fit to interfere with your communications. If your system ignores these helpful tips, then you can go on your merry way without the redirection and acceleration that they offer.

Here is a tcpdump of a connection to tumblr.com (a cesspool of questionable content) being blocked by a policy engine:

12:08:48.849796 IP 66.6.33.31.80 > 192.168.0.84.51172: Flags [P.], seq 2510308747:2510309104, ack 458187453, win 15, length 357: HTTP: HTTP/1.1 301 Moved Permanently
 12:08:48.849825 IP 192.168.0.84.51172 > 66.6.33.31.80: Flags [.], ack 381, win 251, options [nop,nop,sack 1 {0:357}], length 0
 12:08:49.099136 IP 192.168.0.84.51204 > 66.6.33.31.80: Flags [S], seq 3649489092, win 29200, options [mss 1460,sackOK,TS val 3200081088 ecr 0,nop,wscale 7], length 0
 12:08:49.313994 IP 192.168.0.84.51172 > 66.6.33.31.80: Flags [F.], seq 1, ack 381, win 251, length 0
 12:08:49.357485 IP 66.6.33.31.80 > 192.168.0.84.51204: Flags [S.], seq 2428884831, ack 3649489093, win 14600, options [mss 1460,nop,nop,sackOK,nop,wscale 10], length 0
 12:08:49.357557 IP 192.168.0.84.51204 > 66.6.33.31.80: Flags [.], ack 1, win 229, length 0
 12:08:49.357854 IP 192.168.0.84.51204 > 66.6.33.31.80: Flags [P.], seq 1:75, ack 1, win 229, length 74: HTTP: GET / HTTP/1.1
 12:08:49.359564 IP 66.6.33.31.80 > 192.168.0.84.51204: Flags [FP.], seq 1:381, ack 75, win 4096, length 380: HTTP: HTTP/1.0 302 Moved
 12:08:49.359725 IP 66.6.33.31.80 > 192.168.0.84.51204: Flags [R.], seq 1, ack 75, win 16, length 0
 12:08:49.359742 IP 66.6.33.31.80 > 192.168.0.84.51204: Flags [FP.], seq 1:381, ack 75, win 4096, length 380: HTTP: HTTP/1.0 302 Moved
 12:08:49.359770 IP 192.168.0.84.51204 > 66.6.33.31.80: Flags [.], ack 382, win 251, options [nop,nop,sack 1 {1:382}], length 0
 12:08:49.359835 IP 66.6.33.31.80 > 192.168.0.84.51204: Flags [R.], seq 1, ack 75, win 16, length 0

The highlighted lines appear to be a very quick response from the remote server, saying (1) go to another URL and (2) close the connection – and these are the packets that were generated by the policy engine. The real server is blissfully unaware of the interference, and sends its own response – but by then, the connection has been closed:

 12:08:49.360259 IP 192.168.0.84.51204 > 66.6.33.31.80: Flags [F.], seq 75, ack 382, win 251, length 0
 12:08:49.615439 IP 66.6.33.31.80 > 192.168.0.84.51204: Flags [.], ack 75, win 15, length 0
 12:08:49.615475 IP 192.168.0.84.51204 > 66.6.33.31.80: Flags [.], ack 382, win 251, length 0
 12:08:49.615487 IP 66.6.33.31.80 > 192.168.0.84.51204: Flags [P.], seq 1:358, ack 75, win 15, length 357: HTTP: HTTP/1.1 301 Moved Permanently
 12:08:49.615505 IP 192.168.0.84.51204 > 66.6.33.31.80: Flags [.], ack 382, win 251, options [nop,nop,sack 1 {1:358}], length 0
 12:08:50.033977 IP 192.168.0.84.51204 > 66.6.33.31.80: Flags [F.], seq 75, ack 382, win 251, length 0
 12:08:50.202639 IP 66.6.33.31.80 > 192.168.0.84.51204: Flags [P.], seq 1:358, ack 75, win 15, length 357: HTTP: HTTP/1.1 301 Moved Permanently
 12:08:50.202668 IP 192.168.0.84.51204 > 66.6.33.31.80: Flags [.], ack 382, win 251, options [nop,nop,sack 1 {1:358}], length 0

By simply ignoring these packets, you can do (mostly) normal communications:

iptables  -I INPUT -p tcp -m tcp --tcp-flags RST RST -m multiport --sports 80,443 -j DROP
iptables -I INPUT -p tcp -m tcp --sport 80 -m string --string "Location: http://100.64.12.12:" --algo bm --to 65535 -j DROP
# iptables -I INPUT -p tcp -m tcp --sport 80 -m string --string "Location: http://" --algo bm --to 65535 -j DROP

The first ignores TCP reset packets from web servers, so that there is no way for a remote web server to shut down the connection.

The second ignores packets that redirect to the policy engine enforcement URL, or to the caching server’s delivery URL – you need to customise that for your own policy engine’s redirects.

These rules could probably be improved to look for the tell-tale sequence number of 1, if the policy engine does what this one does. Oh wait, looking into that, it’s not going to work – that’s a synthetic number. It might work to check the TTL and only drop those that have the magic TTL that matches the distance from you to the filter device.

This entry was posted in Stuff and tagged , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *