Greetings all;
I have a need to scratch and haven't been able to work out a good way of doing it all together in an elegant, let alone functional, way.
I need to capture and count packets coming from multiple sources, using multiple filters, in real time. Right now I just have three separate perl scripts doing the task, but I'd like to fold it into a single tool. I currently use an open() on the tcpdump tool (under Linux).
Simple psuedo-code to give you an idea what I'm up to:
$SIG{ALRM} = \&every_sec(); alarm(1);
open(PROCESS, "tcpdump -ln 'filter'"|);
while(<PROCESS>) {
next if (!&ParseIPandCheckSomething($_));
$Counter++;
}
sub every_sec {
print "This past second: $Counter\n";
$Counter = 0;
alarm(1);
}
Here are the approaches I've looked at:
Incorporating Net::Pcap and doing it the "proper" way without reading the external 'tcpdump' output... except Net::Pcap can't handle multiple instances (the filters and like are stored in a single shared variable, according to its documentation). I also require the use of a SIGALRM to keep track of per-second counts, and Net::Pcap::loop must disable this, because the alarm callback certainly isn't being called each second like it's supposed to.
Opening several 'tcpdump' filehandles and looping over reading each one. When I do this the 'real time' aspect of it goes to heck. I was trying to do a bunch of non-blocking read()s and pull in a block of bytes, jump to the next file handle, and so on, and then process completed inputted packets... but it obviously isn't either fast enough, or designed properly, because "real time" it is not.
foreach $filter (qw(filter1 filter2 filter3)) {
my $fh = FileHandle->new();
$fh->open("tcpdump -ln $filter|");
$fh->autoflush(1);
push(@FHStack, $fh);
}
while(1) {
# Read anything (up to 4096 bytes) from tcpdump
foreach my $fh (@FHStack) {
my $bytes = read($FH, my $buffer, 4096);
$PackStack{$FH} .= $buffer;
}
# Process what we've gotten, looking for a complete packet
foreach my $fh (@FHStack) {
if ($PackStack{$FH} =~ /\n/) {
# LF means completed packet received from tcpdump
$PackStack{$FH} = &ProcessPacketAndRemove($PackStack{$FH
+});
}
}
}
Boy, folks, I know there's a better way to do this, I'd sure love to hear your input.
Thanks!
-- Alexander Widdlemouse undid his bellybutton and his bum dropped off --
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.