r_socks 0.1.8 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83fd1b16e6fe57dd2c8370023d0b2d2540fd472d871d304b14efb8cdef31db23
4
- data.tar.gz: 617ab279bbb464955f8453dda146b8ea6d3e5b668232ebae316ce95c51487b74
3
+ metadata.gz: 8aeaa60ff88cdf8c84892a5c95c9613d1bc8726fdaf3a5e8d113eeb47f6fb77a
4
+ data.tar.gz: 84ec2ec281d97bf06bfd3838131cb35c11869f85361157088e593f2be03c78cb
5
5
  SHA512:
6
- metadata.gz: d9c5c5edf153de04d45bc21237b0c0d2a61c6b071d23daaaaad3eafb7668f0f15e77d268e249abfede7584e31fc685c1b3fecaad983cd215695df9a1d811d4a9
7
- data.tar.gz: cb28113a10dfd13bb5597bd013bbb6b1a7c2570d6385c1aa60209d84a243147a1674106841dfed5df28435f0e7a9adcd76dba1a221036e442c9863a1d198fae3
6
+ metadata.gz: 0b2c40a1456321518b5ce51918f34046ddb3f06056b634b08a026bd95cb231fe221c443848bf1dfd4c6d8add73363afcb47864c7de251c42786ce7778d08876e
7
+ data.tar.gz: 96df7a1ac2898bf062a8801b49570d351d5110946f309e8c3e74185e3e3f303f3b981d3781127f13971a6cd8a4f76c4dc6f0191c8fcd23f2e33f57cf42c68981
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- r_socks (0.1.7)
4
+ r_socks (0.2.0)
5
5
  eventmachine (~> 1.2, >= 1.2.7)
6
6
 
7
7
  GEM
@@ -5,7 +5,7 @@ module RSocks
5
5
  def initialize(adaptor = nil)
6
6
  @default_user = ENV['RSOCKS_USER'] || 'default'
7
7
  @default_password = ENV['RSOCKS_PASSWORD'] || 'default'
8
- @adaptor = nil
8
+ @adaptor = adaptor
9
9
  end
10
10
 
11
11
  def auth!(data)
@@ -14,17 +14,29 @@ module RSocks
14
14
 
15
15
  def auth_method=(method)
16
16
  if method == :no_auth
17
- @store[:auth_method] = RSocks::NO_AUTH
17
+ @store[:auth_method] = :no_auth
18
18
  elsif method == :password
19
- @store[:auth_method] = RSocks::PASSWORD_LOGIN
20
-
19
+ @store[:auth_method] = :password
21
20
  else
22
21
  raise Error, "unknown auth method #{method}"
23
22
  end
24
23
  end
25
24
 
26
25
  def auth_method
27
- @store[:auth_method]
26
+ @store[:auth_method] || :password
27
+ end
28
+
29
+ def proxy_type=(type)
30
+ if type == :http
31
+ @store[:proxy_type] = :http
32
+
33
+ elsif type == :socks5
34
+ @store[:proxy_type] = :socks5
35
+ end
36
+ end
37
+
38
+ def proxy_type
39
+ @store[:proxy_type] || :socks5
28
40
  end
29
41
 
30
42
  def proxy_buffer_size
@@ -1,12 +1,10 @@
1
1
  require 'socket'
2
2
  require 'eventmachine'
3
3
  require 'socket'
4
- require 'ipaddr'
5
- require 'r_socks/errors'
6
- require 'r_socks/socks5_bit_codes'
7
- require 'r_socks/state_machine'
4
+ require 'r_socks/http_proxy_response_codes'
5
+ require 'r_socks/http_proxy_parser'
8
6
  require 'r_socks/target_connection_handler'
9
- require 'r_socks/authenticator'
7
+ require 'r_socks/socks5_proxy_parser'
10
8
 
11
9
  module RSocks
12
10
 
@@ -15,10 +13,8 @@ module RSocks
15
13
  def initialize(config, *args)
16
14
  super(*args)
17
15
  @state_machine = RSocks::StateMachine.new
18
- @original_addr = nil
19
- @original_port = nil
20
- @authenticator = RSocks::Authenticator.new(config.auth_adaptor)
21
16
  @config = config
17
+ @parser = create_proxy_parser
22
18
  end
23
19
 
24
20
  def post_init
@@ -29,39 +25,29 @@ module RSocks
29
25
  close_connection
30
26
  end
31
27
  end
32
- # sample \x05\x01\x00\x03\ngoogle.com\x00P
33
28
 
34
29
  def receive_data(data)
35
30
 
36
31
  return send_data(not_accept) if data.nil? || data == ''
37
32
 
38
33
  begin
39
-
40
- if @state_machine.handshake?
41
- return init_handshake(data)
42
- end
43
-
44
- if @state_machine.auth?
45
- passed = @authenticator.auth!(data)
46
- if passed
47
- send_data(RSocks::SUCCESS_RESPONSE)
48
- @state_machine.connect!
49
- return
50
- end
51
-
34
+ begin
35
+ @addr, @port = @parser.call(data)
36
+ rescue RSocks::HttpAuthFailed, RSocks::HttpNotSupport
37
+ send_data(RSocks::HttpProxyResponseCodes::FAILED_AUTH)
38
+ close_connection_after_writing
39
+ rescue RSocks::NotSupport
52
40
  send_data(RSocks::FAILED_RESPONSE)
53
- return
54
- end
55
-
56
- if @state_machine.connect?
57
- connect_request(data)
58
- return
41
+ close_connection_after_writing
59
42
  end
60
43
 
61
- return send_data(not_accept) unless @state_machine.start?
44
+ return unless @state_machine.start?
62
45
 
63
46
  if @target.nil?
64
- @target = EventMachine.connect(@addr, @port, RSocks::TargetConnectionHandler, self, @config, data)
47
+ @target = EventMachine.connect(@addr, @port, RSocks::TargetConnectionHandler, self, @config)
48
+ if @config.proxy_type == :http
49
+ send_data(RSocks::HttpProxyResponseCodes::SUCCESS)
50
+ end
65
51
  end
66
52
 
67
53
  proxy_incoming_to(@target, @config.proxy_buffer_size)
@@ -82,116 +68,14 @@ module RSocks
82
68
 
83
69
  private
84
70
 
85
- def init_handshake(data)
86
-
87
- version, num = data.unpack('CC')
88
-
89
- if version != RSocks::VERSION || num <= 0
90
- send_data(not_accept)
91
- close_connection
92
- end
93
-
94
- position = 'C' * num
95
-
96
- methods = data[2..-1].unpack(position)
97
-
98
- data = nil
99
-
100
- auth_method = @config.auth_method || RSocks::NO_AUTH
101
-
102
- if methods.include?(auth_method)
103
-
104
- if auth_method == RSocks::NO_AUTH
105
- @state_machine.connect!
106
- elsif auth_method == RSocks::PASSWORD_LOGIN
107
- @state_machine.auth!
108
- end
109
-
110
- data = [RSocks::VERSION, auth_method].pack('CC')
111
- end
112
-
113
- if data.nil?
114
- send_data(not_accept)
115
- close_connection
116
- end
117
-
118
- send_data(data)
119
- end
120
-
121
- def connect_request(data)
122
- version, cmd = data.unpack('CC')
123
- return not_accept if version != RSocks::VERSION
124
-
125
- begin
126
- @addr, @port, @type = check_sock_cmd(cmd, data[2..-1])
127
- rescue
128
- send_data([RSocks::VERSION,RSocks::CONNECT_FAIL].pack('CC'))
129
- return close_connection
71
+ def create_proxy_parser
72
+ if @config.proxy_type == :http
73
+ return RSocks::HttpProxyParser.new(@state_machine, @config)
130
74
  end
131
75
 
132
- @state_machine.start!
133
-
134
- send_data([RSocks::VERSION, RSocks::CONNECT_SUCCESS].
135
- pack('CC') + pack_address_and_port_info(@type))
136
- end
137
-
138
- def check_sock_cmd(cmd, data)
139
- raise RSocks::NotSupport unless cmd == RSocks::CMD_CONNECT
140
-
141
- _, addr_type = data.unpack('CC')
142
-
143
- address = nil
144
- port = nil
145
- type = nil
146
-
147
- if addr_type == RSocks::ADDR_IPV4
148
- type = RSocks::ADDR_IPV4
149
- address, port = parse_address_port(data[2..-1], 4, type)
150
- elsif addr_type == RSocks::ADDR_IPV6
151
- type = RSocks::ADDR_IPV6
152
- address, port = parse_address_port(data[2..-1], 16, type)
153
- elsif addr_type == RSocks::ADDR_DOMAIN
154
- type = RSocks::ADDR_DOMAIN
155
- padding = data[2].unpack('C')[0]
156
- address, port = parse_address_port(data[3..-1], padding, type)
76
+ if @config.proxy_type == :socks5
77
+ return RSocks::Socks5ProxyParser.new(@state_machine, @config, self)
157
78
  end
158
-
159
- [address, port, type]
160
- end
161
-
162
- def not_accept
163
- [RSocks::VERSION, RSocks::NOT_ACCEPT].pack('CC')
164
- end
165
-
166
- def parse_address_port(data, padding, type)
167
- address = data[0...padding]
168
- port_start = padding
169
-
170
- @original_port = data[port_start..-1]
171
- @original_addr = address
172
-
173
- temp = @original_port.unpack('CC')
174
-
175
- port = (temp[0] << 8) | temp[1]
176
-
177
- addr_str = if type == RSocks::ADDR_DOMAIN
178
- address
179
- else
180
- IPAddr.ntop(address)
181
- end
182
-
183
- [addr_str, port]
184
- end
185
-
186
- def pack_address_and_port_info(type)
187
- addr = @original_addr
188
- if type == RSocks::ADDR_DOMAIN
189
- domain_size = [addr.size].pack('C')
190
- addr = domain_size + @original_addr
191
- end
192
-
193
- temp = [RSocks::KEEP_ONE_BIT, type]
194
- temp.pack('C' * temp.size) + addr + @original_port
195
79
  end
196
80
 
197
81
  end
@@ -1,4 +1,6 @@
1
1
  module RSocks
2
2
  class Error < StandardError; end
3
3
  class NotSupport < Error; end
4
+ class HttpNotSupport < Error; end
5
+ class HttpAuthFailed < Error; end
4
6
  end
@@ -0,0 +1,76 @@
1
+ require 'base64'
2
+
3
+ module RSocks
4
+ class HttpProxyParser
5
+
6
+ def initialize(state_machine, config)
7
+ @state_machine = state_machine
8
+ @auth_method = config.auth_method
9
+ @default_user = ENV['RSOCKS_USER'] || 'default'
10
+ @default_password = ENV['RSOCKS_PASSWORD'] || 'default'
11
+ @adaptor = config.auth_adaptor
12
+ end
13
+
14
+ def call(data)
15
+ parser_connect_http(data)
16
+ @state_machine.start!
17
+ [@schema_parse.host, @schema_parse.port]
18
+ end
19
+
20
+ private
21
+
22
+ def parser_connect_http(data)
23
+ temp = data.split("\r\n")
24
+ host_format_checking(temp.shift)
25
+ generate_header(temp)
26
+
27
+ state = auth_user
28
+ raise RSocks::HttpAuthFailed unless state
29
+ state
30
+ end
31
+
32
+ def auth_user
33
+ temp = @header['Proxy-Authorization']
34
+ pattern = /^Basic /
35
+ token = temp.gsub(pattern, '')
36
+ begin
37
+ str = Base64.decode64(token)
38
+ @user, @password = str.split(':')
39
+ rescue
40
+ raise RSocks::HttpNotSupport, "token parse failed #{token}"
41
+ end
42
+
43
+ if @adaptor
44
+ return @adaptor.call(@user, @password)
45
+ else
46
+ return @password == @default_password && @user == @default_user
47
+ end
48
+ end
49
+
50
+ def host_format_checking(data)
51
+ temp = data.split("\s")
52
+ raise RSocks::HttpNotSupport if temp[0] != 'CONNECT'
53
+ @schema_parse = URI("tcp://#{temp[1]}/")
54
+ end
55
+
56
+ def generate_header(arr)
57
+ header = {}
58
+ arr.each do |val|
59
+ name, value = val.split(':')
60
+ next if name.nil?
61
+ header[name.strip] = value&.strip
62
+ end
63
+ @header = header
64
+ end
65
+ end
66
+ end
67
+
68
+ # state_machine = RSocks::StateMachine.new
69
+ # a = RSocks::HttpProxyParser.new(state_machine, RSocks::Config.new)
70
+ #
71
+ # data = "CONNECT www.google.com.sg:80 HTTP/1.1\r\nHost: www.google.com.sg:80\r\nUser-Agent: Surge macOS/939\r\nConnection: keep-alive\r\nProxy-Connection: keep-alive\r\nProxy-Authorization: Basic ZGVmYXVsdDpkZWZhdWx0\r\n\r\n"
72
+ #
73
+ # host, port = a.call(data)
74
+ #
75
+ # puts host
76
+ # puts port
@@ -0,0 +1,6 @@
1
+ module RSocks
2
+ module HttpProxyResponseCodes
3
+ SUCCESS = "HTTP/1.1 200 OK\r\n\r\n"
4
+ FAILED_AUTH = "HTTP/1.1 401 Unauthorized\r\n\r\n"
5
+ end
6
+ end
@@ -0,0 +1,174 @@
1
+ require 'ipaddr'
2
+ require 'r_socks/errors'
3
+ require 'r_socks/socks5_bit_codes'
4
+ require 'r_socks/state_machine'
5
+ require 'r_socks/target_connection_handler'
6
+ require 'r_socks/authenticator'
7
+ require 'r_socks/socks5_proxy_parser'
8
+
9
+ module RSocks
10
+ class Socks5ProxyParser
11
+ def initialize(state_machine, config, client)
12
+ @state_machine = state_machine
13
+ @auth_method = config.auth_method
14
+ @default_user = ENV['RSOCKS_USER'] || 'default'
15
+ @default_password = ENV['RSOCKS_PASSWORD'] || 'default'
16
+ @authenticator = RSocks::Authenticator.new(config.auth_adaptor)
17
+ @original_addr = nil
18
+ @original_port = nil
19
+ @config = config
20
+ @adaptor = config.auth_adaptor
21
+ @client = client
22
+ end
23
+
24
+
25
+ def call(data)
26
+ if @state_machine.handshake?
27
+ init_handshake(data)
28
+ return
29
+ end
30
+
31
+ if @state_machine.auth?
32
+ passed = @authenticator.auth!(data)
33
+ if passed
34
+ send_data(RSocks::SUCCESS_RESPONSE)
35
+ @state_machine.connect!
36
+ return
37
+ end
38
+
39
+ send_data(RSocks::FAILED_RESPONSE)
40
+ return
41
+ end
42
+
43
+ if @state_machine.connect?
44
+ connect_request(data)
45
+ return [@addr, @port]
46
+ end
47
+
48
+ return send_data(not_accept) unless @state_machine.start?
49
+ end
50
+
51
+ private
52
+
53
+ def init_handshake(data)
54
+
55
+ version, num = data.unpack('CC')
56
+
57
+ if version != RSocks::VERSION || num <= 0
58
+ send_data(not_accept)
59
+ close_connection
60
+ end
61
+
62
+ position = 'C' * num
63
+
64
+ methods = data[2..-1].unpack(position)
65
+
66
+ data = nil
67
+
68
+
69
+ auth_method = @config.auth_method == :password ? PASSWORD_LOGIN : RSocks::NO_AUTH
70
+
71
+ if methods.include?(auth_method)
72
+
73
+ if auth_method == RSocks::NO_AUTH
74
+ @state_machine.connect!
75
+ elsif auth_method == RSocks::PASSWORD_LOGIN
76
+ @state_machine.auth!
77
+ end
78
+
79
+ data = [RSocks::VERSION, auth_method].pack('CC')
80
+ end
81
+
82
+ if data.nil?
83
+ send_data(not_accept)
84
+ close_connection
85
+ end
86
+
87
+ send_data(data)
88
+ end
89
+
90
+ def connect_request(data)
91
+ version, cmd = data.unpack('CC')
92
+ return not_accept if version != RSocks::VERSION
93
+
94
+ begin
95
+ @addr, @port, @type = check_sock_cmd(cmd, data[2..-1])
96
+ rescue
97
+ send_data([RSocks::VERSION,RSocks::CONNECT_FAIL].pack('CC'))
98
+ return close_connection
99
+ end
100
+
101
+ @state_machine.start!
102
+
103
+ send_data([RSocks::VERSION, RSocks::CONNECT_SUCCESS].
104
+ pack('CC') + pack_address_and_port_info(@type))
105
+ end
106
+
107
+ def check_sock_cmd(cmd, data)
108
+ raise RSocks::NotSupport unless cmd == RSocks::CMD_CONNECT
109
+
110
+ _, addr_type = data.unpack('CC')
111
+
112
+ address = nil
113
+ port = nil
114
+ type = nil
115
+
116
+ if addr_type == RSocks::ADDR_IPV4
117
+ type = RSocks::ADDR_IPV4
118
+ address, port = parse_address_port(data[2..-1], 4, type)
119
+ elsif addr_type == RSocks::ADDR_IPV6
120
+ type = RSocks::ADDR_IPV6
121
+ address, port = parse_address_port(data[2..-1], 16, type)
122
+ elsif addr_type == RSocks::ADDR_DOMAIN
123
+ type = RSocks::ADDR_DOMAIN
124
+ padding = data[2].unpack('C')[0]
125
+ address, port = parse_address_port(data[3..-1], padding, type)
126
+ end
127
+
128
+ [address, port, type]
129
+ end
130
+
131
+ def not_accept
132
+ [RSocks::VERSION, RSocks::NOT_ACCEPT].pack('CC')
133
+ end
134
+
135
+ def parse_address_port(data, padding, type)
136
+ address = data[0...padding]
137
+ port_start = padding
138
+
139
+ @original_port = data[port_start..-1]
140
+ @original_addr = address
141
+
142
+ temp = @original_port.unpack('CC')
143
+
144
+ port = (temp[0] << 8) | temp[1]
145
+
146
+ addr_str = if type == RSocks::ADDR_DOMAIN
147
+ address
148
+ else
149
+ IPAddr.ntop(address)
150
+ end
151
+
152
+ [addr_str, port]
153
+ end
154
+
155
+ def pack_address_and_port_info(type)
156
+ addr = @original_addr
157
+ if type == RSocks::ADDR_DOMAIN
158
+ domain_size = [addr.size].pack('C')
159
+ addr = domain_size + @original_addr
160
+ end
161
+
162
+ temp = [RSocks::KEEP_ONE_BIT, type]
163
+ temp.pack('C' * temp.size) + addr + @original_port
164
+ end
165
+
166
+ def send_data(data)
167
+ @client.send_data(data)
168
+ end
169
+
170
+ def close_connection
171
+ @client.close_connection_after_writing
172
+ end
173
+ end
174
+ end
@@ -1,21 +1,20 @@
1
1
  require 'eventmachine'
2
+ require 'r_socks/http_proxy_response_codes'
2
3
 
3
4
  module RSocks
4
5
  class TargetConnectionHandler < EM::Connection
5
6
 
6
- def initialize(client, config, data)
7
+ def initialize(client, config)
7
8
  @client = client
8
- @init_data = data
9
9
  @config = config
10
10
  end
11
11
 
12
12
  def post_init
13
- proxy_incoming_to(@client,60000)
13
+ proxy_incoming_to(@client, @config.proxy_buffer_size)
14
14
  end
15
15
 
16
- def connection_completed
17
- send_data @init_data
18
- @init_data = nil
16
+ def receive_data(data)
17
+ @client.send_data(data)
19
18
  end
20
19
 
21
20
  def proxy_target_unbound
@@ -1,3 +1,3 @@
1
1
  module RSocks
2
- VERSION = "0.1.8"
3
- end
2
+ VERSION = "0.2.0"
3
+ end
data/lib/r_socks.rb CHANGED
@@ -1,3 +1,8 @@
1
+ require 'r_socks/state_machine'
2
+ require 'r_socks/config'
3
+ require 'r_socks/http_proxy_response_codes'
4
+ require 'r_socks/errors'
5
+ require 'r_socks/connection_handler'
1
6
  require 'r_socks/tcp_server'
2
7
  # example
3
8
  #
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: r_socks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick An
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-24 00:00:00.000000000 Z
11
+ date: 2020-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: eventmachine
@@ -51,7 +51,10 @@ files:
51
51
  - lib/r_socks/config.rb
52
52
  - lib/r_socks/connection_handler.rb
53
53
  - lib/r_socks/errors.rb
54
+ - lib/r_socks/http_proxy_parser.rb
55
+ - lib/r_socks/http_proxy_response_codes.rb
54
56
  - lib/r_socks/socks5_bit_codes.rb
57
+ - lib/r_socks/socks5_proxy_parser.rb
55
58
  - lib/r_socks/state_machine.rb
56
59
  - lib/r_socks/target_connection_handler.rb
57
60
  - lib/r_socks/tcp_server.rb