PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/gems/net-ssh-2.0.15/lib/net/ssh/proxy/socks5.rb

https://github.com/wangmh/webistrano
Ruby | 142 lines | 84 code | 30 blank | 28 comment | 11 complexity | 9629eeed911add0060e0d5b780b5794b MD5 | raw file
  1. require 'socket'
  2. require 'net/ssh/ruby_compat'
  3. require 'net/ssh/proxy/errors'
  4. module Net
  5. module SSH
  6. module Proxy
  7. # An implementation of a SOCKS5 proxy. To use it, instantiate it, then
  8. # pass the instantiated object via the :proxy key to Net::SSH.start:
  9. #
  10. # require 'net/ssh/proxy/socks5'
  11. #
  12. # proxy = Net::SSH::Proxy::SOCKS5.new('proxy.host', proxy_port,
  13. # :user => 'user', :password => "password")
  14. # Net::SSH.start('host', 'user', :proxy => proxy) do |ssh|
  15. # ...
  16. # end
  17. class SOCKS5
  18. # The SOCKS protocol version used by this class
  19. VERSION = 5
  20. # The SOCKS authentication type for requests without authentication
  21. METHOD_NO_AUTH = 0
  22. # The SOCKS authentication type for requests via username/password
  23. METHOD_PASSWD = 2
  24. # The SOCKS authentication type for when there are no supported
  25. # authentication methods.
  26. METHOD_NONE = 0xFF
  27. # The SOCKS packet type for requesting a proxy connection.
  28. CMD_CONNECT = 1
  29. # The SOCKS address type for connections via IP address.
  30. ATYP_IPV4 = 1
  31. # The SOCKS address type for connections via domain name.
  32. ATYP_DOMAIN = 3
  33. # The SOCKS response code for a successful operation.
  34. SUCCESS = 0
  35. # The proxy's host name or IP address
  36. attr_reader :proxy_host
  37. # The proxy's port number
  38. attr_reader :proxy_port
  39. # The map of options given at initialization
  40. attr_reader :options
  41. # Create a new proxy connection to the given proxy host and port.
  42. # Optionally, :user and :password options may be given to
  43. # identify the username and password with which to authenticate.
  44. def initialize(proxy_host, proxy_port=1080, options={})
  45. @proxy_host = proxy_host
  46. @proxy_port = proxy_port
  47. @options = options
  48. end
  49. # Return a new socket connected to the given host and port via the
  50. # proxy that was requested when the socket factory was instantiated.
  51. def open(host, port)
  52. socket = TCPSocket.new(proxy_host, proxy_port)
  53. methods = [METHOD_NO_AUTH]
  54. methods << METHOD_PASSWD if options[:user]
  55. packet = [VERSION, methods.size, *methods].pack("C*")
  56. socket.send packet, 0
  57. version, method = socket.recv(2).unpack("CC")
  58. if version != VERSION
  59. socket.close
  60. raise Net::SSH::Proxy::Error, "invalid SOCKS version (#{version})"
  61. end
  62. if method == METHOD_NONE
  63. socket.close
  64. raise Net::SSH::Proxy::Error, "no supported authorization methods"
  65. end
  66. negotiate_password(socket) if method == METHOD_PASSWD
  67. packet = [VERSION, CMD_CONNECT, 0].pack("C*")
  68. if host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
  69. packet << [ATYP_IPV4, $1.to_i, $2.to_i, $3.to_i, $4.to_i].pack("C*")
  70. else
  71. packet << [ATYP_DOMAIN, host.length, host].pack("CCA*")
  72. end
  73. packet << [port].pack("n")
  74. socket.send packet, 0
  75. version, reply, = socket.recv(2).unpack("C*")
  76. socket.recv(1)
  77. address_type = socket.recv(1).getbyte(0)
  78. case address_type
  79. when 1
  80. socket.recv(4) # get four bytes for IPv4 address
  81. when 3
  82. len = socket.recv(1).getbyte(0)
  83. hostname = socket.recv(len)
  84. when 4
  85. ipv6addr hostname = socket.recv(16)
  86. else
  87. socket.close
  88. raise ConnectionError, "Illegal response type"
  89. end
  90. portnum = socket.recv(2)
  91. unless reply == SUCCESS
  92. socket.close
  93. raise ConnectError, "#{reply}"
  94. end
  95. return socket
  96. end
  97. private
  98. # Simple username/password negotiation with the SOCKS5 server.
  99. def negotiate_password(socket)
  100. packet = [0x01, options[:user].length, options[:user],
  101. options[:password].length, options[:password]].pack("CCA*CA*")
  102. socket.send packet, 0
  103. version, status = socket.recv(2).unpack("CC")
  104. if status != SUCCESS
  105. socket.close
  106. raise UnauthorizedError, "could not authorize user"
  107. end
  108. end
  109. end
  110. end
  111. end
  112. end