Store various call info into the database, determine whether the call is fax/modem/vmb/voice/dialtone, add a type pie chart - warvox - VoIP based wardialing tool, forked from rapid7/warvox.
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
   DIR commit 6389d305a83d6a5384d3332e5ca69cf6d35a8abf
   DIR parent 76fc65ae7c8b0a944971cfcdbdf4dae3bb1cd3ec
  HTML Author: HD Moore <hd_moore@rapid7.com>
       Date:   Wed,  4 Mar 2009 03:57:08 +0000
       
       Store various call info into the database, determine whether the call is fax/modem/vmb/voice/dialtone, add a type pie chart
       
       
       Diffstat:
         M lib/warvox/jobs/analysis.rb         |      82 +++++++++++++++++++++++++++----
         M web/app/controllers/analyze_contro… |      19 +++++++++++++++++++
         M web/app/views/analyze/view.html.erb |      21 +++++++++++++--------
         A web/db/migrate/20090304013815_add_… |       9 +++++++++
         A web/db/migrate/20090304013839_add_… |       9 +++++++++
         A web/db/migrate/20090304013909_add_… |       9 +++++++++
         A web/db/migrate/20090304014018_add_… |       9 +++++++++
         A web/db/migrate/20090304014033_add_… |       9 +++++++++
         M web/db/schema.rb                    |       7 ++++++-
         R web/public/images/overlay.png -> w… |       0 
       
       10 files changed, 156 insertions(+), 18 deletions(-)
       ---
   DIR diff --git a/lib/warvox/jobs/analysis.rb b/lib/warvox/jobs/analysis.rb
       @@ -7,7 +7,7 @@ class Analysis < Base
                @@kissfft_loaded = false
                begin
                        require 'kissfft'
       -                @kissfft_loaded = true
       +                @@kissfft_loaded = true
                rescue ::LoadError
                end
                
       @@ -62,11 +62,16 @@ class Analysis < Base
                                #
                                # Create the signature database
                                # 
       -                        raw = WarVOX::Audio::Raw.from_file(r.rawfile)
       -                        fd = File.new("#{bname}.sig", "wb")
       -                        fd.write raw.to_flow
       +                        
       +                        raw  = WarVOX::Audio::Raw.from_file(r.rawfile)
       +                        flow = raw.to_flow
       +                        fd   = File.new("#{bname}.sig", "wb")
       +                        fd.write flow
                                fd.close
                                
       +                        # Save the signature data
       +                        r.sig_data = flow
       +                        
                                #
                                # Create a raw decompressed file
                                #
       @@ -108,6 +113,9 @@ class Analysis < Base
                                        end
                                end
                                
       +                        # Save the peak frequency
       +                        r.peak_freq = maxf
       +                        
                                # Calculate average frequency and peaks over time
                                avg = {}
                                pks = []
       @@ -118,17 +126,73 @@ class Analysis < Base
                                                avg[ freq[0] ] +=  freq[1]
                                        end
                                end
       +                        
       +                        # Save the peak frequencies over time
       +                        r.peak_freq_data = pks.map{|f| "#{f[0]}-#{f[1]}" }.join(" ")
       +                        
       +                        # Generate the frequency file
                                avg.keys.sort.each do |k|
                                        avg[k] = avg[k] / res.length
                                        frefile.write("#{k} #{avg[k]}\n")
                                end
                                frefile.flush
        
       -                        # XXX: Store all frequency information
       -                        # maxf   == peak frequency
       -                        # avg    == averages over whole sample
       -                        # pks    == peaks over time
       -                        # tones  == significant frequencies
       +                        #
       +                        # XXX: store significant frequencies somewhere (tones)
       +                        #
       +                        
       +                        # Make a guess as to what kind of phone number we found
       +                        line_type = nil
       +                        while(not line_type)
       +
       +                                # Look for modems by detecting 2250hz tones
       +                                f_2250 = 0
       +                                pks.each{|f| f_2250 += 1 if(f[0] > 2240 and f[0] < 2260) }
       +                                if(f_2250 > 2)
       +                                        line_type = 'modem'
       +                                        break                                
       +                                end
       +                                
       +                                # Look for the 1000hz voicemail BEEP
       +                                if(r.peak_freq > 990 and r.peak_freq < 1010)
       +                                        line_type = 'voicemail'
       +                                        break
       +                                end
       +
       +                                # Most faxes have at least two of the following tones
       +                                f_1625 = f_1660 = f_1825 = f_2100 = false
       +                                pks.each do |f|
       +                                        # $stderr.puts "#{r.number} #{f.inspect}"
       +                                        f_1625 = true if(f[0] > 1620 and f[0] < 1630)
       +                                        f_1660 = true if(f[0] > 1655 and f[0] < 1665)
       +                                        f_1825 = true if(f[0] > 1820 and f[0] < 1830)
       +                                        f_2100 = true if(f[0] > 2090 and f[0] < 2110)                                                                                
       +                                end
       +                                if([ f_1625, f_1660, f_1825, f_2100 ].grep(true).length >= 2)
       +                                        line_type = 'fax'
       +                                        break
       +                                end                        
       +
       +                                # Dial tone detection
       +                                f_440 = false
       +                                f_350 = false
       +                                pks.each do |f|
       +                                        f_440 = true if(f[0] > 435 and f[0] < 445)
       +                                        f_345 = true if(f[0] > 345 and f[0] < 355)
       +                                end
       +                                if(f_440 and f_350)
       +                                        line_type = 'dialtone'
       +                                        break
       +                                end
       +                                
       +                                # Detect humans based on long pauses
       +                                
       +                                # Default to voice
       +                                line_type = 'voice'
       +                        end
       +
       +                        # Save the guessed line type
       +                        r.line_type = line_type
        
                                # Plot samples to a graph
                                plotter = Tempfile.new("gnuplot")
   DIR diff --git a/web/app/controllers/analyze_controller.rb b/web/app/controllers/analyze_controller.rb
       @@ -19,6 +19,25 @@ class AnalyzeController < ApplicationController
                        :per_page => 10,
                        :conditions => [ 'completed = ? and processed = ? and busy = ?', true, true, false ]
                )
       +        
       +        @g1 = Ezgraphix::Graphic.new(:c_type => 'pie2d', :div_name => 'calls_pie1')
       +        @g1.render_options(:caption => 'Line Types')
       +                
       +        @g2 = Ezgraphix::Graphic.new(:c_type => 'pie2d', :div_name => 'calls_pie2')
       +        @g2.render_options(:caption => 'Ring Time')
       +        
       +        res_types = {}
       +        res_rings = {}
       +        
       +        @results.each do |r|
       +                res_rings[ r.ringtime ] ||= 0
       +                res_rings[ r.ringtime ]  += 1
       +                res_types[ r.line_type.capitalize.to_sym ] ||= 0
       +                res_types[ r.line_type.capitalize.to_sym ]  += 1                
       +        end
       +        
       +        @g1.data = res_types
       +        @g2.data = res_rings
          end
        
          # GET /dial_results/1/resource?id=XXX&type=YYY
   DIR diff --git a/web/app/views/analyze/view.html.erb b/web/app/views/analyze/view.html.erb
       @@ -2,8 +2,8 @@
        
        <table width='100%' align='center' border=0 cellspacing=0 cellpadding=6>
        <tr>
       -        <td align='center'> </td>
       -        <td align='center'> </td>
       +        <td align='center'><%= render_ezgraphix @g1 %></td>
       +        <td align='center'><%= render_ezgraphix @g2 %></td>
        </tr>
        </table>
        
       @@ -11,11 +11,13 @@
        
        <table class='table_scaffold' width='100%'>
          <tr>
       -    <th>ID</th>
       +    <th>ID</th>  
       +    <th>Number</th>
       +    <th>Type</th>
       +    <th>Peak Freq</th>
                  <th>Signal</th>
                <th>Spectrum</th>
       -    <th>Number</th>
       -    <th>CallerID</th>
       +    <th>CID</th>
            <th>Provider</th>
            <th>Call Time</th>
                <th>Ring Time</th>
       @@ -24,15 +26,18 @@
        <%  @results.each do |dial_result| %>
          <tr>
            <td><%=h dial_result.id %></td>
       +        <td>
       +                <a href="<%=resource_analyze_path(@job_id)%>?result_id=<%= dial_result.id %>&type=mp3" target="_new"><%= dial_result.number %></a>
       +        </td>
       +    <td><%=h dial_result.line_type %></td>        
       +    <td><%=h dial_result.peak_freq.to_i %></td>                
                  <td>
                        <a href="<%=resource_analyze_path(@job_id)%>?result_id=<%= dial_result.id %>&type=big_sig_dots" rel="lightbox"><img src="<%=resource_analyze_path(@job_id)%>?result_id=<%= dial_result.id %>&type=small_sig" /></a>
                </td>
                <td>
                        <a href="<%=resource_analyze_path(@job_id)%>?result_id=<%= dial_result.id %>&type=big_freq" rel="lightbox"><img src="<%=resource_analyze_path(@job_id)%>?result_id=<%= dial_result.id %>&type=small_freq" /></a>
                </td>
       -        <td>
       -                <a href="<%=resource_analyze_path(@job_id)%>?result_id=<%= dial_result.id %>&type=mp3" target="_new"><%= dial_result.number %></a>
       -        </td>
       +
            <td><%=h dial_result.cid %></td>        
            <td><%=h dial_result.provider.name %></td>
            <td><%=h dial_result.seconds %></td>
   DIR diff --git a/web/db/migrate/20090304013815_add_peak_freq_to_dial_results.rb b/web/db/migrate/20090304013815_add_peak_freq_to_dial_results.rb
       @@ -0,0 +1,9 @@
       +class AddPeakFreqToDialResults < ActiveRecord::Migration
       +  def self.up
       +    add_column :dial_results, :peak_freq, :number
       +  end
       +
       +  def self.down
       +    remove_column :dial_results, :peak_freq
       +  end
       +end
   DIR diff --git a/web/db/migrate/20090304013839_add_peak_freq_data_to_dial_results.rb b/web/db/migrate/20090304013839_add_peak_freq_data_to_dial_results.rb
       @@ -0,0 +1,9 @@
       +class AddPeakFreqDataToDialResults < ActiveRecord::Migration
       +  def self.up
       +    add_column :dial_results, :peak_freq_data, :string
       +  end
       +
       +  def self.down
       +    remove_column :dial_results, :peak_freq_data
       +  end
       +end
   DIR diff --git a/web/db/migrate/20090304013909_add_sig_data_to_dial_results.rb b/web/db/migrate/20090304013909_add_sig_data_to_dial_results.rb
       @@ -0,0 +1,9 @@
       +class AddSigDataToDialResults < ActiveRecord::Migration
       +  def self.up
       +    add_column :dial_results, :sig_data, :string
       +  end
       +
       +  def self.down
       +    remove_column :dial_results, :sig_data
       +  end
       +end
   DIR diff --git a/web/db/migrate/20090304014018_add_line_type_to_dial_results.rb b/web/db/migrate/20090304014018_add_line_type_to_dial_results.rb
       @@ -0,0 +1,9 @@
       +class AddLineTypeToDialResults < ActiveRecord::Migration
       +  def self.up
       +    add_column :dial_results, :line_type, :string
       +  end
       +
       +  def self.down
       +    remove_column :dial_results, :line_type
       +  end
       +end
   DIR diff --git a/web/db/migrate/20090304014033_add_notes_to_dial_results.rb b/web/db/migrate/20090304014033_add_notes_to_dial_results.rb
       @@ -0,0 +1,9 @@
       +class AddNotesToDialResults < ActiveRecord::Migration
       +  def self.up
       +    add_column :dial_results, :notes, :string
       +  end
       +
       +  def self.down
       +    remove_column :dial_results, :notes
       +  end
       +end
   DIR diff --git a/web/db/schema.rb b/web/db/schema.rb
       @@ -9,7 +9,7 @@
        #
        # It's strongly recommended to check this file into your version control system.
        
       -ActiveRecord::Schema.define(:version => 20090303225838) do
       +ActiveRecord::Schema.define(:version => 20090304014033) do
        
          create_table "dial_jobs", :force => true do |t|
            t.string   "range"
       @@ -39,6 +39,11 @@ ActiveRecord::Schema.define(:version => 20090303225838) do
            t.datetime "updated_at"
            t.datetime "processed_at"
            t.string   "cid"
       +    t.decimal  "peak_freq"
       +    t.string   "peak_freq_data"
       +    t.string   "sig_data"
       +    t.string   "line_type"
       +    t.string   "notes"
          end
        
          create_table "providers", :force => true do |t|
   DIR diff --git a/web/public/images/overlay.png b/web/public/stylesheets/overlay.png
       Binary files differ.