r_socks 0.1.8 → 0.2.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 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