The effect may not always be what the administrator expects.
A little background:
The netfilter modules in the linux kernel operate on IP packets. They mainly evaluate, process and/or modify the headers from those IP packets and generally do not touch upon the the data section (that would be more the realm of deep packet inspection (DPI)).
The headers of IP packets do not contain human readable names, they consist of things like the IP protocol number
, a source and destination IP-address
, TCP source and destination port
numbers etc.
To be the most efficient the rules for the packet filters in the Linux kernel are also stored with the values for the IP protocol, port numbers and IP-address in the same format as that will be found in packets they're evaluating.
When a rule is loaded into the kernel iptables
and nftables
translate the human readable input into the numeric values needed by and stored in the netfilter kernel modules.
The system resolver is used to translate protocols, services, network names and hostnames. That makes the actual resolving dependent on your configuration ( nsswitch.conf)
iptables
and nftables
translate the human readable input into the numeric values when the commands are run.
the resulting numeric rules remain effective in the kernel for as longs as they are not explicitly flushed/removed/updated.
That also has a number of effects and/or consequences that are not immediately obvious.
Using protocol names with iptables
:
That is generally speaking safe and does not lead to any unnecessary confusion.
The file /etc/protocols
is used by default to translate protocol names to protocol numbers in iptables --protocol [human readable protocol name]
It is unlikely that IP protocol names (such as UPD and TCP) cause confusion.
Using hostnames with iptables
or nftables
:
The default file /etc/networks
could be used to translate network names used in the destinations and/or sources. At least according to the manual, I have never seen anybody use that in the real world yet. Since as far as I know getent networks network-name
also doesn't provide a method to return a netmask either, that makes using network names impractical IMHO.
The default file /etc/hosts
is used to translate hostnames to IP-addresses in destinations and/or sources, with typically DNS as the fallback.
Don't use hostnames.
The packet filter works on IP-addresses. Use IP-addresses and IP-address ranges in your firewall configuration too.
When a hostname is used in a firewall rule with iptables
it will effected with the (single) IP-address to hostname resolves to at the moment the iptables command was executed.
When a hostname can't be resolved, the rule won't be added at all.
That seems obvious and not very problematic but that results in many corner cases, that in practice turn out to really common.
a firewall configuration is typically applied at boot before fully activating the network and then DNS resolving won't work yet. A rule to for example allow remote administration from your bastion host iptables -I INPUT --source bastion.example.com -j ALLOW
won't apply (at system boot) when there is no entry bastion.example.com in the system hosts file. (And who wants to maintain hosts files when they have internal DNS?)
When the forward DNS record is updated: the Linux firewall will continue to use old IP-address until the rule is explicitly flushed/removed/updated (by running the iptables
command again).
When the forward DNS record is a round-robin record or uses geo-location: often only a single IP-address will be used.
In other words: iptables -I OUTPUT --destination www.google.com -j REJECT
will for example only partially block access to Google for no more than 300 seconds. Then the DNS TTL expires and queries for www.google.com
return a different IP-address, usually a new one that is not blocked in your effective firewall rules.
Normally using a hostname to reject undesired access is already a bad idea.
Systems normally only see the IP-address from an incoming connection and they'll need to do a reverse lookup on the IP-address to determine the associated hostname. Blocking by hostname is then problematic for two reasons:
reverse DNS lookups can be slow
the resulting hostname can't be trusted because the owner of an IP-address can set any hostname they want on the reverse DNS record. They can change their untrusted.example.net
to trusted.example.com
at will (Some systems address that by doing a second forward lookup of the hostname from the PTR record and will only accept systems where the two match.)
iptables -A INPUT --source untrusted.example.net -j REJECT
For iptables the problem is slightly different, as only a forward DNS lookup will be done. But nevertheless, when you use untrusted.example.net rather than an IP-address you no longer control what is blocked.
If the owner of that DNS record changes untrusted.example.net to let's say the IP-address of your gateway, you will lock yourself out.
If the owner completely removes the record, you're no longer blocking their IP either.
Another potentially confusing thing: when displaying the firewall rules the mapping from IP-address to hostname if done via reverse DNS lookup. Frequently that PTR record won't exists and when it does exist, as often as not the resulting hostname won't correspond to the hostname that was used when the rule was created. For example:
www.google.com. 300 IN A 172.217.168.228
228.168.217.172.in-addr.arpa. 18721 IN PTR ams15s40-in-f4.1e100.net.
And probably some other reasons I forgot.
Using service names with iptables
:
Although safe this also seems to generate some confusion.
The file /etc/services
is used to translate the service name to port number when instead of a port number a human readable "service name" is used with iptables --protocol tcp --source-port
(or the alias --sport
and the similar --destination-port
/ --dport
ect.).
The service name is effectively a human readable port number and (as long as nobody modified /etc/services) when an administrator uses for example ssh
that will be the same as using port 22
.
iptables -I INPUT -p tcp --dport ssh -j ACCEPT
The source of confusion seems that people confuse the service name (ssh) with the application protocol (ssh).
The rule above does not allow all incoming ssh traffic.
When for example your ssh server is configured to listen on port 22222 that port is not opened by this rule.
That rule only allows all traffic to port 22.
It also does not block traffic that is not ssh from connecting to port 22 either. The typical ssh daemon won't be able to respond properly but requests such as http://hostname:22/
are not blocked the packet filter either. (That would require DPI.)