#!/usr/bin/perl -w # Copyright (C) 2009-2010 Pierre Chifflier # # This program is free software; you can redistribute it and/or modify # it under the same terms as Perl itself, either Perl version 5.8.4 or, # at your option, any later version of Perl 5 you may have available. use strict; use IO::Socket; use Net::Pcap; my $ULOGD_SOCKET_MARK = 0x41c90fd4; my $dumpfile = shift or die "Unable to open pcap file"; my($pcap_t, $err); my($ulogd_client); my $socketfile = "/var/run/ulogd2.sock"; my $data_buffer; my $linktype; my $proto_offset; my %linktype_to_offset = ( Net::Pcap::DLT_LINUX_SLL => 14, Net::Pcap::DLT_EN10MB => 12, ); sub connect_ulogd2 { (-S $socketfile) or die "ulogd2 socket $socketfile does not exist - is ulogd running ?"; $ulogd_client = IO::Socket::UNIX->new(Peer => $socketfile, Type => SOCK_STREAM ) or die $!; $ulogd_client->autoflush(0); } sub print_padding { my ($offset) = @_; my $padding; my $align = 8; my $data; $padding = ($align - ($offset % $align)) % $align; #print "offset: $offset padding $padding\n"; $data = "\0" x $padding; $data_buffer .= $data; } sub process_pkt { my($user, $hdr, $pkt) = @_; if (($user ne "xyz") or !defined($hdr) or !defined($pkt)) { print("Bad args passed to callback\n"); print("Bad user data\n"), if ($user ne "xyz"); print("Bad pkthdr\n"), if (!defined($hdr)); print("Bad pkt data\n"), if (!defined($pkt)); print("not ok\n"); exit; } #print "Header: len $hdr->{len}\n"; #my $len = length $pkt; #print "Packet length: $len\n"; my $size = length($pkt) - ($proto_offset+2); #my $pcaphdr = unpack ("H*", substr ($pkt, 0, 16)); #printf("pcap hdr: $pcaphdr\n"); my $proto = unpack ("H*", substr ($pkt, $proto_offset, 2)); #printf("proto: $proto\n"); if ($proto ne "0800") { print "ignoring packet with proto $proto\n"; return; } #my $ip_firstbyte = unpack ("H*", substr ($pkt, $proto_offset+2, 2)); #printf("ip_firstbyte: $ip_firstbyte\n"); # decode packet for a SLL: # packet type (sent by us: 4) # link layer address type: 1 # link layer address length: 6 # src dst # protocol (IP, ARP, PPP, SNMP ...) # data my $srcmac = substr ($pkt, 6, 6); (my $hex_src = unpack("H*", $srcmac)) =~ s/(..)/$1:/g; chop $hex_src; #printf "source mac: $hex_src\n"; my $hex_dst = "\0"; # format data my $data; $data_buffer = undef; # ulogd packet signature $data = pack ('N', $ULOGD_SOCKET_MARK); $data_buffer .= $data; my $options_num=2; my $options_len=length($hex_src) + length($hex_dst); # total length (will be filled later) my $total_size = 0; $data = pack ('n', $total_size); $data_buffer .= $data; # reserved + payload length + payload $data = pack ('Nna*', 0, $size, substr($pkt,$proto_offset+2,$size)); $data_buffer .= $data; print_padding($size); # options my $OOB_IN = 2; $data = pack ('NNa*', $OOB_IN, length($hex_src), $hex_src); $data_buffer .= $data; print_padding(length($hex_src)); my $OOB_OUT = 3; $data = pack ('NNa*', $OOB_OUT, length($hex_dst), $hex_dst); $data_buffer .= $data; print_padding(length($hex_dst)); # replace total size in buffer my $l = length($data_buffer) - 4; substr($data_buffer, 4, 2) = pack('n', $l); #(my $hex = unpack("H*", $data_buffer)) =~ s/(..)/$1 /g; #print "$l will be encoded as " . unpack("H*", pack('n', $l)) . "\n"; #print $hex, "\n"; print $ulogd_client $data_buffer; $ulogd_client->flush; #exit; } connect_ulogd2 or die $!; $pcap_t = Net::Pcap::open_offline($dumpfile, \$err); if (!defined($pcap_t)) { print("Net::Pcap::dump_open failed: ", Net::Pcap::geterr($pcap_t), "\n"); exit; } $linktype = Net::Pcap::pcap_datalink($pcap_t); if (not exists $linktype_to_offset{$linktype}) { print("Unsupported link type ", Net::Pcap::pcap_datalink_val_to_name($linktype), "\n"); exit 1; } $proto_offset = $linktype_to_offset{$linktype}; Net::Pcap::loop($pcap_t, -1, \&process_pkt, "xyz"); Net::Pcap::close($pcap_t);