📄 collector.pl
字号:
#!/usr/bin/perl -w# This is a Cisco NetFlow datagram collector# Netflow protocol reference:# http://www.cisco.com/univercd/cc/td/doc/product/rtrmgmt/nfc/nfc_3_0/nfc_ug/nfcform.htm# XXX Doesn't support NetFlow 9my $af;BEGIN { use strict; use warnings; use IO qw(Socket); use Socket; use Carp; use POSIX qw(strftime); use Getopt::Long; eval "use IO::Socket::INET6;"; eval "use Socket6;";}############################################################################sub timestamp(){ return strftime "%Y-%m-%dT%H:%M:%S", localtime;}sub fuptime($){ my $t = shift; my $r = ""; my $tmp; # Milliseconds $tmp = $t % 1000; $r = sprintf ".%03u%s", $tmp, $r; # Seconds $t = int($t / 1000); $tmp = $t % 60; $r = "${tmp}s${r}"; # Minutes $t = int($t / 60); $tmp = $t % 60; $r = "${tmp}m${r}" if $tmp; # Hours $t = int($t / 60); $tmp = $t % 24; $r = "${tmp}h${r}" if $tmp; # Days $t = int($t / 24); $tmp = $t % 7; $r = "${tmp}d${r}" if $tmp; # Weeks $t = int($t / 7); $tmp = $t % 52; $r = "${tmp}w${r}" if $tmp; # Years $t = int($t / 52); $r = "${tmp}y${r}" if $tmp; return $r;}sub do_listen($$){ my $port = shift or confess "No UDP port specified"; my $socket; if ($af == 4) { $socket = IO::Socket::INET->new(Proto=>'udp', LocalPort=>$port) or croak "Couldn't open UDP socket: $!"; } elsif ($af == 6) { $socket = IO::Socket::INET6->new(Proto=>'udp', LocalPort=>$port) or croak "Couldn't open UDP socket: $!"; } else { croak "Unsupported AF"; } return $socket;}sub process_nf_v1($$){ my $sender = shift; my $pkt = shift; my %header; my %flow; my $sender_s; %header = qw(); $sender_s = inet_ntoa($sender) if $af == 4; $sender_s = inet_ntop(AF_INET6, $sender) if $af == 6; ($header{ver}, $header{flows}, $header{uptime}, $header{secs}, $header{nsecs}) = unpack("nnNNN", $pkt); if (length($pkt) < (16 + (48 * $header{flows}))) { printf STDERR timestamp()." Short Netflow v.1 packet: %d < %d\n", length($pkt), 16 + (48 * $header{flows}); return; } printf timestamp() . " HEADER v.%u (%u flow%s)\n", $header{ver}, $header{flows}, $header{flows} == 1 ? "" : "s"; for(my $i = 0; $i < $header{flows}; $i++) { my $off = 16 + (48 * $i); my $ptr = substr($pkt, $off, 52); %flow = qw(); (my $src1, my $src2, my $src3, my $src4, my $dst1, my $dst2, my $dst3, my $dst4, my $nxt1, my $nxt2, my $nxt3, my $nxt4, $flow{in_ndx}, $flow{out_ndx}, $flow{pkts}, $flow{bytes}, $flow{start}, $flow{finish}, $flow{src_port}, $flow{dst_port}, my $pad1, $flow{protocol}, $flow{tos}, $flow{tcp_flags}) = unpack("CCCCCCCCCCCCnnNNNNnnnCCC", $ptr); $flow{src} = sprintf "%u.%u.%u.%u", $src1, $src2, $src3, $src4; $flow{dst} = sprintf "%u.%u.%u.%u", $dst1, $dst2, $dst3, $dst4; $flow{nxt} = sprintf "%u.%u.%u.%u", $nxt1, $nxt2, $nxt3, $nxt4; printf timestamp() . " " . "from %s started %s finish %s proto %u %s:%u > %s:%u %u " . "packets %u octets\n", $sender_s, fuptime($flow{start}), fuptime($flow{finish}), $flow{protocol}, $flow{src}, $flow{src_port}, $flow{dst}, $flow{dst_port}, $flow{pkts}, $flow{bytes}; }}sub process_nf_v5($$){ my $sender = shift; my $pkt = shift; my %header; my %flow; my $sender_s; %header = qw(); $sender_s = inet_ntoa($sender) if $af == 4; $sender_s = inet_ntop(AF_INET6, $sender) if $af == 6; ($header{ver}, $header{flows}, $header{uptime}, $header{secs}, $header{nsecs}, $header{flow_seq}, ) = unpack("nnNNNN", $pkt); if (length($pkt) < (24 + (48 * $header{flows}))) { printf STDERR timestamp()." Short Netflow v.1 packet: %d < %d\n", length($pkt), 24 + (48 * $header{flows}); return; } printf timestamp() . " HEADER v.%u (%u flow%s) seq %u\n", $header{ver}, $header{flows}, $header{flows} == 1 ? "" : "s", $header{flow_seq}; for(my $i = 0; $i < $header{flows}; $i++) { my $off = 24 + (48 * $i); my $ptr = substr($pkt, $off, 52); %flow = qw(); (my $src1, my $src2, my $src3, my $src4, my $dst1, my $dst2, my $dst3, my $dst4, my $nxt1, my $nxt2, my $nxt3, my $nxt4, $flow{in_ndx}, $flow{out_ndx}, $flow{pkts}, $flow{bytes}, $flow{start}, $flow{finish}, $flow{src_port}, $flow{dst_port}, my $pad1, $flow{tcp_flags}, $flow{protocol}, $flow{tos}, $flow{src_as}, $flow{dst_as}, $flow{src_mask}, $flow{dst_mask}) = unpack("CCCCCCCCCCCCnnNNNNnnCCCCnnCC", $ptr); $flow{src} = sprintf "%u.%u.%u.%u", $src1, $src2, $src3, $src4; $flow{dst} = sprintf "%u.%u.%u.%u", $dst1, $dst2, $dst3, $dst4; $flow{nxt} = sprintf "%u.%u.%u.%u", $nxt1, $nxt2, $nxt3, $nxt4; printf timestamp() . " " . "from %s started %s finish %s proto %u %s:%u > %s:%u %u " . "packets %u octets\n", $sender_s, fuptime($flow{start}), fuptime($flow{finish}), $flow{protocol}, $flow{src}, $flow{src_port}, $flow{dst}, $flow{dst_port}, $flow{pkts}, $flow{bytes}; }}############################################################################# Commandline optionsmy $debug = 0;my $af4 = 0;my $af6 = 0;my $port;# Long option Short optionGetOptions( 'debug+' => \$debug, 'd+' => \$debug, '4+' => \$af4, '6+' => \$af6, 'port=i' => \$port, 'p=i' => \$port);# Unbuffer output$| = 1;die "The -4 and -6 are mutually exclusive\n" if $af4 && $af6;die "You must specify a port (collector.pl -p XXX).\n" unless $port;$af4 = $af = 4 if $af4 || (!$af4 && !$af6);$af6 = $af = 6 if $af6;# These modules aren't standard everywhere, so load them only if necessary# Main loop - receive and process a packetfor (;;) { my $socket; my $from; my $payload; my $ver; my $failcount = 0; my $netflow; my $junk; my $sender; # Open the listening port if we haven't already $socket = do_listen($port, $af) unless defined $socket; # Fetch a packet $from = $socket->recv($payload, 8192, 0); ($junk, $sender) = unpack_sockaddr_in($from) if $af4; ($junk, $sender) = unpack_sockaddr_in6($from) if $af6; # Reopen listening socket on error if (!defined $from) { $socket->close; undef $socket; $failcount++; die "Couldn't recv: $!\n" if ($failcount > 5); next; # Socket will be reopened at start of loop } if (length($payload) < 16) { printf STDERR timestamp()." Short packet recevied: %d < 16\n", length($payload); next; } # The version is always the first 16 bits of the packet ($ver) = unpack("n", $payload); if ($ver == 1) { process_nf_v1($sender, $payload); } elsif ($ver == 5) { process_nf_v5($sender, $payload); } else { printf STDERR timestamp()." Unsupported netflow version %d\n", $ver; next; } undef $payload; next; }exit 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -