Frage

Vor ein paar Wochen schrieb ich einen SNMP relayer für unsere ops Gruppe. Sie haben einige dumme Geräte, die nur Traps an eine einzelne IP senden können, und wir haben ein Überwachungssystem, das auf mehrere IPs für die Verfügbarkeit zuhört. Der Code des Toten einfach, und im Wesentlichen:

while (recv($packet)) {
  foreach $target (@targets) {
    send($target, $packet);
  }
}

Es gearbeitet hat, im Grunde, aber jetzt ist das offensichtlich kurz kommt, dass es nicht den Urheber nicht enthalten IP ist ein Thema (anscheinend die erste Klasse der Vorrichtung enthalten die Informationen als varbind und eine neue Klasse nicht).

Was würde ich tun möchte, ist der Code so etwas wie dies zu ändern:

while ($server->recv($packet)) {
  my $obj = decompile($packet)
  if (!$obj->{varbind}{snmpTrapAddress}) {
    $obj->{varbind}{snmpTrapAddress} = inet_ntoa($server->peeraddr());
  }
  $packet = compile($obj);
  foreach $target (@targets) {
    send($target, $packet);
  }
}

Mit anderen Worten, wenn mein Absender ohne snmpTrapAddress ist, fügen Sie es. Das Problem ist, dass jedes SNMP-Paket ich für Perl geschaut habe sehr stark fokussiert scheint Fallen auf der Infrastruktur des Empfangens und Durchführung wird.

Also: Gibt es ein einfaches Perl-Modul, das mir „hier ist ein Klecks von Daten, die eine SNMP-Trap zu sagen, wird es ermöglichen, in etwas entschlüsselt ich leicht manipulieren kann, dann ist es neu kompiliert einen Blob zurück in ich über das Netzwerk werfen. „?

Wenn die Antwort, die Sie geben, ist „Verwendung von SNMP Dummy“, können Sie Beispiele dafür bieten? Ich kann nur blind sein, aber von dem Ausgang der Perldoc SNMP es mir nicht klar ist, wie man verwenden sie es auf diese Weise.

EDIT:

Es stellte sich heraus, nachdem sich ein wenig suchen, dass "SNMP-Codierung" ist wirklich ASN.1 BER (Basic Encoding Rules). Auf dieser Grundlage habe ich einen gehen mit Convert :: BER. Ich würde es begrüßen, noch jede einfache Bruchs / bearbeiten / rebuild Tipps für SNMP.

War es hilfreich?

Lösung

Ich habe nie eine perfekte Lösung für dieses Problem. Net :: SNMP :: Message (Teil Net :: SNMP ) könnte dies ermöglichen, aber scheint nicht eine öffentlich definierte Schnittstelle zu haben, und keiner der Net :: SNMP-Schnittstelle schien besonders relevant. NSNMP am nächsten ist, den Geist von dem, was ich suchte, aber es ist spröde und nicht für mein Paket aus der Box nicht funktionierte und wenn ich spröde Code unterstützen werde, es wird mein eigener spröden Code =) sein.

Mon :: SNMP bekam auch in der Nähe zu dem, was ich suchte, aber es wurde aus dem Kasten heraus zu gebrochen. Es scheint mit der letzten Veröffentlichung im Jahr 2001 aufgegeben, zu sein und die letzten CPAN Release Entwickler im Jahr 2002 ich es nicht an der Zeit ahnte, aber ich denke jetzt, dass es aufgrund einer Änderung in der Schnittstelle zum Konvertieren gebrochen ist :: BER Modul verwendet es.

Mon :: SNMP hat mich deutete auf Convert :: BER . Ein paar Tausend liest der Convert :: BER POD, die Mon :: SNMP Quelle und RFC 1157 (insb. 4.1.6, "The Trap-PDU") später und ich kam mit diesem Code als Proof of concept zu tun, was ich wollte. Dies ist nur Proof of Concept (aus Gründen werde ich ausführlich nach dem Code), so dass es nicht perfekt sein, aber ich dachte, es in diesem Bereich nützliche Referenz für zukünftige Perl Menschen bieten könnte arbeiten, so ist es hier:

#!/usr/bin/perl

use Convert::BER;
use Convert::BER qw(/^(\$|BER_)/);

my $ber = Convert::BER->new();

# OID I want to add to the trap if not already present
my $snmpTrapAddress = '1.3.6.1.6.3.18.1.3';

# this would be from the incoming socket in production
my $source_ip = '10.137.54.253';

# convert the octets into chars to match SNMP standard for IPs
my $source_ip_str = join('', map { chr($_); } split(/\./, $source_ip));

# Read the binary trap data from STDIN or ARGV.  Normally this would
# come from the UDP receiver
my $d = join('', <>);

# Stuff my trap data into $ber
$ber->buffer($d);

print STDERR "Original packet:\n";
$ber->dump();

# Just decode the first two fields so we can tell what version we're dealing with
$ber->decode(
                SEQUENCE => [
                    INTEGER => \$version,
                    STRING => \$community,
                    BER => \$rest_of_trap,
                ],
) || die "Couldn't decode packet: ".$ber->error()."\n";

if ($version == 0) {
  #print STDERR "This is a version 1 trap, proceeding\n";

  # decode the PDU up to but not including the VARBINDS
  $rest_of_trap->decode(
    [ SEQUENCE => BER_CONTEXT | BER_CONSTRUCTOR | 0x04 ] =>
      [
        OBJECT_ID => \$enterprise_oid,
        [ STRING => BER_APPLICATION | 0x00 ] => \$agentaddr,
        INTEGER => \$generic,
        INTEGER => \$specific,
        [ INTEGER => BER_APPLICATION | 0x03 ] => \$timeticks,
        SEQUENCE => [ BER => \$varbind_ber, ],
      ],
  ) || die "Couldn't decode packet: ".$extra->error()."\n";;

  # now decode the actual VARBINDS (just the OIDs really, to decode the values
  # We'd have to go to the MIBs, which I neither want nor need to do
  my($r, $t_oid, $t_val, %varbinds);
  while ($r = $varbind_ber->decode(
    SEQUENCE => [
      OBJECT_ID => \$t_oid,
      ANY       => \$t_val,
    ], ))
  {
    if (!$r) {
      die "Couldn't decode SEQUENCE: ".$extra->error()."\n";
    }
    $varbinds{$t_oid} = $t_val;
  }

  if ($varbinds{$snmpTrapAddress} || $varbinds{"$snmpTrapAddress.0"}) {
    # the original trap already had the data, just print it back out
    print $d;
  } else {
    # snmpTrapAddress isn't present, create a new object and rebuild the packet
    my $new_trap = new Convert::BER;
    $new_trap->encode(
      SEQUENCE => [
        INTEGER => $version,
        STRING => $community,
        [ SEQUENCE => BER_CONTEXT | BER_CONSTRUCTOR | 0x04 ] =>
          [
            OBJECT_ID => $enterprise_oid,
            [ STRING => BER_APPLICATION | 0x00 ] => $agentaddr,
            INTEGER => $generic,
            INTEGER => $specific,
            [ INTEGER => BER_APPLICATION | 0x03 ] => $timeticks,
            SEQUENCE => [
              BER => $varbind_ber,
              # this next oid/val is the only mod we should be making
              SEQUENCE => [
                OBJECT_ID => "$snmpTrapAddress.0",
                [ STRING => BER_APPLICATION | 0x00 ] => $source_ip_str,
              ],
            ],
          ],
      ],
    );
    print STDERR "New packet:\n";
    $new_trap->dump();
    print $new_trap->buffer;
  }
} else {
  print STDERR "I don't know how to decode non-v1 packets yet\n";
  # send back the original packet
  print $d;  
}

So, das ist es. Hier ist der Kicker. Ich nahm ops an ihrem Wort, dass sie nicht die IP-Adresse des ursprünglichen Absenders in der Falle zu bekommen. Während durch dieses Beispiel funktioniert, fand ich, dass, zumindest in dem Beispiel mir, sie gab, in dem Agent-addr Feld die ursprüngliche IP in der Falle war. sie dies und wo in der API des Werkzeugs Nach zeigen ihre Verwendung dieses ausgesetzt ist, sie ging zu versuchen, die Änderung an ihrem Ende zu machen. Ich daving den Code oben gegen die Zeit, die sie mich um etwas bitten muss ich tatsächlich in dem Paket zum Dreck, aber jetzt die oben wird nicht rigoros getestete Proof of Concept-Code bleiben. Hoffe, es hilft jemand einen Tag.

Andere Tipps

Haben Sie versucht, NSNMP ?

Auf jeden Fall überprüfen SNMP_Session.

http://code.google.com/p/snmp-session/

Achten Sie darauf, die Links auf die alte Verteilungsstelle zu folgen, die mehrere Beispiele hat.

Ich habe reiste im Grunde den gleichen Weg durch Mon :: SNMP, Konvertieren :: BER, TCP / IP Illustrated, etc .. SNMP_Session das einzige, was ich in der Lage gewesen zu arbeiten. Durch die Arbeit, ich meine einen SNMP-Trap auf UDP-Port 162 akzeptieren und dekodieren in String-Äquivalente für die Protokollierung ohne mehrere Räder neu zu erfinden. Ich verwende nur die Falle Funktionalität erhalten, aber ich denke, es kann das tun, was Sie wollen auch.

Es ist auf Google Code, nicht obwohl cpan, so ist es ein wenig schwer zu finden ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top