#!/usr/bin/perl
use strict;
use IO::Socket;
use IO::Interface qw(:flags);
use Net::Pcap ':functions';
use Sys::Hostname;

my(%devs,$err) = ();
my $s = IO::Socket::INET->new(Proto => 'udp');
my @devs = findalldevs(\%devs, \$err);

my $hostname = hostname();
my $aliases  = (gethostbyname($hostname))[1];

print "Host information\n", 
      "----------------\n", 
      "  Hostname      : $hostname\n";
print "  Aliases       : $aliases\n" if $aliases;
print "  Pcap version  : ", lib_version(), $/,
      $/, 
      "Devices information\n", 
      "-------------------\n";

for my $dev (@devs) {
    my $default = $dev eq lookupdev(\$err) ? "(default)" : '';

    print "Device $dev $default\n", 
          "  Description       : $devs{$dev}\n"; 
    print "  Link type         : ", linktype($dev), $/, 
          "  Hardware address  : ", $s->if_hwaddr($dev), $/, 
          "  Network address   : ", $s->if_addr($dev), $/, 
          "  Network mask      : ", $s->if_netmask($dev), $/,
          "  Flags             : ", flags($dev), $/, 
          if $dev ne 'any';
    print $/;
}

sub linktype {
    my $dev = shift;
    my $linktype = "<can't get this information>";

    if(my $pcap = open_live($dev, 1024, 1, 0, \$err)) {
        $linktype = datalink_val_to_description(datalink($pcap));
        pcap_close($pcap);
    }

    chomp(my $status = `/sbin/mii-tool $dev 2>/dev/null`);
    $status =~ s/$dev\:/,/;

    return $linktype . $status
}

sub flags {
    my $dev = shift;
    my $flags = $s->if_flags($dev);
    my $string = '';

    $string .= "up "          if $flags & IFF_UP;
    $string .= "running "     if $flags & IFF_RUNNING;
    $string .= "broadcast "   if $flags & IFF_BROADCAST;
    $string .= "debug "       if $flags & IFF_DEBUG;
    $string .= "loopback "    if $flags & IFF_LOOPBACK;
    $string .= "p-to-p "      if $flags & IFF_POINTOPOINT;
    $string .= "notrailers "  if $flags & IFF_NOTRAILERS;
    $string .= "noarp "       if $flags & IFF_NOARP;
    $string .= "promiscuous " if $flags & IFF_PROMISC;
    $string .= "multicast "   if $flags & IFF_MULTICAST;
    $string .= "allmulti "    if $flags & IFF_ALLMULTI;
    $string .= "master "      if $flags & IFF_MASTER;
    $string .= "slave "       if $flags & IFF_SLAVE;
    $string .= "portsel "     if $flags & IFF_PORTSEL;
    $string .= "automedia "   if $flags & IFF_AUTOMEDIA;

    return $string
}

__END__

=head1 NAME

pcapinfo - Prints detailed information about the network devices

=head1 SYNOPSIS

    pcapinfo

=head1 OPTIONS

None.

=head1 DESCRIPTION

B<pcapinfo> prints detailed information about the network devices 
and Pcap library available on the current host. Here is an example: 

    Host information
    ----------------
      Hostname      : fangorn.maddingue.net
      Aliases       : fangorn.local fangorn
      Pcap version  : libpcap version 0.8.3

    Devices information
    -------------------
    Device eth0 (default)
      Description       : No description available
      Link type         : Ethernet, no autonegotiation, 10baseT-HD, link ok
      Hardware address  : 00:0c:6e:0a:c3:ca
      Network address   : 10.0.1.51
      Network mask      : 255.255.255.0
      Flags             : up running broadcast multicast

    Device eth1
      Description       : No description available
      Link type         : Ethernet, no autonegotiation, 10baseT-HD, link ok
      Hardware address  : 00:26:54:0a:d8:4d
      Network address   : 192.168.1.51
      Network mask      : 255.255.255.0
      Flags             : up running broadcast multicast

The device marked as C<"(default)"> is the one returned when calling 
C<Net::Pcap::lookupdev()>

Some information like the link type can only be gathered with root 
privileges. 

=head1 AUTHOR

SE<eacute>bastien Aperghis-Tramoni, E<lt>sebastien@aperghis.netE<gt>

=head1 COPYRIGHT

Copyright (C) 2005 SE<eacute>bastien Aperghis-Tramoni. All rights reserved.

This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut
