Skip to content

Commit ccf6734

Browse files
committed
Fix up assorted SOCKS issues & limit interception to non-proxy traffic
Plan is to ship like this, with it only used on non-proxy traffic on HTTP ports (very limited) and then slowly widen the net: move to all ports with exclusions, and then potentially SOCKS over all to give us a single consistent tunneling model (and later, metadata) everywhere.
1 parent 756bd03 commit ccf6734

File tree

7 files changed

+26
-42
lines changed

7 files changed

+26
-42
lines changed

app/src/main/java/tech/httptoolkit/android/ProxyDetails.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ data class ProxyConfig(
8787
* Preferred capture protocol for this proxy. If null, only the default RAW
8888
* HTTP redirect behavior is supported.
8989
*/
90+
@Json(serializeNull = false)
9091
val captureProtocol: ProxyCaptureProtocol?
9192
) : Parcelable
9293

app/src/main/java/tech/httptoolkit/android/vpn/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@ Some quick notes on how this all hangs together:
1717
* SessionManager allows opening and closing upstream sessions and their channels (TCP/UDP connections), registering each channel with `SocketNIODataService`.
1818
* SocketNIODataService runs on a single thread, using NIO to write VPN-received data from the session to the upstream channel when the channel is available, and to read data from upstream channels when it's received.
1919
* Data is sent back into the VPN (by both SessionHandler and the NIO thread) via ClientPacketWriter, which runs on its own thread, looping on a blocking queue to do each requested write.
20-
* SessionManager can be configured with traffic redirections, to redirect traffic on certain ports to different destinations (e.g. all outgoing traffic on 80/443 to a transparent proxy server).
20+
* SessionManager takes a CaptureController, which defines which traffic to modify and how.
21+
* CaptureController uses the destination address and the port capture configuration of the app to decide which packets to capture.
22+
* To capture them, SessionManager attaches a ProxyProtocolHandler (build by CaptureController) which captures the traffic according to the configured proxy protocol (e.g. raw redirection, SOCKS, etc).

app/src/main/java/tech/httptoolkit/android/vpn/SessionManager.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -182,16 +182,19 @@ public Session createNewTCPSession(int ip, int port, int srcIp, int srcPort) thr
182182
if (existingSession != null) return existingSession;
183183

184184
String ips = PacketUtil.intToIPAddress(ip);
185-
boolean shouldCapture = captureController.shouldCapture(ips, port);
186-
SocketAddress socketAddress = shouldCapture
187-
? captureController.getProxyAddress()
188-
: new InetSocketAddress(ips, port);
189-
190-
ProxyProtocolHandler proxyHandler = shouldCapture
191-
? captureController.getProxyHandler(ips, port)
192-
: null;
193-
194-
Session session = new Session(SessionProtocol.TCP, srcIp, srcPort, ip, port, this, proxyHandler);
185+
InetSocketAddress originalDestinationAddress = new InetSocketAddress(ips, port);
186+
boolean shouldCapture = captureController.shouldCapture(originalDestinationAddress);
187+
188+
SocketAddress sessionAddress;
189+
Session session;
190+
191+
if (shouldCapture) {
192+
sessionAddress = captureController.getProxyAddress();
193+
session = new Session(SessionProtocol.TCP, srcIp, srcPort, ip, port, this, captureController.getProxyHandler(ips, port));
194+
} else {
195+
sessionAddress = originalDestinationAddress;
196+
session = new Session(SessionProtocol.TCP, srcIp, srcPort, ip, port, this, null);
197+
}
195198

196199
SocketChannel channel;
197200
channel = SocketChannel.open();
@@ -209,8 +212,8 @@ public Session createNewTCPSession(int ip, int port, int srcIp, int srcPort) thr
209212
session.setChannel(channel);
210213

211214
// Initiate connection straight away, to reduce latency
212-
Log.d(TAG,"Initiate connecting to remote tcp server: " + socketAddress.toString());
213-
boolean connected = channel.connect(socketAddress);
215+
Log.d(TAG,"Initiate connecting to remote tcp server: " + sessionAddress.toString());
216+
boolean connected = channel.connect(sessionAddress);
214217
session.setConnected(connected);
215218

216219
table.put(key, session);

app/src/main/java/tech/httptoolkit/android/vpn/capture/CaptureController.java

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,12 @@
11
package tech.httptoolkit.android.vpn.capture;
22

33
import java.net.InetSocketAddress;
4+
import java.net.SocketAddress;
45
import java.util.List;
56

67
import tech.httptoolkit.android.ProxyConfig;
78
import tech.httptoolkit.android.ProxyCaptureProtocol;
89

9-
/*
10-
Reader: in SocketChannelReader, we get data from the server and then push it to the client.
11-
This needs to somehow push to the protocol handler instead until it's done.
12-
Could be in session, but feels like that's doing too much already.
13-
14-
Writer: NIO calls SocketChannelWriter.write, IFF session have data available (need to override that check somehow)
15-
SCW.write writes client data to upstream server connection
16-
Should instead write directly into protocol handler
17-
*/
18-
1910
public class CaptureController {
2011

2112
private final InetSocketAddress proxyAddress;
@@ -40,11 +31,9 @@ public InetSocketAddress getProxyAddress() {
4031
return proxyAddress;
4132
}
4233

43-
public boolean shouldCapture(
44-
String destIp,
45-
int destPort
46-
) {
47-
return this.portsToCapture.contains(destPort);
34+
public boolean shouldCapture(InetSocketAddress destAddress) {
35+
return !destAddress.equals(proxyAddress) &&
36+
this.portsToCapture.contains(destAddress.getPort());
4837
}
4938

5039
public ProxyProtocolHandler getProxyHandler(

app/src/main/java/tech/httptoolkit/android/vpn/capture/ProxyProtocolHandler.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,4 @@ public boolean isPending() {
6464
public boolean hasFailed() {
6565
return state == State.FAILED;
6666
}
67-
68-
public State getState() {
69-
return state;
70-
}
71-
72-
public String getOriginalDestIp() {
73-
return originalDestIp;
74-
}
75-
76-
public int getOriginalDestPort() {
77-
return originalDestPort;
78-
}
7967
}

app/src/main/java/tech/httptoolkit/android/vpn/capture/SOCKS5Handler.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ public void processHandshakeData(ByteBuffer data) {
8484
} else {
8585
Log.e(TAG, "SOCKS5 auth failed");
8686
state = State.FAILED;
87+
throw new RuntimeException("SOCKS5 authentication failed");
8788
}
8889
return;
8990

@@ -95,11 +96,13 @@ public void processHandshakeData(ByteBuffer data) {
9596
} else {
9697
Log.e(TAG, "SOCKS5 connect failed");
9798
state = State.FAILED;
99+
throw new RuntimeException("SOCKS5 connection request failed");
98100
}
99101
return;
100102

101103
default:
102104
Log.w(TAG, "Unexpected data in SOCKS5 state: " + socksState);
105+
throw new RuntimeException("Unexpected data in SOCKS5 state: " + socksState);
103106
}
104107
}
105108
}

app/src/main/java/tech/httptoolkit/android/vpn/socket/SocketChannelReader.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ private void readTCP(@NonNull Session session) {
102102
readBuffer.limit(len);
103103
readBuffer.flip();
104104
sendToRequester(readBuffer, session);
105-
readBuffer.clear();
106105
} else if (len == -1) {
107106
Log.d(TAG,"End of data from remote server, will send FIN to client");
108107
Log.d(TAG,"send FIN to: " + session);
@@ -225,7 +224,6 @@ private void readUDP(Session session){
225224
//create UDP packet
226225
byte[] packetData = UDPPacketFactory.createResponsePacket(
227226
session.getLastIpHeader(), session.getLastUdpHeader(), readBuffer);
228-
readBuffer.clear();
229227

230228
//write to client
231229
writer.write(packetData);

0 commit comments

Comments
 (0)