I've often seen the rule -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT applied. Whilst I'm not an expert, that particular line concerns me. It's pretty obvious that the rule allows all traffic with the only exception that the connection has to have been established or related to an established connection.


  • I'll allow connections to the default SSH port 22 from the servers LAN in the subnet or whatever.
  • SuperInsecureApp® exposes something on port 1337, which I add to my INPUT chain.
  • I've added the conntrack rule to accept ESTABLISHED and RELATED from all sources
  • Chain policy is DROP

So basically that configuration shoud allow SSH-connections from the LAN only, whilst allowing inbound traffic on port 1337 from world.

This is where my confusion blooms. Would the conntrack in any way expose a security flaw that would allow one to get an established connection on 1337 (since it's world open), and then utilize that connection to gain access to the SSH port (or any other port for that matter)?

3 Answers 3


I would not consider ESTABLISHED and RELATED traffic too open. You may be able to omit RELATED, but should definitely allow ESTABLISHED. Both of these traffic categories use conntrack states.

ESTABLISHED connections have already been validated by another rule. This makes it much simpler to implement unidirectional rules. This only allows you to continue transactions on the same port.

RELATED connects are also validated by another rule. They don't apply to a lot of protocols. Again they make it much simpler to configure rules. They also ensure proper sequencing of connections where they apply. This actually makes your rules more secure. While this may make it possible to connect on a different port, that port should only be part of a related process like an FTP data connection. Which ports are allow are controlled by protocol specific conntrack modules.

By allowing ESTABLISHED and RELATED connections, you can concentrate on which new connections you want the firewall to accept. It also avoids broken rules meant to allow return traffic, but which allow new connections.

Given you have classified the program on port 1337 as insecure, it should be started using a dedicated non-root user-id. This will limit the damage someone can do if they do manage to crack he application and gain enhanced access.

It is highly unlikely a connection on port 1337 could be used to access port 22 remotely, but it is possible that a connection to port 1337 could be used to proxy a connection to port 22.

You may want to ensure SSH is secured in depth:

  • Use hosts.allow to limit access in addition to the firewall restrictions.
  • Prevent root access, or at least require the use of keys and limit their access in the authorized_keys file.
  • Audit login failures. A log scanner can send you periodic reports of unusual activity.
  • Consider using a tool like fail2ban to automatically block access on repeated access failures.
  • Although this was an arbitrary example, the first thing I do on new servers is always disabling root access and plaintext authentication in sshd - that's a very good tip. Also fail2ban is actually already installed on the real-life setup from which the example was inspired. "ESTABLISHED connections have already been validated by another rule" was the exact thing I was unsure about and perfectly answers my question. Thanks for your very clear answer!
    – Dencker
    Commented Nov 16, 2016 at 6:40
  • Side question: From a performance perspective, does it change anything at all if the conntrack rule is in the beginning or the end of the chain? From how I understand iptables, it'd have to process all rules on established connections if it were in the end, and only that single rule if it was placed in the beginning?
    – Dencker
    Commented Nov 16, 2016 at 6:45
  • @Dencker You want the ESTABLISHED, RELATED rule first. It will accept by far the most traffic. Beyond that you may want to have the rules that accept the most traffic, although it is best to weigh heavily to readability. My rules are grouped, latency sensitive, high traffic (grouped by type), others. Iptables has counters that allow you to see how much traffic each rule proceses. I use Shorewall, which adds some useful defaults and has an easy to read rules file to build my firewalls.
    – BillThor
    Commented Nov 16, 2016 at 23:17

ESTABLISHED and RELATED are features of "stateful" packet filtering, where filtering does not just depend on a static rule set but also on the context, within which packets are considered. You need ESTABLISHED in order to allow connections to work, and you need RELATED for relevant ICMP messages. Stateful filtering allows to filter more precisely compared to static "stateless" rules.

Let's look at ESTABLISHED first. For instance, consider TCP on port 22. The initiator (client) sends a SYN to serverIPaddr:22. The server returns SYN+ACK to the client. Now it's the client's turn to send an ACK. How should the filtering rule on the server look like, such that only the "matching" ACK is accepted? A general stateless rule would look like

-A INPUT --proto tcp --port 22 -j ACCEPT

which is more liberal than the according stateful rule. The stateless rule allows arbitrary TCP segments, e.g. ACK or FIN without having established a connection first. Port scanners can exploit this kind of behavior for OS fingerprinting.

Now let's have a look at RELATED. This is used for ICMP messages, mostly error messages. For instance, if a packet from the server to the client is dropped, then an error message is sent to the server. This error message is "related" to the previously established connection. Without the RELATED rule one would either need to allow incoming error messages in general (without context), or, as is custom for many sites, drop ICMP altogether and wait for timeouts on the transport layer. (Note that this is a bad idea for IPv6; ICMPv6 plays a more important role for IPv6 than ICMP for IP legacy.)

  • this is a much better answer than the accepted one
    – The Fool
    Commented Mar 30, 2021 at 18:51

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT is a good default for users who don't want to spend much time configuring their firewall, and it will probably always be reasonably secure. However, it leaves the actual policy in place up to the Linux kernel.


  1. All protocols will be accepted, so long as they are initiated by the local system.
  2. All protocols and messages will be accepted, so long as they are related to connections and protocols initiated by the local system.

In particular, this accepts all ICMP messsage types that the kernel could possibly consider "related to" an existing connection. I haven't checked the kernel source code for what exactly that means, however no documentation is immediately forthcoming and most of the ICMP message types are unnecessary (and potentially harmful). As such, a more reasonable choice may be as follows:

-A INPUT -p tcp -m state --state ESTABLISHED -j ACCEPT
-A INPUT -p icmp --icmp-type 3 -m state --state RELATED -j ACCEPT
-A INPUT -p icmp --icmp-type 11 -m state --state RELATED -j ACCEPT
-A INPUT -p icmp --icmp-type 12 -m state --state RELATED -j ACCEPT

This only allows established connections with the TCP protocol, and related connections with the ICMP protocol for the "Destination Unreachable" (type 3), "Time Exceeded" (type 11), and "Parameter Problem" (type 12) control messages. This would prevent, for example, the kernel allowing a new TCP connection just because it considers it "related to" a previous one (which it probably never would).

As far as I can tell, these are the only ICMP message types that would be beneficial to accept for a related connection. Type 11 control messages allow the use of TCP trace route functionality with traceroute -T.

The situation is more complex with IPv6 as it uses ICMPv6. For use on a local machine, for the time being I simply drop all IPv6 traffic over the outbound interface as it would take more effort to secure it and it is currently unnecessary with my ISP. If I was configuring a server, I would try to configure it in a similar fashion.

For posterity's sake I'll mention it might also be useful to allow ICMP type 0 and 9 control messages in the input chain, and ICMP type 8 and 10 control messages in the output chain, so that ping (0/8) and IPv4 router solicitation (9/10) work. This should introduce no additional security concerns as accepting an Echo Reply or Router Advertisement message requires no response, and so cannot be used to query the system state.

iptables -A INPUT -p icmp --icmp-type 0/0 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type 9/0 -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type 8/0 -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type 10/0 -j ACCEPT

You must log in to answer this question.

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