# -*- coding: binary -*-

module Msf

###
#
# This module provides methods for working with the IAX2 protocol
#
###
module Auxiliary::IAX2

  #
  # Initializes an instance of an auxiliary module that uses IAX2
  #

  def initialize(info = {})
    super

    register_options(
      [
        OptAddress.new('IAX_HOST', [true, 'The IAX2 server to communicate with']),
        OptPort.new('IAX_PORT',    [true, 'The IAX2 server port', 4569]),
        OptString.new('IAX_USER',  [false, 'An optional IAX2 username']),
        OptString.new('IAX_PASS',  [false, 'An optional IAX2 password']),
        OptString.new('IAX_CID_NAME',  [false, 'The default caller ID name', '']),
        OptString.new('IAX_CID_NUMBER',  [true, 'The default caller ID number', '15555555555'])
      ], Msf::Auxiliary::IAX2 )

    register_advanced_options(
      [
        OptBool.new('IAX_DEBUG', [false, 'Enable IAX2 debugging messages', false])
      ], Msf::Auxiliary::IAX2 )

  end

  def connect
    @iax.shutdown if @iax
    @iax = Rex::Proto::IAX2::Client.new(
      :server_host    => datastore['IAX_HOST'],
      :username       => datastore['IAX_USER'],
      :password       => datastore['IAX_PASS'],
      :caller_name    => datastore['IAX_CID_NAME'],
      :caller_number  => datastore['IAX_CID_NUMBER'],
      :debugging      => datastore['IAX_DEBUG'],
      :context        => {
        'Msf'        => framework,
        'MsfExploit' => self
      }
    )
    @iax_reg = @iax.create_call()
    r = @iax_reg.register
    if not r
      @iax.shutdown
      @iax = nil
      raise RuntimeError, "Failed to register with the server"
    end
  end

  def create_call
    if not @iax
      raise RuntimeError, "No active IAX2 connection"
    end
    @iax.create_call
  end

  def cleanup
    super
    @iax.shutdown if @iax
  end

  # General purpose phone number mangling routines
  # Convert 123456XXXX to an array of expanded numbers
  def crack_phone_range(range)
    crack_phone_ranges([range])
  end

  def crack_phone_ranges(masks)
    res = {}
    masks.each do |mask|
      mask = mask.strip

      if(mask.index(':'))
        next if mask.index('X')
        rbeg,rend = mask.split(':').map{|c| c.gsub(/[^\d]/, '').to_i }
        rbeg.upto(rend) do |n|
          res[n.to_s] = {}
        end
        next
      end

      incdigits = 0
      mask.each_char do |c|
        incdigits += 1 if c =~ /^[X#]$/i
      end

      max = (10**incdigits)-1

      (0..max).each do |num|
        number = mask.dup # copy the mask
        numstr = sprintf("%0#{incdigits}d", num) # stringify our incrementing number
        j = 0 # index for numstr
        for i in 0..number.length-1 do # step through the number (mask)
          if number[i].chr =~ /^[X#]$/i
            number[i] = numstr[j] # replaced masked indexes with digits from incrementing number
            j += 1
          end
        end
        res[number] = {}
      end

    end

    return res.keys.sort
  end

end
end

