0

Could anyone help me with a review of my iptables rules (running a new Tor relay server), please?

I'm running a Debian GNU/Linux 11 (bullseye), fully updated.

I drop everything in INPUT chain by default, SSH port is censored, so if you see XXYYZ... I changed it to a custom port so that the bots have a little bit more work than just hit the 22.

I will copy-paste the rules.v4 file now:

# Latest revision on 2021-Jul-25

*filter

:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]

--append INPUT --match conntrack --ctstate NEW --protocol tcp ! --syn --match comment --comment "protection: non-syn packets" --jump DROP
--append INPUT --match conntrack --ctstate INVALID --match comment --comment "protection: malformed packets" --jump DROP
--append INPUT --in-interface lo --match comment --comment "loopback: compulsory" --jump ACCEPT
--append INPUT --protocol icmp --icmp-type echo-request --match limit --limit 2/second --limit-burst 5 --match comment --comment "ICMP: ping only" --jump ACCEPT
--append INPUT --match conntrack --ctstate RELATED,ESTABLISHED --match comment --comment "Tor: traffic" --jump ACCEPT
--append INPUT --match conntrack --ctstate NEW,ESTABLISHED --protocol tcp --match tcp --destination-port XXYYZ --match comment --comment "SSH: global obfuscated" --jump ACCEPT
--append INPUT --protocol tcp --match tcp --destination-port 9001 --match comment --comment "Tor: OR" --jump ACCEPT
--append INPUT --protocol tcp --match tcp --destination-port 9030 --match comment --comment "Tor: Dir" --jump ACCEPT

COMMIT

The current output of about one day's uptime is:

# iptables -L INPUT -v --line-numbers

Chain INPUT (policy DROP 29718 packets, 3008K bytes)
num   pkts bytes target     prot opt in     out     source               destination         
1      234  131K DROP       tcp  --  any    any     anywhere             anywhere             ctstate NEW tcp flags:!FIN,SYN,RST,ACK/SYN /* protection: non-syn packets */
2      374 45284 DROP       all  --  any    any     anywhere             anywhere             ctstate INVALID /* protection: malformed packets */
3       96  4800 ACCEPT     all  --  lo     any     anywhere             anywhere             /* loopback: compulsory */
4       24   902 ACCEPT     icmp --  any    any     anywhere             anywhere             icmp echo-request limit: avg 2/sec burst 5 /* ICMP: ping only */
5    3736K 2726M ACCEPT     all  --  any    any     anywhere             anywhere             ctstate RELATED,ESTABLISHED /* Tor: traffic */
6       30  1800 ACCEPT     tcp  --  any    any     anywhere             anywhere             ctstate NEW,ESTABLISHED tcp dpt:XXYYZ /* SSH: global obfuscated */
7    12493  743K ACCEPT     tcp  --  any    any     anywhere             anywhere             tcp dpt:9001 /* Tor: OR */
8     7948  423K ACCEPT     tcp  --  any    any     anywhere             anywhere             tcp dpt:9030 /* Tor: Dir */

The server seems to work like a charm, but I may be simply over-confident, for the lack of a better word.

2
  • Just a suggestion: did you try ufw before? You indicate that you have little networking experience, and ufw is more suitable for beginners imo Commented Jul 26, 2021 at 17:05
  • I recall I read somewhere that for (new) not syn it's better to reject with tcp reset, since they are not necessarily caused by malicious intention and simply dropping them can cause some "valid" connection to hang unnecessarily or so. If you want to make the change, you can consider having a "leveled" approach, like having syn check and the reset in an additional chain and make only what fulfilled other criteria (e.g. port matching) to goto that chain, so that it only tcp reset for those "possibly wanted/valid" traffics. Commented Jul 27, 2021 at 7:34

1 Answer 1

1

For your reference:

*filter
-N RNNS
-A RNNS -p tcp ! --syn -j REJECT --reject-with tcp-reset
# accept (new) syn
-A RNNS -j ACCEPT

-N ALLOW
# tcp (r)eset (n)ew but (n)ot (s)yn
# -j RNNS is fine too since the chain has a "fallback" verdict at the end
-A ALLOW -p tcp --dport 9001 -g RNNS
-A ALLOW -p tcp --dport 9030 -g RNNS
-A ALLOW -p tcp --dport 12345 -g RNNS
# for (new) udp, just accept
-A ALLOW -p udp --dport 54321 -j ACCEPT
# others' fate will be determined by the chain policy of INPUT
# because we came to this chain by -g
# but well, -g ALLOW was the last rule anyway, so -j would have worked too
# and you can -j DROP here anyway

-P INPUT DROP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
# -A INPUT -m conntrack --ctstate INVALID ! -p tcp -j DROP
# could only be of conntrack state NEW; oh well, also see UNTRACKED
-A INPUT -i lo -j ACCEPT
# -A INPUT -i lo -g RNNS
-A INPUT -p icmp --icmp-type echo-request -m limit --limit 2/second --limit-burst 5 -j ACCEPT
# chain policy; optimization / optional
-A INPUT -p icmp -j RETURN
# won't be ICMP
-A INPUT -g ALLOW

-P FORWARD DROP
-P OUTPUT ACCEPT
COMMIT

Note that the order of the rules in the same chain could matter a lot, but certainly the order among rules that have no logical relation does not (see the chain ALLOW), although as an "optimization", we prioritize matching that are more "important" / likely to be true (see the first two --ctstate rules in the INPUT chain) when we can.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.