binproxy 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/binproxy +135 -0
- data/lib/binproxy.rb +2 -0
- data/lib/binproxy/bd_util.rb +267 -0
- data/lib/binproxy/bindata.rb +44 -0
- data/lib/binproxy/class_loader.rb +64 -0
- data/lib/binproxy/connection.rb +105 -0
- data/lib/binproxy/connection/filters.rb +190 -0
- data/lib/binproxy/logger.rb +17 -0
- data/lib/binproxy/parser.rb +76 -0
- data/lib/binproxy/parsers/chat_demo.rb +14 -0
- data/lib/binproxy/parsers/dns.rb +70 -0
- data/lib/binproxy/parsers/dumb_http.rb +28 -0
- data/lib/binproxy/parsers/msgpack.rb +56 -0
- data/lib/binproxy/parsers/plain_text.rb +4 -0
- data/lib/binproxy/parsers/raw_message.rb +4 -0
- data/lib/binproxy/parsers/x11_proto.rb +134 -0
- data/lib/binproxy/parsers/zmq.rb +62 -0
- data/lib/binproxy/proxy.rb +242 -0
- data/lib/binproxy/proxy_event.rb +57 -0
- data/lib/binproxy/proxy_message.rb +191 -0
- data/lib/binproxy/session.rb +47 -0
- data/lib/binproxy/web_console.rb +194 -0
- data/public/bright_squares.png +0 -0
- data/public/ui/app.js +54910 -0
- data/public/ui/fixed-data-table.css +509 -0
- data/views/application.scss +335 -0
- data/views/common.scss +90 -0
- data/views/config.haml +54 -0
- data/views/config.scss +15 -0
- data/views/index.haml +15 -0
- metadata +325 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
class ChatDemo < BinData::Record
|
3
|
+
endian :little
|
4
|
+
uint32 :timestamp
|
5
|
+
string :user, length: 8, trim_padding: true
|
6
|
+
bit1 :emote_flag
|
7
|
+
bit1 :private_flag
|
8
|
+
string :recipient, length: 8, trim_padding: true, onlyif: :private_flag
|
9
|
+
stringz :message
|
10
|
+
|
11
|
+
def summary
|
12
|
+
"#{emote_flag ? 'emote' : 'message'} from #{user}"
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# DNS Parser for BinProxy
|
2
|
+
# use Dns::Packet class for UDP traffic, or Dns::TcpPacket for TCP.
|
3
|
+
|
4
|
+
require 'bindata'
|
5
|
+
require 'binproxy/bd_util'
|
6
|
+
|
7
|
+
module Dns
|
8
|
+
|
9
|
+
class Header < BinData::Record
|
10
|
+
endian :big
|
11
|
+
|
12
|
+
uint16 :id
|
13
|
+
bit1 :qr
|
14
|
+
bit4 :opcode
|
15
|
+
bit1 :aa
|
16
|
+
bit1 :tc
|
17
|
+
bit1 :rd
|
18
|
+
bit1 :ra
|
19
|
+
bit3 :z
|
20
|
+
bit4 :rcode
|
21
|
+
uint16 :qdcount
|
22
|
+
uint16 :ancount
|
23
|
+
uint16 :nscount
|
24
|
+
uint16 :arcount
|
25
|
+
end
|
26
|
+
|
27
|
+
class NameElement < BinData::Record; end
|
28
|
+
|
29
|
+
class NameSeq < BinData::Array
|
30
|
+
default_parameter read_until: lambda { element.flag != 0x0 or element.val == '' }
|
31
|
+
name_element
|
32
|
+
end
|
33
|
+
class NameElement < BinData::Record
|
34
|
+
bit2 :flag
|
35
|
+
choice :val, selection: :flag do
|
36
|
+
pascal_string 0x0, size_type: :bit6
|
37
|
+
pointer 0x3, ptr_type: :bit14, val_type: :name_seq, seek_offset: 2 #XXX
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class DnsRecord < BinData::Record
|
42
|
+
endian :big
|
43
|
+
name_seq :name
|
44
|
+
uint16 :type
|
45
|
+
uint16 :rclass
|
46
|
+
end
|
47
|
+
|
48
|
+
class Question < DnsRecord; end
|
49
|
+
|
50
|
+
class ResourceRecord < DnsRecord
|
51
|
+
uint32 :ttl
|
52
|
+
uint16 :rdlength
|
53
|
+
string :rdata, read_length: :rdlength
|
54
|
+
end
|
55
|
+
|
56
|
+
#XXX can't use Packet for UDP currently b/c of hardcoded 2 byte adjustment to pointers (due to length pre-header in TCP packets)
|
57
|
+
class Packet < BinData::Record
|
58
|
+
header :header
|
59
|
+
array :questions, type: :question, initial_length: lambda { header.qdcount }
|
60
|
+
array :answers, type: :resource_record, initial_length: lambda { header.ancount }
|
61
|
+
array :authorities, type: :resource_record, initial_length: lambda { header.nscount }
|
62
|
+
array :addl_records, type: :resource_record, initial_length: lambda { header.arcount }
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
class TcpPacket < BinData::Record
|
67
|
+
uint16be :len
|
68
|
+
packet :pkt
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# A stupid HTTP BinData class to demonstrate the proxy
|
2
|
+
require_relative '../bd_util'
|
3
|
+
|
4
|
+
module DumbHttp
|
5
|
+
class Headers < BinData::Array
|
6
|
+
default_parameter read_until: lambda { element == '' }
|
7
|
+
line line_end: "\r\n"
|
8
|
+
end
|
9
|
+
|
10
|
+
class BaseMessage < BinData::Record
|
11
|
+
headers :headers
|
12
|
+
|
13
|
+
def body_len
|
14
|
+
(headers.snapshot.grep(/\AContent-Length: (\d+)/) { $1.to_i }).first || 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def summary; headers.first.sub(/HTTP\/\d\.\d/,'').strip; end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Message < BaseMessage
|
21
|
+
string :body, display_as: 'multiline', onlyif: lambda { body_len > 0 }, length: :body_len
|
22
|
+
end
|
23
|
+
|
24
|
+
class BinMessage < BaseMessage
|
25
|
+
string :body, display_as: 'hexdump', onlyif: lambda { body_len > 0 }, length: :body_len
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
|
3
|
+
class MsgPack
|
4
|
+
class MpNil < BinData::Primitive
|
5
|
+
def get; nil; end
|
6
|
+
def set(v); raise unless v.nil? end;
|
7
|
+
end
|
8
|
+
class MpTrue < BinData::Primitive
|
9
|
+
def get; true; end
|
10
|
+
def set(v); raise unless v; end
|
11
|
+
end
|
12
|
+
class MpFalse < BinData::Primitive
|
13
|
+
def get; false; end
|
14
|
+
def set(v); raise unless !v; end
|
15
|
+
end
|
16
|
+
class
|
17
|
+
|
18
|
+
|
19
|
+
class TypedValue < BinData::Choice
|
20
|
+
positive_fixint :positive_fixint
|
21
|
+
fixmap :fixmap
|
22
|
+
fixarray :fixarray
|
23
|
+
fixstr :fixstr
|
24
|
+
mp_nil :nil
|
25
|
+
mp_true :true
|
26
|
+
mp_false :false
|
27
|
+
bin8 :bin8
|
28
|
+
end
|
29
|
+
|
30
|
+
uint8 :type_byte
|
31
|
+
typed_value :value, selection: lambda do
|
32
|
+
case type_byte
|
33
|
+
when 0..0x7f
|
34
|
+
:positive_fixint
|
35
|
+
when 0x80..0x8f
|
36
|
+
:fixmap
|
37
|
+
when 0x90..0x9f
|
38
|
+
:fixarray
|
39
|
+
when 0xa0..0xbf
|
40
|
+
:fixstr
|
41
|
+
when 0xc0
|
42
|
+
:nil
|
43
|
+
when 0xc1
|
44
|
+
:unused
|
45
|
+
when 0xc2
|
46
|
+
:true
|
47
|
+
when 0xc3
|
48
|
+
:false
|
49
|
+
when 0xc4
|
50
|
+
:bin8
|
51
|
+
else
|
52
|
+
raise 'todo'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'bindata'
|
2
|
+
|
3
|
+
module X11
|
4
|
+
end
|
5
|
+
|
6
|
+
class X11SetupReq < BinData::Record
|
7
|
+
endian :little #totally cheating here!
|
8
|
+
uint8 :byte_order
|
9
|
+
skip length: 1
|
10
|
+
uint16 :proto_major
|
11
|
+
uint16 :proto_minor
|
12
|
+
uint16 :auth_proto_name_len, value: lambda { auth_proto_name.length }
|
13
|
+
uint16 :auth_proto_data_len, value: lambda { auth_proto_data.length }
|
14
|
+
string :auth_proto_name, read_length: :auth_proto_name_len
|
15
|
+
skip length: lambda { (4 - (auth_proto_name_len % 4)) % 4 }
|
16
|
+
string :auth_proto_data, read_length: :auth_proto_data_len
|
17
|
+
skip length: lambda { (4 - (auth_proto_data_len % 4)) % 4 }
|
18
|
+
skip length: 2 #???
|
19
|
+
end
|
20
|
+
|
21
|
+
class X11StdReqBody < BinData::Record
|
22
|
+
endian :little
|
23
|
+
uint16 :req_len
|
24
|
+
string :data, read_length: lambda {(req_len - 1) * 4}
|
25
|
+
end
|
26
|
+
|
27
|
+
class X11ExtReqBody < BinData::Record
|
28
|
+
rest :data
|
29
|
+
end
|
30
|
+
|
31
|
+
class X11StdReq < BinData::Record
|
32
|
+
endian :little
|
33
|
+
uint8 :opcode
|
34
|
+
uint8 :subcode
|
35
|
+
choice :req_type, selection: lambda { opcode <= 128 } do
|
36
|
+
x11_std_req_body true
|
37
|
+
x11_ext_req_body false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class X11Req < BinData::Record
|
42
|
+
choice :msg2, display_as: 'anon', selection: lambda { current_state[:connected] } do
|
43
|
+
x11_setup_req false
|
44
|
+
x11_std_req true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class X11SetupRes < BinData::Record
|
49
|
+
endian :little #more cheating
|
50
|
+
uint8 :status
|
51
|
+
skip length: 1
|
52
|
+
uint16 :proto_major
|
53
|
+
uint16 :proto_minor
|
54
|
+
uint16 :addl_data_dwords
|
55
|
+
uint32 :release_num
|
56
|
+
uint32 :res_id_base, display_as: 'hex'
|
57
|
+
uint32 :res_id_mask, display_as: 'hex'
|
58
|
+
uint32 :motion_buffer_size
|
59
|
+
uint16 :vendor_len, value: lambda { vendor.length }
|
60
|
+
uint16 :max_req_len
|
61
|
+
uint8 :num_screens
|
62
|
+
uint8 :num_formats
|
63
|
+
uint8 :image_byte_order
|
64
|
+
uint8 :bitmap_bit_order
|
65
|
+
uint8 :bitmap_format_scanline_unit
|
66
|
+
uint8 :bitmap_format_scanlin_pad
|
67
|
+
uint8 :min_keycode
|
68
|
+
uint8 :max_keycode
|
69
|
+
skip length: 4
|
70
|
+
string :vendor, read_length: :vendor_len
|
71
|
+
string :vpad, read_length: lambda { (4 - ( vendor.length % 4 )) % 4 }
|
72
|
+
rest :listofformatandroots, display_as: 'hexdump'
|
73
|
+
end
|
74
|
+
|
75
|
+
class X11Reply < BinData::Record
|
76
|
+
endian :little
|
77
|
+
uint8 :detail
|
78
|
+
uint16 :seq_num
|
79
|
+
uint32 :extra_len
|
80
|
+
string :data, length: lambda { 24 + (4 * extra_len) }, display_as: 'hexdump'
|
81
|
+
end
|
82
|
+
|
83
|
+
class X11Event < BinData::Record
|
84
|
+
endian :little
|
85
|
+
uint8 :detail
|
86
|
+
string :data, length: 30, display_as: 'hexdump'
|
87
|
+
end
|
88
|
+
|
89
|
+
class X11Error < BinData::Record
|
90
|
+
endian :little
|
91
|
+
uint8 :detail
|
92
|
+
string :data, length: 30, display_as: 'hexdump'
|
93
|
+
end
|
94
|
+
|
95
|
+
class X11StdRes < BinData::Record
|
96
|
+
endian :little
|
97
|
+
uint8 :res_type
|
98
|
+
choice :res_detail, selection: :res_type do
|
99
|
+
x11_error 0
|
100
|
+
x11_reply 1
|
101
|
+
x11_event :default
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
class X11Res < BinData::Record
|
107
|
+
choice :msg2, display_as: 'anon', selection: lambda { current_state[:connected] } do
|
108
|
+
x11_setup_res false
|
109
|
+
x11_std_res true
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class X11Proto < BinData::Record
|
114
|
+
def self.initial_state; { connected: false, endian: nil }; end
|
115
|
+
|
116
|
+
#XXX wrap this in something that dups the current state so we're unable to mutate it by accident
|
117
|
+
def update_state
|
118
|
+
c = current_state.dup
|
119
|
+
if eval_parameter(:src) == 'server' #hack, assume we're connected after 1st c-s-c exchange
|
120
|
+
c[:connected] = true
|
121
|
+
end
|
122
|
+
c
|
123
|
+
end
|
124
|
+
|
125
|
+
def summary
|
126
|
+
msg.msg2.summary
|
127
|
+
end
|
128
|
+
|
129
|
+
choice :msg, selection: :src, display_as: 'anon' do
|
130
|
+
x11_req 'client'
|
131
|
+
x11_res 'server'
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# ZeroMQ (ZMTPv3) Parser for BinProxy
|
2
|
+
|
3
|
+
module ZMQ
|
4
|
+
# this greeting1/2/3 business is due to the fact that
|
5
|
+
# zmq sends the greeting in parts and waits for the reply
|
6
|
+
# from the other endpoint in order to do version detection.
|
7
|
+
class Greeting1 < BinData::Record
|
8
|
+
uint8 :sig_start, asserted_value: 0xFF
|
9
|
+
string :sig_padding, length: 8
|
10
|
+
uint8 :sig_end, asserted_value: 0x7F
|
11
|
+
end
|
12
|
+
|
13
|
+
class Greeting2 < BinData::Record
|
14
|
+
uint8 :version_major, asserted_value: 0x03
|
15
|
+
end
|
16
|
+
|
17
|
+
class Greeting3 < BinData::Record
|
18
|
+
uint8 :version_minor, asserted_value: 0x00
|
19
|
+
|
20
|
+
string :mechanism, length: 20
|
21
|
+
|
22
|
+
uint8 :as_server
|
23
|
+
|
24
|
+
string :filler, length: 31 #pad to 64 bytes
|
25
|
+
end
|
26
|
+
|
27
|
+
class Frame < BinData::Record
|
28
|
+
bit5 :reserved
|
29
|
+
bit1 :is_command
|
30
|
+
bit1 :is_long
|
31
|
+
bit1 :has_more
|
32
|
+
choice :body_size, selection: :is_long, display_as: 'anon' do
|
33
|
+
uint8 0
|
34
|
+
uint64be 1
|
35
|
+
end
|
36
|
+
string :body, read_length: :body_size
|
37
|
+
end
|
38
|
+
|
39
|
+
class Message < BinData::Record
|
40
|
+
# States are (G)reeting 1/2/3 (see above), (H)andshake, and (T)raffic.
|
41
|
+
def next_state(s); {'G1'=>'G2','G2'=>'G3','G3'=>'H', 'H'=>'T', 'T'=>'T'}[s]; end
|
42
|
+
def self.initial_state; {'client'=>'G1','server'=>'G1'}; end
|
43
|
+
|
44
|
+
# Protocol is symmetrical. Each endpoint has its own state.
|
45
|
+
# This is a bit clunky and maybe should be abstracted into a module?
|
46
|
+
# Or update parser.rb to differentiate between proto-shared and endpoint-separate state?
|
47
|
+
def update_state
|
48
|
+
current_state.dup.tap do |s|
|
49
|
+
src = eval_parameter :src
|
50
|
+
s[src] = next_state s[src]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
choice :msg_type, selection: lambda { current_state[eval_parameter(:src) ] }, display_as: 'anon' do
|
55
|
+
greeting1 'G1'
|
56
|
+
greeting2 'G2'
|
57
|
+
greeting3 'G3'
|
58
|
+
frame 'H' #contains a command w/ arbitrary content
|
59
|
+
frame 'T' #can contain command or message
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,242 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'observer'
|
3
|
+
require 'bindata'
|
4
|
+
require 'active_support/core_ext/object/blank'
|
5
|
+
require_relative 'bindata'
|
6
|
+
require_relative 'connection'
|
7
|
+
require_relative 'session'
|
8
|
+
require_relative 'parser'
|
9
|
+
require_relative 'logger'
|
10
|
+
|
11
|
+
module BinProxy
|
12
|
+
class Proxy
|
13
|
+
include BinProxy::Logger
|
14
|
+
include Observable
|
15
|
+
attr_accessor :hold
|
16
|
+
attr_reader :sessions
|
17
|
+
attr_reader :buffer
|
18
|
+
|
19
|
+
def initialize(root, opts)
|
20
|
+
@class_loader = BinProxy::ClassLoader.new(root)
|
21
|
+
@options = {}
|
22
|
+
@sessions = []
|
23
|
+
@buffer = []
|
24
|
+
@filter_pids = []
|
25
|
+
configure(opts)
|
26
|
+
end
|
27
|
+
|
28
|
+
def configure(new_opts = {})
|
29
|
+
old_opts = @options.dup
|
30
|
+
new_opts = old_opts.merge new_opts
|
31
|
+
|
32
|
+
@hold = !! new_opts[:hold];
|
33
|
+
@inbound_filters = []
|
34
|
+
@upstream_filters = []
|
35
|
+
|
36
|
+
if new_opts[:socks_proxy]
|
37
|
+
@inbound_filters << BinProxy::Connection::Filters::Socks
|
38
|
+
elsif new_opts[:http_proxy]
|
39
|
+
@inbound_filters << BinProxy::Connection::Filters::HTTPConnect
|
40
|
+
else
|
41
|
+
@inbound_filters << BinProxy::Connection::Filters::StaticUpstream
|
42
|
+
end
|
43
|
+
|
44
|
+
if new_opts[:tls]
|
45
|
+
@inbound_filters << BinProxy::Connection::Filters::InboundTLS
|
46
|
+
@upstream_filters << BinProxy::Connection::Filters::UpstreamTLS
|
47
|
+
end
|
48
|
+
|
49
|
+
if new_opts[:debug_extra]
|
50
|
+
@inbound_filters << BinProxy::Connection::Filters::Logger
|
51
|
+
@upstream_filters << BinProxy::Connection::Filters::Logger
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
#XXX this reloads the class on every config change
|
57
|
+
#XXX bad, but reloading in web console relies on it
|
58
|
+
new_opts[:class] = @class_loader.load_class(new_opts[:class_name],new_opts[:class_file])
|
59
|
+
if old_opts[:class] != new_opts[:class]
|
60
|
+
@parser_class = Parser.subclass(self, new_opts[:class])
|
61
|
+
@parser_class.validate = new_opts[:validate_parser]
|
62
|
+
elsif new_opts[:class] == nil
|
63
|
+
raise "Option :class must be specified"
|
64
|
+
end
|
65
|
+
|
66
|
+
[:lhost, :lport, :dhost, :dport].each do |o|
|
67
|
+
# let people get away with it if it's already blank
|
68
|
+
if old_opts[o].present? and new_opts[o].blank?
|
69
|
+
raise "Option :#{o} must be specified"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# This will not handle an exception if the server is started asynchronously, but
|
74
|
+
# the only time that should happen is the initial configuration from command line args,
|
75
|
+
# in which case we don't have existing opts to revert to anyway.
|
76
|
+
begin
|
77
|
+
@options = new_opts
|
78
|
+
if old_opts[:lhost] != new_opts[:lhost] or old_opts[:lport] != new_opts[:lport]
|
79
|
+
restart_server!
|
80
|
+
end
|
81
|
+
rescue Exception => e
|
82
|
+
@options = old_opts
|
83
|
+
raise e
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# XXX below is incorrect, we do call it on first configuration
|
88
|
+
# We'll only call this internally if the server's host or port has changed; there's still the possiblility
|
89
|
+
# that a quick a->b->a change, or manually calling this could fail because the OS hasn't released the port yet;
|
90
|
+
# we'll punt on that for now, though.
|
91
|
+
def restart_server!
|
92
|
+
if stop_server!
|
93
|
+
#server was indeed running
|
94
|
+
# TODO investigate whether this is actually necessary, or could be reduced/removed
|
95
|
+
sleep 5
|
96
|
+
end
|
97
|
+
start_server!
|
98
|
+
end
|
99
|
+
|
100
|
+
def start_server!
|
101
|
+
if EM.reactor_running?
|
102
|
+
# Prefer to do this synchronously, so we can catch errors.
|
103
|
+
start_server_now!
|
104
|
+
else
|
105
|
+
# Have to defer this until Sinatra/Thin starts EM running.
|
106
|
+
EM.next_tick { start_server_now! }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def stop_server!
|
111
|
+
if @server_id
|
112
|
+
@filter_pids.each do |pid|
|
113
|
+
log.debug "Killing #{pid}"
|
114
|
+
Process.kill "INT", pid #TODO invstigate ncat signal handling
|
115
|
+
end
|
116
|
+
@filter_pids = [];
|
117
|
+
Process.waitall
|
118
|
+
EM.stop_server @server_id
|
119
|
+
@server_id = nil
|
120
|
+
true
|
121
|
+
else
|
122
|
+
false
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def status
|
127
|
+
@server_id.nil? ? 'stopped' : 'running'
|
128
|
+
end
|
129
|
+
|
130
|
+
def history_size
|
131
|
+
@buffer.length
|
132
|
+
end
|
133
|
+
|
134
|
+
def message_received(message)
|
135
|
+
log.debug "proxy handling message_received"
|
136
|
+
message.id = @buffer.length
|
137
|
+
@buffer.push(message)
|
138
|
+
|
139
|
+
if hold
|
140
|
+
message.disposition = 'Held'
|
141
|
+
else
|
142
|
+
send_message(message, :auto)
|
143
|
+
end
|
144
|
+
|
145
|
+
changed
|
146
|
+
notify_observers(:message_received, message)
|
147
|
+
end
|
148
|
+
|
149
|
+
def update_message_from_hash(hash)
|
150
|
+
log.debug "updating message from hash"
|
151
|
+
orig = @buffer[hash[:head][:message_id]]
|
152
|
+
orig.update!(hash[:body][:snapshot])
|
153
|
+
orig
|
154
|
+
rescue Exception => e
|
155
|
+
puts '', e.class, e.message, e.backtrace, ''
|
156
|
+
on_bindata_error('deserialization', e)
|
157
|
+
end
|
158
|
+
|
159
|
+
def send_message(message, reason)
|
160
|
+
log.debug "proxy.send_message #{message.inspect}"
|
161
|
+
message.forward!(reason)
|
162
|
+
rescue Exception => e
|
163
|
+
puts '', e.class, e.message, e.backtrace, ''
|
164
|
+
on_bindata_error('forwarding', e)
|
165
|
+
end
|
166
|
+
|
167
|
+
def drop_message(message, reason)
|
168
|
+
log.debug "proxy.drop_message #{message.inspect}"
|
169
|
+
message.drop!(reason)
|
170
|
+
rescue Exception => e
|
171
|
+
puts '', e.class, e.message, e.backtrace, ''
|
172
|
+
on_bindata_error('dropping', e)
|
173
|
+
end
|
174
|
+
|
175
|
+
def session_closed(session, closing_peer, reason)
|
176
|
+
pe = BinProxy::ProxyEvent.new("Connection closed (#{reason||'no error'})")
|
177
|
+
pe.id = @buffer.length
|
178
|
+
pe.src = closing_peer
|
179
|
+
pe.session = session
|
180
|
+
@buffer.push(pe)
|
181
|
+
|
182
|
+
session.delete_observer(self)
|
183
|
+
changed
|
184
|
+
notify_observers(:session_event, pe)
|
185
|
+
end
|
186
|
+
|
187
|
+
def ssl_handshake_completed(session, peer)
|
188
|
+
changed
|
189
|
+
notify_observers(:ssl_handshake_completed, session, peer)
|
190
|
+
end
|
191
|
+
|
192
|
+
def on_bindata_error(operation, err)
|
193
|
+
changed
|
194
|
+
notify_observers(:bindata_error, operation, err)
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
def create_session(inbound_conn, upstream_conn)
|
199
|
+
id = @sessions.length
|
200
|
+
session = Session.new(id, inbound_conn, upstream_conn, @parser_class)
|
201
|
+
session.add_observer(self, :send)
|
202
|
+
@sessions << session
|
203
|
+
|
204
|
+
pe = BinProxy::ProxyEvent.new "Connection opened"
|
205
|
+
pe.id = @buffer.length
|
206
|
+
pe.src = :client
|
207
|
+
pe.session = session
|
208
|
+
@buffer.push(pe)
|
209
|
+
|
210
|
+
changed
|
211
|
+
notify_observers(:session_event, pe)
|
212
|
+
rescue Exception => e
|
213
|
+
puts e, e.backtrace
|
214
|
+
end
|
215
|
+
|
216
|
+
def start_server_now!
|
217
|
+
lhost = @options[:lhost]
|
218
|
+
lport = @options[:lport].to_i #force port to_i, or EM may assume different method signature
|
219
|
+
|
220
|
+
#These may be nil and are ignored in socks mode
|
221
|
+
dhost = @options[:dhost]
|
222
|
+
dport = @options[:dport].to_i
|
223
|
+
|
224
|
+
log.info "(re)starting proxy on #{lhost}:#{lport}"
|
225
|
+
upstream_args = {
|
226
|
+
peer: :server,
|
227
|
+
filter_classes: @upstream_filters
|
228
|
+
}
|
229
|
+
inbound_args = {
|
230
|
+
peer: :client,
|
231
|
+
session_callback: self.method(:create_session),
|
232
|
+
tls_args: { cert_chain_file: @options[:tls_cert], private_key_file: @options[:tls_key] },
|
233
|
+
filter_classes: @inbound_filters,
|
234
|
+
upstream_host: dhost,
|
235
|
+
upstream_port: dport,
|
236
|
+
upstream_args: upstream_args
|
237
|
+
}
|
238
|
+
@server_id = EM.start_server(lhost, lport, Connection, inbound_args)
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
end
|