Cargando...
 

Usando Quagga para análisis NfSen

En muchos casos queremos graficar el tráfico de redes específicas. Pero como es el caso de grandes redes tipo Netflix, Google, Akamai, etc. los IPs que ellos anuncian cambian constantemente. Es por eso que debemos dinámicamente conseguir esas redes y actualizar los canales que estamos graficando.

Si ya tenemos un servidor corriendo Quagga podemos aprovecharlo para obtener la información que queremos.

Este script, que vamos a llamar "crear_apple" por ejemplo saca todas las redes de Apple:

#!/bin/bash
vtysh -c "show ip bgp regexp \b6185\b$" | grep "*>i\|* i" > apple_v4.txt
vtysh -c "show ip bgp regexp \b714\b$" | grep "*>i\|* i" >> apple_v4.txt
vtysh -c "show ipv6 bgp regexp \b6185\b$" | grep "*>i" > apple_v6.txt
vtysh -c "show ipv6 bgp regexp \b714\b$" | grep "*>i" >> apple_v6.txt
awk -F '[ i]+' '{if ($2!="200.59.21.1" && $2!="200.59.21.2" && $2!="200.59.21.3") print $2}' apple_v4.txt > apple_v4_p1.txt
awk -F '[./]+' '{ if ($5 == "" && $1 < 192) print $1"."$2"."$3"."$4"/16"; else if ($5 == "" && $1 >= 192) print $1"."$2"."$3"."$4"/24"; else print $1"."$2"."$3"."$4"/"$5 }' apple_v4_p1.txt > apple_pref.txt
awk -F '[ i]+' '{print $2}' apple_v6.txt >> apple_pref.txt
./suma_cdir_filter.pl apple_pref.txt > Apple-filter.txt
cp Apple-filter.txt /var/www/lg/filters/
cp Apple-filter.txt /var/www/lg/filters/Redes_Apple


Yendo por partes vemos que lo que nos interesa son dos ASN de Apple, el 6185 y el 714. Con la línea:

vtysh -c "show ip bgp regexp \b6185\b$" | grep "*>i\|* i" > apple_v4.txt


estamos mandando todas las redes IPv4 del ASN 6185 a un archivo temporal que llamamos "apple_v4.txt". Las siguientes 3 líneas harán lo mismo para el otro ASN y para las redes en IPv6.

Ahora, si vemos el contenido de "apple_v4.txt" veremos algo como:

*>i17.253.0.0/23    200.59.21.2                   100      0 52263 23520 1299 714 6185 i
*>i17.253.2.0/23    200.59.21.2                   100      0 52263 23520 1299 714 6185 i
*>i17.253.4.0/23    200.59.21.2                   100      0 52263 23520 1299 714 6185 i
*>i17.253.6.0/23    200.59.21.2                   100      0 52263 23520 1299 714 6185 i
*>i17.253.8.0/23    200.59.21.2                   100      0 52263 23520 1299 714 6185 i
*>i17.253.10.0/23   200.59.21.2                   100      0 52263 23520 1299 714 6185 i
*>i17.253.12.0/23   200.59.21.2                   100      0 52263 23520 714 6185 i

y "apple_v6.txt":

*>i2403:300:a19::/48
*>i2403:300:a20::/48
*>i2403:300:a41::/48
*>i2403:300:a42::/48
*>i2403:300:a51::/48
*>i2620:149::/36    2800:640:d:1::100
*>i2620:149:1::/48  2800:640:d:1::100
*>i2620:149:11::/48 2800:640:d:1::100
*>i2620:149:40::/44 2800:640:d:1::100


Es por esto que usamos la utilidad "awk" para extraer solo la red, que es la parte que no interesa:

awk -F '[ i]+' '{if ($2!="200.59.21.1" && $2!="200.59.21.2" && $2!="200.59.21.3") print $2}' apple_v4.txt > apple_v4_p1.txt
awk -F '[./]+' '{ if ($5 == "" && $1 < 192) print $1"."$2"."$3"."$4"/16"; else if ($5 == "" && $1 >= 192) print $1"."$2"."$3"."$4"/24"; else print $1"."$2"."$3"."$4"/"$5 }' apple_v4_p1.txt > apple_pref.txt
awk -F '[ i]+' '{print $2}' apple_v6.txt >> apple_pref.txt


Ahora que tenemos el archivo "apple_pref.txt" con todas la redes v4 y v6 que ocupamos es hora de compactarlo.

Para esto usamos una utilidad escrita en perl llamada "suma_cdir.pl". Me tomé la libertad de modificarla un poco para que escriba el archivo con el formato apropiado para NfSen:

#!/usr/bin/perl
# $Id: aggregate-cidr-addresses,v 1.10 2014/11/13 11:53:22 suter Exp suter $
#
# aggregate-cidr-addresses - combine a list of CIDR address blocks
# Copyright (C) 2014 Mark Suter <suter@zwitterion.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see L<http://www.gnu.org/licenses/>.
#
# [MJS 22 Oct 2001] Aggregate CIDR addresses
# [MJS  9 Oct 2007] Overlap idea from Anthony Ledesma at theplanet dot com.
# [MJS 16 Feb 2012] Prompted to clarify license by Alexander Talos-Zens - at at univie dot ac dot at
# [MJS 21 Feb 2012] IPv6 fixes by Alexander Talos-Zens
# [MJS 21 Feb 2012] Split ranges into prefixes (fixes a 10+ year old bug)
# [MJS 13 Nov 2014] Stanislav Sinyagin's patch to check errno after aggregate.

use strict;
use warnings;
use English qw( -no_match_vars );
use Net::IP;

## Read in all the IP addresses
my @addrs = map { Net::IP->new($_) or die "$PROGRAM_NAME: Not an IP: \"$_\"."; }
    map { / \A \s* (.+?) \s* \Z /msix and $1; } <>;

## Split any ranges into prefixes
@addrs = map {
    defined $_->prefixlen ? $_ : map { Net::IP->new($_) }
        $_->find_prefixes
} @addrs;

## Sort the IP addresses
@addrs = sort { $a->version <=> $b->version or $a->bincomp( 'lt', $b ) ? -1 : $a->bincomp( 'gt', $b ) ? 1 : 0 } @addrs;

## Handle overlaps
my $count   = 0;
my $current = $addrs[0];
foreach my $next ( @addrs[ 1 .. $#addrs ] ) {
    my $r = $current->overlaps($next);
    if ( $current->version != $next->version or $r == $IP_NO_OVERLAP ) {
        $current = $next;
        $count++;
    }
    elsif ( $r == $IP_A_IN_B_OVERLAP ) {
        $current = $next;
        splice @addrs, $count, 1;
    }
    elsif ( $r == $IP_B_IN_A_OVERLAP or $r == $IP_IDENTICAL ) {
        splice @addrs, $count + 1, 1;
    }
    else {
        die "$PROGRAM_NAME: internal error - overlaps() returned an unexpected value!\n";
    }
}

## Keep aggregating until we don't change anything
my $change = 1;
while ($change) {
    $change = 0;
    my @new_addrs = ();
    $current = $addrs[0];
    foreach my $next ( @addrs[ 1 .. $#addrs ] ) {
        my $total = $current->aggregate($next);
        if ( defined $total and not $total->errno() ) {
            $current = $total;
            $change  = 1;
        }
        else {
            push @new_addrs, $current;
            $current = $next;
        }
    }
    push @new_addrs, $current;
    @addrs = @new_addrs;
}


## Print out the IP addresses

my $j = 0;
my $i = scalar @addrs;

foreach (@addrs) {
    $j = $j + 1;
    print "NET ";
    print $_->prefix();
    if ($j < $i) {
        print " or ";
    }
}
print "\n";


Llamé a la nueva versión "suma_cdir_filter.pl" y al usarlo obtenemos un archivo como:

NET 17.0.0.0/8 or NET 63.92.224.0/19 or NET 65.199.22.0/23 or NET 144.178.0.0/19 or NET 2403:0300:0000:0000:0000:0000:0000:0000/32 or NET 2620:0149:0000:0000:0000:0000:0000:0000/36 or NET 2a01:b740:0000:0000:0000:0000:0000:0000/32


que es una pequeña lista de sólo 7 prefijos versus la lista original de 965 prefijos anunciados.

Ahora que tenemos todo lo de las redes de Apple podemos continuar creando archivos como este para cualquiera que no interese, de manera dinámica y automatizar los procesos.