Monday, May 25, 2015

Wireshark remote capture with GNS3

So far GNS3 introduced a great way to use it in distributed mode; however, there is a problem: wireshark can not intercept traffic on routers being run on a remote server right now. While developers announced support for remote capture in version 1.4 there is a way to make it work in 1.3 also.


Of course I am assuming that you have ssh access to a remote machine where GNS3-server is running. And as I use exclusively Linux on all of my machines, this guide will cover this OS only.

Monday, May 11, 2015

My virtual GNS3 lab

For most of my experiments I use great program GNS3. Recently I switched from legacy 0.8, included in most distributions, to modern branch version 1.3. It was difficult in the beginning to figure out how to install it but once I made it, things became much easier. New features, like auto discovery of IdlePC for any Cisco router saves a lot of time, and ability to move server to another machine is really helpful. Here I would like to describe my lab and task I use it for.

Sunday, May 10, 2015

ISIS route leaking in IOS XR and XE

Route leaking is useful in some situations when there are more than one exit from an area, like on this picture:


Note: address scheme for most of my schemes - lo0 on every router is 1.1.1.1 on router 1, 2.2.2.2 on router 2 , etc; interrouter links 10.0.XY.X/24 and 10.0.XY.Y/24 where X - number of one router and Y of another. So, for address 10.0.25.5 it can be said that this is R5 side of the link between R2 and R5.

Assuming that all links in this diagram are equal it is obvious that for R6 to reach R5 path through R7 - XE2 - R5 should be used as it has less hops, however in reality R6 will try to reach both R3 and R5 through XR-1 router with 2 and 4 hops respectfully, and R7 will go to R3 and R5 via XE2. This can be confirmed with traceroute from R6:

R6#traceroute 3.3.3.3
Type escape sequence to abort.
Tracing the route to 3.3.3.3
VRF info: (vrf in name/id, vrf out name/id)
  1 10.0.16.1 28 msec 4 msec 8 msec    <============ XR1
  2 10.0.13.3 16 msec 16 msec 16 msec  <============ R3

R6#traceroute 5.5.5.5
Type escape sequence to abort.
Tracing the route to 5.5.5.5
VRF info: (vrf in name/id, vrf out name/id)
  1 10.0.16.1 4 msec 12 msec 8 msec    <============ XR1
  2 10.0.14.4 12 msec 32 msec 16 msec  <============ R4
  3 10.0.24.2 16 msec 28 msec 28 msec  <============ R2
  4 10.0.25.5 24 msec 36 msec 36 msec  <============ R5

And from R7:

R7#traceroute 3.3.3.3
Type escape sequence to abort.
Tracing the route to 3.3.3.3
VRF info: (vrf in name/id, vrf out name/id)
  1 10.0.27.2 8 msec 12 msec 8 msec    <============ XE2
  2 10.0.24.4 16 msec 8 msec 8 msec    <============ R4
  3 10.0.14.1 4 msec 16 msec 16 msec   <============ R1
  4 10.0.13.3 16 msec 20 msec 16 msec  <============ R3

R7#traceroute 5.5.5.5
Type escape sequence to abort.
Tracing the route to 5.5.5.5
VRF info: (vrf in name/id, vrf out name/id)
  1 10.0.27.2 12 msec 8 msec 12 msec   <============ XE2
  2 10.0.25.5 12 msec 12 msec 4 msec   <============ R5

To fix this issue route leaking can be used on XR1 and XE2.

Friday, April 24, 2015

ipv4 over ipv6

I will use the next topology created using gns3.

First, interfaces and OSPFv3 need to be configured. What is really good about IPv6 that you don't have to configure all the addresses by hand. All you need to do is to enable it on any interface and it will use link-local address. Like this:

int Fa0/0
  ipv6 enable
  ipv6 ospf 1 area 0
!

This configuration is enough for OSPFv3 to form adjacency. However to build a tunnel it is better to have a couple of persistent addresses. I used addresses 1::1/128 and 3::3/128 for loopback interfaces on routers R1 and R3 respectfully. Next step is to configure tunnel itself:

interface Tunnel0
  ip address 10.10.10.1 255.255.255.0
  ip ospf 2 area 0
  tunnel source Loopback0
  tunnel destination 3::3
  tunnel mode ipv6
end

This is configuration of R1 tunnel interface, on R3 it is basically the same. Here we have some options about packet encapsulation:

tunnel mode ipv6
uses "Generic packet tunneling in IPv6", which means that IPv4 is simply enveloped in IPv6. Here is a screenshot of ICMP packet delivered through the tunnel:

tunnel mode gre ipv6
is another possible option, which uses GRE encapsulation between IPv4 and IPv6 headers. It can be seen on another captured packet:

Tuesday, April 7, 2015

How to add interface descriptions to Zabbix



For those who are unsatisfied with default Zabbix discoveries. There is a great way to have both interface Name (i.e. Gi1/1/2) and Alias (i.e. Link to SuperServer) together in the name name of an item itself. This solution was tested on Cisco, Extreme Networks, Dlink and Force10 devices. It uses standard SNMP OID so probably would work on every device.

To make this type of discovery it is essential to use external source of discovered data. It can be done using any language, in this case I decided to use perl. The idea of a script is to get information from a device and return it in JSON format, like this:

{
    "data" : [
        {
            "{#ALIAS}" : "server-2",
            "{#NAME}" : "Gi1/0/7",
            "{#INDEX}" : "10107"
        },
        {
            "{#ALIAS}" : "server-1",
            "{#NAME}" : "Gi1/0/2",
            "{#INDEX}" : "10102"
        },
        {
            "{#ALIAS}" : "provider-1",
            "{#NAME}" : "Te1/1/2",
            "{#INDEX}" : "10402"
        }
    ]
}

For Zabbix to use the script it should be located in External scripts directory (check your Zabbix server conf file, it depends on distribution) and, of course, to have an executable bit set. Script should NOT return any additional data, except for a correct JSON. Then create new template with name "Network interfaces" or something like that, and add a discovery with the setting:


External check means that Zabbix will use a script from an external scripts folder;
Key is a name of a script and parameters. In this case there are two parameters: {HOST.IP}, which is global variable and will take the IP address from an interface of a host this template will attached to, and {$SNMP_COMMUNITY1} is a global macros, defined under Administration -> General -> Macros. As a result, the final command Zabbix will call will look something like "interface-discovery.pl 192.168.1.254 public"

Then add items to the new discovery, for Speed, traffic, statuses and so on. There are a lot of useful examples here:



In SNMP OID field you can use numeric OID, if you do not have MIBs installed. Good ideas to monitor:

IF-MIB::ifHCInOctets - 1.3.6.1.2.1.31.1.1.1.6 - incoming traffic
IF-MIB::ifHCOutOctets - 1.3.6.1.2.1.31.1.1.1.10 - outgoing traffic
IF-MIB::ifAdminStatus - 1.3.6.1.2.1.2.2.1.7 - admin status of interface
IF-MIB::ifAlias - 1.3.6.1.2.1.31.1.1.1.18 - description of interface
IF-MIB::ifOperStatus - 1.3.6.1.2.1.2.2.1.8 - operational status of interface
IF-MIB::ifInErrors - 1.3.6.1.2.1.2.2.1.14 - incoming errors on interface
IF-MIB::ifOutErrors - 1.3.6.1.2.1.2.2.1.20 - outgoing errors on interface

Another good suggestions you may find at cisco site.

Just add ".{#INDEX}" in the end of any OID. Here is a list of items I use for my system:





Create triggers with names that would actually mean something to you, and with expressions you like:





And voila! Newly created items will look like this:




New triggers with adequate names:





And, as a bonus, interface names and aliases on graphs:





Of course, descriptions change over time, but it is not a problem, actually. You just need to set up your discovery to run periodically. I use period of 1 day and it works great. Zabbix realizes that its not a new item but the old one with a new name based on the item key, and just changes name, preserving all the history. So this method will work if you will keep keys persistent. For example, I use interface name as a unique part of a key. After periodical discovery finishes, it will update name of items everywhere - in triggers and graphs.

And here is my script. I am not a programmer so it definitely has some problems. Your suggestions are welcome!


#!/usr/bin/perl

use warnings;
use strict;
use Data::Dumper;
use Net::SNMP;
use JSON;

open(STDERR, '>', '/tmp/int_results_error.log') or warn "Can't open log";

die("Usage: $0 ipaddress community\n") unless ( $#ARGV == 1 ); #we expect to see 2 arguments

my $oid_ifName = '1.3.6.1.2.1.31.1.1.1.1';
my $oid_ifAlias = '1.3.6.1.2.1.31.1.1.1.18';
my $oid_ifType = '1.3.6.1.2.1.2.2.1.3';

my ($session, $error) = Net::SNMP->session(
    -hostname => $ARGV[0],
    -community => $ARGV[1],
    -version => 'snmpv2c',
);

die("ERROR: $error\n") unless ( $session );

my $names = $session->get_table(-baseoid => $oid_ifName,);
die("ERROR getting names: ".$session->error()."\n") unless ( $names );
foreach ( keys %$names) {
    my $new_key;
    ( $new_key = $_ ) =~ s/.*\.//;
    $names->{ $new_key } = delete $names->{$_};
}

my $aliases = $session->get_table(-baseoid => $oid_ifAlias,);
die("ERROR getting aliases: ".$session->error()."\n") unless ( $aliases );
foreach ( keys %$aliases) {
    my $new_key;
    ( $new_key = $_ ) =~ s/.*\.//;
    $aliases->{ $new_key } = delete $aliases->{$_};
    $aliases->{ $new_key } =~ s/[^\x20-\x7E]//g;
}

my $types = $session->get_table(-baseoid => $oid_ifType,);
die("ERROR getting types: ".$session->error()."\n") unless ( $types );
foreach ( keys %$types) {
    my $new_key;
    ( $new_key = $_ ) =~ s/.*\.//;
    $types->{ $new_key } = delete $types->{$_};
}

my @interfaces;
foreach my $index ( keys %$names ) { #for each found port
    no warnings 'uninitialized';

    # hacks
    next if ( $names->{$index} =~ /--(Unc|C)ontrolled/ ); # hack to exempt 4500 strange interfaces
    next if ( $types->{$index} != 6 ); # exempt everything but physical interfaces (type = 6)
    next if ( $names->{$index} =~ /^NDE/ ); #hack to exempt NetFlow interfaces of c6k
    if ( $names->{$index} =~ /^(\d:|)\d{2}$/ ) {
        my $nport;
        ( $nport = $names->{$index} ) =~ s/^(\d:|)(\d+)$/$2/;
        next if ( $nport > 48); # hack to exempt ports 49-62 on extreme switches
    }
    # /hacks

    push(@interfaces, {"{#INDEX}" => $index, "{#NAME}" => $names->{$index}, "{#ALIAS}" => $aliases->{$index}});
}

print JSON::XS->new->utf8->pretty(1)->encode( { "data" => \@interfaces });

END { $session->close() if ( $session ); }