0

I'm making a Perl plugin for Nagios for the F5 load balancer. I have to convert the pool name to a decimal format that matches the OID for SNMP.

my ( $PoolName )         = $ARGV[1];
my ( $rootOIDPoolStatus ) = '1.3.6.1.4.1.3375.2.2.5.5.2.1.2';

For example, $PoolName is "/Common/Atlassian" and I need to convert that to /.C.o.m.m.o.n./.A.t.l.a.s.s.i.a.n and then to 47.67.111.109.109.111.110.47.65.116.108.97.115.115.105.97.110

Once that has been converted they would get pulled into one variable

my ( $PoolStatus ) = "$rootOIDPoolStatus.$OIDPoolName"

I have been backwards-engineering other people's Perl plugins for Nagios and this is what someone else is doing, but I couldn't make it work no matter what kind of combinations I was doing. Their $name would be my $PoolName

sub to_oid($) {
    my $oid;
    my ($name) = $_[0];
    return "" if ( ! $name );
    $oid = ( length $name ) . '.' . ( join '.', ( map { unpack 'C', $ } ( split '',$name ) ) );
    return $oid;
}

Could someone help me to build or understand the Perl logic in order to convert $PoolName to the decimal format I need for the OID?

Borodin
  • 126,100
  • 9
  • 70
  • 144
BigD
  • 5
  • 1
  • Looks OK from here (except I don't know what `unpack 'C',$` does. Did you mean `unpack 'C',$_`? Also, `unpack 'C',$_` can be replaced by `ord($_)` or sometimes just `ord`). – mob Oct 25 '17 at 20:13
  • That lower section was from another persons script that I believe does what I'm wanting to do, but do not understand it and cannot get it to work. – BigD Oct 25 '17 at 20:37
  • `sub to_oid($)` should be just `sub to_oid`. It does no harm here, but it's an indication that you're looking at code written by someone who doesn't know any better than you do! Are you sure that you need dots `.` every other character? It may well be that the string needs to be UTF-16 encoded, and the display has converted zero bytes to dots. Do you have a reference to the appropriate part of the Nagios spec? – Borodin Oct 26 '17 at 00:15

3 Answers3

2
my $poolStatus = join '.', $rootOIDPoolStatus, map ord, split //, $poolName;

Not sure what the length() is for in your code, you don't show anything like that in your example.

ysth
  • 96,171
  • 6
  • 121
  • 214
  • The length is needed when you want to encode a string into an OID. – PerlDuck Oct 26 '17 at 08:18
  • Yeah, sorry, I totally forgot to mention that in my original post. – BigD Oct 26 '17 at 12:20
  • @BigD does that mean a length needs to be removed from $rootOIDPoolStatus and a new length added that takes into account both the status and name parts? – ysth Oct 26 '17 at 14:49
  • @ysth $rootOIDPoolStatus never had the length as that would be calculated when converting $PoolName. The length would always change while the root would stay static. PerlDuck answering this question with the proper solution I was needing. Thanks for your input though! – BigD Oct 26 '17 at 17:10
2

You seem to be using a string as an index to an SNMP table. The index of a table can be thought of as the row number or row id for that table. Often the index for a table is just a number starting from 1 and increasing with each row the table has. Such a number is encoded in the OID as is, i.e. if the table has 3 columns and two rows, they would have these OIDs:

$base.1         # table
$base.1.1       # table entry
$base.1.1.1.1   # col1, row1
$base.1.1.1.2   # col1, row2
$base.1.1.2.1   # col2, row1
$base.1.1.2.2   # col2, row2
$base.1.1.3.1   # col3, row1
$base.1.1.3.2   # col3, row2
            ^---index

Sometimes the index is an IP address, a combination of IP:port, or a combination of two IP addresses, especially for IP related tables. An IP address as index would look like this:

$base.1                 # table
$base.1.1               # table entry
$base.1.1.1.1.0.0.127   # col1, row "127.0.0.1"
$base.1.1.1.0.0.0.0     # col1, row "0.0.0.0"
$base.1.1.2.1.0.0.127   # col2, row "127.0.0.1"
$base.1.1.2.0.0.0.0     # col2, row "0.0.0.0"
$base.1.1.3.1.0.0.127   # col3, row "127.0.0.1"
$base.1.1.3.0.0.0.0     # col3, row "0.0.0.0"
            ^^^^^^^---- index

As you can see, the length of the index varies depending on its datatype (there's a dedicated IPV4 datatype).

Sometimes the index is a string (as in your case). When a string is used it must as well be somehow encoded to make up a "row number" for the table. Strings as indexes are encoded character-wise and preceeded by their length, i.e.:

$base.1                     # table
$base.1.1                   # table entry
$base.1.1.1.2.65.66         # col1, row "AB"
$base.1.1.1.3.120.121.122   # col1, row "xyz"
$base.1.1.2.2.65.66         # col2, row "AB"
$base.1.1.2.3.120.121.122   # col2, row "xyz"
$base.1.1.3.2.65.66         # col3, row "AB"
$base.1.1.3.3.120.121.122   # col3, row "xyz"
            ^^^^^^^^^^^^^---- index

So "AB" becomes "2.65.66" because length('AB')==2 and ord('A')==65, ord('B')==66. Likewise "xyz" becomes "3.120.121.122".

Your function to_oid does exactly that, although I'd simplify it as follows:

#!/usr/bin/env perl

use strict;
use warnings;

sub to_oid
{
    my $string = shift;
    return sprintf('%d.%s', length($string), join('.', unpack('C*', $string)));
}

my $rootOIDPoolStatus = '1.3.6.1.4.1.3375.2.2.5.5.2.1.2';
my $PoolName = '/Common/Atlassian';

my $poolname_oid = to_oid($PoolName);
my $complete_oid = "$rootOIDPoolStatus.$poolname_oid";

print $complete_oid, "\n";

Output:

1.3.6.1.4.1.3375.2.2.5.5.2.1.2.17.47.67.111.109.109.111.110.47.65.116.108.97.115.115.105.97.110
|<------- rootOID ----------->|<------------ poolname_oid ----...--->|
PerlDuck
  • 5,610
  • 3
  • 20
  • 39
  • Thank you very much! You went above and beyond with this. Even catching my error about how the length worked. I've been so tunnel visioned I forgot to mention it. – BigD Oct 26 '17 at 12:18
  • 1
    Tested the code and it works perfectly in Nagios now :) tyvm – BigD Oct 26 '17 at 12:20
0
my $PoolStatus = join('.', $rootOIDPoolStatus, unpack('C*', $PoolName));

or

my $PoolStatus = sprintf("%s.%vd", $rootOIDPoolStatus, $PoolName);
ikegami
  • 367,544
  • 15
  • 269
  • 518