Class: Rex::Proto::IAX2::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/rex/proto/iax2/client.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(uopts = {}) ⇒ Client


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/rex/proto/iax2/client.rb', line 23

def initialize(uopts={})
  opts = {
    :caller_number => '15555555555',
    :caller_name   => '',
    :server_port   => IAX2_DEFAULT_PORT,
    :context       => { }
  }.merge(uopts)

  self.caller_name   = opts[:caller_name]
  self.caller_number = opts[:caller_number]
  self.server_host   = opts[:server_host]
  self.server_port   = opts[:server_port]
  self.username      = opts[:username]
  self.password      = opts[:password]

  self.sock = Rex::Socket::Udp.create(
    'PeerHost' => self.server_host,
    'PeerPort' => self.server_port,
    'Context'  => opts[:context]
  )

  self.monitor   = ::Thread.new { monitor_socket }

  self.src_call_idx = 0
  self.calls = {}

end

Instance Attribute Details

#caller_nameObject

Returns the value of attribute caller_name


16
17
18
# File 'lib/rex/proto/iax2/client.rb', line 16

def caller_name
  @caller_name
end

#caller_numberObject

Returns the value of attribute caller_number


16
17
18
# File 'lib/rex/proto/iax2/client.rb', line 16

def caller_number
  @caller_number
end

#callsObject

Returns the value of attribute calls


21
22
23
# File 'lib/rex/proto/iax2/client.rb', line 21

def calls
  @calls
end

#debuggingObject

Returns the value of attribute debugging


20
21
22
# File 'lib/rex/proto/iax2/client.rb', line 20

def debugging
  @debugging
end

#monitorObject

Returns the value of attribute monitor


18
19
20
# File 'lib/rex/proto/iax2/client.rb', line 18

def monitor
  @monitor
end

#passwordObject

Returns the value of attribute password


17
18
19
# File 'lib/rex/proto/iax2/client.rb', line 17

def password
  @password
end

#server_hostObject

Returns the value of attribute server_host


16
17
18
# File 'lib/rex/proto/iax2/client.rb', line 16

def server_host
  @server_host
end

#server_portObject

Returns the value of attribute server_port


16
17
18
# File 'lib/rex/proto/iax2/client.rb', line 16

def server_port
  @server_port
end

#sockObject

Returns the value of attribute sock


18
19
20
# File 'lib/rex/proto/iax2/client.rb', line 18

def sock
  @sock
end

#src_call_idxObject

Returns the value of attribute src_call_idx


19
20
21
# File 'lib/rex/proto/iax2/client.rb', line 19

def src_call_idx
  @src_call_idx
end

#usernameObject

Returns the value of attribute username


17
18
19
# File 'lib/rex/proto/iax2/client.rb', line 17

def username
  @username
end

Instance Method Details

#allocate_call_idObject


108
109
110
111
112
113
114
115
# File 'lib/rex/proto/iax2/client.rb', line 108

def allocate_call_id
  res = ( self.src_call_idx += 1 )
  if ( res > 0x8000 )
    self.src_call_idx = 1
    res = 1
  end
  res
end

#create_callObject


55
56
57
58
# File 'lib/rex/proto/iax2/client.rb', line 55

def create_call
  cid  = allocate_call_id()
  self.calls[ cid ] = IAX2::Call.new(self, cid)
end

#create_ie(ie_type, ie_data) ⇒ Object


199
200
201
# File 'lib/rex/proto/iax2/client.rb', line 199

def create_ie(ie_type, ie_data)
  [ie_type, ie_data.length].pack('CC') + ie_data
end

#create_pkt(src_call, dst_call, tstamp, out_seq, inp_seq, itype, data) ⇒ Object


203
204
205
206
207
208
209
210
211
212
# File 'lib/rex/proto/iax2/client.rb', line 203

def create_pkt(src_call, dst_call, tstamp, out_seq, inp_seq, itype, data)
  [
    src_call | 0x8000,  # High bit indicates a full packet
    dst_call,
    tstamp,
    out_seq & 0xff,     # Sequence numbers wrap at 8-bits
    inp_seq & 0xff,     # Sequence numbers wrap at 8-bits
    itype
  ].pack('nnNCCC') + data
end

#dprint(msg) ⇒ Object


117
118
119
120
# File 'lib/rex/proto/iax2/client.rb', line 117

def dprint(msg)
  return if not self.debugging
  $stderr.puts "[#{Time.now.to_s}] #{msg}"
end

#matching_call(pkt) ⇒ Object


88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/rex/proto/iax2/client.rb', line 88

def matching_call(pkt)
  src_call = pkt[0,2].unpack('n')[0]
  dst_call = nil

  if (src_call & 0x8000 != 0)
    dst_call = pkt[2,2].unpack('n')[0]
    dst_call ^= 0x8000 if (dst_call & 0x8000 != 0)
  end

  src_call ^= 0x8000 if (src_call & 0x8000 != 0)

  # Find a matching call in our list
  mcall = self.calls.values.select {|x| x.dcall == src_call or (dst_call and x.scall == dst_call) }.first
  if not mcall
    dprint("Packet received for non-existent call #{[src_call, dst_call].inspect}  vs #{self.calls.values.map{|x| [x.dcall, x.scall]}.inspect}")
    return
  end
  mcall
end

#monitor_socketObject

Transport


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rex/proto/iax2/client.rb', line 64

def monitor_socket
  while true
    begin
      pkt, src = self.sock.recvfrom(65535)
      next if not pkt

      # Find the matching call object
      mcall = matching_call(pkt)
      next if not mcall

      if (pkt[0,1].unpack("C")[0] & 0x80) != 0
        mcall.handle_control(pkt)
      else
        # Dispatch the buffer via the call handler
        mcall.handle_audio(pkt)
      end
    rescue ::Exception => e
      dprint("monitor_socket: #{e.class} #{e} #{e.backtrace}")
      break
    end
  end
  self.sock.close rescue nil
end

#send_ack(call) ⇒ Object


130
131
132
133
# File 'lib/rex/proto/iax2/client.rb', line 130

def send_ack(call)
  data =	[ IAX_SUBTYPE_ACK ].pack('C')
  send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ), false )
end

#send_authrep_chall_response(call, chall) ⇒ Object


173
174
175
176
177
178
179
# File 'lib/rex/proto/iax2/client.rb', line 173

def send_authrep_chall_response(call, chall)
  data =
    [ IAX_SUBTYPE_AUTHREP ].pack('C') +
    create_ie(IAX_IE_CHALLENGE_RESP, ::Digest::MD5.hexdigest( chall + self.password ))

  send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
end

#send_data(call, data, inc_seq = true) ⇒ Object


122
123
124
125
126
127
128
# File 'lib/rex/proto/iax2/client.rb', line 122

def send_data(call, data, inc_seq = true )
  r = self.sock.sendto(data, self.server_host, self.server_port, 0)
  if inc_seq
    call.oseq = (call.oseq + 1) & 0xff
  end
  r
end

#send_hangup(call) ⇒ Object


151
152
153
154
# File 'lib/rex/proto/iax2/client.rb', line 151

def send_hangup(call)
  data =	[ IAX_SUBTYPE_HANGUP ].pack('C')
  send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
end

#send_invalid(call) ⇒ Object


146
147
148
149
# File 'lib/rex/proto/iax2/client.rb', line 146

def send_invalid(call)
  data =	[ IAX_SUBTYPE_INVAL ].pack('C')
  send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
end

#send_lagrp(call, stamp) ⇒ Object


140
141
142
143
# File 'lib/rex/proto/iax2/client.rb', line 140

def send_lagrp(call, stamp)
  data =	[ IAX_SUBTYPE_LAGRP ].pack('C')
  send_data( call, create_pkt( call.scall, call.dcall, stamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
end

#send_new(call, number) ⇒ Object


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/rex/proto/iax2/client.rb', line 156

def send_new(call, number)
  data = [ IAX_SUBTYPE_NEW ].pack('C')

  cid = call.caller_number || self.caller_number
  cid = number if cid == 'SELF'

  data << create_ie(IAX_IE_CALLING_NUMBER, cid )
  data << create_ie(IAX_IE_CALLING_NAME, call.caller_name || self.caller_name)
  data << create_ie(IAX_IE_DESIRED_CODEC, [IAX_SUPPORTED_CODECS].pack("N") )
  data << create_ie(IAX_IE_ACTUAL_CODECS, [IAX_SUPPORTED_CODECS].pack("N") )
  data << create_ie(IAX_IE_USERNAME, self.username) if self.username
  data << create_ie(IAX_IE_CALLED_NUMBER, number)
  data << create_ie(IAX_IE_ORIGINAL_DID, number)

  send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
end

#send_pong(call, stamp) ⇒ Object


135
136
137
138
# File 'lib/rex/proto/iax2/client.rb', line 135

def send_pong(call, stamp)
  data =	[ IAX_SUBTYPE_PONG ].pack('C')
  send_data( call, create_pkt( call.scall, call.dcall, stamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
end

#send_regreq(call) ⇒ Object


181
182
183
184
185
186
187
# File 'lib/rex/proto/iax2/client.rb', line 181

def send_regreq(call)
  data = [ IAX_SUBTYPE_REGREQ ].pack('C')
  data << create_ie(IAX_IE_USERNAME, self.username) if self.username
  data << create_ie(IAX_IE_REG_REFRESH, [IAX_DEFAULT_REG_REFRESH].pack('n'))

  send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
end

#send_regreq_chall_response(call, chall) ⇒ Object


189
190
191
192
193
194
195
196
197
# File 'lib/rex/proto/iax2/client.rb', line 189

def send_regreq_chall_response(call, chall)
  data =
    [ IAX_SUBTYPE_REGREQ ].pack('C') +
    create_ie(IAX_IE_USERNAME, self.username) +
    create_ie(IAX_IE_CHALLENGE_RESP, ::Digest::MD5.hexdigest( chall + self.password )) +
    create_ie(IAX_IE_REG_REFRESH, [IAX_DEFAULT_REG_REFRESH].pack('n'))

  send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
end

#shutdownObject


51
52
53
# File 'lib/rex/proto/iax2/client.rb', line 51

def shutdown
  self.monitor.kill rescue nil
end