binproxy 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|