#!/usr/bin/perl -Tw | |
# build_iptables.pl domain_list [ domain_list... ] | |
# | |
# Create a firewall ruleset in iptables-restore format to create a layer 4 DNS | |
# proxy using NAT that filters domains from given lists. | |
# In this example: | |
# - 123.123.123.158 is the proxy address. | |
# - 123.123.123.{152,154,156} are the real DNS resolvers. | |
# Copyright (c) 2009 Terry Burton | |
# | |
# http://www.terryburton.co.uk | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY | |
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO | |
# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | |
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | |
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
# IN THE SOFTWARE. | |
use strict; | |
die "Usage: $0 domain_list [ domain_list... ]" unless $#ARGV>=0; | |
my @doms=(); | |
foreach my $filename (@ARGV) { | |
open(FILE,"<$filename") or die("Unable to open file"); | |
@_=<FILE>; | |
close(FILE); | |
map {chomp} @_; | |
push @doms,@_; | |
} | |
print <<'EOF'; | |
*mangle | |
:PREROUTING ACCEPT [0:0] | |
-A PREROUTING -d 123.123.123.158 -p udp -m udp --dport 53 -m statistic --mode nth --every 3 --packet 0 -m state --state new -j CONNMARK --set-mark 1 | |
-A PREROUTING -d 123.123.123.158 -p udp -m udp --dport 53 -m statistic --mode nth --every 3 --packet 1 -m state --state new -j CONNMARK --set-mark 2 | |
-A PREROUTING -d 123.123.123.158 -p udp -m udp --dport 53 -m statistic --mode nth --every 3 --packet 2 -m state --state new -j CONNMARK --set-mark 3 | |
-A PREROUTING -d 123.123.123.158 -p tcp -m tcp --dport 53 -m statistic --mode random --probability 0.333333 -m state --state new -j CONNMARK --set-mark 1 | |
-A PREROUTING -d 123.123.123.158 -p tcp -m tcp --dport 53 -m statistic --mode random --probability 0.5 -m state --state new -j CONNMARK --set-mark 2 | |
-A PREROUTING -d 123.123.123.158 -p tcp -m tcp --dport 53 -m state --state new -j CONNMARK --set-mark 3 | |
COMMIT | |
*nat | |
:PREROUTING ACCEPT [0:0] | |
:POSTROUTING ACCEPT [0:0] | |
-A PREROUTING -m connmark --mark 1 -j DNAT --to-destination 123.123.123.152 | |
-A PREROUTING -m connmark --mark 2 -j DNAT --to-destination 123.123.123.154 | |
-A PREROUTING -m connmark --mark 3 -j DNAT --to-destination 123.123.123.156 | |
-A POSTROUTING -m connmark --mark 1 -j SNAT --to-destination 123.123.123.158 | |
-A POSTROUTING -m connmark --mark 2 -j SNAT --to-destination 123.123.123.158 | |
-A POSTROUTING -m connmark --mark 3 -j SNAT --to-destination 123.123.123.158 | |
COMMIT | |
*filter | |
:LOGDROP - [0:0] | |
-A LOGDROP -m limit --limit 1/second --limit-burst 100 -j LOG | |
-A LOGDROP -j DROP | |
:DNSCHECK - [0:0] | |
:FORWARD ACCEPT [0:0] | |
-A FORWARD -s 123.123.0.0/16 -p udp --dport 53 -m u32 --u32 "0>>22&0x3C@8>>15&0x01=0" -j DNSCHECK | |
-A FORWARD -s 123.123.0.0/16 -p udp --dport 53 -j ACCEPT | |
-A FORWARD -s 123.123.0.0/16 -p tcp --dport 53 -j ACCEPT | |
-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT | |
-A FORWARD -j LOGDROP | |
EOF | |
my $last_prefix=''; | |
foreach my $dom (sort @doms) { | |
(my $prefix,my $suffix)=$dom=~/^(..)(.*)$/; | |
if ($prefix ne $last_prefix) { | |
$last_prefix=$prefix; | |
print ":DNSCHECK$prefix - [0:0]\n"; | |
if ($prefix=~/^.\./) { | |
my $hex=sprintf("01%02lx", ord substr($prefix,0,1)); | |
print "-A DNSCHECK -m u32 --u32 \"0>>22&0x3C\@18&0xffff=0x$hex\" -j DNSCHECK$prefix\n"; | |
} else { | |
(my $hex=$prefix)=~s/(.)/sprintf("%02lx", ord $1)/eg; | |
print "-A DNSCHECK -m u32 --u32 \"0>>22&0x3C\@19&0xffff=0x$hex\" -j DNSCHECK$prefix\n"; | |
} | |
} | |
my $enc=''; my $offset=40; | |
foreach (split /\./, $dom) { | |
$enc.='|'.(sprintf '%02x', length)."|$_"; | |
$offset+=(length $_)+1; | |
} | |
print "-A DNSCHECK$prefix -m string --from 40 --to $offset --hex-string \"$enc|00|\" --algo bm -j LOGDROP\n"; | |
} | |
print <<'EOF' | |
COMMIT | |
EOF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment