Question

Il y a quelques semaines j'ai écrit un Relayer SNMP pour notre groupe d'opérations. Ils ont des dispositifs muets qui ne peuvent envoyer des interruptions à une seule adresse IP, et nous avons un système de surveillance qui écoute sur plusieurs adresses IP pour la disponibilité. mort simple du code, et essentiellement:

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

Il a travaillé, au fond, mais maintenant l'évidence courte à venir qu'il ne comprend pas l'origine IP est un problème (apparemment la première classe de dispositif inclus l'information comme varbind et une nouvelle classe ne fonctionne pas).

Ce que je voudrais faire est de changer mon code à quelque chose comme ceci:

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);
  }
}

En d'autres termes, si mon expéditeur n'inclut pas snmpTrapAddress, ajoutez-le. Le problème est que chaque paquet SNMP je l'ai regardé pour Perl semble très fortement axé sur l'infrastructure de réception des pièges et l'exécution devient.

Alors: est-il d'un simple module Perl qui me permettra de dire « voici un blob de données représentant un piège snmp décodent dans quelque chose que je peux facilement manipuler, puis recompiler de nouveau dans un blob je peux jeter sur le réseau. « ?

Si la réponse que vous donnez est « l'utilisation factice SNMP », pouvez-vous donner des exemples de cela? Je peux juste être aveugle, mais depuis la sortie de perldoc SNMP il est pas évident pour moi comment l'utiliser de cette manière.

EDIT:

Turns out après avoir regardé autour d'un bit que "SNMP encodage" est vraiment ASN.1 BER (Basic Encoding Rules). Sur la base de ce que je vais avoir un aller avec Convert :: BER. Je voudrais encore accueillir une pause facile vers le bas / éditer / reconstruire des conseils pour SNMP.

Était-ce utile?

La solution

Je ne ai jamais trouvé une solution parfaite à ce sujet. Net :: SNMP :: Message (partie de Net :: SNMP ) pourrait permettre cela, mais ne semble pas avoir une interface publique définie, et aucune de l'interface net :: SNMP semblait particulièrement pertinent. NSNMP est le plus proche de l'esprit de ce que je cherchais, mais il est fragile et ne fonctionne pas pour mon paquet hors de la boîte et si je vais supporter le code fragile, il va être mon propre code fragile =).

:: Mon SNMP a également obtenu près de ce que Je cherchais, mais aussi était cassé hors de la boîte. Il semble être abandonné, avec la dernière version en 2001 et la dernière version CPAN du développeur en 2002. Je ne savais pas à l'époque mais je pense maintenant qu'il est brisé à cause d'un changement dans l'interface du Convert :: BER le module qu'il utilise.

Mon :: SNMP a pointé vers moi Convert :: BER . Quelques milliers de lectures du Convert :: BER POD, la source Mon :: SNMP et RFC 1157 (esp. 4.1.6, « Le piège-PDU ») plus tard et je suis venu avec ce code comme une preuve de concept à faire ce que je voulais. Ceci est la preuve que concept (pour des raisons que je détaillerai après le code) de sorte qu'il ne peut pas être parfait, mais je pense qu'il pourrait fournir une référence utile pour les personnes à venir Perl travaillant dans ce domaine, donc la voici:

#!/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;  
}

Alors, voilà. Voici le kicker. Je pris ops à leur parole qu'ils ne reçoivent pas l'adresse IP de l'expéditeur d'origine dans le piège. Tout en travaillant à travers cet exemple, je trouve que, au moins dans l'exemple on m'a donné, l'IP était d'origine dans le domaine agent adr dans le piège. Après leur montrer cela et où dans l'API de l'outil leur utilisation de c'est exposé, ils sont partis pour essayer de faire le changement à leur fin. Je daving le code ci-dessus contre le temps, ils me demandent quelque chose que je dois en fait muck dans le paquet pour, mais pour l'instant ce qui précède restera une preuve non rigoureusement testé du code concept. Il aide quelqu'un l'espoir un jour.

Autres conseils

Avez-vous essayé NSNMP ?

vérifier définitivement SNMP_Session.

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

Assurez-vous de suivre les liens vers l'ancien site de distribution qui a plusieurs exemples.

J'ai essentiellement parcouru le même chemin à travers Mon :: SNMP, Convert :: BER, TCP / IP Illustrated, etc .. SNMP_Session est la seule chose que je suis en mesure de faire le travail. Par le travail, je veux dire accepter un piège SNMP sur le port UDP 162 et le décoder en équivalents de chaîne pour l'enregistrement sans réinventer plusieurs roues. Je suis seulement en utilisant la fonctionnalité de réception de piège, mais je pense qu'il peut faire ce que vous voulez aussi.

Il est sur Google Code, pas CPAN, donc il est un peu difficile à trouver.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top