With nftables it is possible to match multiple protocols within a single rule. The exact syntax to do this depends on the nftables release and kernel release; two different methods have been listed.
For recent releases of nftables the match condition syntax is (assuming the match should be for TCP and UDP):
<optional match conditions> meta l4proto { tcp, udp } th <match ports> \
<action>
Examples (these can be placed in the nftables configuration file):
meta l4proto { tcp, udp } th dport 53 \
accept \
comment "Permit TCP and UDP DNS requests (port 53)"
meta l4proto { tcp, udp } th sport 2500 \
accept \
comment "Permit TCP and UDP traffic sourced from port 2500"
meta l4proto { tcp, udp } th dport 5000 th sport 5500 \
accept \
comment "Permit TCP and UDP traffic to port 5000 sourced from port 5500"
ip saddr 192.0.2.1 meta l4proto { tcp, udp } th dport 443 \
accept \
comment "Permit TCP and UDP trafic inbound to port 443 (HTTPS) sourced from 192.0.2.1"
ip6 saddr 2001:db8::/32 meta l4proto { tcp, udp } th dport 443 \
accept \
comment "Permit TCP and UDP trafic inbound to port 443 (HTTPS) sourced from 2001:db8::/32"
For older releases of nftables the syntax is slightly different; the transport header offset must be defined. For IPv4, the fields are:
<optional match conditions> meta l4proto { tcp, udp } @th,16,16 <match ports> \
<action>
Examples (these can be placed in the nftables configuration file):
meta l4proto { tcp, udp } @th,16,16 dport 53 \
accept \
comment "Permit TCP and UDP DNS requests (port 53)"
meta l4proto { tcp, udp } @th,0,16 sport 2500 \
accept \
comment "Permit TCP and UDP traffic sourced from port 2500"
meta l4proto { tcp, udp } @th,16,16 5000 @th,0,16 5500 \
accept \
comment "Permit TCP and UDP traffic to port 5000 sourced from port 5500"
ip saddr 192.0.2.1 meta l4proto { tcp, udp } @th,16,16 dport 443 \
accept \
comment "Permit TCP and UDP trafic inbound to port 443 (HTTPS) sourced from 192.0.2.1"