use
Dancer
qw/:syntax :script/
;
our
@EXPORT
= ();
our
@EXPORT_OK
=
qw/
fixup_device_auth get_communities snmp_comm_reindex
/
;
our
%EXPORT_TAGS
= (
all
=> \
@EXPORT_OK
);
sub
fixup_device_auth {
my
$config
= (setting(
'snmp_auth'
) || setting(
'device_auth'
));
my
@new_stanzas
= ();
foreach
my
$stanza
(
@$config
) {
my
$tag
=
''
;
if
(1 ==
scalar
keys
%$stanza
) {
$tag
= (
keys
%$stanza
)[0];
$stanza
=
$stanza
->{
$tag
};
if
(
$tag
eq
'community'
) {
$tag
=
$stanza
;
$stanza
= {
community
=>
$tag
};
}
}
$stanza
->{tag} ||=
$tag
;
$stanza
->{
read
} = 1
if
!
exists
$stanza
->{
read
};
$stanza
->{
no
} ||= [];
$stanza
->{only} ||= [
'any'
];
die
"error: config: snmpv2 community in device_auth must be single item, not list\n"
if
ref
$stanza
->{community};
die
"error: config: stanza in device_auth must have a tag\n"
if
not
$stanza
->{tag} and
exists
$stanza
->{user};
push
@new_stanzas
,
$stanza
}
push
@new_stanzas
,
map
{{
read
=> 1,
write
=> 0,
no
=> [],
only
=> [
'any'
],
community
=>
$_
,
}} @{setting(
'community'
) || []};
push
@new_stanzas
,
map
{{
write
=> 1,
read
=> 0,
no
=> [],
only
=> [
'any'
],
community
=>
$_
,
}} @{setting(
'community_rw'
) || []};
foreach
my
$stanza
(
@new_stanzas
) {
$stanza
->{driver} ||=
'snmp'
if
exists
$stanza
->{community}
or
exists
$stanza
->{user};
}
return
@new_stanzas
;
}
sub
get_communities {
my
(
$device
,
$mode
) =
@_
;
$mode
||=
'read'
;
my
$seen_tags
= {};
my
$config
= (setting(
'device_auth'
) || []);
my
@communities
= ();
push
@communities
, _get_external_community(
$device
,
$mode
)
if
setting(
'get_community'
) and
length
setting(
'get_community'
);
my
$tag_name
=
'snmp_auth_tag_'
.
$mode
;
my
$stored_tag
=
eval
{
$device
->community->
$tag_name
};
if
(
$device
->in_storage and
$stored_tag
) {
foreach
my
$stanza
(
@$config
) {
if
(
$stanza
->{tag} and
$stored_tag
eq
$stanza
->{tag}) {
push
@communities
, {
%$stanza
,
only
=> [
$device
->ip]};
last
;
}
}
}
push
@communities
, {
read
=> 1,
write
=> 0,
driver
=>
'snmp'
,
only
=> [
$device
->ip],
community
=>
$device
->snmp_comm,
}
if
defined
$device
->snmp_comm and
$mode
eq
'read'
;
my
$snmp_comm_rw
=
eval
{
$device
->community->snmp_comm_rw };
push
@communities
, {
write
=> 1,
read
=> 0,
driver
=>
'snmp'
,
only
=> [
$device
->ip],
community
=>
$snmp_comm_rw
,
}
if
$snmp_comm_rw
and
$mode
eq
'write'
;
eval
{
$device
->community->update({
$tag_name
=>
undef
}) }
if
$device
->in_storage
and (not
$stored_tag
or !
exists
$seen_tags
->{
$stored_tag
});
return
(
@communities
,
@$config
);
}
sub
_get_external_community {
my
(
$device
,
$mode
) =
@_
;
my
$cmd
= setting(
'get_community'
);
my
$ip
=
$device
->ip;
my
$host
= (
$device
->dns || hostname_from_ip(
$ip
) ||
$ip
);
if
(
defined
$cmd
and
length
$cmd
) {
$cmd
=~ s/\
%HOST
\%/
$host
/egi;
$cmd
=~ s/\
%IP
\%/
$ip
/egi;
my
$result
= `
$cmd
`;
return
()
unless
defined
$result
and
length
$result
;
my
@lines
=
split
(m/\n/,
$result
);
foreach
my
$line
(
@lines
) {
if
(
$line
=~ m/^community\s*=\s*(.*)\s*$/i) {
if
(
length
$1 and
$mode
eq
'read'
) {
return
map
{{
read
=> 1,
only
=> [
$device
->ip],
community
=>
$_
,
}}
split
(m/\s*,\s*/,$1);
}
}
elsif
(
$line
=~ m/^setCommunity\s*=\s*(.*)\s*$/i) {
if
(
length
$1 and
$mode
eq
'write'
) {
return
map
{{
write
=> 1,
only
=> [
$device
->ip],
community
=>
$_
,
}}
split
(m/\s*,\s*/,$1);
}
}
}
}
return
();
}
sub
snmp_comm_reindex {
my
(
$snmp
,
$device
,
$vlan
) =
@_
;
my
$ver
=
$snmp
->snmp_ver;
if
(
$ver
== 3) {
my
$prefix
=
''
;
my
@comms
= get_communities(
$device
,
'read'
);
foreach
my
$c
(
@comms
) {
next
unless
$c
->{tag}
and
$c
->{tag} eq (
eval
{
$device
->community->snmp_auth_tag_read } ||
''
);
$prefix
=
$c
->{context_prefix} and
last
;
}
$prefix
||=
'vlan-'
;
debug
sprintf
'[%s] reindexing to "%s%s" (ver: %s, class: %s)'
,
$device
->ip,
$prefix
,
$vlan
,
$ver
,
$snmp
->class;
$vlan
?
$snmp
->update(
Context
=> (
$prefix
.
$vlan
))
:
$snmp
->update(
Context
=>
''
);
}
else
{
my
$comm
=
$snmp
->snmp_comm;
debug
sprintf
'[%s] reindexing to vlan %s (ver: %s, class: %s)'
,
$device
->ip,
$vlan
,
$ver
,
$snmp
->class;
$vlan
?
$snmp
->update(
Community
=>
$comm
.
'@'
.
$vlan
)
:
$snmp
->update(
Community
=>
$comm
);
}
}
true;