#!/usr/bin/perl

###################################
#                                 #
# Simple NetFlow v5 packet parser #
# for ipt_NETFLOW                 #
#            by Alexander Ptitsyn #
#                  modified by Fd #
# v0.001                 (c) 2009 #
#                                 #
###################################

use strict;
use warnings;
use IO::Socket;

my ($packet, $sourceAddress, $sourcePort, $sourceMaskPrefix, $destinationAddress, $destinationPort,
	$destinationMaskPrefix, $packets, $octets, $proto, $tcpFlags, $typeOfService, $sourceAS,
	$destinationAS, $nextHop, $snmpIn, $snmpOut, $systemUptimeFlowStart, $systemUptimeFlowStop);


my %config = (
				hostname => 'localhost',
				port	 => 2055,
				proto	 => 'udp',

				headerTemplate => 'nnNNNNCCn',
				footerTemplate => 'NNNnnNNNNnnCCCCnnCCn',
			);

my $sockObj = IO::Socket::INET->new(
						LocalHost	=> $config{hostname},
						LocalPort	=> $config{port},
						Proto		=> $config{proto},
				) || die "Can't open socket: $!";

while ($sockObj->recv($packet,1464)) {

        my @header = unpack $config{headerTemplate}, $packet;

        my ($flowVersion, $flowCount, $flowSysUptime, $flowUnixSeconds, $flowUnixNanoseconds,
        	$flowSequence, $flowEngineType, $flowEngineID, $flowSamplingInterval) = (@header)[0..8];

        die $! if $flowVersion != 5 && ($flowCount < 0 || $flowCount > 30);

        my $Template = $config{headerTemplate};
        $Template .= $config{footerTemplate} for 0 .. $flowCount;

        my @flow = unpack $Template, $packet;

        if ($flowCount > 0) {
                for (my $i = 0; $i < $flowCount; $i++) {
                        $sourceAddress 			= ip_to_str($flow[9+$i*20]);
                        $sourcePort 			= $flow[18+$i*20];
                        $sourceMaskPrefix 		= $flow[26+$i*20];

                        $destinationAddress 		= ip_to_str($flow[10+$i*20]);
                        $destinationPort 		= $flow[19+$i*20];
                        $destinationMaskPrefix 		= $flow[27+$i*20];

                        $packets 			= $flow[14+$i*20];
                        $octets 			= $flow[15+$i*20];

                        $proto 				= $flow[22+$i*20];
                        $tcpFlags 			= $flow[21+$i*20];
                        $typeOfService 			= $flow[23+$i*20];

                        $sourceAS 			= $flow[24+$i*20];
                        $destinationAS 			= $flow[25+$i*20];

                        $nextHop 			= $flow[11+$i*20];
                        $snmpIn 			= $flow[12+$i*20];
                        $snmpOut 			= $flow[13+$i*20];

                        $systemUptimeFlowStart 		= $flow[16+$i*20];
                        $systemUptimeFlowStop 		= $flow[17+$i*20];
                }
        }
}

sub ip_to_str { inet_ntoa( pack( 'N', shift )); }


__END__

Bytes		Contents		Description

0-1		version			NetFlow export format version number
2-3		count			Number of flows exported in this packet (1-30)
4-7		sys_uptime		Current time in milliseconds since the export device booted
8-11		unix_secs		Current count of seconds since 0000 UTC 1970
12-15		unix_nsecs		Residual nanoseconds since 0000 UTC 1970
16-19		flow_sequence		Sequence counter of total flows seen
20		engine_type		Type of flow-switching engine
21		engine_id		Slot number of the flow-switching engine
22-23		sampling_interval	First two bits hold the sampling mode; remaining 14 bits hold value of sampling interval

Flow record format
Bytes		Contents		Description

0-3		srcaddr			Source IP address
4-7		dstaddr			Destination IP address
8-11		nexthop			IP address of next hop router
12-13		input			SNMP index of input interface
14-15		output			SNMP index of output interface
16-19		dPkts			Packets in the flow
20-23		dOctets			Total number of Layer 3 bytes in the packets of the flow
24-27		first			SysUptime at start of flow
28-31		last			SysUptime at the time the last packet of the flow was received
32-33		srcport			TCP/UDP source port number or equivalent
34-35		dstport			TCP/UDP destination port number or equivalent
36		pad1			Unused (zero) bytes
37		tcp_flags		Cumulative OR of TCP flags
38		prot			IP protocol type (for example, TCP = 6; UDP = 17)
39		tos			IP type of service (ToS)
40-41		src_as			Autonomous system number of the source, either origin or peer
42-43		dst_as			Autonomous system number of the destination, either origin or peer
44		src_mask		Source address prefix mask bits
45		dst_mask		Destination address prefix mask bits
46-47		pad2			Unused (zero) bytes