package FusionInventory::Agent::SNMP::Live; use strict; use warnings; use parent 'FusionInventory::Agent::SNMP'; use Encode qw(encode); use English qw(-no_match_vars); use Net::SNMP; use Net::SNMP qw/SNMP_PORT/; sub new { my ($class, %params) = @_; die "no hostname parameters\n" unless $params{hostname}; my $version = ! $params{version} ? 'snmpv1' : $params{version} eq '1' ? 'snmpv1' : $params{version} eq '2c' ? 'snmpv2c' : $params{version} eq '3' ? 'snmpv3' : undef ; die "invalid SNMP version $params{version} parameter\n" unless $version; my $self; # shared options my %options = ( -retries => 0, -version => $version, -hostname => $params{hostname}, -port => $params{port} || SNMP_PORT, -domain => $params{domain} || 'udp/ipv4', ); $options{'-timeout'} = $params{timeout} if $params{timeout}; # version-specific options if ($version eq 'snmpv3') { # only username is mandatory $options{'-username'} = $params{username}; $options{'-authprotocol'} = $params{authprotocol} if $params{authprotocol}; $options{'-authpassword'} = $params{authpassword} if $params{authpassword}; $options{'-privprotocol'} = $params{privprotocol} if $params{privprotocol}; $options{'-privpassword'} = $params{privpassword} if $params{privpassword}; } else { # snmpv2c && snmpv1 # $options{'-community'} = $params{community}; $self->{community} = $params{community}; } ($self->{session}, my $error) = Net::SNMP->session(%options); if (!$self->{session}) { die "no response from host $params{hostname}\n" if $error =~ /^No response from remote host/; die "authentication error on host $params{hostname}\n" if $error =~ /^Received usmStats(WrongDigests|UnknownUserNames)/; die $error . "\n"; } if ($version ne 'snmpv3') { my $oid = '.1.3.6.1.2.1.1.1.0'; my $response = $self->{session}->get_request( -varbindlist => [$oid] ); die "no response from host $params{hostname}\n" if !$response; die "empty response from host $params{hostname} on System variables request\n" if !$response->{$oid}; die "no response from host $params{hostname}\n" if $response->{$oid} =~ /No response from remote host/; } bless $self, $class; return $self; } sub switch_vlan_context { my ($self, $vlan_id) = @_; my $version_id = $self->{session}->version(); my $version = $version_id == 0 ? 'snmpv1' : $version_id == 1 ? 'snmpv2c' : $version_id == 3 ? 'snmpv3' : undef ; my $error; if ($version eq 'snmpv3') { $self->{context} = 'vlan-' . $vlan_id; } else { # save original session $self->{oldsession} = $self->{session} unless $self->{oldsession}; ($self->{session}, $error) = Net::SNMP->session( -timeout => $self->{session}->timeout(), -retries => 0, -version => $version, -hostname => $self->{session}->hostname(), -community => $self->{community} . '@' . $vlan_id ); } die $error."\n" unless $self->{session}; } sub reset_original_context { my ($self) = @_; my $version_id = $self->{session}->version(); my $version = $version_id == 0 ? 'snmpv1' : $version_id == 1 ? 'snmpv2c' : $version_id == 3 ? 'snmpv3' : undef ; if ($version eq 'snmpv3') { delete $self->{context}; } else { $self->{session} = $self->{oldsession}; delete $self->{oldsession}; } } sub get { my ($self, $oid) = @_; return unless $oid; my $session = $self->{session}; my %options = (-varbindlist => [$oid]); $options{'-contextname'} = $self->{context} if $self->{context}; my $response = $session->get_request(%options); return unless $response; return if $response->{$oid} =~ /noSuchInstance/; return if $response->{$oid} =~ /noSuchObject/; return if $response->{$oid} =~ /No response from remote host/; my $value = $response->{$oid}; return $value; } sub walk { my ($self, $oid) = @_; return unless $oid; my $session = $self->{session}; my %options = (-baseoid => $oid); $options{'-contextname'} = $self->{context} if $self->{context}; $options{'-maxrepetitions'} = 1 if $session->version() != 0; my $response = $session->get_table(%options); return unless $response; my $values; my $offset = length($oid) + 1; foreach my $oid (keys %{$response}) { my $value = $response->{$oid}; $values->{substr($oid, $offset)} = $value; } return $values; } sub peer_address { my ($self) = @_; # transport() API is not documented in Net::SNMP my $transport = $self->{session}->transport() or return; return $transport->peer_address(); } 1; __END__ =head1 NAME FusionInventory::Agent::SNMP::Live - Live SNMP client =head1 DESCRIPTION This is the object used by the agent to perform SNMP queries on live host. =head1 METHODS =head2 new(%params) The constructor. The following parameters are allowed, as keys of the %params hash: =over =item version (mandatory) Can be one of: =over =item '1' =item '2c' =item '3' =back =item timeout The transport layer timeout =item hostname (mandatory) =item port =item domain Can be one of: =over =item 'udp/ipv4' (default) =item 'udp/ipv6' =item 'tcp/ipv4' =item 'tcp/ipv6' =back =item community =item username =item authpassword =item authprotocol =item privpassword =item privprotocol =back