How to match both UDP and TCP for given ports in one line with nftables

61

Solution 1

With a recent enough nftables, you can just write:

meta l4proto {tcp, udp} th dport 53 counter accept comment "accept DNS"

Actually, you can do even better:

set okports {
  type inet_proto . inet_service
  counter
  elements = {
    tcp . 22,  # SSH
    tcp . 53,  # DNS (TCP)
    udp . 53   # DNS (UDP)
}

And then:

meta l4proto . th dport @okports accept

You can also write domain instead of 53 if you prefer using port/service names (from /etc/services).

Solution 2

For the sake of telling it's possible (but probably not that useful), yes it's possible, using a recent enough nftables and a raw payload expression.

So for the inet (dual ip/ip6) table, you have to first filter the right level 4 protocol (here TCP=6 and UDP=17) using a set, then filter the port 53. That's handy, TCP and UDP have the same location for the destination port in their respective format. dport is expressed as the offset of the destination port in the TCP/UDP part of the packet: 16 bits, with a size of 16 bits as seen in the previous links. While tcp and udp can be used by their symbolic name, It appears that dns must be stated as 53 not dns, I can only imagine that's because dns/tcp and dns/udp (or domain see later) are in two different "protocol namespaces".

The resulting command is (additional single quotes or else escaping the double quotes is needed here):

# nft 'add rule inet filter input meta l4proto {tcp, udp} @th,16,16 53 counter accept comment "accept DNS"'

If you want it for IPv4 only, initialize the corresponding ip table and chains and replace inet with ip.

Please also note that almost the same is given as example in the 0.8.3 release notes and is now included in nft's man page, alas, that example doesn't work: dns and http have to be replaced with 53 and 80 (and anyway some distributions/versions might have required domain instead of dns).

Share:
61

Related videos on Youtube

Yu-an Kuo
Author by

Yu-an Kuo

Updated on September 18, 2022

Comments

  • Yu-an Kuo
    Yu-an Kuo over 1 year

    I wrote a function to show the midi event. MIDI input device send a note every 25ms. The uitextview refresh very very slowly after my app execute for a while.

    Does anyone know how to solve this? I want to update the UI after got the MIDI event.

    Thank you.

    func MyMIDIReadBlock(packetList: UnsafePointer<MIDIPacketList>, srcConnRefCon: UnsafeMutableRawPointer?) -> Swift.Void {
        let packets = packetList.pointee
    
        let packet:MIDIPacket = packets.packet
    
        var ap = UnsafeMutablePointer<MIDIPacket>.allocate(capacity: 1)
        ap.initialize(to:packet)
        var p = ap.pointee
        for _ in 0 ..< packets.numPackets {
            p = ap.pointee
            str_event = handle(p)
            //show_note_event(event:str_event)
    
    
            DispatchQueue.main.async{
                //self.current_note_index.text = self.str_event
                self.show_input_event.text.append(self.str_event)  //append string to uitextview
                let range = NSMakeRange(self.show_input_event.text.characters.count - 1, 1)
                self.show_input_event.scrollRangeToVisible(range)
    
            }
            ap = MIDIPacketNext(ap)
        }
    }
    
  • hayath786
    hayath786 about 4 years
    Is there any performance difference between the two original simple rules compared to this single complex rule?
  • A.B
    A.B about 4 years
    @scai probably not (ok it should be a little better). It's all compiled into bytecode in the end. Try nft --debug=netlink -a list ruleset