Tôi chưa bao giờ tìm được giải pháp hoàn hảo cho điều này. Net :: SNMP :: Message (một phần của Net::SNMP) có thể cho phép điều này nhưng dường như không có giao diện được xác định công khai và không giao diện Net :: SNMP nào có vẻ đặc biệt phù hợp. NSNMP là gần với tinh thần của những gì tôi đang tìm kiếm, nhưng nó giòn và không làm việc cho gói của tôi ra khỏi hộp và nếu tôi sẽ hỗ trợ mã giòn, nó sẽ là mã giòn của riêng tôi =).
Mon::SNMP cũng gần với những gì tôi đang tìm kiếm, nhưng nó cũng bị phá vỡ khỏi hộp. Nó dường như bị bỏ rơi, với bản phát hành cuối cùng vào năm 2001 và bản phát hành CPAN cuối cùng của nhà phát triển vào năm 2002. Tôi đã không nhận ra nó vào lúc đó nhưng bây giờ tôi nghĩ rằng nó bị hỏng do thay đổi giao diện cho Convert :: BER mô-đun mà nó sử dụng.
Thứ hai :: SNMP cho tôi chỉ về phía Convert::BER. Một vài nghìn lần đọc của Convert :: BER POD, Mon :: SNMP source, và RFC 1157 (đặc biệt là 4.1.6, "The Trap-PDU") sau đó và tôi đã đưa ra mã này như là một bằng chứng về khái niệm để làm những gì tôi muốn. Đây chỉ là bằng chứng của khái niệm (vì lý do tôi sẽ chi tiết sau mã) vì vậy nó có thể không hoàn hảo, nhưng tôi nghĩ nó có thể cung cấp tài liệu tham khảo hữu ích cho những người Perl trong tương lai làm việc trong lĩnh vực này, vì vậy đây là:
#!/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;
}
Vì vậy, đó là nó. Đây là kicker. Tôi đã sử dụng từ khóa của họ rằng họ không nhận được IP của người gửi ban đầu trong cái bẫy. Trong khi làm việc thông qua ví dụ này, tôi thấy rằng, ít nhất là trong ví dụ họ đã cho tôi, IP ban đầu là trong lĩnh vực đại lý-addr trong cái bẫy.Sau khi cho họ thấy điều này và ở đâu trong API của công cụ mà họ sử dụng, chúng sẽ bị lộ ra để cố gắng thay đổi kết thúc. Tôi đang giải mã đoạn mã trên chống lại thời gian họ hỏi tôi về một thứ mà tôi thực sự cần muck trong gói, nhưng bây giờ ở trên sẽ vẫn không được kiểm tra nghiêm ngặt bằng chứng về mã khái niệm. Hy vọng nó sẽ giúp ai đó một ngày nào đó.
Tôi không biết gì về 'SNMP' nhưng' Net-SNMP' có lớp 'Net :: SNMP :: Message'. –