@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b123ce6c20f6502e2d9113a4776a23460b0decdd1aa47becebccc4aa682ed85
|
4
|
+
data.tar.gz: d866a719eae28e9841f2969ebe9873a5bff63cb85044f2e8253632cf4f8c86a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb343ce13ca2a3974703538709958e7dc974e630d7caa7c928a3494cdaf473d2f156f195becb274f2d7286d93aa770a992696c11730fedef31d0e3d6bc2c8f27
|
7
|
+
data.tar.gz: e989aa22f362ac3f7f74290866a86b52b06bd48d219852bc4573770c64e6696abb62b35c2b23b94b8cb60310bfe114d121424fb52eb174a2074cfdb49979cb82
|
@@ -0,0 +1,2 @@
|
|
1
|
+
*.gem
|
2
|
+
.rspec_status
|
@@ -1,3 +1,3 @@
|
|
1
1
|
example_id | status | run_time |
|
2
2
|
---------------------------- | ------ | --------------- |
|
3
|
-
./spec/socket_spec.rb[1:1:1] | passed | 0.
|
3
|
+
./spec/socket_spec.rb[1:1:1] | passed | 0.13532 seconds |
|
Binary file
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module DressSocks
|
2
|
+
class Socket < ::TCPSocket
|
3
|
+
attr_accessor :socks_server, :socks_port, :socks_version, :socks_ignores, :socks_username, :socks_password
|
4
|
+
|
5
|
+
alias :initialize_tcp :initialize
|
6
|
+
|
7
|
+
|
8
|
+
def encoded_socks_version
|
9
|
+
(self.socks_version == "4a" or self.socks_version == "4") ? "\004" : "\005"
|
10
|
+
end
|
11
|
+
|
12
|
+
# See http://tools.ietf.org/html/rfc1928
|
13
|
+
def initialize(remote_host=nil, remote_port=0, local_host=nil, local_port=nil,
|
14
|
+
socks_username: nil, socks_password: nil, socks_server: nil, socks_port: nil,
|
15
|
+
socks_ignores: [], socks_version: '5')
|
16
|
+
|
17
|
+
self.socks_server = socks_server
|
18
|
+
self.socks_port = socks_port
|
19
|
+
self.socks_username = socks_username
|
20
|
+
self.socks_password = socks_password
|
21
|
+
self.socks_ignores = socks_ignores
|
22
|
+
self.socks_version = socks_version
|
23
|
+
|
24
|
+
|
25
|
+
if socks_server and socks_port and not socks_ignores.include?(remote_host)
|
26
|
+
initialize_tcp socks_server, socks_port
|
27
|
+
|
28
|
+
socks_authenticate unless socks_version =~ /^4/
|
29
|
+
|
30
|
+
if remote_host
|
31
|
+
socks_connect(remote_host, remote_port)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
initialize_tcp remote_host, remote_port, local_host, local_port
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Authentication
|
39
|
+
def socks_authenticate
|
40
|
+
if self.socks_username || self.socks_password
|
41
|
+
write "\005\001\002"
|
42
|
+
else
|
43
|
+
write "\005\001\000"
|
44
|
+
end
|
45
|
+
auth_reply = recv(2)
|
46
|
+
if auth_reply.empty?
|
47
|
+
raise DressSocks::SOCKSError.new("Server doesn't reply authentication")
|
48
|
+
end
|
49
|
+
if auth_reply[0..0] != "\004" and auth_reply[0..0] != "\005"
|
50
|
+
raise DressSocks::SOCKSError.new("SOCKS version #{auth_reply[0..0]} not supported")
|
51
|
+
end
|
52
|
+
if self.socks_username || self.socks_password
|
53
|
+
if auth_reply[1..1] != "\002"
|
54
|
+
raise DressSocks::SOCKSError.new("SOCKS authentication method #{auth_reply[1..1]} neither requested nor supported")
|
55
|
+
end
|
56
|
+
auth = "\001"
|
57
|
+
auth += self.socks_username.to_s.length.chr
|
58
|
+
auth += self.socks_username.to_s
|
59
|
+
auth += self.socks_password.to_s.length.chr
|
60
|
+
auth += self.socks_password.to_s
|
61
|
+
write auth
|
62
|
+
auth_reply = recv(2)
|
63
|
+
if auth_reply[1..1] != "\000"
|
64
|
+
raise DressSocks::SOCKSError.new("SOCKS authentication failed")
|
65
|
+
end
|
66
|
+
else
|
67
|
+
if auth_reply[1..1] != "\000"
|
68
|
+
raise DressSocks::SOCKSError.new("SOCKS authentication method #{auth_reply[1..1]} neither requested nor supported")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Connect
|
74
|
+
def socks_connect(host, port)
|
75
|
+
port = ::Socket.getservbyname(port) if port.is_a?(String)
|
76
|
+
req = String.new
|
77
|
+
req << self.encoded_socks_version
|
78
|
+
req << "\001"
|
79
|
+
req << "\000" if self.socks_version == "5"
|
80
|
+
req << [port].pack('n') if self.socks_version =~ /^4/
|
81
|
+
|
82
|
+
if self.socks_version == "4"
|
83
|
+
host = Resolv::DNS.new.getaddress(host).to_s
|
84
|
+
end
|
85
|
+
if host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)#x2F; # to IPv4 address
|
86
|
+
req << "\001" if self.socks_version == "5"
|
87
|
+
_ip = [$1.to_i,
|
88
|
+
$2.to_i,
|
89
|
+
$3.to_i,
|
90
|
+
$4.to_i
|
91
|
+
].pack('CCCC')
|
92
|
+
req << _ip
|
93
|
+
elsif host =~ /^[:0-9a-f]+#x2F; # to IPv6 address
|
94
|
+
raise "TCP/IPv6 over SOCKS is not yet supported (inet_pton missing in Ruby & not supported by Tor"
|
95
|
+
req << "\004"
|
96
|
+
else # to hostname
|
97
|
+
if self.socks_version == "5"
|
98
|
+
req << "\003" + [host.size].pack('C') + host
|
99
|
+
else
|
100
|
+
req << "\000\000\000\001"
|
101
|
+
req << "\007\000"
|
102
|
+
req << host
|
103
|
+
req << "\000"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
req << [port].pack('n') if self.socks_version == "5"
|
107
|
+
|
108
|
+
write req
|
109
|
+
|
110
|
+
socks_receive_reply
|
111
|
+
end
|
112
|
+
|
113
|
+
# returns [bind_addr: String, bind_port: Fixnum]
|
114
|
+
def socks_receive_reply
|
115
|
+
if self.socks_version == "5"
|
116
|
+
connect_reply = recv(4)
|
117
|
+
if connect_reply.empty?
|
118
|
+
raise DressSocks::SOCKSError.new("Server doesn't reply")
|
119
|
+
end
|
120
|
+
if connect_reply[0..0] != "\005"
|
121
|
+
raise DressSocks::SOCKSError.new("SOCKS version #{connect_reply[0..0]} is not 5")
|
122
|
+
end
|
123
|
+
if connect_reply[1..1] != "\000"
|
124
|
+
raise DressSocks::SOCKSError.for_response_code(connect_reply.bytes.to_a[1])
|
125
|
+
end
|
126
|
+
bind_addr_len = case connect_reply[3..3]
|
127
|
+
when "\001"
|
128
|
+
4
|
129
|
+
when "\003"
|
130
|
+
recv(1).bytes.first
|
131
|
+
when "\004"
|
132
|
+
16
|
133
|
+
else
|
134
|
+
raise DressSocks::SOCKSError.for_response_code(connect_reply.bytes.to_a[3])
|
135
|
+
end
|
136
|
+
bind_addr_s = recv(bind_addr_len)
|
137
|
+
bind_addr = case connect_reply[3..3]
|
138
|
+
when "\001"
|
139
|
+
bind_addr_s.bytes.to_a.join('.')
|
140
|
+
when "\003"
|
141
|
+
bind_addr_s
|
142
|
+
when "\004" # Untested!
|
143
|
+
i = 0
|
144
|
+
ip6 = ""
|
145
|
+
bind_addr_s.each_byte do |b|
|
146
|
+
if i > 0 and i % 2 == 0
|
147
|
+
ip6 += ":"
|
148
|
+
end
|
149
|
+
i += 1
|
150
|
+
|
151
|
+
ip6 += b.to_s(16).rjust(2, '0')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
bind_port = recv(bind_addr_len + 2)
|
155
|
+
[bind_addr, bind_port.unpack('n')]
|
156
|
+
else
|
157
|
+
connect_reply = recv(8)
|
158
|
+
unless connect_reply[0] == "\000" and connect_reply[1] == "\x5A"
|
159
|
+
raise DressSocks::SOCKSError.new("Failed while connecting througth socks")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -1,3 +1,3 @@
|
|
1
1
|
module DressSocks
|
2
|
-
VERSION = "0.1.
|
2
|
+
VERSION = "0.1.2"
|
3
3
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dress_socks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin McNally
|
@@ -60,6 +60,7 @@ executables: []
|
|
60
60
|
extensions: []
|
61
61
|
extra_rdoc_files: []
|
62
62
|
files:
|
63
|
+
- ".gitignore"
|
63
64
|
- ".rspec"
|
64
65
|
- ".rspec_status"
|
65
66
|
- Changelog.md
|
@@ -70,10 +71,10 @@ files:
|
|
70
71
|
- Rakefile
|
71
72
|
- bin/console
|
72
73
|
- bin/setup
|
73
|
-
- dress_socks-0.1.0.gem
|
74
74
|
- dress_socks.gemspec
|
75
75
|
- lib/dress_socks.rb
|
76
76
|
- lib/dress_socks/errors.rb
|
77
|
+
- lib/dress_socks/socket.rb
|
77
78
|
- lib/dress_socks/version.rb
|
78
79
|
homepage: https://github.com/chowly/dress_socks
|
79
80
|
licenses:
|