Can IP tables allow specific DNS queries based on domain name?
I have iptables blocking all UDP traffic at the moment, however I want to allow only certain DNS queries to get through.
Let's use google.com as an example.
I am trying to use string matching to find the domain name in the request, and allow it. This is what I came up with.
iptables -A OUTPUT -o eth0 -p udp --sport 53 -m string --string "google.com" --algo bm -j ACCEPT
I have also tried --dport 53
instead of --sport
. No dice.
If anyone knows how this can be done or see's where I went wrong?
Solution 1:
the dot "." in a DNS query is not represented as a character, but as the length of the string that follows. For example www.google.com is queried as
0x03 w w w 0x06 g o o g l e 0x03 c o m
you can easily allow/block DNS queries by matching the domain names with --hex-string. In your case:
-m string --algo bm --hex-string '|06 676f6f676c65 03 636f6d|' -j ACCEPT
will accept every DNS packet containing ".google.com".
I often use this technique against the DNS query amplification attack.
source: DNS RFC 1035
Solution 2:
To complement nrc's anwser, where is a quick command to convert domains to the hexadecimal string:
DOMAIN=google.com
perl -e 'print map {chr(length($_)).$_} split /\./, "'$DOMAIN'" | xxd -p
So, in your case:
DOMAIN=google.com
HEX=$(perl -e 'print map {chr(length($_)).$_} split /\./, "'$DOMAIN'"' | xxd -p)
iptables -A OUTPUT -o eth0 -p udp --sport 53 \
-m string --hex-string "|$HEX|" --algo bm -j ACCEPT