Compare commits
19 Commits
Author | SHA1 | Date |
---|---|---|
Zane C. B-H | aead20b4a0 | |
Zane C. B-H | d550f30d45 | |
Zane C. B-H | 4052319faa | |
Zane C. B-H | 8941c256ac | |
Zane C. B-H | d4cbe61492 | |
Zane C. B-H | 906f113bef | |
Zane C. B-H | 8a48932f14 | |
Zane C. B-H | d78c077ccd | |
Zane C. B-H | fde8327c9a | |
Zane C. B-H | 13184cf0d5 | |
Zane C. B-H | 5fb4f34090 | |
Zane C. B-H | 6112ee058d | |
Zane C. B-H | 7c479576bf | |
Zane C. B-H | 359daebdd5 | |
Zane C. B-H | 1674f4f45a | |
Zane C. B-H | edaaadd874 | |
Zane C. B-H | 60bb179e74 | |
Zane C. B-H | bcf609fba4 | |
Zane C. B-H | b3bbb47024 |
|
@ -1,15 +1,44 @@
|
|||
Revision history for Parse-Netstat-Search
|
||||
|
||||
0.0.2 2019-02-24/08:30
|
||||
- Previous issue turned out to be specifically. Added
|
||||
addtional handling for UDP as it is stateless. This
|
||||
removes '?' from previously. State for for UDP is ''.
|
||||
0.2.2 2019-05-23/01:10
|
||||
- Net::CIDR now treats ::/0 and 0.0.0.0/0 as the same.
|
||||
t/search.t has been updated to reflect this.
|
||||
|
||||
0.0.1 2019-02-24/06:30
|
||||
- Handle where FreeBSD does not state LISTEN.
|
||||
- Add a missing error flag.
|
||||
- If state is not defined use '?'.
|
||||
0.2.1 2019-04-15/21:20
|
||||
- Add missing depend Net::DNS. (SREZIC, #129196)
|
||||
|
||||
0.0.0 2019-02-20/06:00
|
||||
-Initial release.
|
||||
0.2.0 2019-04-15/02:30
|
||||
- Minor typo correction(japh).
|
||||
- Add PTR search support.
|
||||
- Add regexp PTR search support.
|
||||
|
||||
0.1.1 2019-02-26/04:00
|
||||
- Apparently Net::CIDR does not like searching IPv4 and IPv6 at the
|
||||
same time. Each requested CIDR is now checked on its own. While
|
||||
it says the functions will handle both in the docs, apparently
|
||||
this does not mean at the same time.
|
||||
|
||||
0.1.0 2019-02-26/00:15
|
||||
- Add in handling of % in IPv6 addresses.
|
||||
- Add in handling of slightly malformed IPv6 address that netstat
|
||||
on FreeBSD seems to sometimes produce, using ':.' for the port
|
||||
delimiter instead of '.'. This is not to be confused with ::
|
||||
appearing at the end, but like "fe80::4ecc:6aff:.123".
|
||||
|
||||
0.0.3 2019-02-25/06:30
|
||||
- Use eval to talk to Net::CIDR as it seems to not always like IPv6.
|
||||
This allows it to continue instead of killing the entire op.
|
||||
|
||||
0.0.2 2019-02-24/08:30
|
||||
- Previous issue turned out to be specifically. Added
|
||||
addtional handling for UDP as it is stateless. This
|
||||
removes '?' from previously. State for for UDP is ''.
|
||||
|
||||
0.0.1 2019-02-24/06:30
|
||||
- Handle where FreeBSD does not state LISTEN.
|
||||
- Add a missing error flag.
|
||||
- If state is not defined use '?'.
|
||||
|
||||
0.0.0 2019-02-20/06:00
|
||||
-Initial release.
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ WriteMakefile(
|
|||
'Net::CIDR' => '0',
|
||||
'Parse::Netstat'=>'0.14',
|
||||
'Error::Helper' => '1.0.0',
|
||||
'Net::DNS' => '1.20',
|
||||
},
|
||||
dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
|
||||
clean => { FILES => 'Parse-Netstat-Search-*' },
|
||||
|
|
|
@ -5,6 +5,7 @@ use strict;
|
|||
use warnings;
|
||||
use base 'Error::Helper';
|
||||
use Net::CIDR;
|
||||
use Net::DNS;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
|
@ -12,11 +13,11 @@ Parse::Netstat::Search - Searches the connection list in the results returned by
|
|||
|
||||
=head1 VERSION
|
||||
|
||||
Version 0.0.2
|
||||
Version 0.2.2
|
||||
|
||||
=cut
|
||||
|
||||
our $VERSION = '0.0.2';
|
||||
our $VERSION = '0.2.2';
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
@ -25,7 +26,7 @@ our $VERSION = '0.0.2';
|
|||
use Parse::Netstat::Search;
|
||||
use Parse::Netstat qw(parse_netstat);
|
||||
|
||||
my $res = parse_netstat(output => join("", `netstat -anp`), flavor=>'linux');
|
||||
my $res = parse_netstat(output => join("", `netstat -n`), flavor=>$^O);
|
||||
|
||||
my $search = Parse::Netstat::Search->new();
|
||||
|
||||
|
@ -37,6 +38,37 @@ our $VERSION = '0.0.2';
|
|||
Two big things to bet aware of is this module does not currently resulve names and this module
|
||||
does not handle unix sockets. Unix sockets will just be skipped over.
|
||||
|
||||
The connection hashes returned differ from Parse::Netstat slightly. Below is what a standard ones
|
||||
for IPv4/6 looks like.
|
||||
|
||||
{
|
||||
'foreign_host'=>'10.0.0.1',
|
||||
'local_host'=>'10.0.0.2',
|
||||
'foreign_port'=>'22222',
|
||||
'local_port'=>'22',
|
||||
'sendq'=>'0',
|
||||
'recvq'=>'0',
|
||||
'state' => 'ESTABLISHED',
|
||||
'proto' => 'tcp4',
|
||||
}
|
||||
|
||||
This module has two additional keys, "local_pp" and "foreign_pp". Which contains and data
|
||||
after % in a address. So "fe80::1%lo0" would be split into "fe80::1" and "lo0" as in the
|
||||
example below.
|
||||
|
||||
{
|
||||
'state' => '',
|
||||
'foreign_host' => '*',
|
||||
'local_port' => '123',
|
||||
'proto' => 'udp6',
|
||||
'foreign_pp' => undef,
|
||||
'foreign_port' => '*',
|
||||
'local_host' => 'fe80::1',
|
||||
'recvq' => '44',
|
||||
'local_pp' => 'lo0',
|
||||
'sendq' => '33'
|
||||
}
|
||||
|
||||
=head1 methods
|
||||
|
||||
=head2 new
|
||||
|
@ -63,6 +95,15 @@ sub new{
|
|||
protocols=>{},
|
||||
ports=>{},
|
||||
states=>{},
|
||||
ptrs=>{},
|
||||
ptrs_r=>[],
|
||||
resolver=>Net::DNS::Resolver->new,
|
||||
ptr_invert=>0,
|
||||
ptr_r_invert=>0,
|
||||
cidr_invert=>0,
|
||||
protocol_invert=>0,
|
||||
state_invert=>0,
|
||||
port_invert=>0,
|
||||
};
|
||||
bless $self;
|
||||
|
||||
|
@ -90,6 +131,28 @@ sub get_cidrs{
|
|||
return @{ $self->{cidrs} };
|
||||
}
|
||||
|
||||
=head2 get_cidrs_invert
|
||||
|
||||
Gets the invert status of the CIDRs search.
|
||||
|
||||
if ( $search->get_cidrs_invert ){
|
||||
print "The search will be inverted\n";
|
||||
}else{
|
||||
print "The search will not be inverted";
|
||||
}
|
||||
|
||||
=cut
|
||||
|
||||
sub get_cidrs_invert{
|
||||
my $self=$_[0];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
return $self->{cidr_invert};
|
||||
}
|
||||
|
||||
=head2 get_ports
|
||||
|
||||
Gets a list of desired ports.
|
||||
|
@ -111,6 +174,28 @@ sub get_ports{
|
|||
return keys( %{ $self->{ports} } );
|
||||
}
|
||||
|
||||
=head2 get_ports_invert
|
||||
|
||||
Gets the invert status of the ports search.
|
||||
|
||||
if ( $search->get_ports_invert ){
|
||||
print "The search will be inverted\n";
|
||||
}else{
|
||||
print "The search will not be inverted";
|
||||
}
|
||||
|
||||
=cut
|
||||
|
||||
sub get_ports_invert{
|
||||
my $self=$_[0];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
return $self->{port_invert};
|
||||
}
|
||||
|
||||
=head2 get_protocols
|
||||
|
||||
Gets a list of desired protocols.
|
||||
|
@ -135,6 +220,28 @@ sub get_protocols{
|
|||
return keys( %{ $self->{protocols} } );
|
||||
}
|
||||
|
||||
=head2 get_protocols_invert
|
||||
|
||||
Gets the invert status of the protocols search.
|
||||
|
||||
if ( $search->get_protocols_invert ){
|
||||
print "The search will be inverted\n";
|
||||
}else{
|
||||
print "The search will not be inverted";
|
||||
}
|
||||
|
||||
=cut
|
||||
|
||||
sub get_protocols_invert{
|
||||
my $self=$_[0];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
return $self->{protocol_invert};
|
||||
}
|
||||
|
||||
=head2 get_states
|
||||
|
||||
Get a list of desired sets.
|
||||
|
@ -158,6 +265,112 @@ sub get_states{
|
|||
return keys( %{ $self->{states} } );
|
||||
}
|
||||
|
||||
=head2 get_state_invert
|
||||
|
||||
Gets the invert status of the states search.
|
||||
|
||||
if ( $search->get_state_invert ){
|
||||
print "The search will be inverted\n";
|
||||
}else{
|
||||
print "The search will not be inverted";
|
||||
}
|
||||
|
||||
=cut
|
||||
|
||||
sub get_states_invert{
|
||||
my $self=$_[0];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
return $self->{state_invert};
|
||||
}
|
||||
|
||||
=head2 get_ptrs
|
||||
|
||||
Gets the list of PTRs to search for.
|
||||
|
||||
The returned value is a array. Each item is a PTR.
|
||||
|
||||
my @PTRs=$search->get_ptrs;
|
||||
|
||||
=cut
|
||||
|
||||
sub get_ptrs{
|
||||
my $self=$_[0];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
return keys( %{ $self->{ptrs} } );
|
||||
}
|
||||
|
||||
=head2 get_ptrs_invert
|
||||
|
||||
Gets the invert status of the PTRs search.
|
||||
|
||||
if ( $search->get_ptr_invert ){
|
||||
print "The search will be inverted\n";
|
||||
}else{
|
||||
print "The search will not be inverted";
|
||||
}
|
||||
|
||||
=cut
|
||||
|
||||
sub get_ptrs_invert{
|
||||
my $self=$_[0];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
return $self->{ptr_invert};
|
||||
}
|
||||
|
||||
=head2 get_ptrs_r
|
||||
|
||||
Gets the list of PTR regexps to search for.
|
||||
|
||||
The returned value is a array. Each item is a PTR.
|
||||
|
||||
my @regexps=$search->get_ptrs_r;
|
||||
|
||||
=cut
|
||||
|
||||
sub get_ptrs_r{
|
||||
my $self=$_[0];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
return @{ $self->{ptrs_r} };
|
||||
}
|
||||
|
||||
=head2 get_ptrs_invert
|
||||
|
||||
Gets the invert status of the PTRs search.
|
||||
|
||||
if ( $search->get_ptr_invert ){
|
||||
print "The search will be inverted\n";
|
||||
}else{
|
||||
print "The search will not be inverted";
|
||||
}
|
||||
|
||||
=cut
|
||||
|
||||
sub get_ptrs_r_invert{
|
||||
my $self=$_[0];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
return $self->{ptr_r_invert};
|
||||
}
|
||||
|
||||
=head2 search
|
||||
|
||||
This runs the search results.
|
||||
|
@ -181,7 +394,7 @@ sub search{
|
|||
( ! defined( $res->[2]->{active_conns} ) )
|
||||
){
|
||||
$self->{error}=3;
|
||||
$self->{errorString}='$res->[2]->{active_conns} not defiend. Does not appear to be a Parse::Netstat return';
|
||||
$self->{errorString}='$res->[2]->{active_conns} not defined. Does not appear to be a Parse::Netstat return';
|
||||
$self->warn;
|
||||
return undef;
|
||||
}
|
||||
|
@ -194,6 +407,8 @@ sub search{
|
|||
my $cidr_require=0;
|
||||
my $protocol_require=0;
|
||||
my $state_require=0;
|
||||
my $ptr_require=0;
|
||||
my $ptr_r_require=0;
|
||||
|
||||
# figure out what we need to check for
|
||||
if (defined( $self->{cidrs}[0] )){
|
||||
|
@ -208,6 +423,12 @@ sub search{
|
|||
if (defined( (keys(%{ $self->{states} }))[0] )){
|
||||
$state_require=1;
|
||||
}
|
||||
if (defined( (keys(%{ $self->{ptrs} }))[0] )){
|
||||
$ptr_require=1;
|
||||
}
|
||||
if (defined( $self->{ptrs_r}[0] )){
|
||||
$ptr_r_require=1;
|
||||
}
|
||||
|
||||
my $res_int=0;
|
||||
while ( defined( $res->[2]->{active_conns}->[$res_int] ) ){
|
||||
|
@ -219,11 +440,24 @@ sub search{
|
|||
my $state=$res->[2]->{active_conns}->[$res_int]->{state};
|
||||
my $protocol=$res->[2]->{active_conns}->[$res_int]->{proto};
|
||||
my $local_port=$res->[2]->{active_conns}->[$res_int]->{local_port};
|
||||
my $local_host=$res->[2]->{active_conns}->[$res_int]->{local_host};
|
||||
my $foreign_host=$res->[2]->{active_conns}->[$res_int]->{foreign_host};
|
||||
#my $local_host=$res->[2]->{active_conns}->[$res_int]->{local_host};
|
||||
#my $foreign_host=$res->[2]->{active_conns}->[$res_int]->{foreign_host};
|
||||
my $sendq=$res->[2]->{active_conns}->[$res_int]->{sendq};
|
||||
my $recvq=$res->[2]->{active_conns}->[$res_int]->{recvq};
|
||||
|
||||
#handle IPv6 % stuff if needed
|
||||
my ( $local_host, $local_pp ) = split( /\%/, $res->[2]->{active_conns}->[$res_int]->{local_host} );
|
||||
my ( $foreign_host, $foreign_pp ) = split( /\%/, $res->[2]->{active_conns}->[$res_int]->{foreign_host} );
|
||||
|
||||
# Handle when parse netstat chokes on lines like...
|
||||
# udp6 0 0 fe80::4ecc:6aff:.123 *.*
|
||||
if ( $local_host =~ /[0123456789AaBbCcDdEeFf]\:$/ ){
|
||||
$local_host =~ s/\:$//;
|
||||
}
|
||||
if ( $foreign_host =~ /[0123456789AaBbCcDdEeFf]\:$/ ){
|
||||
$foreign_host =~ s/\:$//;
|
||||
}
|
||||
|
||||
# UDP is stateless and in some cases on listening ports for it Parse::Netstat
|
||||
# does not return any host, so use * for it.
|
||||
if (!defined( $foreign_host )){
|
||||
|
@ -247,39 +481,44 @@ sub search{
|
|||
my $port_meet=1;
|
||||
my $cidr_meet=1;
|
||||
my $protocol_meet=1;
|
||||
my $ptr_meet=1;
|
||||
my $ptr_r_meet=1;
|
||||
my $protocol_search=lc( $protocol );
|
||||
my $state_meet=1;
|
||||
my $state_search=lc( $state );
|
||||
|
||||
# reset the meet checks
|
||||
if ( $port_require ) {
|
||||
$port_meet=0;
|
||||
}
|
||||
if ( $cidr_require ) {
|
||||
$cidr_meet=0;
|
||||
}
|
||||
if ( $protocol_require ) {
|
||||
$protocol_meet=0;
|
||||
}
|
||||
if ( $state_require ) {
|
||||
$state_meet=0;
|
||||
}
|
||||
# XOR the meet and require, setting the meet to false if required
|
||||
$port_meet = $port_meet ^ $port_require;
|
||||
$cidr_meet = $cidr_meet ^ $cidr_require;
|
||||
$protocol_meet = $protocol_meet ^ $protocol_require;
|
||||
$state_meet = $state_meet ^ $state_require;
|
||||
$ptr_meet = $ptr_meet ^ $ptr_require;
|
||||
$ptr_r_meet = $ptr_r_meet ^ $ptr_r_require;
|
||||
|
||||
# checks the forient port against each CIDR
|
||||
if (
|
||||
$cidr_require &&
|
||||
(
|
||||
(
|
||||
( $foreign_host ne '*' ) &&
|
||||
( Net::CIDR::cidrlookup( $foreign_host, @{ $self->{cidrs} } ) )
|
||||
) ||
|
||||
(
|
||||
( $local_host ne '*' ) &&
|
||||
( Net::CIDR::cidrlookup( $local_host, @{ $self->{cidrs} } ) )
|
||||
)
|
||||
)
|
||||
) {
|
||||
$cidr_meet=1;
|
||||
my @cidrs=@{ $self->{cidrs} };
|
||||
if ( $cidr_require ){
|
||||
# check each one by its self... Net::CIDR will error if you tell it to search for in IPv4 and IPv6 space at the same time
|
||||
my @cidrs=@{ $self->{cidrs} };
|
||||
my $cidr=pop( @cidrs );
|
||||
while (
|
||||
( defined( $cidr ) ) &&
|
||||
( ! $cidr_meet )
|
||||
){
|
||||
if (
|
||||
(
|
||||
( $foreign_host ne '*' ) &&
|
||||
( eval{ Net::CIDR::cidrlookup( $foreign_host, $cidr ) })
|
||||
) || (
|
||||
( $local_host ne '*' ) &&
|
||||
( eval{ Net::CIDR::cidrlookup( $local_host, $cidr ) } )
|
||||
)
|
||||
){
|
||||
$cidr_meet=1;
|
||||
}
|
||||
|
||||
$cidr=pop( @cidrs );
|
||||
}
|
||||
}
|
||||
|
||||
# handle it if port checking is required
|
||||
|
@ -309,9 +548,90 @@ sub search{
|
|||
$state_meet=1;
|
||||
}
|
||||
|
||||
# check if the PTR of any matches
|
||||
if ( $ptr_require ){
|
||||
#look both up
|
||||
my $answer_f=$self->{resolver}->search( $foreign_host );
|
||||
my $answer_l=$self->{resolver}->search( $local_host );
|
||||
|
||||
# figure out if we have a ptr or not for foriegn host and if so grab it
|
||||
my $ptr_f='NOTFOUND';
|
||||
if ( defined( $answer_f->{answer}[0] ) &&
|
||||
( ref( $answer_f->{answer}[0] ) eq 'Net::DNS::RR::PTR' )
|
||||
){
|
||||
$ptr_f=lc($answer_f->{answer}[0]->ptrdname);
|
||||
}
|
||||
|
||||
# figure out if we have a ptr or not for foriegn host and if so grab it
|
||||
my $ptr_l='NOTFOUND';
|
||||
if ( defined( $answer_l->{answer}[0] ) &&
|
||||
( ref( $answer_l->{answer}[0] ) eq 'Net::DNS::RR::PTR' )
|
||||
){
|
||||
$ptr_l=lc($answer_l->{answer}[0]->ptrdname);
|
||||
}
|
||||
|
||||
# now that we have it, check if either are defined in the lookup table
|
||||
if (
|
||||
defined( $self->{ptrs}{$ptr_l} ) ||
|
||||
defined( $self->{ptrs}{$ptr_f} )
|
||||
){
|
||||
$ptr_meet=1;
|
||||
}
|
||||
}
|
||||
|
||||
# check if the PTR of any matches
|
||||
if ( $ptr_r_require ){
|
||||
#look both up
|
||||
my $answer_f=$self->{resolver}->search( $foreign_host );
|
||||
my $answer_l=$self->{resolver}->search( $local_host );
|
||||
|
||||
# figure out if we have a ptr or not for foriegn host and if so grab it
|
||||
my $ptr_f='NOTFOUND';
|
||||
if ( defined( $answer_f->{answer}[0] ) &&
|
||||
( ref( $answer_f->{answer}[0] ) eq 'Net::DNS::RR::PTR' )
|
||||
){
|
||||
$ptr_f=lc($answer_f->{answer}[0]->ptrdname);
|
||||
}
|
||||
|
||||
# figure out if we have a ptr or not for foriegn host and if so grab it
|
||||
my $ptr_l='NOTFOUND';
|
||||
if ( defined( $answer_l->{answer}[0] ) &&
|
||||
( ref( $answer_l->{answer}[0] ) eq 'Net::DNS::RR::PTR' )
|
||||
){
|
||||
$ptr_l=lc($answer_l->{answer}[0]->ptrdname);
|
||||
}
|
||||
|
||||
# check if any of them match
|
||||
my @ptrs_r=@{ $self->{ptrs_r} };
|
||||
my $ptr=pop( @ptrs_r );
|
||||
while (
|
||||
defined( $ptr ) &&
|
||||
( ! $ptr_r_meet )
|
||||
){
|
||||
|
||||
if (
|
||||
( $ptr_f =~ /$ptr/ ) ||
|
||||
( $ptr_l =~ /$ptr/ )
|
||||
){
|
||||
$ptr_r_meet=1;
|
||||
}
|
||||
|
||||
$ptr=pop( @ptrs_r );
|
||||
}
|
||||
}
|
||||
|
||||
# handle inversion
|
||||
$port_meet = $port_meet ^ $self->{port_invert};
|
||||
$protocol_meet = $protocol_meet ^ $self->{protocol_invert};
|
||||
$cidr_meet = $cidr_meet ^ $self->{cidr_invert};
|
||||
$state_meet = $state_meet ^ $self->{state_invert};
|
||||
$ptr_require = $ptr_require ^ $self->{ptr_invert};
|
||||
$ptr_r_require = $ptr_r_require ^ $self->{ptr_r_invert};
|
||||
|
||||
# if these are all good, add them
|
||||
if (
|
||||
$port_meet && $protocol_meet && $cidr_meet && $state_meet
|
||||
$port_meet && $protocol_meet && $cidr_meet && $state_meet &&
|
||||
$ptr_meet && $ptr_r_meet
|
||||
){
|
||||
push( @found, {
|
||||
'foreign_port'=>$foreign_port,
|
||||
|
@ -322,6 +642,8 @@ sub search{
|
|||
'recvq'=>$recvq,
|
||||
'proto'=>$protocol,
|
||||
'state'=>$state,
|
||||
'local_pp'=>$local_pp,
|
||||
'foreign_pp'=>$foreign_pp,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -393,6 +715,38 @@ sub set_cidrs{
|
|||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_cidrs_invert
|
||||
|
||||
This sets if the CIDRs search should be inverted or not.
|
||||
|
||||
One value is taken and that is a boolean.
|
||||
|
||||
# if it does not match, hit on it
|
||||
$search->set_cidrs_invert(1);
|
||||
|
||||
# only hit on matches, the default
|
||||
$search->set_cidrs_invert; # or...
|
||||
$search->set_cidrs_invert(0);
|
||||
|
||||
=cut
|
||||
|
||||
sub set_cidrs_invert{
|
||||
my $self=$_[0];
|
||||
my $bool=$_[1];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ( $bool ){
|
||||
$self->{cidr_invert}=1;
|
||||
}else{
|
||||
$self->{cidr_invert}=0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_ports
|
||||
|
||||
This sets the ports to search for in either
|
||||
|
@ -458,6 +812,38 @@ sub set_ports{
|
|||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_ports_invert
|
||||
|
||||
This sets if the ports search should be inverted or not.
|
||||
|
||||
One value is taken and that is a boolean.
|
||||
|
||||
# if it does not match, hit on it
|
||||
$search->set_port_invert(1);
|
||||
|
||||
# only hit on matches, the default
|
||||
$search->set_port_invert; # or...
|
||||
$search->set_port_invert(0);
|
||||
|
||||
=cut
|
||||
|
||||
sub set_ports_invert{
|
||||
my $self=$_[0];
|
||||
my $bool=$_[1];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ( $bool ){
|
||||
$self->{port_invert}=1;
|
||||
}else{
|
||||
$self->{port_invert}=0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_protocols
|
||||
|
||||
Sets the list of desired protocols to match.
|
||||
|
@ -474,9 +860,6 @@ Starting and trailing white space is removed.
|
|||
|
||||
# Set the desired ports to the contents of @protocols.
|
||||
$search->set_protocols( \@protocols );
|
||||
if ( $search->error ){
|
||||
warn("Bad value in ports array");
|
||||
}
|
||||
|
||||
# removes any previous selections
|
||||
$search->set_protocols;
|
||||
|
@ -516,6 +899,188 @@ sub set_protocols{
|
|||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_protocols_invert
|
||||
|
||||
This sets if the protocols search should be inverted or not.
|
||||
|
||||
One value is taken and that is a boolean.
|
||||
|
||||
# if it does not match, hit on it
|
||||
$search->set_port_invert(1);
|
||||
|
||||
# only hit on matches, the default
|
||||
$search->set_protocol_invert; # or...
|
||||
$search->set_protocol_invert(0);
|
||||
|
||||
=cut
|
||||
|
||||
sub set_protocols_invert{
|
||||
my $self=$_[0];
|
||||
my $bool=$_[1];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ( $bool ){
|
||||
$self->{protocol_invert}=1;
|
||||
}else{
|
||||
$self->{protocol_invert}=0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_ptrs
|
||||
|
||||
This sets a list of PTRs to search for.
|
||||
|
||||
One value is taken and that is a array.
|
||||
|
||||
If this is undef, then previous settings will be cleared.
|
||||
|
||||
White space, [\ \t], at the start or end of each
|
||||
item is removed. It is then converted to lowercase
|
||||
and saved for later lookup.
|
||||
|
||||
# Set the desired PTRs to the contents of @ptrs.
|
||||
$search->set_ptrs( \@ptrs );
|
||||
|
||||
# removes any previous selections
|
||||
$search->set_ptrs;
|
||||
|
||||
=cut
|
||||
|
||||
sub set_ptrs{
|
||||
my $self=$_[0];
|
||||
my @ptrs;
|
||||
if ( defined( $_[1] ) ){
|
||||
@ptrs=@{ $_[1] };
|
||||
}
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ( !defined( $ptrs[0] ) ){
|
||||
$self->{ptrs}={};
|
||||
}
|
||||
|
||||
# convert each one to a array
|
||||
my %lookup_hash;
|
||||
my $ptr=pop( @ptrs );
|
||||
while( defined( $ptr ) ){
|
||||
$ptr=~s/^[\ \t]*//;
|
||||
$ptr=~s/^[\ \t]*//;
|
||||
|
||||
#create a LCed version of the ptr name
|
||||
$lookup_hash{ lc( $ptr) }=1;
|
||||
|
||||
$ptr=pop( @ptrs );
|
||||
}
|
||||
|
||||
# save it for later use
|
||||
$self->{ptrs}=\%lookup_hash;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_ptrs_invert
|
||||
|
||||
This sets if the PTRs search should be inverted or not.
|
||||
|
||||
One value is taken and that is a boolean.
|
||||
|
||||
# if it does not match, hit on it
|
||||
$search->set_ptrs_invert(1);
|
||||
|
||||
# only hit on match, the default
|
||||
$search->set_ptrs_invert; # or...
|
||||
$search->set_ptrs_invert(0);
|
||||
|
||||
=cut
|
||||
|
||||
sub set_ptrs_invert{
|
||||
my $self=$_[0];
|
||||
my $bool=$_[1];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ( $bool ){
|
||||
$self->{ptr_invert}=1;
|
||||
}else{
|
||||
$self->{ptr_invert}=0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_ptrs_r
|
||||
|
||||
This sets a list of PTRs to search for via regexp
|
||||
|
||||
One value is taken and that is a array.
|
||||
|
||||
If this is undef, then previous settings will be cleared.
|
||||
|
||||
# Set the desired PTRs regexps to the contents of @ptrs.
|
||||
$search->set_ptrs_r( \@ptrs );
|
||||
|
||||
# removes any previous selections
|
||||
$search->set_ptrs;
|
||||
|
||||
=cut
|
||||
|
||||
sub set_ptrs_r{
|
||||
my $self=$_[0];
|
||||
my @regexps;
|
||||
if ( defined( $_[1] ) ){
|
||||
@regexps=@{ $_[1] };
|
||||
}
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
$self->{ptrs_r}=\@regexps;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_ptrs_invert
|
||||
|
||||
This sets if the regexp PTRs search should be inverted or not.
|
||||
|
||||
One value is taken and that is a boolean.
|
||||
|
||||
# if it does not match, hit on it
|
||||
$search->set_ptrs_r_invert(1);
|
||||
|
||||
# only hit on match, the default
|
||||
$search->set_ptrs_r_invert; # or...
|
||||
$search->set_ptrs_r_invert(0);
|
||||
|
||||
=cut
|
||||
|
||||
sub set_ptrs_r_invert{
|
||||
my $self=$_[0];
|
||||
my $bool=$_[1];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ( $bool ){
|
||||
$self->{ptr_r_invert}=1;
|
||||
}else{
|
||||
$self->{ptr_r_invert}=0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_states
|
||||
|
||||
Sets the list of desired states to match.
|
||||
|
@ -574,6 +1139,38 @@ sub set_states{
|
|||
return 1;
|
||||
}
|
||||
|
||||
=head2 set_ptrs_invert
|
||||
|
||||
This sets if the state search should be inverted or not.
|
||||
|
||||
One value is taken and that is a boolean.
|
||||
|
||||
# if it does not match, hit on it
|
||||
$search->set_state_invert(1);
|
||||
|
||||
# only hit on match, the default
|
||||
$search->set_state_invert; # or...
|
||||
$search->set_state_invert(0);
|
||||
|
||||
=cut
|
||||
|
||||
sub set_state_invert{
|
||||
my $self=$_[0];
|
||||
my $bool=$_[1];
|
||||
|
||||
if( ! $self->errorblank ){
|
||||
return undef;
|
||||
}
|
||||
|
||||
if ( $bool ){
|
||||
$self->{state_invert}=1;
|
||||
}else{
|
||||
$self->{state_invert}=0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
=head1 ERROR CODES / FLAGS
|
||||
|
||||
Error handling is provided by L<Error::Helper>.
|
||||
|
@ -634,7 +1231,7 @@ L<https://metacpan.org/release/Parse-Netstat-Search>
|
|||
|
||||
=item * Code Repo
|
||||
|
||||
L<http://gitea.eesdp.org/vvelox/Parse-Netstat-Search>
|
||||
L<https://gitea.eesdp.org/vvelox/Parse-Netstat-Search>
|
||||
|
||||
=back
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use strict;
|
||||
|
||||
use Test::More;
|
||||
use Data::Dumper;
|
||||
|
||||
BEGIN {
|
||||
use_ok('Parse::Netstat::Search');
|
||||
|
@ -82,6 +81,16 @@ my $res=[ '0', '1',
|
|||
'refs' => '0',
|
||||
'nextref' => '0'
|
||||
},
|
||||
{
|
||||
'foreign_host' => '*',
|
||||
'recvq' => '44',
|
||||
'local_port' => '123',
|
||||
'local_host' => 'fe80::1:%lo0',
|
||||
'foreign_port' => '*',
|
||||
'state' => '',
|
||||
'proto' => 'udp6',
|
||||
'sendq' => '33'
|
||||
},
|
||||
],
|
||||
}
|
||||
];
|
||||
|
@ -101,7 +110,7 @@ my $search=Parse::Netstat::Search->new;
|
|||
|
||||
#return all non-unix connections
|
||||
my @found=$search->search($res);
|
||||
ok( $#found eq '5', 'search, all') or diag('"'.$#found.'" number of returned connections for a empty search instead of "5"');
|
||||
ok( $#found eq '6', 'search, all') or diag('"'.$#found.'" number of returned connections for a empty search instead of "6"');
|
||||
|
||||
# set a state and make sure returns only those
|
||||
$search->set_states( ['LISTEN'] );
|
||||
|
@ -109,7 +118,7 @@ $search->set_states( ['LISTEN'] );
|
|||
ok( $#found eq '1', 'search, LISTEN state') or diag('"'.$#found.'" number of returned connections for LISTEN state search instead of "2"');
|
||||
$search->set_states;
|
||||
@found=$search->search($res);
|
||||
ok( $#found eq '5', 'search, state reset') or diag('"'.$#found.'" number of returned connections for a empty search instead of "5"... failed to reset the states');
|
||||
ok( $#found eq '6', 'search, state reset') or diag('"'.$#found.'" number of returned connections for a empty search instead of "6"... failed to reset the states');
|
||||
|
||||
# makes sure searching based on CIDR works
|
||||
# set a state and make sure returns only those
|
||||
|
@ -124,7 +133,7 @@ $search->set_cidrs( ['10.0.0.0/24','127.0.0.1/32'] );
|
|||
ok( $#found eq '4', 'search, CIDR 3') or diag('"'.$#found.'" number of returned connections for CIDR 127.0.0.1/32 10.0.0.0/24 search instead of "4"');
|
||||
$search->set_cidrs;
|
||||
@found=$search->search($res);
|
||||
ok( $#found eq '5', 'search, CIDR reset') or diag('"'.$#found.'" number of returned connections for a empty search instead of "5"... failed to reset the CIDRs');
|
||||
ok( $#found eq '6', 'search, CIDR reset') or diag('"'.$#found.'" number of returned connections for a empty search instead of "6"... failed to reset the CIDRs');
|
||||
|
||||
#make sure we can match multiple items
|
||||
$search->set_cidrs( ['127.0.0.0/24'] );
|
||||
|
@ -134,7 +143,7 @@ ok( $#found eq '0', 'search, CIDR+state') or diag('"'.$#found.'" number of retur
|
|||
$search->set_cidrs;
|
||||
$search->set_states;
|
||||
@found=$search->search($res);
|
||||
ok( $#found eq '5', 'search, CIDR+state reset') or diag('"'.$#found.'" number of returned connections for a empty search instead of "5"... failed to reset the CIDRs and states');
|
||||
ok( $#found eq '6', 'search, CIDR+state reset') or diag('"'.$#found.'" number of returned connections for a empty search instead of "6"... failed to reset the CIDRs and states');
|
||||
|
||||
#make sure we cans search based on protocols
|
||||
$search->set_protocols(['udp4']);
|
||||
|
@ -149,7 +158,7 @@ ok( $#found eq '0', 'search, Protocol+Listen') or diag('"'.$#found.'" number of
|
|||
$search->set_states;
|
||||
$search->set_protocols;
|
||||
@found=$search->search($res);
|
||||
ok( $#found eq '5', 'search, protocol+state reset') or diag('"'.$#found.'" number of returned connections for a empty search instead of "5"... failed to reset the protocols and states');
|
||||
ok( $#found eq '6', 'search, protocol+state reset') or diag('"'.$#found.'" number of returned connections for a empty search instead of "6"... failed to reset the protocols and states');
|
||||
|
||||
#make sure we can search based on ports
|
||||
$search->set_ports(['22']);
|
||||
|
@ -167,6 +176,17 @@ ok( $#found eq '0', 'search, port+state') or diag('"'.$#found.'" number of retur
|
|||
$search->set_states;
|
||||
$search->set_ports;
|
||||
@found=$search->search($res);
|
||||
ok( $#found eq '5', 'search, port+state reset') or diag('"'.$#found.'" number of returned connections for a empty search instead of "5"... failed to reset the ports and states');
|
||||
ok( $#found eq '6', 'search, port+state reset') or diag('"'.$#found.'" number of returned connections for a empty search instead of "6"... failed to reset the ports and states');
|
||||
|
||||
done_testing(20);
|
||||
# find all IPv6 addresses
|
||||
$search->set_cidrs( ['fe80::/32'] );
|
||||
@found=$search->search($res);
|
||||
ok( $#found eq '0', 'IPv6 CIDR search 1') or diag('"'.$#found.'" number of returned connections for fe80::/32 instead of "0"');
|
||||
ok( $found[0]->{local_pp} eq 'lo0', 'IPv6 % removal test') or diag('"local_pp" not defined for removed % section of IPv6 address. "lo0" expected');
|
||||
|
||||
# test for future regrestions in mixed IPv4/6 CIDR lists
|
||||
$search->set_cidrs( ['fe80::/32','192.168.0.0/16'] );
|
||||
@found=$search->search($res);
|
||||
ok( $#found eq '1', 'Mixed IPv4/6 CIDR search 1') or diag('"'.$#found.'" number of returned connections for fe80::/32,192.168.0.0/16 instead of "1"');
|
||||
|
||||
done_testing(23);
|
||||
|
|
Loading…
Reference in New Issue