From 0e5a02c9496a35fee9cfd40815eec963a23b71d7 Mon Sep 17 00:00:00 2001 From: janw Date: Mon, 28 Jan 2008 14:19:14 +0000 Subject: [PATCH] Added ArpWatch component. git-svn-id: https://oss.gonicus.de/repositories/gosa/trunk@8620 594d385d-05f5-0310-b6e9-bd551577e9d8 --- gosa-si/debian/gosa-si-common.install | 1 + gosa-si/modules/ArpWatch.pm | 172 ++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 gosa-si/modules/ArpWatch.pm diff --git a/gosa-si/debian/gosa-si-common.install b/gosa-si/debian/gosa-si-common.install index 4f629564e..b9b8f74d3 100644 --- a/gosa-si/debian/gosa-si-common.install +++ b/gosa-si/debian/gosa-si-common.install @@ -1,2 +1,3 @@ modules/GosaSupportDaemon.pm usr/share/perl5/GOSA modules/DBsqlite.pm usr/share/perl5/GOSA +modules/ArpWatch.pm usr/share/perl5/POE/Component diff --git a/gosa-si/modules/ArpWatch.pm b/gosa-si/modules/ArpWatch.pm new file mode 100644 index 000000000..1db2a78af --- /dev/null +++ b/gosa-si/modules/ArpWatch.pm @@ -0,0 +1,172 @@ +#!/usr/bin/perl +package POE::Component::ArpWatch; + +use strict; + +use POE; + +use Pcap; + +use NetPacket::Ethernet qw( :types ); +use NetPacket::ARP qw( :opcodes ); + +## Map arp opcode #'s to strings +my %arp_opcodes = ( + NetPacket::ARP::ARP_OPCODE_REQUEST, 'ARP Request', + NetPacket::ARP::ARP_OPCODE_REPLY, 'ARP Reply', + NetPacket::ARP::RARP_OPCODE_REQUEST, 'RARP Request', + NetPacket::ARP::RARP_OPCODE_REPLY, 'RARP Reply', + ); + +## +## POE::Component::ArpWatch->spawn( +## [ Alias => 'arp_watch' ], +## [ Device => 'eth0' ], +## [ Dispatch => dispatch_state ], +## [ Session => dispatch_session ], +## ) +## +sub spawn { + my $class = shift; + my %args = @_; + + $args{ Alias } ||= 'arp_watch'; + + POE::Session->create( + inline_states => { + _start => \&_start, +# _signal => \&_signal, + _stop => \&_stop,, + _dispatch => \&_dispatch, + set_dispatch => \&set_dispatch, + run => \&run, + pause => \&pause, + shutdown => \&shutdown, + }, + args => [ + $args{ Alias }, # ARG0 + $args{ Device }, # ARG1 + $args{ Dispatch },# ARG2 + $args{ Session }, # ARG3 + ], + ); + + return $args{ Alias }; +} + +sub _start { + my ($kernel, $heap, $session, + $alias, $device, $target_state, $target_session ) + = @_[ KERNEL, HEAP, SESSION, ARG0..ARG3 ]; + + POE::Component::Pcap->spawn( + Alias => $alias . '_pcap', + Device => $device, + Filter => 'arp', + Dispatch => '_dispatch', + Session => $session, + ); + + $heap->{'pcap_session'} = $kernel->alias_resolve( $alias . '_pcap' ); + + ## Set alias for ourselves and remember it + $kernel->alias_set( $alias ); + $heap->{Alias} = $alias; + + ## Set dispatch target session and state if it was given + if( defined( $target_session ) ) { + $heap->{'target_session'} = $target_session; + $heap->{'target_state'} = $target_state; + } +} + +sub set_dispatch { + my( $heap, $sender, $target ) = @_[ HEAP, SENDER, ARG0 ]; + + if( defined $target ) { + ## Remember whome to forward results to + $heap->{'target_session'} = $sender; + $heap->{'target_state'} = $target; + } else { + ## Clear target + delete $heap->{'target_session'}; + delete $heap->{'target_state'}; + } +} + +sub run { + $_[KERNEL]->post( $_[HEAP]->{'pcap_session'} => 'run' ); +} + +sub pause { + $_[KERNEL]->post( $_[HEAP]->{'pcap_session'} => 'pause' ); +} + +sub _dispatch { + my( $kernel, $heap, $packets ) = + @_[ KERNEL, HEAP, ARG0 ]; + + if( exists $heap->{'target_session'} ) { + $kernel->post( $heap->{'target_session'}, + $heap->{'target_state'}, + _process_packet( @{ $_ } ) ) foreach( @{$packets} ); + } +} + +sub _signal { + # print "Got signal ", $_[ARG0], "\n"; + + $_[KERNEL]->post( pcap => 'shutdown' ); + + return 1 +} + +sub shutdown { + my ( $kernel, $heap, $session, $sender ) + = @_[ KERNEL, HEAP, SESSION, SENDER ]; + my $alias = $heap->{Alias}; + +# print "In shutdown for sid ", $session->ID, ", alias $alias\n"; +# print "shutdown by ", $sender->ID, "\n"; + + $kernel->post( $heap->{'pcap_session'} => 'shutdown' ); + + $kernel->alias_remove( $alias ); + +# print "Out shutdown for sid ", $session->ID, ", alias $alias\n"; +} + +sub _stop { + my ( $kernel, $heap, $session ) = @_[ KERNEL, HEAP, SESSION ]; + my $alias = $heap->{Alias}; + +# print "In state_stop for sid ", $session->ID, ", alias $alias\n"; + +# print "Out state_stop for sid ", $session->ID, ", alias $alias\n"; +} + +sub _process_packet { + my( $hdr, $pkt ) = @_; + + my $arp = + NetPacket::ARP->decode( NetPacket::Ethernet->decode($pkt)->{data} ); + + ## Return hashref with apropriate fields + return { + type => $arp_opcodes{ $arp->{opcode} }, + tv_sec => $hdr->{tv_sec}, + tv_usec => $hdr->{tv_usec}, + source_haddr => _phys( $arp->{sha} ), + source_ipaddr => _ipaddr( $arp->{spa} ), + target_haddr => _phys( $arp->{tha} ), + target_ipaddr => _ipaddr( $arp->{tpa} ), + } +} + +## Pretty printing subs for addresses +sub _ipaddr { join( ".", unpack( "C4", pack( "N", oct( "0x". shift ) ) ) ) } +sub _phys { join( ":", grep {length} split( /(..)/, shift ) ) } + +1; + +__END__ -- 2.30.2