Skip to content

Commit

Permalink
Merge branch 'master' into playstore
Browse files Browse the repository at this point in the history
  • Loading branch information
emanuele-f committed Mar 12, 2024
2 parents 0dcf8b6 + 9764809 commit 5ef3662
Show file tree
Hide file tree
Showing 33 changed files with 585 additions and 54 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/debug-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ jobs:
runs-on: ubuntu-latest
if: github.ref != 'refs/heads/playstore'
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: 'recursive'
- uses: actions/setup-java@v1

- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

- run: ./gradlew test
- run: ./gradlew assembleDebug -PdoNotStrip
4 changes: 2 additions & 2 deletions .github/workflows/gradle-wrapper-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ jobs:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
- uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v2
3 changes: 2 additions & 1 deletion .github/workflows/native-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: 'recursive'

- name: Run native tests
working-directory: ./app/src/main/jni/tests
run: make run_tests
7 changes: 5 additions & 2 deletions .github/workflows/windows-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ jobs:
runs-on: windows-latest
if: github.ref != 'refs/heads/playstore'
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: 'recursive'
- uses: actions/setup-java@v1

- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

- run: ./gradlew.bat assembleDebug
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

Releases available at https://github.com/emanuele-f/PCAPdroid/releases

## [1.7.0] - 2024-02-10
- Select multiple target apps
- Copy/export the connections payload
- Android 14 support
- mitmproxy 10.1.6 and Doze fix
- Ability to block QUIC only on decryption
- Fix decryption status for QUIC connections
- Fix inaccurate firewall grace period
- Integrations to run with Tor and DNSCrypt
- Use your own mitmproxy addons (experimental)
- Remove mitm-addon permission
- Show termux main app instead of its sub-apps
- Use ISO 8601 dates in CSV export

## [1.6.9] - 2023-12-04
- Fix root capture start on some devices
- Fix root permission incorrectly requested on read from pcap file
Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ android {
minSdkVersion 21
compileSdk 34
targetSdk 34
versionCode 72
versionName "1.6.9"
versionCode 73
versionName "1.7.0"

buildConfigField "long", "BUILD_TIME", System.currentTimeMillis() + "L"
}
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@
<action android:name="android.net.VpnService" />
</intent-filter>
</service>
<service
android:name=".VpnReconnectService"
android:foregroundServiceType="specialUse"
android:exported="false">

<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="waits for the termination of the active VpnService"/>
</service>

<receiver android:name="com.emanuelef.remote_capture.ActionReceiver" />

Expand Down
20 changes: 14 additions & 6 deletions app/src/main/java/com/emanuelef/remote_capture/Blacklists.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import android.content.Context;
import android.content.SharedPreferences;
import android.os.SystemClock;
import android.util.ArrayMap;

import androidx.collection.ArraySet;
Expand Down Expand Up @@ -56,7 +57,7 @@
*/
public class Blacklists {
public static final String PREF_BLACKLISTS_STATUS = "blacklists_status";
public static final int BLACKLISTS_UPDATE_SECONDS = 86400; // 1d
public static final long BLACKLISTS_UPDATE_MILLIS = 86400 * 1000; // 1d
private static final String TAG = "Blacklists";
private final ArrayList<BlacklistDescriptor> mLists = new ArrayList<>();
private final ArrayMap<String, BlacklistDescriptor> mListByFname = new ArrayMap<>();
Expand All @@ -66,11 +67,13 @@ public class Blacklists {
private boolean mUpdateInProgress;
private boolean mStopRequest;
private long mLastUpdate;
private long mLastUpdateMonotonic;
private int mNumDomainRules;
private int mNumIPRules;

public Blacklists(Context ctx) {
mLastUpdate = 0;
mLastUpdateMonotonic = -BLACKLISTS_UPDATE_MILLIS;
mNumDomainRules = 0;
mNumIPRules = 0;
mContext = ctx;
Expand Down Expand Up @@ -110,11 +113,15 @@ public void deserialize() {
String serialized = mPrefs.getString(PREF_BLACKLISTS_STATUS, "");
if(!serialized.isEmpty()) {
JsonObject obj = JsonParser.parseString(serialized).getAsJsonObject();

mLastUpdate = obj.getAsJsonPrimitive("last_update").getAsLong();
mNumDomainRules = obj.getAsJsonPrimitive("num_domain_rules").getAsInt();
mNumIPRules = obj.getAsJsonPrimitive("num_ip_rules").getAsInt();

// set the monotonic time based on the last update wall clock time
long millis_since_last_update = System.currentTimeMillis() - mLastUpdate;
if (millis_since_last_update > 0)
mLastUpdateMonotonic = SystemClock.elapsedRealtime() - millis_since_last_update;

JsonObject blacklists_obj = obj.getAsJsonObject("blacklists");
if(blacklists_obj != null) { // support old format
for(Map.Entry<String, JsonElement> bl_entry: blacklists_obj.entrySet()) {
Expand Down Expand Up @@ -179,7 +186,7 @@ private void checkFiles() {

if(!f.exists()) {
// must update
mLastUpdate = 0;
mLastUpdateMonotonic = -BLACKLISTS_UPDATE_MILLIS;
}
}

Expand All @@ -200,9 +207,9 @@ private void checkFiles() {
}

public boolean needsUpdate(boolean firstUpdate) {
long now = System.currentTimeMillis();
return((now - mLastUpdate) >= BLACKLISTS_UPDATE_SECONDS * 1000)
|| (firstUpdate && (getNumUpdatedBlacklists() < getNumBlacklists()));
long now = SystemClock.elapsedRealtime();
return (((now - mLastUpdateMonotonic) >= BLACKLISTS_UPDATE_MILLIS)
|| (firstUpdate && (getNumUpdatedBlacklists() < getNumBlacklists())));
}

// NOTE: invoked in a separate thread (CaptureService.mBlacklistsUpdateThread)
Expand Down Expand Up @@ -232,6 +239,7 @@ public void update() {
}

mLastUpdate = System.currentTimeMillis();
mLastUpdateMonotonic = SystemClock.elapsedRealtime();
notifyListeners();
}

Expand Down
56 changes: 34 additions & 22 deletions app/src/main/java/com/emanuelef/remote_capture/CaptureHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.VpnService;
import android.os.Handler;
Expand All @@ -33,6 +34,7 @@
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;

Expand All @@ -41,33 +43,40 @@

public class CaptureHelper {
private static final String TAG = "CaptureHelper";
private final ComponentActivity mActivity;
private final ActivityResultLauncher<Intent> mLauncher;
private final Context mContext;
private final @Nullable ActivityResultLauncher<Intent> mLauncher;
private final boolean mResolveHosts;
private CaptureSettings mSettings;
private CaptureStartListener mListener;

public CaptureHelper(ComponentActivity activity, boolean resolve_hosts) {
mActivity = activity;
mContext = activity;
mResolveHosts = resolve_hosts;
mLauncher = activity.registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(), this::captureServiceResult);
}

/** Note: This constructor does not handle the first-time VPN prepare */
public CaptureHelper(Context context) {
mContext = context;
mResolveHosts = true;
mLauncher = null;
}

private void captureServiceResult(final ActivityResult result) {
if(result.getResultCode() == Activity.RESULT_OK)
resolveHosts();
else if(mListener != null) {
Utils.showToastLong(mActivity, R.string.vpn_setup_failed);
Utils.showToastLong(mContext, R.string.vpn_setup_failed);
mListener.onCaptureStartResult(false);
}
}

private void startCaptureOk() {
final Intent intent = new Intent(mActivity, CaptureService.class);
final Intent intent = new Intent(mContext, CaptureService.class);
intent.putExtra("settings", mSettings);

ContextCompat.startForegroundService(mActivity, intent);
ContextCompat.startForegroundService(mContext, intent);
if(mListener != null)
mListener.onCaptureStartResult(true);
}
Expand Down Expand Up @@ -121,7 +130,7 @@ private void resolveHosts() {
if(failed_host == null)
startCaptureOk();
else {
Utils.showToastLong(mActivity, R.string.host_resolution_failed, failed_host);
Utils.showToastLong(mContext, R.string.host_resolution_failed, failed_host);
mListener.onCaptureStartResult(false);
}
});
Expand All @@ -139,23 +148,26 @@ public void startCapture(CaptureSettings settings) {
return;
}

Intent vpnPrepareIntent = VpnService.prepare(mActivity);
Intent vpnPrepareIntent = VpnService.prepare(mContext);
if(vpnPrepareIntent != null) {
new AlertDialog.Builder(mActivity)
.setMessage(R.string.vpn_setup_msg)
.setPositiveButton(R.string.ok, (dialog, whichButton) -> {
try {
mLauncher.launch(vpnPrepareIntent);
} catch (ActivityNotFoundException e) {
Utils.showToastLong(mActivity, R.string.no_intent_handler_found);
if (mLauncher != null)
new AlertDialog.Builder(mContext)
.setMessage(R.string.vpn_setup_msg)
.setPositiveButton(R.string.ok, (dialog, whichButton) -> {
try {
mLauncher.launch(vpnPrepareIntent);
} catch (ActivityNotFoundException e) {
Utils.showToastLong(mContext, R.string.no_intent_handler_found);
mListener.onCaptureStartResult(false);
}
})
.setOnCancelListener(dialog -> {
Utils.showToastLong(mContext, R.string.vpn_setup_failed);
mListener.onCaptureStartResult(false);
}
})
.setOnCancelListener(dialog -> {
Utils.showToastLong(mActivity, R.string.vpn_setup_failed);
mListener.onCaptureStartResult(false);
})
.show();
})
.show();
else if (mListener != null)
mListener.onCaptureStartResult(false);
} else
resolveHosts();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with PCAPdroid. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2020-21 - Emanuele Faranda
* Copyright 2020-24 - Emanuele Faranda
*/

package com.emanuelef.remote_capture;
Expand Down Expand Up @@ -112,6 +112,7 @@ public class CaptureService extends VpnService implements Runnable {
final Condition mCaptureStopped = mLock.newCondition();
private ParcelFileDescriptor mParcelFileDescriptor;
private boolean mIsAlwaysOnVPN;
private boolean mRevoked;
private SharedPreferences mPrefs;
private CaptureSettings mSettings;
private Billing mBilling;
Expand Down Expand Up @@ -236,6 +237,9 @@ public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
return abortStart();
}

if (VpnReconnectService.isAvailable())
VpnReconnectService.stopService();

mHandler = new Handler(Looper.getMainLooper());
mBilling = Billing.newInstance(this);

Expand Down Expand Up @@ -605,6 +609,7 @@ public void onReceive(Context context, Intent intent) {
@Override
public void onRevoke() {
Log.d(CaptureService.TAG, "onRevoke");
mRevoked = true;
stopService();
super.onRevoke();
}
Expand Down Expand Up @@ -1052,6 +1057,11 @@ public static boolean isReadingFromPcapFile() {
(INSTANCE.isPcapFileCapture() == 1));
}

public static boolean isIPv6Enabled() {
return((INSTANCE != null) &&
(INSTANCE.getIPv6Enabled() == 1));
}

public static boolean isDecryptionListEnabled() {
return(INSTANCE != null && (INSTANCE.mDecryptionList != null));
}
Expand Down Expand Up @@ -1404,6 +1414,15 @@ private void updateServiceStatus(ServiceStatus cur_status) {
reloadDecryptionList();
reloadBlocklist();
reloadFirewallWhitelist();
} else if (cur_status == ServiceStatus.STOPPED) {
if (mRevoked && Prefs.restartOnDisconnect(mPrefs) && !mIsAlwaysOnVPN && (isVpnCapture() == 1)) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
Log.i(TAG, "VPN disconnected, starting reconnect service");

final Intent intent = new Intent(this, VpnReconnectService.class);
ContextCompat.startForegroundService(this, intent);
}
}
}
}

Expand Down
Loading

0 comments on commit 5ef3662

Please sign in to comment.