Skip to content

Commit ac9510d

Browse files
cbrandtbuffalosunnavy
authored andcommitted
Add IPinfo.io as a lookup tool
1 parent 3897198 commit ac9510d

7 files changed

Lines changed: 327 additions & 2 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ RUN cd /usr/local/src \
2929
&& perl -I/opt/rt5/local/lib -I/opt/rt5/lib sbin/rt-setup-database --action init --dba="$RT_DBA_USER" --dba-password="$RT_DBA_PASSWORD" \
3030
&& rm -rf /usr/local/src/*
3131

32-
RUN cpm install --global --no-prebuilt --test --with-all --show-build-log-on-failure Net::Domain::TLD Net::Whois::RIPE Parse::BooleanLogic
32+
RUN cpm install --global --no-prebuilt --test --with-all --show-build-log-on-failure Net::Domain::TLD Net::Whois::RIPE Parse::BooleanLogic Geo::IPinfo
3333

3434
ENV RT_DBA_USER="$RT_DBA_USER"
3535
ENV RT_DBA_PASSWORD="$RT_DBA_PASSWORD"

META.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ no_index:
2727
- t
2828
requires:
2929
DBIx::SearchBuilder: 1.61
30+
Geo::IPinfo: 0
3031
Net::Domain::TLD: 0
3132
Parse::BooleanLogic: 0
3233
Regexp::Common: 0

Makefile.PL

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ requires('Parse::BooleanLogic');
3434
# Domain searching
3535
requires('Net::Domain::TLD');
3636

37+
# Lookup tools
38+
requires('Geo::IPinfo');
39+
3740
# for tests
3841
build_requires('Test::More');
3942
build_requires('File::Find');

docs/UPGRADING-6.0

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,27 @@ work by loading them in an Iframe.
5050

5151
=back
5252

53+
=head2 New Lookup Tools
54+
55+
RTIR 6 adds a few new default lookup tools for finding additional
56+
information about incident data, like domains and IP addresses.
57+
58+
The active lookup tools can be managed with the C<@RTIRResearchTools>
59+
configuration options. If you don't want some tools presented in
60+
the interface, update this configuration in C<RT_SiteConfig.pm> and
61+
remove them from the list.
62+
63+
=over
64+
65+
=item *
66+
67+
IPinfo.io provides a service that returns metadata for provided IP
68+
addresses. They offer a base free plan and various other plans
69+
that offer more information at higher levels.
70+
71+
To enable this lookup tool, create an account and token at IPinfo.io
72+
and set C<$LookupIPinfoToken>.
73+
74+
=back
75+
5376
=cut

etc/RTIR_Config.pm

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ using the following mason components:
792792
793793
=cut
794794

795-
Set( @RTIRResearchTools, (qw(Traceroute Whois)));
795+
Set(@RTIRResearchTools, (qw(Traceroute Whois IPinfo)));
796796

797797
=item C<$TracerouteCommand>
798798
@@ -843,6 +843,13 @@ Set($whois, {
843843
},
844844
} );
845845

846+
=item C<$LookupIPinfoToken>
847+
848+
The token to use when performing lookups using the IPinfo service.
849+
IPinfo has free plans for a limited number of searches.
850+
851+
=cut
852+
846853
=item C<$RunWhoisRequestByDefault>
847854
848855
RTIR prior to 2.6.1 was running whois request by default on lookup.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
%# BEGIN BPS TAGGED BLOCK {{{
2+
%#
3+
%# COPYRIGHT:
4+
%#
5+
%# This software is Copyright (c) 1996-2025 Best Practical Solutions, LLC
6+
%# <sales@bestpractical.com>
7+
%#
8+
%# (Except where explicitly superseded by other copyright notices)
9+
%#
10+
%#
11+
%# LICENSE:
12+
%#
13+
%# This work is made available to you under the terms of Version 2 of
14+
%# the GNU General Public License. A copy of that license should have
15+
%# been provided with this software, but in any event can be snarfed
16+
%# from www.gnu.org.
17+
%#
18+
%# This work is distributed in the hope that it will be useful, but
19+
%# WITHOUT ANY WARRANTY; without even the implied warranty of
20+
%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21+
%# General Public License for more details.
22+
%#
23+
%# You should have received a copy of the GNU General Public License
24+
%# along with this program; if not, write to the Free Software
25+
%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26+
%# 02110-1301 or visit their web page on the internet at
27+
%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28+
%#
29+
%#
30+
%# CONTRIBUTION SUBMISSION POLICY:
31+
%#
32+
%# (The following paragraph is not intended to limit the rights granted
33+
%# to you to modify and distribute this software under the terms of
34+
%# the GNU General Public License and is only of importance to you if
35+
%# you choose to contribute your changes and enhancements to the
36+
%# community by submitting them to Best Practical Solutions, LLC.)
37+
%#
38+
%# By intentionally submitting any modifications, corrections or
39+
%# derivatives to this work, or any other work intended for use with
40+
%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
41+
%# you are the copyright holder for those contributions and you grant
42+
%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
43+
%# royalty-free, perpetual, license to use, copy, create derivative
44+
%# works based on those contributions, and sublicense and distribute
45+
%# those contributions and any derivatives thereof.
46+
%#
47+
%# END BPS TAGGED BLOCK }}}
48+
<form name="ToolFormIPInfo" action="IPinfo.html" method="get">
49+
<div class="row mt-2 justify-content-center">
50+
<div class="col-3 label">
51+
<label for="q">
52+
<&|/l&>IPinfo Lookup</&>
53+
</label>
54+
</div>
55+
<div class="col-7">
56+
<input class="form-control" type="text" name="q" value="<% $q %>" placeholder="<% loc('Enter an IP address') %>" />
57+
</div>
58+
<div class="col-2">
59+
<input class="btn btn-primary" type="submit" value="<%loc('Look up')%>" />
60+
</div>
61+
% foreach my $arg ( grep exists $ARGS{$_}, @PassArguments ) {
62+
<input type="hidden" name="<% $arg %>" value="<% $ARGS{ $arg } %>" />
63+
% }
64+
</div>
65+
</form>
66+
<%args>
67+
$q => ''
68+
$TicketObj => undef
69+
@PassArguments => ()
70+
</%args>
71+
<%init>
72+
my $required_module = RT::StaticUtil::RequireModule('Geo::IPinfo');
73+
my $token = RT->Config->Get('LookupIPinfoToken');
74+
if ( $required_module && $token ) {
75+
RT->Logger->debug('Running Geo::IPinfo lookup');
76+
}
77+
else {
78+
RT->Logger->warn('Install the module Geo::IPinfo to use the IPinfo lookup tool') unless $required_module;
79+
RT->Logger->warn('IPinfo lookups require a token from IPinfo.io to be set with the config option LookupIPinfoToken') unless $token;
80+
return;
81+
}
82+
83+
# IPinfo only works with IP addresses, so don't populate the lookup box in the form
84+
# because it will error if they try to run the lookup on a non-IP address.
85+
86+
use Regexp::Common qw(net);
87+
88+
unless ($q =~ /^($RE{net}{IPv4})$/ or $q =~ /^($RE{net}{IPv6})$/) {
89+
$q = '';
90+
}
91+
92+
</%init>

html/RTIR/Tools/IPinfo.html

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
%# BEGIN BPS TAGGED BLOCK {{{
2+
%#
3+
%# COPYRIGHT:
4+
%#
5+
%# This software is Copyright (c) 1996-2025 Best Practical Solutions, LLC
6+
%# <sales@bestpractical.com>
7+
%#
8+
%# (Except where explicitly superseded by other copyright notices)
9+
%#
10+
%#
11+
%# LICENSE:
12+
%#
13+
%# This work is made available to you under the terms of Version 2 of
14+
%# the GNU General Public License. A copy of that license should have
15+
%# been provided with this software, but in any event can be snarfed
16+
%# from www.gnu.org.
17+
%#
18+
%# This work is distributed in the hope that it will be useful, but
19+
%# WITHOUT ANY WARRANTY; without even the implied warranty of
20+
%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21+
%# General Public License for more details.
22+
%#
23+
%# You should have received a copy of the GNU General Public License
24+
%# along with this program; if not, write to the Free Software
25+
%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26+
%# 02110-1301 or visit their web page on the internet at
27+
%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28+
%#
29+
%#
30+
%# CONTRIBUTION SUBMISSION POLICY:
31+
%#
32+
%# (The following paragraph is not intended to limit the rights granted
33+
%# to you to modify and distribute this software under the terms of
34+
%# the GNU General Public License and is only of importance to you if
35+
%# you choose to contribute your changes and enhancements to the
36+
%# community by submitting them to Best Practical Solutions, LLC.)
37+
%#
38+
%# By intentionally submitting any modifications, corrections or
39+
%# derivatives to this work, or any other work intended for use with
40+
%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
41+
%# you are the copyright holder for those contributions and you grant
42+
%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
43+
%# royalty-free, perpetual, license to use, copy, create derivative
44+
%# works based on those contributions, and sublicense and distribute
45+
%# those contributions and any derivatives thereof.
46+
%#
47+
%# END BPS TAGGED BLOCK }}}
48+
<& /RTIR/Elements/Header, Title => $title &>
49+
<& /Elements/Tabs &>
50+
51+
<div class="m-2">
52+
53+
<&| /Widgets/TitleBox,
54+
title => $title,
55+
class => 'ipinfo',
56+
&>
57+
<div class="container">
58+
<div class="row">
59+
<div class="col m-3">
60+
<pre><samp>
61+
<%perl>
62+
$SavedContent .= $ipinfo_results . "\n";
63+
$m->out( $ipinfo_results );
64+
</%perl>
65+
</samp></pre>
66+
</div>
67+
</div>
68+
</div>
69+
</&>
70+
71+
% if ($TicketObj and $SavedContent) {
72+
% my $url = RT::IR->HREFTo(
73+
% "Tools/Lookup.html?"
74+
% . $m->comp(
75+
% '/Elements/QueryString',
76+
% ticket => $ticket,
77+
% q => $q,
78+
% )
79+
% );
80+
<div class="container">
81+
<div class="row mt-2 justify-content-center">
82+
<div class="col-auto">
83+
<form method="post" action="<% $url %>">
84+
<input type="hidden" name="LookupResults" value="<% $SavedContent %>" />
85+
<input class="btn btn-primary" type="submit" value="<% loc('Save these results to the ticket') %>" id="save-results-to-ticket" />
86+
</form>
87+
</div>
88+
</div>
89+
</div>
90+
% }
91+
92+
</div>
93+
<%init>
94+
# IPinfo only works with IP addresses
95+
use Regexp::Common qw(net);
96+
97+
unless ($q =~ /^($RE{net}{IPv4})$/ or $q =~ /^($RE{net}{IPv6})$/) {
98+
Abort(loc('IPinfo accepts only IPv4 or IPv6 IP addresses for lookups.'));
99+
}
100+
101+
my $title = loc("IPinfo lookup for '[_1]'", $q);
102+
my $token = RT->Config->Get('LookupIPinfoToken');
103+
my ($ipinfo_results, $TicketObj, $SavedContent);
104+
105+
# Set a sensible order for the default info available for all IPinfo plans
106+
my @ipinfo_order = qw(
107+
ip
108+
hostname
109+
org
110+
city
111+
postal
112+
region
113+
country_name
114+
continent
115+
timezone
116+
longitude
117+
latitude
118+
);
119+
120+
my $required_module = RT::StaticUtil::RequireModule('Geo::IPinfo');
121+
if ( $required_module && $token ) {
122+
RT->Logger->debug('Running Geo::IPinfo lookup');
123+
124+
if ($ticket) {
125+
$TicketObj = LoadTicket($ticket);
126+
}
127+
128+
my $ipinfo = Geo::IPinfo->new($token);
129+
my $ip_details;
130+
131+
if ( $q =~ /^($RE{net}{IPv6})$/ ) {
132+
$ip_details = $ipinfo->info_v6($q);
133+
}
134+
else {
135+
$ip_details = $ipinfo->info($q);
136+
}
137+
138+
if ( $ip_details ) {
139+
foreach my $core_field ( @ipinfo_order ) {
140+
if ( exists $ip_details->{$core_field} ) {
141+
my $label = ucfirst($core_field);
142+
# Special cases
143+
$label = 'IP' if $core_field eq 'ip';
144+
$label = 'Country Name' if $core_field eq 'country_name';
145+
146+
if ( $core_field eq 'continent' ) {
147+
$ipinfo_results
148+
.= loc($label) . ': '
149+
. Encode::decode( 'UTF-8', $ip_details->{$core_field}{'name'} ) . ' ('
150+
. Encode::decode( 'UTF-8', $ip_details->{$core_field}{'code'} ) . ")\n";
151+
}
152+
else {
153+
$ipinfo_results
154+
.= loc($label) . ': ' . Encode::decode( 'UTF-8', $ip_details->{$core_field} ) . "\n";
155+
}
156+
delete $ip_details->{$core_field};
157+
}
158+
}
159+
160+
# IPinfo returns more data with higher paid plans, so if we have anything
161+
# remaining, dump it to the screen.
162+
if ( keys %$ip_details ) {
163+
$ipinfo_results .= "\nAdditional Data:\n\n";
164+
}
165+
166+
foreach my $more_data ( sort keys %$ip_details ) {
167+
168+
# IPinfo seems to only have one layer of extra data
169+
if ( ref $ip_details->{$more_data} eq 'HASH' ) {
170+
$ipinfo_results .= loc(ucfirst($more_data)) . ':' . "\n";
171+
foreach my $data_detail ( sort keys %{$ip_details->{$more_data}} ) {
172+
$ipinfo_results
173+
.= ' '
174+
. loc( ucfirst($data_detail) ) . ': '
175+
. Encode::decode( 'UTF-8', $ip_details->{$more_data}{$data_detail} ) . "\n";
176+
}
177+
}
178+
else {
179+
$ipinfo_results
180+
.= loc( ucfirst($more_data) ) . ': ' . Encode::decode( 'UTF-8', $ip_details->{$more_data} ) . "\n";
181+
}
182+
}
183+
}
184+
else {
185+
RT->Logger->error('Error calling IPinfo: ' . $ipinfo->error_msg);
186+
$ipinfo_results .= loc('Error calling IPinfo') . ': ' . $ipinfo->error_msg;
187+
}
188+
}
189+
else {
190+
RT->Logger->warn('Install the module Geo::IPinfo to use the IPinfo lookup tool') unless $required_module;
191+
RT->Logger->warn('IPinfo lookups require a token from IPinfo.io to be set with the config option LookupIPinfoToken') unless $token;
192+
return;
193+
}
194+
195+
</%init>
196+
<%args>
197+
$ticket => undef
198+
$q => ''
199+
</%args>

0 commit comments

Comments
 (0)