Renamed project to ruby-proxifier and renamed gem to proxifier.

This commit is contained in:
Samuel Kadolph committed 2011-07-19 16:11:35 -04:00
1 parent 653e57fa03
commit dad9540ef4
21 files changed
+387 -343

No files matched your search

+25
View File
@@ -0,0 +1,25 @@
require "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
@@ -1,6 +1,24 @@
require "sockets/proxy"
require "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(proxy.host, proxy.port, local_host, local_port, :proxy => nil)
begin
proxify(socket, host, port)
rescue
socket.close
raise
end
socket
end
end
module Sockets
module Proxify
def self.included(klass)
klass.class_eval do
@@ -18,11 +36,11 @@ module Sockets
options = options_if_local_host
end
if options[:proxy] && (proxy = Sockets::Proxy(options.delete(:proxy), options)) && proxy.proxify?(host)
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 Exception
rescue
close
raise
end
@@ -31,9 +49,7 @@ module Sockets
end
end
end
end
module Sockets
module EnvironmentProxify
def self.included(klass)
klass.class_eval do
@@ -66,12 +82,30 @@ module Sockets
module ClassMethods
def environment_proxy
ENV["proxy"] || ENV["PROXY"] || ENV["socks_proxy"] || ENV["http_proxy"]
ENV["proxy"] || ENV["PROXY"] || specific_environment_proxy
end
def environment_no_proxy
ENV["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
end
end
end
end
class TCPSocket
include Proxifier::Proxify
include Proxifier::EnvironmentProxify
end
+19
View File
@@ -0,0 +1,19 @@
require "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
+103
View File
@@ -0,0 +1,103 @@
require "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
+44
View File
@@ -0,0 +1,44 @@
require "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
+9
View File
@@ -0,0 +1,9 @@
require "proxifier/proxies/socks"
module Proxifier
class SOCKS4AProxy < SOCKSProxy
def do_proxify(*)
raise NotImplementedError, "SOCKS4A is not yet implemented"
end
end
end
+63
View File
@@ -0,0 +1,63 @@
require "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(proxy.host, proxy.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
@@ -1,3 +1,3 @@
module Sockets
module Proxifier
VERSION = "1.0.0"
end
-5
View File
@@ -1,5 +0,0 @@
require "sockets/version"
require "sockets/proxy"
module Sockets
end
-28
View File
@@ -1,28 +0,0 @@
require "socket"
require "sockets"
require "sockets/proxify"
module Sockets
class Proxy
def open(host, port, local_host = nil, local_port = nil)
if proxify?(host)
socket = TCPSocket.new(proxy.host, proxy.port, local_host, local_port, :proxy => nil)
begin
proxify(socket, host, port)
rescue Exception
socket.close
raise
end
socket
else
TCPSocket.new(host, port, local_host, local_port, :proxy => nil)
end
end
end
end
class TCPSocket
include Sockets::Proxify
include Sockets::EnvironmentProxify
end
-4
View File
@@ -1,4 +0,0 @@
module Sockets
module Proxies
end
end
-21
View File
@@ -1,21 +0,0 @@
require "net/http"
require "sockets/proxy"
module Sockets
module Proxies
class HTTP < 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
end
-103
View File
@@ -1,103 +0,0 @@
require "ipaddr"
require "sockets/proxy"
module Sockets
module Proxies
class SOCKS < 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
end
end
-46
View File
@@ -1,46 +0,0 @@
require "sockets/proxies/socks"
module Sockets
module Proxies
class SOCKS4 < SOCKS
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
end
-9
View File
@@ -1,9 +0,0 @@
module Sockets
module Proxies
class SOCKS4A < Proxy
def do_proxify(*)
raise NotImplementedError, "SOCKS4A is not yet implemented"
end
end
end
end
-75
View File
@@ -1,75 +0,0 @@
require "socket"
require "uri"
require "uri/socks"
module Sockets
class Proxy
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)
if proxify?(host)
socket = TCPSocket.new(proxy.host, proxy.port, local_host, local_port)
begin
proxify(socket, host, port)
rescue Exception
socket.close
raise
end
socket
else
TCPSocket.new(host, port, local_host, local_port)
end
end
def proxify?(host)
return true unless options[:no_proxy]
dont_proxy = options[:no_proxy].split(",")
dont_proxy.none? { |h| host =~ /#{h}\Z/ }
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", __FILE__, __LINE__
end
def query_options
@query ||= query ? Hash[query.split("&").map { |q| q.split("=") }] : {}
end
%w(no_proxy).each do |option|
class_eval "def #{option}; options[:#{option}] end", __FILE__, __LINE__
end
protected
def do_proxify(socket, host, port)
raise NotImplementedError, "#{self} must implement do_proxify"
end
end
def self.Proxy(url, options = {})
url = URI.parse(url)
raise(ArgumentError, "proxy has no scheme") unless url.scheme
begin
klass = Proxies.const_get(url.scheme.upcase)
rescue NameError
begin
require "sockets/proxies/#{url.scheme}"
klass = Proxies.const_get(url.scheme.upcase)
rescue LoadError, NameError
raise(ArgumentError, "unknown proxy scheme `#{url.scheme}'")
end
end
klass.new(url, options)
end
end