[Rt-commit] rtir branch, ipv6, created. 2.6.0-23-gd7198e7
Ruslan Zakirov
ruz at bestpractical.com
Thu Apr 21 15:53:24 EDT 2011
The branch, ipv6 has been created
at d7198e76bbf953dfe0cb2a0abc65e95046e8f3da (commit)
- Log -----------------------------------------------------------------
commit 064a660e745a7fcf518cfd8670297e9bc613eb8d
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Thu Apr 21 23:25:34 2011 +0400
backport IPv6 support from RT4
diff --git a/lib/RT/IR.pm b/lib/RT/IR.pm
index 19c5a4f..8ca0b25 100644
--- a/lib/RT/IR.pm
+++ b/lib/RT/IR.pm
@@ -318,6 +318,7 @@ sub DefaultConstituency {
use Hook::LexWrap;
use Regexp::Common qw(RE_net_IPv4);
use Regexp::Common::net::CIDR;
+use Regexp::IPv6 qw($IPv6_re);
require Net::CIDR;
sub ParseIPRange {
@@ -327,6 +328,9 @@ sub ParseIPRange {
my $cidr = join( '.', map $_||0, (split /\./, $1)[0..3] ) ."/$2";
$arg = (Net::CIDR::cidr2range( $cidr ))[0] || $arg;
}
+ elsif ( $arg =~ /^(?:$IPv6_re|::)(?:\/\d+)?$/o ) {
+ $arg = (Net::CIDR::cidr2range( $arg ))[0] || $arg;
+ }
my ($sIP, $eIP);
if ( $arg =~ /^\s*($RE{net}{IPv4})\s*$/o ) {
@@ -336,6 +340,15 @@ sub ParseIPRange {
$sIP = sprintf "%03d.%03d.%03d.%03d", split /\./, $1;
$eIP = sprintf "%03d.%03d.%03d.%03d", split /\./, $2;
}
+ elsif ( $arg =~ /^($IPv6_re|::)$/o ) {
+ $sIP = ParseIP( $1 );
+ $eIP = $sIP;
+ }
+ elsif ( $arg =~ /^($IPv6_re|::)-($IPv6_re|::)$/o ) {
+ ($sIP, $eIP) = ( $1, $2 );
+ $sIP = ParseIP( $sIP );
+ $eIP = ParseIP( $eIP );
+ }
else {
return ();
}
@@ -345,6 +358,52 @@ sub ParseIPRange {
}
+sub ParseIP {
+ my $value = shift or return;
+ $value = lc $value;
+ $value =~ s!^\s+!!;
+ $value =~ s!\s+$!!;
+
+ if ( $value =~ /^($RE{net}{IPv4})$/o ) {
+ return sprintf "%03d.%03d.%03d.%03d", split /\./, $1;
+ }
+ elsif ( $value =~ /^(?:$IPv6_re|::)$/o ) {
+ # up_fields are before '::'
+ # low_fields are after '::' but without v4
+ # v4_fields are the v4
+ my ( @up_fields, @low_fields, @v4_fields );
+ my $v6;
+ if ( $value =~ /(.*:)(\d+\..*)/ ) {
+ ( $v6, my $v4 ) = ( $1, $2 );
+ chop $v6 unless $v6 =~ /::$/;
+ while ( $v4 =~ /(\d+)\.(\d+)/g ) {
+ push @v4_fields, sprintf '%.2x%.2x', $1, $2;
+ }
+ }
+ else {
+ $v6 = $value;
+ }
+
+ my ( $up, $low );
+ if ( $v6 =~ /::/ ) {
+ ( $up, $low ) = split /::/, $v6;
+ }
+ else {
+ $up = $v6;
+ }
+
+ @up_fields = split /:/, $up;
+ @low_fields = split /:/, $low if $low;
+
+ my @zero_fields =
+ ('0000') x ( 8 - @v4_fields - @up_fields - @low_fields );
+ my @fields = ( @up_fields, @zero_fields, @low_fields, @v4_fields );
+
+ return join ':', map { sprintf "%.4x", hex "0x$_" } @fields;
+ }
+ return;
+}
+
# limit formatting "%03d.%03d.%03d.%03d"
# "= 'sIP-eIP'" => "( >=sIP AND <=eIP)"
# "!= 'sIP-eIP'" => "( <sIP OR >eIP)"
@@ -353,10 +412,14 @@ require RT::Tickets;
wrap 'RT::Tickets::_CustomFieldLimit',
pre => sub {
return if $_[2] && $_[2] =~ /^[<>]=?$/;
- return unless $_[3] =~ /^\s*($RE{net}{IPv4})\s*(?:-\s*($RE{net}{IPv4})\s*)?$/o;
- my ($start_ip, $end_ip) = ($1, ($2 || $1));
- $_ = sprintf "%03d.%03d.%03d.%03d", split /\./, $_
- for $start_ip, $end_ip;
+
+ my ($start_ip, $end_ip);
+ return unless
+ $_[3] =~ /^\s*($RE{net}{IPv4})\s*(?:-\s*($RE{net}{IPv4})\s*)?$/o
+ || $_[3] =~ /^\s*($IPv6_re|::)\s*(?:-\s*($IPv6_re|::)\s*)?$/o;
+
+ ($start_ip, $end_ip) = ($1, ($2 || $1));
+ $_ = ParseIP( $_ ) for $start_ip, $end_ip;
($start_ip, $end_ip) = ($end_ip, $start_ip) if $start_ip gt $end_ip;
my ($tickets, $field, $op, $value, %rest) = @_[0..($#_-1)];
@@ -400,14 +463,20 @@ wrap 'RT::Tickets::_CustomFieldLimit',
$_[-1] = ref $_[-1]? [1]: 1;
};
+my $IPv6_mask_re = qr{12[0-8]|1[01][0-9]|[1-9]?[0-9]};
+
# "[!]= 'CIDR'" => "op 'sIP-eIP'"
wrap 'RT::Tickets::_CustomFieldLimit',
pre => sub {
- return unless $_[3] =~ /^\s*$RE{net}{CIDR}{IPv4}{-keep}\s*$/o;
- # convert incomplete 192.168/24 to 192.168.0.0/24 format
- my $cidr = join( '.', map $_||0, (split /\./, $1)[0..3] ) ."/$2";
- # convert to range and continue, it will be catched by next wrapper
- $_[3] = (Net::CIDR::cidr2range( $cidr ))[0] || $_[3];
+ # convert CIDR (IP/mask) to range (IP-IP) and continue,
+ # it will be catched by next wrapper
+ if ( $_[3] =~ /^\s*$RE{net}{CIDR}{IPv4}{-keep}\s*$/o ) {
+ # convert incomplete 192.168/24 to 192.168.0.0/24 format
+ my $cidr = join( '.', map $_||0, (split /\./, $1)[0..3] ) ."/$2";
+ $_[3] = (Net::CIDR::cidr2range( $cidr ))[0] || $_[3];
+ } elsif ( $_[3] =~ m{^\s*($IPv6_re/$IPv6_mask_re)\s*$}o ) {
+ $_[3] = (Net::CIDR::cidr2range( $1 ))[0] || $_[3];
+ }
};
$RT::Tickets::dispatch{'CUSTOMFIELD'} = \&RT::Tickets::_CustomFieldLimit;
@@ -454,14 +523,21 @@ wrap 'RT::ObjectCustomFieldValue::Content',
post => sub {
return unless $_[-1];
my $val = ref $_[-1]? \$_[-1][0]: \$_[-1];
- return unless $$val =~ /^\s*($re_ip_serialized)\s*$/o;
- $$val = sprintf "%d.%d.%d.%d", split /\./, $1;
-
- my $large_content = $obj->__Value('LargeContent');
- return if !$large_content
- || $large_content !~ /^\s*($re_ip_serialized)\s*$/o;
- my $eIP = sprintf "%d.%d.%d.%d", split /\./, $1;
- $$val .= '-'. $eIP unless $$val eq $eIP;
+
+ if ( $$val =~ /^\s*($re_ip_serialized)\s*$/o ) {
+ $$val = sprintf "%d.%d.%d.%d", split /\./, $1;
+
+ my $large_content = $obj->__Value('LargeContent');
+ return if !$large_content
+ || $large_content !~ /^\s*($re_ip_serialized)\s*$/o;
+ my $eIP = sprintf "%d.%d.%d.%d", split /\./, $1;
+ $$val .= '-'. $eIP unless $$val eq $eIP;
+ } elsif ( $$val =~ /^\s*($IPv6_re)\s*$/o ) {
+ my $large_content = $obj->__Value('LargeContent');
+ return if !$large_content || $large_content eq $$val
+ || $large_content !~ /^\s*($IPv6_re)\s*$/o;
+ $$val .= '-'. $1;
+ }
return;
};
}
commit 5bc5f7b604e4caa4de017a4eda25c232bcdf3a9b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Thu Apr 21 23:26:13 2011 +0400
update IPs extraction action with IPv6 support
diff --git a/lib/RT/Action/RTIR_FindIP.pm b/lib/RT/Action/RTIR_FindIP.pm
index f3872d9..5e4465a 100644
--- a/lib/RT/Action/RTIR_FindIP.pm
+++ b/lib/RT/Action/RTIR_FindIP.pm
@@ -7,8 +7,15 @@ use base qw(RT::Action::RTIR);
use Regexp::Common qw(net);
use Regexp::Common::net::CIDR ();
+use Regexp::IPv6 qw($IPv6_re);
use Net::CIDR ();
+my $IPv4_mask_re = qr{3[0-2]|[1-2]?[0-9]};
+my $IPv6_mask_re = qr{12[0-8]|1[01][0-9]|[1-9]?[0-9]};
+my $IP4_re = qr[(?<![0-9.])(?!0\.0\.0\.0)($RE{net}{IPv4})(?!/$IPv4_mask_re)(?![0-9.])];
+my $IP6_re = qr[(?<![0-9a-fA-F:.])($IPv6_re)(?:/($IPv6_mask_re))?(?![0-9a-fA-F:.])];
+my $IP_re = qr{$IP6_re|$IP4_re|$RE{net}{CIDR}{IPv4}{-keep}};
+
=head2 Prepare
Always run this.
@@ -48,25 +55,30 @@ sub Commit {
my $spots_left = $how_many_can - keys %existing;
my $content = $attach->Content || '';
-# 0.0.0.0 is illegal IP address
- my @IPs = ( $content =~ /(?<!\d)(?!0\.0\.0\.0)($RE{net}{IPv4})(?!\d)(?!\/(?:3[0-2]|[1-2]?[0-9])(?:\D|\z))/go );
- foreach my $ip ( @IPs ) {
- $spots_left -= $self->AddIP(
- IP => $ip,
- CustomField => $cf,
- Skip => \%existing,
- );
- return 1 unless $spots_left;
- }
-
-# but 0.0.0.0/0 is legal CIDR
- my @CIDRs = ( $content =~ /(?<![0-9.])$RE{net}{CIDR}{IPv4}{-keep}(?!\.?[0-9])/go );
- while ( my ($addr, $bits) = splice @CIDRs, 0, 2 ) {
- my $cidr = join( '.', map $_||0, (split /\./, $addr)[0..3] ) ."/$bits";
- my $range = (Net::CIDR::cidr2range( $cidr ))[0] or next;
- $spots_left -= $self->AddIP(
- IP => $range, CustomField => $cf, Skip => \%existing
- );
+ while ( $content =~ m/$IP_re/go ) {
+ if ( $1 && defined $2 ) { # IPv6/mask
+ my $range = (Net::CIDR::cidr2range( "$1/$2" ))[0] or next;
+ $spots_left -= $self->AddIP(
+ IP => $range, CustomField => $cf, Skip => \%existing
+ );
+ }
+ elsif ( $1 ) { # IPv6
+ $spots_left -= $self->AddIP(
+ IP => $1, CustomField => $cf, Skip => \%existing
+ );
+ }
+ elsif ( $3 ) { # IPv4
+ $spots_left -= $self->AddIP(
+ IP => $3, CustomField => $cf, Skip => \%existing
+ );
+ }
+ elsif ( $4 && defined $5 ) { # IPv4/mask
+ my $cidr = join( '.', map $_||0, (split /\./, $4)[0..3] ) ."/$5";
+ my $range = (Net::CIDR::cidr2range( $cidr ))[0] or next;
+ $spots_left -= $self->AddIP(
+ IP => $range, CustomField => $cf, Skip => \%existing
+ );
+ }
return 1 unless $spots_left;
}
commit 9e5d73d048c177e84a3280f4d1e68ce890104a7c
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Thu Apr 21 23:27:51 2011 +0400
extend IP's pattern with IPv6
diff --git a/etc/initialdata b/etc/initialdata
index 3aebac3..eb811ef 100644
--- a/etc/initialdata
+++ b/etc/initialdata
@@ -33,7 +33,8 @@
use Regexp::Common qw(net);
use Regexp::Common::net::CIDR();
-my $ip_pattern = qr{(?#IP/IP-IP/CIDR)^(?:|\s*$RE{net}{IPv4}(?:\s*-\s*$RE{net}{IPv4})?\s*|$RE{net}{CIDR}{IPv4})$};
+use Regexp::IPv6 qw($IPv6_re);
+my $ip_pattern = qr{(?#IP/IP-IP/CIDR)^(?:|\s*$RE{net}{IPv4}(?:\s*-\s*$RE{net}{IPv4})?\s*|$RE{net}{CIDR}{IPv4}|$IPv6_re(?:\/\d+)?|$IPv6_re-$IPv6_re)$};
@CustomFields = (
commit 687617e35fbd29c12732735125a3cb5d1a6dab5b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Thu Apr 21 23:29:32 2011 +0400
test IPv6 support
diff --git a/t/custom-fields/ipv6.t b/t/custom-fields/ipv6.t
new file mode 100644
index 0000000..b8b5c54
--- /dev/null
+++ b/t/custom-fields/ipv6.t
@@ -0,0 +1,556 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::IR::Test tests => 772;
+
+RT::Test->started_ok;
+my $agent = default_agent();
+
+use_ok('RT::IR');
+
+my %valid = (
+ 'abcd:' x 7 . 'abcd' => 'abcd:' x 7 . 'abcd',
+ '034:' x 7 . '034' => '0034:' x 7 . '0034',
+ 'abcd::' => 'abcd:' . '0000:' x 6 . '0000',
+ '::abcd' => '0000:' x 7 . 'abcd',
+ 'abcd::034' => 'abcd:' . '0000:' x 6 . '0034',
+ 'abcd::192.168.1.1' => 'abcd:' . '0000:' x 5 . 'c0a8:0101',
+ '::192.168.1.1' => '0000:' x 6 . 'c0a8:0101',
+);
+
+my %test_set = (
+ 'abcd:' x 7 . 'abcd' => 'abcd:' x 7 . 'abcd',
+ 'abcd::034' => 'abcd:' . '0000:' x 6 . '0034',
+ '::192.168.1.1' => '0000:' x 6 . 'c0a8:0101',
+);
+my %test_cidr = (
+ 'abcd:' x 7 . 'abcd/32' => 'abcd:abcd'. ':0000' x 6 .'-'. 'abcd:abcd'. ':ffff' x 6,
+ '::192.168.1.1/120' => '0000:' x 6 . 'c0a8:0100' .'-'. '0000:' x 6 . 'c0a8:01ff',
+);
+
+my $cf;
+diag "load and check basic properties of the IP CF" if $ENV{'TEST_VERBOSE'};
+{
+ my $cfs = RT::CustomFields->new( $RT::SystemUser );
+ $cfs->Limit( FIELD => 'Name', VALUE => 'IP' );
+ is( $cfs->Count, 1, "found one CF with name 'IP'" );
+
+ $cf = $cfs->First;
+ is( $cf->Type, 'Freeform', 'type check' );
+ is( $cf->LookupType, 'RT::Queue-RT::Ticket', 'lookup type check' );
+ ok( !$cf->MaxValues, "unlimited number of values" );
+ ok( !$cf->Disabled, "not disabled" );
+}
+
+diag "check that CF applies to all RTIR's queues" if $ENV{'TEST_VERBOSE'};
+{
+ foreach ( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+ my $queue = RT::Queue->new( $RT::SystemUser );
+ $queue->Load( $_ );
+ ok( $queue->id, 'loaded queue '. $_ );
+ my $cfs = $queue->TicketCustomFields;
+ $cfs->Limit( FIELD => 'id', VALUE => $cf->id, ENTRYAGGREGATOR => 'AND' );
+ is( $cfs->Count, 1, 'field applies to queue' );
+ }
+}
+my $rtir_user = RT::CurrentUser->new( rtir_user() );
+
+diag "create a ticket via web and set IP" if $ENV{'TEST_VERBOSE'};
+while ( my ($short, $full) = each %valid ) {
+ my $incident_id; # block couldn't be created without incident id
+ foreach my $queue( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+ diag "create a ticket in the '$queue' queue" if $ENV{'TEST_VERBOSE'};
+
+ my $id = $agent->create_rtir_ticket_ok(
+ $queue,
+ {
+ Subject => "test ip",
+ ( $queue eq 'Blocks' ? ( Incident => $incident_id ) : () ),
+ },
+ { IP => $short },
+ );
+ $incident_id = $id if $queue eq 'Incidents';
+
+ $agent->display_ticket( $id);
+ $agent->content_like( qr/\Q$full/, "IP on the page" );
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $full, 'correct value' );
+ }
+}
+
+diag "create a ticket via web with IP in message" if $ENV{'TEST_VERBOSE'};
+while ( my ($short, $full) = each %test_set ) {
+ my $incident_id; # block couldn't be created without incident id
+ foreach my $queue( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+ diag "create a ticket in the '$queue' queue" if $ENV{'TEST_VERBOSE'};
+
+ my $id = $agent->create_rtir_ticket_ok(
+ $queue,
+ {
+ Subject => "test ip in message",
+ ($queue eq 'Blocks'? (Incident => $incident_id): ()),
+ Content => "$short",
+ },
+ );
+ $incident_id = $id if $queue eq 'Incidents';
+
+ $agent->display_ticket( $id );
+ $agent->content_like( qr/\Q$full/, "IP on the page" );
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok( $ticket->id, 'loaded ticket' );
+ is( $ticket->FirstCustomFieldValue('IP'), $full, 'correct value' );
+ }
+}
+
+diag "create a ticket via web with CIDR" if $ENV{'TEST_VERBOSE'};
+while ( my ($short, $full) = each %test_cidr ) {
+ my $incident_id; # block couldn't be created without incident id
+ foreach my $queue( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+ diag "create a ticket in the '$queue' queue" if $ENV{'TEST_VERBOSE'};
+
+ my $id = $agent->create_rtir_ticket_ok(
+ $queue,
+ {
+ Subject => "test ip",
+ ($queue eq 'Blocks'? (Incident => $incident_id): ()),
+ },
+ { IP => $short },
+ );
+ $incident_id = $id if $queue eq 'Incidents';
+
+ $agent->display_ticket( $id);
+ $agent->content_like( qr/\Q$full/, "IP range on the page" );
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok( $ticket->id, 'loaded ticket' );
+ my $values = $ticket->CustomFieldValues('IP');
+ my %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+ ok( $has{ $full }, "has value" )
+ or diag "but has values ". join ", ", keys %has;
+ }
+}
+
+diag "create a ticket via web with CIDR in message" if $ENV{'TEST_VERBOSE'};
+while ( my ($short, $full) = each %test_cidr ) {
+ my $incident_id; # block couldn't be created without incident id
+ foreach my $queue( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+ diag "create a ticket in the '$queue' queue" if $ENV{'TEST_VERBOSE'};
+
+ my $id = $agent->create_rtir_ticket_ok(
+ $queue,
+ {
+ Subject => "test ip in message",
+ ($queue eq 'Blocks'? (Incident => $incident_id): ()),
+ Content => "$short",
+ },
+ );
+ $incident_id = $id if $queue eq 'Incidents';
+
+ $agent->display_ticket( $id);
+ $agent->content_like( qr/\Q$full/, "IP range on the page" );
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok( $ticket->id, 'loaded ticket' );
+ my $values = $ticket->CustomFieldValues('IP');
+ my %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+ ok( $has{ $full }, "has value" )
+ or diag "but has values ". join ", ", keys %has;
+ }
+}
+
+diag "create a ticket and edit IP field using Edit page" if $ENV{'TEST_VERBOSE'};
+{
+ my $i = 0;
+ my $incident_id; # block couldn't be created without incident id
+ foreach my $queue( 'Incidents', 'Incident Reports', 'Investigations', 'Blocks' ) {
+ diag "create a ticket in the '$queue' queue" if $ENV{'TEST_VERBOSE'};
+
+ my $id = $agent->create_rtir_ticket_ok(
+ $queue,
+ {
+ Subject => "test ip in message",
+ ($queue eq 'Blocks'? (Incident => $incident_id): ()),
+ },
+ );
+ $incident_id = $id if $queue eq 'Incidents';
+ $agent->display_ticket( $id);
+
+ my $field_name = "Object-RT::Ticket-$id-CustomField-". $cf->id ."-Values";
+
+diag "set IP" if $ENV{'TEST_VERBOSE'};
+ my $val = 'abcd::192.168.1.1';
+ $agent->follow_link_ok({text => 'Edit', n => "1"}, "Followed 'Edit' link");
+ $agent->form_number(3);
+ like( $agent->value($field_name), qr/^\s*$/, 'IP is empty' );
+ $agent->field( $field_name => $val );
+ $agent->click('SaveChanges');
+
+ $agent->content_like( qr/\Q$valid{$val}/, "IP on the page" );
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok( $ticket->id, 'loaded ticket' );
+ my $values = $ticket->CustomFieldValues('IP');
+ my %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+ is( scalar values %has, 1, "one IP were added");
+ ok( $has{ $valid{ $val } }, "has value" )
+ or diag "but has values ". join ", ", keys %has;
+
+diag "set IP with spaces around" if $ENV{'TEST_VERBOSE'};
+ $val = " ::192.168.1.1 \n ";
+ $agent->follow_link_ok({text => 'Edit', n => "1"}, "Followed 'Edit' link");
+ $agent->form_number(3);
+ like( $agent->value($field_name), qr/^\s*\Q$valid{'abcd::192.168.1.1'}\E\s*$/, 'IP is in input box' );
+ $agent->field( $field_name => $val );
+ $agent->click('SaveChanges');
+
+ $agent->content_like( qr/\Q$valid{'::192.168.1.1'}/, "IP on the page" );
+
+ $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok( $ticket->id, 'loaded ticket' );
+ $values = $ticket->CustomFieldValues('IP');
+ %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+ is( scalar values %has, 1, "one IP were added");
+ ok( $has{ $valid{'::192.168.1.1'} }, "has value" )
+ or diag "but has values ". join ", ", keys %has;
+
+diag "replace IP with a range" if $ENV{'TEST_VERBOSE'};
+ $val = '::192.168.1.1/120';
+ $agent->follow_link_ok({text => 'Edit', n => "1"}, "Followed 'Edit' link");
+ $agent->form_number(3);
+ like( $agent->value($field_name), qr/^\s*\Q$valid{'::192.168.1.1'}\E\s*$/, 'IP is in input box' );
+ $agent->field( $field_name => $val );
+ $agent->click('SaveChanges');
+
+ $agent->content_like( qr/\Q$test_cidr{ $val }/, "IP on the page" );
+
+ $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok( $ticket->id, 'loaded ticket' );
+ $values = $ticket->CustomFieldValues('IP');
+ %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+ is( scalar values %has, 1, "one IP were added");
+ ok( $has{ $test_cidr{ $val } }, "has value" )
+ or diag "but has values ". join ", ", keys %has;
+ }
+}
+
+#diag "check that we parse correct IPs only" if $ENV{'TEST_VERBOSE'};
+# XXX: waiting for regressions
+
+diag "check that IPs in messages don't add duplicates" if $ENV{'TEST_VERBOSE'};
+{
+ my $id = $agent->create_ir( {
+ Subject => "test ip",
+ Content => 'abcd::192.168.1.1 abcd::192.168.1.1 abcd::192.168.1.1/128'
+ } );
+ ok($id, "created first ticket");
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok( $ticket->id, 'loaded ticket' );
+
+ my $values = $ticket->CustomFieldValues('IP');
+ my %has;
+ $has{ $_->Content }++ foreach @{ $values->ItemsArrayRef };
+ is(scalar values %has, 1, "one IP were added");
+ ok(!grep( $_ != 1, values %has ), "no duplicated values");
+ ok($has{ $valid{ 'abcd::192.168.1.1' } }, "IP is there")
+ or diag "but has values ". join ", ", keys %has;
+}
+
+diag "search tickets by IP" if $ENV{'TEST_VERBOSE'};
+{
+ my $id = $agent->create_ir( {
+ Subject => "test ip",
+ Content => '::192.168.1.1/120',
+ } );
+ ok($id, "created first ticket");
+
+ my $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("id = $id AND CF.{IP} = '::192.168.1.1'");
+ ok( $tickets->Count, "found tickets" );
+
+ my $flag = 1;
+ while ( my $ticket = $tickets->Next ) {
+ my %has = map { $_->Content => 1 } @{ $ticket->CustomFieldValues('IP')->ItemsArrayRef };
+ next if $has{ $test_cidr{'::192.168.1.1/120'} };
+ $flag = 0;
+ ok(0, "ticket #". $ticket->id ." has no range ::192.168.1.1/120, but should")
+ or diag "but has values ". join ", ", keys %has;
+ last;
+ }
+ ok(1, "all tickets has IP ::192.168.1.1/120") if $flag;
+}
+
+diag "search tickets by IP range" if $ENV{'TEST_VERBOSE'};
+{
+ my $id = $agent->create_ir( {
+ Subject => "test ip",
+ Content => '::c0a8:01a0'
+ } );
+ ok($id, "created first ticket");
+
+ my $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("id = $id AND CF.{IP} = '::c0a8:0101-::c0a8:01ff'");
+ ok( $tickets->Count, "found tickets" );
+
+ my $flag = 1;
+ while ( my $ticket = $tickets->Next ) {
+ my %has = map { $_->Content => 1 } @{ $ticket->CustomFieldValues('IP')->ItemsArrayRef };
+ next if grep /^0000(:0000){5}:c0a8:01/, keys %has;
+ $flag = 0;
+ ok(0, "ticket #". $ticket->id ." has no IP from '::c0a8::-::c0a8:01ff', but should");
+ last;
+ }
+ ok(1, "all tickets have at least one IP from the range") if $flag;
+}
+
+diag "create two tickets with different IPs and check several searches" if $ENV{'TEST_VERBOSE'};
+{
+ my $id1 = $agent->create_ir( { Subject => "test ip" }, { IP => '::c0a8:3310' } );
+ ok($id1, "created first ticket");
+ my $id2 = $agent->create_ir( { Subject => "test ip" }, { IP => '::c0a8:aa10' } );
+ ok($id2, "created second ticket");
+
+ my $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("id = $id1 OR id = $id2");
+ is( $tickets->Count, 2, "found both tickets by 'id = x OR y'" );
+
+ # IP
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:3310'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:aa10'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+
+ # IP/32 - one address
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:3310/128'");
+ is( $tickets->Count, 1, "found one ticket" ) or diag $tickets->BuildSelectQuery;
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:aa10/128'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+
+ # IP range
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:3300-::c0a8:33ff'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:aa00-::c0a8:aaff'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+
+ # IP range, with start IP greater than end
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:33ff-::c0a8:3300'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:aaff-::c0a8:aa00'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+
+ # CIDR/120
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:3300/120'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:aa00/120'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+
+ # IP is not in CIDR/120
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} != '::c0a8:3300/120'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} != '::c0a8:aa00/120'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+
+ # CIDR or CIDR
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND "
+ ."(CF.{IP} = '::c0a8:3300/120' OR CF.{IP} = '::c0a8:aa00/120')");
+ is( $tickets->Count, 2, "found both tickets" );
+
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::c0a8:0000/0'");
+ is( $tickets->Count, 2, "found both tickets" ) or diag $tickets->BuildSelectQuery;
+}
+
+diag "create two tickets with different IP ranges and check several searches" if $ENV{'TEST_VERBOSE'};
+{
+ my $id1 = $agent->create_ir( { Subject => "test ip" }, { IP => '::192.168.21.0-::192.168.21.127' } );
+ ok($id1, "created first ticket");
+ my $id2 = $agent->create_ir( { Subject => "test ip" }, { IP => '::192.168.21.128-::192.168.21.255' } );
+ ok($id2, "created second ticket");
+
+ my $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("id = $id1 OR id = $id2");
+ is( $tickets->Count, 2, "found both tickets by 'id = x OR y'" );
+
+ # IP
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.0'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.64'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.127'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.128'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.191'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.255'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+
+ # IP/32 - one address
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.63/128'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.191/128'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id2, "correct value" );
+
+ # IP range, lower than both
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.20.0-::192.168.20.255'");
+ is( $tickets->Count, 0, "didn't finnd ticket" ) or diag "but found ". $tickets->First->id;
+
+ # IP range, intersect with the first range
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.20.0-::192.168.21.63'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+
+ # IP range, equal to the first range
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.0-::192.168.21.127'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+
+ # IP range, lay inside the first range
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.31-::192.168.21.63'");
+ is( $tickets->Count, 1, "found one ticket" );
+ is( $tickets->First->id, $id1, "correct value" );
+
+ # IP range, intersect with the ranges
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.31-::192.168.21.191'");
+ is( $tickets->Count, 2, "found both tickets" );
+
+ # IP range, equal to range from the starting IP of the first ticket to the ending IP of the second
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.21.0-::192.168.21.255'");
+ is( $tickets->Count, 2, "found both tickets" );
+
+ # IP range, has the both ranges inside it
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.0.0/112'");
+ is( $tickets->Count, 2, "found both tickets" );
+
+ # IP range, greater than both
+ $tickets = RT::Tickets->new( $rtir_user );
+ $tickets->FromSQL("(id = $id1 OR id = $id2) AND CF.{IP} = '::192.168.22.0/120'");
+ is( $tickets->Count, 0, "didn't finnd ticket" ) or diag "but found ". $tickets->First->id;
+}
+
+diag "merge ticket, IPs should be merged";
+{
+ my $incident_id = $agent->create_rtir_ticket_ok(
+ 'Incidents',
+ { Subject => "test" },
+ );
+ my $b1_id = $agent->create_block(
+ {
+ Subject => "test ip",
+ Incident => $incident_id,
+ },
+ { IP => '::172.16.0.1' },
+ );
+ my $b2_id = $agent->create_block(
+ {
+ Subject => "test ip",
+ Incident => $incident_id,
+ },
+ { IP => '::172.16.0.2' },
+ );
+
+ $agent->display_ticket( $b1_id);
+ $agent->follow_link_ok({ text => 'Merge' }, "Followed merge link");
+ $agent->form_number(3);
+ $agent->field('SelectedTicket', $b2_id);
+ $agent->submit;
+ $agent->ok_and_content_like( qr{Merge Successful}, 'Merge Successful');
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $b1_id );
+ ok $ticket->id, 'loaded ticket';
+ my $values = $ticket->CustomFieldValues('IP');
+ my %has = map { $_->Content => 1 } @{ $values->ItemsArrayRef };
+ is( scalar values %has, 2, "both IPs are there");
+ ok( $has{ '0000:'x6 .'ac10:0001' }, "has value" )
+ or diag "but has values ". join ", ", keys %has;
+ ok( $has{ '0000:'x6 .'ac10:0002' }, "has value" )
+ or diag "but has values ". join ", ", keys %has;
+}
+
+diag "merge ticket with the same IP";
+{
+ my $incident_id = $agent->create_rtir_ticket_ok(
+ 'Incidents',
+ { Subject => "test" },
+ );
+ my $b1_id = $agent->create_block(
+ {
+ Subject => "test ip",
+ Incident => $incident_id,
+ },
+ { IP => '::172.16.0.1' },
+ );
+ my $b2_id = $agent->create_block(
+ {
+ Subject => "test ip",
+ Incident => $incident_id,
+ },
+ { IP => '::172.16.0.1' },
+ );
+
+ $agent->display_ticket( $b1_id);
+ $agent->follow_link_ok({ text => 'Merge' }, "Followed merge link");
+ $agent->form_number(3);
+ $agent->field('SelectedTicket', $b2_id);
+ $agent->submit;
+ $agent->ok_and_content_like( qr{Merge Successful}, 'Merge Successful');
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $b1_id );
+ ok $ticket->id, 'loaded ticket';
+ my $values = $ticket->CustomFieldValues('IP');
+ my @has = map $_->Content, @{ $values->ItemsArrayRef };
+ is( scalar @has, 1, "only one IP") or diag "values: @has";
+ is( $has[0], '0000:'x6 .'ac10:0001', "has value" );
+}
+
commit d56f63a53ece8a70a62977027f82c9fb9bb91ab3
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Thu Apr 21 23:52:16 2011 +0400
IPv6 in quick search and make clicky
diff --git a/html/Callbacks/RTIR/Elements/MakeClicky/Default b/html/Callbacks/RTIR/Elements/MakeClicky/Default
index 0adfe9e..f33d7ca 100644
--- a/html/Callbacks/RTIR/Elements/MakeClicky/Default
+++ b/html/Callbacks/RTIR/Elements/MakeClicky/Default
@@ -99,10 +99,12 @@ my %actions;
},
);
+use Regexp::IPv6 qw($IPv6_re);
+
my @types = (
{
name => "ip",
- regex => qr[(?<!\d)$RE{'net'}{'IPv4'}(?!\d)]o,
+ regex => qr[(?<!\d)$RE{'net'}{'IPv4'}(?!\d)|(?<![0-9a-fA-F:])$IPv6_re(?![0-9a-fA-F:])]o,
action => "ip",
},
{
diff --git a/html/RTIR/index.html b/html/RTIR/index.html
index b1c58c9..865921c 100644
--- a/html/RTIR/index.html
+++ b/html/RTIR/index.html
@@ -39,6 +39,7 @@ unless ( exists $session{'my_rtir_portlets'} ) {
my $portlets = $session{'my_rtir_portlets'};
use Regexp::Common qw(RE_net_IPv4);
+use Regexp::IPv6 qw($IPv6_re);
if ( $ARGS{'q'} ) {
my $query = $ARGS{'q'};
@@ -68,7 +69,7 @@ if ( $ARGS{'q'} ) {
}
$query ||= 'id = 0';
}
- elsif ( $query =~ /^\s*($RE{net}{IPv4})\s*$/o && RT::IR->CustomFields('IP') ) {
+ elsif ( $query =~ /^\s*($RE{net}{IPv4}|$IPv6_re)\s*$/o && RT::IR->CustomFields('IP') ) {
$query = join ' OR ', map "Queue = '$_'", ('Incidents', 'Incident Reports', 'Investigations', 'Blocks');
$query = "($query) AND 'CustomField.{IP}' = '$1'";
commit d7198e76bbf953dfe0cb2a0abc65e95046e8f3da
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Thu Apr 21 23:53:00 2011 +0400
update M::I::RTx
diff --git a/inc/Module/Install/RTx.pm b/inc/Module/Install/RTx.pm
index f027f78..726b3fb 100644
--- a/inc/Module/Install/RTx.pm
+++ b/inc/Module/Install/RTx.pm
@@ -8,7 +8,7 @@ no warnings 'once';
use Module::Install::Base;
use base 'Module::Install::Base';
-our $VERSION = '0.27';
+our $VERSION = '0.28';
use FindBin;
use File::Glob ();
@@ -44,8 +44,8 @@ sub RTx {
local @INC = (
$ENV{RTHOME} ? ( $ENV{RTHOME}, "$ENV{RTHOME}/lib" ) : (),
@INC,
- map { ( "$_/rt3/lib", "$_/lib/rt3", "$_/lib" ) } grep $_,
- @prefixes
+ map { ( "$_/rt4/lib", "$_/lib/rt4", "$_/rt3/lib", "$_/lib/rt3", "$_/lib" )
+ } grep $_, @prefixes
);
until ( eval { require RT; $RT::LocalPath } ) {
warn
-----------------------------------------------------------------------
More information about the Rt-commit
mailing list