-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathSOCKSProxy.java
194 lines (165 loc) · 6.51 KB
/
SOCKSProxy.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*************************************
* SOCKS Proxy in JAVA
* By Gareth Owen
* MIT Licence
************************************/
// NOTES : LISTENS ON PORT 8000
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
public class SOCKSProxy {
// socks client class - one per client connection
class SocksClient {
SocketChannel client, remote;
boolean connected;
long lastData = 0;
SocksClient(SocketChannel c) throws IOException {
client = c;
client.configureBlocking(false);
lastData = System.currentTimeMillis();
}
public void newRemoteData(Selector selector, SelectionKey sk) throws IOException {
ByteBuffer buf = ByteBuffer.allocate(1024);
if(remote.read(buf) == -1)
throw new IOException("disconnected");
lastData = System.currentTimeMillis();
buf.flip();
client.write(buf);
}
public void newClientData(Selector selector, SelectionKey sk) throws IOException {
if(!connected) {
ByteBuffer inbuf = ByteBuffer.allocate(512);
if(client.read(inbuf)<1)
return;
inbuf.flip();
// read socks header
int ver = inbuf.get();
if (ver != 4) {
throw new IOException("incorrect version" + ver);
}
int cmd = inbuf.get();
// check supported command
if (cmd != 1) {
throw new IOException("incorrect version");
}
final int port = inbuf.getShort();
final byte ip[] = new byte[4];
// fetch IP
inbuf.get(ip);
InetAddress remoteAddr = InetAddress.getByAddress(ip);
while ((inbuf.get()) != 0) ; // username
// hostname provided, not IP
if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] != 0) { // host provided
String host = "";
byte b;
while ((b = inbuf.get()) != 0) {
host += b;
}
remoteAddr = InetAddress.getByName(host);
System.out.println(host + remoteAddr);
}
remote = SocketChannel.open(new InetSocketAddress(remoteAddr, port));
ByteBuffer out = ByteBuffer.allocate(20);
out.put((byte)0);
out.put((byte) (remote.isConnected() ? 0x5a : 0x5b));
out.putShort((short) port);
out.put(remoteAddr.getAddress());
out.flip();
client.write(out);
if(!remote.isConnected())
throw new IOException("connect failed");
remote.configureBlocking(false);
remote.register(selector, SelectionKey.OP_READ);
connected = true;
} else {
ByteBuffer buf = ByteBuffer.allocate(1024);
if(client.read(buf) == -1)
throw new IOException("disconnected");
lastData = System.currentTimeMillis();
buf.flip();
remote.write(buf);
}
}
}
static ArrayList <SocksClient> clients = new ArrayList<SocksClient>();
// utility function
public SocksClient addClient(SocketChannel s) {
SocksClient cl;
try {
cl = new SocksClient(s);
} catch (IOException e) {
e.printStackTrace();
return null;
}
clients.add(cl);
return cl;
}
public SOCKSProxy() throws IOException {
ServerSocketChannel socks = ServerSocketChannel.open();
socks.socket().bind(new InetSocketAddress(8000));
socks.configureBlocking(false);
Selector select = Selector.open();
socks.register(select, SelectionKey.OP_ACCEPT);
int lastClients = clients.size();
// select loop
while(true) {
select.select(1000);
Set keys = select.selectedKeys();
Iterator iterator = keys.iterator();
while (iterator.hasNext()) {
SelectionKey k = (SelectionKey) iterator.next();
if (!k.isValid())
continue;
// new connection?
if (k.isAcceptable() && k.channel() == socks) {
// server socket
SocketChannel csock = socks.accept();
if (csock == null)
continue;
addClient(csock);
csock.register(select, SelectionKey.OP_READ);
} else if (k.isReadable()) {
// new data on a client/remote socket
for (int i = 0; i < clients.size(); i++) {
SocksClient cl = clients.get(i);
try {
if (k.channel() == cl.client) // from client (e.g. socks client)
cl.newClientData(select, k);
else if (k.channel() == cl.remote) { // from server client is connected to (e.g. website)
cl.newRemoteData(select, k);
}
} catch (IOException e) { // error occurred - remove client
cl.client.close();
if (cl.remote != null)
cl.remote.close();
k.cancel();
clients.remove(cl);
}
}
}
}
// client timeout check
for (int i = 0; i < clients.size(); i++) {
SocksClient cl = clients.get(i);
if((System.currentTimeMillis() - cl.lastData) > 30000L) {
cl.client.close();
if(cl.remote != null)
cl.remote.close();
clients.remove(cl);
}
}
if(clients.size() != lastClients) {
System.out.println(clients.size());
lastClients = clients.size();
}
}
}
public static void main(String[] args) throws IOException {
new SOCKSProxy();
}
}