Redian新闻
>
kubernetes之nftables用法介绍

kubernetes之nftables用法介绍

公众号新闻

Kubernetes 1.29版本中已经将nftables作为一个featureGates,本文简单整理了nftables的用法,便于后续理解kubernetes的nftables规则。文末给出了使用kubeadm部署启用nftables featureGates的配置文件。

如下内容来源nftables的man文档以及wiki。

nftables和iptables的不同之处

  1. nftables使用了新的语法:nftables使用了类似tcpdump的紧凑语法

  2. 可以完全配置tables和chains:iptables中有一些预定义的tables和chains(即使不需要),会对性能造成一定的影响。而nftables则没有预定义的tables和chains,因此需要明确定义各个table,以及其包含的对象(chains、sets、maps、flowtables和state object)。你可以定义table和chain的名称以及netfilter hook优先级。

  3. 单个nftables可以执行多个动作:iptables中通过匹配只能执行单个动作,但在nftables 规则中可以包含0或多个expressions(用于匹配报文),以及1或多个statements,每个expression会测试一个报文是否匹配特定的payload字段或报文/流的元数据。多个expressions会从左到右作线性评估,如果第一个expression匹配成功,则继续评估下一个expression。如果匹配了所有的expressions,则会执行statement。

    每个statement会执行一个动作,如设置netfilter mark、计算报文数、记录报文日志或做出诸如接收或丢弃报文或跳到另一个chain的决定。多个statements也是从左到右线性执行的,这样一条规则可以通过多个statements执行多个动作(需要注意的是verdict statement 会终结规则)。

  4. chain和rule中没有内置的计数器:nftables中的计数器是可选的,可以在需要时启用

  5. 可以更好地支持动态规则更新:iptables的规则是一体式的,一条规则的变更会影响到整体规则。而nftables的ruleset在内部以链表表示。现在,添加或删除一条规则不会影响道其他规则,从而简化了内部状态信息的维护。

  6. 简化了IPv4/IPv6双栈管理:nftables的inet family 可以同时支持IPv4和IPv6的chain。不再需要脚本来复制规则

  7. 新的通用型基础结构:该基础结构与nftables的核心紧密集成,并支持高级配置,如maps, verdict maps 和 intervals ,以实现面向性能的报文分类。

  8. 支持串联(Concatenations):从Linux kernel 4.1开始,可以串联多个keys,并将它们与maps 和 verdict maps相结合。其思想是构建一个元组,并该元组的值进行哈希以获得接近O(1)的查找效率。

  9. 无需升级内核即可支持新协议:内核升级一项耗时且艰巨的任务,尤其是当你必须在网络中维护多个防火墙时。分发的内核版本通常滞后于最新版本。当虚拟机使用nftables时,支持新协议通常不需要更新内核,只需要更新用户空间的nft即可。

nftables的结构

跟iptables一样,nftables也使用了table->chain->rule的概念。并使用family的概念区分了报文类型。

ADDRESS FAMILIES

Address families决定了处理的报文类型,默认使用ip

ipIPv4 address family.
ip6IPv6 address family.
inetInternet (IPv4/IPv6) address family.
arpARP address family, handling IPv4 ARP packets.
bridgeBridge address family, handling packets which traverse a bridge device.
netdevNetdev address family, handling packets on ingress and egress.

内核在报文处理路径的不同阶段设置了hooks,不同的address family对应各自的hooks。如 **IPv4/IPv6/ **的hooks如下:

HookDescription
prerouting所有报文进入系统前都会经过prerouting hook的处理。在执行路由前调用,早期过滤或通过变更报文属性来影响路由结果。
input在报文进入本地系统时会经过input hook 的处理
forward在将报文转发到不同的主机时会经过forward hook的处理
output本地进程发送的报文会经过outpu hook的处理
postrouting所有离开系统的报文都会经过 postrouting hook的处理
ingress所有进入系统的报文都会经过该hook的处理。它会在3层协议处理前被调用,因此它更早于prerouting hook,,可以用于过滤和策略处理。Ingress只针对Inet family (Linux kernel 5.10以上)生效。

特殊语法

连接符

nft中使用.表示连接符,如下面表示1.1.1.1 and 2.2.2.2 and TCP1.1.1.1 and 3.3.3.3 and UDP


nft add rule ip filter input ip saddr . ip daddr . ip protocol { 1.1.1.1 . 2.2.2.2 . tcp, 1.1.1.1 . 3.3.3.3 . udp} counter accept

Intervals

可以使用value-value的方式表示Intervals,一个Intervals可以视作一个参数


% nft add rule filter input ip daddr 192.168.0.1-192.168.0.250 drop

通用参数

位置参数handle

nftables中使用handle来表示位置ID,用于添加或删除表项,对应命令中的handle参数。可以通过-a参数输出handle信息。


$ nft -a list ruleset

注释comment

注释为一个单词或双引号中的多个单词。在hash中,需要使用斜杠来转移引号,如\"enable ssh for servers\"

DATA TYPES

DATA TYPES为Expression提供了数据类型定义。

RULESET

  • {list | flushruleset [family]

注意黑体字是关键字段,斜体为自定义字段,带[]的表示有默认值,为可选字段

ruleset表示所有的tables、chains等。

Example
  • nft list ruleset:显示所有的nftables规则,对应iptables的iptables-save命令.

    • 还可以指定family类型,如nft list ruleset inet

  • nft flush ruleset:清空所有的nftables规则

备份和恢复

备份


% echo "flush ruleset" > backup.nft

% nft list ruleset >> backup.nft

恢复


% nft -f backup.nft

TABLES

{add | createtable [familytable [ {comment comment ;} { flags 'flags ; }]
{delete | destroy | list | flushtable [familytable
list tables [family]
delete table [familyhandle handle
destroy table [familyhandle handle

tables包含chains、sets和stateful objects,并使用address family和名称进行区分,address family必须是ipip6inetarpbridgenetdevinet用于创建 IPv4/IPv6混合tables,如果不指定,默认为ipaddcreate的区别是,前者不会在table存在的情况下返回错误,而后者会。deletedestroy的区别也是如此,delete会在table不存在的情况下返货错误,而destroy则不会。

Example

$ nft add table inet my_table

CHAINS

  • {add | createchain [familytable chain [{ type type hook hook [device devicepriority priority ; [policy policy ;] [comment comment ;] }]

  • {delete | destroy | list | flushchain ['familytable chain

  • list chains [family]

  • delete chain [familytable handle handle

  • destroy chain [familytable handle handle

  • rename chain [familytable chain newname

chains中包含了规则(rules)。chains有两种:base chainsregular chainsbase chains为来自网络栈的报文的入口,regular chain用于跳转和组织规则。

对于base chain需要指定 typehook 和 priority参数:

TypeFamiliesHooksDescription
filterallallStandard chain type to use in doubt.
natip, ip6, inetprerouting, input, output, postrouting该类型的Chains可以根据conntrack表项执行NAT地址转换。一条连接中,只有第一个报文会经过该chain,其包含的rules定义了创建conntrack表项的详细信息。
routeip, ip6output如果报文已遍历了该类型的chain并将被接受,则如果IP首部的相关字段发送了更改,则将执行新的路由查找。这可以在Nftables中实现策略路由选择器。
priority

priority参数接收一个有符号整数或一个标准优先级名称,其指定了具有相同hook下的chain的执行顺序。数值越小优先级越高。

对于nat类型的chain,其优先级的下限为-200。

标准优先级名称、family和hook兼容性矩阵图:

NameValueFamiliesHooks
raw-300ip, ip6, inetall
mangle-150ip, ip6, inetall
dstnat-100ip, ip6, inetprerouting
filter0ip, ip6, inet, arp, netdevall
security50ip, ip6, inetall
srcnat100ip, ip6, inetpostrouting

可以使用基本的算术表达式(加法或减法)结合标准优先级名称来实现相对优先级,如 mangle - 5 表示-155。在使用list等命令显示时也使用这种表达方式。

bridge family的标准优先级名称和hook兼容性:

NameValueHooks
dstnat-300prerouting
filter-200all
out100output
srcnat300postrouting
policy

定义接收还是拒绝匹配到chain规则的报文,可选值为accept(默认值)或drop

Example

$ nft add chain inet mytable myin { type filter hook input priority 1; policy accept;}

下面展示了优先级和策略的用法:

table inet filter {    # This chain is evaluated first due to priority    chain services {        type filter hook input priority 0; policy accept;         # If matched, this rule will prevent any further evaluation        tcp dport http drop         # If matched, and despite the accept verdict, the packet proceeds to enter the chain below        tcp dport ssh accept         # Likewise for any packets that get this far and hit the default policy    }     # This chain is evaluated last due to priority    chain input {        type filter hook input priority 1; policy drop;        # All ingress packets end up being dropped here!    }}

RULES

  • {add | insertrule [familytable chain [handle handle | index indexstatement ... [comment comment]

  • replace rule [familytable chain handle handle statement ... [comment comment]

  • {delete | resetrule [familytable chain handle handle

  • destroy rule [familytable chain handle handle

  • reset rules [family] [table [chain]]

规则中,如果没有指定family,则默认使用ip。规则包含两部分:expression和statement

addinset都用于添加规则,前者用于将规则追加到给定的chain中(或给定的位置handle之后),后者用于将规则插入到给定的chain的开头(给给定的位置handle的前面)

Example

$ nft add rule ip filter output ip daddr 192.168.0.0/24 accept

# nft -a list ruleset

table inet filter {

chain input {

type filter hook input priority filter; policy accept;

ct state established,related accept # handle 4

ip saddr 10.1.1.1 tcp dport ssh accept # handle 5

...

# delete the rule with handle 5

nft delete rule inet filter input handle 5

SETS

  • add set [familytable set { type type | typeof expression ; [flags flags ;] [timeout timeout ;] [gc-interval gc-interval ;] [elements = { element[, ...] } ;] [size size ;] [comment comment ;] [policy 'policy ;] [auto-merge ;] }

  • {delete | destroy | list | flushset [familytable set

  • list sets [family]

  • delete set [familytable handle handle

  • {add | delete | destroy } element [familytable set { element[, ...] }

KeywordDescriptionType
type定义集合元素的数据类型支持字符串: ipv4_addripv6_addrether_addrinet_protoinet_servicemark
typeof定义集合元素的数据类型从Expression派生出的数据类型
flags集合标识字符串: constant, dynamic, interval, timeout. 用于描述集合属性
timeout元素停留在集合中的时间,如果集合来自报文路径(ruleset),则为强制字段字符串, 十进制加单位表示. 单位为: d, h, m, s
gc-intervalGC间隔,在指定timeout或flag timeout时生效字符串, 十进制加单位表示. 单位为: d, h, m, s
elements定义集合中的元素集合的数据类型
size集合的最大元素数目,如果集合来自报文路径(ruleset),则为强制字段unsigned integer (64 bit)
policy集合策略字符串: performance [默认], memory
auto-merge自动连接或合并集合元素(仅适用于interval集合)

nftables提供了两种集合的概念:匿名集合和命名集合。

Example

下面给出了set的基本用法:


$ nft add set ip filter flags_set {type ipv4_addr\; flags constant, interval\;}



$ nft add set ip filter daddrs {type ipv4_addr \; flags timeout \; elements={192.168.1.1 timeout 10s, 192.168.1.2 timeout 30s} \;}
匿名集合

匿名集合使用大括号表示,内部使用逗号划分元素,一旦规则被移除,该集合也会被移除,且集合中的内容不可变(除非删除再添加)。匿名集合不需要定义元素类型。下面几个使用匿名集合的例子。


$ nft add rule filter input ip saddr { 10.0.0.0/8, 192.168.0.0/16 } tcp dport { 22, 443 } accept

$ nft add rule ip6 filter input tcp dport {telnet, http, https} accept

$ nft add rule ip6 filter input icmpv6 type { nd-neighbor-solicit, echo-request, nd-router-advert, nd-neighbor-advert } accept
命名集合

命名集合可以在任意时间添加或移除元素,通过在名称前面使用@前缀来引用命名集合。命名集合需要定义元素的类型,然后再给出元素的值。


$ nft add set ip filter blackhole { type ipv4_addr\; comment \"drop all packets from these hosts\" \; }

$ nft add element ip filter blackhole { 192.168.3.4 } #添加元素

$ nft add element ip filter blackhole { 192.168.1.4, 192.168.1.5 } #添加元素

$ nft add rule ip filter input ip saddr @blackhole drop #引用命名集合

$ nft add rule ip filter output ip daddr != @blackhole accept

MAPS

  • add map [familytable map { type type | typeof expression [flags flags ;] [elements = { element[, ...] } ;] [size size ;] [comment comment ;] [policy 'policy ;] }

  • {delete | destroy | list | flushmap [familytable map

  • list maps [family]

KeywordDescriptionType
type定义Map元素的数据类型字符串: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark, counter, quota. 不能使用Counter 和 quota 作为keys
typeof定义Map元素的数据类型从表示式派生出的数据类型
flagsmap 标识string, same as set flags
elements定义map中的元素map数据类型
sizeMap的最大元素数目unsigned integer (64 bit)
policymap 策略字符串: performance [默认], memory
匿名map

如果端口是80,则DNAT到192.168.1.100,如果端口是8888,则DNAT到192.168.1.101


$ nft add rule ip nat prerouting dnat to tcp dport map { 80 : 192.168.1.100, 8888 : 192.168.1.101 }
命名map

$ nft add map nat porttoip { type inet_service: ipv4_addr\; }

$ nft add element nat porttoip { 80 : 192.168.1.100, 8888 : 192.168.1.101 }

TCP/80且源地址为192.168.1.100的出站报文会被SNAT为TCP/8888,地址为192.168.1.101


$ nft add rule ip nat postrouting snat to tcp dport map @porttoip

ELEMENTS

  • {add | create | delete | destroy | get } element [familytable set { ELEMENT[, ...] }

    ELEMENT := key_expression OPTIONS [: value_expression]
    OPTIONS := [timeout TIMESPEC] [expires TIMESPEC] [comment string]
    TIMESPEC := [numd][numh][numm][num[s]]

OptionDescription
timeoutsets/maps flag 中的timeout 值
expirestimeout开始的倒计时计数器,当数值为0时,会删除掉element
comment单个元素的注释字段

element命令用于修改命名集合和命名maps的内容。key_expression用于集合类型的值,value_expression用于map类型,表示map的数据部分。

Example

$ nft add table inet myfilter

$ nft add set inet myfilter myset {type ipv4_addr\; flags timeout\; }

$ nft add element inet myfilter myset {10.0.0.1 timeout 10s }

FLOWTABLES

Flowtables用于加速报文的转发,它可以绕过传统的转发路径。


userspace process

^ |

| |

_____|____ ____\/___

/ \ / \

| input | | output |

\__________/ \_________/

^ |

| |

_________ __________ --------- _____\/_____

/ \ / \ |Routing | / \

--> ingress ---> prerouting ---> |decision| | postrouting|--> neigh_xmit

\_________/ \__________/ ---------- \____________/ ^

| ^ | ^ |

flowtable | ____\/___ | |

| | / \ | |

__\/___ | | forward |------------ |

|-----| | \_________/ |

|-----| | 'flow offload' rule |

|-----| | adds entry to |

|_____| | flowtable |

| | |

/ \ | |

/hit\_no_| |

\ ? / |

\ / |

|__yes_________________fastpath bypass ____________________________|



Fig.1 Netfilter hooks and flowtable interactions

STATEFUL OBJECTS

可以使用"type name"来引用Statefulset object,如"counter name"、"quota name"、"limit name"

COUNTER
  • add counter [family] table counter_name [{ [ packets packets bytes bytes ; ] [ comment comment ; }]

  • delete counter [familytable counter_name

  • list counters

计数器,统计报文总数和自上次重置以来所接收到的总字节数。需要明确指定统计的每个规则的计数器。

匿名counter

匿名counter只属于其所在的rule。下面匿名counter用于统计所有路由到本地的TCP流量:

table ip counter_demo {    chain IN {        type filter hook input priority filter; policy drop;         ip protocol tcp counter    }}
命名counter

$ nft add counter filter http

$ nft add rule filter input tcp dport 80 counter name \"http\"

在map中使用counter:


$ nft add counter filter http

$ nft add counter filter https

$ nft add rule filter input counter name tcp dport map { 80 : \"http\", 443 : \"https\" }

重置counter:


$ nft reset counter filter http
Quotas
  • add quota [familytable name { [over|untilbytes BYTE_UNIT [ used bytes BYTE_UNIT ] ; [ comment comment ; ] }

  • BYTE_UNIT := bytes | kbytes | mbytes

  • delete quota [family] table name

  • list quotas

KeywordDescriptionType
quota配额限制,作为配额名称两个参数:unsigned integer (64 bit) 和 字符串: bytes, kbytes, mbytes。在这些参数前面加上"over" 和 "until"
used一开始使用的配额值两个参数:unsigned integer (64 bit) 和 字符串: bytes, kbytes, mbytes
comment每个quota的注释字符串

配额,用于定义:

  1. 字节数上限

  2. 设置初始的字节数(默认0字节)

  3. 计算从初始字节数开始接收到的总字节数,直到字节数达到或超过上限。

匿名Quota

下面配置要求到端口udp/5060的数据量不超过100 mbytes。

table inet anon_quota_demo {    chain IN {        type filter hook input priority filter; policy drop;         udp dport 5060 quota until 100 mbytes accept    }}
命名Quota

下面定义了一对quota,并在chain IN中引用了这两个quotas。

  • 到端口udp/5060的数据不超过100 mbytes,并丢弃其余到该端口的报文;

  • 到端口tcp/80的数据不超过500 mbytes,,并丢弃其余到该端口的报文;

  • tcp/443 (https)的报文不设限;

  • 丢弃其余报文(policy drop)

table inet quota_demo {   quota q_until_sip { until 100 mbytes used 0 bytes }   quota q_over_http { over  500 mbytes ; comment "cap http (but not https)" ; }    chain IN {       type filter hook input priority filter; policy drop;       udp dport 5060 quota name "q_until_sip" accept      tcp dport 80 quota name "q_over_http" drop      tcp dport { 80, 443 } accept   }}

下面是在map中引用quota的例子


$ nft add quota filter user123 { over 20 mbytes }

$ nft add quota filter user124 { over 20 mbytes }

$ nft add rule filter input quota name ip saddr map { 192.168.10.123 : \"user123\", 192.168.10.124 : \"user124\" }
Limits

使用token bucket进行限流。

匿名limits

下面限制每秒最多10个ICMP echo-request报文


$ nft add rule filter input icmp type echo-request limit rate 10/second accept
命名limits

下面定义了两个limits,分别为:

  • 接收所有类型的icmp报文,限制最大速率为400 packets / minute.

  • 接收到端口 tcp/25 (smtp)的流量,最大速率为 1024 bytes / second,可接收的最大突发流量为512 bytes

  • 丢弃其他流量(policy drop)

table inet limit_demo {    limit lim_400ppm { rate 400/minute ; comment "use to limit incoming icmp" ; }   limit lim_1kbps  { rate over 1024 bytes/second burst 512 bytes ; comment "use to limit incoming smtp" ; }    chain IN {       type filter hook input priority filter; policy drop;       meta l4proto icmp limit name "lim_400ppm" accept      tcp dport 25 limit name "lim_1kbps" accept   }}
Others
  • Conntrack helpers (ct helper, Layer 7 ALG)

  • Conntrack timeout policies (ct timeout)

  • Conntrack expectations (ct expectation)

数据类型

EXPRESSIONS

PRIMARY EXPRESSIONS

expression用于匹配报文。

primary expression是最低阶的表达式,表示来自报文的payload、元数据或有状态模块的常量单个数据

下面仅列出了部分expressions。

META EXPRESSIONS
  • meta {length | nfproto | l4proto | protocol | priority}

  • [meta] {mark | iif | iifname | iiftype | oif | oifname | oiftype | skuid | skgid | nftrace | rtclassid | ibrname | obrname | pkttype | cpu | iifgroup | oifgroup | cgroup | random | ipsec | iifkind | oifkind | time | hour | day }

从上面看出,元数据有很多种,每种元数据都对应特定的类型。这里根据元数据的类型进行了划分。

meta expression指与报文有关的元数据。

meta expressions有两种:unqualified 和 qualified meta expressions,区别就是有没有meta关键字:


# qualified meta expression

filter output meta oif eth0

filter forward meta iifkind { "tun", "veth" }



# unqualified meta expression

filter output oif eth0
ROUTING EXPRESSIONS
  • rt [ip | ip6] {classid | nexthop | mtu | ipsec}

KeywordDescriptionType
classidRouting realmrealm
nexthopRouting nexthopipv4_addr/ipv6_addr
mtuTCP maximum segment size of routeinteger (16 bit)
ipsecroute via ipsec tunnel or transportboolean

routeing expression指与报文有关的路由数据:


# IP family independent rt expression

filter output rt classid 10



# IP family dependent rt expressions

ip filter output rt nexthop 192.168.0.1

ip6 filter output rt nexthop fd00::1

inet filter output rt ip nexthop 192.168.0.1

inet filter output rt ip6 nexthop fd00::1



# outgoing packet will be encapsulated/encrypted by ipsec

filter output rt ipsec exists
NUMGEN EXPRESSION
  • numgen {inc | random} mod NUM [ offset NUM ]

生成一个数字,inc 或 random 用于控制其操作模式,inc模式下,最后的返回值会简单递增,而random模式下,会返回一个随机数。mod用于执行取模操作,可选的offset可以让返回值加上一个固定的偏移量。

numgen通常用于负载均衡:


# round-robin between 192.168.10.100 and 192.168.20.200:

add rule nat prerouting dnat to numgen inc mod 2 map \

{ 0 : 192.168.10.100, 1 : 192.168.20.200 }



# probability-based with odd bias using intervals:

add rule nat prerouting dnat to numgen random mod 10 map \

{ 0-2 : 192.168.10.100, 3-9 : 192.168.20.200 }
HASH EXPRESSIONS
  • jhash {ip saddr | ip6 daddr | tcp dport | udp sport | ether saddr} [. ...] mod NUM [ seed NUM ] [ offset NUM ]

  • symhash mod NUM [ offset NUM ]

使用哈希函数来生成一个数字,可用的哈希函数为jhash(Jenkins hash),symhash(Symmetric Hash)。jhash需要一个expression来确定哈希参数(报文首部),可以串联多个参数。mod用于执行取模操作,可选的seed执行了哈希函数的种子,可选的offset可以让返回值加上一个固定的偏移量。

jhashsymhash的通常用于负载均衡:


# load balance based on source ip between 2 ip addresses:

add rule nat prerouting dnat to jhash ip saddr mod 2 map \

{ 0 : 192.168.10.100, 1 : 192.168.20.200 }



# symmetric load balancing between 2 ip addresses:

add rule nat prerouting dnat to symhash mod 2 map \

{ 0 : 192.168.10.100, 1 : 192.168.20.200 }

PAYLOAD EXPRESSIONS

指来自报文payload的数据。下面给出常用报文的expressions。

ETHERNET HEADER EXPRESSION
  • ether {daddr | saddr | type}

KeywordDescriptionType
daddrDestination MAC addressether_addr
saddrSource MAC addressether_addr
typeEtherTypeether_type
VLAN HEADER EXPRESSION

除非接口配置了reorder_hdr off ,否则无法在 ipip6 和 inet family上生效。

  • vlan {id | dei | pcp | type}

KeywordDescriptionType
idVLAN ID (VID)integer (12 bit)
deiDrop Eligible Indicatorinteger (1 bit)
pcpPriority code pointinteger (3 bit)
typeEtherTypeether_type
IPV4 HEADER EXPRESSION
  • ip {version | hdrlength | dscp | ecn | length | id | frag-off | ttl | protocol | checksum | saddr | daddr }

KeywordDescriptionType
versionIP header version (4)integer (4 bit)
hdrlengthIP header length including optionsinteger (4 bit) FIXME scaling
dscpDifferentiated Services Code Pointdscp
ecnExplicit Congestion Notificationecn
lengthTotal packet lengthinteger (16 bit)
idIP IDinteger (16 bit)
frag-offFragment offsetinteger (16 bit)
ttlTime to liveinteger (8 bit)
protocolUpper layer protocolinet_proto
checksumIP header checksuminteger (16 bit)
saddrSource addressipv4_addr
daddrDestination addressipv4_addr
ICMP HEADER EXPRESSION
  • icmp {type | code | checksum | id | sequence | gateway | mtu}

当在inetbridgenetdev family中使用时,将导致对IPv4的隐式依赖。

KeywordDescriptionType
typeICMP type fieldicmp_type
codeICMP code fieldinteger (8 bit)
checksumICMP checksum fieldinteger (16 bit)
idID of echo request/responseinteger (16 bit)
sequencesequence number of echo request/responseinteger (16 bit)
gatewaygateway of redirectsinteger (32 bit)
mtuMTU of path MTU discoveryinteger (16 bit)
TCP HEADER EXPRESSION
  • tcp {sport | dport | sequence | ackseq | doff | reserved | flags | window | checksum | urgptr}

KeywordDescriptionType
sportSource portinet_service
dportDestination portinet_service
sequenceSequence numberinteger (32 bit)
ackseqAcknowledgement numberinteger (32 bit)
doffData offsetinteger (4 bit) FIXME scaling
reservedReserved areainteger (4 bit)
flagsTCP flagstcp_flag
windowWindowinteger (16 bit)
checksumChecksuminteger (16 bit)
urgptrUrgent pointerinteger (16 bit)
UDP HEADER EXPRESSION
  • udp {sport | dport | length | checksum}

KeywordDescriptionType
sportSource portinet_service
dportDestination portinet_service
lengthTotal packet lengthinteger (16 bit)
checksumChecksuminteger (16 bit)
EXTENSION HEADER EXPRESSIONS

指与协议首部有关的扩展字段,如IPv6扩展首部,TCP选项和IPv4选项。

CONNTRACK EXPRESSIONS
  • ct {state | direction | status | mark | expiration | helper | label | count | id}

  • ct [original | reply] {l3proto | protocol | bytes | packets | avgpkt | zone}

  • ct {original | reply} {proto-src | proto-dst}

  • ct {original | reply} {ip | ip6} {saddr | daddr}

用于匹配报文的连接元数据

STATEMENTS

Statements表示需要执行的动作,可以是变更控制流(return、jump到另一个chain、accept或drop报文)或执行动作,如logging、拒绝报文等等。

下面给出了部分主要的statements。

VERDICT STATEMENT

  • {accept | drop | queue | continue | return}

  • {jump | goto} chain

verdict statement 用于修改ruleset中的控制流,并确定报文策略。

accept 和drop都属于 绝对verdicts

accept结束ruleset评估并接收报文。
drop结束ruleset评估,并丢弃报文。drop是立即执行的,不再评估后续的chains或hooks,因此无法在该后续的chain中accept报文
queue结束ruleset评估,并将报文传给用户空间队列中。用户空间必须提供一个drop或accept的verdict statement 。在accept的情况下,会在下一个base chain hook中继续处理报文,而不是跟在queue verdict中的规则中处理。
continue使用下一个规则继续评估ruleset,如果一条规则没有指定verdict statement ,则默认使用该statement。
return从当前chain中返回,并继续使用下一个chain中的规则进行评估,如果执行该statement的是一个base chain, 则它相当于一个base chain policy.
jump chain继续在 chain的第一条规则中进行评估,ruleset的当前位置会被push到一个调用栈中,并在新的chain评估结束或执行了return 之后返回到之前的位置。如果chain中的某个规则执行了绝对VERDICT,则将立即终止对ruleset的评估,并采取响应的操作。
goto chain类似 jump,但不会将当前位置push到调用栈,意味着在新chain评估结束之后会继续执行下一个chain,而不会返回之前的位置。
Example

# process packets from eth0 and the internal network in from_lan

# chain, drop all packets from eth0 with different source addresses.



filter input iif eth0 ip saddr 192.168.0.0/24 jump from_lan

filter input iif eth0 drop

REJECT STATEMENT

  • reject [ with REJECT_WITH ]

    REJECT_WITH := icmp icmp_code |
    icmpv6 icmpv6_code |
    icmpx icmpx_code |
    tcp reset

拒绝匹配到的报文,并返回错误。默认的错误为port-unreachable。只能用于 inputforward 或 output hooks

LOG STATEMENT

  • log [prefix quoted_string] [level syslog-level] [flags log-flags]

  • log group nflog_group [prefix quoted_string] [queue-threshold value] [snaplen size]

  • log level audit

用于将匹配到的报文记录到内核日志中,可以使用dmesg(1) 读取日志或从 syslog中读取日志。当然也可以通过监听nflog_group将日志转发到用户空间。

COUNTER STATEMENT

设置匹配报文的字节数。

  • counter packets number bytes number

  • counter { packets number | bytes number }

MAP STATEMENT

  • expression map { MAP_ELEMENTS }

    MAP_ELEMENTS := MAP_ELEMENT [, MAP_ELEMENTS]
    MAP_ELEMENT := key : value

map statement用于根据特定的key查找数据,key通常是一个expression的返回值。


# select DNAT target based on TCP dport,key为dport

# connections to port 80 are redirected to 192.168.1.100,

# connections to port 8888 are redirected to 192.168.1.101

nft add rule ip nat prerouting dnat tcp dport map { 80 : 192.168.1.100, 8888 : 192.168.1.101 }



# source address based SNAT,key为saddr

# packets from net 192.168.1.0/24 will appear as originating from 10.0.0.1,

# packets from net 192.168.2.0/24 will appear as originating from 10.0.0.2

nft add rule ip nat postrouting snat to ip saddr map { 192.168.1.0/24 : 10.0.0.1, 192.168.2.0/24 : 10.0.0.2 }

VMAP STATEMENT

  • expression vmap { VMAP_ELEMENTS }

    VMAP_ELEMENTS := VMAP_ELEMENT [, VMAP_ELEMENTS]
    VMAP_ELEMENT := key : verdict

vmap statement和map statement类似,但包含一个verdicts字段


# jump to different chains depending on layer 4 protocol type:

$ nft add rule ip filter input ip protocol vmap { tcp : jump tcp-chain, udp : jump udp-chain , icmp : jump icmp-chain }

NAT STATEMENTS

  • snat [[ip | ip6] [ prefix ] to] ADDR_SPEC [:PORT_SPEC] [FLAGS]

  • dnat [[ip | ip6] [ prefix ] to] ADDR_SPEC [:PORT_SPEC] [FLAGS]

  • masquerade [to :PORT_SPEC] [FLAGS]

  • redirect [to :PORT_SPEC] [FLAGS]

    ADDR_SPEC := address | address - address
    PORT_SPEC := port | port - port

    FLAGS := FLAG [, FLAGS]
    FLAG := persistent | random | fully-random

nat statement仅适用于nat 类型的chain。

snat 和 masquerade statements都会修改报文的源地址。snat只能用在postrouting和input chain,masquerade只能用在postrouting chain。dnat 和 redirect statements只能用在prerouting和output chain,用于修改报文的目的地址。

masquerade statement是一种特殊的snat,用于将报文的源地址转换为出接口的IP地址。特别适用于使用动态IP地址的网关。

redirect statement是一种特殊的dnat,将目的地址转换为本地主机地址。如果只想更改不同接口上传入流量的目的端口,就可以使用该statement。

在内核4.18之前,nat statement要求同时有prerouting和postrouting base chain,否则netfilter将看不到返回路径上的数据包,因此不会反向转换地址。

ExpressionDescriptionType
address指定要修改的报文的源/目的地址,可以指定一个mapping,包含由任意expression key与地址值组合的列表。ipv4_addr, ipv6_addr, 如 abcd::1234, 或使用mapping,如 meta mark map
port指定要修改的报文的源/目的端口端口号 (16 bit)
基本用法

# create a suitable table/chain setup for all further examples

add table nat

add chain nat prerouting { type nat hook prerouting priority dstnat; }

add chain nat postrouting { type nat hook postrouting priority srcnat; }



# translate source addresses of all packets leaving via eth0 to address 1.2.3.4

add rule nat postrouting oif eth0 snat to 1.2.3.4



# redirect all traffic entering via eth0 to destination address 192.168.1.120

add rule nat prerouting iif eth0 dnat to 192.168.1.120



# translate source addresses of all packets leaving via eth0 to whatever

# locally generated packets would use as source to reach the same destination

add rule nat postrouting oif eth0 masquerade



# redirect incoming TCP traffic for port 22 to port 2222

add rule nat prerouting tcp dport 22 redirect to :2222



# inet family:

# handle ip dnat:

add rule inet nat prerouting dnat ip to 10.0.2.99

# handle ip6 dnat:

add rule inet nat prerouting dnat ip6 to fe80::dead

# this masquerades both ipv4 and ipv6:

add rule inet nat postrouting meta oif ppp0 masquerade
高级用法
# map prefixes in one network to that of another, e.g. 10.141.11.4 is mangled to 192.168.2.4,# 10.141.11.5 is mangled to 192.168.2.5 and so on.add rule nat postrouting snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 } # map a source address, source port combination to a pool of destination addresses and ports:add rule nat postrouting dnat to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.2-10.141.10.5 . 8888-8999 } # The above example generates the following NAT expression:## [ nat dnat ip addr_min reg 1 addr_max reg 10 proto_min reg 9 proto_max reg 11 ]## which expects to obtain the following tuple:# IP address (min), source port (min), IP address (max), source port (max)# to be obtained from the map. The given addresses and ports are inclusive. # This also works with named maps and in combination with both concatenations and ranges:table ip nat {        map ipportmap {                typeof ip saddr : interval ip daddr . tcp dport                flags interval                elements = { 192.168.1.2 : 10.141.10.1-10.141.10.3 . 8888-8999, 192.168.2.0/24 : 10.141.11.5-10.141.11.20 . 8888-8999 }        }         chain prerouting {                type nat hook prerouting priority dstnat; policy accept;                ip protocol tcp dnat ip to ip saddr map @ipportmap        }} # @ipportmap maps network prefixes to a range of hosts and ports.# The new destination is taken from the range provided by the map element.# Same for the destination port. # Note the use of the "interval" keyword in the typeof description.# This is required so nftables knows that it has to ask for twice the# amount of storage for each key-value pair in the map. # ": ipv4_addr . inet_service" would allow associating one address and one port# with each key.  But for this case, for each key, two addresses and two ports# (The minimum and maximum values for both) have to be stored.

MONITOR

  • monitor [new | destroy] MONITOR_OBJECT
    monitor trace

    MONITOR_OBJECT := tables | chains | sets | rules | elements | ruleset

Monitor 命令可以监听nf_tables子系统产生的Netlink事件。这些事件要么与对象的创建和删除有关,要么与启用meta nftrace的报文有关。这些事件将以JSON或原生的nft格式打印到stdout。

可以使用MONITOR_OBJECT过滤与具体对象有关的事件。

使用newdestroy来过滤与特定动作有关的事件。

第二种形式的调用没有选项,只打印启用nftrace的报文生成的事件。

启用nftrace

为了启用nftrace,只需要在规则之后跟上下面statement即可:


meta nftrace set 1

当然也可以为特定的报文启用nftrace,下面为tcp报文启用nftrace:


ip protocol tcp meta nftrace set 1
使用单独chain来启用nftrace

推荐使用单独的chain来启用nftrace,下面用于跟踪prerouting chain,如果有已经有一个prerouting chain,则需要确保trace_chain的优先级更高。


$ nft add chain filter trace_chain { type filter hook prerouting priority -301\; }

$ nft add rule filter trace_chain meta nftrace set 1

在调试结束之后,删除创建的trace_chain即可:


% nft delete chain filter trace_chain
monitor trace事件

在启用nftrace之后,就可以监控产生的跟踪事件:


#Listen to all events, report in native nft format.

% nft monitor



#Listen to deleted rules, report in JSON format.

% nft -j monitor destroy rules



#Listen to both new and destroyed chains, in native nft format.

% nft monitor chains



#Listen to ruleset events such as table, chain, rule, set, counters and quotas, in native nft format.

% nft monitor ruleset



#Trace incoming packets from host 10.0.0.1.

% nft add rule filter input ip saddr 10.0.0.1 meta nftrace set 1

% nft monitor trace

kubernetes中启用nftables

kubernetes v1.29中需要在kube-proxy中启用NFTablesProxyMode feature gate并指定mode为nftables时才能使用nftables。下面是一个使用kubeadm启动单节点集群的例子

apiVersion: kubeadm.k8s.io/v1beta3bootstrapTokens:- groups:  - system:bootstrappers:kubeadm:default-node-token  token: abcdef.0123456789abcdef  ttl: 24h0m0s  usages:  - signing  - authenticationkind: InitConfigurationnodeRegistration:  criSocket: unix:///var/run/containerd/containerd.sock  imagePullPolicy: IfNotPresent  name: node  taints: null---apiServer:  timeoutForControlPlane: 4m0sapiVersion: kubeadm.k8s.io/v1beta3certificatesDir: /etc/kubernetes/pkiclusterName: kubernetescontrollerManager: {}etcd:  local:    dataDir: /var/lib/etcdimageRepository: registry.k8s.iokind: ClusterConfigurationkubernetesVersion: 1.29.0networking:  dnsDomain: cluster.local  serviceSubnet: 10.96.0.0/12scheduler: {}---apiVersion: kubeproxy.config.k8s.io/v1alpha1kind: KubeProxyConfigurationfeatureGates:  NFTablesProxyMode: truemode: nftables


链接:https://www.cnblogs.com/charlieroro/p/17982707

(版权归原作者所有,侵删)

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
【JetBlue收购Spirit被判违反反垄断法】Frontier Airlines和Spirit Airlines宣布将合并!‘Blossoms Shanghai’: Wong Kar-wai’s Love Letter to His Hometown市区River North房源RN02 | 不收中介费/芝加哥唯一拥有360度无敌湖景露台/包含Streeterville区域“红色新闻兵”李振盛:用镜头记录文革历史 (不朽的记录)一文带你检查Kubernetes应用是否为最佳实践Winter Break Nearing, China Targets Illegal Student Competitions加拿大实习丨Nestlé开启数据类2024 Internship岗位精选SDE岗位 | Tesla、Apple、Warner Media公司岗位发布!从罗馬到纽约的十七天忆仙姿:致力义工留迹麻州一流公立学区,富豪名流聚居地,本周豪宅精选--Weston/Newton/Wellesley/Winchester使用kind搭建kubernetesJava 近期新闻:JHipster Blueprint、Jox Channel 库、Infinispan 15.0 候选版本Quarkus 开发基于 LangChain4j 的扩展,方便将 LLM 集成到 Quarkus 应用程序中Providing Long-Term Care for Shanghai’s Most Vulnerable Resident德勤咨询(US)面向大二同学开放Deloitte National Leadership Conference!市区River North房源RN05 | 不收中介费/包含Streeterville区域/西北芝大Downtown校区Kubernetes Gateway API 攻略:解锁集群流量服务新维度!The ‘Invisible’ Cleaners Keeping the Cities SpotlessDulwich College International tops IB results table in China长篇小说﹕纽约八年 (34) 谜底 (4)Kubernetes 配置Pod使用代理上网Kubernetes:kube-scheduler 源码分析Learning Curve: Young Teachers Strive as Class LeadersKubernetes高可用集群二进制部署v1.28.0版本【ERP全职Offer】Value Wholesaler录用Offer!|求职战报市区River North房源RN01 | 不收中介费/包含Streeterville区域CNCF 孵化 Strimzi 以简化 Kubernetes 上的Kafka起薪达28w美元!精品投行William Blair开放2025 Summer Internship既然有了Kubernetes,为什么还需要 Istio?【租房】Boston顶级设计公司Elkus Manfredi作品|免中介费申请|Ink Block高级公寓|人均$2500+CIBC/Jefferies/Northwestern Mutual开放海量实习岗位, 留学生快冲!Java连接kubernates集群最优雅的两种方式历史学家 “解放的悲剧”作者 冯克 Frank Dik?tter教授对廖碧兰“龙的女儿的日记”一书的评说hé bàng?hé bèng?
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。