Net::Write::Layer - base class and constants


Net-Write documentation Contained in the Net-Write distribution.

Index


Code Index:

NAME

Top

Net::Write::Layer - base class and constants

SYNOPSIS

Top

   use Net::Write::Layer qw(:constants);

DESCRIPTION

Top

This is the base class for Net::Write::Layer2, Net::Write::Layer3 and Net::Write::Layer4 modules.

It just provides those layers with inheritable attributes, methods and constants.

ATTRIBUTES

Top

dev

Network interface to use.

dst

Target IPv4 or IPv6 address.

protocol

Transport layer protocol to use (TCP, UDP, ...).

family

Adresse family to use (NW_AF_INET, NW_AF_INET6).

METHODS

Top

new

Object constructor.

open

Open the descriptor, when you are ready to send.

send (scalar)

Send the raw data passed as a parameter. Returns undef on failure, true otherwise.

close

Close the descriptor.

CONSTANTS

Top

NW_AF_INET
NW_AF_INET6
NW_AF_UNSPEC

Address family constants, for use with family attribute.

NW_IPPROTO_IP
NW_IPPROTO_IPv6
NW_IPPROTO_ICMPv4
NW_IPPROTO_TCP
NW_IPPROTO_UDP
NW_IPPROTO_ICMPv6

Transport layer protocol constants, for use with protocol attribute.

NW_IP_HDRINCL
NW_IPPROTO_RAW

Mostly used internally.

SEE ALSO

Top

Net::Write::Layer2, Net::Write::Layer3, Net::Write::Layer4

AUTHOR

Top

Patrice <GomoR> Auffret

COPYRIGHT AND LICENSE

Top


Net-Write documentation Contained in the Net-Write distribution.

#
# $Id: Layer.pm 1636 2009-06-10 18:38:24Z gomor $
#
package Net::Write::Layer;
use strict;
use warnings;

require Exporter;
require Class::Gomor::Array;
our @ISA = qw(Exporter Class::Gomor::Array);
our @AS = qw(
   dev
   dst
   protocol
   family
   _io
   _sockaddr
);
__PACKAGE__->cgBuildIndices;
__PACKAGE__->cgBuildAccessorsScalar(\@AS);

sub _setIpProtoIpConstant {
   my $val = 0;
   if (defined(&IPPROTO_IP)) {
      $val = &IPPROTO_IP;
   }
   elsif ($^O eq 'darwin'
      ||  $^O eq 'linux'
      ||  $^O eq 'freebsd'
      ||  $^O eq 'openbsd'
      ||  $^O eq 'netbsd'
      ||  $^O eq 'aix') {
      $val = 0;
   }
   eval "use constant NW_IPPROTO_IP => $val;";
}

sub _setIpProtoIpv6Constant {
   my $val = 0;
   if (defined(&IPPROTO_IPv6)) {
      $val = &IPPROTO_IPv6;
   }
   elsif ($^O eq 'linux'
      ||  $^O eq 'freebsd') {
      $val = 41;
   }
   eval "use constant NW_IPPROTO_IPv6 => $val;";
}

sub _setIpProtoRawConstant {
   my $val = 255;
   if (defined(&IPPROTO_RAW)) {
      $val = &IPPROTO_RAW;
   }
   elsif ($^O eq 'darwin'
      ||  $^O eq 'linux'
      ||  $^O eq 'freebsd'
      ||  $^O eq 'openbsd'
      ||  $^O eq 'netbsd'
      ||  $^O eq 'aix') {
      $val = 255;
   }
   eval "use constant NW_IPPROTO_RAW => $val;";
}

sub _setIpHdrInclConstant {
   my $val = 2;
   if (defined(&IP_HDRINCL)) {
      $val = &IP_HDRINCL;
   }
   elsif ($^O eq 'darwin'
      ||  $^O eq 'freebsd'
      ||  $^O eq 'openbsd'
      ||  $^O eq 'netbsd'
      ||  $^O eq 'linux'
      ||  $^O eq 'aix'
      ||  $^O eq 'cygwin') {
      $val = 2;
   }
   elsif ($^O eq 'hpux') {
      $val = 0x1002;
   }
   eval "use constant NW_IP_HDRINCL => $val;";
}

sub _setAfinet6Constant {
   require Socket6;
   require Socket;
   my $val = 0;
   if (defined(&Socket6::AF_INET6)) {
      $val = &Socket6::AF_INET6;
   }
   elsif (defined(&Socket::AF_INET6)) {
      $val = &Socket::AF_INET6;
   }
   eval "use constant NW_AF_INET6  => $val;";
}

BEGIN {
   my $osname = {
      cygwin  => \&_checkWin32,
      MSWin32 => \&_checkWin32,
   };

   *_check  = $osname->{$^O} || \&_checkOther;
   _setIpProtoIpConstant();
   _setIpProtoIpv6Constant();
   _setIpProtoRawConstant();
   _setIpHdrInclConstant();
   _setAfinet6Constant();
}

no strict 'vars';

use Socket;
use Socket6 qw(getaddrinfo);
use IO::Socket;
use Net::Pcap;
use Carp;

use constant NW_AF_INET   => AF_INET();
use constant NW_AF_UNSPEC => AF_UNSPEC();

use constant NW_IPPROTO_ICMPv4 => 1;
use constant NW_IPPROTO_TCP    => 6;
use constant NW_IPPROTO_UDP    => 17;
use constant NW_IPPROTO_ICMPv6 => 58;

our %EXPORT_TAGS = (
   constants => [qw(
      NW_AF_INET
      NW_AF_INET6
      NW_AF_UNSPEC
      NW_IPPROTO_IP
      NW_IPPROTO_IPv6
      NW_IPPROTO_ICMPv4
      NW_IPPROTO_TCP
      NW_IPPROTO_UDP
      NW_IPPROTO_ICMPv6
      NW_IP_HDRINCL
      NW_IPPROTO_RAW
   )],
);

our @EXPORT_OK = (
   @{$EXPORT_TAGS{constants}},
);

sub _checkWin32 { }

sub _checkOther {
   croak("Must be EUID 0 (or equivalent) to open a device for writing.\n")
      if $>;
}

sub new { _check(); shift->SUPER::new(@_) }

sub open {
   my $self = shift;
   my ($hdrincl) = @_;

   my @res = getaddrinfo($self->[$__dst], 0, $self->[$__family], SOCK_STREAM)
      or croak("@{[(caller(0))[3]]}: getaddrinfo: $!\n");

   my ($family, $saddr) = @res[0, 3] if @res >= 5;
   $self->[$___sockaddr] = $saddr;

   socket(my $s, $family, SOCK_RAW, $self->[$__protocol])
      or croak("@{[(caller(0))[3]]}: socket: $!\n");

   my $fd = fileno($s) or croak("@{[(caller(0))[3]]}: fileno: $!\n");

   if ($hdrincl) {
      $self->_setIpHdrincl($s, $self->[$__family])
         or croak("@{[(caller(0))[3]]}: setsockopt: $!\n");
   }

   my $io = IO::Socket->new;
   $io->fdopen($fd, 'w') or croak("@{[(caller(0))[3]]}: fdopen: $!\n");

   $self->[$___io] = $io;

   1;
}

sub send {
   my $self = shift;
   my ($raw) = @_;

   while (1) {
      my $ret = CORE::send($self->_io, $raw, 0, $self->_sockaddr);
      unless ($ret) {
         if ($!{ENOBUFS}) {
            $self->cgDebugPrint(2, "ENOBUFS returned, sleeping for 1 second");
            sleep 1;
            next;
         }
         elsif ($!{EHOSTDOWN}) {
            $self->cgDebugPrint(2, "host is down");
            last;
         }
         carp("@{[(caller(0))[3]]}: $!\n");
         return undef;
      }
      last;
   }

   1;
}

sub close { shift->_io->close }

1;

__END__