Skip to content

Instantly share code, notes, and snippets.

@flaviovs
Last active January 16, 2024 07:08
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save flaviovs/103a0dbf62c67ff371ff75fc62fdded3 to your computer and use it in GitHub Desktop.
Save flaviovs/103a0dbf62c67ff371ff75fc62fdded3 to your computer and use it in GitHub Desktop.
How to use TARPIT in Linux without consuming (your) resources

Iptables(8) TARPIT is a useful security mechanism that can slow down or stop attacks on a network. If everyone used TARPIT to block attackers, in theory their resources would be exhausted as their connection attempts would be delayed, which would discouraged people from attempting unauthorized access. Here's a brief description of how TARPIT works:

To achieve this tar pit state, iptables accepts the incoming TCP/IP connection and then switches to a zero-byte window. This forces the attacker's system to stop sending data, rather like the effect of pressing Ctrl-S on a terminal. Any attempts by the attacker to close the connection are ignored, so the connection remains active and typically times out after only 12–24 minutes. This consumes resources on the attacker's system but not the Linux server or firewall running the tar pit.

(Source: https://www.linuxjournal.com/article/7180)

However, if implemented incorrectly, TARPIT can also lead to resource exhaustion in your own server, specifically with the conntrack module. That's because conntrack is used by the kernel to keep track of network connections, and excessive use of conntrack entries can lead to system performance issues, or even DOS attacks.

The script below uses packet marks to flag packets candidate for TARPITing. Together with the NOTRACK chain, this avoids the conntrack issue while keeping the TARPIT mechanism working.

#
# This is the MARK we will use to flag packets that should be
# tarpitted. If you already use -m mark in your rules you may want to
# tweak the value and/or add a mask to to the rules below to avoid
# conflicts.
#
MARK=8
#
# This example uses ipset(8) and the BLACKLIST_SET list to determine
# IP addresses that should be blacklisted. You can also blacklist
# using iptables(8) matching if you don't use ipset(8). For example:
#
# iptables -t raw -A PREROUTING \
# --src $EVIL_IP \
# -j MARK --set-mark $MARK
#
# The important thing to remember is:
#
# * Your blocking rules should be placed in the "raw" table and in
# the PREROUTING chain by using "-t raw -A PREROUTING"; and
#
# * You don't DROP, REJECT, or TARPIT here; just mark the packet
# with "-j MARK --set-mark $MARK"
#
iptables -t raw -A PREROUTING -m set --match-set BLACKLIST_SET src \
-j MARK --set-mark $MARK
# Disable connection tracking for marked packets.
iptables -t raw -A PREROUTING -m mark --mark $MARK -j NOTRACK
#
# Now setup the BLACKLIST chain.
#
iptables -N BLACKLIST
# Log blacklisted packets.
iptables -A BLACKLIST -m hashlimit --hashlimit-upto 6/hour \
--hashlimit-mode srcip --hashlimit-name blacklist \
-j LOG --log-prefix "BLACKLIST "
# Send TCP packets to the TARPIT.
iptables -A BLACKLIST -p tcp -j TARPIT
# Everything else is dropped.
iptables -A BLACKLIST -j DROP
#
# Now add a rule to the INPUT chain diverting all marked packets to
# the BLACKLIST chain.
#
iptables -I INPUT 1 -m mark --mark $MARK -j BLACKLIST
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment