22.03.2018

Selective BGP blackhole or traffic diversion in FastNetMon Advanced

In this guide we will describe required steps to announce hosts from first host group as /32 with specific community (blackhole for example) and hosts from second host group as /24 with different community (to redirect traffic to scrubbing centre for example). Host group is a group of multiple networks in CIDR format.

Please upgrade FastNetMon to version 2.0.78, it’s minimum possible version for this guide.

This guide assumes that you have configured BGP connection. Please follow quick start guide for it.

After configuring BGP, please disable any standard actions for BGP. We will use notify script instead because we need custom logic:

sudo fcli set main gobgp_announce_host disable
sudo fcli set main gobgp_announce_whole_subnet disable
sudo fcli commit

First of all, convert (split or aggregate) all your networks in networks_list (sudo fcli show main networks_list) to /24 CIDR networks only.

You can remove existing networks from this list this way:

sudo fcli delete main networks_list 11.22.33.44/32

And add new ones this way:

sudo fcli set main networks_list 11.22.33.44/24

Then, you need to create two host groups.

First one for hosts where you need blackhole action.

sudo fcli set hostgroup host_to_blackhole
sudo fcli set hostgroup host_to_blackhole threshold_mbps 100
sudo fcli set hostgroup host_to_blackhole ban_for_bandwidth enable

sudo fcli set hostgroup host_to_blackhole enable_ban enable
sudo fcli set hostgroup host_to_blackhole networks 11.22.33.44/24

Second one for hosts where you need traffic diversion action:

sudo fcli set hostgroup host_to_scrubbing
sudo fcli set hostgroup host_to_scrubbing threshold_mbps 100
sudo fcli set hostgroup host_to_scrubbing ban_for_bandwidth enable

sudo fcli set hostgroup host_to_scrubbing enable_ban enable
sudo fcli set hostgroup host_to_scrubbing networks 10.10.10.10/24

Please install JSON processing library for Perl:

sudo apt-get install -y libjson-perl

Finally, you need to put this script into file /usr/local/bin/notify_json.pl:

#!/usr/bin/perl
 
use strict;
use warnings;
 
use JSON;
 
use Data::Dumper;

my $community_host_to_blackhole = '65000:777';
my $community_host_to_scrubbing = '65000:888';
 
# Write some debug to /tmp
 
open my $fl, ">>", "/tmp/fastnetmon_notify_script.log" or die "Could not open file for writing";
 
# This script executed from FastNetMon this way: ban 11.22.33.44
 
if (scalar @ARGV != 2) {
    print {$fl} "Please specify all arguments. Got only: @ARGV\n";
    die "Please specify all arguments\n";
}
 
my ($action, $ip_address) = @ARGV;
# action could be: ban, unban, partial_block
 
# Read data from stdin
my $input_attack_details = join '', <STDIN>;
 
# try to decode this data to json
my $attack_details = eval{  decode_json($input_attack_details); };
 
# report error
 
if ($@) {
    print {$fl} "JSON decode failed: $input_attack_details\n";
 
    die "JSON decode failed\n";
}
 
print {$fl} "Received notification about $ip_address with action $action\n";
 
print {$fl} Dumper($attack_details);

my $host_group = $attack_details->{attack_details}->{'host_group'};

my $command = '';

if ($host_group eq 'host_to_scrubbing') {
    my $host_network = $attack_details->{attack_details}->{host_network};

    if ($action eq 'ban') {
        $command = "gobgp global rib add -a ipv4 $host_network community $community_host_to_scrubbing";
    } elsif ($action eq 'unban') {
        $command = "gobgp global rib del -a ipv4 $host_network";
    }
} elsif ($host_group eq 'host_to_blackhole') {
    if ($action eq 'ban') {
        $command = "gobgp global rib add -a ipv4 $attack_details->{ip}/32 community $community_host_to_blackhole";
    } elsif ($action eq 'unban') {
        $command = "gobgp global rib del -a ipv4 $attack_details->{ip}/32";
    }
} else {
    print {$fl} "Unknown host group $host_group. Do not apply any actions\n";
}
 
if ($command ne '') {
    print {$fl} "Will execute command $command for group $host_group\n";
    my $res = system($command);

    if ($res != 0) {
        print {$fl} "Command failed with code $res\n";
    } else {
        print {$fl} "Command executed correctly\n";
    }

}

close $fl;
 
exit 0;

Set executable bit for it:

sudo chmod +x /usr/local/bin/notify_json.pl

And configure it for your FastNetMon instance to call it when FastNetMon detects an attack.

sudo fcli set main notify_script_enabled enable
sudo fcli set main notify_script_format json
sudo fcli set main notify_script_path /usr/local/bin/notify_json.pl
sudo fcli commit

After initial setup, we suggest manual check for hosts from each group and test FastNetMon’s behaviour in each case.

To test host from group host_to_blackhole:

sudo fcli set blackhole 11.22.33.44

To test host from group host_to_scrubbing:

sudo fcli set blackhole 10.10.10.10

You can debug actions from our script using this command:

sudo tail -f /tmp/fastnetmon_notify_script.log