182 lines
4.3 KiB
Ruby
182 lines
4.3 KiB
Ruby
module Telephony
|
|
|
|
class Modem
|
|
attr_accessor :serialport, :sp, :sock
|
|
attr_accessor :baud, :data_bits, :parity, :stop_bits
|
|
attr_accessor :flowcontrol
|
|
attr_accessor :display
|
|
attr_reader :commandstate
|
|
|
|
NONE = SerialPort::NONE
|
|
HARD = SerialPort::HARD
|
|
SOFT = SerialPort::SOFT
|
|
SPACE = SerialPort::SPACE
|
|
MARK = SerialPort::MARK
|
|
EVEN = SerialPort::EVEN
|
|
ODD = SerialPort::ODD
|
|
|
|
def initialize(serialport = '/dev/ttyS0')
|
|
@serialport = serialport || '/dev/ttyS0'
|
|
@sp = nil
|
|
@baud = 2400
|
|
@data_bits = 8
|
|
@parity = NONE
|
|
@stop_bits = 1
|
|
@flowcontrol = NONE
|
|
@commandstate = true
|
|
@display = true
|
|
|
|
# Connect to and init modem
|
|
begin
|
|
#print("Opening Serial Port #{@serialport} (#{@baud} #{@data_bits}#{@parity}#{@stop_bits})\r\n")
|
|
@sp = SerialPort.create(serialport)
|
|
@sp.modem_params = {'baud' => @baud, 'data_bits' => @data_bits, 'parity' => @parity, 'stop_bits' => @stop_bits}
|
|
@sp.read_timeout = -1
|
|
@sp.rts = 1
|
|
@sp.dtr = 1 if sp.respond_to?:dtr= # unsupported in windows ):
|
|
@sock = @sp
|
|
@sock.extend(Rex::IO::Stream)
|
|
@sock.extend(Rex::IO::StreamAbstraction::Ext)
|
|
rescue ::Interrupt
|
|
raise $!
|
|
rescue ::Exception => e
|
|
print("Error opening serial port #{@serialport} : #{e.class} #{e} #{e.backtrace}\r\n")
|
|
return true
|
|
end
|
|
end
|
|
|
|
# This provides pass-through method support for the SerialPort object
|
|
def method_missing(meth, *args); self.sp.send(meth, *args); end
|
|
|
|
def put_command(command, timeout)
|
|
switchback = false
|
|
if ! @commandstate
|
|
commandstate
|
|
switchback = true
|
|
end
|
|
|
|
begin
|
|
self.flush # TODO: This doesn't work in exploits for some reason but it does in aux modules
|
|
@sp.puts command + "\r\n"
|
|
echo = get_response(timeout) # read back the echoed command (not really a response)
|
|
|
|
rescue ::Interrupt
|
|
raise $!
|
|
rescue ::Exception => e
|
|
print("Error sending command to modem: #{e.class} #{e} #{e.backtrace}\r\n")
|
|
return
|
|
end
|
|
|
|
result = get_response(timeout)
|
|
|
|
datastate if switchback == true
|
|
|
|
return result
|
|
end
|
|
|
|
def get_response(timeout)
|
|
time = Time.now
|
|
|
|
@sp.read_timeout = -1
|
|
result = ''
|
|
while Time.now <= time + timeout
|
|
# get a char from the modem
|
|
begin
|
|
c = @sp.getc
|
|
if c
|
|
c = c.chr
|
|
result += c
|
|
if c == "\n"
|
|
result = result.chomp
|
|
break if result.length > 0
|
|
end
|
|
end
|
|
rescue ::Interrupt
|
|
raise $!
|
|
rescue ::Exception => e
|
|
print("Error reading from modem: #{e.class} #{e} #{e.backtrace}\r\n")
|
|
return
|
|
end
|
|
end
|
|
|
|
if result.length > 0
|
|
print "[m] #{result}\r\n" if @display
|
|
else
|
|
result = 'TIMEOUT'
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
def commandstate
|
|
if ! @commandstate
|
|
@sp.break 10 # tenths of a second
|
|
@sp.puts '+++'
|
|
@sp.break 10 # tenths of a second
|
|
result = get_response(3)
|
|
if result != 'OK'
|
|
print( "Error switching to command state: FAILED\r\n" )
|
|
return false
|
|
else
|
|
@commandstate = true
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
def datastate
|
|
if @commandstate
|
|
result = put_command('ATO0', 3)
|
|
if result =~ /CONNECT/i
|
|
@commandstate = false
|
|
else
|
|
print( "Error switching to data state: FAILED\r\n" )
|
|
return false
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
def hangup
|
|
flush
|
|
if @commandstate == true
|
|
#print( "Hanging up... (commandstate ATH0)\r\n" )
|
|
result = put_command('ATH0', 3)
|
|
return true if result == 'OK' or result == 'NO CARRIER'
|
|
else
|
|
if @sp.respond_to?:dtr= # unsupported in windows ):
|
|
#print( "Hanging up... (DTR = 0)\r\n" )
|
|
@sp.dtr = 0
|
|
sleep 0.75
|
|
@sp.dtr = 1
|
|
result = get_response(3)
|
|
@commandstate = true if result == 'NO CARRIER'
|
|
return true
|
|
else
|
|
#print( "Hanging up... (datastate ATH0)\r\n" )
|
|
commandstate
|
|
result = put_command('ATH0', 3)
|
|
return true if result == 'OK'
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
# flush any stale data in the read buffer
|
|
def flush
|
|
@sp.read_timeout = -1
|
|
while @sp.getc; end
|
|
end
|
|
|
|
# TODO: convert all calls to Modem.params to Modem.modem_params and remove this def
|
|
def params=(params)
|
|
@sp.modem_params = params
|
|
end
|
|
|
|
end
|
|
|
|
end
|