Can anyone please suggest a way to use a domain name in iptables rules.

5 Answers 5


If it is all possible please consider setting up a transparent application-level proxy. An application proxy will probably be much easier to do this type of filtering with.

If you must do it with iptables a kludgy option would be to create a chain, create a command line script that periodically updates that particular chain with the results from DNS for the name you need to use.

If someone was going to attempt to create such a thing that truly did packet-filtering based DNS it would almost certainly have to be done via userspace. Specifically you would use something like libnetfilter_queue. I have never used it, but Packetbl may be close to do this, but it doesn't appear to be very well maintained.

Another alternative might be to setup Layer 7 filtering. You might be able to filter a portion of the request if DNS name is being transmuted as part of the payload of the packet.


Short answer, if you are sure the IP is static forever:

iptables -A INPUT -s `dig host.your-domain-name.com +short`/32 -p tcp -m tcp --dport 22 -j ACCEPT
  • I don't think you need the /32. Also, what happens if the dig command fails? Oct 8, 2022 at 17:50

I needed iptables to allow ssh access based on domain name from my home ip but wanted to keep it closed for all other addresses. Since I have a dynamic ip that changes occasionally, I wrote a script to update the rules based on the ip of my dynamic dns entry. I'm new at this so I'm sure there is a better way. Replace "yourname" with your dynamic dns hostname.


/usr/bin/nslookup yourname.dynalias.org > temp
while read LINE
 if [[ "$LINE" == Address* ]]; then
        let found++
        if [[ $found == 2 ]]; then
                /sbin/iptables-save > /root/rulesdump
                while read LINE2
                        if [[ "$LINE2" == *$address* ]]; then
                done < /root/rulesdump;
                if [[ "$ruleexists" != 1 ]]; then
                        /sbin/iptables -D INPUT -j LOG_DROP
                        /sbin/iptables -A INPUT -s $address -p tcp -m tcp --dport 22 -j LOG_ACCEPT
                        /sbin/iptables -A INPUT -j LOG_DROP
done < /root/temp;

Put the above script in crontab to run every so often.

  • 2
    Its hard for me to decipher whether you do remove old IPs or not. I would also consider using a separate chain so you could make a more straight forward "here's all the new config, just replace the old" approach.
    – Theuni
    Dec 8, 2012 at 23:32

Same thing in ruby and shorter:

#!/usr/bin/env ruby
require 'resolv'
ip = Resolv.getaddress "mydomain.com"
`iptables -A INPUT -p tcp --dport 22 -s #{ip} -j ACCEPT` if `iptables --list` !~ /#{ip}/
  • 2
    Please note that your script would never remove old IPs AFAICT.
    – Theuni
    Dec 8, 2012 at 23:31

Since Linux 2.4.x, you have ipset that can be used to create a set of IPs without having to tweak your firewall rules.

# create the ipset (it may exist)
sudo ipset create dynamic_ips hash:ip -exist

# add a rule where the source IP must match that ipset
sudo iptables -A INPUT -p tcp -m tcp --dport 22 --syn \
               -m set --match-set dynamic_ips src -j ACCEPT

Now that rule will match only if the computer trying to connect has an address that matches the addresses found in dynamic_ips. While the set is empty, nothing happens (it cannot match any IPs). We add a new IP address to the set with the following command:

sudo ipset add dynamic_ips

To see what you currently have in your set, use the list command like so:

sudo ipset list dynamic_ips

Now, to update the list, you actually want to do that atomically. This is done using the ipset swap ... command. For that to work you create a new set and swap it with the old set. Internally, it's just a rename so you can have very large sets and the time it takes to swap them remains constant.

Here is the sequence of events I would propose:

# destroy the new set in case something went wrong and it lingered
# ignore errors if the command fails
sudo ipset destroy new_ips

# for the following, fail on error

# create the new set
sudo ipset create new_ips hash:ip

# determine the list of ip(s)
new_ip=`dig example.com +short`

# add the ip(s) to the set
for ip in $new_ip
    sudo ipset add new_ips $ip

# finally swap the sets
sudo ipset swap dynamic_ips new_ips

# remove the old set, safer & saves some memory
sudo ipset destroy new_ips

As we can see, this is 100% atomic and can be done without tweaking the iptables rules, which is generally ill advised.


If you are absolutely sure that the domain name resolves to a single IP address, then you can directly use the domain name on the ipset command line:

sudo ipset add dynamic_ips example.com

The problem which the script above resolves is when more than one IP address is returned by a lookup to that domain name returns more than one address, then the ipset command only picks the first IP.

Also, here I've shown the commands to handle IPv4. You have another set of commands to handle IPv6 IP addresses. Make sure to use the correct set or handle both as required.

For example, to create the correct set:

sudo ipset create dynamic_ip4 hash:ip family inet
sudo ipset create dynamic_ip6 hash:ip family inet6

And you will have to add IPv6 to the dynamic_ip6 set.

For more documentation about sets, try man ipset.

Final words: although blocking all IPs except yours is pretty safe, it is possible for a good hacker to pretend that his connection is coming from your IP address by forging his packets. Therefore, it is a great protection, but your server is still penetrable. Another addition is to use port knocking. I have my own solution (post includes the iptables rules) to set that up with the ipload tool found in my iplock project. Mixing both, your IP and port knocking, it becomes nearly impossible for a hacker to access your server (there is, of course, your secret key as well... so that makes it three protections to crack).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .