Community discussions

MikroTik App
 
zentavr
just joined
Topic Author
Posts: 20
Joined: Tue Nov 05, 2013 2:11 pm

[Advanced] Ban own DDoSed IPs using BGP Blackhole updates

Tue Dec 08, 2020 1:26 am

There is a wiki article, help article and a forum topic regarding how to detect DDoS attack. The problem is that if you have 1Gbps/1Gbps Tx/Rx pipe with your provider and ban someone at your router - that does not help much if someone strikes from the canon with 2G to your /32 of /24 network space.

As the solution - if you have a BGP peering with your upstream and it supports /32 blackhole announcements with the certain BGP communities - it can make your life easier by asking the upstream to block that traffic at their upstream routers.

The logic is the next:
1. have these IP/Firewall rules available
2. Install the BGP Helper which would ad/remove the anounces and add/remove Routing Filters.

The helper is here:
# (c) 2020 Andrii Miroshnychenko <zentavr@linet.zp.ua>
# 
# The script checks if there are any IP addresses of our blocks being DDoSed and if they do
# we update BGP networks and filters in order to notify our BGP peers to block the traffic.

:log warning "Starting BGP Blacklist Helper"

# The Black List name in IP->Firewall->Address List
:local addDisabled "yes"
:local appendBgpCommunities "65534:0,3326:666"
:local badIps [ :toarray "" ]
:local bgpNetworks [ :toarray "" ]
:local bgpNetworkList "Linet RIPE Networks"
:local blacklist "ddosed"
:local comment "linet-bgp-blocker"
:local filterChain "LINET-OWN-BLACKHOLE"
:local notifyAddress "noc@example.com"
:local myHostName [/system identity get name]
:local emailBody

# Maintaned addresses
:local bgpBannedIps [ :toarray "" ]
:local bgpRemovedIps [ :toarray "" ]

# Fetch all the IPs which we own from the address list
:foreach i in [ /ip firewall address-list find where list="$bgpNetworkList" disabled=no ] do={
    :log warning "... >$bgpNetworkList: Processing $i"
    :set $network [ /ip firewall address-list get value-name=address number=$i ]
    :set bgpNetworks ( $bgpNetworks, $network )
}

#:put $bgpNetworks

# Fetch the addresses from the address list
:foreach i in [ /ip firewall address-list find where list=$blacklist disabled=no ] do={
    :log warning "... Processing $i"
    :set $ip [ /ip firewall address-list get value-name=address number=$i ]
    :log warning "... IP address is: $ip"
    :set badIps ( $badIps, $ip )

#   Check if the IP is in the BGP Network anouncements
    :set $match false
    :foreach net in=$bgpNetworks do={
        :if ( $ip in $net ) do={
            :set $match true
        }
    }
    if ( ! $match ) do={
        :log warning "We should not add any anouncements to $ip"
    } else={
#       Set up BGP Advertised Network
        :if ( [ /routing bgp network find where network="$ip/32" comment="$comment" ] = "" ) do={
            :log warning "Adding $ip to routing/bgp/network list"
            /routing bgp network add network="$ip/32" disabled=$addDisabled synchronize=no comment="$comment"
            :set $bgpBannedIps ( $bgpBannedIps, $ip )
        } else={
            :log warning "$ip is already present in BGP Networks"
        }

#       Set up Routing Filter
        :if ( [ /routing filter find where chain=$filterChain prefix=$ip comment="$comment" ] = "" ) do={
            :log warning "Adding routing filter for $ip"
            /routing filter add chain=$filterChain prefix="$ip/32" comment="$comment" disabled=$addDisabled action=return append-bgp-communities=$appendBgpCommunities
        } else={
            :log warning "The routing filter for $ip exists"
        }
    }
}

#:log warning "$badIps"
#:put $badIps

# Cleaning the filters which are expired
:foreach f in [ /routing filter find where chain=$filterChain comment="$comment" ] do={
    :log warning "Inspecting routing filter $f"
    set $fPrefix [ /routing filter get value-name=prefix number=$f ]
    set $fComment [ /routing filter get value-name=comment number=$f ]
    set $fChain [ /routing filter get value-name=chain number=$f ]
    :if ( [:typeof [:find $fPrefix "/"]] = "nil" ) do={
        :log warning "    ... Prefix has no mask!"
        set $fIp $fPrefix
    } else={
        set $fIp [:pick $fPrefix 0 [:find $fPrefix "/"]]
    }

#   Processing
    :log warning "... prefix: $fPrefix. IP: $fIp, comment: $fComment, chain: $fChain"
    :if ( $fComment = $comment && $fChain = $filterChain ) do={
        :put "... checking if $f filter should be adjusted"
        :set $ipIsBanned [ :find $badIps $fIp ]

        :if ( [ :type $ipIsBanned ] = "nil" ) do={
            :log warning "... $fIp is NOT blacklisted. Removing the filter."
            :do {
                /routing filter remove numbers=$f
            } on-error={
                :log error "Caught an error while tried to remove $f routing filter"
            }
        } else={
            :log warning "... $fIp is still blacklisted"
        }
    } else={
        :log error "BGP Blacklist Helper: caught routing filter after the search which should not be there!!!"
    }
}

# Cleaning bgp networks which are expired
# A bug is present here. Despite we specify a comment in the search - all networks get returned
:foreach n in [ /routing bgp network find where comment="$comment" ] do={
    :log warning "Inspecting BGP Network $n"
    set $nNetwork [ /routing bgp network get value-name=network number=$n ]
    set $nComment [ /routing bgp network get value-name=comment number=$n ]
    set $nIp [:pick $nNetwork 0 [:find $nNetwork "/"]]

#   Processing
    :log warning "... network: $nNetwork, IP: $nIp, comment: $nComment"
    :if ( $nComment = $comment ) do={
        :put "... checking if $n bgp network should be adjusted"
        :set $ipIsBanned [ :find $badIps $nIp ]

        :if ( [ :type $ipIsBanned ] = "nil" ) do={
            :log warning "... $nIp is NOT blacklisted. Removing the network."
            :do {
                /routing bgp network remove numbers=$n
                :set $bgpRemovedIps ( $bgpRemovedIps, $nIp )
            } on-error={
                :log error "Caught an error while tried to remove $n bgp network"
            }
        } else={
            :log warning "... $nIp is still blacklisted"
        }
    } else={
        :log error "BGP Blacklist Helper: caught BGP network after the search which should not be there!!!"
    }
}

# Sending an email report
:if ([:len $bgpBannedIps] > 0 or [:len $bgpRemovedIps] > 0) do={
    :set $emailBody ("BGP Blacklist Helper did the modifications.\r\n")
    :set $emailBody ($emailBody."Date: $[/system clock get date] $[/system clock get time]\r\n")

#   Printing Banned IPs
    :if ( [:len $bgpBannedIps] > 0 ) do={
        :set $emailBody ($emailBody."\r\nBlacklisted the next addresses:\r\n")
        :foreach a in=$bgpBannedIps do={
            :set $emailBody ($emailBody."    - $a\r\n")
        }
        :set $emailBody ($emailBody."\r\n")
    }
#   Printing Whitelisted IPs
    :if ( [:len $bgpRemovedIps] > 0 ) do={
        :set $emailBody ($emailBody."\r\nRemoved from BGP blacklist the next addresses:\r\n")
        :foreach a in=$bgpRemovedIps do={
            :set $emailBody ($emailBody."    - $a\r\n")
        }
        :set $emailBody ($emailBody."\r\n")
    }

    :log warning "Sending an email to admins"
    /tool e-mail send to="$notifyAddress" subject="$myHostName: BGP Modifications" body="$emailBody"
} else={
    :log warning "There are no banned or removed from the ban addresses. No email updates are going to be sent."
}

:log warning "BGP Blacklist Helper execution is done"

The script requires *read*, *write* and *test* policies.

Who is online

Users browsing this forum: No registered users and 25 guests