<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Firewall on KnightLi Blog</title>
        <link>https://www.knightli.com/en/tags/firewall/</link>
        <description>Recent content in Firewall on KnightLi Blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en</language>
        <lastBuildDate>Sat, 18 Apr 2026 10:31:12 +0800</lastBuildDate><atom:link href="https://www.knightli.com/en/tags/firewall/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Understanding the nftables Framework: Tables, Chains, Rules, and Sets</title>
        <link>https://www.knightli.com/en/2026/04/18/nftables-framework-concepts/</link>
        <pubDate>Sat, 18 Apr 2026 10:31:12 +0800</pubDate>
        
        <guid>https://www.knightli.com/en/2026/04/18/nftables-framework-concepts/</guid>
        <description>&lt;p&gt;When learning &lt;code&gt;nftables&lt;/code&gt;, it is easy to start with command details: how to add a rule, how to delete a handle, or how to write a port match. Commands matter, but if you understand the framework first, reading rules, troubleshooting, and designing rule sets become much easier.&lt;/p&gt;
&lt;p&gt;You can think of nftables as a layered structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;table&lt;/code&gt; isolates rule namespaces.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;family&lt;/code&gt; decides which network protocols the rules apply to.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chain&lt;/code&gt; decides at which stage rules are executed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rule&lt;/code&gt; defines the actual match and action.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, and &lt;code&gt;verdict map&lt;/code&gt; reduce repeated rules and make rule sets easier to maintain.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following sections explain these concepts layer by layer.&lt;/p&gt;
&lt;h2 id=&#34;table-rule-namespace&#34;&gt;table: Rule Namespace
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;table&lt;/code&gt; is the outermost rule container in nftables. Different tables are isolated from each other, so a common practice is to put related rules into the same table.&lt;/p&gt;
&lt;p&gt;For example, you can separate filtering rules, NAT rules, or custom testing rules. This keeps boundaries clear: when debugging, you know which group of rules you are changing; when cleaning up, you are less likely to delete unrelated content by mistake.&lt;/p&gt;
&lt;p&gt;A table itself does not directly process packets. The chain and rule objects inside the table are what actually participate in packet processing.&lt;/p&gt;
&lt;h2 id=&#34;family-which-protocols-the-rules-apply-to&#34;&gt;family: Which Protocols the Rules Apply To
&lt;/h2&gt;&lt;p&gt;When creating a table, you need to choose a &lt;code&gt;family&lt;/code&gt;. It determines what kind of packets the rules in the table apply to.&lt;/p&gt;
&lt;p&gt;Common families can be understood this way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ip&lt;/code&gt;: handles IPv4 only.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ip6&lt;/code&gt;: handles IPv6 only.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inet&lt;/code&gt;: handles both IPv4 and IPv6.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;arp&lt;/code&gt;: handles ARP.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bridge&lt;/code&gt;: handles bridge-layer traffic.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;netdev&lt;/code&gt;: closer to the network device ingress path, suitable for handling traffic at an earlier stage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For ordinary firewall rules, &lt;code&gt;inet&lt;/code&gt; is commonly used. It lets you keep IPv4 and IPv6 rules in the same table and avoids maintaining two similar rule structures.&lt;/p&gt;
&lt;h2 id=&#34;chain-where-rules-are-executed&#34;&gt;chain: Where Rules Are Executed
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;chain&lt;/code&gt; is a list of rules. After a packet enters a hook, it passes through the rules in the chain in order.&lt;/p&gt;
&lt;p&gt;Chains can roughly be divided into two types:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Base chain: attached to a hook in the kernel network path and actively called by the packet flow.&lt;/li&gt;
&lt;li&gt;Regular chain: not directly attached to a hook; it must be called by jumps from other rules.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A base chain usually specifies several key properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;type&lt;/code&gt;: the purpose of the chain, such as &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;nat&lt;/code&gt;, or &lt;code&gt;route&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hook&lt;/code&gt;: the processing stage, such as &lt;code&gt;prerouting&lt;/code&gt;, &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;forward&lt;/code&gt;, &lt;code&gt;output&lt;/code&gt;, or &lt;code&gt;postrouting&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;priority&lt;/code&gt;: when multiple chains exist on the same hook, this decides which runs first.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;policy&lt;/code&gt;: the default action when no rule matches, commonly &lt;code&gt;accept&lt;/code&gt; or &lt;code&gt;drop&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key point is that rules do not take effect just anywhere. The same rule has completely different meaning when placed in &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;forward&lt;/code&gt;, or &lt;code&gt;output&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;rule-match-conditions-plus-actions&#34;&gt;rule: Match Conditions Plus Actions
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;rule&lt;/code&gt; is where nftables actually makes decisions. It usually consists of two parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Match conditions: source IP, destination IP, protocol, port, interface, connection state, and so on.&lt;/li&gt;
&lt;li&gt;Actions: &lt;code&gt;accept&lt;/code&gt;, &lt;code&gt;drop&lt;/code&gt;, &lt;code&gt;reject&lt;/code&gt;, &lt;code&gt;counter&lt;/code&gt;, &lt;code&gt;jump&lt;/code&gt;, &lt;code&gt;return&lt;/code&gt;, and so on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rules are evaluated in order. After a packet matches an action that terminates processing, subsequent rules are no longer evaluated. If nothing matches, evaluation continues until the chain ends or the default policy is triggered.&lt;/p&gt;
&lt;p&gt;This is why rule order matters: more specific rules usually need to appear before broader rules, otherwise they may never get a chance to run.&lt;/p&gt;
&lt;h2 id=&#34;set-group-values-together&#34;&gt;set: Group Values Together
&lt;/h2&gt;&lt;p&gt;If you need to match many IP addresses, ports, or interfaces, writing many separate rules becomes hard to maintain. &lt;code&gt;set&lt;/code&gt; lets you manage a group of values of the same type in one place.&lt;/p&gt;
&lt;p&gt;For example, a group of trusted IPs, a group of blocked ports, or a group of addresses that need rate limiting can all be stored in a set. The rule only needs to check whether a value belongs to that set.&lt;/p&gt;
&lt;p&gt;The benefits of set are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fewer rules.&lt;/li&gt;
&lt;li&gt;Better readability.&lt;/li&gt;
&lt;li&gt;Easier element additions and removals later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When a rule set contains many repeated conditions, it is usually time to consider set.&lt;/p&gt;
&lt;h2 id=&#34;map-map-a-matched-value-to-a-result&#34;&gt;map: Map a Matched Value to a Result
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;map&lt;/code&gt; can be understood as a lookup table. It returns a result based on an input value.&lt;/p&gt;
&lt;p&gt;For example, different ports can map to different marks, or different addresses can map to different processing parameters. Compared with writing many if/else-style rules, map is more centralized and easier to maintain.&lt;/p&gt;
&lt;p&gt;set answers &amp;ldquo;is this value in the collection&amp;rdquo;; map answers &amp;ldquo;what result corresponds to this value&amp;rdquo;.&lt;/p&gt;
&lt;h2 id=&#34;verdict-map-map-a-matched-value-to-an-action&#34;&gt;verdict map: Map a Matched Value to an Action
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;verdict map&lt;/code&gt; is an important use of map: it maps a matched value to a verdict, which means a rule action.&lt;/p&gt;
&lt;p&gt;For example, different IP ranges can correspond to &lt;code&gt;accept&lt;/code&gt;, &lt;code&gt;drop&lt;/code&gt;, or jumps to different chains. This can compress many branches into one structure.&lt;/p&gt;
&lt;p&gt;When a rule set grows more complex, verdict map is very useful. It reduces repeated rules and expresses policy more like a table rather than a long list of conditional statements.&lt;/p&gt;
&lt;h2 id=&#34;designing-rules-from-the-concepts&#34;&gt;Designing Rules from the Concepts
&lt;/h2&gt;&lt;p&gt;When designing nftables rules, you can think in this order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First decide which &lt;code&gt;family&lt;/code&gt; the rules belong to.&lt;/li&gt;
&lt;li&gt;Then decide which &lt;code&gt;table&lt;/code&gt; they should go into.&lt;/li&gt;
&lt;li&gt;Choose the proper &lt;code&gt;hook&lt;/code&gt; and &lt;code&gt;chain&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Write the concrete &lt;code&gt;rule&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If there are many repeated conditions, introduce &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, or &lt;code&gt;verdict map&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Rules written this way are easier to maintain and easier to troubleshoot.&lt;/p&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary
&lt;/h2&gt;&lt;p&gt;nftables concepts are not complicated, but the hierarchy matters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;table defines rule boundaries.&lt;/li&gt;
&lt;li&gt;family defines protocol scope.&lt;/li&gt;
&lt;li&gt;chain defines execution position.&lt;/li&gt;
&lt;li&gt;rule defines matching and action.&lt;/li&gt;
&lt;li&gt;set, map, and verdict map manage complexity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Understand these concepts first, then look at concrete commands. That is more reliable than memorizing commands directly. Especially after a rule set grows, clear concepts help you determine whether a problem is in protocol scope, execution stage, rule order, or the match condition itself.&lt;/p&gt;
&lt;h2 id=&#34;references&#34;&gt;References
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.redhat.com/zh-cn/documentation/red_hat_enterprise_linux/10/html/configuring_firewalls_and_packet_filters/concepts-in-the-nftables-framework&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://docs.redhat.com/zh-cn/documentation/red_hat_enterprise_linux/10/html/configuring_firewalls_and_packet_filters/concepts-in-the-nftables-framework&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>nftables Quick Start: Tables, Chains, Rules, and Common Operations</title>
        <link>https://www.knightli.com/en/2026/04/18/nftables-quick-start/</link>
        <pubDate>Sat, 18 Apr 2026 10:22:07 +0800</pubDate>
        
        <guid>https://www.knightli.com/en/2026/04/18/nftables-quick-start/</guid>
        <description>&lt;p&gt;&lt;code&gt;nftables&lt;/code&gt; is a common packet filtering and firewall rule management tool on Linux. If you only need device access control, traffic counters, port matching, or basic rate limiting, you do not need to learn the entire rule system at once. Start with three concepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;table&lt;/code&gt;: a container for rules.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chain&lt;/code&gt;: where rules are evaluated, usually attached to a hook.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rule&lt;/code&gt;: the actual matching condition and action.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This article outlines a minimal workflow that is suitable for testing first in a safe environment.&lt;/p&gt;
&lt;h2 id=&#34;basic-structure&#34;&gt;Basic Structure
&lt;/h2&gt;&lt;p&gt;Prepare a few variables first. The following commands reuse them:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;customtable
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;chain&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;custom_control
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;target&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;drop
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;ip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;192.168.18.251
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;mac&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;00:00:01:02:03:04
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Create an &lt;code&gt;inet&lt;/code&gt; table that supports both IPv4 and IPv6:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add table inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then create a chain attached to the &lt;code&gt;forward&lt;/code&gt; stage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt; filter hook forward priority 0&lt;span class=&#34;se&#34;&gt;\;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Here, &lt;code&gt;type filter&lt;/code&gt; means this is a filtering rule chain, and &lt;code&gt;hook forward&lt;/code&gt; means it processes forwarded packets.&lt;/p&gt;
&lt;h2 id=&#34;common-matching-methods&#34;&gt;Common Matching Methods
&lt;/h2&gt;&lt;p&gt;Match by source IP. This is usually useful for the upload direction:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ip saddr &lt;span class=&#34;nv&#34;&gt;$ip&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Match by destination IP. This is usually useful for the download direction:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ip daddr &lt;span class=&#34;nv&#34;&gt;$ip&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;When matching by MAC address, &lt;code&gt;ether saddr&lt;/code&gt; can be used to control upstream traffic:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ether saddr &lt;span class=&#34;nv&#34;&gt;$mac&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Note that in networks involving bridging, forwarding, or address translation, downstream packets may not always be reliably filtered by destination MAC. For device access control, start by validating &lt;code&gt;ether saddr&lt;/code&gt; or IP-based rules first.&lt;/p&gt;
&lt;p&gt;To match ports, you can cover both TCP and UDP:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt; tcp, udp &lt;span class=&#34;o&#34;&gt;}&lt;/span&gt; dport &lt;span class=&#34;m&#34;&gt;22&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;To match a port range, use a comparison expression:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; tcp dport &lt;span class=&#34;se&#34;&gt;\&amp;gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1024&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;count-traffic-for-one-device&#34;&gt;Count Traffic for One Device
&lt;/h2&gt;&lt;p&gt;If you only want to count upload and download traffic for an IP address, use &lt;code&gt;counter return&lt;/code&gt;. After a match, it records the counter and returns, which can reduce further matching overhead when more statistic rules exist later.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ip saddr &lt;span class=&#34;nv&#34;&gt;$ip&lt;/span&gt; counter &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ip daddr &lt;span class=&#34;nv&#34;&gt;$ip&lt;/span&gt; counter &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;View the statistics:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft list chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If you need to see the &lt;code&gt;handle&lt;/code&gt; for each rule, add &lt;code&gt;-a&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft -a list chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;handle&lt;/code&gt; is important because nftables usually relies on it to delete a single rule.&lt;/p&gt;
&lt;h2 id=&#34;basic-rate-limiting&#34;&gt;Basic Rate Limiting
&lt;/h2&gt;&lt;p&gt;Rate limiting can be done with &lt;code&gt;limit rate over&lt;/code&gt;. For example, limit traffic over a specified rate by MAC address:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;rate&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;unit&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;mbytes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft add rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; ether saddr &lt;span class=&#34;nv&#34;&gt;$mac&lt;/span&gt; limit rate over &lt;span class=&#34;nv&#34;&gt;$rate&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$unit&lt;/span&gt;/second drop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Here, &lt;code&gt;mbytes&lt;/code&gt; and &lt;code&gt;kbytes&lt;/code&gt; can be understood as the usual M and K units. You do not need to manually multiply by 8. In practice, start with a more relaxed value, confirm the matching direction and effect, then tighten it if needed.&lt;/p&gt;
&lt;h2 id=&#34;delete-and-clean-up-rules&#34;&gt;Delete and Clean Up Rules
&lt;/h2&gt;&lt;p&gt;First list rules with &lt;code&gt;handle&lt;/code&gt; values:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft -a list chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then delete a rule by handle:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft delete rule inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt; handle &amp;lt;handle&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Flush a chain:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft flush chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Delete a chain:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft delete chain inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$chain&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Delete the entire table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft delete table inet &lt;span class=&#34;nv&#34;&gt;$table&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;During daily debugging, only clean up the table you created yourself. Avoid directly changing tables automatically generated by the system or other services. This makes rollback easier even if a rule is written incorrectly.&lt;/p&gt;
&lt;h2 id=&#34;usage-notes&#34;&gt;Usage Notes
&lt;/h2&gt;&lt;p&gt;When using nftables, it is often safer to create your own independent table and chain first. This has two benefits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Your rules are less likely to mix with existing system rules.&lt;/li&gt;
&lt;li&gt;Debugging, flushing, and deletion are safer.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After writing rules, always use &lt;code&gt;nft list chain&lt;/code&gt; to check actual matching behavior. MAC, interface, port, and rate-limit rules may behave differently across devices, bridge setups, and system versions. Small-scope testing is safer than writing complex rules all at once.&lt;/p&gt;
&lt;h2 id=&#34;references&#34;&gt;References
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.right.com.cn/forum/thread-8369750-1-1.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://www.right.com.cn/forum/thread-8369750-1-1.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        
    </channel>
</rss>
