How can I block UDP connections from a specific IP using nftables?

icebowl

New Member
Joined
Jun 13, 2024
Messages
5
Reaction score
4
Credits
44
I am experimenting using nftables on a Raspberry Pi and a Debian 12 system.
I am able to block TCP IP addresses as follows:
ip saddr 192.168.1.98 counter packets 0 bytes 0 drop
The above will drop a TCP connections but not a UDP connection.

Can anyone explain how to block both?

Here is my current nttable.conf file (simple)

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
chain input {
type filter hook input priority 0;
ip protocol icmp counter accept comment "accept all ICMP types - this is a ping"
ip saddr 192.168.1.98 counter packets 0 bytes 0 drop
ip saddr 192.168.1.7 counter packets 0 bytes 0 drop
# accept any localhost traffic
iif lo accept

# accept traffic originated from us
ct state established,related accept

# activate the following line to accept common local services
tcp dport { 22, 80, 443} ct state new accept
udp dport {4711,25565,5353 ,59122 ,57324 ,631,19132 ,45091 } ct state new accept

# ICMPv6 packets which must not be dropped, see https://tools.ietf.org/html/rfc4890#section-4.4.1
meta nfproto ipv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-reply, echo-request, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, 148, 149 } accept
ip6 saddr fe80::/10 icmpv6 type { 130, 131, 132, 143, 151, 152, 153 } accept


# count and drop any other traffic
counter drop
}
#from gentoo
chain forward {
type filter hook forward priority 0; policy drop;
counter comment "count dropped packets"
}

# If you're not counting packets, this chain can be omitted.
chain output {
type filter hook output priority 0; policy accept;
counter comment "count accepted packets"
}
}
 


Isn't it just easier to have a default block/drop policy and only allow what you want to be open by using something like this in your input chain.
Code:
{ type filter hook input priority 0 ; policy drop ; }
 
To block both TCP and UDP connections originating from specific IP addresses using nftables, you need to add rules for both TCP and UDP in the input chain. Here's how you can modify your nftables configuration file to achieve that:

Code:
#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0;

        # Accept any localhost traffic
        iif lo accept comment "Accept loopback traffic"

        # Accept traffic originated from us
        ct state established,related accept

        # Accept common local services for TCP
        tcp dport { 22, 80, 443 } ct state new accept

        # Accept common local services for UDP
        udp dport { 4711, 25565, 5353, 59122, 57324, 631, 19132, 45091 } ct state new accept

        # Accept specific ICMPv6 packets
        meta nfproto ipv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-reply, echo-request, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, 148, 149 } accept
        ip6 saddr fe80::/10 icmpv6 type { 130, 131, 132, 143, 151, 152, 153 } accept

        # Accept all ICMP types (e.g., ping)
        ip protocol icmp accept comment "Accept all ICMP types - this is a ping"

        # Drop TCP connections from specified IP addresses
        ip saddr 192.168.1.98 tcp counter drop
        ip saddr 192.168.1.7 tcp counter drop

        # Drop UDP connections from specified IP addresses
        ip saddr 192.168.1.98 udp counter drop
        ip saddr 192.168.1.7 udp counter drop

        # Drop any other traffic
        counter drop
    }

    # Forward chain (dropping all forwarded packets)
    chain forward {
        type filter hook forward priority 0; policy drop;
        counter comment "Count dropped packets"
    }

    # Output chain (accepting all outgoing packets)
    chain output {
        type filter hook output priority 0; policy accept;
        counter comment "Count accepted packets"
    }
}


In this modified configuration:

I separated the rules for TCP and UDP connections from the specified IP addresses into distinct lines.

Each line specifies whether it's for TCP or UDP, ensuring both types of traffic are blocked from the specified IP addresses.

I maintained the other rules and chains in your configuration.

This should now effectively block both TCP and UDP connections from the specified IP addresses while allowing other traffic as per your configuration. Make sure to reload your nftables rules after making these changes.

NOTE: My LLM walked me through this. Test thoroughly before deploying in production.
 
Last edited:
@AlphaObeisance
You want loopback rule to be first for performance reasons.
This way for loopback traffic no other filtering is done prior hitting the rule.

I appreciate the clarification! I believe I've updated the config appropriately.
 
Thank you so much for all the posts. I've only been using nftables for a week now.

This solved the problem immediately:
Code:
{ type filter hook input priority 0 ; policy drop ; }

All these comments have been extremely helpful. I do have a bit (a lot) to learn.
An OG can learn new things.
Thanks again!
 
I have been able to block UDP and TCP ip addresses.
Now I am searching for ways to drop all UDP and TCP traffic and only accept a small list (1 to 4) of Ip addresses.
I've tried ct stat with no luck.

Code:
    ct state {established, related} accept
        ip saddr 10.12.0.10 ip daddr 10.1.0.2 drop
        ip saddr 10.1.0.2 ip daddr 10.12.0.10 accept

Please throw me a bone.
 
You need to set up rules in the input chain to drop all UDP and TCP traffic by default, and then selectively allow traffic from specific IP addresses.

Set the default policy of the input chain to drop all packets unless explicitly allowed:
Code:
policy drop;

Allow traffic on the loopback interface:
Code:
iif lo accept comment "Accept loopback traffic";

Accept traffic that is part of an established connection or related to one:
Code:
ct state established,related accept;

Allow TCP connections from specific IP addresses (10.1.0.2 and 10.12.0.10) on ports (22, 80, 443):
Code:
ip saddr { 10.1.0.2, 10.12.0.10 } tcp dport { 22, 80, 443 } ct state new accept;

Allow UDP connections from the same IP addresses on ports (4711, 25565):
Code:
ip saddr { 10.1.0.2, 10.12.0.10 } udp dport { 4711, 25565 } ct state new accept;

Drop All Other TCP and UDP Traffic:
Code:
ip protocol tcp counter drop;
ip protocol udp counter drop;
\

Drop any other traffic not explicitly allowed:
Code:
counter drop;

Make sure to adjust the IP addresses and port numbers to match your specific requirements. After configuring your nftables rules, reload them using nft -f your_config_file.conf and test thoroughly before deploying in a production environment.

Most of this should be directly applicable to the context of this conversation but I just woke up and responded over coffee so review the details thoroughly.

Should at least get you in the right direction anyway.
 

AlphaObeisance

Thank you so much. Your accept ip for udp and tcp worked perfect for my application. I am a retired teacher of 40 years. My last job was teaching introductory Cyber Security to High School students. I developed a unit on ethical hacking where I used Minecraft Pi . We used ufw in the past. The nftables script you sent me will be used for students to block people from populating the worlds using python code. Link to python code: https://gitlab.com/icebowl/mcpi-python. I am still involved with the CS program and will share the nftables code the members helped me with. Your documentation really helped.

Here is my script that works now to accept specific MineCraft Pi users.

Code:
#!/usr/sbin/nft -f

flush ruleset

table inet filter {
        chain input {
                type filter hook input priority 0; policy drop;
        iif lo accept comment "Accept loopback traffic";     
                ct state established,related accept;
                ip saddr { 192.168.1.98,192.168.1.7, 192.168.1.85 } tcp dport { 22, 80, 443 , 4711} ct state new accept;
                ip saddr { 192.168.1.98, 192.168.1.7  } udp dport {4711, 631, 19132, 57324, 59122,5353} ct state new accept;
                # minecraft pi udp ports 4711, 631, 19132, 57324, 59122,5353
                   ip protocol tcp counter drop;
                ip protocol udp counter drop;     
        counter drop;

        }

  # Forward chain (dropping all forwarded packets)
    chain forward {
        type filter hook forward priority 0; policy drop;
        counter comment "Count dropped packets"
    }

}
 
Last edited:
@icebowl
since the default policy is drop you do not need to manually drop TCP and UDP in your input chain.
When default is drop all you need is accept rules and no drop rules at all.

And forward chain is redundant, just delete it which is equal to drop by default.
Unless you need to forward traffic there is no need for forward chain.
 
It's important to allow 143/udp to pass either way because that's used by the Network Time Protocol.

Signed,

Matthew Campbell
 
NTP uses port 123 btw, and only outbound is needed if outbound is default block.
Oops, that's embarrassing. I read that wrong. It is 123. It's important to remember that UDP does not use connections so using a default input policy of block might prevent the responses from getting back in.

Signed,

Matthew Campbell
 
Oops, that's embarrassing. I read that wrong. It is 123. It's important to remember that UDP does not use connections so using a default input policy of block might prevent the responses from getting back in.

Signed,

Matthew Campbell

Trenix25, thanks for the post. How would this be coded?​


chain output {
type filter hook output priority 0; policy accept;
counter comment "Count accepted packets


# Accept common local services for UDP
udp dport { 123} ct state new accept


}
 
Last edited:

Trenix25, thanks for the post. How would this be coded?​


chain output {
type filter hook output priority 0; policy accept;
counter comment "Count accepted packets


# Accept common local services for UDP
udp dport { 123} ct state new accept


}
Mine uses a bash script so it looks a little different. NFT is defined as /usr/sbin/nft.

Code:
# Allow Network Time Protocol packets.

/usr/bin/echo "Allowing Network Time Protocol packets."

$NFT add rule ip filter4 input udp dport 123 accept
$NFT add rule ip6 filter6 input udp dport 123 accept
$NFT add rule ip filter4 output udp dport 123 accept
$NFT add rule ip6 filter6 output udp dport 123 accept

My filter4 table filters IPv4 traffic and my filter6 table filters IPv6 traffic.

Signed,

Matthew Campbell
 


Top