diff options
Diffstat (limited to 'scripts/snmp/vyatta-snmp.pl')
-rwxr-xr-x | scripts/snmp/vyatta-snmp.pl | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/scripts/snmp/vyatta-snmp.pl b/scripts/snmp/vyatta-snmp.pl new file mode 100755 index 00000000..5c4ff1d0 --- /dev/null +++ b/scripts/snmp/vyatta-snmp.pl @@ -0,0 +1,333 @@ +#!/usr/bin/perl +# +# Module: vyatta-snmp.pl +# +# **** License **** +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# 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. +# +# This code was originally developed by Vyatta, Inc. +# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc. +# All Rights Reserved. +# +# Author: Stig Thormodsrud +# Date: October 2007 +# Description: Script to glue vyatta cli to snmp daemon +# +# **** End License **** +# + +use strict; +use warnings; + +use lib "/opt/vyatta/share/perl5/"; +use Vyatta::Config; +use Vyatta::Misc; +use NetAddr::IP; +use Getopt::Long; +use File::Copy; +use Socket; +use Socket6; + +my $mibdir = '/opt/vyatta/share/snmp/mibs'; +my $snmp_start = 'systemctl start snmpd.service'; +my $snmp_stop = 'systemctl stop snmpd.service'; +my $snmp_conf = '/etc/snmp/snmpd.conf'; +my $snmp_client = '/etc/snmp/snmp.conf'; +my $snmp_tmp = "/tmp/snmpd.conf.$$"; +my $snmp_snmpv3_user_conf = '/usr/share/snmp/snmpd.conf'; +my $snmp_snmpv3_createuser_conf = '/var/lib/snmp/snmpd.conf'; +my $versionfile = '/opt/vyatta/etc/version'; +my $local_agent = 'unix:/run/snmpd.socket'; +my $password_file = '/config/snmp/superuser_pass'; + +my $snmp_level = 'service snmp'; + +sub snmp_running { + open (my $pidf, '<', "/run/snmpd.pid") + or return; + my $pid = <$pidf>; + close $pidf; + + chomp $pid; + my $exe = readlink "/proc/$pid/exe"; + + return (defined($exe) && $exe eq "/usr/sbin/snmpd"); +} + +sub snmp_stop { + system("$snmp_stop > /dev/null 2>&1"); +} + +sub snmp_start { + # we must stop snmpd first for creating vyatta user + system("$snmp_stop > /dev/null 2>&1"); + open (my $fh, '>', $snmp_tmp) + or die "Couldn't open $snmp_tmp - $!"; + + select $fh; + snmp_get_constants(); + snmp_get_values(); + snmp_get_traps(); + close $fh; + select STDOUT; + + snmp_client_config(); + + move($snmp_tmp, $snmp_conf) + or die "Couldn't move $snmp_tmp to $snmp_conf - $!"; +} + +sub get_version { + my $version = "unknown-version"; + + if (open (my $f, '<', $versionfile)) { + while (<$f>) { + chomp; + if (m/^Version\s*:\s*(.*)$/) { + $version = $1; + last; + } + } + close $f; + } + return $version; +} + +# convert address to snmpd transport syntax +sub transport_syntax { + my ($addr, $port) = @_; + my $ip = new NetAddr::IP $addr; + die "$addr: not a valid IP address" unless $ip; + + my $version = $ip->version(); + return "udp:$addr:$port" if ($version == 4); + return "udp6:[$addr]:$port" if ($version == 6); + die "$addr: unknown IP version $version"; +} + +# Test if IPv6 is possible by opening a socket +sub ipv6_disabled { + socket ( my $s, PF_INET6, SOCK_DGRAM, 0) + or return 1; + close($s); + return; +} + +# Find SNMP agent listening addresses +sub get_listen_address { + my $config = new Vyatta::Config; + my @listen; + + $config->setLevel('service snmp listen-address'); + my @address = $config->listNodes(); + + if(@address) { + foreach my $addr (@address) { + my $port = $config->returnValue("$addr port"); + push @listen, transport_syntax($addr, $port); + } + } else { + # default if no address specified + @listen = ( 'udp:161' ); + push @listen, 'udp6:161' unless ipv6_disabled(); + return @listen; + } + + return @listen; +} + +sub snmp_get_constants { + my $version = get_version(); + my $now = localtime; + my @addr = get_listen_address(); + + # add local unix domain target for use by operational commands + unshift @addr, $local_agent; + + print "# autogenerated by vyatta-snmp.pl on $now\n"; + print "sysDescr VyOS $version\n"; + print "sysObjectID 1.3.6.1.4.1.44641\n"; + print "sysServices 14\n"; + print "master agentx\n"; # maybe needed by lldpd + print "agentaddress ", join(',',@addr), "\n"; + print "agentXPerms 0755 0755\n"; + + # add hook to read IF-MIB::ifAlias from sysfs + print "pass .1.3.6.1.2.1.31.1.1.1.18 /opt/vyatta/sbin/if-mib-alias\n"; + + print "smuxpeer .1.3.6.1.4.1.3317.1.2.2\n"; # ospfd + print "smuxpeer .1.3.6.1.4.1.3317.1.2.5\n"; # bgpd + print "smuxpeer .1.3.6.1.4.1.3317.1.2.3\n"; # ripd + print "smuxpeer .1.3.6.1.4.1.3317.1.2.9\n"; # mribd + print "smuxpeer .1.3.6.1.2.1.83\n"; # mribd + print "smuxpeer .1.3.6.1.4.1.3317.1.2.8\n"; # pimd + print "smuxpeer .1.3.6.1.2.1.157\n"; # pimd + print "smuxsocket localhost\n"; +} + +# generate a random character hex string +sub randhex { + my $length = shift; + return join "", map { unpack "H*", chr(rand(256)) } 1..($length/2); +} + +# output snmpd.conf file syntax for community +sub print_community { + my ($config, $community) = @_; + my $ro = $config->returnValue('authorization'); + $ro = 'ro' unless $ro; + + my @clients = $config->returnValues('client'); + my @networks = $config->returnValues('network'); + + my @restriction = (@clients, @networks); + if (!@restriction) { + print $ro . "community $community\n"; + print $ro . "community6 $community\n" unless ipv6_disabled(); + return; + } + + foreach my $addr (@restriction) { + my $ip = new NetAddr::IP $addr; + die "$addr: Not a valid IP address" unless $ip; + + if ($ip->version() == 4) { + print $ro . "community $community $addr\n"; + } elsif ($ip->version() == 6) { + print $ro . "community6 $community $addr\n"; + } else { + die "$addr: bad IP version ", $ip->version(); + } + } +} + +sub snmp_get_values { + my $config = new Vyatta::Config; + + my @communities = $config->listNodes("service snmp community"); + foreach my $community (@communities) { + $config->setLevel("service snmp community $community"); + print_community($config, $community); + } + + $config->setLevel("service snmp smux-peer"); + my @smuxpeers = $config->returnValues(); + foreach my $smuxpeer (@smuxpeers) { + print "smuxpeer $smuxpeer \n"; + } + + $config->setLevel($snmp_level); + my $contact = $config->returnValue("contact"); + if (defined $contact) { + print "SysContact $contact \n"; + } + + my $description = $config->returnValue("description"); + if (defined $description) { + print "SysDescr $description \n"; + } + + my $location = $config->returnValue("location"); + if (defined $location) { + print "SysLocation $location \n"; + } +} + +sub snmp_get_traps { + my $config = new Vyatta::Config; + $config->setLevel($snmp_level); + + # linkUp/Down configure the Event MIB tables to monitor + # the ifTable for network interfaces being taken up or down + # for making internal queries to retrieve any necessary information + + # create an internal snmpv3 user of the form 'vyattaxxxxxxxxxxxxxxxx' + my $vyatta_user = "vyatta" . randhex(16); + snmp_create_snmpv3_user($vyatta_user); + snmp_write_snmpv3_user($vyatta_user); + print "iquerySecName $vyatta_user\n"; + + # Modified from the default linkUpDownNotification + # to include more OIDs and poll more frequently + print <<EOF; +notificationEvent linkUpTrap linkUp ifIndex ifDescr ifType ifAdminStatus ifOperStatus +notificationEvent linkDownTrap linkDown ifIndex ifDescr ifType ifAdminStatus ifOperStatus +monitor -r 10 -e linkUpTrap "Generate linkUp" ifOperStatus != 2 +monitor -r 10 -e linkDownTrap "Generate linkDown" ifOperStatus == 2 +EOF + + my @trap_targets = $config->listNodes("trap-target"); + return unless @trap_targets; + + foreach my $trap_target (@trap_targets) { + my $port = $config->returnValue("trap-target $trap_target port"); + my $community + = $config->returnValue("trap-target $trap_target community"); + + print "trap2sink $trap_target"; + print ":$port" if $port; + print " $community" if $community; + print "\n"; + } +} + +# Configure SNMP client parameters +sub snmp_client_config { + my $config = new Vyatta::Config; + $config->setLevel($snmp_level); + + open (my $cf, '>', $snmp_client) + or die "Couldn't open $snmp_client - $!"; + + my $version = get_version(); + my $now = localtime; + print {$cf} "# autogenerated by vyatta-snmp.pl on $now\n"; + + my $trap_source = $config->returnValue('trap-source'); + print {$cf} "clientaddr $trap_source\n" if ($trap_source); + close $cf; +} + +sub snmp_create_snmpv3_user { + + my $vyatta_user = shift; + my $passphrase = randhex(32); + + my $createuser = "createUser $vyatta_user MD5 \"$passphrase\" DES"; + open(my $fh, '>', $snmp_snmpv3_createuser_conf) || die "Couldn't open $snmp_snmpv3_createuser_conf - $!"; + print $fh $createuser; + close $fh; + + open(my $pass_file, '>', $password_file) || die "Couldn't open $password_file - $!"; + print $pass_file $passphrase; + close $pass_file; +} + +sub snmp_write_snmpv3_user { + + my $vyatta_user = shift; + my $user = "rwuser $vyatta_user\n"; + open(my $fh, '>', $snmp_snmpv3_user_conf) || die "Couldn't open $snmp_snmpv3_user_conf - $!"; + print $fh $user; + close $fh; +} + + +# +# main +# +my $update_snmp; +my $stop_snmp; + +GetOptions("update-snmp!" => \$update_snmp, + "stop-snmp!" => \$stop_snmp); + +snmp_start() if ($update_snmp); +snmp_stop() if ($stop_snmp); |