Add ability to select interface in root mode

Closes #110
This commit is contained in:
emanuele-f 2021-08-25 21:40:01 +02:00
parent 2d6cc8496d
commit 25f495335a
10 changed files with 89 additions and 2 deletions

View File

@ -584,6 +584,8 @@ public class CaptureService extends VpnService implements Runnable {
public int getAppFilterUid() { return(app_filter_uid); }
public String getCaptureInterface() { return(mSettings.capture_interface); }
public int getOwnAppUid() {
AppDescriptor app = AppsResolver.resolve(getPackageManager(), BuildConfig.APPLICATION_ID, 0);

View File

@ -37,6 +37,10 @@ import com.emanuelef.remote_capture.Utils;
import com.emanuelef.remote_capture.model.Prefs;
import com.emanuelef.remote_capture.R;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.regex.Matcher;
public class SettingsActivity extends BaseActivity {
@ -74,6 +78,7 @@ public class SettingsActivity extends BaseActivity {
private Preference mTlsHelp;
private Preference mProxyPrefs;
private Preference mIpv6Enabled;
private DropDownPreference mCapInterface;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@ -82,6 +87,7 @@ public class SettingsActivity extends BaseActivity {
setupUdpExporterPrefs();
setupHttpServerPrefs();
setupSocks5ProxyPrefs();
setupCapturePrefs();
setupOtherPrefs();
socks5ProxyHideShow(mTlsDecryptionEnabled.isChecked());
@ -117,6 +123,40 @@ public class SettingsActivity extends BaseActivity {
mHttpServerPort.setOnPreferenceChangeListener((preference, newValue) -> validatePort(newValue.toString()));
}
private void refreshInterfaces() {
ArrayList<String> labels = new ArrayList<>();
ArrayList<String> values = new ArrayList<>();
labels.add(getString(R.string.internet));
values.add("@inet");
labels.add(getString(R.string.all_interfaces));
values.add("any");
try {
Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
while (ifaces.hasMoreElements()) {
NetworkInterface iface = ifaces.nextElement();
if(!iface.isUp())
continue;
String name = iface.getName();
labels.add(name);
values.add(name);
}
} catch (SocketException e) {
e.printStackTrace();
}
mCapInterface.setEntryValues(values.toArray(new String[0]));
mCapInterface.setEntries(labels.toArray(new String[0]));
}
private void setupCapturePrefs() {
mCapInterface = findPreference(Prefs.PREF_CAPTURE_INTERFACE);
refreshInterfaces();
}
private void setupSocks5ProxyPrefs() {
mProxyPrefs = findPreference("proxy_prefs");
mTlsHelp = findPreference("tls_how_to");
@ -194,6 +234,7 @@ public class SettingsActivity extends BaseActivity {
private void rootCaptureHideShow(boolean enabled) {
mProxyPrefs.setVisible(!enabled);
mIpv6Enabled.setVisible(!enabled);
mCapInterface.setVisible(enabled);
}
}
}

View File

@ -74,6 +74,7 @@ public class StatusFragment extends Fragment implements AppStateListener, AppsLo
private Menu mMenu;
private MenuItem mMenuItemStartBtn;
private MenuItem mMenuSettings;
private TextView mInterfaceInfo;
private TextView mCollectorInfo;
private TextView mCaptureStatus;
private View mQuickSettings;
@ -140,6 +141,7 @@ public class StatusFragment extends Fragment implements AppStateListener, AppsLo
@SuppressLint("ClickableViewAccessibility")
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
mInterfaceInfo = view.findViewById(R.id.interface_info);
mCollectorInfo = view.findViewById(R.id.collector_info);
mCaptureStatus = view.findViewById(R.id.status_view);
mQuickSettings = view.findViewById(R.id.quick_settings);
@ -339,6 +341,7 @@ private void refreshPcapDumpInfo() {
mCaptureStatus.setText(R.string.ready);
mCollectorInfo.setVisibility(View.GONE);
mInterfaceInfo.setVisibility(View.GONE);
mQuickSettings.setVisibility(View.VISIBLE);
break;
case starting:
@ -358,6 +361,18 @@ private void refreshPcapDumpInfo() {
mCaptureStatus.setText(Utils.formatBytes(CaptureService.getBytes()));
mCollectorInfo.setVisibility(View.VISIBLE);
mQuickSettings.setVisibility(View.GONE);
if(CaptureService.isCapturingAsRoot()) {
CaptureService service = CaptureService.requireInstance();
String capiface = service.getCaptureInterface();
if(capiface.equals("@inet"))
capiface = getString(R.string.internet);
else if(capiface.equals("any"))
capiface = getString(R.string.all_interfaces);
mInterfaceInfo.setText(String.format(getResources().getString(R.string.capturing_from), capiface));
mInterfaceInfo.setVisibility(View.VISIBLE);
}
refreshPcapDumpInfo();
break;
default:

View File

@ -17,6 +17,7 @@ public class CaptureSettings implements Serializable {
public final boolean ipv6_enabled;
public final boolean root_capture;
public final boolean pcapdroid_trailer;
public final String capture_interface;
public CaptureSettings(SharedPreferences prefs) {
dump_mode = Prefs.getDumpMode(prefs);
@ -30,6 +31,7 @@ public class CaptureSettings implements Serializable {
ipv6_enabled = Prefs.getIPv6Enabled(prefs);
root_capture = Prefs.isRootCaptureEnabled(prefs);
pcapdroid_trailer = Prefs.isPcapdroidTrailerEnabled(prefs);
capture_interface = Prefs.getCaptureInterface(prefs);
}
public CaptureSettings(Intent intent) {
@ -44,6 +46,7 @@ public class CaptureSettings implements Serializable {
ipv6_enabled = intent.getBooleanExtra(Prefs.PREF_IPV6_ENABLED, false);
root_capture = intent.getBooleanExtra(Prefs.PREF_ROOT_CAPTURE, false);
pcapdroid_trailer = intent.getBooleanExtra(Prefs.PREF_PCAPDROID_TRAILER, false);
capture_interface = getString(intent, Prefs.PREF_CAPTURE_INTERFACE, "@inet");
}
private static String getString(Intent intent, String key, String def_value) {

View File

@ -31,6 +31,7 @@ public class Prefs {
public static final String PREF_COLLECTOR_PORT_KEY = "collector_port";
public static final String PREF_SOCKS5_PROXY_IP_KEY = "socks5_proxy_ip_address";
public static final String PREF_SOCKS5_PROXY_PORT_KEY = "socks5_proxy_port";
public static final String PREF_CAPTURE_INTERFACE = "capture_interface";
public static final String PREF_TLS_DECRYPTION_ENABLED_KEY = "tls_decryption_enabled";
public static final String PREF_APP_FILTER = "app_filter";
public static final String PREF_HTTP_SERVER_PORT = "http_server_port";
@ -75,4 +76,5 @@ public class Prefs {
public static boolean useEnglishLanguage(SharedPreferences p){ return("english".equals(p.getString(PREF_APP_LANGUAGE, "system")));}
public static boolean isRootCaptureEnabled(SharedPreferences p) { return(Utils.isRootAvailable() && p.getBoolean(PREF_ROOT_CAPTURE, false)); }
public static boolean isPcapdroidTrailerEnabled(SharedPreferences p) { return(p.getBoolean(PREF_PCAPDROID_TRAILER, false)); }
public static String getCaptureInterface(SharedPreferences p) { return(p.getString(PREF_CAPTURE_INTERFACE, "@inet")); }
}

View File

@ -111,9 +111,11 @@ static int connectPcapd(vpnproxy_data_t *proxy) {
int client = -1;
char bpf[256];
char workdir[PATH_MAX], pcapd[PATH_MAX];
char capture_interface[16];
getStringPref(proxy, "getPcapDumperBpf", bpf, sizeof(bpf));
getStringPref(proxy, "getPcapdWorkingDir", workdir, PATH_MAX);
getStringPref(proxy, "getCaptureInterface", capture_interface, sizeof(capture_interface));
get_libprog_path(proxy, "pcapd", pcapd, sizeof(pcapd));
if(!pcapd[0])
@ -157,7 +159,7 @@ static int connectPcapd(vpnproxy_data_t *proxy) {
// Start the daemon
char args[256];
snprintf(args, sizeof(args), "-l pcapd.log -d -u %d -b \"%s\"", proxy->app_filter, bpf);
snprintf(args, sizeof(args), "-l pcapd.log -i %s -d -u %d -b \"%s\"", capture_interface, proxy->app_filter, bpf);
su_cmd(pcapd, args);
// Wait for pcapd to start

View File

@ -24,10 +24,20 @@
android:drawablePadding="10dp"
tools:text="Collector Info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/status_view" />
<TextView
android:id="@+id/interface_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center"
tools:text="Capturing from eth0..."
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/collector_info" />
<TextView
android:id="@+id/status_view"
android:layout_width="210dp"

View File

@ -175,5 +175,9 @@
<string name="ctrl_consent_title">PCAPdroid Control Request</string>
<string name="ctrl_consent_denied">The control request was denied</string>
<string name="ctrl_consent_allowed">The control request was allowed</string>
<string name="capture_interface">Capture Interface</string>
<string name="internet">Internet</string>
<string name="all_interfaces">All Interfaces</string>
<string name="capturing_from">Capturing packets from \"%1$s\"</string>
</resources>

View File

@ -82,6 +82,13 @@
app:summary="@string/root_capture_summary"
app:defaultValue="false" />
<DropDownPreference
app:key="capture_interface"
app:title="@string/capture_interface"
app:iconSpaceReserved="false"
app:useSimpleSummaryProvider="true"
app:defaultValue="\@inet" />
<SwitchPreference
app:key="pcapdroid_trailer"
app:title="@string/pcapdroid_trailer"

View File

@ -81,3 +81,4 @@ As shown above, the capture settings can be specified by using intent extras. Th
| ipv6_enabled | bool | true to enable IPv6 support in non-root mode |
| root_capture | bool | true to capture packets in root mode, false to use the VPNService |
| pcapdroid_trailer | bool | true to enable the PCAPdroid trailer |
| capture_interface | string | @inet \| any \| ifname - network interface to use in root mode |