-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTCProxy.java
More file actions
311 lines (279 loc) · 8.72 KB
/
TCProxy.java
File metadata and controls
311 lines (279 loc) · 8.72 KB
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
package com.umarabdul.networking.tcproxy;
import java.net.*;
import java.io.*;
import java.util.ArrayList;
import com.umarabdul.wrapper.socketwrapper.SocketWrapper;
import com.umarabdul.util.argparser.ArgParser;
/**
* A static TCP proxy in Java for tunneling TCP connections.
* @author Umar Abdul
* @version 1.0
* @since 2020
*/
public class TCProxy{
private boolean active = false;
private int workers = 0;
private String lhost;
private int lport;
private String rhost;
private int rport;
private int backlog = 100;
private int timeout = 50; // read timeout in milliseconds, must be very small for faster routing.
private int blockSize = 9999; // maximum bytes to read at single socket read operation, the bigger the value, the more memory is used, the faster traffic is routed.
private ArrayList<String> filter;
private ServerSocket server = null;
private int verbosity = 0;
/**
* TCProxy constructor.
* @param lhost Host to listen on.
* @param lport Port to listen on.
* @param rhost Host to route connections to.
* @param rport Port to route connections to.
*/
public TCProxy(String lhost, int lport, String rhost, int rport){
this.lhost = lhost;
this.lport = lport;
this.rhost = rhost;
this.rport = rport;
filter = new ArrayList<String>();
}
/**
* Obtain the address of remote host.
* @return Remote host address.
*/
public String getRhost(){
return rhost;
}
/**
* Obtain the port number of remote host.
* @return Remote port.
*/
public int getRport(){
return rport;
}
/**
* Obtain the address used for listening.
* @return Listening host.
*/
public String getLhost(){
return lhost;
}
/**
* Obtain the port number used for listening.
* @return Listening port.
*/
public int getLport(){
return lport;
}
/**
* Check if the proxy is running. Useful when the class was executed as a separate thread.
* @return {@code true} if the proxy is active.
*/
public boolean isActive(){
return active;
}
/**
* Check if there is an active connection being routed.
* @return {@code true} if there is an active connection.
*/
public boolean hasWorkers(){
return (workers > 0 ? true : false);
}
/**
* Obtain the number of active connections being routed.
* @return Number of active connections being routed.
*/
public int getWorkers(){
return workers;
}
/**
* Add a list of IPs to connection whitelist. This will enable host filtering and any host not in the list will be blocked.
* @param hosts A list of IPs to whitelist.
*/
public void addWhitelist(String[] hosts){
for (String s : hosts){
if (!(filter.contains(s)))
filter.add(s);
}
}
/**
* Clear the list of whitelisted hosts and disable host filtering.
*/
public void clearWhitelist(){
filter.clear();
}
/**
* Set socket connection backlog for the proxy server.
* @param backlog Backlog to use.
*/
public void setBacklog(int backlog){
this.backlog = backlog;
}
/**
* Set socket read timeout used during routing.
* @param timeout Timeout in milliseconds. The smaller the value, the faster traffic is routed.
*/
public void setTimeout(int timeout){
this.timeout = timeout;
}
/**
* Set block size for socket read operations. Large value consumes more memory but allows for faster routing.
* @param blockSize Block size to use.
*/
public void setBlockSize(int blockSize){
this.blockSize = blockSize;
}
/**
* Set verbosity of server outputs.
* @param verbosity Value of verbosity to use, where {@code 0 = none, 1 = verbose, 2 = very verbose}.
*/
public void setVerbosity(int verbosity){
this.verbosity = verbosity;
}
/**
* Start the proxy server.
*/
public void start(){
if (active)
return;
try{
server = new ServerSocket(lport, backlog, InetAddress.getByName(lhost));
server.setSoTimeout(300); // timeout for accepting connections.
}catch(Exception e){
e.printStackTrace();
return;
}
active = true;
Socket client;
Thread t;
if (verbosity > 0)
System.out.println(String.format("[*] Listening for connections on: %s:%d...", lhost, lport));
while (active){
try{
client = server.accept();
t = new Thread(new Router(client));
t.start();
}catch(SocketTimeoutException e){
continue;
}catch(IOException e1){
e1.printStackTrace();
active = false;
}
}
try{
server.close();
}catch(IOException e){}
}
/**
* This inner class handles data routing for a single connection.
*/
private class Router implements Runnable{
private Socket client;
public Router(Socket client){
this.client = client;
}
@Override
public void run(){
String chost = client.getRemoteSocketAddress().toString();
if (filter.size() > 0){ // filter connection.
boolean allow = false;
for (String s : filter){
if (chost.startsWith("/"+s+":")){
allow = true;
break;
}
}
if (!(allow)){
if (verbosity > 1)
System.out.println(String.format("[!] Connection from %s rejected!", chost));
return;
}
}
workers++;
SocketWrapper rconn;
SocketWrapper cconn;
try{
rconn = new SocketWrapper(rhost, rport, false);
rconn.getSocket().setSoTimeout(timeout);
cconn = new SocketWrapper(client);
cconn.getSocket().setSoTimeout(timeout);
}catch(Exception e){
workers--;
return;
}
if (verbosity > 0)
System.out.println(String.format("[+] Tunneling: %s ==> %s:%d...", chost, rhost, rport));
// Route.
byte[] buffer = null;
while (active){
buffer = rconn.readBytes(blockSize);
if (buffer == null)
break;
if (buffer.length > 0){
if (verbosity > 1)
System.out.println(String.format("[*] %s:%d (%d bytes) ==> %s...", rhost, rport, buffer.length, chost));
if (!(cconn.writeBytes(buffer, 0, buffer.length)))
break;
}
buffer = cconn.readBytes(blockSize);
if (buffer == null)
break;
if (buffer.length > 0){
if (verbosity > 1)
System.out.println(String.format("[*] %s (%d bytes) ==> %s:%d...", chost, buffer.length, rhost, rport));
if (!(rconn.writeBytes(buffer, 0, buffer.length)))
break;
}
}
try{
rconn.getSocket().close();
cconn.getSocket().close();
}catch(IOException e){}
workers--;
}
}
/**
* Start a static proxy using command-line arguments.
* @param args Command-line arguments: listening host, listening port, remote host, and remote port.
*/
public static void main(String[] args){
String helpPage = "TCProxy v1.0 - Static TCP Proxy (Author: https://github.com/UmarAbdul01)\n"+
" Usage: tcproxy --lhost <host:port> --rhost <host:port> [options]\n"+
" Options:\n"+
" -l|--lhost <host:port> : Address to listen on\n"+
" -r|--rhost <host:port> : Remote address to route to\n"+
" -b|--blocksize <int> : Bytes to read per socket cycle\n"+
" -w|--whitelist <host1,host2,..> : Hosts to whitelist\n"+
" -v|--verbosity <int> : verbosity level (default: 1)\n"+
" -h|--help : Print this help page";
ArgParser agp = new ArgParser(args);
agp.setAlias("lhost", "l");
agp.setAlias("rport", "r");
agp.setAlias("blocksize", "b");
agp.setDefault("blocksize", "9999");
agp.setAlias("whitelist", "w");
agp.setAlias("verbosity", "v");
agp.setDefault("verbosity", "1");
if (agp.hasArg("-h") || agp.hasArg("--help")){
System.out.println(helpPage);
return;
}
if (!(agp.hasKWarg("lhost") && agp.hasKWarg("rhost"))){
System.out.println(helpPage);
return;
}
String lhost = agp.getString("lhost").split(":")[0];
int lport = Integer.parseInt(agp.getString("lhost").split(":")[1]);
String rhost = agp.getString("rhost").split(":")[0];
int rport = Integer.parseInt(agp.getString("rhost").split(":")[1]);
int blocksize = agp.getInt("blocksize");
int verbosity = agp.getInt("verbosity");
String whitelist = agp.getString("whitelist");
TCProxy proxy = new TCProxy(lhost, lport, rhost, rport);
proxy.setVerbosity(verbosity);
proxy.setBlockSize(blocksize);
if (whitelist != null)
proxy.addWhitelist(whitelist.split(","));
proxy.start();
}
}