How to use dup in nftables to only mirror packets for specific port

I have begun using the following ruleset to duplicate packets for 2 clients (192.168.5.10 and 192.168.6.11) to a wireshark monitor (192.168.1.107)

table ip duper {
        chain input {
                type filter hook prerouting priority filter; policy accept;
                dup to ip daddr map { 192.168.5.10 : 192.168.1.107, 192.168.6.11 : 192.168.1.107 }
        }
}

However this is alot of traffic and mostly unrelated to what the monitor is setup for, I really only need to monitor traffic over a specific port (59900). How would I modify the ruleset to accomplish this?

Here is the full ruleset incase its necessary

table inet fw4 {
        chain input {
                type filter hook input priority filter; policy accept;
                iifname "lo" accept comment "!fw4: Accept traffic from loopback"
                ct state established,related accept comment "!fw4: Allow inbound established and related flows"
                tcp flags syn / fin,syn,rst,ack jump syn_flood comment "!fw4: Rate limit TCP syn packets"
                meta nfproto ipv4 iifname "br0" jump input_lan comment "!fw4: Handle lan IPv4 input traffic"
                meta nfproto ipv4 iifname "tun0" jump input_wan comment "!fw4: Handle wan IPv4 input traffic"
                meta nfproto ipv4 iifname "eth0.2" jump input_lan1 comment "!fw4: Handle lan1 IPv4 input traffic"
                meta nfproto ipv4 iifname "eth0.3" jump input_lan2 comment "!fw4: Handle lan2 IPv4 input traffic"
        }

        chain forward {
                type filter hook forward priority filter; policy drop;
                ct state established,related accept comment "!fw4: Allow forwarded established and related flows"
                meta nfproto ipv4 iifname "br0" jump forward_lan comment "!fw4: Handle lan IPv4 forward traffic"
                meta nfproto ipv4 iifname "tun0" jump forward_wan comment "!fw4: Handle wan IPv4 forward traffic"
                meta nfproto ipv4 iifname "eth0.2" jump forward_lan1 comment "!fw4: Handle lan1 IPv4 forward traffic"
                meta nfproto ipv4 iifname "eth0.3" jump forward_lan2 comment "!fw4: Handle lan2 IPv4 forward traffic"
                jump handle_reject
        }

        chain output {
                type filter hook output priority filter; policy accept;
                oifname "lo" accept comment "!fw4: Accept traffic towards loopback"
                ct state established,related accept comment "!fw4: Allow outbound established and related flows"
                meta nfproto ipv4 oifname "br0" jump output_lan comment "!fw4: Handle lan IPv4 output traffic"
                meta nfproto ipv4 oifname "tun0" jump output_wan comment "!fw4: Handle wan IPv4 output traffic"
                meta nfproto ipv4 oifname "eth0.2" jump output_lan1 comment "!fw4: Handle lan1 IPv4 output traffic"
                meta nfproto ipv4 oifname "eth0.3" jump output_lan2 comment "!fw4: Handle lan2 IPv4 output traffic"
        }

        chain prerouting {
                type filter hook prerouting priority filter; policy accept;
                meta nfproto ipv4 iifname "eth0.2" jump helper_lan1 comment "!fw4: Handle lan1 IPv4 helper assignment"
                meta nfproto ipv4 iifname "eth0.3" jump helper_lan2 comment "!fw4: Handle lan2 IPv4 helper assignment"
        }

        chain handle_reject {
                meta l4proto tcp reject with tcp reset comment "!fw4: Reject TCP traffic"
                reject comment "!fw4: Reject any other traffic"
        }

        chain syn_flood {
                limit rate 25/second burst 50 packets return comment "!fw4: Accept SYN packets below rate-limit"
                drop comment "!fw4: Drop excess packets"
        }

        chain input_lan {
                jump accept_from_lan
        }

        chain output_lan {
                jump accept_to_lan
        }

        chain forward_lan {
                jump accept_to_lan
        }

        chain accept_from_lan {
                meta nfproto ipv4 iifname "br0" counter packets 1120 bytes 121478 accept comment "!fw4: accept lan IPv4 traffic"
        }

        chain accept_to_lan {
                meta nfproto ipv4 oifname "br0" ct state invalid counter packets 10 bytes 400 drop comment "!fw4: Prevent NAT leakage"
                meta nfproto ipv4 oifname "br0" counter packets 227674 bytes 44098198 accept comment "!fw4: accept lan IPv4 traffic"
        }

        chain input_wan {
                jump reject_from_wan
        }

        chain output_wan {
                jump accept_to_wan
        }

        chain forward_wan {
                jump reject_to_wan
        }

        chain accept_to_wan {
                meta nfproto ipv4 oifname "tun0" ct state invalid counter packets 125 bytes 7291 drop comment "!fw4: Prevent NAT leakage"
                meta nfproto ipv4 oifname "tun0" counter packets 1130 bytes 117231 accept comment "!fw4: accept wan IPv4 traffic"
        }

        chain reject_from_wan {
                meta nfproto ipv4 iifname "tun0" counter packets 4 bytes 216 jump handle_reject comment "!fw4: reject wan IPv4 traffic"
        }

        chain reject_to_wan {
                meta nfproto ipv4 oifname "tun0" counter packets 0 bytes 0 jump handle_reject comment "!fw4: reject wan IPv4 traffic"
        }

        chain input_lan1 {
                jump accept_from_lan1
        }

        chain output_lan1 {
                jump accept_to_lan1
        }

        chain forward_lan1 {
                meta nfproto ipv4 jump accept_to_wan comment "!fw4: Accept lan1 to wan IPv4 forwarding"
                jump accept_to_lan1
        }

        chain helper_lan1 {
        }

        chain accept_from_lan1 {
                meta nfproto ipv4 iifname "eth0.2" counter packets 0 bytes 0 accept comment "!fw4: accept lan1 IPv4 traffic"
        }

        chain accept_to_lan1 {
                meta nfproto ipv4 oifname "eth0.2" counter packets 0 bytes 0 accept comment "!fw4: accept lan1 IPv4 traffic"
        }

        chain input_lan2 {
                jump accept_from_lan2
        }

        chain output_lan2 {
                jump accept_to_lan2
        }

        chain forward_lan2 {
                meta nfproto ipv4 jump accept_to_wan comment "!fw4: Accept lan2 to wan IPv4 forwarding"
                jump accept_to_lan2
        }

        chain helper_lan2 {
        }

        chain accept_from_lan2 {
                meta nfproto ipv4 iifname "eth0.3" counter packets 6 bytes 1008 accept comment "!fw4: accept lan2 IPv4 traffic"
        }

        chain accept_to_lan2 {
                meta nfproto ipv4 oifname "eth0.3" counter packets 2 bytes 658 accept comment "!fw4: accept lan2 IPv4 traffic"
        }

        chain dstnat {
                type nat hook prerouting priority dstnat; policy accept;
        }

        chain srcnat {
                type nat hook postrouting priority srcnat; policy accept;
                meta nfproto ipv4 oifname "br0" jump srcnat_lan comment "!fw4: Handle lan IPv4 srcnat traffic"
                meta nfproto ipv4 oifname "tun0" jump srcnat_wan comment "!fw4: Handle wan IPv4 srcnat traffic"
        }

        chain srcnat_lan {
                meta nfproto ipv4 masquerade comment "!fw4: Masquerade IPv4 lan traffic"
        }

        chain srcnat_wan {
                meta nfproto ipv4 masquerade comment "!fw4: Masquerade IPv4 wan traffic"
        }

        chain raw_prerouting {
                type filter hook prerouting priority raw; policy accept;
        }

        chain raw_output {
                type filter hook output priority raw; policy accept;
        }

        chain mangle_prerouting {
                type filter hook prerouting priority mangle; policy accept;
        }

        chain mangle_postrouting {
                type filter hook postrouting priority mangle; policy accept;
        }

        chain mangle_input {
                type filter hook input priority mangle; policy accept;
        }

        chain mangle_output {
                type route hook output priority mangle; policy accept;
        }

        chain mangle_forward {
                type filter hook forward priority mangle; policy accept;
                meta nfproto ipv4 iifname "br0" tcp flags syn tcp option maxseg size set rt mtu comment "!fw4: Zone lan IPv4 ingress MTU fixing"
                meta nfproto ipv4 oifname "br0" tcp flags syn tcp option maxseg size set rt mtu comment "!fw4: Zone lan IPv4 egress MTU fixing"
                meta nfproto ipv4 iifname "tun0" tcp flags syn tcp option maxseg size set rt mtu comment "!fw4: Zone wan IPv4 ingress MTU fixing"
                meta nfproto ipv4 oifname "tun0" tcp flags syn tcp option maxseg size set rt mtu comment "!fw4: Zone wan IPv4 egress MTU fixing"
        }
}
table ip duper {
        chain input {
                type filter hook prerouting priority filter; policy accept;
                dup to ip daddr map { 192.168.5.10 : 192.168.1.107, 192.168.6.11 : 192.168.1.107 }
        }
}

Problem solved

#!/usr/sbin/nft -f

table ip duper {
        chain input {
                type filter hook prerouting priority filter; policy accept;
                dup to ip daddr . udp dport map { 192.168.5.10 . 59900 : 192.168.1.107, 192.168.6.11 . 59900 : 192.168.1.107 }
        }
}
1 Like

You can also add udp dport 59900 before the dup.

2 Likes

like this?

#!/usr/sbin/nft -f

table ip duper {
        chain input {
                type filter hook prerouting priority filter; policy accept;
                udp dport 59900 dup to ip daddr map { 192.168.5.10 : 192.168.1.107, 192.168.6.11 : 192.168.1.107 }
        }
}
2 Likes

Yup, in general you can stack a bunch of expressions in front of a bunch of statements (so Dave's idea is to add a filtering expression before the dup statement, your solution was to simply concatenate the port into the map key, both are perfectly valid methods for accomplishing the same goal).

chain blah_blah {
    ip saddr 10.1.1.0/24   ip daddr 10.1.1.200   dport 22   counter   update @my_set { ip saddr }   reject
    ^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^   ^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^
    Expr1                  E2                    E3         Stmt1     S2                            S3

So, when

  1. The source address is in the range 10.1.1.0-10.1.1.255 AND
  2. The destination is exactly 10.1.1.200 AND
  3. The destination port is 22,

then

  1. Increment the "I've been triggered" counter for this rule,
  2. Put the source address into the set my_set,
  3. Send a reject back to the source and terminate processing of this packet.

If you look at your full table dump for hours and hours :joy:, you'll start to be able to pick out the parts of the compound expressions, likewise for the statement parts. It's just word soup the first hundred times, but it makes sense after a while. (That's why, when I write rules in scripts or posts like this, I put 2-3 spaces between each clause in each rule to help distinguish them.)

2 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.