nftables rate limiting per multiple seconds - nftables

I'm trying to convert some iptables rules to nftables
I want to make a rule that blocks a connection if there are more than 4 attempts in a 30 seconds time span
My original iptables rules are:
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 30 --hitcount 4 --rttl --name SSH -j DROP
How can I do the same (or equivelent) in nftables?

As far as I understand the iptables recent module does not have an equivalent in nftables, however, you should be able to achieve similar functionality using meters.
nft add rule ip filter INPUT tcp dport 22 ct state new meter SSHban { ip saddr and 255.255.255.255 limit rate over 8/minute burst 4 packets } counter drop
Documented here: https://wiki.nftables.org/wiki-nftables/index.php/Meters

I try months, can not find an exact match. But the I have a workaround.
sshPort=2222
nft add table ip sshGuard
nft add chain ip sshGuard input { type filter hook input priority 0 \; }
nft add set ip sshGuard denylist { type ipv4_addr \; flags dynamic, timeout \; timeout 5m \; }
nft add set ip sshGuard sshlist { type ipv4_addr \; flags dynamic, timeout \; timeout 5m \; }
nft add rule ip sshGuard input ct state established,related accept
nft add rule ip sshGuard input tcp dport $sshPort ct state new ip saddr #denylist reject
nft add rule ip sshGuard input tcp dport $sshPort ct state new ip saddr #sshlist add #denylist { ip saddr } accept
nft add rule ip sshGuard input tcp dport $sshPort ct state new limit rate over 2/minute burst 3 packets add #sshlist { ip saddr } counter accept
nft list table ip sshGuard
For a fresh state, around 5 connections will be accepted for any new IP. If the limit rate is hit, a new IP (not in sshlist) has 2 chances. For any IP in sshlist, only one chance left. And for any IP in denylist, any new connection will be rejected, until it is deleted from the denylist by its 5 minute timeout.

Related

How to mirror udp traffic between two hosts to a third remote k8s host in a readable manner?

Use case: Onpremise log server traffic need to be replicated to a cloud based log server.
What works : Device A can send logs to log Server B over UDP 514. Server B and cloud based log server C are reachable to each other but on different network. A GRE network tunnel is created between B and C to bring them in same network. So, traffic mirror from B to C works as below.
B # iptables -t mangle -I PREROUTING -i eth0 -p UDP --dport 514 -j TEE --gateway C.greIP
Challenge : Traffic received by C was actually destined for B hence getting dropped in C. There is a listener on UDP port 514 on C server binded to 0.0.0.0 however the log server of C does not see the logs.
It seems the UDP packets are getting dropped at C. What could be possible solution to handle non local ip traffic?
I have tried DNAT C # iptables -t nat -I PREROUTING -p UDP -d B --dport 514 -j DNAT --to-destination C:514 but it won't work. tcpdump on C shows packets are being received for non local IP and C # iptables -nvL -t nat shows that DNAT rule is getting matched.
Well, the same method which duplicated the packets from B to C worked on C.
Basically B duplicates the packets B # iptables -t mangle -I PREROUTING -i eth0 -p UDP --dport 514 -j TEE --gateway C.greIP and then once the packets are arrived in C, C can duplicate the packets to C # iptables -t mangle -I PREROUTING -i enlight -p udp -d B --dport 514 -j TEE --gateway C
This allowed the local process on C machine to handle duplicate udp syslog packets.

iptable rules for port forwarding and blocking

I would like to know your professional opinions on the following rule for iptables. I know it is possible to move cPanel's port but it's not so easy for WHM and some other services etc.
I needed something to route a new private port i.e. 1234 to the service while blocking the default port i.e. 2083. In my head, the following rule does this:
Marks the packets incoming on the private port
Redirects the packets to the actual port
Only accepts marked packets on the actual port
Note: The policies are defaulted to DROP all NEW connections
The rules below are working as expected, but before I go and get too excited that the job is done, I wanted a pro opinion on it first. The rules, and preceding context:
# Policy defaults
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD DROP
# Accept anything to/from localhost
iptables -A INPUT -i lo -j ACCEPT
# Accept anything established/related
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# --------------------------------------------------------------------
# Port forward and block (cPanel)
iptables -A PREROUTING -t mangle -p tcp --dport 1234 -j MARK --set-mark 0x400
iptables -A PREROUTING -t nat -p tcp --dport 1234 -j REDIRECT --to-ports 2083
iptables -A INPUT -p tcp --dport 2083 -m mark --mark 0x400/0x400 -m state --state NEW -j ACCEPT -m comment --comment "cPanel (Secure)"
Im no iptables wizzkid but it seems to work, Is this fairly secure?
Thanks in advance

Iptables Prevent Flooding

I know you can limit number of connections per ip, per time interval etc, but what I am wanting is amount of data.
I'm hosting a socket server, and I thought rather than making it do the processing to check for flooding - offload it to the firewall. I know you can guard against syn flooding attacks, like mentioned here:
http://www.cyberciti.biz/tips/howto-limit-linux-syn-attacks.html
For example:
# Limit the number of incoming tcp connections
# Interface 0 incoming syn-flood protection
iptables -N syn_flood
iptables -A INPUT -p tcp --syn -j syn_flood
iptables -A syn_flood -m limit --limit 1/s --limit-burst 3 -j RETURN
iptables -A syn_flood -j DROP
#Limiting the incoming icmp ping request:
iptables -A INPUT -p icmp -m limit --limit 1/s --limit-burst 1 -j ACCEPT
iptables -A INPUT -p icmp -m limit --limit 1/s --limit-burst 1 -j LOG --log-prefix PING-DROP:
iptables -A INPUT -p icmp -j DROP
iptables -A OUTPUT -p icmp -j ACCEPT
I'm not sure what iptables can do, so the question is a bit vague. But since web-sockets use tcp I should be able to limit number of bytes per second. And flag connections exceeding that limit or just drop them, whatever.
I can't seem to find a good reference on this, as they are all about tracking connections etc, not data transfer. Does anyone know of a good reference or how to do this? Is iptables not a good firewall for this? if not what is?
The kernel-side firewall is the fastest and the most secure software solution (difficult to kill the kernel isn't it?). Using it have also the advantage to use the hardware firewall found on some network controllers.
Iptables is the primary tool for controlling it, but there are many others frontends with easier syntax.
If you want to configure easier, you should use this :.
Keep in mind tracking byte count for each IP can use lot of memory.
In your case I would install ipset, which is developed by the same team of iptables :
#create ipset for accounting with default lifetime 300 secs
ipset create IP_QUOTA_SET hash:ip timeout 300 counters
#create separated rule chain
iptables --new-chain PER_IP_QOUTING
#send packets to chain
iptables -t filter -A INPUT \
-i <in-iface> --dst <ip> \
-p tcp --dport <dstport> \
-j PER_IP_QUOTING
#if ip doesn't exist in the set, add it
iptables -t filter -A PER_IP_QUOTING \
-m set ! --match-set IP_QUOTA_SET src \
-j SET --add-set IP_QUOTA_SET src --timeout 300
#if packet exists in the set, check bytes
#if byte counter > quota then drop packet
iptables -t filter -A PER_IP_QUOTING \
-m set --match-set IP_QUOTA_SET src \
--bytes-gr 1000 -j DROP
#pass other packets (for debug purpose)
iptables -t filter -A PER_IP_QUOTING \
-j RETURN
In this case you can check the list and edit it by ipset command.
To show current list with counters and timeouts :ipset list IP_QUOTA_SET.
STRONG NOTE : iptables is Linux specific and is available since linux 2.4. The kernel implementation along the userspace tools did change in 2.0 and 2.2 previously.
The 3.13 version introduced a new change which will replace ipset; arptables; ebtables; ip6tables, and iptables with a single tool.
As with previous versions, their will be a transition period where frontends like vuurmuur will remain compatible with the kernel, but don't expect to use iptables in the future.
You can try the iptable command mark together with tc (traffic-shaping):http://www.amiryan.org/2009/02/16/traffic-shaping-under-linux-with-tc-and-iptables/.

Iptable does not drop incoming or out going packets

I'm using CentOS.
I have done the following in my IPTable test environment. I have flushed all the rules, using
iptables -F
Then I have added the following rule.
iptables -I INPUT -p all -j ACCEPT
Then based on an observation, I have added the this rule;
iptables -A INPUT -s 192.168.2.50 -j DROP
I have run the
service iptable save
After that i tried to ping the blocked ip (192.168.2.50). I can still ping it and the blocked ip can ping me.
I want to block any incomming connection from blocked IP.
This is my output for iptables -L
Chain INPUT (policy DROP) target prot opt source destination
ACCEPT all -- anywhere anywhere
DROP all -- 192.168.2.50 anywhere
Chain FORWARD (policy DROP) target prot opt source destination
Chain OUTPUT (policy ACCEPT) target prot opt source destination
Chain icmp_packets (0 references) target prot opt source destination
Chain tcp_packets (0 references) target prot opt source destination
Please help.. Thanks..
Iptables works with chains of rules. Inside a chain, rules are applied to packets in order, from the first (at the top) to the last.
Your first rule ACCEPT all -- anywhere anywhere let all the packets going through the chain to be accepted, so they don't go further to the next rule which should drop all.
Thus, if you want just to drop ALL the traffic to your macchine, just remove your first rule with iptables -D INPUT 1 which will delete the first rule in the input chain, leaving only the drop all rule. Then add again the accept all rule with iptables -A INPUT -p all -j ACCEPT, so all the packets that are not from the blocked ip will be allowed to pass.
I think you should do
iptables -A INPUT -s 192.168.2.50 -j DROP
before iptables -I INPUT -p all -j ACCEPT.

Changing the incoming interface of the packet using iptables MARK and ip route commands

I was trying to change the incoming interface of the packet using iptables MARK and ip route commands.
I have tried this approach which suggests the use of iptable Mark and iproute2 utilities instead of ROUTE target, but could not find any success changing the incoming interface of the packet in the receiving path.
I have an application 'A' which binds to an interface intfA in linux i.e the application sends and receives packets only on via intfA.
Sending path
In a tunnel based setup, I was able to send packet's out from intfA to tap0 using the following iptable commands:
iptables -t mangle -A OUTPUT -d 8.9.10.11/32 -j MARK --set-mark 1
ip rule add fwmark 1 priority 9000 table 1
My default routing entry in main table is pointing to intfA
In table '1' I have made the default routing table entry point to tap0:
route add default dev tap0 table 1
I could observe from the kernel dmesg logs that the outgoing interface of the packet changed succesfully from intfA to tap0.
In the return path
After tap0 gets the encrypted packet from tunnel, it decrypts it and injects the plain text packet with destination 'a.b.c.d' into the linux kernel via the tap0 interface.
So at the kernel prerouting hook, I see the packet coming with IP = 'a.b.c.d' and with incoming tap0.
Following iptable rules were used to change the incoming interface:
iptables -t mangle -A PREROUTING -d a.b.c.d/32 -j MARK --set-mark 2
ip rule add fwmark 2 priority 8000 table 2
In table '2' I have made the default routing table entry point to intfA:
route add default dev intfA table 2
I tried to log the packets at the PREROUTING hook and the INPUT hook using the following iptable commands:
iptables -t mangle -A PREROUTING -d a.b.c.d/32 -j LOG --log-level 0 --log-prefix "VPN PREOUTING: "
iptables -t mangle -A INPUT -d a.b.c.d/32 -j LOG --log-level 0 --log-prefix "VPN INPUT: "
I was hoping the incoming interface of the packet to be changed from tap0 to intfA between the PREROUTING hook and INPUT hook. But suprisingly the interface doesn't change in both the kernel log trace. I could see the incoming packets marked with mark 2 as well.
From the dmesg log's i confirmed that the Incoming interface still remains as tap0 after the INPUT hook.
I wanted to understand the reason behind this behaviour for the iptables commands I have used. Not sure if I missed anything in iptables commands I used which is causing this issue.
I have the same problem. As a temporary solution I've found that -j TEE target helps:
iptables -t mangle -A PREROUTING [options] -j TEE --gateway IP
In your case, fill [options] and the gateway's IP (intfA address) with your values.