1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
# Simple Man in the middle server
#
# server = MitmServer.new('localhost', 22)
# Net.SSH.start('localhost', ENV['USER'], port: server.port)
# server.run
class MitmServer < TCPServer
attr_accessor :local_read_size
attr_accessor :target_read_size
def initialize(remote_host = 'localhost', remote_port = 22)
@remote_host = remote_host
@remote_port = remote_port
@server = TCPServer.open(0)
@local_read_size = 2048
@target_read_size = 2048
end
def port
@server.addr[1]
end
def host
'localhost'
end
def run
start(@server, @remote_host, @remote_port)
end
private
def start_server(server, &block)
server ||= TCPServer.open(0)
Thread.start do
loop do
Thread.start(server.accept) do |client|
yield(client)
end
end
end
return server
end
def dlog(message); end
def start(server, remote_host, remote_port)
err = nil
server = start_server(server) do |local|
remote = TCPSocket.new(remote_host, remote_port)
loop do
r,_w,_e = IO.select([local, remote],nil,nil)
if r.include? local
begin
data = local.recv local_read_size
rescue StandardError => e
data = nil
dlog "Local closed: #{e}"
break
end
if data.empty?
dlog "Local closed: #{data.inspect}"
break
end
dlog "Forwarding: #{data.length} to remote"
begin
remote.write data
rescue StandardError => e
dlog "remote closed: #{e}"
break
end
end
if r.include? remote # rubocop:disable Style/Next
begin
data = remote.recv target_read_size
rescue StandardError => e
dlog "remote closed: #{e}"
break
end
if data.nil? || data.empty?
dlog "Remote closed: #{data.inspect} #{err.inspect}"
break
end
dlog "Forwarding: #{data.length} to local"
begin
local.write data
rescue StandardError => e
dlog "local closed: #{e}"
break
end
end
end
dlog "Closing..."
local.close
remote.close
end
@server = server
return server
end
end
|