Syn flood protection for FORWARD?

#!/bin/sh

#config Section
wan_device="" #setting a device between the quotation marks disable auto detection, "" autotection
	          #you can set more then one Wan interface with a comma between the device names for example "eth0,eth1"

bogon="0" #enable Bogon filter "1" enable "0" disable

forward_router="0.0.0.0" #Enter here the Ip address/network of the upstream router if you use the Bogon filter and have a forward router.
			     #You can add multiple ip addresses or networks with a comma betwen the addresses, network format at example 192.168.0.0/24
syn_flood="0"  #enable syn flood protection

icmp_flood="0" #enable icmp flood protection

udp_flood="0"  #enable udp flood protection

port_scan_detection="0"

syn_flood_limit="25" 	   #syn flood limit

syn_flood_burst_limit="50" #indicates the number of packets that can exceed the rate limit, must be greater than or equal to 1

icmp_flood_limit="15"      #icmp flood limit

icmp_flood_burst_limit="5" #indicates the number of packets that can exceed the rate limit, must be greater than or equal to 1

udp_flood_limit="100"       #udp flood limit

udp_flood_burst_limit="50" #indicates the number of packets that can exceed the rate limit, must be greater than or equal to 1

portscan_limit="50"         #sets the packet limit before the address is blocked

portscan_drop_time="5m"   #Sets the time limit in which the source of the port scan is blocked s=seconds m=minutes h=hours

portscan_src_ports="22" #remote ports for which portscan does not respond  

portscan_dst_ports="22" #target ports for which portscan does not respond

bogon_adresses="0.0.0.0/8, \
		10.0.0.0/8, \
		100.64.0.0/10, \
		127.0.0.0/8, \
		169.254.0.0/16, \
		172.16.0.0/12, \
		192.0.0.0/24, \
		192.0.2.0/24, \
		192.168.0.0/16, \
		198.18.0.0/15, \
		198.51.100.0/24, \
		203.0.113.0/24, \
		224.0.0.0/4, \
		240.0.0.0/4, \
		255.255.255.255/32"

bogon_ipv6_adresses="::/128, \
		     ::1/128, \
		     ::ffff:0:0/96, \
		     ::/96, \
		     100::/64, \
		     2001:10::/28, \
		     2001:db8::/32, \
		     fc00::/7, \
		     fe80::/10, \
		     fec0::/10, \
		     ff00::/8"

wan_input_drop_enable="0"       #Drops inet input to wan interface

wireguard_input_drop_enable="0" #Drops inet input to wireguard interface

reject_with_icmp="0"		#Reject Wan/Wireguard input with Icmp unreachable 

#config Section

verbose=false

if [ -z "$wan_device" ]; then

wan_device=$(uci get network.wan.device)

fi

nft list ruleset | grep -q 'netdev' && nft delete table netdev NETDEV && nft delete table inet DDOS
nft list ruleset | grep -q 'block_tcp_portscan' && nft delete table netdev block_tcp_portscan && nft delete table inet tcp_portscan

if [ $port_scan_detection -ge 1 ]; then
nft -f - <<TABLE
table netdev block_tcp_portscan {
        set enemies4 {
                type ipv4_addr
                flags dynamic,timeout
                timeout $portscan_drop_time
        }

        set enemies6 {
                type ipv6_addr
                flags dynamic,timeout
                timeout $portscan_drop_time
    }

    chain portscan_filter {
        type filter hook ingress devices = { $wan_device } priority -500;
	ip  saddr @enemies4  update @enemies4 { ip  saddr }  counter  drop  comment "Already known-bad, count it and drop"
        ip6 saddr @enemies6  update @enemies6 { ip6 saddr }  counter  drop  comment "Already known-bad, count it and drop"
meta pkttype unicast tcp flags fin,psh,urg / fin,psh,urg jump input_limit
meta pkttype unicast tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 jump input_limit

	}

     chain input_limit {
                limit rate $portscan_limit/second  counter  return
       	        update @enemies4 { ip  saddr } counter drop
                update @enemies6 { ip6 saddr } counter drop
     }
}
TABLE

nft -f - <<TABLE
table inet tcp_portscan {
          set enemies4 {
                  type ipv4_addr
                  flags dynamic,timeout
                 timeout $portscan_drop_time
         }

         set enemies6 {
                 type ipv6_addr
                 flags dynamic,timeout
                 timeout $portscan_drop_time

	}

    chain portscan_prerouting {

    ip  saddr @enemies4  update @enemies4 { ip  saddr }  counter  drop
    ip6 saddr @enemies6  update @enemies6 { ip6 saddr }  counter  drop
    type filter hook prerouting priority -160;
    iifname { $wan_device } ct state established,related counter accept
    iifname { $wan_device } tcp sport != { $portscan_src_ports } tcp flags syn,fin,ack th dport != { $portscan_dst_ports } jump input_limit

     }

    chain input_limit {
                 limit rate $portscan_limit/second  counter  return
                 update @enemies4 { ip  saddr } counter drop
                 update @enemies6 { ip6 saddr } counter drop

	}
}
TABLE
fi

if [[ $reject_with_icmp -ge 1 ]]; then
nft -f - <<TABLE
table inet DDOS {
	chain reject_drop {
	counter reject with icmp type port-unreachable
	counter reject with icmpv6 type port-unreachable
	counter drop
        }
    }
TABLE
else
nft -f - <<TABLE
table inet DDOS {
         chain reject_drop {
	 counter drop
         }
     }
TABLE
fi;

if [[ $syn_flood -ge 1 ]]; then
nft -f - <<TABLE
                 table netdev NETDEV {
		chain syn_flood {
		limit rate $syn_flood_limit/second burst $syn_flood_burst_limit packets return comment "Accept SYN packets below rate-limit"
		counter drop comment "Drop excess packets"
		}
}
TABLE
else
nft -f - <<TABLE
                  table netdev NETDEV {
                 chain syn_flood {
		return
		}
}
TABLE
fi;

if [[ $icmp_flood -ge 1 ]]; then
nft -f - <<TABLE
                 table netdev NETDEV {
		chain icmp_flood {
		limit rate $icmp_flood_limit/second burst $icmp_flood_burst_limit packets return
		counter drop comment "Drop excess packets"
	}
}
TABLE
else
nft -f - <<TABLE
                  table netdev NETDEV {
                 chain icmp_flood {
		 return
	}
}
TABLE
fi;

if [[ $udp_flood -ge 1 ]]; then
nft -f - <<TABLE
                 table inet DDOS {
		chain udp_flood {
		limit rate $udp_flood_limit/second burst $udp_flood_burst_limit packets return
		counter drop comment "Drop excess packets"
		}
}
TABLE
else
nft -f - <<TABLE
                  table inet DDOS {
                 chain udp_flood {
		return
		}
}
TABLE
fi;


nft -f - <<TABLE

		table netdev NETDEV {

  	  chain ingress {
        	type filter hook ingress devices = { $wan_device } priority -495;

		tcp flags syn / fin,syn,rst,ack jump syn_flood comment "!fw4: Rate limit TCP syn packets"

		ip protocol icmp icmp type {echo-reply, destination-unreachable, source-quench, redirect, echo-request, time-exceeded, parameter-problem, timestamp-request, timestamp-reply, info-request, info-reply, \
		 address-mask-request, address-mask-reply, router-advertisement, router-solicitation} jump icmp_flood

		ip protocol icmpv6 icmpv6 type {destination-unreachable, packet-too-big, time-exceeded, echo-request, echo-reply, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, \
		 nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect, parameter-problem, router-renumbering} jump icmp_flood

		tcp flags & (syn|rst) == (syn|rst) counter drop
		tcp flags syn,psh / syn,psh counter drop
		tcp flags ack,psh,rst / ack,psh,rst counter drop
		tcp flags ack,psh,rst,fin / ack,psh,rst,fin counter drop
		tcp flags ack,psh,rst,syn / ack,psh,rst,syn counter drop
		tcp flags ack,psh,rst,syn,fin / ack,psh,rst,syn,fin counter drop
		tcp flags ack,psh,syn / ack,psh,syn counter drop
		tcp flags ack,psh,syn,fin / ack,psh,syn,fin counter drop
		tcp flags ack,rst / ack,rst limit rate over 10/second counter drop
		tcp flags fin,psh / fin,psh limit rate over 10/second counter drop
		tcp flags ack,fin / ack,fin limit rate over 25/second counter drop
		tcp flags ack,rst,fin / ack,rst,fin counter drop
		tcp flags ack,rst,syn / ack,rst,syn counter drop
		tcp flags ack,rst,syn,fin / ack,rst,syn,fin counter drop
		tcp flags ack,syn,fin / ack,syn,fin counter drop
		tcp flags psh,rst,fin / psh,rst,fin counter drop
		tcp flags psh,rst,syn / psh,rst,syn counter drop
		tcp flags psh,rst,syn,fin / psh,rst,syn,fin counter drop
		tcp flags psh,syn,fin / psh,syn,fin counter drop
		tcp flags rst,fin / rst,fin counter drop
		tcp flags rst,syn,fin / rst,syn,fin counter drop
		tcp flags syn,fin / syn,fin counter drop
		tcp flags urg,ack / urg,ack counter drop
		tcp flags urg,ack,fin / urg,ack,fin counter drop
		tcp flags urg,ack,psh / urg,ack,psh counter drop
		tcp flags urg,ack,psh,fin / urg,ack,psh,fin counter drop
		tcp flags urg,ack,psh,rst / urg,ack,psh,rst counter drop
		tcp flags urg,ack,psh,rst,fin / urg,ack,psh,rst,fin counter drop
		tcp flags urg,ack,psh,syn / urg,ack,psh,syn counter drop
		tcp flags urg,ack,psh,syn,fin / urg,ack,psh,syn,fin counter drop
		tcp flags urg,ack,rst / urg,ack,rst counter drop
		tcp flags urg,ack,rst,fin / urg,ack,rst,fin counter drop
		tcp flags urg,ack,rst,syn / urg,ack,rst,syn counter drop
		tcp flags urg,ack,rst,syn,fin / urg,ack,rst,syn,fin counter drop
		tcp flags urg,ack,syn / urg,ack,syn counter drop
		tcp flags urg,ack,syn,fin / urg,ack,syn,fin counter drop
		tcp flags urg,fin / urg,fin counter drop
		tcp flags urg,psh / urg,psh counter drop
		tcp flags urg,psh,fin / urg,psh,fin counter drop
		tcp flags urg,psh,rst / urg,psh,rst counter drop
		tcp flags urg,psh,rst,fin / urg,psh,rst,fin counter drop
		tcp flags urg,psh,rst,syn / urg,psh,rst,syn counter drop
		tcp flags urg,psh,rst,syn,fin / urg,psh,rst,syn,fin counter drop
		tcp flags urg,psh,syn / urg,psh,syn counter drop
		tcp flags urg,psh,syn,fin / urg,psh,syn,fin counter drop
		tcp flags urg,rst / urg,rst counter drop
		tcp flags urg,rst,fin / urg,rst,fin counter drop
		tcp flags urg,rst,syn / urg,rst,syn counter drop
		tcp flags urg,rst,syn,fin / urg,rst,syn,fin counter drop
		tcp flags urg,syn / urg,syn counter drop
		tcp flags urg,syn,fin / urg,syn,fin counter drop

		# IP FRAGMENTS
		ip frag-off & 0x1fff != 0 counter drop

		# TCP NULL
		tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop

		# TCP MSS
		tcp flags syn \
			tcp option maxseg size 1-535 \
			counter drop

		}

}

     table inet DDOS {
	chain drop_ddos {
		type filter hook prerouting priority -155;

		# CT INVALID
		ct state invalid counter drop

		udp sport 1-65535 ct state new jump udp_flood

		# TCP SYN (CT NEW)
		tcp flags & (fin|syn|rst|ack) != syn \
			ct state new \
			counter drop

		ct state established, related counter accept

        }
    }
TABLE

if [ $wan_input_drop_enable -ge 1 ]; then

nft -f - <<TABLE

table inet DDOS {
	chain drop_ddos {
		type filter hook prerouting priority -155;

		iifname { $wan_device } goto reject_drop

        }
    }
TABLE

fi

if [ $wireguard_input_drop_enable -ge 1 ]; then

nft -f - <<TABLE

table inet DDOS {
	chain drop_ddos {
		type filter hook prerouting priority -155;

		iifname "Wg0" goto reject_drop
      }
   }
TABLE

fi

if [ $bogon -ge 1 ]; then

nft -f - <<TABLE

		table netdev NETDEV {

  	  chain ingress {
        	type filter hook ingress devices = { $wan_device } priority -495;

		ip saddr { $forward_router } counter accept

		ip saddr { $bogon_adresses } counter drop

		ip6 saddr { $bogon_ipv6_adresses } counter drop

}

      }

		table inet DDOS {

  	  chain drop_forward {
        	type filter hook forward priority filter -5;

        ip daddr { $forward_router } counter accept

	oifname { $wan_device } ip daddr { $bogon_adresses } counter reject with icmp type host-unreachable

	oifname { $wan_device } ip6 daddr { $bogon_ipv6_adresses } counter reject with icmpv6 type no-route

           }

	chain drop_postrouting {
                 type filter hook postrouting priority filter +5;

         ip daddr { $forward_router } counter accept


         oifname { $wan_device } ip daddr { $bogon_adresses } counter drop

	oifname { $wan_device } ip6 daddr { $bogon_ipv6_adresses } counter drop

         }

}

TABLE

fi

$verbose

exit 0

  • added a possibility to override the wan port detection simply write a device between the quotation marks at wan_device for example "eth0", so it is now also possible to use multiple wan ports for example "eth0,eth1"
  • under forward_router you can now enter several addresses/networks, for example "192.168.0.1, 192.168.1.1" or for the entire network "192.168.0.0/24, 192.168.1.0/24".