From 721193ccb8642d5a42fc506e5d1607968b81d29d Mon Sep 17 00:00:00 2001 From: "Eric A. Miller" Date: Sun, 6 May 2018 14:02:35 -0400 Subject: [PATCH] #255 IPv6 support --- Build.PL | 1 + Changes | 6 ++++++ META.json | 1 + META.yml | 1 + README | 7 +++++++ lib/SNMP/Info.pm | 36 +++++++++++++++++++++++++++++++++++- xt/lib/Test/SNMP/Info.pm | 30 ++++++++++++++++++++++++------ 7 files changed, 75 insertions(+), 7 deletions(-) diff --git a/Build.PL b/Build.PL index cbbd4c82..8f589450 100644 --- a/Build.PL +++ b/Build.PL @@ -16,6 +16,7 @@ Module::Build->new( requires => { 'SNMP' => '0', 'Math::BigInt' => '0', + 'NetAddr::IP' => '4.068', }, recommends => { 'PPI' => '0', diff --git a/Changes b/Changes index 4203c5b0..4752f2c9 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,9 @@ +Version 3.61 + + [ENHANCEMENTS] + + * #255 IPv6 support + Version 3.60 (2018-05-06) [ENHANCEMENTS] diff --git a/META.json b/META.json index a5129553..bc0a614d 100644 --- a/META.json +++ b/META.json @@ -29,6 +29,7 @@ }, "requires" : { "Math::BigInt" : "0", + "NetAddr::IP" : "4.068", "SNMP" : "0" } }, diff --git a/META.yml b/META.yml index 672688ec..a3e0353a 100644 --- a/META.yml +++ b/META.yml @@ -414,6 +414,7 @@ recommends: PPI: '0' requires: Math::BigInt: '0' + NetAddr::IP: '4.068' SNMP: '0' resources: IRC: irc://irc.freenode.org/#netdisco diff --git a/README b/README index a589534f..413ecd0d 100644 --- a/README +++ b/README @@ -1988,6 +1988,13 @@ SNMP::INFO INTERNALS Takes an OID and return the object name if the right MIB is loaded. Internally Used Functions + resolve_desthost() + Takes the SNMP::Session "DestHost" argument and determines if it is + an 'IPv4' or 'IPv6' host. 'IPv6' hosts are prefixed with the "udp6:" + "transport-specifier" as required by the undelying "Net-SNMP" + library. If unable to determine the type of address or resolve a DNS + name, 'undef' will be returned causing the session creation to fail. + $info->init() Used internally. Loads all entries in %MIBS. diff --git a/lib/SNMP/Info.pm b/lib/SNMP/Info.pm index bd5aa4ea..7e7d7dee 100644 --- a/lib/SNMP/Info.pm +++ b/lib/SNMP/Info.pm @@ -16,6 +16,7 @@ use Exporter; use SNMP; use Carp; use Math::BigInt; +use NetAddr::IP::Lite ':lower'; @SNMP::Info::ISA = qw/Exporter/; @SNMP::Info::EXPORT_OK = qw//; @@ -1320,6 +1321,11 @@ sub new { $new_obj->{mibdirs} = $args{MibDirs}; delete $sess_args{MibDirs}; } + + # For IPv6 hosts set transport + if ( defined $sess_args{DestHost} ) { + $sess_args{DestHost} = resolve_desthost($sess_args{DestHost}); + } $new_obj->{nosuch} = $args{RetryNoSuch} || $NOSUCH; @@ -3745,6 +3751,32 @@ sub munge_e_type { =over +=item resolve_desthost() + +Takes the SNMP::Session C argument and determines if it is an +'IPv4' or 'IPv6' host. 'IPv6' hosts are prefixed with the C +C as required by the undelying C library. +If unable to determine the type of address or resolve a DNS name, 'undef' +will be returned causing the session creation to fail. + +=cut + +sub resolve_desthost { + my $desthost = shift; + + my $ip = NetAddr::IP::Lite->new($desthost); + + if ($ip and $ip->bits == 32) { + return $ip->addr; + } + elsif ($ip and $ip->bits == 128) { + return 'udp6:' . $ip->addr; + } + else { + return; + } +} + =item $info->init() Used internally. Loads all entries in %MIBS. @@ -4514,6 +4546,9 @@ sub snmp_connect_ip { my $comm = $self->snmp_comm(); return if $self->{Offline}; + + $ip = resolve_desthost($ip); + return unless $ip; return if ( $ip eq '0.0.0.0' ) or ( $ip =~ /^127\./ ); # Create session object @@ -4543,7 +4578,6 @@ sub snmp_connect_ip { } return 1; - } =item modify_port_list(portlist,offset,replacement) diff --git a/xt/lib/Test/SNMP/Info.pm b/xt/lib/Test/SNMP/Info.pm index cee505a2..71fe4791 100644 --- a/xt/lib/Test/SNMP/Info.pm +++ b/xt/lib/Test/SNMP/Info.pm @@ -781,6 +781,24 @@ sub munge_e_type : Tests(3) { '.100.3.6.1.2.1.11.4', 'OID returned when unable to translate'); } +sub resolve_desthost : Tests(4) { + my $test = shift; + + can_ok($test->{info}, 'resolve_desthost'); + + is(SNMP::Info::resolve_desthost('1.2.3.4'), + '1.2.3.4', 'IPv4 address returns unchanged'); + + is(SNMP::Info::resolve_desthost('::1.2.3.4'), + 'udp6:0:0:0:0:0:0:102:304', q(IPv6 address returns with 'udp6:' prefix)); + + is( + SNMP::Info::resolve_desthost('fe80::2d0:b7ff:fe21:c6c0'), + 'udp6:fe80:0:0:0:2d0:b7ff:fe21:c6c0', + q(Net-SNMP example IPv6 address returns with 'udp6:' prefix) + ); +} + sub init : Tests(3) { my $test = shift; @@ -1299,10 +1317,10 @@ sub private_load_attr : Tests(18) { 'IF-MIB::ifCounterDiscontinuityTime' => {0 => 'NOSUCHINSTANCE'}, 'IF-MIB::ifHCOutOctets' => {1 => 0, 2 => 1828306359704, 3 => 1002545943585, 4 => 'ENDOFMIBVIEW'}, - + # Tables to test partial and full OIDs - '.1.3.6.1.4.1.171.12.1.1.12' => {1 => 'partial', 2 => 'oid', 3 => 'data'}, - '.100.3.6.1.4.1.171.12.1.1.12' => {2 => 'full', 3 => 'oid', 4 => 'leaf'}, + '.1.3.6.1.4.1.171.12.1.1.12' => {1 => 'partial', 2 => 'oid', 3 => 'data'}, + '.100.3.6.1.4.1.171.12.1.1.12' => {2 => 'full', 3 => 'oid', 4 => 'leaf'}, }; # Load cache with data to for initial tests @@ -1418,13 +1436,13 @@ sub private_load_attr : Tests(18) { cmp_deeply($test->{info}->cache(), $expected_cache, 'Cache contains expected data'); - + # Test OID based table fetches # This is from Layer3::DLink will only partially resolve $test->{info}{funcs}{partial_oid} = '.1.3.6.1.4.1.171.12.1.1.12'; my $expected_p_oid_data = {1 => 'partial', 2 => 'oid', 3 => 'data'}; - + cmp_deeply($test->{info}->partial_oid(), $expected_p_oid_data, 'Partial translated OID leaf returns expected data'); @@ -1432,7 +1450,7 @@ sub private_load_attr : Tests(18) { $test->{info}{funcs}{full_oid} = '.100.3.6.1.4.1.171.12.1.1.12'; my $expected_f_oid_data = {2 => 'full', 3 => 'oid', 4 => 'leaf'}; - + cmp_deeply($test->{info}->full_oid(), $expected_f_oid_data, 'Full OID leaf returns expected data'); }