aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@frank.tg14.gathering.org>2014-04-15 13:49:39 +0200
committerroot <root@frank.tg14.gathering.org>2014-04-15 13:49:39 +0200
commit46959e031175a33d9a7ab52501323f7b1f9873e5 (patch)
tree64bd29cfed9b49dabb5b2ecb5a448fa5ec170748
parenta9515634b61b307440b8996685b4f0785be1cb48 (diff)
ipv6-dns v2 (fetich via SNMP, new DB schema)
-rwxr-xr-xclients/ipv6-dns.pl17
-rw-r--r--clients/ipv6-stats-v2.pl98
-rwxr-xr-xclients/ipv6-stats.pl89
-rw-r--r--include/nms.pm2
-rw-r--r--sql/nms.sql25
5 files changed, 115 insertions, 116 deletions
diff --git a/clients/ipv6-dns.pl b/clients/ipv6-dns.pl
index 24b8bfb..dcb059d 100755
--- a/clients/ipv6-dns.pl
+++ b/clients/ipv6-dns.pl
@@ -8,10 +8,10 @@ use strict;
use warnings;
BEGIN {
- require "../include/config.pm";
- eval {
- require "../include/config.local.pm";
- };
+require "../include/config.pm";
+ eval {
+ require "../include/config.local.pm";
+ };
}
my $dbh = nms::db_connect() or die "Can't connect to database";
@@ -44,7 +44,12 @@ print "Running automagic IPv6 DNS updates\n";
while (1) {
# Fetch visible IPv6 addresses from the last three minutes
- my $q = $dbh->prepare("SELECT DISTINCT ON (ipv6.mac) ipv6.address AS v6, ipv6.mac, ipv4.address AS v4, ipv6.time - ipv6.age*'1 second'::interval FROM ipv6 LEFT JOIN ipv4 ON ipv4.mac = ipv6.mac WHERE ipv6.time > NOW()-'3 min'::interval ORDER BY ipv6.mac, ipv6.time DESC, mac")
+ #my $q = $dbh->prepare("SELECT DISTINCT ON (ipv6.mac) ipv6.address AS v6, ipv6.mac, ipv4.address AS v4, ipv6.time - ipv6.age*'1 second'::interval FROM ipv6 LEFT JOIN ipv4 ON ipv4.mac = ipv6.mac WHERE ipv6.time > NOW()-'3 min'::interval ORDER BY ipv6.mac, ipv6.time DESC, mac")
+ my $q = $dbh->prepare(
+"SELECT DISTINCT ON (v6) v6, ipv6.mac, ipv6.seen, v4
+FROM (SELECT DISTINCT ON (address) address AS v6, mac, seen FROM seen_mac WHERE family(address) = 6 AND seen > CURRENT_TIMESTAMP - '3 min'::interval) ipv6
+LEFT JOIN (SELECT DISTINCT ON (address) address AS v4, mac, seen FROM seen_mac WHERE family(address) = 4 AND seen > CURRENT_TIMESTAMP - '3 min'::interval) ipv4 ON ipv4.mac = ipv6.mac
+ORDER BY v6, ipv6.seen DESC, mac")
or die "Can't prepare query";
$q->execute() or die "Can't execute query";
@@ -104,7 +109,7 @@ while (1) {
# try to delete everything. FIXME: Query the zone file and diff against the
# database, to avoid running as many NS-updates as tuples in the result set.
- $q = $dbh->prepare("SELECT DISTINCT address AS v6 FROM ipv6 WHERE time < NOW() - '4 hours'::interval AND time > NOW() - '4 hours 30 minutes'::interval")
+ $q = $dbh->prepare("SELECT DISTINCT address AS v6 FROM seen_mac WHERE seen BETWEEN CURRENT_TIMESTAMP - '4 hours'::interval AND CURRENT_TIMESTAMP - '4 hours 30 minutes'::interval")
or die "Can't prepare query";
$q->execute() or die "Can't execute query";
diff --git a/clients/ipv6-stats-v2.pl b/clients/ipv6-stats-v2.pl
new file mode 100644
index 0000000..ab76cc9
--- /dev/null
+++ b/clients/ipv6-stats-v2.pl
@@ -0,0 +1,98 @@
+#! /usr/bin/perl
+use strict;
+use warnings;
+use lib '../include';
+use nms;
+use Data::Validate::IP qw(is_public_ipv6 is_public_ipv4 is_private_ipv4);
+use Net::MAC qw(mac_is_unicast);
+
+my $dbh = nms::db_connect();
+$dbh->{AutoCommit} = 0;
+
+while (1) {
+ my $coregws = $dbh->prepare("SELECT ip, community, sysname FROM switches WHERE switchtype <> 'dlink3100'")
+ or die "Can't prepare query: $!";
+ $coregws->execute;
+
+ my %seen = ();
+ my $num_v4 = 0;
+ my $num_v6 = 0;
+ while (my $ref = $coregws->fetchrow_hashref) {
+ print STDERR "Querying ".$ref->{'sysname'}." ...\n";
+ my $snmp;
+ eval {
+ $snmp = nms::snmp_open_session($ref->{'ip'}, $ref->{'community'});
+ };
+ warn $@ if $@;
+ next if not $snmp;
+
+ # Pull in old media table that does not support ipv6.
+ my $ip_phys_table = fetch($snmp, ('ipNetToMediaNetAddress', 'ipNetToMediaPhysAddress'));
+ for my $entry (values %$ip_phys_table) {
+ my $ip_addr = $entry->{'ipNetToMediaNetAddress'};
+ my $mac = Net::MAC->new(
+ mac => nms::convert_mac($entry->{'ipNetToMediaPhysAddress'}),
+ die => 0,
+ );
+
+ next if $mac->get_base() != 16 || $mac->get_mac() eq ''; # We only support base 16 addresses
+ next if (!is_public_ipv4($ip_addr) && !is_private_ipv4($ip_addr)); # We consider RFC1918 public
+
+ $seen{$ip_addr} = $mac->get_mac();
+ $num_v4++;
+ }
+
+ # Pull in new media table with IPv6 support
+ $ip_phys_table = $snmp->gettable('ipNetToPhysicalTable');
+ for my $entry (values %$ip_phys_table) {
+ my $type = $entry->{'ipNetToPhysicalNetAddressType'};
+ my $ip_addr = undef;
+ my $mac = Net::MAC->new(
+ mac => nms::convert_mac($entry->{'ipNetToPhysicalPhysAddress'}),
+ die => 0,
+ );
+
+ if ($type != 2) {
+ warn "$ip_addr is of unexpected type $type (should be 2)! Tell Berge.\n";
+ next;
+ }
+
+ $ip_addr = nms::convert_ipv6($entry->{'ipNetToPhysicalNetAddress'});
+
+ next if $mac->get_base() != 16 || $mac->get_mac() eq ''; # We only support base 16 addresses
+ next if not is_public_ipv6($ip_addr);
+
+ $seen{$ip_addr} = $mac->get_mac();
+ $num_v6++;
+ }
+
+ }
+
+ # Populate database
+ my $i = 0;
+ foreach my $ip_addr (keys %seen) {
+ $i++;
+ my $q = $dbh->do('INSERT INTO seen_mac (address, mac) VALUES (?, ?)', undef, $ip_addr, $seen{$ip_addr})
+ or die "Can't execute query: $!";
+ }
+
+ $dbh->commit;
+ print "Collected $num_v6 IPv6 addresses and $num_v4 IPv4 addresses. $i unique addresses.\n";
+ print "Sleeping for 60 seconds ...\n";
+ sleep(60);
+}
+
+
+# Fetch provided fields from a single table returning {iid => {tag => val}}
+sub fetch {
+ my $session = shift;
+ my @vars = map { new SNMP::Varbind([$_]) } @_;
+ my $data = {};
+ foreach my $result (@{$session->bulkwalk(0, 8, new SNMP::VarList(@vars))}) {
+ foreach my $entry (@$result) {
+ $data->{$entry->iid}->{$entry->tag} = $entry->val;
+ }
+ }
+ return $data;
+}
+
diff --git a/clients/ipv6-stats.pl b/clients/ipv6-stats.pl
deleted file mode 100755
index 59dacbd..0000000
--- a/clients/ipv6-stats.pl
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/usr/bin/perl
-
-use warnings;
-use strict;
-use lib '../include';
-use nms qw(switch_connect switch_exec switch_disconnect);
-use Net::Telnet::Cisco;
-
-BEGIN {
- require "../include/config.pm";
- eval {
- require "../include/config.local.pm";
- };
-}
-
-#
-# Fetch list of MAC addresses and IPv6 addresses
-#
-sub query_router {
- my ($host) = @_;
-
- my $ios = Net::Telnet::Cisco->new(
- Host => $host,
- Errmode => 'return');
- if (not defined $ios) {
- warn "Can't connect to $host: $!, skipping";
- return ();
- }
- if (not $ios->login($nms::config::ios_user, $nms::config::ios_pass)) {
- warn "Can't login to $host. Wrong username or password?";
- return ();
- }
- $ios->autopage(0);
- $ios->cmd("terminal length 0");
- my @v6data = $ios->cmd('show ipv6 neighbors')
- or warn "$host wouldn't let me run show ipv6 neighbors.";
- my @v4data = $ios->cmd('show ip arp')
- or warn "$host wouldn't let me run show ip arp.";
-
- # Remove useless header and footer
-# shift @v6data;
- pop @v6data;
-# shift @v4data;
- pop @v4data;
-
- return { 'v6' => \@v6data, 'v4' => \@v4data };
-}
-
-while (1) {
- print "Gathering IPv6 and IPv4 stats\n";
- # Connect to DB
- my $dbh = nms::db_connect();
- $dbh->{AutoCommit} = 0;
-
- my ($v4, $v6) = 0;
- foreach my $router (@nms::config::distrobox_ips) {
- my $data = query_router($router);
- # IPv6
- foreach my $line (@{$data->{'v6'}}) {
- my ($address, $age, $mac, undef, undef) = split('\s+', $line);
- if ($mac =~ /[a-f0-9]{4}\.[a-f0-9]{4}\.[a-f0-9]{4}/ && # Sanity check MAC address
- $address !~ /^FE.*/) { # Filter out non-routable addresses
- my $q = $dbh->prepare('INSERT INTO ipv6 (address, age, mac, time) VALUES (?, ?, ?, timeofday()::timestamp)')
- or die "Can't prepare query: $!";
- $q->execute($address, $age, $mac)
- or die "Can't execute query: $!";
- $v6++;
- }
- }
- # IPv4
- foreach my $line (@{$data->{'v4'}}) {
- my (undef, $address, $age, $mac, undef, undef) = split('\s+', $line);
- if ($mac =~ /[a-f0-9]{4}\.[a-f0-9]{4}\.[a-f0-9]{4}/) {# Sanity check MAC address
- $age = 0 if $age eq '-';
- my $q = $dbh->prepare('INSERT INTO ipv4 (address, age, mac, time) VALUES (?, ?, ?, timeofday()::timestamp)')
- or die "Can't prepare query: $!";
- $q->execute($address, $age, $mac)
- or die "Can't execute query: $!";
- $v4++;
- }
- }
- }
- print "Added $v6 IPv6 addresses and $v4 IPv4 addresses.\n";
- $dbh->commit;
- $dbh->disconnect;
-
- print "Sleeping for two minutes.\n";
- sleep 120; # Sleep for two minutes
-}
diff --git a/include/nms.pm b/include/nms.pm
index a0f570b..3f89384 100644
--- a/include/nms.pm
+++ b/include/nms.pm
@@ -27,6 +27,8 @@ BEGIN {
SNMP::loadModules('ENTITY-MIB');
SNMP::loadModules('IF-MIB');
SNMP::loadModules('LLDP-MIB');
+ SNMP::loadModules('IP-MIB');
+ SNMP::loadModules('IP-FORWARD-MIB');
}
sub db_connect {
diff --git a/sql/nms.sql b/sql/nms.sql
index 002ae6b..fe5f4b8 100644
--- a/sql/nms.sql
+++ b/sql/nms.sql
@@ -347,34 +347,17 @@ CREATE TABLE dhcp (
ALTER TABLE public.dhcp OWNER TO nms;
+-- Name: seen_mac; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
--- Name: ipv4; Type: TABLE; Schema: public; Owner: nms; Tablespace:
---
-
-CREATE TABLE ipv4 (
- mac macaddr NOT NULL,
- address inet NOT NULL,
- "time" timestamp without time zone NOT NULL,
- age integer
-);
-
-ALTER TABLE public.ipv4 OWNER TO nms;
-
---
--- Name: ipv6; Type: TABLE; Schema: public; Owner: nms; Tablespace:
---
-
-CREATE TABLE ipv6 (
+CREATE TABLE seen_mac (
mac macaddr NOT NULL,
address inet NOT NULL,
- "time" timestamp with time zone NOT NULL,
- age integer,
- vlan text
+ seen timestamp with time zone DEFAULT now() NOT NULL
);
-ALTER TABLE public.ipv6 OWNER TO nms;
+ALTER TABLE public.seen_mac OWNER TO nms;
--
-- Name: mbd_log; Type: TABLE; Schema: public; Owner: nms; Tablespace: