IPSET(8)

๐ŸŒธ IPSET(8) โ€” the ipset page, but make it make sense ๐ŸŒธ

okay bestie, buckle up, because this is the manual for ipset and we're doing the whole thing together ๐Ÿ’–


โœจ NAME โœจ

ipset โ€” administration tool for IP sets


โœจ SYNOPSIS โœจ

ipset [ OPTIONS ] COMMAND [ COMMAND-OPTIONS ]

COMMANDS := { create | add | del | test | destroy | list | save |
restore | flush | rename | swap | help | version | - }

OPTIONS := { -exist | -output { plain | save | xml } | json } | -quiet |
-resolve | -sorted | -name | -terse | -file filename }

ipset create SETNAME TYPENAME [ CREATE-OPTIONS ]

ipset add SETNAME ADD-ENTRY [ ADD-OPTIONS ]

ipset del SETNAME DEL-ENTRY [ DEL-OPTIONS ]

ipset test SETNAME TEST-ENTRY [ TEST-OPTIONS ]

ipset destroy [ SETNAME ]

ipset list [ SETNAME ]

ipset save [ SETNAME ]

ipset restore

ipset flush [ SETNAME ]

ipset rename SETNAME-FROM SETNAME-TO

ipset swap SETNAME-FROM SETNAME-TO

ipset help [ TYPENAME ]

ipset version

ipset -

โœจ DESCRIPTION โœจ

So ipset is your girl for setting up, maintaining and inspecting the so-called IP sets living inside the Linux kernel. And depending on what type of set you're working with, an IP set can hold IP(v4/v6) addresses, (TCP/UDP) port numbers, IP and MAC address pairs, IP address and port number pairs, etc. ๐Ÿ‘‘ All the set type definitions are down below, don't worry.

Iptables matches and targets that point at sets create references, and those references protect the sets in the kernel. Meaning: a set cannot be destroyed while there's even a single reference pointing at it. no cap. ๐Ÿซถ


โœจ OPTIONS โœจ

The options ipset recognizes split up into a few different groups. vibe check time ๐ŸŽ€

๐ŸŽฏ COMMANDS

These options say what action you want to happen. Only one of them can be specified on the command line unless it says otherwise below. And for all the long versions of the command names, you only need to type enough letters for ipset to tell it apart from every other command. The ipset parser walks the order below when it's hunting for the shortest match in the long command names. iykyk ๐Ÿ’…

  • n, create SETNAME TYPENAME [ CREATE-OPTIONS ] โ€” create a set identified with setname and the type you specified. The type might demand type-specific options. If the -exist option is given, ipset ignores the error it would otherwise raise when that exact same set already exists (same setname, same create parameters). โœจ
  • add SETNAME ADD-ENTRY [ ADD-OPTIONS ] โ€” add the given entry to the set. If the -exist option is given, ipset ignores it when the entry is already added to the set. ๐Ÿซถ
  • del SETNAME DEL-ENTRY [ DEL-OPTIONS ] โ€” delete an entry from a set. If the -exist option is given and the entry isn't in the set (maybe it already expired?), then the command is just ignored. ๐Ÿ’€
  • test SETNAME TEST-ENTRY [ TEST-OPTIONS ] โ€” test whether an entry is in a set or not. The exit status number is zero if the tested entry is in the set, and nonzero if it's missing from the set. ๐Ÿ”ฅ
  • x, destroy [ SETNAME ] โ€” destroy the specified set, or all the sets if none is given.

If the set has got reference(s), nothing happens and no set gets destroyed. ๐Ÿ›‘

  • list [ SETNAME ] [ OPTIONS ] โ€” list the header data and the entries for the specified set, or for all sets if none is given. The -resolve option forces name lookups (which may be slow ๐Ÿ˜ญ). When -sorted is given, entries are listed/saved sorted (which may also be slow ๐Ÿ˜ญ). The -output option controls the format of the listing: plain, save, xml or json. (The default is plain.) If -name is specified, just the names of the existing sets get listed. If -terse is specified, just the set names and headers get listed. Output goes to stdout, and the -file option lets you name a filename instead of stdout. ๐Ÿ’–
  • save [ SETNAME ] โ€” save the given set, or all sets if none is given, to stdout in a format that restore can read. The -file option lets you name a filename instead of stdout. ๐Ÿ’พ
  • restore โ€” restore a saved session generated by save. The saved session can be fed from stdin, or the -file option lets you name a filename instead of stdin.
Please note, existing sets and elements are not erased by restore unless it's specified so in the restore file. All commands are allowed in restore mode except list, help, version, interactive mode and restore itself. ๐Ÿ™ˆ
  • flush [ SETNAME ] โ€” flush all entries from the specified set, or flush all sets if none is given. ๐ŸŒŠ
  • e, rename SETNAME-FROM SETNAME-TO โ€” rename a set. The set identified by SETNAME-TO must not exist. โญ
  • w, swap SETNAME-FROM SETNAME-TO โ€” swap the content of two sets, or in other words, exchange the name of two sets. The referred sets must exist, and only compatible types of sets can be swapped. ๐Ÿ”„
  • help [ TYPENAME ] โ€” print help, plus set type specific help if TYPENAME is specified. ๐ŸŽ€
  • version โ€” print program version. ๐Ÿ‘‘
  • - โ€” if a dash is specified as command, then ipset enters a simple interactive mode and the commands are read from standard input. You finish interactive mode by entering the pseudo-command quit. ๐Ÿฆ‹

๐ŸŒˆ OTHER OPTIONS

The following extra options can be specified too. And heads up: the long option names cannot be abbreviated. ๐Ÿ’…

  • -!, -exist โ€” ignore errors when exactly the same set is to be created, or an already added entry is added, or a missing entry is deleted. ๐Ÿ™ˆ
  • -o, -output { plain | save | xml | json } โ€” select the output format for the list command. โœจ
  • -q, -quiet โ€” suppress any output to stdout and stderr. ipset will still exit with an error if it cannot continue. ๐Ÿคซ
  • -r, -resolve โ€” when listing sets, enforce name lookup. The program will try to display the IP entries resolved to host names, which requires slow DNS lookups. ๐ŸŒ
  • -s, -sorted โ€” sorted output. When listing or saving sets, the entries are listed sorted. ๐Ÿ”ค
  • -n, -name โ€” list just the names of the existing sets, i.e. suppress listing of set headers and members. ๐Ÿท๏ธ
  • -t, -terse โ€” list the set names and headers, i.e. suppress listing of set members. โœ‚๏ธ
  • -f, -file filename โ€” specify a filename to print into instead of stdout (list or save commands), or to read from instead of stdin (restore command). ๐Ÿ“

โœจ INTRODUCTION โœจ

A set type is made up of the storage method the data is stored by, plus the data type(s) stored in the set. So the TYPENAME parameter of the create command follows this syntax:

TYPENAME := method:datatype[,datatype[,datatype]]

where the current list of methods is bitmap, hash, and list, and the possible data types are ip, net, mac, port and iface. The dimension of a set equals the number of data types in its type name. ๐Ÿฆ‹

When you're adding, deleting or testing entries in a set, that same comma separated data syntax has to be used for the entry parameter of the commands, i.e.

ipset add foo ipaddr,portnum,ipaddr

If host names or service names with a dash in the name get used instead of IP addresses or service numbers, then the host name or service name must be enclosed in square brackets. Example:

ipset add foo [test-hostname],[ftp-data]

And in the case of host names, the DNS resolver is called internally by ipset, but if it returns multiple IP addresses, only the first one is used. ๐Ÿ™ˆ

The bitmap and list types use a fixed sized storage. The hash types use a hash to store the elements. To avoid clashes in the hash, a limited number of chaining happens, and if that's exhausted, the doubling of the hash size is performed when entries are added by the ipset command. But when entries are added by the SET target of iptables/ip6tables, then the hash size is fixed and the set won't be duplicated, even if the new entry cannot be added to the set. ๐Ÿ’€


โœจ GENERIC CREATE AND ADD OPTIONS โœจ

โณ timeout โณ

okay so bestie, every single set type supports the optional timeout parameter when you're creating a set and when you're adding entries. The value you give to timeout in the create command is the default timeout value (in seconds) for new entries. If a set is created with timeout support, then you can use that same timeout option to set non-default timeout values when adding entries. A timeout of zero means the entry is added permanent to the set. You can change the timeout value of already added elements by re-adding the element with the -exist option. The largest possible timeout value is 2147483 (in seconds). Example:

ipset create test hash:ip timeout 300

ipset add test 192.168.0.1 timeout 60

ipset -exist add test 192.168.0.1 timeout 600

When you're listing the set, the number of entries printed in the header might be larger than the listed number of entries for sets with the timeout extensions: the number of entries in the set is updated when elements are added/deleted to the set and periodically when the garbage collector evicts the timed out entries.


๐Ÿ’– counters, packets, bytes ๐Ÿ’–

All set types support the optional counters option when creating a set. If you specify it, the set is created with packet and byte counters per element support. The packet and byte counters are initialized to zero when the elements are (re-)added to the set, unless the packet and byte counter values are explicitly specified by the packets and bytes options. Here's an example when an element is added to a set with non-zero counter values:

ipset create foo hash:ip counters

ipset add foo 192.168.1.1 packets 42 bytes 1024

๐Ÿ’ฌ comment ๐Ÿ’ฌ

All set types support the optional comment extension. Enabling this extension on an ipset lets you annotate an ipset entry with an arbitrary string. This string is completely ignored by both the kernel and ipset itself and is purely for providing a convenient means to document the reason for an entry's existence. Comments must not contain any quotation marks and the usual escape character (\) has no meaning. For example, the following shell command is illegal:

ipset add foo 1.1.1.1 comment "this comment is \"bad\""

In the above, your shell will of course escape the quotation marks and ipset will see the quote marks in the argument for the comment, which will result in a parse error. If you are writing your own system, you should avoid creating comments containing a quotation mark if you do not want to break ipset save and ipset restore, nonetheless, the kernel will not stop you from doing so. The following is perfectly acceptable:

ipset create foo hash:ip comment

ipset add foo 192.168.1.1/24 comment "allow access to SMB share
on \\\\fileserv\\"

the above would appear as: "allow access to SMB share on
\\fileserv\"

๐ŸŽ€ skbinfo, skbmark, skbprio, skbqueue ๐ŸŽ€

All set types support the optional skbinfo extension. This extension allows you to store the metainfo (firewall mark, tc class and hardware queue) with every entry and map it to packets by usage of SET netfilter target with --map-set option. skbmark option format: MARK or MARK/MASK, where MARK and MASK are 32bit hex numbers with 0x prefix. If only mark is specified mask 0xffffffff are used. skbprio option has tc class format: MAJOR:MINOR, where major and minor numbers are hex without 0x prefix. skbqueue option is just decimal number.

ipset create foo hash:ip skbinfo

ipset add foo 192.168.0.1 skbmark 0x1111/0xff00ffff skbprio 1:10
skbqueue 10

#๏ธโƒฃ hashsize #๏ธโƒฃ

This parameter is valid for the create command of all hash type sets. It defines the initial hash size for the set, default is 1024. The hash size must be a power of two, the kernel automatically rounds up non power of two hash sizes to the first correct value. Example:

ipset create test hash:ip hashsize 1536

๐Ÿ”ข maxelem ๐Ÿ”ข

This parameter is valid for the create command of all hash type sets. It defines the maximal number of elements which can be stored in the set, default 65536. Example:

ipset create test hash:ip maxelem 2048

๐Ÿชฃ bucketsize ๐Ÿชฃ

This parameter is valid for the create command of all hash type sets. It specifies the maximal number of elements which can be stored in a hash bucket. Possible values are any even number between 2-14 and the default is 14. Setting the value lower forces ipset to create larger hashes which consumes more memory but gives more speed at matching in the set. Example:

ipset create test hash:ip bucketsize 2

๐ŸŒ family { inet | inet6 } ๐ŸŒ

This parameter is valid for the create command of all hash type sets except for hash:mac. It defines the protocol family of the IP addresses to be stored in the set. The default is inet, i.e IPv4. For the inet family one can add or delete multiple entries by specifying a range or a network of IPv4 addresses in the IP address part of the entry:

ipaddr := { ip | fromaddr-toaddr | ip/cidr }

netaddr := { fromaddr-toaddr | ip/cidr }

Example:

ipset create test hash:ip family inet6

๐Ÿšซ nomatch ๐Ÿšซ

The hash set types which can store net type of data (i.e. hash:*net*) support the optional nomatch option when adding entries. When matching elements in the set, entries marked as nomatch are skipped as if those were not added to the set, which makes possible to build up sets with exceptions. See the example at hash type hash:net below.

When elements are tested by ipset, the nomatch flags are taken into account. If one wants to test the existence of an element marked with nomatch in a set, then the flag must be specified too.


๐Ÿ’ช forceadd ๐Ÿ’ช

All hash set types support the optional forceadd parameter when creating a set. When sets created with this option become full the next addition to the set may succeed and evict a random entry from the set.

ipset create foo hash:ip forceadd

โœจ wildcard โœจ

This flag is valid when adding elements to a hash:net,iface set. If the flag is set, then prefix matching is used when comparing with this element. For example, an element containing the interface name "eth" will match any name with that prefix.


๐Ÿ‘‘ SET TYPES ๐Ÿ‘‘

๐ŸŽ€ bitmap:ip ๐ŸŽ€

The bitmap:ip set type uses a memory range to store either IPv4 host (default) or IPv4 network addresses. A bitmap:ip type of set can store up to 65536 entries.

CREATE-OPTIONS := range fromip-toip|ip/cidr [ netmask cidr ] [ timeout value ] [ counters ] [ comment ] [ skbinfo ]

ADD-ENTRY := { ip | fromip-toip | ip/cidr }

ADD-OPTIONS := [ timeout value ] [ packets value ] [ bytes value ] [ comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := { ip | fromip-toip | ip/cidr }

TEST-ENTRY := ip

Mandatory create options:

  • range fromip-toip|ip/cidr โ€” Create the set from the specified inclusive address range expressed in an IPv4 address range or network. The size of the range (in entries) cannot exceed the limit of maximum 65536 elements.

Optional create options:

  • netmask cidr โ€” When the optional netmask parameter specified, network addresses will be stored in the set instead of IP host addresses. The cidr prefix value must be between 1-32. An IP address will be in the set if the network address, which is resulted by masking the address with the specified netmask, can be found in the set.

The bitmap:ip type supports adding or deleting multiple entries in one command.

Examples:

ipset create foo bitmap:ip range 192.168.0.0/16

ipset add foo 192.168.1/24

ipset test foo 192.168.1.1

๐ŸŽ€ bitmap:ip,mac ๐ŸŽ€

The bitmap:ip,mac set type uses a memory range to store IPv4 and a MAC address pairs. A bitmap:ip,mac type of set can store up to 65536 entries.

CREATE-OPTIONS := range fromip-toip|ip/cidr [ timeout value ] [ counters ] [ comment ] [ skbinfo ]

ADD-ENTRY := ip[,macaddr]

ADD-OPTIONS := [ timeout value ] [ packets value ] [ bytes value ] [ comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := ip[,macaddr]

TEST-ENTRY := ip[,macaddr]

Mandatory options to use when creating a bitmap:ip,mac type of set:

  • range fromip-toip|ip/cidr โ€” Create the set from the specified inclusive address range expressed in an IPv4 address range or network. The size of the range cannot exceed the limit of maximum 65536 entries.

The bitmap:ip,mac type is exceptional in the sense that the MAC part can be left out when adding/deleting/testing entries in the set. If we add an entry without the MAC address specified, then when the first time the entry is matched by the kernel, it will automatically fill out the missing MAC address with the MAC address from the packet. The source MAC address is used if the entry matched due to a src parameter of the set match, and the destination MAC address is used if available and the entry matched due to a dst parameter. If the entry was specified with a timeout value, the timer starts off when the IP and MAC address pair is complete.

The bitmap:ip,mac type of sets require two src/dst parameters of the set match and SET target netfilter kernel modules. For matches on destination MAC addresses, see COMMENTS below.

Examples:

ipset create foo bitmap:ip,mac range 192.168.0.0/16

ipset add foo 192.168.1.1,12:34:56:78:9A:BC

ipset test foo 192.168.1.1

๐ŸŽ€ bitmap:port ๐ŸŽ€

The bitmap:port set type uses a memory range to store port numbers and such a set can store up to 65536 ports.

CREATE-OPTIONS := range fromport-toport [ timeout value ] [ counters ] [ comment ] [ skbinfo ]

ADD-ENTRY := { [proto:]port | [proto:]fromport-toport }

ADD-OPTIONS := [ timeout value ] [ packets value ] [ bytes value ] [ comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := { [proto:]port | [proto:]fromport-toport }

TEST-ENTRY := [proto:]port

Mandatory options to use when creating a bitmap:port type of set:

  • range [proto:]fromport-toport โ€” Create the set from the specified inclusive port range.

The set match and SET target netfilter kernel modules interpret the stored numbers as TCP or UDP port numbers.

proto only needs to be specified if a service name is used and that name does not exist as a TCP service. The protocol is never stored in the set, just the port number of the service.

Examples:

ipset create foo bitmap:port range 0-1024

ipset add foo 80

ipset test foo 80

ipset del foo udp:[macon-udp]-[tn-tl-w2]

๐ŸŽ€ hash:ip ๐ŸŽ€

The hash:ip set type uses a hash to store IP host addresses (default) or network addresses. Zero valued IP address cannot be stored in a hash:ip type of set.

okay bestie, picking right back up where we left off โ€” here's the rest of what hash:ip is willing to take at create time, plus what you can hand it per entry:

CREATE-OPTIONS := [ family { inet | inet6 } ] [ hashsize value ] [ maxelem value ] [ bucketsize value ] [ netmask cidr ] [ bitmask mask ] [ timeout value ] [ counters ] [ comment ] [ skbinfo ]

ADD-ENTRY := ipaddr

ADD-OPTIONS := [ timeout value ] [ packets value ] [ bytes value ] [ comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := ipaddr

TEST-ENTRY := ipaddr

Optional create options, and yes we're doing them again because each set type has its own lil rules ๐Ÿ’…

  • netmask cidr โ€” when you actually pass this optional netmask parameter, the set stores network addresses instead of IP host addresses. That cidr prefix value has to sit between 1-32 for IPv4 and between 1-128 for IPv6. An IP address counts as being in the set if the network address โ€” the one you get by masking the address with the netmask โ€” can be found in the set. Like, the whole vibe is "we're matching blocks not people". Examples:
ipset create foo hash:ip netmask 30

ipset add foo 192.168.1.0/24

ipset test foo 192.168.1.2
  • bitmask mask โ€” this one works similar to netmask but it will accept any valid IPv4/v6 address. It does not have to be a valid netmask. so yeah, it's the unhinged flexible cousin ๐Ÿฆ‹

๐Ÿ“ hash:mac ๐Ÿ“

The hash:mac set type uses a hash to store MAC addresses. Zero valued MAC addresses cannot be stored in a hash:mac type of set โ€” like, it's just not happening, bestie. For matches on destination MAC addresses, see COMMENTS below.

CREATE-OPTIONS := [ hashsize value ] [ maxelem value ] [ bucketsize value ] [ timeout value ] [ counters ] [ comment ] [ skbinfo ]

ADD-ENTRY := macaddr

ADD-OPTIONS := [ timeout value ] [ packets value ] [ bytes value ] [ comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := macaddr

TEST-ENTRY := macaddr

Examples, because seeing it > reading it fr fr:

ipset create foo hash:mac

ipset add foo 01:02:03:04:05:06

ipset test foo 01:02:03:04:05:06

๐Ÿฆ‹ hash:ip,mac ๐Ÿฆ‹

The hash:ip,mac set type uses a hash to store IP and a MAC address pairs โ€” it's giving power couple, honestly. Zero valued MAC addresses cannot be stored in a hash:ip,mac type of set. For matches on destination MAC addresses, see COMMENTS below.

CREATE-OPTIONS := [ family { inet | inet6 } ] [ hashsize value ] [ maxelem value ] [ bucketsize value ] [ timeout value ] [ counters ] [ comment ] [ skbinfo ]

ADD-ENTRY := ipaddr,macaddr

ADD-OPTIONS := [ timeout value ] [ packets value ] [ bytes value ] [ comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := ipaddr,macaddr

TEST-ENTRY := ipaddr,macaddr

Examples:

ipset create foo hash:ip,mac

ipset add foo 1.1.1.1,01:02:03:04:05:06

ipset test foo 1.1.1.1,01:02:03:04:05:06

๐Ÿ’œ hash:net ๐Ÿ’œ

The hash:net set type uses a hash to store different sized IP network addresses. A network address with zero prefix size cannot be stored in this type of sets. periodt.

CREATE-OPTIONS := [ family { inet | inet6 } ] [ hashsize value ] [ maxelem value ] [ bucketsize value ] [ timeout value ] [ counters ] [ comment ] [ skbinfo ]

ADD-ENTRY := netaddr

ADD-OPTIONS := [ timeout value ] [ nomatch ] [ packets value ] [ bytes value ] [ comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := netaddr

TEST-ENTRY := netaddr

where netaddr := ip[/cidr]

When you're adding/deleting/testing entries, if the cidr prefix parameter is not specified, then the host prefix value is assumed. When adding/deleting entries, the exact element is added/deleted and overlapping elements are not checked by the kernel. When testing entries, if a host address is tested, then the kernel tries to match the host address in the networks added to the set and reports the result accordingly. so basically it'll go looking for you ๐Ÿ’…

From the set netfilter match point of view, the searching for a match always starts from the smallest size of netblock (most specific prefix) to the largest one (least specific prefix) added to the set. When adding/deleting IP addresses to the set by the SET netfilter target, it will be added/deleted by the most specific prefix which can be found in the set, or by the host prefix value if the set is empty.

The lookup time grows linearly with the number of the different prefix values added to the set โ€” iykyk, more prefixes, more walking.

Example:

ipset create foo hash:net

ipset add foo 192.168.0.0/24

ipset add foo 10.1.0.0/16

ipset add foo 192.168.0/24

ipset add foo 192.168.0/30 nomatch

When matching the elements in the set above, all IP addresses will match from the networks 192.168.0.0/24, 10.1.0.0/16 and 192.168.0/24 except the ones from 192.168.0/30. slay.


๐ŸŒˆ hash:net,net ๐ŸŒˆ

The hash:net,net set type uses a hash to store pairs of different sized IP network addresses. Bear in mind that the first parameter has precedence over the second, so a nomatch entry could be potentially be ineffective if a more specific first parameter existed with a suitable second parameter. Network address with zero prefix size cannot be stored in this type of set.

CREATE-OPTIONS := [ family { inet | inet6 } ] [ hashsize value ] [ maxelem value ] [ bucketsize value ] [ netmask cidr ] [ bitmask mask ] [ timeout value ] [ counters ] [ comment ] [ skbinfo ]

ADD-ENTRY := netaddr,netaddr

ADD-OPTIONS := [ timeout value ] [ nomatch ] [ packets value ] [ bytes value ] [ comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := netaddr,netaddr

TEST-ENTRY := netaddr,netaddr

where netaddr := ip[/cidr]

When adding/deleting/testing entries, if the cidr prefix parameter is not specified, then the host prefix value is assumed. When adding/deleting entries, the exact element is added/deleted and overlapping elements are not checked by the kernel. When testing entries, if a host address is tested, then the kernel tries to match the host address in the networks added to the set and reports the result accordingly.

From the set netfilter match point of view, the searching for a match always starts from the smallest size of netblock (most specific prefix) to the largest one (least specific prefix) with the first param having precedence. When adding/deleting IP addresses to the set by the SET netfilter target, it will be added/deleted by the most specific prefix which can be found in the set, or by the host prefix value if the set is empty.

The lookup time grows linearly with the number of the different prefix values added to the first parameter of the set. The number of secondary prefixes further increases this as the list of secondary prefixes is traversed per primary prefix. (not me explaining quadratic suffering ๐Ÿ˜ญ)

Optional create options:

  • netmask cidr โ€” when the optional netmask parameter is specified, network addresses will be stored in the set instead of IP host addresses. The cidr prefix value must be between 1-32 for IPv4 and between 1-128 for IPv6. An IP address will be in the set if the network address, which is resulted by masking the address with the netmask, can be found in the set.
  • bitmask mask โ€” this works similar to netmask but it will accept any valid IPv4/v6 address. It does not have to be a valid netmask.

Example:

ipset create foo hash:net,net

ipset add foo 192.168.0.0/24,10.0.1.0/24

ipset add foo 10.1.0.0/16,10.255.0.0/24

ipset add foo 192.168.0/24,192.168.54.0-192.168.54.255

ipset add foo 192.168.0/30,192.168.64/30 nomatch

When matching the elements in the set above, all IP addresses will match from the networks 192.168.0.0/24<->10.0.1.0/24, 10.1.0.0/16<->10.255.0.0/24 and 192.168.0/24<->192.168.54.0/24 except the ones from 192.168.0/30<->192.168.64/30.


๐ŸŽ€ hash:ip,port ๐ŸŽ€

The hash:ip,port set type uses a hash to store IP address and port number pairs. The port number is interpreted together with a protocol (default TCP) and zero protocol number cannot be used.

CREATE-OPTIONS := [ family { inet | inet6 } ] [ hashsize value ] [ maxelem value ] [ bucketsize value ] [ netmask cidr ] [ bitmask mask ] [ timeout value ] [ counters ] [ comment ] [ skbinfo ]

ADD-ENTRY := ipaddr,[proto:]port

ADD-OPTIONS := [ timeout value ] [ packets value ] [ bytes value ] [ comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := ipaddr,[proto:]port

TEST-ENTRY := ipaddr,[proto:]port

The [proto:]port part of the elements may be expressed in the following forms, where the range variations are valid when adding or deleting entries:

  • portname[-portname] โ€” TCP port or range of ports expressed in TCP portname identifiers from /etc/services
  • portnumber[-portnumber] โ€” TCP port or range of ports expressed in TCP port numbers
  • tcp|sctp|udp|udplite:portname|portnumber[-portname|portnumber] โ€” TCP, SCTP, UDP or UDPLITE port or port range expressed in port name(s) or port number(s)
  • icmp:codename|type/code โ€” ICMP codename or type/code. The supported ICMP codename identifiers can always be listed by the help command.
  • icmpv6:codename|type/code โ€” ICMPv6 codename or type/code. The supported ICMPv6 codename identifiers can always be listed by the help command.
  • proto:0 โ€” all other protocols, as an identifier from /etc/protocols or number. The pseudo port number must be zero.

The hash:ip,port type of sets require two src/dst parameters of the set match and SET target kernel modules. heads up ๐Ÿ’€

Optional create options:

  • netmask cidr โ€” when the optional netmask parameter is specified, network addresses will be stored in the set instead of IP host addresses. The cidr prefix value must be between 1-32 for IPv4 and between 1-128 for IPv6. An IP address will be in the set if the network address, which is resulted by masking the address with the netmask, can be found in the set.
  • bitmask mask โ€” this works similar to netmask but it will accept any valid IPv4/v6 address. It does not have to be a valid netmask.

Examples:

ipset create foo hash:ip,port

ipset add foo 192.168.1.0/24,80-82

ipset add foo 192.168.1.1,udp:53

ipset add foo 192.168.1.1,vrrp:0

ipset test foo 192.168.1.1,80

โœจ hash:net,port โœจ

The hash:net,port set type uses a hash to store different sized IP network address and port pairs. The port number is interpreted together with a protocol (default TCP) and zero protocol number cannot be used. Network address with zero prefix size is not accepted either. like, zero prefix, zero chill ๐Ÿ™ˆ

CREATE-OPTIONS := [ family { inet | inet6 } ] [ hashsize value ] [ maxelem value ] [ bucketsize value ] [ timeout value ] [ counters ] [ comment ] [ skbinfo ]

ADD-ENTRY := netaddr,[proto:]port

so the hash:net,port element syntax wraps up like this, bestie:

ADD-OPTIONS := [ timeout value ]  [ nomatch ] [ packets value ] [ bytes
value ] [ comment string ] [ skbmark value ] [ skbprio value ] [
skbqueue value ]

DEL-ENTRY := netaddr,[proto:]port

TEST-ENTRY := netaddr,[proto:]port

where netaddr := ip[/cidr]

For the netaddr part of the elements, go look at the hash:net set type description. For the [proto:]port part, it's the hash:ip,port set type description. Easy peasy. โœจ

When you're adding/deleting/testing entries and you don't specify the cidr prefix parameter, the host prefix value is assumed. When adding/deleting entries, the exact element is added/deleted and the kernel does not check overlapping elements. When testing entries, if a host address is tested, the kernel tries to match the host address in the networks added to the set and reports the result accordingly. No cap. ๐Ÿ’…

From the set netfilter match point of view, searching for a match always starts from the smallest size of netblock (most specific prefix) to the largest one (least specific prefix) added to the set. When adding/deleting IP addresses to the set by the SET netfilter target, it will be added/deleted by the most specific prefix which can be found in the set, or by the host prefix value if the set is empty. Periodt. ๐Ÿ‘‘

The lookup time grows linearly with the number of the different prefix values added to the set. Just so you know. ๐Ÿ˜ญ

Examples, bestie:

ipset create foo hash:net,port

ipset add foo 192.168.0/24,25

ipset add foo 10.1.0.0/16,80

ipset test foo 192.168.0/24,25

hash:ip,port,ip ๐Ÿ’–

The hash:ip,port,ip set type uses a hash to store IP address, port number and a second IP address triples. The port number is interpreted together with a protocol (default TCP) and zero protocol number cannot be used. Slay. โœจ

CREATE-OPTIONS := [ family { inet | inet6 } ] [ hashsize value ] [
maxelem value ] [ bucketsize value ] [ timeout value ] [ counters ] [
comment ] [ skbinfo ]

ADD-ENTRY := ipaddr,[proto:]port,ip

ADD-OPTIONS := [ timeout value ] [ packets value ] [ bytes value ] [
comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := ipaddr,[proto:]port,ip

TEST-ENTRY := ipaddr,[proto:]port,ip

For the first ipaddr and [proto:]port parts of the elements, see the descriptions at the hash:ip,port set type. The hash:ip,port,ip type of sets require three src/dst parameters of the set match and SET target kernel modules. ๐Ÿ”ฅ

Examples:

ipset create foo hash:ip,port,ip

ipset add foo 192.168.1.1,80,10.0.0.1

ipset test foo 192.168.1.1,udp:53,10.0.0.1

hash:ip,port,net ๐Ÿฆ‹

The hash:ip,port,net set type uses a hash to store IP address, port number and IP network address triples. The port number is interpreted together with a protocol (default TCP) and zero protocol number cannot be used. Network address with zero prefix size cannot be stored either. Not me finding that out the hard way. ๐Ÿ™ˆ

CREATE-OPTIONS := [ family { inet | inet6 } ] [ hashsize value ] [
maxelem value ] [ bucketsize value ] [ timeout value ] [ counters ] [
comment ] [ skbinfo ]

ADD-ENTRY := ipaddr,[proto:]port,netaddr

ADD-OPTIONS := [ timeout value ]  [ nomatch ] [ packets value ] [ bytes
value ] [ comment string ] [ skbmark value ] [ skbprio value ] [
skbqueue value ]

DEL-ENTRY := ipaddr,[proto:]port,netaddr

TEST-ENTRY := ipaddr,[proto:]port,netaddr

where netaddr := ip[/cidr]

For the ipaddr and [proto:]port parts of the elements, see the descriptions at the hash:ip,port set type. For the netaddr part, see the description at the hash:net set type.

From the set netfilter match point of view, searching for a match always starts from the smallest size of netblock (most specific cidr) to the largest one (least specific cidr) added to the set. When adding/deleting triples to the set by the SET netfilter target, it will be added/deleted by the most specific cidr which can be found in the set, or by the host cidr value if the set is empty. Iconic. ๐Ÿ‘‘

The lookup time grows linearly with the number of the different cidr values added to the set.

The hash:ip,port,net type of sets require three src/dst parameters of the set match and SET target kernel modules.

Examples:

ipset create foo hash:ip,port,net

ipset add foo 192.168.1,80,10.0.0/24

ipset add foo 192.168.2,25,10.1.0.0/16

ipset test foo 192.168.1,80.10.0.0/24

hash:ip,mark ๐ŸŽ€

The hash:ip,mark set type uses a hash to store IP address and packet mark pairs. Cute. โœจ

CREATE-OPTIONS := [ family { inet | inet6 } ] [ markmask value ] [
hashsize value ] [ maxelem value ] [ bucketsize value ] [ timeout value
] [ counters ] [ comment ] [ skbinfo ]

ADD-ENTRY := ipaddr,mark

ADD-OPTIONS := [ timeout value ] [ packets value ] [ bytes value ] [
comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := ipaddr,mark

TEST-ENTRY := ipaddr,mark

Optional create options:

  • markmask value โ€” Lets you set bits you are interested in the packet mark. This value is then used to perform bitwise AND operation for every mark added. markmask can be any value between 1 and 4294967295, by default all 32 bits are set. ๐Ÿ’…

The mark can be any value between 0 and 4294967295.

The hash:ip,mark type of sets require two src/dst parameters of the set match and SET target kernel modules.

Examples:

ipset create foo hash:ip,mark

ipset add foo 192.168.1.0/24,555

ipset add foo 192.168.1.1,0x63

ipset add foo 192.168.1.1,111236

hash:net,port,net ๐ŸŒˆ

The hash:net,port,net set type behaves similarly to hash:ip,port,net but accepts a cidr value for both the first and last parameter. Either subnet is permitted to be a /0 should you wish to match port between all destinations. Main character energy fr fr. ๐Ÿ‘‘

CREATE-OPTIONS := [ family { inet | inet6 } ] [ hashsize value ] [
maxelem value ] [ bucketsize value ] [ timeout value ] [ counters ] [
comment ] [ skbinfo ]

ADD-ENTRY := netaddr,[proto:]port,netaddr

ADD-OPTIONS := [ timeout value ]  [ nomatch ] [ packets value ] [ bytes
value ] [ comment string ] [ skbmark value ] [ skbprio value ] [
skbqueue value ]

DEL-ENTRY := netaddr,[proto:]port,netaddr

TEST-ENTRY := netaddr,[proto:]port,netaddr

where netaddr := ip[/cidr]

For the [proto:]port part of the elements, see the description at the hash:ip,port set type. For the netaddr part, see the description at the hash:net set type.

From the set netfilter match point of view, searching for a match always starts from the smallest size of netblock (most specific cidr) to the largest one (least specific cidr) added to the set. When adding/deleting triples to the set by the SET netfilter target, it will be added/deleted by the most specific cidr which can be found in the set, or by the host cidr value if the set is empty. The first subnet has precedence when performing the most-specific lookup, just as for hash:net,net. The way that works is lowkey iconic. โœจ

The lookup time grows linearly with the number of the different cidr values added to the set and by the number of secondary cidr values per primary.

The hash:net,port,net type of sets require three src/dst parameters of the set match and SET target kernel modules.

Examples:

ipset create foo hash:net,port,net

ipset add foo 192.168.1.0/24,0,10.0.0/24

ipset add foo 192.168.2.0/24,25,10.1.0.0/16

ipset test foo 192.168.1.1,80,10.0.0.1

hash:net,iface ๐Ÿงš

The hash:net,iface set type uses a hash to store different sized IP network address and interface name pairs. Obsessed. ๐Ÿ’œ

CREATE-OPTIONS := [ family { inet | inet6 } ] [ hashsize value ] [
maxelem value ] [ bucketsize value ] [ timeout value ] [ counters ] [
comment ] [ skbinfo ]

ADD-ENTRY := netaddr,[physdev:]iface

ADD-OPTIONS := [ timeout value ]  [ nomatch ] [ packets value ] [ bytes
value ] [ comment string ] [ skbmark value ] [ skbprio value ] [
skbqueue value ] [ wildcard ]

DEL-ENTRY := netaddr,[physdev:]iface

TEST-ENTRY := netaddr,[physdev:]iface

where netaddr := ip[/cidr]

For the netaddr part of the elements, see the description at the hash:net set type.

When adding/deleting/testing entries, if the cidr prefix parameter is not specified, then the host prefix value is assumed. When adding/deleting entries, the exact element is added/deleted and overlapping elements are not checked by the kernel. When testing entries, if a host address is tested, then the kernel tries to match the host address in the networks added to the set and reports the result accordingly. No cap. ๐Ÿ’…

From the set netfilter match point of view, searching for a match always starts from the smallest size of netblock (most specific prefix) to the largest one (least specific prefix) added to the set. When adding/deleting IP addresses to the set by the SET netfilter target, it will be added/deleted by the most specific prefix which can be found in the set, or by the host prefix value if the set is empty.

The second direction parameter of the set match and SET target modules corresponds to the incoming/outgoing interface: src to the incoming one (similar to the -i flag of iptables), while dst to the outgoing one (similar to the -o flag of iptables). When the interface is flagged with physdev:, the interface is interpreted as the incoming/outgoing bridge port. iykyk. ๐ŸŒ‰

The lookup time grows linearly with the number of the different prefix values added to the set.

The internal restriction of the hash:net,iface set type is that the same network prefix cannot be stored with more than 64 different interfaces in a single set. Not me crying about that limit. ๐Ÿ˜ญ

Examples:

ipset create foo hash:net,iface

ipset add foo 192.168.0/24,eth0

ipset add foo 10.1.0.0/16,eth1

ipset test foo 192.168.0/24,eth0

list:set ๐Ÿ“

The list:set type uses a simple list in which you can store set names. So meta. โœจ

CREATE-OPTIONS := [ size value ] [ timeout value ] [ counters ] [
comment ] [ skbinfo ]

ADD-ENTRY := setname [ { before | after } setname ]

ADD-OPTIONS := [ timeout value ] [ packets value ] [ bytes value ] [
comment string ] [ skbmark value ] [ skbprio value ] [ skbqueue value ]

DEL-ENTRY := setname [ { before | after } setname ]

TEST-ENTRY := setname [ { before | after } setname ]

Optional create options:

  • size value โ€” The size of the list, the default is 8. The parameter is ignored since ipset version 6.24. So like, it's giving legacy. ๐Ÿ’€

By the ipset command you can add, delete and test set names in a list:set type of set. Periodt. ๐Ÿ’…

Okay bestie, so you can totally poke at the sets inside a <code>list:set</code> using the <code>set</code> match or the <code>SET</code> target from netfilter ๐Ÿ’… โ€” like, test entries, add entries, delete entries, all of it. The match is gonna go hunting for a matching entry inside those sets, and the target is gonna try to yeet an entry into the first set that'll actually take it. โœจ

And the number of direction options you hand to the match and target? Lowkey the whole plot. Sets that need more parameters than you specified get skipped, periodt. Sets with equal or fewer parameters get checked, and their elements get added or deleted. So if a and b are list:set type sets, then in this command:

iptables -m set --match-set a src,dst -j SET --add-set b src,dst

the match and target will skip any set in a and b that stores data triples ๐Ÿšซ, but will match every set with single or double data storage in a, stop matching at the first successful set, and then add src to the first single-storage set โ€” or src,dst to the first double-storage set โ€” in b that can accept the entry. Think of a list:set type set as an ordered union of the set elements. Iconic, honestly. ๐Ÿ‘‘

Not me being dramatic, but please note: with the ipset command you can add, delete and test the setnames in a list:set type of set โ€” not whether some set's member (like an IP address) is present. Different thing entirely, bestie. ๐Ÿซถ

๐Ÿšง GENERAL RESTRICTIONS ๐Ÿšง

  • Zero valued set entries? Cannot vibe with hash methods at all. Nope.
  • Zero protocol value with ports? Also a no. ๐Ÿšซ

๐Ÿ’ฌ COMMENTS ๐Ÿ’ฌ

Okay so real talk, choosing your set type is a whole personality decision and here's the tea:

  • Wanna store same-size subnets from one given network (say /24 blocks out of a /8 network)? Use the bitmap:ip set type. ๐ŸŽ€
  • Wanna store random same-size networks (say random /24 blocks)? Use the hash:ip set type. ๐Ÿฆ‹
  • Got random-size netblocks? hash:net. Boom, that's the one. ๐ŸŒˆ

Now, about matching on destination MAC addresses using the dst parameter of the set match netfilter kernel modules โ€” this only works if the destination MAC address is actually available in the packet at that processing stage. Which means: it only applies to incoming packets in the PREROUTING, INPUT and FORWARD chains, matched against the MAC address as originally found in the received packet (typically, one of the MAC addresses of the local host). ๐Ÿซก

Important: this is not the destination MAC address that a destination IP address resolves to, after routing. Not the same thing, don't get it twisted. If the MAC address isn't available (e.g. in the OUTPUT chain), the packet will simply not match. That's it, that's the rule. ๐Ÿ’€

Backward compatibility is maintained, so the old ipset syntax is still supported. Slay, legacy support. ๐Ÿ’œ

And heads up: the iptree and iptreemap set types are removed โ€” if you refer to them, they get automatically replaced by hash:ip type of sets. Gone but not forgotten, ig. โœจ


๐Ÿฉบ DIAGNOSTICS ๐Ÿฉบ

Various error messages get printed to standard error. The exit code is 0 for correct functioning. So if you see a 0, you ate. ๐Ÿ‘‘


๐Ÿ› BUGS ๐Ÿ›

Bugs? No, just funny features. :-) OK, just kidding...

(She's unserious and I love that for her. ๐Ÿ˜ญ)


๐Ÿ‘€ SEE ALSO ๐Ÿ‘€


๐Ÿ‘‘ AUTHORS ๐Ÿ‘‘

  • Jozsef Kadlecsik wrote ipset, which is based on ippool by Joakim Axelsson, Patrick Schaaf and Martin Josefsson. ๐Ÿซถ
  • Sven Wegener wrote the iptreemap type. ๐Ÿ’–

๐ŸŒŸ LAST REMARK ๐ŸŒŸ

I stand on the shoulders of giants.

Periodt. That's the whole page, bestie โ€” go forth and configure your sets, you absolute main character. ๐Ÿ’…โœจ๐ŸŒธ


This gorgeous thing came from ipset by Jozsef Kadlecsik, dated Jun 25, 2015, and it's page IPSET(8). Bye babes, ily, go read iptables(8) next ๐ŸŽ€๐Ÿ’œ