An implementation of a socket factory that returns a socket which will tunnel the connection through a SOCKS5 proxy. It allows explicit specification of the user and password, but if none are given it will look in the SOCKS_USER/SOCKS_PASSWORD and CONNECT_USER/CONNECT_PASSWORD environment variables as well.
Methods
Constants
| SOCKS_VERSION | = | 5 |
| SOCKS_METHOD_NO_AUTH | = | 0 |
| SOCKS_METHOD_GSSAPI | = | 1 |
| SOCKS_METHOD_PASSWD | = | 2 |
| SOCKS_METHOD_NONE | = | 0xFF |
| SOCKS_CMD_CONNECT | = | 1 |
| SOCKS_ATYP_IPV4 | = | 1 |
| SOCKS_ATYP_DOMAIN | = | 3 |
| SOCKS_ATYP_IPV6 | = | 4 |
| SOCKS_SUCCESS | = | 0 |
| SOCKS_FAILURE | = | 1 |
| SOCKS_NOT_ALLOWED | = | 2 |
| SOCKS_NETWORK_UNREACHABLE | = | 3 |
| SOCKS_HOST_UNREACHABLE | = | 4 |
| SOCKS_REFUSED | = | 5 |
| SOCKS_TTL_EXPIRED | = | 6 |
| SOCKS_CMD_NOT_SUPPORTED | = | 7 |
| SOCKS_ADDR_NOT_SUPPORTED | = | 8 |
Public Class methods
Create a new proxy connection to the given proxy host and port. Optionally, @:user@ and @:password@ options may be given to identify the username and password with which to authenticate.
[ show source ]
# File lib/net/ssh/proxy/socks5.rb, line 58
58: def initialize( proxy_host, proxy_port=1080, options={} )
59: @proxy_host = proxy_host
60: @proxy_port = proxy_port
61: @options = options
62: end
Public Instance methods
Return a new socket connected to the given host and port via the proxy that was requested when the socket factory was instantiated.
[ show source ]
# File lib/net/ssh/proxy/socks5.rb, line 66
66: def open( host, port )
67: sock = TCPSocket.new( @proxy_host, @proxy_port )
68:
69: methods = [ SOCKS_METHOD_NO_AUTH ]
70: methods << SOCKS_METHOD_PASSWD if proxy_user
71:
72: packet = [ SOCKS_VERSION, methods.size, *methods ].pack( "C*" )
73: sock.send packet, 0
74:
75: version, method = sock.recv( 2 ).unpack( "CC" )
76: if version != 5
77: sock.close
78: raise Net::SSH::Proxy::Error,
79: "invalid SOCKS version (#{version})"
80: end
81:
82: if method == SOCKS_METHOD_NONE
83: sock.close
84: raise Net::SSH::Proxy::Error,
85: "no supported authorization methods"
86: end
87:
88: case method
89: when SOCKS_METHOD_NO_AUTH
90: # no method-dependent subnegotiation required
91:
92: when SOCKS_METHOD_PASSWD
93: negotiate_password( sock )
94: end
95:
96: packet = [ SOCKS_VERSION, SOCKS_CMD_CONNECT, 0 ].pack( "C*" )
97:
98: if host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
99: packet << [ SOCKS_ATYP_IPV4, $1.to_i, $2.to_i,
100: $3.to_i, $4.to_i ].pack( "C*" )
101: else
102: packet << [ SOCKS_ATYP_DOMAIN, host.length, host ].pack( "CCA*" )
103: end
104:
105: packet << [ port ].pack( "n" )
106: sock.send packet, 0
107:
108: version, reply, = sock.recv( 4 ).unpack( "C*" )
109: len = sock.recv( 1 )[0]
110: sock.recv( len + 2 )
111:
112: unless reply == SOCKS_SUCCESS
113: sock.close
114: raise ConnectError, "#{reply}"
115: end
116:
117: return sock
118: end