1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 08:37:37 +03:00

bastion RSSH + other changes

This commit is contained in:
Anton Afanasyeu
2026-06-15 11:56:23 +02:00
parent 22cc1c6a6a
commit 2421c4007b
19 changed files with 549 additions and 53 deletions

View File

@@ -139,5 +139,9 @@ dependencies {
implementation 'com.github.mwiede:jsch:0.2.21'
implementation 'org.apache.sshd:sshd-core:2.14.0'
implementation 'org.apache.sshd:sshd-scp:2.14.0'
implementation 'org.slf4j:slf4j-android:1.7.36'
implementation project(':tunnel')
}

View File

@@ -19,6 +19,7 @@
<li><b>Google Play In-App Review</b> — Google Play SDK terms</li>
<li><b>Eclipse Paho MQTT client</b> — Eclipse Public License 1.0 and Eclipse Distribution License 1.0 (dual-licensed)</li>
<li><b>JSch (mwiede fork)</b> — BSD 3-Clause License (reverse SSH remote access)</li>
<li><b>Apache MINA SSHD</b> — Apache License 2.0 (embedded local SSH on device for RSSH alpha)</li>
</ul>
<h2>JUnit 4</h2>

View File

@@ -42,6 +42,10 @@ public final class ReverseSshTunnelBridge {
Log.w(TAG, "incomplete RSSH credentials");
return false;
}
if (!RsshLocalSshServer.start(user, pass, localPort)) {
Log.w(TAG, "local SSH on :" + localPort + " failed");
return false;
}
CountDownLatch connectedLatch = new CountDownLatch(1);
AtomicBoolean ok = new AtomicBoolean(false);
worker = new Thread(() -> {
@@ -54,7 +58,7 @@ public final class ReverseSshTunnelBridge {
s.setConfig(cfg);
s.setServerAliveInterval(30_000);
s.connect(CONNECT_TIMEOUT_MS);
s.setPortForwardingR(remotePort, localHost, localPort);
s.setPortForwardingR("127.0.0.1", remotePort, localHost, localPort);
session = s;
connected.set(true);
ok.set(true);
@@ -98,6 +102,7 @@ public final class ReverseSshTunnelBridge {
Session s = session;
session = null;
connected.set(false);
RsshLocalSshServer.stop();
if (s != null) {
try {
s.disconnect();

View File

@@ -0,0 +1,83 @@
package com.foxx.androidcast.remoteaccess;
import android.util.Log;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.password.PasswordAuthenticator;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.shell.ProcessShellFactory;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Embedded SSH on {@code 127.0.0.1:8022} for RSSH reverse forward target.
* Operator reaches this via bastion forwarded port (same username/password).
*/
public final class RsshLocalSshServer {
private static final String TAG = "RsshLocalSsh";
private static volatile SshServer server;
private static volatile String activeUser = "";
private static final AtomicBoolean running = new AtomicBoolean(false);
private RsshLocalSshServer() {}
public static boolean start(String username, String password, int port) {
stop();
if (username == null || username.isEmpty() || password == null || password.isEmpty()) {
return false;
}
if (port <= 0 || port > 65535) {
port = 8022;
}
final String user = username;
final String pass = password;
final int listenPort = port;
try {
Path hostKey = Files.createTempFile("rssh_host", ".key");
hostKey.toFile().deleteOnExit();
SshServer sshd = SshServer.setUpDefaultServer();
sshd.setHost("127.0.0.1");
sshd.setPort(listenPort);
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(hostKey));
sshd.setPasswordAuthenticator((PasswordAuthenticator) (u, p, session) ->
user.equals(u) && pass.equals(p));
sshd.setShellFactory(new ProcessShellFactory("/system/bin/sh", "-"));
sshd.start();
server = sshd;
activeUser = user;
running.set(true);
Log.i(TAG, "local SSH listening 127.0.0.1:" + listenPort + " user=" + user);
return true;
} catch (Exception e) {
Log.w(TAG, "local SSH start failed: " + e.getMessage());
stop();
return false;
}
}
public static void stop() {
running.set(false);
activeUser = "";
SshServer local = server;
server = null;
if (local != null) {
try {
local.stop(true);
} catch (Exception e) {
Log.d(TAG, "local SSH stop: " + e.getMessage());
}
}
}
public static boolean isRunning() {
SshServer local = server;
return running.get() && local != null && local.isStarted();
}
public static String activeUsername() {
return activeUser != null ? activeUser : "";
}
}