From 939901a89abb169648423473056260335d3af639 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 6 Apr 2023 01:08:05 +0200 Subject: first pass on obfs4-hop pt integration --- .../pluggableTransports/HoppingConfig.java | 49 +++++++++++++++ .../pluggableTransports/HoppingObfsVpnClient.java | 72 ++++++++++++++++++++++ .../pluggableTransports/Obfs4Options.java | 21 +++---- .../pluggableTransports/ObfsVpnClient.java | 25 ++++++-- .../pluggableTransports/PtClientBuilder.java | 18 ++++++ .../pluggableTransports/PtClientInterface.java | 9 +++ .../pluggableTransports/ShapeshifterClient.java | 5 +- 7 files changed, 179 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/pluggableTransports/HoppingConfig.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/pluggableTransports/HoppingObfsVpnClient.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/pluggableTransports/PtClientBuilder.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/pluggableTransports/PtClientInterface.java (limited to 'app/src/main/java/se/leap/bitmaskclient/pluggableTransports') diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/HoppingConfig.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/HoppingConfig.java new file mode 100644 index 00000000..e885166a --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/HoppingConfig.java @@ -0,0 +1,49 @@ +package se.leap.bitmaskclient.pluggableTransports; + +import androidx.annotation.NonNull; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import se.leap.bitmaskclient.base.models.Transport; + +public class HoppingConfig { + final boolean kcp; + final String proxyAddr; + final String[] remotes; + final String[] certs; + final int portSeed; + final int portCount; + final int minHopSeconds; + final int hopJitter; + + public HoppingConfig(boolean kcp, + String proxyAddr, + Transport transport, + int minHopSeconds, + int hopJitter) { + this.kcp = kcp; + this.proxyAddr = proxyAddr; + Transport.Endpoint[] endpoints = transport.getOptions().getEndpoints(); + this.remotes = new String[endpoints.length]; + this.certs = new String[endpoints.length]; + for (int i = 0; i < remotes.length; i++) { + remotes[i] = endpoints[i].getIp(); + certs[i] = endpoints[i].getCert(); + } + this.portSeed = transport.getOptions().getPortSeed(); + this.portCount = transport.getOptions().getPortCount(); + this.minHopSeconds = minHopSeconds; + this.hopJitter = hopJitter; + } + + @NonNull + @Override + public String toString() { + Gson gson = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .create(); + return gson.toJson(this); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/HoppingObfsVpnClient.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/HoppingObfsVpnClient.java new file mode 100644 index 00000000..1b19213f --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/HoppingObfsVpnClient.java @@ -0,0 +1,72 @@ +package se.leap.bitmaskclient.pluggableTransports; + +import static de.blinkt.openvpn.core.connection.Connection.TransportProtocol.KCP; + +import client.Client; +import client.HopClient; +import de.blinkt.openvpn.core.VpnStatus; +import se.leap.bitmaskclient.base.models.Constants; + +public class HoppingObfsVpnClient implements PtClientInterface { + + public static final int PORT = 8080; + public static final String IP = "127.0.0.1"; + + public final HopClient client; + + public HoppingObfsVpnClient(Obfs4Options options) throws IllegalStateException { + + //FIXME: use a different strategy here + //Basically we would want to track if the more performant transport protocol (KCP?/TCP?) usage was successful + //if so, we stick to it, otherwise we flip the flag + boolean kcp = Constants.KCP.equals(options.transport.getProtocols()[0]); + + if (options.transport.getOptions().getEndpoints() == null) { + throw new IllegalStateException("No Endpoints for hopping pt detected!"); + } + + HoppingConfig hoppingConfig = new HoppingConfig(kcp,IP+":"+PORT, options.transport, 10, 10); + try { + client = Client.newFFIHopClient(hoppingConfig.toString()); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @Override + public int start() { + try { + client.setEventLogger(this); + return client.start() ? PORT : 0; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public void stop() { + try { + client.stop(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + client.setEventLogger(null); + } + } + + @Override + public boolean isStarted() { + return client.isStarted(); + } + + @Override + public void error(String s) { + VpnStatus.logError("[hopping-obfs4] " + s); + } + + @Override + public void log(String state, String message) { + VpnStatus.logDebug("[hopping-obfs4] " + state + ": " + message); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Obfs4Options.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Obfs4Options.java index b96f88ca..0dd81eb8 100644 --- a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Obfs4Options.java +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/Obfs4Options.java @@ -2,20 +2,15 @@ package se.leap.bitmaskclient.pluggableTransports; import java.io.Serializable; +import se.leap.bitmaskclient.base.models.Transport; + public class Obfs4Options implements Serializable { - public String cert; - public String iatMode; - public String remoteIP; - public String remotePort; - // openvpn is still using tcp, obfs4 is wrapped in kcp, if udp == true - public boolean udp; + public String gatewayIP; + public Transport transport; - public Obfs4Options(String remoteIP, String remotePort, String cert, String iatMode, boolean udp) { - this.cert = cert; - this.iatMode = iatMode; - this.remoteIP = remoteIP; - this.remotePort = remotePort; - this.udp = udp; + public Obfs4Options(String gatewayIP, + Transport transport) { + this.gatewayIP = gatewayIP; + this.transport = transport; } - } diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ObfsVpnClient.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ObfsVpnClient.java index f6c8837e..9d5ddcf9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ObfsVpnClient.java +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ObfsVpnClient.java @@ -1,5 +1,7 @@ package se.leap.bitmaskclient.pluggableTransports; +import static se.leap.bitmaskclient.base.models.Constants.KCP; + import android.util.Log; import java.util.Observable; @@ -7,12 +9,12 @@ import java.util.Observer; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import client.Client_; +import client.Client; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.eip.EipStatus; -public class ObfsVpnClient implements Observer, client.EventLogger { +public class ObfsVpnClient implements Observer, PtClientInterface { public static final AtomicInteger SOCKS_PORT = new AtomicInteger(4430); public static final String SOCKS_IP = "127.0.0.1"; @@ -27,9 +29,17 @@ public class ObfsVpnClient implements Observer, client.EventLogger { private final client.Client_ obfsVpnClient; private final Object LOCK = new Object(); - public ObfsVpnClient(Obfs4Options options) { - obfsVpnClient = new Client_(options.udp, SOCKS_IP+":"+SOCKS_PORT.get(), options.cert); - obfsVpnClient.setEventLogger(this); + public ObfsVpnClient(Obfs4Options options) throws IllegalStateException{ + //FIXME: use a different strategy here + //Basically we would want to track if the more performant transport protocol (KCP?/TCP?) usage was successful + //if so, we stick to it, otherwise we flip the flag + boolean kcp = KCP.equals(options.transport.getProtocols()[0]); + + if (options.transport.getOptions().getCert() == null) { + throw new IllegalStateException("No cert found to establish a obfs4 connection"); + } + + obfsVpnClient = Client.newClient(kcp, SOCKS_IP+":"+SOCKS_PORT.get(), options.transport.getOptions().getCert()); } /** @@ -38,6 +48,7 @@ public class ObfsVpnClient implements Observer, client.EventLogger { */ public int start() { synchronized (LOCK) { + obfsVpnClient.setEventLogger(this); Log.d(TAG, "aquired LOCK"); new Thread(this::startSync).start(); waitUntilStarted(); @@ -46,6 +57,7 @@ public class ObfsVpnClient implements Observer, client.EventLogger { return SOCKS_PORT.get(); } + // We're waiting here until the obfsvpn client has found a unbound port and started private void waitUntilStarted() { int count = -1; try { @@ -88,6 +100,8 @@ public class ObfsVpnClient implements Observer, client.EventLogger { } catch (Exception e) { e.printStackTrace(); VpnStatus.logError("[obfsvpn] " + e.getLocalizedMessage()); + } finally { + obfsVpnClient.setEventLogger(null); } pendingNetworkErrorHandling.set(false); Log.d(TAG, "stopping obfsVpnClient releasing LOCK ..."); @@ -98,6 +112,7 @@ public class ObfsVpnClient implements Observer, client.EventLogger { return obfsVpnClient.isStarted(); } + // TODO: register observer! @Override public void update(Observable observable, Object arg) { if (observable instanceof EipStatus) { diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/PtClientBuilder.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/PtClientBuilder.java new file mode 100644 index 00000000..945e3d7a --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/PtClientBuilder.java @@ -0,0 +1,18 @@ +package se.leap.bitmaskclient.pluggableTransports; + +import de.blinkt.openvpn.core.connection.Connection; +import de.blinkt.openvpn.core.connection.Obfs4Connection; +import de.blinkt.openvpn.core.connection.Obfs4HopConnection; + +public class PtClientBuilder { + public static PtClientInterface getPtClient(Connection connection) throws IllegalStateException { + switch (connection.getTransportType()) { + case OBFS4: + return new ObfsVpnClient(((Obfs4Connection) connection).getObfs4Options()); + case OBFS4_HOP: + return new HoppingObfsVpnClient(((Obfs4HopConnection) connection).getObfs4Options()); + default: + throw new IllegalStateException("Unexpected pluggable transport " + connection.getTransportType()); + } + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/PtClientInterface.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/PtClientInterface.java new file mode 100644 index 00000000..28d19a97 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/PtClientInterface.java @@ -0,0 +1,9 @@ +package se.leap.bitmaskclient.pluggableTransports; + +import client.EventLogger; + +public interface PtClientInterface extends EventLogger { + int start(); + void stop(); + boolean isStarted(); +} diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ShapeshifterClient.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ShapeshifterClient.java index f1eb0f1b..102dcf35 100644 --- a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ShapeshifterClient.java +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ShapeshifterClient.java @@ -42,6 +42,7 @@ public class ShapeshifterClient implements Observer { private int retry = 0; private final Handler reconnectHandler; + @Deprecated public class ShapeshifterLogger implements shapeshifter.Logger { @Override public void log(String s) { @@ -71,8 +72,8 @@ public class ShapeshifterClient implements Observer { private void setup(Obfs4Options options) { shapeShifter.setSocksAddr(DISPATCHER_IP+":"+DISPATCHER_PORT); - shapeShifter.setTarget(options.remoteIP+":"+options.remotePort); - shapeShifter.setCert(options.cert); + shapeShifter.setTarget(options.gatewayIP +":"+options.transport.getPorts()[0]); + shapeShifter.setCert(options.transport.getOptions().getCert()); } public void setOptions(Obfs4Options options) { -- cgit v1.2.3