File: mitm_server.rb

package info (click to toggle)
ruby-net-ssh 1%3A6.1.0-2%2Bdeb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,884 kB
  • sloc: ruby: 15,997; makefile: 4
file content (101 lines) | stat: -rw-r--r-- 2,354 bytes parent folder | download
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