CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

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