Skip to content

Commit

Permalink
Implemented configurable listening address
Browse files Browse the repository at this point in the history
When applied, this commit tries to implement the feature requests reported on the issues bk138#43 and bk138#227.
Basically, with this, it is now possible to make the server listen only on certain addresses.
This increases security and allows the typical "SSH usage", that is, SSH + publickey auth + local port forwarding + VNC listening on localhost only.

To achieve this:

- on droidvnc-ng.c, vncServerStart was modified in order to provide a further "jstring listenIf" parameter.
It uses rfbScreenInfo*'s listenInterface property.

- A TableRow was added in order to allow users to input the desired address to use ("Listening Address").

- On droidvnc-ng.c, the method vncServerGetListenInterface was introduced in order to track if the server is currenctly set to listen to 0.0.0.0 or not (this is used to properly show what addresses are available to use on the UI).

Please note that, if an invalid address/host is set, by default, it is assumed the address 0.0.0.0 is requested.
  • Loading branch information
elluisian committed Sep 1, 2024
1 parent e8877a3 commit ac90fb2
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 3 deletions.
21 changes: 20 additions & 1 deletion app/src/main/cpp/droidvnc-ng.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ JNIEXPORT jboolean JNICALL Java_net_christianbeier_droidvnc_1ng_MainService_vncS
}


JNIEXPORT jboolean JNICALL Java_net_christianbeier_droidvnc_1ng_MainService_vncStartServer(JNIEnv *env, jobject thiz, jint width, jint height, jint port, jstring desktopname, jstring password, jstring httpRootDir) {
JNIEXPORT jboolean JNICALL Java_net_christianbeier_droidvnc_1ng_MainService_vncStartServer(JNIEnv *env, jobject thiz, jint width, jint height, jstring listenIf, jint port, jstring desktopname, jstring password, jstring httpRootDir) {

int argc = 0;

Expand All @@ -315,6 +315,17 @@ JNIEXPORT jboolean JNICALL Java_net_christianbeier_droidvnc_1ng_MainService_vncS
theScreen->setXCutTextUTF8 = onCutText;
theScreen->newClientHook = onClientConnected;

in_addr_t address = 0; // Default is 0.0.0.0
if (listenIf != NULL) {
const char *listenIfNative = (*env)->GetStringUTFChars(env, listenIf, NULL);
if (!rfbStringToAddr((char*)listenIfNative, &address)) {
address = 0; // If problems arise, assume 0.0.0.0
}
(*env)->ReleaseStringUTFChars(env, listenIf, listenIfNative);
}

// With the listenInterface property one can define where the server will be available
theScreen->listenInterface = address;
theScreen->port = port;
theScreen->ipv6port = port;

Expand Down Expand Up @@ -491,4 +502,12 @@ JNIEXPORT jint JNICALL Java_net_christianbeier_droidvnc_1ng_MainService_vncGetFr

JNIEXPORT jboolean JNICALL Java_net_christianbeier_droidvnc_1ng_MainService_vncIsActive(JNIEnv *env, jobject thiz) {
return theScreen && rfbIsActive(theScreen);
}

JNIEXPORT jint JNICALL Java_net_christianbeier_droidvnc_1ng_MainService_vncGetListenInterface(JNIEnv *env, jobject thiz) {
if (!theScreen) {
return -1;
}

return theScreen->listenInterface;
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class Constants {
/*
user settings
*/
public static final String PREFS_KEY_SETTINGS_LISTEN_INTERFACE = "settings_listen_interface";
public static final String PREFS_KEY_SETTINGS_PORT = "settings_port";
public static final String PREFS_KEY_SETTINGS_PASSWORD = "settings_password" ;
public static final String PREFS_KEY_SETTINGS_START_ON_BOOT = "settings_start_on_boot" ;
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/net/christianbeier/droidvnc_ng/Defaults.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class Defaults {
private const val PREFS_KEY_DEFAULTS_ACCESS_KEY = "defaults_access_key"
}

@EncodeDefault
var listenInterface = "0.0.0.0"
private set

@EncodeDefault
var port = 5900
private set
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ protected void onCreate(Bundle savedInstanceState) {
mButtonToggle.setOnClickListener(view -> {

Intent intent = new Intent(MainActivity.this, MainService.class);
intent.putExtra(MainService.EXTRA_LISTEN_INTERFACE, prefs.getString(Constants.PREFS_KEY_SETTINGS_LISTEN_INTERFACE, mDefaults.getListenInterface()));
intent.putExtra(MainService.EXTRA_PORT, prefs.getInt(Constants.PREFS_KEY_SETTINGS_PORT, mDefaults.getPort()));
intent.putExtra(MainService.EXTRA_PASSWORD, prefs.getString(Constants.PREFS_KEY_SETTINGS_PASSWORD, mDefaults.getPassword()));
intent.putExtra(MainService.EXTRA_FILE_TRANSFER, prefs.getBoolean(Constants.PREFS_KEY_SETTINGS_FILE_TRANSFER, mDefaults.getFileTransfer()));
Expand Down Expand Up @@ -306,6 +307,35 @@ protected void onCreate(Bundle savedInstanceState) {
});


final EditText listenInterface = findViewById(R.id.settings_listen_interface);
listenInterface.setText(prefs.getString(Constants.PREFS_KEY_SETTINGS_LISTEN_INTERFACE, mDefaults.getListenInterface()));
listenInterface.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

}

@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
// only save new value if it differs from the default and was not saved before
if(!(prefs.getString(Constants.PREFS_KEY_SETTINGS_LISTEN_INTERFACE, null) == null && charSequence.toString().equals(mDefaults.getListenInterface()))) {
SharedPreferences.Editor ed = prefs.edit();
ed.putString(Constants.PREFS_KEY_SETTINGS_LISTEN_INTERFACE, charSequence.toString());
ed.apply();
}
}

@Override
public void afterTextChanged(Editable editable) {

}
});
listenInterface.setOnFocusChangeListener((v, hasFocus) -> {
// move cursor to end of text
listenInterface.setSelection(listenInterface.getText().length());
});


final EditText port = findViewById(R.id.settings_port);
if(prefs.getInt(Constants.PREFS_KEY_SETTINGS_PORT, mDefaults.getPort()) < 0) {
port.setHint(R.string.main_activity_settings_port_not_listening);
Expand Down Expand Up @@ -757,7 +787,15 @@ private void onServerStarted() {
if(MainService.getPort() >= 0) {
HashMap<ClickableSpan, Pair<Integer,Integer>> spans = new HashMap<>();
// uhh there must be a nice functional way for this
ArrayList<String> hosts = MainService.getIPv4s();
ArrayList<String> hosts = null;

if (MainService.isListeningOnAnyInterface()) {
hosts = MainService.getIPv4s();
} else {
hosts = new ArrayList<>();
hosts.add(MainService.getListenInterface());
}

StringBuilder sb = new StringBuilder();
sb.append(getString(R.string.main_activity_address)).append(" ");
for (int i = 0; i < hosts.size(); ++i) {
Expand Down Expand Up @@ -798,6 +836,7 @@ public void onClick(@NonNull View widget) {
findViewById(R.id.outbound_buttons).setVisibility(View.VISIBLE);

// indicate that changing these settings does not have an effect when the server is running
findViewById(R.id.settings_listen_interface).setEnabled(false);
findViewById(R.id.settings_port).setEnabled(false);
findViewById(R.id.settings_password).setEnabled(false);
findViewById(R.id.settings_access_key).setEnabled(false);
Expand All @@ -823,6 +862,7 @@ private void onServerStopped() {
findViewById(R.id.outbound_buttons).setVisibility(View.GONE);

// indicate that changing these settings does have an effect when the server is stopped
findViewById(R.id.settings_listen_interface).setEnabled(true);
findViewById(R.id.settings_port).setEnabled(true);
findViewById(R.id.settings_password).setEnabled(true);
findViewById(R.id.settings_access_key).setEnabled(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public class MainService extends Service {
public static final String ACTION_CONNECT_REPEATER = "net.christianbeier.droidvnc_ng.ACTION_CONNECT_REPEATER";
public static final String EXTRA_REQUEST_ID = "net.christianbeier.droidvnc_ng.EXTRA_REQUEST_ID";
public static final String EXTRA_REQUEST_SUCCESS = "net.christianbeier.droidvnc_ng.EXTRA_REQUEST_SUCCESS";
public static final String EXTRA_LISTEN_INTERFACE = "net.christianbeier.droidvnc_ng.EXTRA_LISTEN_INTERFACE";
public static final String EXTRA_HOST = "net.christianbeier.droidvnc_ng.EXTRA_HOST";
public static final String EXTRA_PORT = "net.christianbeier.droidvnc_ng.EXTRA_PORT";
public static final String EXTRA_REPEATER_ID = "net.christianbeier.droidvnc_ng.EXTRA_REPEATER_ID";
Expand Down Expand Up @@ -104,6 +105,10 @@ public class MainService extends Service {

final static String ACTION_HANDLE_NOTIFICATION_RESULT = "action_handle_notification_result";

// Used to correctly signal if the server is listening on the "any address" (0.0.0.0)
private static final String PREFS_KEY_SERVER_LAST_LISTEN_WAS_ANY = "server_last_listen_was_any" ;

private static final String PREFS_KEY_SERVER_LAST_LISTEN_INTERFACE = "server_last_listen_interface" ;
private static final String PREFS_KEY_SERVER_LAST_PORT = "server_last_port" ;
private static final String PREFS_KEY_SERVER_LAST_PASSWORD = "server_last_password" ;
private static final String PREFS_KEY_SERVER_LAST_FILE_TRANSFER = "server_last_file_transfer" ;
Expand Down Expand Up @@ -166,9 +171,10 @@ public void onServiceUnregistered(NsdServiceInfo nsdServiceInfo) {
}

@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private native boolean vncStartServer(int width, int height, int port, String desktopName, String password, String httpRootDir);
private native boolean vncStartServer(int width, int height, String listenIf, int port, String desktopName, String password, String httpRootDir);
private native boolean vncStopServer();
private native boolean vncIsActive();
private native int vncGetListenInterface();
private native long vncConnectReverse(String host, int port);
private native long vncConnectRepeater(String host, int port, String repeaterIdentifier);
static native boolean vncNewFramebuffer(int width, int height);
Expand Down Expand Up @@ -331,16 +337,21 @@ public int onStartCommand(Intent intent, int flags, int startId)
startScreenCapture();
} else {
DisplayMetrics displayMetrics = Utils.getDisplayMetrics(this, Display.DEFAULT_DISPLAY);
String listenIf = PreferenceManager.getDefaultSharedPreferences(this).getString(PREFS_KEY_SERVER_LAST_LISTEN_INTERFACE, mDefaults.getListenInterface()).toLowerCase();
int port = PreferenceManager.getDefaultSharedPreferences(this).getInt(PREFS_KEY_SERVER_LAST_PORT, mDefaults.getPort());
// get device name
String name = Utils.getDeviceName(this);

boolean status = vncStartServer(displayMetrics.widthPixels,
displayMetrics.heightPixels,
listenIf,
port,
name,
PreferenceManager.getDefaultSharedPreferences(this).getString(PREFS_KEY_SERVER_LAST_PASSWORD, mDefaults.getPassword()),
getFilesDir().getAbsolutePath() + File.separator + "novnc");

this.updateLastListenWasAnyFlag();

Intent answer = new Intent(ACTION_START);
answer.putExtra(EXTRA_REQUEST_ID, PreferenceManager.getDefaultSharedPreferences(this).getString(PREFS_KEY_SERVER_LAST_START_REQUEST_ID, null));
answer.putExtra(EXTRA_REQUEST_SUCCESS, status);
Expand Down Expand Up @@ -374,15 +385,19 @@ public int onStartCommand(Intent intent, int flags, int startId)
if (mResultCode != 0 && mResultData != null
|| (Build.VERSION.SDK_INT >= 30 && PreferenceManager.getDefaultSharedPreferences(this).getBoolean(PREFS_KEY_SERVER_LAST_FALLBACK_SCREEN_CAPTURE, false))) {
DisplayMetrics displayMetrics = Utils.getDisplayMetrics(this, Display.DEFAULT_DISPLAY);
String listenIf = PreferenceManager.getDefaultSharedPreferences(this).getString(PREFS_KEY_SERVER_LAST_LISTEN_INTERFACE, mDefaults.getListenInterface()).toLowerCase();
int port = PreferenceManager.getDefaultSharedPreferences(this).getInt(PREFS_KEY_SERVER_LAST_PORT, mDefaults.getPort());
String name = Utils.getDeviceName(this);
boolean status = vncStartServer(displayMetrics.widthPixels,
displayMetrics.heightPixels,
listenIf,
port,
name,
PreferenceManager.getDefaultSharedPreferences(this).getString(PREFS_KEY_SERVER_LAST_PASSWORD, mDefaults.getPassword()),
getFilesDir().getAbsolutePath() + File.separator + "novnc");

this.updateLastListenWasAnyFlag();

Intent answer = new Intent(ACTION_START);
answer.putExtra(EXTRA_REQUEST_ID, PreferenceManager.getDefaultSharedPreferences(this).getString(PREFS_KEY_SERVER_LAST_START_REQUEST_ID, null));
answer.putExtra(EXTRA_REQUEST_SUCCESS, status);
Expand Down Expand Up @@ -445,6 +460,7 @@ public int onStartCommand(Intent intent, int flags, int startId)
// Step 0: persist given arguments to be able to recover from possible crash later
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor ed = prefs.edit();
ed.putString(PREFS_KEY_SERVER_LAST_LISTEN_INTERFACE, intent.getStringExtra(EXTRA_LISTEN_INTERFACE) != null ? intent.getStringExtra(EXTRA_LISTEN_INTERFACE) : prefs.getString(Constants.PREFS_KEY_SETTINGS_LISTEN_INTERFACE, mDefaults.getListenInterface()));
ed.putInt(PREFS_KEY_SERVER_LAST_PORT, intent.getIntExtra(EXTRA_PORT, prefs.getInt(Constants.PREFS_KEY_SETTINGS_PORT, mDefaults.getPort())));
ed.putString(PREFS_KEY_SERVER_LAST_PASSWORD, intent.getStringExtra(EXTRA_PASSWORD) != null ? intent.getStringExtra(EXTRA_PASSWORD) : prefs.getString(Constants.PREFS_KEY_SETTINGS_PASSWORD, mDefaults.getPassword()));
ed.putBoolean(PREFS_KEY_SERVER_LAST_FILE_TRANSFER, intent.getBooleanExtra(EXTRA_FILE_TRANSFER, prefs.getBoolean(Constants.PREFS_KEY_SETTINGS_FILE_TRANSFER, mDefaults.getFileTransfer())));
Expand Down Expand Up @@ -744,6 +760,41 @@ private void sendBroadcastToOthersAndUs(Intent intent) {
}
}


/**
* It updates the flag that signals if the server is listening on the "any interface" (0.0.0.0)
* @return void
*/
private void updateLastListenWasAnyFlag() {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor ed = prefs.edit();
ed.putBoolean(PREFS_KEY_SERVER_LAST_LISTEN_WAS_ANY, this.vncGetListenInterface() == 0);
ed.apply();
}



static boolean isListeningOnAnyInterface() {
try {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(instance);
return prefs.getBoolean(PREFS_KEY_SERVER_LAST_LISTEN_WAS_ANY, false);
} catch (Exception e) {
return false;
}
}


static String getListenInterface() {
try {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(instance);
return prefs.getString(PREFS_KEY_SERVER_LAST_LISTEN_INTERFACE, new Defaults(instance).getListenInterface());
} catch (Exception e) {
return null;
}
}



static boolean isServerActive() {
try {
return instance.vncIsActive();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public void onReceive(Context context, Intent arg1)

Intent intent = new Intent(context, MainService.class);
intent.setAction(MainService.ACTION_START);
intent.putExtra(MainService.EXTRA_LISTEN_INTERFACE, prefs.getString(Constants.PREFS_KEY_SETTINGS_LISTEN_INTERFACE, defaults.getListenInterface()));
intent.putExtra(MainService.EXTRA_PORT, prefs.getInt(Constants.PREFS_KEY_SETTINGS_PORT, defaults.getPort()));
intent.putExtra(MainService.EXTRA_PASSWORD, prefs.getString(Constants.PREFS_KEY_SETTINGS_PASSWORD, defaults.getPassword()));
intent.putExtra(MainService.EXTRA_FILE_TRANSFER, prefs.getBoolean(Constants.PREFS_KEY_SETTINGS_FILE_TRANSFER, defaults.getFileTransfer()));
Expand Down
33 changes: 33 additions & 0 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,40 @@
android:layout_weight="2"
android:layout_column="0"
android:padding="10dp"
<<<<<<< HEAD
android:hyphenationFrequency="full"
=======
android:text="@string/main_activity_settings_listening_address" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="1"
android:padding="10dp"
android:text="@string/main_activity_colon" />

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="2"
android:padding="10dp"
android:hint="@string/settings_listen_interface_hint"
android:layout_weight="1"
android:inputType="textUri"
android:maxLines="1"
android:id="@+id/settings_listen_interface"/>
</TableRow>

<TableRow
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:padding="10dp"
>>>>>>> 4710b51 (Implemented configurable listening address)
android:text="@string/main_activity_settings_port" />

<TextView
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<resources>
<string name="main_activity_title">droidVNC-NG Admin-Panel</string>
<string name="main_activity_settings">Einstellungen</string>
<string name="main_activity_settings_listening_address">Höradresse</string>
<string name="main_activity_settings_port">Port</string>
<string name="main_activity_settings_port_not_listening">Eingehende Verbindungen deaktiviert</string>
<string name="main_activity_settings_password">Passwort</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-it/strings.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<resources>
<string name="main_activity_title">Amministrazione di droidVNC-NG</string>
<string name="main_activity_settings">Impostazioni</string>
<string name="main_activity_settings_listening_address">Indirizzo d\'ascolto</string>
<string name="main_activity_settings_port">Porta</string>
<string name="main_activity_settings_port_not_listening">Connessioni in entrata disabilitate</string>
<string name="main_activity_settings_password">Password</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-ja/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<string name="app_name" translatable="false">droidVNC-NG</string>
<string name="main_activity_title">droidVNC-NG管理パネル</string>
<string name="main_activity_settings">設定</string>
<string name="main_activity_settings_listening_address">リスニングアドレス</string>
<string name="main_activity_settings_port">ポート</string>
<string name="main_activity_settings_port_not_listening">インバウンド接続は無効です</string>
<string name="main_activity_settings_password">パスワード</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-pt/strings.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<resources>
<string name="main_activity_title">Painel Administrativo do droidVNC-NG</string>
<string name="main_activity_settings">Configurações</string>
<string name="main_activity_settings_listening_address">Endereço de escuta</string>
<string name="main_activity_settings_port">Porta</string>
<string name="main_activity_settings_port_not_listening">Conexões de entrada desativadas</string>
<string name="main_activity_settings_password">Senha</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<resources>
<string name="main_activity_title">droidVNC-NG管理面板</string>
<string name="main_activity_settings">设置</string>
<string name="main_activity_settings_listening_address">監聽地址</string>
<string name="main_activity_settings_port">端口</string>
<string name="main_activity_settings_port_not_listening">禁用传入连接</string>
<string name="main_activity_settings_password">密码</string>
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<resources>
<string name="app_name" translatable="false">droidVNC-NG</string>
<string name="settings_listen_interface_hint" translatable="false">0.0.0.0</string>
<string name="main_activity_title">droidVNC-NG Admin Panel</string>
<string name="main_activity_settings">Settings</string>
<string name="main_activity_settings_listening_address">Listening Address</string>
<string name="main_activity_settings_port">Port</string>
<string name="main_activity_settings_port_not_listening">Inbound connections disabled</string>
<string name="main_activity_settings_password">Password</string>
Expand Down

0 comments on commit ac90fb2

Please sign in to comment.