Reading packets with Linux::TunTap
Asked Answered
I

1

6

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?

Irrefragable answered 27/9, 2015 at 0:34 Comment(4)
These are raw IP packets like described in en.wikipedia.org/wiki/IPv4 so you could use unpack or perl modules like NetPacket::IP to process them.Incomprehension
@Steffen Ullrich worked like a charm, thanks! After stripping off the TunTap header contained in the first 4 bytes of $packet, the remainder could be parsed with NetPacket::IP. Too bad one can't accept a comment as answer.Irrefragable
If @SteffenUllrich doesn't write one, you can always write your own answer explaining what you did, give credit to his comment and make the answer community wiki. :)Cordeelia
Yes, I recommend you do your own answer and include the necessary code. I only inspired you to do the right thing without getting into the details.Incomprehension
I
5

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.

Irrefragable answered 27/9, 2015 at 18:11 Comment(1)
Please don't use indirect object notation (new Linux::TunTap) as it has several side effects!Lalitta

© 2022 - 2024 — McMap. All rights reserved.