librex 0.0.44 → 0.0.46
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|