Class: BinProxy::Proxy

Inherits:
Object
  • Object
show all
Includes:
Logger, Observable
Defined in:
lib/binproxy/proxy.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Logger

log

Constructor Details

#initialize(root, opts) ⇒ Proxy

Returns a new instance of Proxy.



19
20
21
22
23
24
25
26
# File 'lib/binproxy/proxy.rb', line 19

def initialize(root, opts)
  @class_loader = BinProxy::ClassLoader.new(root)
  @options = {}
  @sessions = []
  @buffer = []
  @filter_pids = []
  configure(opts)
end

Instance Attribute Details

#bufferObject (readonly)

Returns the value of attribute buffer.



17
18
19
# File 'lib/binproxy/proxy.rb', line 17

def buffer
  @buffer
end

#holdObject

Returns the value of attribute hold.



15
16
17
# File 'lib/binproxy/proxy.rb', line 15

def hold
  @hold
end

#sessionsObject (readonly)

Returns the value of attribute sessions.



16
17
18
# File 'lib/binproxy/proxy.rb', line 16

def sessions
  @sessions
end

Instance Method Details

#configure(new_opts = {}) ⇒ Object



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
# File 'lib/binproxy/proxy.rb', line 28

def configure(new_opts = {})
  old_opts = @options.dup
  new_opts = old_opts.merge new_opts

  @hold = !! new_opts[:hold];
  @inbound_filters = []
  @upstream_filters = []

  if new_opts[:socks_proxy]
    @inbound_filters << BinProxy::Connection::Filters::Socks
  elsif new_opts[:http_proxy]
    @inbound_filters << BinProxy::Connection::Filters::HTTPConnect
  else
    @inbound_filters << BinProxy::Connection::Filters::StaticUpstream
  end

  if new_opts[:tls]
    @inbound_filters << BinProxy::Connection::Filters::InboundTLS
    @upstream_filters << BinProxy::Connection::Filters::UpstreamTLS
  end

  if new_opts[:debug_extra]
    @inbound_filters << BinProxy::Connection::Filters::Logger
    @upstream_filters << BinProxy::Connection::Filters::Logger
  end



  #XXX this reloads the class on every config change
  #XXX bad, but reloading in web console relies on it
  new_opts[:class] = @class_loader.load_class(new_opts[:class_name],new_opts[:class_file])
  if old_opts[:class] != new_opts[:class]
    @parser_class = Parser.subclass(self, new_opts[:class])
    @parser_class.validate = new_opts[:validate_parser]
  elsif new_opts[:class] == nil
    raise "Option :class must be specified"
  end

  [:lhost, :lport, :dhost, :dport].each do |o|
    # let people get away with it if it's already blank
    if old_opts[o].present? and new_opts[o].blank?
      raise "Option :#{o} must be specified"
    end
  end

  # This will not handle an exception if the server is started asynchronously, but
  # the only time that should happen is the initial configuration from command line args,
  # in which case we don't have existing opts to revert to anyway.
  begin
    @options = new_opts
    if old_opts[:lhost] != new_opts[:lhost] or old_opts[:lport] != new_opts[:lport]
      restart_server!
    end
  rescue Exception => e
    @options = old_opts
    raise e
  end
end

#drop_message(message, reason) ⇒ Object



167
168
169
170
171
172
173
# File 'lib/binproxy/proxy.rb', line 167

def drop_message(message, reason)
  log.debug "proxy.drop_message #{message.inspect}"
  message.drop!(reason)
rescue Exception => e
  puts '', e.class, e.message, e.backtrace, ''
  on_bindata_error('dropping', e)
end

#history_sizeObject



130
131
132
# File 'lib/binproxy/proxy.rb', line 130

def history_size
  @buffer.length
end

#message_received(message) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/binproxy/proxy.rb', line 134

def message_received(message)
  log.debug "proxy handling message_received"
  message.id = @buffer.length
  @buffer.push(message)

  if hold
    message.disposition = 'Held'
  else
    send_message(message, :auto)
  end

  changed
  notify_observers(:message_received, message)
end

#on_bindata_error(operation, err) ⇒ Object



192
193
194
195
# File 'lib/binproxy/proxy.rb', line 192

def on_bindata_error(operation, err)
  changed
  notify_observers(:bindata_error, operation, err)
end

#restart_server!Object

XXX below is incorrect, we do call it on first configuration We’ll only call this internally if the server’s host or port has changed; there’s still the possiblility that a quick a->b->a change, or manually calling this could fail because the OS hasn’t released the port yet; we’ll punt on that for now, though.



91
92
93
94
95
96
97
98
# File 'lib/binproxy/proxy.rb', line 91

def restart_server!
  if stop_server!
    #server was indeed running
    #  TODO investigate whether this is actually necessary, or could be reduced/removed
    sleep 5
  end
  start_server!
end

#send_message(message, reason) ⇒ Object



159
160
161
162
163
164
165
# File 'lib/binproxy/proxy.rb', line 159

def send_message(message, reason)
  log.debug "proxy.send_message #{message.inspect}"
  message.forward!(reason)
rescue Exception => e
  puts '', e.class, e.message, e.backtrace, ''
  on_bindata_error('forwarding', e)
end

#session_closed(session, closing_peer, reason) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
# File 'lib/binproxy/proxy.rb', line 175

def session_closed(session, closing_peer, reason)
  pe = BinProxy::ProxyEvent.new("Connection closed (#{reason||'no error'})")
  pe.id = @buffer.length
  pe.src = closing_peer
  pe.session = session
  @buffer.push(pe)

  session.delete_observer(self)
  changed
  notify_observers(:session_event, pe)
end

#ssl_handshake_completed(session, peer) ⇒ Object



187
188
189
190
# File 'lib/binproxy/proxy.rb', line 187

def ssl_handshake_completed(session, peer)
  changed
  notify_observers(:ssl_handshake_completed, session, peer)
end

#start_server!Object



100
101
102
103
104
105
106
107
108
# File 'lib/binproxy/proxy.rb', line 100

def start_server!
  if EM.reactor_running?
    # Prefer to do this synchronously, so we can catch errors.
    start_server_now!
  else
    # Have to defer this until Sinatra/Thin starts EM running.
    EM.next_tick { start_server_now! }
  end
end

#statusObject



126
127
128
# File 'lib/binproxy/proxy.rb', line 126

def status
  @server_id.nil? ? 'stopped' : 'running'
end

#stop_server!Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/binproxy/proxy.rb', line 110

def stop_server!
  if @server_id
    @filter_pids.each do |pid|
      log.debug "Killing #{pid}"
      Process.kill "INT", pid  #TODO invstigate ncat signal handling
    end
    @filter_pids = [];
    Process.waitall
    EM.stop_server @server_id
    @server_id = nil
    true
  else
    false
  end
end

#update_message_from_hash(hash) ⇒ Object



149
150
151
152
153
154
155
156
157
# File 'lib/binproxy/proxy.rb', line 149

def update_message_from_hash(hash)
  log.debug "updating message from hash"
  orig = @buffer[hash[:head][:message_id]]
  orig.update!(hash[:body][:snapshot])
  orig
rescue Exception => e
  puts '', e.class, e.message, e.backtrace, ''
  on_bindata_error('deserialization', e)
end