proxxxy 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -0
  4. data/VERSION +1 -0
  5. data/proxxxy +173 -0
  6. metadata +94 -0
  7. metadata.gz.sig +0 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1cbd25ab103ea7fd597ec4799f76aa370491653970b2620ac9d4af5038294066
4
+ data.tar.gz: b6a88b2f582055d111af3834fcadb01b5d70be2ef0d77940b4e04ae562f9391e
5
+ SHA512:
6
+ metadata.gz: 4b12301ffd533867ff583f3beb21d1774252034ace96cdca8f356ff9d3fdb0dccef2062fb8bd414767d80433384f8ab1d327c2760902e7f05157af766517c299
7
+ data.tar.gz: c6993d55cf225e46b95b8d832c839b7ea07fcea4bc6ba05149c2b48b4b85eb10bf1e6eafcd0899c268d10ee0f36596d96eda1eb4131b78a458a8c0ec753678c9
Binary file
@@ -0,0 +1 @@
1
+ D4���<�rD7�b��������૪�� ��1�t�y�u�"=s�_
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/proxxxy ADDED
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env -S ruby -w
2
+ # frozen_string_literal: true
3
+
4
+ require 'csv'
5
+ require 'eventmachine'
6
+ require 'optparse'
7
+ require 'pathname'
8
+ require 'socket'
9
+ require 'time'
10
+
11
+ op = OptionParser.new do |opts|
12
+ opts.banner =
13
+ "Usage: proxxxy [options]\n" \
14
+ 'https proxy'
15
+
16
+ opts.summary_width = 20
17
+
18
+ opts.separator ''
19
+ opts.separator 'Options'
20
+ opts.on('-h', '--host HOST', String, 'Bind to host (default: 0.0.0.0)')
21
+ opts.on('-p', '--port PORT', OptionParser::DecimalInteger, 'Use port (default: 3128)') do |port|
22
+ raise OptionParser::InvalidArgument, port unless (0..65535).cover?(port)
23
+ port
24
+ end
25
+ opts.on('-s', '--socket FILE', String, 'Bind to unix domain socket')
26
+ opts.on('-q', '--quiet', 'Disable logging')
27
+ opts.on('-v', '--version', 'Show version and exit') do
28
+ version = Pathname(__dir__).join('VERSION').read
29
+ puts(version)
30
+ exit
31
+ end
32
+ opts.on_tail('--help', 'Print this help') do
33
+ puts opts
34
+ exit
35
+ end
36
+ end
37
+
38
+ begin
39
+ op.parse!(into: opts = {})
40
+ rescue OptionParser::ParseError => e
41
+ op.abort(e)
42
+ else
43
+ if opts[:socket]
44
+ if opts[:host] || opts[:port]
45
+ op.abort('host/port and socket are mutually exclusive')
46
+ end
47
+ else
48
+ opts[:host] ||= '0.0.0.0'
49
+ opts[:port] ||= 3128
50
+ end
51
+ end
52
+
53
+ class Client < EventMachine::Connection
54
+ attr_accessor :quiet
55
+
56
+ def post_init
57
+ @client_addr = client_addr
58
+ @buf = nil
59
+ @host = nil
60
+ @port = nil
61
+ @server = nil
62
+ end
63
+
64
+ def receive_data(data)
65
+ return if @server
66
+
67
+ @buf ? @buf << data : @buf = data
68
+ return unless @buf.match?(/\r?\n\r?\n/)
69
+
70
+ match = @buf.match(
71
+ /\ACONNECT ([^:]+):([1-9][0-9]*) (HTTP\/[0-1]\.\d+).*\r?\n\r?\n/m
72
+ )
73
+ unless match
74
+ log('failure', "request: #{@buf[0, 32].inspect[1...-1]}")
75
+ close_connection
76
+ return
77
+ end
78
+ @buf = nil
79
+ @host, @port, @httpv = match.captures
80
+ begin
81
+ @server = EventMachine.connect(@host, @port, Server, self)
82
+ rescue EventMachine::ConnectionError => e
83
+ log('failure', e)
84
+ close_connection
85
+ rescue RangeError
86
+ log('failure', 'invalid port')
87
+ close_connection
88
+ else
89
+ proxy_incoming_to(@server)
90
+ @server.proxy_incoming_to(self)
91
+ @server.send_data(match.post_match)
92
+ end
93
+ end
94
+
95
+ def send_ok
96
+ send_data("#{@httpv} 200 Connection established\r\n\r\n")
97
+ end
98
+
99
+ def unbind
100
+ return unless @server
101
+
102
+ if @server.error
103
+ log('failure', 'server connection error')
104
+ else
105
+ log('success', get_proxied_bytes)
106
+ end
107
+
108
+ @server.close_connection_after_writing
109
+ @server = nil
110
+ end
111
+
112
+ private
113
+
114
+ def client_addr
115
+ addrinfo = Addrinfo.new(get_peername)
116
+ rescue RuntimeError
117
+ nil
118
+ else
119
+ addrinfo.unix? ? '-' : addrinfo.inspect_sockaddr
120
+ end
121
+
122
+ def log(status, comment)
123
+ return if quiet
124
+
125
+ time = Time.now.iso8601(3)
126
+ server = @host && @port ? "#{@host}:#{@port}" : '-'
127
+
128
+ row = [time, @client_addr, server, status, comment.to_s]
129
+ puts CSV.generate_line(row, col_sep: ' ')
130
+ end
131
+ end
132
+
133
+ class Server < EventMachine::Connection
134
+ attr_reader :error
135
+
136
+ def initialize(client)
137
+ super
138
+
139
+ @client = client
140
+ @connected = false
141
+ @error = false
142
+ end
143
+
144
+ def connection_completed
145
+ @connected = true
146
+ @client.send_ok
147
+ end
148
+
149
+ def unbind
150
+ @error = true unless @connected
151
+
152
+ @client.close_connection_after_writing
153
+ end
154
+ end
155
+
156
+ EventMachine.epoll
157
+ EventMachine.run do
158
+ trap('INT') { EventMachine.stop }
159
+
160
+ host = opts[:host] || opts[:socket]
161
+ port = opts[:port]
162
+
163
+ begin
164
+ EventMachine.start_server(host, port, Client) do |client|
165
+ client.quiet = opts[:quiet]
166
+ end
167
+ rescue RuntimeError => e
168
+ EventMachine.stop
169
+ op.abort(e)
170
+ end
171
+ end
172
+
173
+ # vim: ft=ruby
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: proxxxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - soylent
8
+ autorequire:
9
+ bindir: "."
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDGjCCAgKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9lZmly
14
+ L0RDPXNveWxlbnQwHhcNMjAwMzA3MDEzNzUwWhcNMjEwMzA3MDEzNzUwWjAaMRgw
15
+ FgYDVQQDDA9lZmlyL0RDPXNveWxlbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
16
+ ggEKAoIBAQC2DMbzgA39U+3VTMjXn+0jnOQyLdmXQ5EXgSLKCgBLIcFTc9J47Th0
17
+ 7Yb/f4RzWh49/EkDBiDtLqFeKBYsj3q0e8tRCAs32NtVyl/4FDyJvWsK3R2tcXOV
18
+ qxs48J3CgG+rFLOcMC9YF4FPTkz4p3EYGFVjZTbiqyVVuIZzWtrwdZesBVgpBRyN
19
+ 8sEyNoi8vcDiOmEwf9/TVMTDf/wu6a+i3LNVGYWlvgMJRssaAnj/IbFFtPTz30Hx
20
+ eTUdfJu8YbwRspfFzcJGLf32E7vXfmHHqNzqjh4zD9sVpvTHbqLLsgVa+nYHPHAe
21
+ dzSZ5gZjG1oZ7hZDCJoEPj0oCHT0qkuXAgMBAAGjazBpMAkGA1UdEwQCMAAwCwYD
22
+ VR0PBAQDAgSwMB0GA1UdDgQWBBSsvp1HAfA+QTjOg/ehyhv7adp0FjAXBgNVHREE
23
+ EDAOgQxlZmlyQHNveWxlbnQwFwYDVR0SBBAwDoEMZWZpckBzb3lsZW50MA0GCSqG
24
+ SIb3DQEBCwUAA4IBAQBsJ7htnm3RB5xQwzC2agRAgG2ax5uaD6lCEPWshGJbfT6v
25
+ jaRrwrPSbaxBTD2v8QpXJe/fALJKWHUbNZilZU2t7HyQkfSyVQyLYcjo7lWFoHA1
26
+ z0YB3dCGcMkvLa7r73ynEtYbnYfesbXVlcRJG7SgJqWvZMnj1HnYfBevlcjSBFy2
27
+ 5xZKSwreHM+va8McxpEZmG3ecdefRQ1u+xZabamN2hhel3nKF1BUBqgxYWXYRkZP
28
+ VIAqJBK/gwFlRxVYjmi2w4Ouc4wL8HtX104yQqOuD9gVPN6PJecue66As7i2I/2q
29
+ EARmnubhy24GUdxEooHV6pOs1mLLRuFepMgBnHfs
30
+ -----END CERTIFICATE-----
31
+ date: 2020-05-20 00:00:00.000000000 Z
32
+ dependencies:
33
+ - !ruby/object:Gem::Dependency
34
+ name: eventmachine
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: cutest
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.2'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.2'
61
+ description:
62
+ email:
63
+ executables:
64
+ - proxxxy
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - "./proxxxy"
69
+ - VERSION
70
+ - proxxxy
71
+ homepage: https://github.com/soylent/proxxxy
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 2.5.0
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubygems_version: 3.1.2
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: https proxy
94
+ test_files: []
Binary file