mirror of
git://f0xx.org/android_cast
synced 2026-07-29 05:58:14 +03:00
fix(dev): show WG VPN IP and RSSH bind in network self-test
Persist tunnel endpoint metadata from connect credentials so the VPN section reports allocated addresses: WireGuard vpn-ip plus hub-only egress hint, and RSSH bastion/remote-bind/local-forward with live rssh-connected status. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -69,6 +69,10 @@ public final class AppPreferences {
|
|||||||
private static final String KEY_DEV_REMOTE_ACCESS_RANDOM = "dev_remote_access_random";
|
private static final String KEY_DEV_REMOTE_ACCESS_RANDOM = "dev_remote_access_random";
|
||||||
private static final String KEY_DEV_REMOTE_ACCESS_SESSION_ID = "dev_remote_access_session_id";
|
private static final String KEY_DEV_REMOTE_ACCESS_SESSION_ID = "dev_remote_access_session_id";
|
||||||
private static final String KEY_DEV_REMOTE_ACCESS_EXPIRES_AT = "dev_remote_access_expires_at";
|
private static final String KEY_DEV_REMOTE_ACCESS_EXPIRES_AT = "dev_remote_access_expires_at";
|
||||||
|
private static final String KEY_DEV_REMOTE_ACCESS_VPN_ADDRESS = "dev_remote_access_vpn_address";
|
||||||
|
private static final String KEY_DEV_REMOTE_ACCESS_RSSH_BASTION = "dev_remote_access_rssh_bastion";
|
||||||
|
private static final String KEY_DEV_REMOTE_ACCESS_RSSH_REMOTE_BIND = "dev_remote_access_rssh_remote_bind";
|
||||||
|
private static final String KEY_DEV_REMOTE_ACCESS_RSSH_LOCAL_FORWARD = "dev_remote_access_rssh_local_forward";
|
||||||
private static final String KEY_DEV_REMOTE_ACCESS_VPN_ROUTE_SCOPE = "dev_remote_access_vpn_route_scope";
|
private static final String KEY_DEV_REMOTE_ACCESS_VPN_ROUTE_SCOPE = "dev_remote_access_vpn_route_scope";
|
||||||
private static final String KEY_DEV_REMOTE_ACCESS_VPN_APP_SCOPE = "dev_remote_access_vpn_app_scope";
|
private static final String KEY_DEV_REMOTE_ACCESS_VPN_APP_SCOPE = "dev_remote_access_vpn_app_scope";
|
||||||
private static final String KEY_DEV_ADB_WIFI_KEEPER = "dev_adb_wifi_keeper";
|
private static final String KEY_DEV_ADB_WIFI_KEEPER = "dev_adb_wifi_keeper";
|
||||||
@@ -519,11 +523,73 @@ public final class AppPreferences {
|
|||||||
.apply();
|
.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** WG interface address from last connect credentials (host part, no CIDR). */
|
||||||
|
public static String getDevRemoteAccessVpnAddress(Context context) {
|
||||||
|
return prefs(context).getString(KEY_DEV_REMOTE_ACCESS_VPN_ADDRESS, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setDevRemoteAccessVpnAddress(Context context, String addressCidr) {
|
||||||
|
String host = addressCidr != null ? addressCidr.trim() : "";
|
||||||
|
int slash = host.indexOf('/');
|
||||||
|
if (slash > 0) {
|
||||||
|
host = host.substring(0, slash);
|
||||||
|
}
|
||||||
|
prefs(context).edit()
|
||||||
|
.putString(KEY_DEV_REMOTE_ACCESS_VPN_ADDRESS, host)
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDevRemoteAccessRsshBastionEndpoint(Context context) {
|
||||||
|
return prefs(context).getString(KEY_DEV_REMOTE_ACCESS_RSSH_BASTION, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Bastion-side operator bind (127.0.0.1:port) from last RSSH connect. */
|
||||||
|
public static String getDevRemoteAccessRsshRemoteBind(Context context) {
|
||||||
|
return prefs(context).getString(KEY_DEV_REMOTE_ACCESS_RSSH_REMOTE_BIND, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDevRemoteAccessRsshLocalForward(Context context) {
|
||||||
|
return prefs(context).getString(KEY_DEV_REMOTE_ACCESS_RSSH_LOCAL_FORWARD, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setDevRemoteAccessRsshTunnelMeta(
|
||||||
|
Context context,
|
||||||
|
String bastionHost,
|
||||||
|
int bastionPort,
|
||||||
|
int remoteBindPort,
|
||||||
|
String localForwardHost,
|
||||||
|
int localForwardPort) {
|
||||||
|
String host = bastionHost != null ? bastionHost.trim() : "";
|
||||||
|
String bastion = host.isEmpty()
|
||||||
|
? ""
|
||||||
|
: host + ":" + Math.max(1, Math.min(65535, bastionPort));
|
||||||
|
String remoteBind = remoteBindPort > 0 ? "127.0.0.1:" + remoteBindPort : "";
|
||||||
|
String localHost = localForwardHost != null && !localForwardHost.isEmpty()
|
||||||
|
? localForwardHost.trim() : "127.0.0.1";
|
||||||
|
String localForward = localForwardPort > 0 ? localHost + ":" + localForwardPort : "";
|
||||||
|
prefs(context).edit()
|
||||||
|
.putString(KEY_DEV_REMOTE_ACCESS_RSSH_BASTION, bastion)
|
||||||
|
.putString(KEY_DEV_REMOTE_ACCESS_RSSH_REMOTE_BIND, remoteBind)
|
||||||
|
.putString(KEY_DEV_REMOTE_ACCESS_RSSH_LOCAL_FORWARD, localForward)
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Clears WG/RSSH tunnel endpoint fields from the last connect (not mode/route prefs). */
|
||||||
|
public static void clearDevRemoteAccessTunnelMeta(Context context) {
|
||||||
|
prefs(context).edit()
|
||||||
|
.remove(KEY_DEV_REMOTE_ACCESS_VPN_ADDRESS)
|
||||||
|
.remove(KEY_DEV_REMOTE_ACCESS_RSSH_BASTION)
|
||||||
|
.remove(KEY_DEV_REMOTE_ACCESS_RSSH_REMOTE_BIND)
|
||||||
|
.remove(KEY_DEV_REMOTE_ACCESS_RSSH_LOCAL_FORWARD)
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
public static void clearDevRemoteAccessSession(Context context) {
|
public static void clearDevRemoteAccessSession(Context context) {
|
||||||
prefs(context).edit()
|
prefs(context).edit()
|
||||||
.remove(KEY_DEV_REMOTE_ACCESS_SESSION_ID)
|
.remove(KEY_DEV_REMOTE_ACCESS_SESSION_ID)
|
||||||
.remove(KEY_DEV_REMOTE_ACCESS_EXPIRES_AT)
|
.remove(KEY_DEV_REMOTE_ACCESS_EXPIRES_AT)
|
||||||
.apply();
|
.apply();
|
||||||
|
clearDevRemoteAccessTunnelMeta(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getDevRemoteAccessExpiresAt(Context context) {
|
public static long getDevRemoteAccessExpiresAt(Context context) {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public final class DevVpnStatusProbe {
|
|||||||
String typeLabel = mode == RemoteAccessMode.DISABLED ? "off" : mode.name().toLowerCase(Locale.US);
|
String typeLabel = mode == RemoteAccessMode.DISABLED ? "off" : mode.name().toLowerCase(Locale.US);
|
||||||
r.itemPass("type", typeLabel);
|
r.itemPass("type", typeLabel);
|
||||||
|
|
||||||
if (mode != RemoteAccessMode.DISABLED) {
|
if (mode == RemoteAccessMode.WIREGUARD) {
|
||||||
r.itemPass(
|
r.itemPass(
|
||||||
"vpn-route-scope",
|
"vpn-route-scope",
|
||||||
RemoteAccessVpnRouting.routeScopeLabel(
|
RemoteAccessVpnRouting.routeScopeLabel(
|
||||||
@@ -78,6 +78,24 @@ public final class DevVpnStatusProbe {
|
|||||||
String tunnelLabel = formatTunnelStateLabel(tunnelState, last);
|
String tunnelLabel = formatTunnelStateLabel(tunnelState, last);
|
||||||
r.item(tunnelLevel, "tunnel-state", tunnelLabel);
|
r.item(tunnelLevel, "tunnel-state", tunnelLabel);
|
||||||
|
|
||||||
|
if (mode == RemoteAccessMode.WIREGUARD) {
|
||||||
|
String vpnIp = AppPreferences.getDevRemoteAccessVpnAddress(context);
|
||||||
|
if (!vpnIp.isEmpty()) {
|
||||||
|
r.itemPass("vpn-ip", vpnIp);
|
||||||
|
} else if (RemoteAccessStatusStore.STATE_SUCCESS.equals(tunnelState)
|
||||||
|
|| RemoteAccessStatusStore.STATE_CONNECTING.equals(tunnelState)) {
|
||||||
|
r.item(DevNetworkSelfTestReport.Level.WARN, "vpn-ip", "not stored (reconnect session)");
|
||||||
|
}
|
||||||
|
if (AppPreferences.getDevRemoteAccessVpnRouteScope(context)
|
||||||
|
== RemoteAccessVpnRouting.RouteScope.HUB_ONLY) {
|
||||||
|
r.itemPass(
|
||||||
|
"wan-egress-via-vpn",
|
||||||
|
"no (hub-only — only " + RemoteAccessVpnRouting.DEFAULT_HUB_ALLOWED_IPS + ")");
|
||||||
|
}
|
||||||
|
} else if (mode == RemoteAccessMode.RSSH) {
|
||||||
|
appendRsshTunnelMeta(context, r, tunnelState);
|
||||||
|
}
|
||||||
|
|
||||||
if (mode != RemoteAccessMode.DISABLED
|
if (mode != RemoteAccessMode.DISABLED
|
||||||
&& !RemoteAccessStatusStore.STATE_OFF.equals(controlPlane)) {
|
&& !RemoteAccessStatusStore.STATE_OFF.equals(controlPlane)) {
|
||||||
DevNetworkSelfTestReport.Level cpLevel;
|
DevNetworkSelfTestReport.Level cpLevel;
|
||||||
@@ -98,6 +116,8 @@ public final class DevVpnStatusProbe {
|
|||||||
if (mainProcess && mode == RemoteAccessMode.WIREGUARD) {
|
if (mainProcess && mode == RemoteAccessMode.WIREGUARD) {
|
||||||
boolean bound = VpnServiceClient.get(context).isBound();
|
boolean bound = VpnServiceClient.get(context).isBound();
|
||||||
r.itemPass("vpn-process-bound", bound ? "yes (:vpn AIDL)" : "no (not bound — normal if idle)");
|
r.itemPass("vpn-process-bound", bound ? "yes (:vpn AIDL)" : "no (not bound — normal if idle)");
|
||||||
|
} else if (mainProcess && mode == RemoteAccessMode.RSSH) {
|
||||||
|
r.itemPass("rssh-connected", ReverseSshTunnelBridge.isConnected() ? "yes" : "no");
|
||||||
}
|
}
|
||||||
if (!vpnDetail.isEmpty()) {
|
if (!vpnDetail.isEmpty()) {
|
||||||
r.itemPass("detail", vpnDetail);
|
r.itemPass("detail", vpnDetail);
|
||||||
@@ -304,6 +324,33 @@ public final class DevVpnStatusProbe {
|
|||||||
return caps != null && caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
|
return caps != null && caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void appendRsshTunnelMeta(
|
||||||
|
Context context,
|
||||||
|
DevNetworkSelfTestReport r,
|
||||||
|
String tunnelState) {
|
||||||
|
String bastion = AppPreferences.getDevRemoteAccessRsshBastionEndpoint(context);
|
||||||
|
if (!bastion.isEmpty()) {
|
||||||
|
r.itemPass("rssh-bastion", bastion);
|
||||||
|
} else if (RemoteAccessStatusStore.STATE_SUCCESS.equals(tunnelState)
|
||||||
|
|| RemoteAccessStatusStore.STATE_CONNECTING.equals(tunnelState)) {
|
||||||
|
r.item(DevNetworkSelfTestReport.Level.WARN, "rssh-bastion", "not stored (reconnect session)");
|
||||||
|
}
|
||||||
|
String remoteBind = AppPreferences.getDevRemoteAccessRsshRemoteBind(context);
|
||||||
|
if (!remoteBind.isEmpty()) {
|
||||||
|
r.itemPass("rssh-remote-bind", remoteBind);
|
||||||
|
} else if (RemoteAccessStatusStore.STATE_SUCCESS.equals(tunnelState)
|
||||||
|
|| RemoteAccessStatusStore.STATE_CONNECTING.equals(tunnelState)) {
|
||||||
|
r.item(DevNetworkSelfTestReport.Level.WARN, "rssh-remote-bind", "not stored (reconnect session)");
|
||||||
|
}
|
||||||
|
String localForward = AppPreferences.getDevRemoteAccessRsshLocalForward(context);
|
||||||
|
if (!localForward.isEmpty()) {
|
||||||
|
r.itemPass("rssh-local-forward", localForward);
|
||||||
|
}
|
||||||
|
r.itemPass(
|
||||||
|
"wan-egress-via-vpn",
|
||||||
|
"no (RSSH — reverse SSH only, no device routing)");
|
||||||
|
}
|
||||||
|
|
||||||
private static void appendTraffic(DevNetworkSelfTestReport r, Context context) {
|
private static void appendTraffic(DevNetworkSelfTestReport r, Context context) {
|
||||||
int uid = Process.myUid();
|
int uid = Process.myUid();
|
||||||
long rx = TrafficStats.getUidRxBytes(uid);
|
long rx = TrafficStats.getUidRxBytes(uid);
|
||||||
|
|||||||
@@ -219,6 +219,19 @@ public final class RemoteAccessService extends Service {
|
|||||||
"connect without credentials", sessionId);
|
"connect without credentials", sessionId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
AppPreferences.clearDevRemoteAccessTunnelMeta(this);
|
||||||
|
if ("wireguard".equals(tunnel)) {
|
||||||
|
AppPreferences.setDevRemoteAccessVpnAddress(
|
||||||
|
this, creds.optString("interface_address", ""));
|
||||||
|
} else if ("ssh_reverse".equals(tunnel)) {
|
||||||
|
AppPreferences.setDevRemoteAccessRsshTunnelMeta(
|
||||||
|
this,
|
||||||
|
creds.optString("bastion_host", ""),
|
||||||
|
creds.optInt("bastion_port", 443),
|
||||||
|
creds.optInt("remote_bind_port", 0),
|
||||||
|
creds.optString("local_forward_host", "127.0.0.1"),
|
||||||
|
creds.optInt("local_forward_port", 8022));
|
||||||
|
}
|
||||||
if ("wireguard".equals(tunnel)) {
|
if ("wireguard".equals(tunnel)) {
|
||||||
String wgConfig = WireGuardConfigBuilder.fromConnectCredentials(this, creds);
|
String wgConfig = WireGuardConfigBuilder.fromConnectCredentials(this, creds);
|
||||||
if (wgConfig.isEmpty()) {
|
if (wgConfig.isEmpty()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user