Skip to content

Commit

Permalink
Reverse connection
Browse files Browse the repository at this point in the history
  • Loading branch information
RetGal committed Jan 25, 2025
1 parent 0b5af1d commit c7be66c
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.awt.*;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
Expand Down Expand Up @@ -43,7 +44,11 @@ public class NetworkAssistantEngine extends NetworkEngine implements ReConfigura

private NetworkAssistantEngineConfiguration configuration;

private SSLServerSocketFactory ssf;
private SSLServerSocketFactory sssf;

private SSLSocketFactory ssf;

private boolean isPublicAccessible;

private static final String APP_NAME = "Dayon!";

Expand Down Expand Up @@ -71,6 +76,7 @@ public void addListener(NetworkAssistantEngineListener listener) {

public boolean selfTest(String publicIp) {
if (publicIp == null) {
isPublicAccessible = false;
return false;
}
if (!manageRouterPorts(0, configuration.getPort())) {
Expand All @@ -81,10 +87,13 @@ public boolean selfTest(String publicIp) {
Log.info("Port " + configuration.getPort() + " is reachable from the outside");
} catch (IOException e) {
Log.warn("Port " + configuration.getPort() + " is not reachable from the outside");
isPublicAccessible = false;
return false;
}
}
return true;
// TODO undo invert
isPublicAccessible = false;
return false;
}

/**
Expand Down Expand Up @@ -173,15 +182,25 @@ private void receivingLoop(boolean compatibilityMode) throws NoSuchAlgorithmExce

private void awaitConnections(boolean compatibilityMode) throws NoSuchAlgorithmException, IOException, KeyManagementException, CertificateEncodingException {
fireOnStarting(configuration.getPort());
ssf = CustomTrustManager.initSslContext(compatibilityMode).getServerSocketFactory();
// TODO check if public ip of the assisted is available

if (!isPublicAccessible) {
ssf = CustomTrustManager.initSslContext(false).getSocketFactory();
while (!initConnection()) {

}
return;
}

sssf = CustomTrustManager.initSslContext(compatibilityMode).getServerSocketFactory();
Log.info(format("Dayon! server [port:%d]", configuration.getPort()));
if (compatibilityMode) {
Log.warn("Compatibility mode enabled, using legacy certificate");
}
if (server != null && server.isBound()) {
safeClose(server);
}
server = (SSLServerSocket) ssf.createServerSocket(configuration.getPort());
server = (SSLServerSocket) sssf.createServerSocket(configuration.getPort());
server.setNeedClientAuth(true);
Log.info("Accepting...");

Expand All @@ -205,6 +224,47 @@ private void awaitConnections(boolean compatibilityMode) throws NoSuchAlgorithmE
server = null;
}

private boolean initConnection() {
try {
connection = (SSLSocket) ssf.createSocket();
connection.setNeedClientAuth(true);
// grace period of 15 seconds for the assistant to accept the connection
connection.setSoTimeout(15000);
// abort the connection attempt after 5 seconds if the assistant cannot be reached
// get address from token
connection.connect(new InetSocketAddress("192.168.0.104", configuration.getPort()), 5000);
// once connected, remain connected until cancelled
connection.setSoTimeout(0);
fireOnAccepted(connection);
} catch (IOException e) {
Log.warn("Unable to connect to the assisted");
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
return false;
}
return true;
}

private boolean initFileConnection() {
try {
fileConnection = (SSLSocket) ssf.createSocket();
//fileConnection.setNeedClientAuth(true);
// grace period of 15 seconds for the assistant to accept the connection
fileConnection.setSoTimeout(15000);
// abort the connection attempt after 5 seconds if the assistant cannot be reached
// get address from token
fileConnection.connect(new InetSocketAddress("192.168.0.104", configuration.getPort()), 5000);
// once connected, remain connected until cancelled
fileConnection.setSoTimeout(0);
} catch (IOException e) {
return false;
}
return true;
}

private void startFileReceiver() {
fileReceiver = new Thread(new RunnableEx() {
@Override
Expand All @@ -223,8 +283,12 @@ private void fileReceivingLoop() {
Log.info(format("Dayon! file server [port:%d]", configuration.getPort()));

try {
fileServer = (SSLServerSocket) ssf.createServerSocket(configuration.getPort());
fileConnection = (SSLSocket) fileServer.accept();
if (!isPublicAccessible) {
initFileConnection();
} else {
fileServer = (SSLServerSocket) sssf.createServerSocket(configuration.getPort());
fileConnection = (SSLSocket) fileServer.accept();
}
initFileSender();
fileIn = new ObjectInputStream(new BufferedInputStream(fileConnection.getInputStream()));

Expand All @@ -235,6 +299,7 @@ private void fileReceivingLoop() {
}

private boolean processIntroduced(NetworkMessageType type, ObjectInputStream in) throws IOException, ClassNotFoundException {
Log.info("Received introduced" + type.name());
switch (type) {
case CAPTURE:
final NetworkCaptureMessage capture = NetworkCaptureMessage.unmarshall(in);
Expand Down Expand Up @@ -285,6 +350,7 @@ private boolean processIntroduced(NetworkMessageType type, ObjectInputStream in)
}

private boolean processUnIntroduced(NetworkMessageType type, ObjectInputStream in) throws IOException {
Log.info("Received un-introduced" + type.name());
switch (type) {
case HELLO:
fireOnConnected(connection, introduce(in));
Expand Down
99 changes: 86 additions & 13 deletions src/main/java/mpo/dayon/assisted/network/NetworkAssistedEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import mpo.dayon.common.network.message.*;
import mpo.dayon.common.security.CustomTrustManager;
import mpo.dayon.common.squeeze.CompressionMethod;
import mpo.dayon.common.version.Version;

import javax.net.ssl.*;
import java.awt.*;
Expand All @@ -29,6 +30,8 @@

import static java.lang.String.format;

import static mpo.dayon.common.version.Version.isCompatibleVersion;

public class NetworkAssistedEngine extends NetworkEngine
implements ReConfigurable<NetworkAssistedEngineConfiguration>, CompressorEngineListener, MouseEngineListener {
private NetworkAssistedEngineConfiguration configuration;
Expand All @@ -49,6 +52,10 @@ public class NetworkAssistedEngine extends NetworkEngine

private final char osId = System.getProperty("os.name").toLowerCase().charAt(0);

private SSLSocketFactory ssf;

private SSLServerSocketFactory sssf;

public NetworkAssistedEngine(NetworkCaptureConfigurationMessageHandler captureConfigurationHandler,
NetworkCompressorConfigurationMessageHandler compressorConfigurationHandler,
NetworkControlMessageHandler controlHandler,
Expand Down Expand Up @@ -117,15 +124,29 @@ public void connect() {
private void start() throws IOException, NoSuchAlgorithmException, KeyManagementException, CertificateEncodingException {
Log.info(format("Connecting to [%s][%s]...", configuration.getServerName(), configuration.getServerPort()));
fireOnConnecting(configuration);
SSLSocketFactory ssf = CustomTrustManager.initSslContext(false).getSocketFactory();
connection = (SSLSocket) ssf.createSocket();
connection.setNeedClientAuth(true);
// grace period of 15 seconds for the assistant to accept the connection
connection.setSoTimeout(15000);
// abort the connection attempt after 5 seconds if the assistant cannot be reached
connection.connect(new InetSocketAddress(configuration.getServerName(), configuration.getServerPort()), 5000);
// once connected, remain connected until cancelled
connection.setSoTimeout(0);
ssf = CustomTrustManager.initSslContext(false).getSocketFactory();
initConnection();

// TODO check if the assistant port is accessible

boolean serve = false;
// start server if necessary
if (connection == null || !connection.isConnected()) {
try {
sssf = CustomTrustManager.initSslContext(false).getServerSocketFactory();
server = (SSLServerSocket) sssf.createServerSocket(configuration.getServerPort());
server.setNeedClientAuth(true);
Log.info("Accepting...");
connection = (SSLSocket) server.accept();
Toolkit.getDefaultToolkit().beep();
serve = true;
} catch (IOException e) {
Log.error("Error accepting connection", e);
closeConnections();
return;
}
}

createInputStream();
runReceiversIfNecessary();
receiver.start();
Expand All @@ -134,15 +155,58 @@ private void start() throws IOException, NoSuchAlgorithmException, KeyManagement
// The first message being sent to the assistant (e.g. version identification, locale and OS).
sender.sendHello(osId);

fileConnection = (SSLSocket) ssf.createSocket(configuration.getServerName(), configuration.getServerPort());
initFileSender();
createFileInputStream();
// start file server if necessary
// if (serve) {
// Log.info("Serving...");
// try {
// fileServer = (SSLServerSocket) sssf.createServerSocket(configuration.getServerPort());
// Log.info("Accepting...");
// fileConnection = (SSLSocket) fileServer.accept();
// } catch (IOException e) {
// Log.error("Error starting file server", e);
// closeConnections();
// return;
// }
// } else {
// fileConnection = (SSLSocket) ssf.createSocket(configuration.getServerName(), configuration.getServerPort());
// }
// TODO
Log.info("File connection ..." + configuration.getServerName() + " " + configuration.getServerPort());
//fileConnection = (SSLSocket) ssf.createSocket(configuration.getServerName(), configuration.getServerPort());
Log.info("File connection established");

try {
initFileSender();
createFileInputStream();
} catch (IOException e) {
Log.error("Error creating file input stream", e);
//closeConnections();
return;
}
Log.info("File receiver starting...");
fileReceiver.start();
Log.info("Connected to the assistant!");
fireOnConnected(CustomTrustManager.calculateFingerprints(connection.getSession(), this.getClass().getSimpleName()));
}

private void initConnection() {
try {
connection = (SSLSocket) ssf.createSocket();
connection.setNeedClientAuth(true);
// grace period of 15 seconds for the assistant to accept the connection
connection.setSoTimeout(15000);
// abort the connection attempt after 5 seconds if the assistant cannot be reached
connection.connect(new InetSocketAddress(configuration.getServerName(), configuration.getServerPort()), 5000);
// once connected, remain connected until cancelled
connection.setSoTimeout(0);
} catch (IOException e) {
Log.warn("Unable to connect to the assistant");
}
}

private void createFileInputStream() throws IOException {
fileIn = new ObjectInputStream(new BufferedInputStream(fileConnection.getInputStream()));
Log.info("File input stream created " + fileIn);
}

private void runReceiversIfNecessary() {
Expand Down Expand Up @@ -170,7 +234,7 @@ private void receivingLoop() {

NetworkMessage.unmarshallMagicNumber(in); // blocking read (!)
NetworkMessageType type = NetworkMessage.unmarshallEnum(in, NetworkMessageType.class);

Log.info("Received " + type.name());
switch (type) {
case CAPTURE_CONFIGURATION:
captureConfigurationHandler.handleConfiguration(NetworkCaptureConfigurationMessage.unmarshall(in));
Expand Down Expand Up @@ -201,6 +265,15 @@ private void receivingLoop() {
screenshotRequestHandler.handleScreenshotRequest();
break;
case PING:
Log.info("Received PING message from the assistant");
break;
case HELLO:
Log.info("Received HELLO message from the assistant");
final NetworkHelloMessage hello = NetworkHelloMessage.unmarshall(in);
if (!isCompatibleVersion(hello.getMajor(), hello.getMinor(), Version.get())) {
Log.error(format("Incompatible assisted version: %d.%d", hello.getMajor(), hello.getMinor()));
throw new IOException("version.wrong");
}
break;
default:
throw new IllegalArgumentException(format(UNSUPPORTED_TYPE, type));
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/mpo/dayon/common/network/NetworkEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ protected void handleIncomingClipboardFiles(ObjectInputStream fileIn, ClipboardO
if (filesHelper.isDone()) {
NetworkMessage.unmarshallMagicNumber(fileIn); // blocking read (!)
type = NetworkMessage.unmarshallEnum(fileIn, NetworkMessageType.class);
Log.debug("Received " + type.name());
Log.info("Received " + type.name());
if (!type.equals(CLIPBOARD_FILES) && !type.equals(PING)) {
throw new IllegalArgumentException(format(UNSUPPORTED_TYPE, type));
}
Expand Down

0 comments on commit c7be66c

Please sign in to comment.