librex 0.0.44 → 0.0.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +1 -1
- data/lib/rex/compat.rb +1 -1
- data/lib/rex/exceptions.rb +5 -5
- data/lib/rex/parser/ci_nokogiri.rb +192 -0
- data/lib/rex/parser/nexpose_raw_nokogiri.rb +4 -1
- data/lib/rex/parser/nexpose_simple_nokogiri.rb +4 -1
- data/lib/rex/pescan/analyze.rb +1 -1
- data/lib/rex/post/meterpreter/client.rb +2 -1
- data/lib/rex/post/meterpreter/client_core.rb +11 -2
- data/lib/rex/post/meterpreter/extensions/lanattacks/lanattacks.rb +84 -0
- data/lib/rex/post/meterpreter/extensions/lanattacks/tlv.rb +16 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/mock_magic.rb +368 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +18 -1
- data/lib/rex/proto.rb +1 -0
- data/lib/rex/proto/http/client.rb +3 -1
- data/lib/rex/proto/iax2.rb +1 -0
- data/lib/rex/proto/iax2/call.rb +320 -0
- data/lib/rex/proto/iax2/client.rb +217 -0
- data/lib/rex/proto/iax2/codecs.rb +4 -0
- data/lib/rex/proto/iax2/codecs/alaw.rb +15 -0
- data/lib/rex/proto/iax2/codecs/g711.rb +2175 -0
- data/lib/rex/proto/iax2/codecs/mulaw.rb +16 -0
- data/lib/rex/proto/iax2/constants.rb +261 -0
- data/lib/rex/proto/proxy/socks4a.rb +49 -48
- data/lib/rex/proto/tftp/server.rb +2 -2
- data/lib/rex/socket/range_walker.rb +3 -0
- data/lib/rex/socket/ssl_tcp.rb +59 -45
- data/lib/rex/socket/ssl_tcp_server.rb +20 -8
- data/lib/rex/ui/text/input.rb +1 -0
- metadata +33 -30
@@ -263,13 +263,30 @@ class Console::CommandDispatcher::Stdapi::Net
|
|
263
263
|
print_error("Failed to stop TCP relay on #{lhost || '0.0.0.0'}:#{lport}")
|
264
264
|
end
|
265
265
|
|
266
|
+
when "flush"
|
267
|
+
|
268
|
+
counter = 0
|
269
|
+
service.each_tcp_relay do |lhost, lport, rhost, rport, opts|
|
270
|
+
next if (opts['MeterpreterRelay'] == nil)
|
271
|
+
|
272
|
+
if (service.stop_tcp_relay(lport, lhost))
|
273
|
+
print_status("Successfully stopped TCP relay on #{lhost || '0.0.0.0'}:#{lport}")
|
274
|
+
else
|
275
|
+
print_error("Failed to stop TCP relay on #{lhost || '0.0.0.0'}:#{lport}")
|
276
|
+
next
|
277
|
+
end
|
278
|
+
|
279
|
+
counter += 1
|
280
|
+
end
|
281
|
+
print_status("Successfully flushed #{counter} rules")
|
282
|
+
|
266
283
|
else
|
267
284
|
cmd_portfwd_help
|
268
285
|
end
|
269
286
|
end
|
270
287
|
|
271
288
|
def cmd_portfwd_help
|
272
|
-
print_line "Usage: portfwd [-h] [add
|
289
|
+
print_line "Usage: portfwd [-h] [add | delete | list | flush] [args]"
|
273
290
|
print_line
|
274
291
|
print @@portfwd_opts.usage
|
275
292
|
end
|
data/lib/rex/proto.rb
CHANGED
@@ -15,6 +15,8 @@ module Http
|
|
15
15
|
###
|
16
16
|
class Client
|
17
17
|
|
18
|
+
DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
|
19
|
+
|
18
20
|
#
|
19
21
|
# Creates a new client instance
|
20
22
|
#
|
@@ -29,7 +31,7 @@ class Client
|
|
29
31
|
'read_max_data' => (1024*1024*1),
|
30
32
|
'vhost' => self.hostname,
|
31
33
|
'version' => '1.1',
|
32
|
-
'agent' =>
|
34
|
+
'agent' => DefaultUserAgent,
|
33
35
|
#
|
34
36
|
# Evasion options
|
35
37
|
#
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'rex/proto/iax2/client'
|
@@ -0,0 +1,320 @@
|
|
1
|
+
module Rex
|
2
|
+
module Proto
|
3
|
+
module IAX2
|
4
|
+
class Call
|
5
|
+
|
6
|
+
attr_accessor :client
|
7
|
+
attr_accessor :oseq, :iseq
|
8
|
+
attr_accessor :scall, :dcall
|
9
|
+
attr_accessor :codec, :state
|
10
|
+
attr_accessor :ring_start, :ring_finish
|
11
|
+
attr_accessor :itime
|
12
|
+
attr_accessor :queue
|
13
|
+
attr_accessor :audio_hook
|
14
|
+
attr_accessor :audio_buff
|
15
|
+
attr_accessor :time_limit
|
16
|
+
attr_accessor :busy
|
17
|
+
|
18
|
+
attr_accessor :caller_name
|
19
|
+
attr_accessor :caller_number
|
20
|
+
attr_accessor :dtmf
|
21
|
+
|
22
|
+
|
23
|
+
def initialize(client, src_id)
|
24
|
+
self.client = client
|
25
|
+
self.scall = src_id
|
26
|
+
self.dcall = 0
|
27
|
+
self.iseq = 0
|
28
|
+
self.oseq = 0
|
29
|
+
self.state = nil
|
30
|
+
|
31
|
+
self.itime = ::Time.now
|
32
|
+
self.queue = ::Queue.new
|
33
|
+
|
34
|
+
self.audio_buff = []
|
35
|
+
|
36
|
+
self.busy = false
|
37
|
+
self.dtmf = ''
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def dprint(msg)
|
42
|
+
self.client.dprint(msg)
|
43
|
+
end
|
44
|
+
|
45
|
+
def wait_for(*stypes)
|
46
|
+
begin
|
47
|
+
::Timeout.timeout( IAX_DEFAULT_TIMEOUT ) do
|
48
|
+
while (res = self.queue.pop )
|
49
|
+
if stypes.include?(res[1])
|
50
|
+
return res
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
rescue ::Timeout::Error
|
55
|
+
return nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Register with the IAX endpoint
|
60
|
+
def register
|
61
|
+
self.client.send_regreq(self)
|
62
|
+
res = wait_for( IAX_SUBTYPE_REGAUTH, IAX_SUBTYPE_REGREJ )
|
63
|
+
return if not res
|
64
|
+
|
65
|
+
if res[1] == IAX_SUBTYPE_REGREJ
|
66
|
+
reason = res[2][IAX_IE_REGREJ_CAUSE] || "Unknown Reason"
|
67
|
+
dprint("REGREJ: #{reason}")
|
68
|
+
# Acknowledge the REGREJ
|
69
|
+
self.client.send_ack(self)
|
70
|
+
return
|
71
|
+
end
|
72
|
+
|
73
|
+
chall = nil
|
74
|
+
if res[2][14] == "\x00\x03" and res[2][IAX_IE_CHALLENGE_DATA]
|
75
|
+
self.dcall = res[0][0]
|
76
|
+
chall = res[2][IAX_IE_CHALLENGE_DATA]
|
77
|
+
end
|
78
|
+
|
79
|
+
self.client.send_regreq_chall_response(self, chall)
|
80
|
+
res = wait_for( IAX_SUBTYPE_REGACK, IAX_SUBTYPE_REGREJ )
|
81
|
+
return if not res
|
82
|
+
|
83
|
+
if res[1] == IAX_SUBTYPE_REGREJ
|
84
|
+
reason = res[2][IAX_IE_REGREJ_CAUSE] || "Unknown Reason"
|
85
|
+
dprint("REGREJ: #{reason}")
|
86
|
+
return
|
87
|
+
end
|
88
|
+
|
89
|
+
if res[2][IAX_IE_APPARENT_ADDR]
|
90
|
+
r_fam, r_port, r_addr = res[2][IAX_IE_APPARENT_ADDR].unpack('nnA4')
|
91
|
+
r_addr = r_addr.unpack("C*").map{|x| x.to_s }.join(".")
|
92
|
+
dprint("REGACK: Registered from address #{r_addr}:#{r_port}")
|
93
|
+
end
|
94
|
+
|
95
|
+
# Acknowledge the REGACK
|
96
|
+
self.client.send_ack(self)
|
97
|
+
|
98
|
+
self.state = :registered
|
99
|
+
|
100
|
+
true
|
101
|
+
end
|
102
|
+
|
103
|
+
def dial(number)
|
104
|
+
self.client.send_new(self, number)
|
105
|
+
res = wait_for(IAX_SUBTYPE_AUTHREQ, IAX_SUBTYPE_ACCEPT)
|
106
|
+
return if not res
|
107
|
+
|
108
|
+
# Handle authentication if its requested
|
109
|
+
if res[1] == IAX_SUBTYPE_AUTHREQ
|
110
|
+
chall = nil
|
111
|
+
if res[2][14] == "\x00\x03" and res[1][15]
|
112
|
+
self.dcall = res[0][0]
|
113
|
+
chall = res[2][15]
|
114
|
+
end
|
115
|
+
|
116
|
+
self.client.send_authrep_chall_response(self, chall)
|
117
|
+
res = wait_for( IAX_SUBTYPE_ACCEPT)
|
118
|
+
return if not res
|
119
|
+
end
|
120
|
+
|
121
|
+
self.codec = res[2][IAX_IE_DESIRED_CODEC].unpack("N")[0]
|
122
|
+
self.state = :ringing
|
123
|
+
self.ring_start = ::Time.now.to_i
|
124
|
+
self.client.send_ack(self)
|
125
|
+
true
|
126
|
+
end
|
127
|
+
|
128
|
+
def hangup
|
129
|
+
self.client.send_hangup(self)
|
130
|
+
self.state = :hangup
|
131
|
+
true
|
132
|
+
end
|
133
|
+
|
134
|
+
def ring_time
|
135
|
+
(self.ring_finish || Time.now).to_i - self.ring_start.to_i
|
136
|
+
end
|
137
|
+
|
138
|
+
def timestamp
|
139
|
+
(( ::Time.now - self.itime) * 1000.0 ).to_i & 0xffffffff
|
140
|
+
end
|
141
|
+
|
142
|
+
def process_elements(data,off=0)
|
143
|
+
res = {}
|
144
|
+
while( off < data.length )
|
145
|
+
ie_type = data[off ,1].unpack("C")[0]
|
146
|
+
ie_len = data[off + 1,2].unpack("C")[0]
|
147
|
+
res[ie_type] = data[off + 2, ie_len]
|
148
|
+
off += ie_len + 2
|
149
|
+
end
|
150
|
+
res
|
151
|
+
end
|
152
|
+
|
153
|
+
# Handling incoming control packets
|
154
|
+
# TODO: Enforce sequence order to prevent duplicates from breaking our state
|
155
|
+
def handle_control(pkt)
|
156
|
+
src_call, dst_call, tstamp, out_seq, inp_seq, itype = pkt.unpack('nnNCCC')
|
157
|
+
|
158
|
+
# Scrub the high bits out of the call IDs
|
159
|
+
src_call ^= 0x8000 if (src_call & 0x8000 != 0)
|
160
|
+
dst_call ^= 0x8000 if (dst_call & 0x8000 != 0)
|
161
|
+
|
162
|
+
phdr = [ src_call, dst_call, tstamp, out_seq, inp_seq, itype ]
|
163
|
+
|
164
|
+
info = nil
|
165
|
+
stype = pkt[11,1].unpack("C")[0]
|
166
|
+
info = process_elements(pkt, 12) if [IAX_TYPE_IAX, IAX_TYPE_CONTROL].include?(itype)
|
167
|
+
|
168
|
+
if dst_call != self.scall
|
169
|
+
dprint("Incoming packet to inactive call: #{dst_call} vs #{self.scall}: #{phdr.inspect} #{stype.inspect} #{info.inspect}")
|
170
|
+
return
|
171
|
+
end
|
172
|
+
|
173
|
+
# Increment the received sequence number
|
174
|
+
self.iseq = (self.iseq + 1) & 0xff
|
175
|
+
|
176
|
+
if self.state == :hangup
|
177
|
+
dprint("Packet received after hangup, replying with invalid")
|
178
|
+
self.client.send_invalid(self)
|
179
|
+
return
|
180
|
+
end
|
181
|
+
|
182
|
+
# Technically these all require an ACK reply
|
183
|
+
# NEW, HANGUP, REJECT, ACCEPT, PONG, AUTHREP, REGREL, REGACK, REGREJ, TXREL
|
184
|
+
|
185
|
+
case itype
|
186
|
+
when IAX_TYPE_DTMF_BEGIN
|
187
|
+
self.dprint("DTMF BEG: #{pkt[11,1]}")
|
188
|
+
self.dtmf << pkt[11,1]
|
189
|
+
|
190
|
+
when IAX_TYPE_DTMF_END
|
191
|
+
self.dprint("DTMF END: #{pkt[11,1]}")
|
192
|
+
|
193
|
+
when IAX_TYPE_CONTROL
|
194
|
+
case stype
|
195
|
+
when IAX_CTRL_HANGUP
|
196
|
+
dprint("HANGUP")
|
197
|
+
self.client.send_ack(self)
|
198
|
+
self.state = :hangup
|
199
|
+
|
200
|
+
when IAX_CTRL_RINGING
|
201
|
+
dprint("RINGING")
|
202
|
+
self.client.send_ack(self)
|
203
|
+
|
204
|
+
when IAX_CTRL_BUSY
|
205
|
+
dprint("BUSY")
|
206
|
+
self.busy = true
|
207
|
+
self.state = :hangup
|
208
|
+
self.client.send_ack(self)
|
209
|
+
|
210
|
+
when IAX_CTRL_ANSWER
|
211
|
+
dprint("ANSWER")
|
212
|
+
if self.state == :ringing
|
213
|
+
self.state = :answered
|
214
|
+
self.ring_finish = ::Time.now.to_i
|
215
|
+
end
|
216
|
+
self.client.send_ack(self)
|
217
|
+
|
218
|
+
when IAX_CTRL_PROGRESS
|
219
|
+
dprint("PROGRESS")
|
220
|
+
|
221
|
+
when IAX_CTRL_PROCEED
|
222
|
+
dprint("PROCEED")
|
223
|
+
|
224
|
+
when 255
|
225
|
+
dprint("STOP SOUNDS")
|
226
|
+
end
|
227
|
+
# Acknowledge all control packets
|
228
|
+
# self.client.send_ack(self)
|
229
|
+
|
230
|
+
when IAX_TYPE_IAX
|
231
|
+
|
232
|
+
dprint( ["RECV", phdr, stype, info].inspect )
|
233
|
+
case stype
|
234
|
+
when IAX_SUBTYPE_HANGUP
|
235
|
+
self.state = :hangup
|
236
|
+
self.client.send_ack(self)
|
237
|
+
when IAX_SUBTYPE_LAGRQ
|
238
|
+
# Lagrps echo the timestamp
|
239
|
+
self.client.send_lagrp(self, tstamp)
|
240
|
+
when IAX_SUBTYPE_ACK
|
241
|
+
# Nothing to do here
|
242
|
+
when IAX_SUBTYPE_PING
|
243
|
+
# Pongs echo the timestamp
|
244
|
+
self.client.send_pong(self, tstamp)
|
245
|
+
when IAX_SUBTYPE_PONG
|
246
|
+
self.client.send_ack(self)
|
247
|
+
else
|
248
|
+
dprint( ["RECV-QUEUE", phdr, stype, info].inspect )
|
249
|
+
self.queue.push( [phdr, stype, info ] )
|
250
|
+
end
|
251
|
+
|
252
|
+
when IAX_TYPE_VOICE
|
253
|
+
v_codec = stype
|
254
|
+
if self.state == :answered
|
255
|
+
handle_audio(pkt)
|
256
|
+
end
|
257
|
+
self.client.send_ack(self)
|
258
|
+
|
259
|
+
when nil
|
260
|
+
dprint("Invalid control packet: #{pkt.unpack("H*")[0]}")
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
|
265
|
+
# Encoded audio from the client
|
266
|
+
def handle_audio(pkt)
|
267
|
+
# Ignore audio received before the call is answered (ring ring)
|
268
|
+
return if self.state != :answered
|
269
|
+
|
270
|
+
# Extract the data from the packet (full or mini)
|
271
|
+
data = audio_packet_data(pkt)
|
272
|
+
|
273
|
+
# Decode the data into linear PCM frames
|
274
|
+
buff = decode_audio_frame(data)
|
275
|
+
|
276
|
+
# Call the caller-provided hook if its exists
|
277
|
+
if self.audio_hook
|
278
|
+
self.audio_buff(buff)
|
279
|
+
# Otherwise append the frame to the buffer
|
280
|
+
else
|
281
|
+
self.audio_buff << buff
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def each_audio_frame(&block)
|
286
|
+
self.audio_buff.each do |frame|
|
287
|
+
block.call(frame)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def decode_audio_frame(buff)
|
292
|
+
case self.codec
|
293
|
+
|
294
|
+
# Convert u-law into signed PCM
|
295
|
+
when IAX_CODEC_G711_MULAW
|
296
|
+
Rex::Proto::IAX2::Codecs::MuLaw.decode(buff)
|
297
|
+
|
298
|
+
# Convert a-law into signed PCM
|
299
|
+
when IAX_CODEC_G711_ALAW
|
300
|
+
Rex::Proto::IAX2::Codecs::ALaw.decode(buff)
|
301
|
+
|
302
|
+
# Linear little-endian signed PCM is our native format
|
303
|
+
when IAX_CODEC_LINEAR_PCM
|
304
|
+
buff
|
305
|
+
|
306
|
+
# Unsupported codec, return empty
|
307
|
+
else
|
308
|
+
dprint("UNKNOWN CODEC: #{self.codec.inspect}")
|
309
|
+
''
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def audio_packet_data(pkt)
|
314
|
+
(pkt[0,1].unpack("C")[0] & 0x80 == 0) ? pkt[4,pkt.length-4] : pkt[12,pkt.length-12]
|
315
|
+
end
|
316
|
+
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
require 'rex/proto/iax2/constants'
|
2
|
+
require 'rex/proto/iax2/codecs'
|
3
|
+
require 'rex/proto/iax2/call'
|
4
|
+
|
5
|
+
require 'rex/socket'
|
6
|
+
require 'thread'
|
7
|
+
require 'digest/md5'
|
8
|
+
require 'timeout'
|
9
|
+
|
10
|
+
module Rex
|
11
|
+
module Proto
|
12
|
+
module IAX2
|
13
|
+
class Client
|
14
|
+
|
15
|
+
attr_accessor :caller_number, :caller_name, :server_host, :server_port
|
16
|
+
attr_accessor :username, :password
|
17
|
+
attr_accessor :sock, :monitor
|
18
|
+
attr_accessor :src_call_idx
|
19
|
+
attr_accessor :debugging
|
20
|
+
attr_accessor :calls
|
21
|
+
|
22
|
+
def initialize(uopts={})
|
23
|
+
opts = {
|
24
|
+
:caller_number => '15555555555',
|
25
|
+
:caller_name => '',
|
26
|
+
:server_port => IAX2_DEFAULT_PORT,
|
27
|
+
:context => { }
|
28
|
+
}.merge(uopts)
|
29
|
+
|
30
|
+
self.caller_name = opts[:caller_name]
|
31
|
+
self.caller_number = opts[:caller_number]
|
32
|
+
self.server_host = opts[:server_host]
|
33
|
+
self.server_port = opts[:server_port]
|
34
|
+
self.username = opts[:username]
|
35
|
+
self.password = opts[:password]
|
36
|
+
|
37
|
+
self.sock = Rex::Socket::Udp.create(
|
38
|
+
'PeerHost' => self.server_host,
|
39
|
+
'PeerPort' => self.server_port,
|
40
|
+
'Context' => opts[:context]
|
41
|
+
)
|
42
|
+
|
43
|
+
self.monitor = ::Thread.new { monitor_socket }
|
44
|
+
|
45
|
+
self.src_call_idx = 0
|
46
|
+
self.calls = {}
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def shutdown
|
51
|
+
self.monitor.kill rescue nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def create_call
|
55
|
+
cid = allocate_call_id()
|
56
|
+
self.calls[ cid ] = IAX2::Call.new(self, cid)
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Transport
|
61
|
+
#
|
62
|
+
|
63
|
+
def monitor_socket
|
64
|
+
while true
|
65
|
+
begin
|
66
|
+
pkt, src = self.sock.recvfrom(65535)
|
67
|
+
next if not pkt
|
68
|
+
|
69
|
+
# Find the matching call object
|
70
|
+
mcall = matching_call(pkt)
|
71
|
+
next if not mcall
|
72
|
+
|
73
|
+
if (pkt[0,1].unpack("C")[0] & 0x80) != 0
|
74
|
+
mcall.handle_control(pkt)
|
75
|
+
else
|
76
|
+
# Dispatch the buffer via the call handler
|
77
|
+
mcall.handle_audio(pkt)
|
78
|
+
end
|
79
|
+
rescue ::Exception => e
|
80
|
+
dprint("monitor_socket: #{e.class} #{e} #{e.backtrace}")
|
81
|
+
break
|
82
|
+
end
|
83
|
+
end
|
84
|
+
self.sock.close rescue nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def matching_call(pkt)
|
88
|
+
src_call = pkt[0,2].unpack('n')[0]
|
89
|
+
dst_call = nil
|
90
|
+
|
91
|
+
if (src_call & 0x8000 != 0)
|
92
|
+
dst_call = pkt[2,2].unpack('n')[0]
|
93
|
+
dst_call ^= 0x8000 if (dst_call & 0x8000 != 0)
|
94
|
+
end
|
95
|
+
|
96
|
+
src_call ^= 0x8000 if (src_call & 0x8000 != 0)
|
97
|
+
|
98
|
+
# Find a matching call in our list
|
99
|
+
mcall = self.calls.values.select {|x| x.dcall == src_call or (dst_call and x.scall == dst_call) }.first
|
100
|
+
if not mcall
|
101
|
+
dprint("Packet received for non-existent call #{[src_call, dst_call].inspect} vs #{self.calls.values.map{|x| [x.dcall, x.scall]}.inspect}")
|
102
|
+
return
|
103
|
+
end
|
104
|
+
mcall
|
105
|
+
end
|
106
|
+
|
107
|
+
def allocate_call_id
|
108
|
+
res = ( self.src_call_idx += 1 )
|
109
|
+
if ( res > 0x8000 )
|
110
|
+
self.src_call_idx = 1
|
111
|
+
res = 1
|
112
|
+
end
|
113
|
+
res
|
114
|
+
end
|
115
|
+
|
116
|
+
def dprint(msg)
|
117
|
+
return if not self.debugging
|
118
|
+
$stderr.puts "[#{Time.now.to_s}] #{msg}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def send_data(call, data, inc_seq = true )
|
122
|
+
r = self.sock.sendto(data, self.server_host, self.server_port, 0)
|
123
|
+
if inc_seq
|
124
|
+
call.oseq = (call.oseq + 1) & 0xff
|
125
|
+
end
|
126
|
+
r
|
127
|
+
end
|
128
|
+
|
129
|
+
def send_ack(call)
|
130
|
+
data = [ IAX_SUBTYPE_ACK ].pack('C')
|
131
|
+
send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ), false )
|
132
|
+
end
|
133
|
+
|
134
|
+
def send_pong(call, stamp)
|
135
|
+
data = [ IAX_SUBTYPE_PONG ].pack('C')
|
136
|
+
send_data( call, create_pkt( call.scall, call.dcall, stamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
|
137
|
+
end
|
138
|
+
|
139
|
+
def send_lagrp(call, stamp)
|
140
|
+
data = [ IAX_SUBTYPE_LAGRP ].pack('C')
|
141
|
+
send_data( call, create_pkt( call.scall, call.dcall, stamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
def send_invalid(call)
|
146
|
+
data = [ IAX_SUBTYPE_INVAL ].pack('C')
|
147
|
+
send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
|
148
|
+
end
|
149
|
+
|
150
|
+
def send_hangup(call)
|
151
|
+
data = [ IAX_SUBTYPE_HANGUP ].pack('C')
|
152
|
+
send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
|
153
|
+
end
|
154
|
+
|
155
|
+
def send_new(call, number)
|
156
|
+
data = [ IAX_SUBTYPE_NEW ].pack('C')
|
157
|
+
|
158
|
+
cid = call.caller_number || self.caller_number
|
159
|
+
cid = number if cid == 'SELF'
|
160
|
+
|
161
|
+
data << create_ie(IAX_IE_CALLING_NUMBER, cid )
|
162
|
+
data << create_ie(IAX_IE_CALLING_NAME, call.caller_name || self.caller_name)
|
163
|
+
data << create_ie(IAX_IE_DESIRED_CODEC, [IAX_SUPPORTED_CODECS].pack("N") )
|
164
|
+
data << create_ie(IAX_IE_ACTUAL_CODECS, [IAX_SUPPORTED_CODECS].pack("N") )
|
165
|
+
data << create_ie(IAX_IE_USERNAME, self.username) if self.username
|
166
|
+
data << create_ie(IAX_IE_CALLED_NUMBER, number)
|
167
|
+
data << create_ie(IAX_IE_ORIGINAL_DID, number)
|
168
|
+
|
169
|
+
send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
|
170
|
+
end
|
171
|
+
|
172
|
+
def send_authrep_chall_response(call, chall)
|
173
|
+
data =
|
174
|
+
[ IAX_SUBTYPE_AUTHREP ].pack('C') +
|
175
|
+
create_ie(IAX_IE_CHALLENGE_RESP, ::Digest::MD5.hexdigest( chall + self.password ))
|
176
|
+
|
177
|
+
send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
|
178
|
+
end
|
179
|
+
|
180
|
+
def send_regreq(call)
|
181
|
+
data = [ IAX_SUBTYPE_REGREQ ].pack('C')
|
182
|
+
data << create_ie(IAX_IE_USERNAME, self.username) if self.username
|
183
|
+
data << create_ie(IAX_IE_REG_REFRESH, [IAX_DEFAULT_REG_REFRESH].pack('n'))
|
184
|
+
|
185
|
+
send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
|
186
|
+
end
|
187
|
+
|
188
|
+
def send_regreq_chall_response(call, chall)
|
189
|
+
data =
|
190
|
+
[ IAX_SUBTYPE_REGREQ ].pack('C') +
|
191
|
+
create_ie(IAX_IE_USERNAME, self.username) +
|
192
|
+
create_ie(IAX_IE_CHALLENGE_RESP, ::Digest::MD5.hexdigest( chall + self.password )) +
|
193
|
+
create_ie(IAX_IE_REG_REFRESH, [IAX_DEFAULT_REG_REFRESH].pack('n'))
|
194
|
+
|
195
|
+
send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.oseq, call.iseq, IAX_TYPE_IAX, data ) )
|
196
|
+
end
|
197
|
+
|
198
|
+
def create_ie(ie_type, ie_data)
|
199
|
+
[ie_type, ie_data.length].pack('CC') + ie_data
|
200
|
+
end
|
201
|
+
|
202
|
+
def create_pkt(src_call, dst_call, tstamp, out_seq, inp_seq, itype, data)
|
203
|
+
[
|
204
|
+
src_call | 0x8000, # High bit indicates a full packet
|
205
|
+
dst_call,
|
206
|
+
tstamp,
|
207
|
+
out_seq & 0xff, # Sequence numbers wrap at 8-bits
|
208
|
+
inp_seq & 0xff, # Sequence numbers wrap at 8-bits
|
209
|
+
itype
|
210
|
+
].pack('nnNCCC') + data
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|