iptables
(and/or the successor tool nftables
) is the user-space utility program that allows a system administrator to configure the IP packet filter rules of the Linux kernel firewall, which is implemented as different Netfilter modules. (summary from Wikipedia)
Since iptables
and nftables
are a user-space utility programs intended to be used by people, by system administrators, and people are not always completely comfortable with the underlying numbers, they accept human readable descriptions for IP-protocols (tcp, icmp, udp etc), IP-addresses (hostnames), and port numbers (service-names).
From a UI aspect using human readable names appears to be a good thing:
- as an administrator I'm probably not the only one that has a much better intuitive grasp of the meaning of:
iptables --protocol udp
compared to:iptables --protocol 17
and similar. - a hostname
gateway.example.net
often makes more sense than an IP-address such as192.0.2.1
- and on a web server allowing HTTP and HTTPS is more obvious than allowing TCP/80 resp. TCP/443.
Is that safe to do?
Or should you stay away from that?
What are the caveats?
The effect may not always be what the administrator expects.
A little background:
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
andnftables
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
andnftables
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 iniptables --protocol [human readable protocol name]
It is unlikely that IP protocol names (such as UPD and TCP) cause confusion.
Using hostnames with
iptables
ornftables
: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 knowgetent 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 forwww.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
totrusted.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.)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:
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 withiptables --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 port22
.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.)