proxifier-1.0.3/0000755000175000017500000000000012677255203014253 5ustar kanashirokanashiroproxifier-1.0.3/lib/0000755000175000017500000000000012677255203015021 5ustar kanashirokanashiroproxifier-1.0.3/lib/proxifier.rb0000644000175000017500000000123512677255203017356 0ustar kanashirokanashirorequire "uri" require "uri/socks" module Proxifier require "proxifier/version" autoload :HTTPProxy, "proxifier/proxies/http" autoload :SOCKSProxy, "proxifier/proxies/socks" autoload :SOCKS5Proxy, "proxifier/proxies/socks" autoload :SOCKS4Proxy, "proxifier/proxies/socks4" autoload :SOCKS4AProxy, "proxifier/proxies/socks4a" def self.Proxy(url, options = {}) url = URI.parse(url) raise(ArgumentError, "proxy url has no scheme") unless url.scheme begin klass = const_get("#{url.scheme.upcase}Proxy") rescue NameError raise(ArgumentError, "unknown proxy scheme `#{url.scheme}'") end klass.new(url, options) end end proxifier-1.0.3/lib/uri/0000755000175000017500000000000012677255203015620 5ustar kanashirokanashiroproxifier-1.0.3/lib/uri/socks.rb0000644000175000017500000000052612677255203017272 0ustar kanashirokanashirorequire "uri/generic" module URI class SOCKS < Generic DEFAULT_PORT = 1080 COMPONENT = [:scheme, :userinfo, :host, :port, :query].freeze end @@schemes["SOCKS"] = SOCKS @@schemes["SOCKS5"] = SOCKS class SOCKS4 < SOCKS end @@schemes["SOCKS4"] = SOCKS4 class SOCKS4A < SOCKS end @@schemes["SOCKS4A"] = SOCKS4A end proxifier-1.0.3/lib/proxifier/0000755000175000017500000000000012677255203017030 5ustar kanashirokanashiroproxifier-1.0.3/lib/proxifier/proxies/0000755000175000017500000000000012677255203020521 5ustar kanashirokanashiroproxifier-1.0.3/lib/proxifier/proxies/socks4a.rb0000644000175000017500000000030012677255203022406 0ustar kanashirokanashirorequire "proxifier/proxies/socks" module Proxifier class SOCKS4AProxy < SOCKSProxy def do_proxify(*) raise NotImplementedError, "SOCKS4A is not yet implemented" end end end proxifier-1.0.3/lib/proxifier/proxies/socks4.rb0000644000175000017500000000245012677255203022255 0ustar kanashirokanashirorequire "proxifier/proxies/socks" module Proxifier class SOCKS4Proxy < SOCKSProxy VERSION = 0x04 protected def greet(socket) # noop end def authenticate(socket, method) # noop end def connect(socket, host, port) begin ip = IPAddr.new(host) rescue ArgumentError ip = IPAddr.new(Socket.getaddrinfo(host, nil, :INET, :STREAM).first) end socket << [VERSION, 0x01, port].pack("CCn") << ip.hton socket << user if user socket << 0x00 version, status, port = socket.read(4).unpack("CCn") check_version(version, 0x00) ip = IPAddr.ntop(socket.read(4)) case status when 0x5A # request granted when 0x5B # request rejected or failed raise "request rejected or failed" when 0x5C # request rejected becasue SOCKS server cannot connect to identd on the client raise "request rejected becasue SOCKS server cannot connect to identd on the client" when 0x5D # request rejected because the client program and identd report different user-ids raise "request rejected because the client program and identd report different user-ids" else raise "unknown SOCKS error" end end end end proxifier-1.0.3/lib/proxifier/proxies/socks.rb0000644000175000017500000000612412677255203022173 0ustar kanashirokanashirorequire "ipaddr" require "proxifier/proxy" module Proxifier class SOCKSProxy < Proxy VERSION = 0x05 def do_proxify(socket, host, port) authenticaton_method = greet(socket) authenticate(socket, authenticaton_method) connect(socket, host, port) end protected def greet(socket) methods = authentication_methods socket << [VERSION, methods.size, *methods].pack("CCC#{methods.size}") version, authentication_method = socket.read(2).unpack("CC") check_version(version) authentication_method end def authenticate(socket, method) case method when 0x00 # NO AUTHENTICATION REQUIRED when 0x02 # USERNAME/PASSWORD user &&= user[0, 0xFF] password &&= password[0, 0xFF] socket << [user.size, user, password.size, password].pack("CA#{user.size}CA#{password.size}") version, status = socket.read(2).unpack("CC") check_version(version) case status when 0x00 # SUCCESS else raise "SOCKS5 username/password authentication failed" end else raise "no acceptable SOCKS5 authentication methods" end end def connect(socket, host, port) host = host[0, 0xFF] socket << [VERSION, 0x01, 0x00, 0x03, host.size, host, port].pack("CCCCCA#{host.size}n") version, status, _, type = socket.read(4).unpack("CCCC") check_version(version) case status when 0x00 # succeeded when 0x01 # general SOCKS server failure raise "general SOCKS server failure" when 0x02 # connection not allowed by ruleset raise "connection not allowed by ruleset" when 0x03 # Network unreachable raise "network unreachable" when 0x04 # Host unreachable raise "host unreachable" when 0x05 # Connection refused raise "connection refused" when 0x06 # TTL expired raise "TTL expired" when 0x07 # Command not supported raise "command not supported" when 0x08 # Address type not supported raise "address type not supported" else # unassigned raise "unknown SOCKS error" end case type when 0x01 # IP V4 address destination = IPAddr.ntop(socket.read(4)) when 0x03 # DOMAINNAME length = socket.read(1).unpack("C").first destination = socket.read(length).unpack("A#{length}") when 0x04 # IP V6 address destination = IPAddr.ntop(socket.read(16)) else raise "unsupported SOCKS5 address type" end port = socket.read(2).unpack("n").first end def check_version(version, should_be = VERSION) raise "mismatched SOCKS version" unless version == should_be end private def authentication_methods methods = [] methods << 0x00 # NO AUTHENTICATION REQUIRED methods << 0x02 if user # USERNAME/PASSWORD methods end end SOCKS5Proxy = SOCKSProxy end proxifier-1.0.3/lib/proxifier/proxies/http.rb0000644000175000017500000000107512677255203022030 0ustar kanashirokanashirorequire "net/http" require "proxifier/proxy" module Proxifier class HTTPProxy < Proxy def do_proxify(socket, host, port) return if query_options["tunnel"] == "false" socket << "CONNECT #{host}:#{port} HTTP/1.1\r\n" socket << "Host: #{host}:#{port}\r\n" socket << "Proxy-Authorization: Basic #{["#{user}:#{password}"].pack("m").chomp}\r\n" if user socket << "\r\n" buffer = Net::BufferedIO.new(socket) response = Net::HTTPResponse.read_new(buffer) response.error! unless response.is_a?(Net::HTTPOK) end end end proxifier-1.0.3/lib/proxifier/version.rb0000644000175000017500000000005112677255203021036 0ustar kanashirokanashiromodule Proxifier VERSION = "1.0.3" end proxifier-1.0.3/lib/proxifier/errors.rb0000644000175000017500000000007612677255203020674 0ustar kanashirokanashiromodule Proxifier class ProxyError < StandardError end end proxifier-1.0.3/lib/proxifier/proxy.rb0000644000175000017500000000266612677255203020550 0ustar kanashirokanashirorequire "socket" require "uri" require "uri/socks" module Proxifier class Proxy class << self def proxify?(host, no_proxy = nil) return true unless no_proxy dont_proxy = no_proxy.split(",") dont_proxy.none? { |h| host =~ /#{h}\Z/ } end end attr_reader :url, :options def initialize(url, options = {}) url = URI.parse(uri) unless url.is_a?(URI::Generic) @url, @options = url, options end def open(host, port, local_host = nil, local_port = nil) return TCPSocket.new(host, port, local_host, local_port) unless proxify?(host) socket = TCPSocket.new(self.host, self.port, local_host, local_port) begin proxify(socket, host, port) rescue socket.close raise end socket end def proxify?(host) self.class.proxify?(host, options[:no_proxy]) end def proxify(socket, host, port) do_proxify(socket, host, port) end %w(host port user password query version).each do |attr| class_eval "def #{attr}; url.#{attr} end" end def query_options @query_options ||= query ? Hash[query.split("&").map { |q| q.split("=") }] : {} end %w(no_proxy).each do |option| class_eval "def #{option}; options[:#{option}] end" end protected def do_proxify(socket, host, port) raise NotImplementedError, "#{self} must implement do_proxify" end end end proxifier-1.0.3/lib/proxifier/env.rb0000644000175000017500000000603012677255203020144 0ustar kanashirokanashirorequire "socket" require "proxifier" module Proxifier class Proxy def open(host, port, local_host = nil, local_port = nil) return TCPSocket.new(host, port, local_host, local_port, :proxy => nil) unless proxify?(host) socket = TCPSocket.new(self.host, self.port, local_host, local_port, :proxy => nil) begin proxify(socket, host, port) rescue socket.close raise end socket end end module Proxify def self.included(klass) klass.class_eval do alias_method :initialize_without_proxy, :initialize alias_method :initialize, :initialize_with_proxy end end def initialize_with_proxy(host, port, options_or_local_host = {}, local_port = nil, options_if_local_host = {}) if options_or_local_host.is_a?(Hash) local_host = nil options = options_or_local_host else local_host = options_or_local_host options = options_if_local_host end if options[:proxy] && (proxy = Proxifier::Proxy(options.delete(:proxy), options)) && proxy.proxify?(host) initialize_without_proxy(proxy.host, proxy.port, local_host, local_port) begin proxy.proxify(self, host, port) rescue close raise end else initialize_without_proxy(host, port, local_host, local_port) end end end module EnvironmentProxify def self.included(klass) klass.class_eval do extend ClassMethods alias_method :initialize_without_environment_proxy, :initialize alias_method :initialize, :initialize_with_environment_proxy end end def initialize_with_environment_proxy(host, port, options_or_local_host = {}, local_port = nil, options_if_local_host = {}) if options_or_local_host.is_a?(Hash) local_host = nil options = options_or_local_host else local_host = options_or_local_host options = options_if_local_host end options = { :proxy => environment_proxy, :no_proxy => environment_no_proxy }.merge(options) initialize_without_environment_proxy(host, port, local_host, local_port, options) end def environment_proxy self.class.environment_proxy end def environment_no_proxy self.class.environment_no_proxy end module ClassMethods def environment_proxy ENV["proxy"] || ENV["PROXY"] || specific_environment_proxy end def environment_no_proxy ENV["no_proxy"] || ENV["NO_PROXY"] end private def specific_environment_proxy %w(socks socks5 socks4a socks4 http).each do |type| if proxy = ENV["#{type}_proxy"] || ENV["#{type.upcase}_PROXY"] scheme = "#{type}://" proxy = proxy.dup proxy.insert(0, scheme) unless proxy.index(scheme) == 0 return proxy end end nil end end end end class TCPSocket include Proxifier::Proxify include Proxifier::EnvironmentProxify end proxifier-1.0.3/bin/0000755000175000017500000000000012677255203015023 5ustar kanashirokanashiroproxifier-1.0.3/bin/pirb0000755000175000017500000000054512677255203015711 0ustar kanashirokanashiro#!/usr/bin/env ruby executable = File.expand_path("../" + Gem.default_exec_format % "irb", Gem.ruby) full_gem_path = Gem.loaded_specs["proxifier"].full_gem_path load_paths = Gem.loaded_specs["proxifier"].require_paths.map { |p| "-I#{File.join(full_gem_path, p)}" } # TODO: support argument switches exec(executable, *load_paths, "-rproxifier/env", *ARGV) proxifier-1.0.3/bin/pruby0000755000175000017500000000045212677255203016113 0ustar kanashirokanashiro#!/usr/bin/env ruby executable = Gem.ruby full_gem_path = Gem.loaded_specs["proxifier"].full_gem_path load_paths = Gem.loaded_specs["proxifier"].require_paths.map { |p| "-I#{File.join(full_gem_path, p)}" } # TODO: support argument switches exec(executable, *load_paths, "-rproxifier/env", *ARGV) proxifier-1.0.3/LICENSE0000644000175000017500000000204512677255203015261 0ustar kanashirokanashiroCopyright (C) 2011 by Samuel Kadolph Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. proxifier-1.0.3/README.md0000644000175000017500000000560512677255203015540 0ustar kanashirokanashiro# ruby-proxifier ## Installing ### Recommended ``` gem install proxifier ``` ### Edge ``` git clone https://github.com/samuelkadolph/ruby-proxifier cd ruby-proxifier && rake install ``` ## Rationale This gem was created for 2 purposes. First is to enable ruby programmers to use HTTP or SOCKS proxies interchangeably when using TCPSockets. Either manually with `Proxifier::Proxy#open` or by `require "proxifier/env"`. The second purpose is to use ruby code that doesn't user proxies for users that have to use proxies.
The pruby and pirb executables are simple wrappers for their respective ruby executables that support proxies from environment variables. ## Usage ### Executable Wrappers & Environment Variables proxifier provides two executables: `pruby` and `pirb`. They are simple wrappers for your current `ruby` and `irb` executables that requires the `"proxifier/env"` script which installs hooks into `TCPSocket` which will use the proxy environment variables to proxy any `TCPSocket`. The environment variables that proxifier will check are (in order of descending precedence):
Variable Name Alternatives Notes
proxy PROXY Requires the proxy scheme to be present.
socks_proxy SOCKS_PROXY
socks5_proxy
SOCKS5_PROXY
Implies the SOCKS5 proxy scheme.
socks4a_proxy SOCKS4A_PROXY Implies the SOCKS4A proxy scheme.
socks4_proxy PROXY Implies the SOCKS4 proxy scheme.
http_proxy HTTP_PROXY Implies the HTTP proxy scheme.
### Ruby ```ruby require "proxifier/proxy" proxy = Proxifier::Proxy("socks://localhost") socket = proxy.open("www.google.com", 80) socket << "GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n" socket.gets # => "HTTP/1.1 200 OK\r\n" ``` ## Supported Proxies
Protocol Formats Notes
HTTP
http://[username[:password]@]host[:port][?tunnel=false]
The port defaults to 80. This is currently a limitation that may be solved in the future.
Appending ?tunnel=false forces the proxy to not use CONNECT.
SOCKS5
socks://[username[:password]@]host[:port]
socks5://[username[:password]@]host[:port]
Port defaults to 1080.
SOCKS4A
socks4a://[username@]host[:port]
Not yet implemented.
SOCKS4
socks4://[username@]host[:port]
Currently hangs. Not sure if the problem is with code or server.
proxifier-1.0.3/metadata.yml0000644000175000017500000000255212677255203016562 0ustar kanashirokanashiro--- !ruby/object:Gem::Specification name: proxifier version: !ruby/object:Gem::Version version: 1.0.3 prerelease: platform: ruby authors: - Samuel Kadolph autorequire: bindir: bin cert_chain: [] date: 2012-03-06 00:00:00.000000000 Z dependencies: [] description: Proxifier adds support for HTTP or SOCKS proxies and lets you force TCPSocket to use proxies. email: - samuel@kadolph.com executables: - pirb - pruby extensions: [] extra_rdoc_files: [] files: - bin/pirb - bin/pruby - lib/proxifier/env.rb - lib/proxifier/errors.rb - lib/proxifier/proxies/http.rb - lib/proxifier/proxies/socks.rb - lib/proxifier/proxies/socks4.rb - lib/proxifier/proxies/socks4a.rb - lib/proxifier/proxy.rb - lib/proxifier/version.rb - lib/proxifier.rb - lib/uri/socks.rb - LICENSE - README.md homepage: https://github.com/samuelkadolph/ruby-proxifier licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 1.8.15 signing_key: specification_version: 3 summary: Proxifier is a gem to force ruby to use a proxy. test_files: []