PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/rex/proto/iax2/client.rb

https://gitlab.com/alx741/metasploit-framework
Ruby | 219 lines | 170 code | 42 blank | 7 comment | 24 complexity | e323fa3681d0cd0984dbf3651c4ff2f1 MD5 | raw file
  1. # -*- coding: binary -*-
  2. require 'rex/proto/iax2/constants'
  3. require 'rex/proto/iax2/codecs'
  4. require 'rex/proto/iax2/call'
  5. require 'rex/socket'
  6. require 'thread'
  7. require 'digest/md5'
  8. require 'timeout'
  9. module Rex
  10. module Proto
  11. module IAX2
  12. class Client
  13. attr_accessor :caller_number, :caller_name, :server_host, :server_port
  14. attr_accessor :username, :password
  15. attr_accessor :sock, :monitor
  16. attr_accessor :src_call_idx
  17. attr_accessor :debugging
  18. attr_accessor :calls
  19. def initialize(uopts={})
  20. opts = {
  21. :caller_number => '15555555555',
  22. :caller_name => '',
  23. :server_port => IAX2_DEFAULT_PORT,
  24. :context => { }
  25. }.merge(uopts)
  26. self.caller_name = opts[:caller_name]
  27. self.caller_number = opts[:caller_number]
  28. self.server_host = opts[:server_host]
  29. self.server_port = opts[:server_port]
  30. self.username = opts[:username]
  31. self.password = opts[:password]
  32. self.debugging = opts[:debugging]
  33. self.sock = Rex::Socket::Udp.create(
  34. 'PeerHost' => self.server_host,
  35. 'PeerPort' => self.server_port,
  36. 'Context' => opts[:context]
  37. )
  38. self.monitor = ::Thread.new { monitor_socket }
  39. self.src_call_idx = 0
  40. self.calls = {}
  41. end
  42. def shutdown
  43. self.monitor.kill rescue nil
  44. end
  45. def create_call
  46. cid = allocate_call_id()
  47. self.calls[ cid ] = IAX2::Call.new(self, cid)
  48. end
  49. #
  50. # Transport
  51. #
  52. def monitor_socket
  53. while true
  54. begin
  55. pkt, src = self.sock.recvfrom(65535)
  56. next if not pkt
  57. # Find the matching call object
  58. mcall = matching_call(pkt)
  59. next if not mcall
  60. if (pkt[0,1].unpack("C")[0] & 0x80) != 0
  61. mcall.handle_control(pkt)
  62. else
  63. # Dispatch the buffer via the call handler
  64. mcall.handle_audio(pkt)
  65. end
  66. rescue ::Exception => e
  67. dprint("monitor_socket: #{e.class} #{e} #{e.backtrace}")
  68. break
  69. end
  70. end
  71. self.sock.close rescue nil
  72. end
  73. def matching_call(pkt)
  74. src_call = pkt[0,2].unpack('n')[0]
  75. dst_call = nil
  76. if (src_call & 0x8000 != 0)
  77. dst_call = pkt[2,2].unpack('n')[0]
  78. dst_call ^= 0x8000 if (dst_call & 0x8000 != 0)
  79. end
  80. src_call ^= 0x8000 if (src_call & 0x8000 != 0)
  81. # Find a matching call in our list
  82. mcall = self.calls.values.select {|x| x.dcall == src_call or (dst_call and x.scall == dst_call) }.first
  83. if not mcall
  84. dprint("Packet received for non-existent call #{[src_call, dst_call].inspect} vs #{self.calls.values.map{|x| [x.dcall, x.scall]}.inspect}")
  85. return
  86. end
  87. mcall
  88. end
  89. def allocate_call_id
  90. res = ( self.src_call_idx += 1 )
  91. if ( res > 0x8000 )
  92. self.src_call_idx = 1
  93. res = 1
  94. end
  95. res
  96. end
  97. def dprint(msg)
  98. return if not self.debugging
  99. $stderr.puts "[#{Time.now.to_s}] #{msg}"
  100. end
  101. def send_data(call, data, inc_seq = true )
  102. r = self.sock.sendto(data, self.server_host, self.server_port, 0)
  103. if inc_seq
  104. call.oseq = (call.oseq + 1) & 0xff
  105. end
  106. r
  107. end
  108. def send_ack(call)
  109. data = [ IAX_SUBTYPE_ACK ].pack('C')
  110. send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ), false )
  111. end
  112. def send_pong(call, stamp)
  113. data = [ IAX_SUBTYPE_PONG ].pack('C')
  114. send_data( call, create_pkt( call.scall, call.dcall, stamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
  115. end
  116. def send_lagrp(call, stamp)
  117. data = [ IAX_SUBTYPE_LAGRP ].pack('C')
  118. send_data( call, create_pkt( call.scall, call.dcall, stamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
  119. end
  120. def send_invalid(call)
  121. data = [ IAX_SUBTYPE_INVAL ].pack('C')
  122. send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
  123. end
  124. def send_hangup(call)
  125. data = [ IAX_SUBTYPE_HANGUP ].pack('C')
  126. send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
  127. end
  128. def send_new(call, number)
  129. data = [ IAX_SUBTYPE_NEW ].pack('C')
  130. cid = call.caller_number || self.caller_number
  131. cid = number if cid == 'SELF'
  132. data << create_ie(IAX_IE_CALLING_NUMBER, cid )
  133. data << create_ie(IAX_IE_CALLING_NAME, call.caller_name || self.caller_name)
  134. data << create_ie(IAX_IE_DESIRED_CODEC, [IAX_SUPPORTED_CODECS].pack("N") )
  135. data << create_ie(IAX_IE_ACTUAL_CODECS, [IAX_SUPPORTED_CODECS].pack("N") )
  136. data << create_ie(IAX_IE_USERNAME, self.username) if self.username
  137. data << create_ie(IAX_IE_CALLED_NUMBER, number)
  138. data << create_ie(IAX_IE_ORIGINAL_DID, number)
  139. send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
  140. end
  141. def send_authrep_chall_response(call, chall)
  142. data =
  143. [ IAX_SUBTYPE_AUTHREP ].pack('C') +
  144. create_ie(IAX_IE_CHALLENGE_RESP, ::Digest::MD5.hexdigest( chall + self.password ))
  145. send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
  146. end
  147. def send_regreq(call)
  148. data = [ IAX_SUBTYPE_REGREQ ].pack('C')
  149. data << create_ie(IAX_IE_USERNAME, self.username) if self.username
  150. data << create_ie(IAX_IE_REG_REFRESH, [IAX_DEFAULT_REG_REFRESH].pack('n'))
  151. send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
  152. end
  153. def send_regreq_chall_response(call, chall)
  154. data =
  155. [ IAX_SUBTYPE_REGREQ ].pack('C') +
  156. create_ie(IAX_IE_USERNAME, self.username) +
  157. create_ie(IAX_IE_CHALLENGE_RESP, ::Digest::MD5.hexdigest( chall + self.password )) +
  158. create_ie(IAX_IE_REG_REFRESH, [IAX_DEFAULT_REG_REFRESH].pack('n'))
  159. send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
  160. end
  161. def create_ie(ie_type, ie_data)
  162. [ie_type, ie_data.length].pack('CC') + ie_data
  163. end
  164. def create_pkt(src_call, dst_call, tstamp, out_seq, inp_seq, itype, data)
  165. [
  166. src_call | 0x8000, # High bit indicates a full packet
  167. dst_call,
  168. tstamp,
  169. out_seq & 0xff, # Sequence numbers wrap at 8-bits
  170. inp_seq & 0xff, # Sequence numbers wrap at 8-bits
  171. itype
  172. ].pack('nnNCCC') + data
  173. end
  174. end
  175. end
  176. end
  177. end