Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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 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 "" --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?

share|improve this question
Post the output of iptables -L -n -v – dmourati Dec 31 '12 at 6:43
Why dont you give access to only required authoritative DNS servers ?? i.e. ns[1-4] in this case – Garfield Carneiro Dec 31 '12 at 7:11
@Jarred Kenny: This usage of string matching in iptables is not accurate. Why do you need to do this? Are you trying to block some websites? – Khaled Dec 31 '12 at 8:14
@Khaled The server connects to a VPN at book. I am writing these rules to prevent any DNS queries being sent over the regular eth0. This rule is an attempt to only allow the DNS queries related to the VPN provider. For example, I only want DNS queries to resolve for * domain names. Once the VPN is connected, DNS queries get piped via the tun- interface and the rule is not relevant. It is just a precaution. – Jarred Kenny Dec 31 '12 at 12:20
You'd probably be better off installing a local DNS server on the machine with selective forwarding. E.g. disable recursion except for zone – James O'Gorman Dec 31 '12 at 18:59

the dot "." in a DNS query is not represented as a character, but as the length of the string that follows. For example 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 "".

I often use this technique against the DNS query amplification attack.

source: DNS RFC 1035

share|improve this answer

To complement nrc's anwser, where is a quick command to convert domains to the hexadecimal string:
perl -e 'print map {chr(length($_)).$_} split /\./, "'$DOMAIN'" | xxd -p

So, in your case:
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
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.