| |

LFCE 83 🐧 ipset — Concepts

⏱️ Estimated read: 12 min | |

ipset is a kernel framework and userspace utility for storing collections of IP addresses, networks, ports, and other values in indexed data structures—hash tables or bitmaps—so that iptables can match against the entire collection with a single rule instead of a long chain of individual rules . The previous chapters covered the iptables rules that match one packet at a time; this chapter covers the mechanism that makes matching against thousands of addresses as fast as matching against one.

The core problem that ipset solves is the linear lookup. A firewall that blocks 10,000 addresses with individual iptables rules has 10,000 rules in the chain, and every packet is compared against them in order until a match is found or the chain ends. The lookup time grows with the size of the list. An ipset stores the same 10,000 addresses in a hash table, and the lookup time is essentially constant regardless of the number of entries . The iptables rule references the set by name, and the kernel checks the set in a single operation.

Key point: An ipset is a named collection of elements that lives in the kernel and is referenced by an iptables rule through the set match or the SET target . The set has a type that determines what it can store—IP addresses, networks, ports, or combinations—and the type determines the data structure and the lookup performance . The set is created with ipset create, populated with ipset add, and referenced in iptables with -m set --match-set <name> src. The set survives independently of the iptables rules, and it can be updated without touching the rule that references it.


Why ipset exists

The linear-lookup problem.

An iptables chain is a linked list. Each rule is evaluated in order, and a packet that matches none of the rules is compared against every one of them. A chain with 10,000 rules performs 10,000 comparisons in the worst case, and the CPU cost grows linearly with the size of the list. The kernel developers introduced ipset to move the list into a data structure that supports constant-time or near-constant-time lookup, so that the firewall can block millions of addresses without degrading the throughput .

The update problem.

Adding a new address to a 10,000-rule chain requires inserting a rule, which may require rebuilding the chain or at least modifying it in place. Adding an address to an ipset is a single operation that does not touch the iptables rules at all. The rule references the set by name, and the set’s contents can change without the rule being reloaded. This is the mechanism that fail2ban and similar tools use: they add and remove addresses from an ipset as the behavior changes, and the iptables rule stays static.

The multiple-match problem.

A packet can be matched against several sets in different rules, and each set can be queried with a different direction (src or dst). The set match in iptables accepts the set name and the direction, and the kernel performs the lookup against the set’s data structure . The SET target can add the packet’s address to a set, which is how dynamic blocklists are populated. The combination of match and target makes ipset a general-purpose mechanism for storing and querying collections of addresses, not just a blocklist.


a. The set types

The set type determines what the set can store and how it is stored. The two families are bitmap and hash, and the subtypes determine the element dimensions.

Bitmap types use a fixed-size memory range where each bit represents an address or port. They are fast and memory-efficient for small, dense ranges, but they are limited to 65,535 entries and a single dimension .

TypeStoresLimit
bitmap:ipIPv4 addresses65,535
bitmap:ip,macIPv4 and MAC pairs65,535
bitmap:portTCP/UDP ports65,535

Hash types use a hash table that grows dynamically as elements are added. They are the correct choice for large or sparse sets, and they support multiple dimensions .

TypeStores
hash:ipIPv4 or IPv6 addresses
hash:netCIDR network blocks of different sizes
hash:ip,portIP and protocol-port pairs
hash:net,portNetwork and port pairs
hash:net,ifaceNetwork and interface name pairs
list:setOther sets (ordered union)

The hash:ip type is the most common for simple blocklists, and the hash:net type is the correct choice when the elements are networks rather than individual hosts . The hash:ip,port type is used when the blocklist is specific to a service, such as blocking an address only on port 22. The list:set type is a meta-set that contains other sets, which allows a rule to match against a union of sets without listing them individually .


b. The set lifecycle

A set is created with ipset create, populated with ipset add, and destroyed with ipset destroy. The ipset list command shows the set’s contents and statistics.

# Create a hash:net set with a maximum of 100000 elements
sudo ipset create blocklist hash:net maxelem 100000

# Add individual addresses and networks
sudo ipset add blocklist 203.0.113.5
sudo ipset add blocklist 192.0.2.0/24

# List the set
sudo ipset list blocklist
# Output shows the type, the members, and the number of entries

The maxelem option sets the maximum number of elements the set can hold. The hash table is sized to accommodate that many entries, and the set grows dynamically until the limit is reached . The timeout option sets a default expiration for every element, which is useful for temporary blocks.

The set is referenced in iptables with the set match.

# Drop packets from any address in the blocklist
sudo iptables -A INPUT -m set --match-set blocklist src -j DROP

The --match-set blocklist src option tells iptables to check the packet’s source address against the set named blocklist . If the address is in the set, the rule matches, and the DROP target is applied. The rule is a single line, regardless of how many addresses the set contains. The dst keyword checks the destination address instead of the source.


c. The SET target and dynamic updates

The SET target adds the packet’s address to a set. It is the mechanism that allows the firewall to learn addresses dynamically, such as adding an address to a blocklist after a failed login attempt.

# Add the source address to the blocklist when a condition is met
sudo iptables -A INPUT -p tcp --dport 22 -m recent --name ssh --update --seconds 60 --hitcount 4 -j SET --add-set blocklist src

The SET --add-set blocklist src target adds the packet’s source address to the blocklist set . The rule can be combined with a match that detects the condition, such as the recent match that counts connections within a time window. The set is updated at the kernel level, and the next packet from the same address is matched by the set rule and dropped.

The ipset command can also add and delete elements from userspace, which is how fail2ban and similar tools manage the blocklist. The set is persistent as long as the kernel module is loaded, and the ipset save and ipset restore commands write and read the set contents to a file for persistence across reboots .


Complete Example Session

# ============================================
# PART 1: CREATE THE SET
# ============================================
sudo ipset create blocklist hash:net maxelem 100000

# ============================================
# PART 2: POPULATE THE SET
# ============================================
sudo ipset add blocklist 203.0.113.5
sudo ipset add blocklist 198.51.100.0/24
sudo ipset add blocklist 192.0.2.10

# ============================================
# PART 3: VERIFY THE SET
# ============================================
sudo ipset list blocklist
# Output shows the type, the members, and the number of entries

# ============================================
# PART 4: REFERENCE THE SET IN IPTABLES
# ============================================
sudo iptables -A INPUT -m set --match-set blocklist src -j DROP

# ============================================
# PART 5: ADD A DYNAMIC UPDATE RULE
# ============================================
sudo iptables -A INPUT -p tcp --dport 22 -m recent --name ssh --update --seconds 60 --hitcount 4 -j SET --add-set blocklist src

# ============================================
# PART 6: TEST THE BLOCKLIST
# ============================================
# From a blocked address: the connection is dropped
# From an allowed address: the connection succeeds

# ============================================
# PART 7: SAVE THE SET
# ============================================
sudo ipset save blocklist > /etc/ipset.blocklist

# ============================================
# PART 8: RESTORE THE SET
# ============================================
sudo ipset restore < /etc/ipset.blocklist

# ============================================
# PART 9: REMOVE AN ELEMENT
# ============================================
sudo ipset del blocklist 203.0.113.5

# ============================================
# PART 10: DESTROY THE SET
# ============================================
sudo ipset destroy blocklist

The ten parts demonstrate the ipset lifecycle: creation, population, verification, iptables reference, dynamic update, testing, saving, restoring, element removal, and destruction. The critical distinction is between Parts 4 and 5: the set match reads from the set, and the SET target writes to it.


Quick Reference

Set Types

TypeStoresUse Case
hash:ipIP addressesSimple blocklist
hash:netCIDR networksNetwork blocklist
hash:ip,portIP and port pairsService-specific block
bitmap:ipIPv4 addresses (dense)Small, fixed range
list:setOther setsUnion of sets

Commands

CommandPurpose
ipset create <name> <type>Create a set
ipset add <name> <element>Add an element
ipset del <name> <element>Remove an element
ipset list <name>Show the set
ipset saveSave to stdout
ipset restoreRestore from stdin
ipset destroy <name>Delete the set

iptables Integration

OptionPurpose
-m set --match-set <name> srcMatch source address
-m set --match-set <name> dstMatch destination address
-j SET --add-set <name> srcAdd source address to set

Best Practices

✅ Do This:

# Use hash:net for network blocklists
ipset create blocklist hash:net maxelem 100000                 # ✅

# Use hash:ip for simple host blocklists
ipset create hosts hash:ip maxelem 65536                       # ✅

# Reference the set in a single iptables rule
iptables -A INPUT -m set --match-set blocklist src -j DROP    # ✅

# Save the set for persistence
ipset save blocklist > /etc/ipset.blocklist                    # ✅

# Use the SET target for dynamic updates
-j SET --add-set blocklist src                                # ✅

❌ Don’t Do This:

# Create 10,000 individual iptables rules
for ip in ...; do iptables -A INPUT -s $ip -j DROP; done      # ❌

# Use bitmap:ip for a large or sparse set
ipset create blocklist bitmap:ip    # Limited to 65,535       # ❌

# Forget to save the set
# The set is lost on reboot                                   # ❌

# Use the set without the hashsize for a large set
ipset create blocklist hash:ip    # Default hashsize may cause collisions # ❌

Common Pitfalls

PitfallWhy It HappensFix
Set not found in iptablesSet name typo or set not createdipset list to verify
Set lost on rebootNot savedipset save and restore at boot
Lookup slowUsed bitmap for a large setUse hash type
Cannot delete elementImplicit membership in a networkDelete the explicit element
Hash collisionshashsize too smallIncrease hashsize

Real-World Examples

1. Create a hash:net set

ipset create blocklist hash:net maxelem 100000

2. Add a network

ipset add blocklist 192.0.2.0/24

3. Add a host

ipset add blocklist 203.0.113.5

4. Reference in iptables

iptables -A INPUT -m set --match-set blocklist src -j DROP

5. Dynamic add with SET target

iptables -A INPUT -p tcp --dport 22 -j SET --add-set blocklist src

6. List the set

ipset list blocklist

7. Remove an element

ipset del blocklist 203.0.113.5

8. Save the set

ipset save blocklist > /etc/ipset.blocklist

9. Restore the set

ipset restore < /etc/ipset.blocklist

10. Destroy the set

ipset destroy blocklist

Visual

ipset vs Individual Rules

┌──────────────────────────────────────────────────────────────┐
│  IPSET REPLACES A LONG CHAIN WITH A SINGLE RULE              │
│                                                              │
│  Without ipset:                                              │
│  ┌────────────────────────────────────────────────────────┐  │
│  │ iptables -A INPUT -s 203.0.113.5 -j DROP               │  │
│  │ iptables -A INPUT -s 198.51.100.10 -j DROP             │  │
│  │ iptables -A INPUT -s 192.0.2.0/24 -j DROP              │  │
│  │ ... (10,000 rules)                                     │  │
│  │                                                        │  │
│  │ Each packet compares against up to 10,000 rules        │  │
│  └────────────────────────────────────────────────────────┘  │
│                                                              │
│  With ipset:                                                 │
│  ┌────────────────────────────────────────────────────────┐  │
│  │ ipset create blocklist hash:net                        │  │
│  │ ipset add blocklist 203.0.113.5                        │  │
│  │ ipset add blocklist 198.51.100.10                      │  │
│  │ ipset add blocklist 192.0.2.0/24                       │  │
│  │                                                        │  │
│  │ iptables -A INPUT -m set --match-set blocklist src -j DROP│
│  │                                                        │  │
│  │ One rule; constant-time lookup in the hash table       │  │
│  └────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────┘

The set Match and SET Target

┌──────────────────────────────────────────────────────────────┐
│  MATCH READS; TARGET WRITES                                  │
│                                                              │
│  set match:                                                  │
│  ┌────────────────────────────────────────────────────────┐  │
│  │ -m set --match-set blocklist src                       │  │
│  │ → checks if the packet's source is in the set          │  │
│  │ → used in filtering rules                              │  │
│  └────────────────────────────────────────────────────────┘  │
│                                                              │
│  SET target:                                                 │
│  ┌────────────────────────────────────────────────────────┐  │
│  │ -j SET --add-set blocklist src                         │  │
│  │ → adds the packet's source to the set                  │  │
│  │ → used in dynamic blocklist rules                      │  │
│  └────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────┘

Persistence

┌──────────────────────────────────────────────────────────────┐
│  SAVE AND RESTORE FOR PERSISTENCE                            │
│                                                              │
│  ipset save blocklist > /etc/ipset.blocklist                 │
│       │                                                      │
│       ▼                                                      │
│  File contains the set definition and its members            │
│       │                                                      │
│       ▼                                                      │
│  At boot: ipset restore < /etc/ipset.blocklist               │
│       │                                                      │
│       ▼                                                      │
│  The set is recreated with the same members                  │
│                                                              │
│  Without the save/restore, the set is lost on reboot.        │
└──────────────────────────────────────────────────────────────┘

Summary

ItemValue
PurposeIndexed set for fast iptables matching
Data structuresHash table or bitmap
LookupConstant or near-constant time
iptables match-m set --match-set <name> src
iptables target-j SET --add-set <name> src
Common typehash:net for networks, hash:ip for hosts
Limitmaxelem option
Persistenceipset save / ipset restore
Created withipset create <name> <type>

Key takeaways:

  • ipset solves the linear-lookup problem. A chain of 10,000 iptables rules is a linked list that performs up to 10,000 comparisons per packet. An ipset stores the same addresses in a hash table, and the lookup time is essentially constant regardless of the set size .
  • The set type determines the data structure and the element dimensions. hash:ip and hash:net are the common types for address blocklists, bitmap types are for small dense ranges, and the multi-dimensional types store IP-port or IP-MAC combinations .
  • The set match reads from the set, and the SET target writes to it. The match is used in filtering rules, and the target is used in rules that add addresses dynamically, such as fail2ban-style SSH protection .
  • The set is independent of the iptables rule. The rule references the set by name, and the set’s contents can be updated without reloading the rule. This is the mechanism that allows dynamic blocklists to grow and shrink without touching the firewall configuration.
  • The set must be saved for persistence. The ipset save command writes the set contents to a file, and the ipset restore command reads it back. Without the save and restore, the set is lost on reboot .
  • The hashsize and maxelem options control the performance. A larger hashsize reduces collisions for large sets, and maxelem sets the upper bound on the number of entries. The defaults are adequate for small sets but should be raised for large blocklists .

Remember: ipset is the mechanism that makes large-scale matching practical. The set is a named collection of addresses or networks stored in a kernel data structure, and the iptables rule matches against the set in a single operation. The set type determines what can be stored, the set match reads from the set, and the SET target writes to it. The set is independent of the rule, so it can be updated dynamically, and it must be saved for persistence. The result is a firewall that can block millions of addresses without the linear-lookup penalty of a long rule chain.


Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!