IPtables question for IPtables experts

Alright folks I am trying to employ better rate limiting on my DNS server. Now ive found quite a few things on the internet and amalgamated them together but Im having difficulty understanding them. Can someone walk me through this a bit more?

:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:DNS_DROP - [0:0]
:DYN_DROP - [0:0]

-A PREROUTING -i lo -j ACCEPT
-A PREROUTING -i eth0 -s <our.net.work.space>/21 -j ACCEPT
-A PREROUTING -m recent --rsource --update --seconds 86400 --name DYN_DROP_LIST -j DROP
-A PREROUTING -p udp -m udp --dport 53 -j DNS_DROP
-A PREROUTING -p tcp -m tcp --dport 53 -j DNS_DROP

-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -o eth0 -d <our.net.work.space>/21 -j ACCEPT
-A OUTPUT -m recent --rdest --update --seconds 86400 --name DYN_DROP_LIST -j DROP

## Permanent DNS drop list (ipset)
-A DNS_DROP -m set --match-set PERM_DNS_DROP src -j DROP

## DNS - UDP progressive rate limit
-A DNS_DROP -p udp -m hashlimit --hashlimit-above  1/sec --hashlimit-burst  5 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire  10000 --hashlimit-name DNS_LIMIT_UDP  -j DROP
-A DNS_DROP -p udp -m hashlimit --hashlimit-above 10/min --hashlimit-burst 10 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 120000 --hashlimit-name DNS_LIMIT_UDP2 -j DROP
-A DNS_DROP -p udp -m hashlimit --hashlimit-above  4/min --hashlimit-burst 15 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 240000 --hashlimit-name DNS_LIMIT_UDP3 -j DROP

## DNS - TCP progressive rate limit
-A DNS_DROP -p tcp -m hashlimit --hashlimit-above  6/sec --hashlimit-burst 30 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire  10000 --hashlimit-name DNS_LIMIT_TCP  -j DROP
-A DNS_DROP -p tcp -m hashlimit --hashlimit-above 60/min --hashlimit-burst 60 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 120000 --hashlimit-name DNS_LIMIT_TCP2 -j DROP
-A DNS_DROP -p tcp -m hashlimit --hashlimit-above 24/min --hashlimit-burst 90 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 240000 --hashlimit-name DNS_LIMIT_TCP3 -j DROP

## DNS - UDP & TCP root any/all query filter
-A DNS_DROP -p udp -m string --hex-string "|0000ff0001|" --algo bm --from 40 -j DYN_DROP
-A DNS_DROP -p tcp -m string --hex-string "|0000ff0001|" --algo bm --from 52 -j DYN_DROP

## Dynamic Drop List
-A DYN_DROP -m recent --rsource --set --name DYN_DROP_LIST -j DROP

So what are these?

:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:DNS_DROP - [0:0]
:DYN_DROP - [0:0]

Filter groups?

What is this section doing?

-A PREROUTING -i lo -j ACCEPT
-A PREROUTING -i eth0 -s <our.net.work.space>/21 -j ACCEPT
-A PREROUTING -m recent --rsource --update --seconds 86400 --name DYN_DROP_LIST -j DROP
-A PREROUTING -p udp -m udp --dport 53 -j DNS_DROP
-A PREROUTING -p tcp -m tcp --dport 53 -j DNS_DROP

-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -o eth0 -d <our.net.work.space>/21 -j ACCEPT
-A OUTPUT -m recent --rdest --update --seconds 86400 --name DYN_DROP_LIST -j DROP

The paste I found was just a paste. No explanation. You are expected to figure it out. If someone can help me decipher this I can discuss it in detail on my DNS rate limit and amplification attack prevention part of my posts on making your own DNS server but I gotta understand this better before I do

so this establishes a permanent drop list based on who smacks the rate limit too much?

Just bumping this. Hoping to get it answered

This graphic may help you visually see the flow of packets through iptables/netfilter. The bottommost layer in the graphic (the link layer) probably isn’t relevant for you currently if you’re not doing any interface bridging, so just look at the flow through the network layer and higher:

These are your chains and their default policies. Packets in your PREROUTING chain and OUTPUT chains will be accepted and allowed to pass through if they don’t match any rules.

Accepts incoming traffic from localhost or from your LAN without further analysis.

If traffic has been identified by your separate chain where you did all the hash ratelimiting checks and gets here:

(assuming the packet contents matched that hex pattern) it gets tagged with that DYN_DROP_LIST name, and that recent rule detects it here and drops it before it ever gets routed (since it’s in the PREROUTING chain).

If we get this far, send in DNS traffic on port 53 into your DNS_DROP chain where it get get tested for the ratelimits you have set up, and into the section I quoted above.

For outgoing traffic leaving your host, accept all traffic destined for localhost or for your LAN.

Same as above, drop outgoing traffic tagged with that DYN_DROP_LIST name.

I’m not 100% certain, but this looks like it’s filtering all your DDOS traffic that exceeds your defined ratelimit. It’s not getting the DYN_DROP_LIST flag set because it probably already did before iptables recognized it exceeding your limits.

1 Like

So all I need to add it to my exisiting IP tables rules is

?

I can exclude these since my stuff is already defined?

Got it so start with including this

and these

So include these

Exclude these as my LAN is already setup properly?

so keep this

and this?

A simple yes would suffice if im correct

Yes I believe that would work. In case I was a bit unclear earlier, a hypothetical bad packet received for the first time would make it all the way through the DNS_DROP chain and then jump to the DYN_DROP chain to get dropped via here:

Then the second time a packet comes in (within 86400 seconds) matching that source IP it gets dropped here:

The only other hitch I can think of is if you have default DROP policies on your PREROUTING or OUTPUT chains. If you do, you’ll need a rule in there somewhere allowing DNS traffic (-j ACCEPT), but you likely already have this in place if that’s true.

sweet sauce… im liking this Nuke It Gewdddd Attitude

1 Like

alright @FamousNerdMan

# Additionals DDoS Mitigation
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:DNS_DROP - [0:0]
:DYN_DROP - [0:0]

# Prerouting Chain Rules
-A PREROUTING -m recent --rsource --update --seconds 86400 --name DYN_DROP_LIST -j DROP
-A PREROUTING -p udp -m udp --dport 53 -j DNS_DROP
-A PREROUTING -p tcp -m tcp --dport 53 -j DNS_DROP

# Output Chain Rules
-A OUTPUT -m recent --rdest --update --seconds 86400 --name DYN_DROP_LIST -j DROP

## Permanent DNS drop list (ipset)
-A DNS_DROP -m set --match-set PERM_DNS_DROP src -j DROP

## DNS - UDP progressive rate limit
-A DNS_DROP -p udp -m hashlimit --hashlimit-above  1/sec --hashlimit-burst  5 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire  10000 --hashlimit-name DNS_LIMIT_UDP  -j DROP
-A DNS_DROP -p udp -m hashlimit --hashlimit-above 10/min --hashlimit-burst 10 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 120000 --hashlimit-name DNS_LIMIT_UDP2 -j DROP
-A DNS_DROP -p udp -m hashlimit --hashlimit-above  4/min --hashlimit-burst 15 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 240000 --hashlimit-name DNS_LIMIT_UDP3 -j DROP

## DNS - TCP progressive rate limit
-A DNS_DROP -p tcp -m hashlimit --hashlimit-above  6/sec --hashlimit-burst 30 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire  10000 --hashlimit-name DNS_LIMIT_TCP  -j DROP
-A DNS_DROP -p tcp -m hashlimit --hashlimit-above 60/min --hashlimit-burst 60 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 120000 --hashlimit-name DNS_LIMIT_TCP2 -j DROP
-A DNS_DROP -p tcp -m hashlimit --hashlimit-above 24/min --hashlimit-burst 90 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 240000 --hashlimit-name DNS_LIMIT_TCP3 -j DROP

## DNS - UDP & TCP root any/all query filter
-A DNS_DROP -p udp -m string --hex-string "|0000ff0001|" --algo bm --from 40 -j DYN_DROP
-A DNS_DROP -p tcp -m string --hex-string "|0000ff0001|" --algo bm --from 52 -j DYN_DROP

## Dynamic Drop List
-A DYN_DROP -m recent --rsource --set --name DYN_DROP_LIST -j DROP

Is that looking cleaner?

Yep looks good to me. Let me know how it works out!

sweet sauce im deploying it soon ™

restore error on line 101

Hmmmmm

iptables-restore -vvv iptables
# Generated by iptables-save v1.8.7 on Sun Jan 23 11:15:14 2022
Flushing chain `PREROUTING'
Flushing chain `INPUT'
Flushing chain `OUTPUT'
Flushing chain `POSTROUTING'
Flushing chain `DOCKER'
Deleting chain `DOCKER'
# Completed on Sun Jan 23 11:15:14 2022
# Generated by iptables-save v1.8.7 on Sun Jan 23 11:15:14 2022
Flushing chain `PREROUTING'
Flushing chain `INPUT'
Flushing chain `FORWARD'
Flushing chain `OUTPUT'
Flushing chain `POSTROUTING'
# Completed on Sun Jan 23 11:15:14 2022
# Generated by iptables-save v1.8.7 on Sun Jan 23 11:15:14 2022
Flushing chain `PREROUTING'
Flushing chain `OUTPUT'
# Completed on Sun Jan 23 11:15:14 2022
# Generated by iptables-save v1.8.7 on Sun Jan 23 11:15:14 2022
Flushing chain `INPUT'
Flushing chain `FORWARD'
Flushing chain `OUTPUT'
# Completed on Sun Jan 23 11:15:14 2022
# Generated by iptables-save v1.8.7 on Sun Jan 23 11:15:14 2022
Flushing chain `INPUT'
Flushing chain `FORWARD'
Flushing chain `OUTPUT'
Flushing chain `DOCKER'
Flushing chain `DOCKER-ISOLATION-STAGE-1'
Flushing chain `DOCKER-ISOLATION-STAGE-2'
Flushing chain `DOCKER-USER'
Deleting chain `DOCKER'
Deleting chain `DOCKER-ISOLATION-STAGE-1'
Deleting chain `DOCKER-ISOLATION-STAGE-2'
Deleting chain `DOCKER-USER'
# Completed on Sun Jan 23 11:15:14 2022
# Additionals DDoS Mitigation
iptables-restore: line 101 failed

I probably did something retarded. Ill check the flow chart

I think you can probably remove these two lines. They are likely already defined in your set of rules.

Yeah those arent allowed there. But wait? would the prerouting and handling still be done properly?

I might have to toss these in the *NAT section to get them to take

The bottom link layer isn’t applicable here unless you’re doing interface bridging. The prerouting chain is running before it gets to your red box above. You’ll need to also make sure your INPUT and OUTPUT chains are allowing through all port 53 traffic by one of the following ways:

  1. Your INPUT chain has a default policy of ACCEPT and you don’t have any rules blocking port 53 traffic
  2. Your INPUT chain has a default policy of DROP and you do have explicit rules for allowing port 53 traffic.

It should be ok to allow at this point because once it’s made it past prerouting, you know it’s good and legitimate incoming DNS traffic.

Same goes for your OUTPUT chain, so responses get back out to the internet.

yeah so the input chains are there but my output is not filtered… Its ACCEPT ALL

-A INPUT -p udp -m udp --dport 53 -j LOG
-A INPUT -p tcp -m tcp --dport 53 -j LOG

So what I need to do is move

:DNS_DROP - [0:0]
:DYN_DROP - [0:0]

To the top of the NAT section before it mangles and filters?

Then call the Chains in the filter section?

and place the rules?

Because mind you there are already chains and other stuff in the file

I think the :DNS_DROP and :DYN_DROP should be right below *filter with all the other rule chains, and the rules on those chains also in the filter section.

Yes.

[root@bi-frost]/etc/sysconfig# iptables -v -t raw -L PREROUTING
Chain PREROUTING (policy ACCEPT 2170 packets, 254K bytes)
 pkts bytes target     prot opt in     out     source               destination         
   46  2944 DROP       all  --  any    any     anywhere             anywhere             recent: UPDATE seconds: 86400 name: DYN_DROP_LIST side: source mask: 255.255.255.255
  833 49610 DNS_DROP   udp  --  any    any     anywhere             anywhere             udp dpt:domain
    0     0 DNS_DROP   tcp  --  any    any     anywhere             anywhere             tcp dpt:domain
[root@bi-frost]/etc/sysconfig# iptables -v -t raw -L PREROUTING
Chain PREROUTING (policy ACCEPT 2219 packets, 258K bytes)
 pkts bytes target     prot opt in     out     source               destination         
   47  3008 DROP       all  --  any    any     anywhere             anywhere             recent: UPDATE seconds: 86400 name: DYN_DROP_LIST side: source mask: 255.255.255.255
  876 52183 DNS_DROP   udp  --  any    any     anywhere             anywhere             udp dpt:domain
    0     0 DNS_DROP   tcp  --  any    any     anywhere             anywhere             tcp dpt:domain
[root@bi-frost]/etc/sysconfig# iptables -v -t raw -L PREROUTING
Chain PREROUTING (policy ACCEPT 2237 packets, 259K bytes)
 pkts bytes target     prot opt in     out     source               destination         
   48  3072 DROP       all  --  any    any     anywhere             anywhere             recent: UPDATE seconds: 86400 name: DYN_DROP_LIST side: source mask: 255.255.255.255
  883 52596 DNS_DROP   udp  --  any    any     anywhere             anywhere             udp dpt:domain
    0     0 DNS_DROP   tcp  --  any    any     anywhere             anywhere             tcp dpt:domain
[root@bi-frost]/etc/sysconfig# iptables -v -t raw -L PREROUTING
Chain PREROUTING (policy ACCEPT 2280 packets, 266K bytes)
 pkts bytes target     prot opt in     out     source               destination         
   48  3072 DROP       all  --  any    any     anywhere             anywhere             recent: UPDATE seconds: 86400 name: DYN_DROP_LIST side: source mask: 255.255.255.255
  897 53422 DNS_DROP   udp  --  any    any     anywhere             anywhere             udp dpt:domain
    0     0 DNS_DROP   tcp  --  any    any     anywhere             anywhere             tcp dpt:domain
[root@bi-frost]/etc/sysconfig# iptables -v -t raw -L PREROUTING
Chain PREROUTING (policy ACCEPT 2306 packets, 269K bytes)
 pkts bytes target     prot opt in     out     source               destination         
   48  3072 DROP       all  --  any    any     anywhere             anywhere             recent: UPDATE seconds: 86400 name: DYN_DROP_LIST side: source mask: 255.255.255.255
  915 54496 DNS_DROP   udp  --  any    any     anywhere             anywhere             udp dpt:domain
    0     0 DNS_DROP   tcp  --  any    any     anywhere             anywhere             tcp dpt:domain
[root@bi-frost]/etc/sysconfig# iptables -v -t raw -L PREROUTING
Chain PREROUTING (policy ACCEPT 2339 packets, 276K bytes)
 pkts bytes target     prot opt in     out     source               destination         
   50  3200 DROP       all  --  any    any     anywhere             anywhere             recent: UPDATE seconds: 86400 name: DYN_DROP_LIST side: source mask: 255.255.255.255
  923 54968 DNS_DROP   udp  --  any    any     anywhere             anywhere             udp dpt:domain
    0     0 DNS_DROP   tcp  --  any    any     anywhere             anywhere             tcp dpt:domain
[root@bi-frost]/etc/sysconfig# iptables -v -t raw -L PREROUTING
Chain PREROUTING (policy ACCEPT 2376 packets, 280K bytes)
 pkts bytes target     prot opt in     out     source               destination         
   50  3200 DROP       all  --  any    any     anywhere             anywhere             recent: UPDATE seconds: 86400 name: DYN_DROP_LIST side: source mask: 255.255.255.255
  934 55617 DNS_DROP   udp  --  any    any     anywhere             anywhere             udp dpt:domain
    0     0 DNS_DROP   tcp  --  any    any     anywhere             anywhere             tcp dpt:domain
[root@bi-frost]/etc/sysconfig# iptables -v -t raw -L PREROUTING
Chain PREROUTING (policy ACCEPT 2403 packets, 282K bytes)
 pkts bytes target     prot opt in     out     source               destination         
   50  3200 DROP       all  --  any    any     anywhere             anywhere             recent: UPDATE seconds: 86400 name: DYN_DROP_LIST side: source mask: 255.255.255.255
  942 56089 DNS_DROP   udp  --  any    any     anywhere             anywhere             udp dpt:domain
    0     0 DNS_DROP   tcp  --  any    any     anywhere             anywhere             tcp dpt:domain


The work is slow but the DDoS is being mitigated

1 Like

image

They are getting rekt… HAH botnet 0 Doxxo 2

2 Likes

That’s really nice! Depending on how many different IPs they’re spamming you from, it might not be a bad idea to lengthen the 86400 seconds (1 day) timeout period if they just keep slamming you immediately after they get unbanned 1 day later.

good point. I was thinking of modifying the hash rates too

On average I get 2500 queries an hour. This is about the peak actually. SO what should I make these to say limit them more without hurting existing users?

-A DNS_DROP -p udp -m hashlimit --hashlimit-above  1/sec --hashlimit-burst  3 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire  10000 --hashlimit-name DNS_LIMIT_UDP  -j DROP
-A DNS_DROP -p udp -m hashlimit --hashlimit-above 10/min --hashlimit-burst 9 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 120000 --hashlimit-name DNS_LIMIT_UDP2 -j DROP
-A DNS_DROP -p udp -m hashlimit --hashlimit-above  4/min --hashlimit-burst 9 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 240000 --hashlimit-name DNS_LIMIT_UDP3 -j DROP
## DNS - TCP progressive rate limit

-A DNS_DROP -p tcp -m hashlimit --hashlimit-above  6/sec --hashlimit-burst 30 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire  10000 --hashlimit-name DNS_LIMIT_TCP  -j DROP
-A DNS_DROP -p tcp -m hashlimit --hashlimit-above 60/min --hashlimit-burst 60 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 120000 --hashlimit-name DNS_LIMIT_TCP2 -j DROP
-A DNS_DROP -p tcp -m hashlimit --hashlimit-above 24/min --hashlimit-burst 90 --hashlimit-mode srcip --hashlimit-srcmask 24 --hashlimit-htable-expire 240000 --hashlimit-name DNS_LIMIT_TCP3 -j DROP

It’s hard to say exactly - I’d probably wait until tomorrow at the earliest and possibly even a week from now to analyze your traffic and see how much you’re blocking vs. permitting, and make these sorts of decisions when you have more knowledge of your baseline data. I’m only an amateur network admin with a home server and segregated VLANs for guests and IoT devices, and others who do this stuff professionally may have more/better input here.

1 Like