I've put together a perl script that reads packets into userspace via Linux::TunTap, and it all seems to work fine:
#!/usr/bin/perl
use warnings;
use strict;
use Linux::TunTap;
$tun = new Linux::TunTap(NAME => 'localtun')
or die "Couldn't connect to IF\n";
while (my $packet = $tun->get_raw()) {
print Dumper($packet);
}
Now the question is: How do I turn the string representing the raw IP packet as read from the tuntap device into a proper datastructure for processing? In particular I'm after the source, destination, and sequence number.
Obviously, the raw IP packet isn't very human readable in its original format. Here's the output after sending a ping through the tuntap interface:
{{{�}/��8V�| !"#$%&'()*+,-./0123456ET��@@4
How do I proceed from here to be able to process this data programatically?
Based on the comment made by SteffenUlrich, I had a look at NetPacket::IP, which did the trick for me through its decode()
method. It worked pretty much out of the box after baking it into my code, with the only caveat being that the first four bytes has to go from the raw data (see lazy regex below), as these bytes form an additional header added by the TunTap layer.
My code now looks like this, and works as intended:
#!/usr/bin/perl
use warnings;
use strict;
use Linux::TunTap;
use NetPacket::IP;
$tun = new Linux::TunTap(NAME => 'localtun')
or die "Couldn't connect to IF\n";
while (my $rawdata = $tun->get_raw()) {
$rawdata =~ s/^....//; # Using regex to strip 4 bytes, because I'm lazy
my $packet = NetPacket::IP->decode($rawdata);
print "$packet->{id} $packet->{src_ip} -> $packet->{dest_ip} $packet->{proto} $packet->{len}\n";
}
The above code prints the sequence, source IP, destination IP, protocol number, and packet length.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With