Implement generic sip analysis logic.

You now can search by uuid (either caller or callee) and call-id, independently
from a subscriber.
3.4
Andreas Granig 14 years ago
parent 20921081e3
commit 7d34bff60f

@ -0,0 +1,206 @@
package admin::Controller::sipanalysis;
use strict;
use warnings;
use base 'Catalyst::Controller';
use admin::Utils;
use HTML::Entities;
=head1 NAME
admin::Controller::sipcanalysis- Catalyst Controller
=head1 DESCRIPTION
This provides functionality for analyzing SIP traffic
=head1 METHODS
=head2 index
Display search form.
=cut
sub index : Private {
my ( $self, $c ) = @_;
$c->stash->{template} = 'tt/sipanalysis.tt';
return 1;
}
=head2 search
Search for SIP sessions and display results.
=cut
sub search : Local {
my ( $self, $c ) = @_;
my $limit = 10;
my %filter;
$c->stash->{template} = 'tt/sipanalysis.tt';
if($c->request->params->{use_session}) {
%filter = %{ $c->session->{search_filter} }
if defined $c->session->{search_filter};
} else {
foreach my $sf (qw(uuid call_id)) {
if(defined $c->request->params->{'search_'.$sf}
and length $c->request->params->{'search_'.$sf})
{
$filter{$sf} = $c->request->params->{'search_'.$sf} || '';
}
}
$c->session->{search_filter} = { %filter };
}
foreach my $sf (qw(uuid call_id)) {
# set values for webform
$c->stash->{'search_'.$sf} = $filter{$sf};
next unless defined $filter{$sf};
}
my $offset = $c->request->params->{offset} || 0;
$offset = 0 if $offset !~ /^\d+$/;
my $calls;
return unless $c->model('Provisioning')->call_prov( $c, 'voip', 'search_sipstat_calls',
{ filter => { %filter,
# limit => $limit,
# offset => $limit * $offset
}
},
\$calls
);
$c->stash->{searched} = 1;
# TODO: pagination goes here
$c->stash->{calls} = $calls;
return;
}
sub pcap : Local {
my ( $self, $c ) = @_;
$c->stash->{template} = 'tt/sipanalysis.tt';
my $callid = $c->request->params->{callid};
my $packets;
return unless $c->model('Provisioning')->call_prov( $c, 'voip', 'get_sipstat_packets',
{
callid => $callid,
},
\$packets
);
my $pcap = admin::Utils::generate_pcap($packets);
my $filename = $callid . '.pcap';
$c->stash->{current_view} = 'Plain';
$c->stash->{content_type} = 'application/octet-stream';
$c->stash->{content_disposition} = qq[attachment; filename="$filename"];
$c->stash->{content} = eval { $pcap };
return;
}
sub callmap_png : Local {
my ( $self, $c ) = @_;
$c->stash->{template} = 'tt/sipanalysis_call.tt';
my $callid = $c->request->params->{callid};
$c->stash->{callid} = $callid;
my $calls;
return unless $c->model('Provisioning')->call_prov( $c, 'voip', 'get_sipstat_packets',
{
callid => $callid,
},
\$calls
);
my $png = admin::Utils::generate_callmap_png($c, $calls);
my $filename = $callid . '.png';
$c->stash->{current_view} = 'Plain';
$c->stash->{content_type} = 'image/png';
$c->stash->{content_disposition} = qq[attachment; filename="$filename"];
$c->stash->{content} = eval { $png };
return;
}
sub callmap : Local {
my ( $self, $c ) = @_;
$c->stash->{template} = 'tt/sipanalysis_call.tt';
my $callid = $c->request->params->{callid};
$c->stash->{callid} = $callid;
my $calls;
return unless $c->model('Provisioning')->call_prov( $c, 'voip', 'get_sipstat_packets',
{
callid => $callid,
},
\$calls
);
$c->stash->{canvas} = admin::Utils::generate_callmap($c, $calls);
return;
}
sub packet : Local {
my ( $self, $c ) = @_;
$c->stash->{template} = 'tt/sipanalysis_call.tt';
my $pkgid = $c->request->params->{pkgid};
my $pkg;
return unless $c->model('Provisioning')->call_prov( $c, 'voip', 'get_sipstat_packet',
{
packetid => $pkgid,
},
\$pkg
);
$pkg->{payload} = encode_entities($pkg->{payload});
$pkg->{payload} =~ s/^([^\n]+)\n/<b>$1<\/b>\n/;
$pkg->{payload} = $pkg->{src_ip}.':'.$pkg->{src_port}.' &rarr; '. $pkg->{dst_ip}.':'.$pkg->{dst_port}.'<br/><br/>'.$pkg->{payload};
$pkg->{payload} =~ s/\n([a-zA-Z0-9\-_]+\:)/\n<b>$1<\/b>/g;
$pkg->{payload} =~ s/\r?\n/<br\/>/g;
$c->stash->{current_view} = 'Plain';
$c->stash->{content_type} = 'text/html';
$c->stash->{content} = eval { $pkg->{payload} };
return;
}
=head1 BUGS AND LIMITATIONS
=over
=item currently none
=back
=head1 SEE ALSO
Provisioning model, Catalyst
=head1 AUTHORS
=over
=item Andreas Granig <agranig@sipwise.com>
=back
=head1 COPYRIGHT
The subscriber controller is Copyright (c) 2007-2012 Sipwise GmbH,
Austria. You should have received a copy of the licences terms together
with the software.
=cut
1;

@ -8,6 +8,9 @@
[% IF Catalyst.config.dashboard.enabled %]
<li [% 'class="active_menu"' IF menu.active == "dashboard" %]><a href="/dashboard">Statistics</a></li>
[% END %]
[% IF Catalyst.config.voisniff_features %]
<li [% 'class="active_menu"' IF menu.active == "sipanalysis" %]><a href="/sipanalysis">SIP Traffic Analysis</a></li>
[% END %]
</ul>
</div>

@ -0,0 +1,93 @@
<h3>Find SIP Sessions</h3>
<ul class="cleanlist">
<form action="/sipanalysis/search" method="post">
<li class="ui-state-default">
<div class="span-3">
<label class="search_label" for="search_by_uuid">UUID:</label>
</div>
<div class="span-5">
<input type="text" size="50" id="search_by_uuid" name="search_uuid" value="[% search_uuid %]"
title="search by source or destination UUID" />
</div>
</li>
<li class="ui-state-default">
<div class="span-3">
<label class="search_label" for="search_by_call_id">Call-ID:</label>
</div>
<div class="span-5">
<input type="text" size="50" id="search_by_call_id" name="search_call_id" value="[% search_callid %]"
title="search by the SIP Call-ID" />
</div>
</li>
</ul>
<div class="hspace-20"></div>
<button name="submit" class="button-search">Search</button>
</form>
<br/>
<div class="hspace-20"></div>
[% IF searched %]
<h3>SIP Sessions</h3>
<ul class="cleanlist">
[% IF !calls.defined || calls.size == 0 %]
<li class="ui-state-default">
<div class="span-14">No SIP sessions found.</div>
</li>
[% ELSE %]
<li class="ui-state-default">
<div class="span-4">Timestamp</div>
<div class="span-10">Call-ID</div>
<div class="span-2 last">Method</div>
</li>
[% END %]
[% FOREACH call IN calls %]
<li class="ui-state-default">
<div class="span-4">[% call.timestamp %]</div>
<div class="span-10"><a href="callmap?callid=[% call.call_id %]">[% IF call.call_id.length > 50 %][% call.call_id.substr(0, 50) %]...[% ELSE %][% call.call_id %][% END %]</a></div>
<div class="span-2 last">[% call.method %]</div>
</li>
[% END %]
</ul>
[% IF 0 %]
[% IF pagination %]
<div class="pagination">
<ul>
[% IF offset == 0 %]
<li class="disablepage">&#171; prev</li>
[% ELSE %]
<li class="nextpage">
<a href="/subscriber/search?use_session=1&amp;offset=[% offset - 1 %]">&#171; prev</a>
</li>
[% END %]
[% FOREACH pagine = pagination %]
[% IF pagine.offset == offset %]
<li class="currentpage">
[% pagine.offset + 1 %]
</li>
[% ELSIF pagine.offset == -1 %]
...
[% ELSE %]
<li>
<a href="/subscriber/search?use_session=1&amp;offset=[% pagine.offset %]">[% pagine.offset + 1 %]</a>
</li>
[% END %]
[% END %]
[% IF offset >= max_offset %]
<li class="disablepage">
next &#187;
</li>
[% ELSE %]
<li class="nextpage">
<a href="/subscriber/search?use_session=1&amp;offset=[% offset + 1 %]">next &#187;</a>
</li>
[% END %]
</ul>
</div>
[% END %]
[% END %]
[% END %]

@ -0,0 +1,23 @@
<script type="text/javascript" src="/js/modal.popup.js"></script>
<script type="text/javascript">
function pkgPopup(pkgid) {
// http://www.jquerypopup.com/documentation.php
modalPopup("center", 100, 640, 10, "#666666", 40, "#FFFFFF", "#000000", 4, 5, 300,
"packet?pkgid="+pkgid,
"/static/images/loader.gif");
}
</script>
<h3 id="calldata">Call Details for Call-ID [% callid %]</h3>
<div style="clear:both"></div>
<a href="/sipanalysis"><span class="button-back">Back</span></a>
<a href="pcap?callid=[% callid %]"><span class="button-download">Download PCAP</span></a>
<div style="clear:both"></div>
<image src="callmap_png?callid=[% callid %]" width="[% canvas.width %]" height="[% canvas.height %]" usemap="#diamap" />
<map name="diamap">
[% FOREACH area IN canvas.areas %]
<area shape="rect" coords="[% area.coords %]" href="javascript:pkgPopup([% area.id %])" />
[% END %]
</map>
Loading…
Cancel
Save