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 Jun 15, 2023
2 parents 09fdd36 + 4c42340 commit 9b8ee80
Show file tree
Hide file tree
Showing 53 changed files with 896 additions and 215 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/debug-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ jobs:
submodules: 'recursive'
- uses: actions/setup-java@v1
with:
java-version: '11'
java-version: '17'
- run: ./gradlew test
- run: ./gradlew assembleDebug -PdoNotStrip
2 changes: 1 addition & 1 deletion .github/workflows/windows-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ jobs:
submodules: 'recursive'
- uses: actions/setup-java@v1
with:
java-version: '11'
java-version: '17'
- run: ./gradlew.bat assembleDebug
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

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

## [1.6.4] - 2023-04-24
- Fix QR code activation crash on Android 32+
- Update translations

## [1.6.3] - 2023-04-23
- Add paid features activation via QR code for non-Play builds
- Fix firewall not working when loading duplicate domain rules
Expand Down
10 changes: 5 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ android {
applicationId "com.emanuelef.remote_capture"
minSdkVersion 21
targetSdkVersion 33
versionCode 65
versionName "1.6.3"
versionCode 66
versionName "1.6.4"

buildConfigField "long", "BUILD_TIME", System.currentTimeMillis() + "L"
}
Expand Down Expand Up @@ -75,20 +75,20 @@ dependencies {
// Tests
testImplementation 'junit:junit:4.13.2'
testImplementation 'androidx.test:core:1.5.0'
testImplementation "org.robolectric:robolectric:4.9"
testImplementation "org.robolectric:robolectric:4.10.3"

// AndroidX
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.fragment:fragment:1.5.5'
implementation 'androidx.fragment:fragment:1.5.7'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
implementation 'androidx.preference:preference:1.2.0'
implementation 'androidx.recyclerview:recyclerview:1.3.0'
implementation "androidx.navigation:navigation-fragment:2.5.3"
implementation "androidx.navigation:navigation-ui:2.5.3"

// Google
implementation 'com.google.android.material:material:1.8.0'
implementation 'com.google.android.material:material:1.9.0'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'org.brotli:dec:0.1.2'

Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/emanuelef/remote_capture/Billing.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ public class Billing {
R.string.firewall_summary, R.string.no_root_firewall,
R.string.unlock_token, R.string.unlock_token_summary, R.string.unlock_token_error,
R.string.license_service_unavailable, R.string.requesting_unlock_token, R.string.show_action, R.string.unlock_token_msg1,
R.string.license_limit_reached, R.string.license_error, R.string.requesting_license, R.string.license_activation_ok,
R.string.qr_license_confirm, R.string.qr_purchase_required
R.string.qr_license_confirm, R.string.qr_purchase_required, R.string.license_limit_reached,
R.string.license_error, R.string.requesting_license
};

protected final Context mContext;
Expand Down
25 changes: 13 additions & 12 deletions app/src/main/java/com/emanuelef/remote_capture/CaptureService.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public class CaptureService extends VpnService implements Runnable {
private Blocklist mBlocklist;
private MatchList mMalwareWhitelist;
private MatchList mFirewallWhitelist;
private MatchList mDecryptionWhitelist;
private MatchList mDecryptionList;
private SparseArray<String> mIfIndexToName;
private boolean mSocks5Enabled;
private String mSocks5Address;
Expand Down Expand Up @@ -383,9 +383,9 @@ else if(mSettings.dump_mode == Prefs.DumpMode.PCAP_FILE) {
}

if(mSettings.tls_decryption && !mSettings.root_capture)
mDecryptionWhitelist = PCAPdroid.getInstance().getDecryptionWhitelist();
mDecryptionList = PCAPdroid.getInstance().getDecryptionList();
else
mDecryptionWhitelist = null;
mDecryptionList = null;

if ((mSettings.app_filter != null) && (!mSettings.app_filter.isEmpty())) {
try {
Expand Down Expand Up @@ -424,10 +424,11 @@ else if(mSettings.dump_mode == Prefs.DumpMode.PCAP_FILE) {

// Route unicast IPv6 addresses
builder.addRoute("2000::", 3);
builder.addRoute("fc00::", 7);

try {
builder.addDnsServer(InetAddress.getByName(Prefs.getDnsServerV6(mPrefs)));
} catch (UnknownHostException e) {
} catch (UnknownHostException | IllegalArgumentException e) {
Log.w(TAG, "Could not set IPv6 DNS server");
}
}
Expand Down Expand Up @@ -1008,8 +1009,8 @@ public static boolean isDecryptingTLS() {
(INSTANCE.isTlsDecryptionEnabled() == 1));
}

public static boolean isDecryptionWhitelistEnabled() {
return(INSTANCE != null && (INSTANCE.mDecryptionWhitelist != null));
public static boolean isDecryptionListEnabled() {
return(INSTANCE != null && (INSTANCE.mDecryptionList != null));
}

public static Prefs.PayloadMode getCurPayloadMode() {
Expand Down Expand Up @@ -1350,8 +1351,8 @@ private void updateServiceStatus(ServiceStatus cur_status) {
if(cur_status == ServiceStatus.STARTED) {
if(mMalwareDetectionEnabled)
reloadMalwareWhitelist();
if(mDecryptionWhitelist != null)
reloadDecryptionWhitelist();
if(mDecryptionList != null)
reloadDecryptionList();
reloadBlocklist();
reloadFirewallWhitelist();
}
Expand Down Expand Up @@ -1445,12 +1446,12 @@ public static void reloadMalwareWhitelist() {
reloadMalwareWhitelist(INSTANCE.mMalwareWhitelist.toListDescriptor());
}

public static void reloadDecryptionWhitelist() {
if((INSTANCE == null) || (INSTANCE.mDecryptionWhitelist == null))
public static void reloadDecryptionList() {
if((INSTANCE == null) || (INSTANCE.mDecryptionList == null))
return;

Log.i(TAG, "reloading TLS decryption whitelist");
reloadDecryptionWhitelist(INSTANCE.mDecryptionWhitelist.toListDescriptor());
reloadDecryptionList(INSTANCE.mDecryptionList.toListDescriptor());
}

public static void setFirewallEnabled(boolean enabled) {
Expand Down Expand Up @@ -1509,7 +1510,7 @@ public static void waitForCaptureStop() {
private static native boolean reloadBlocklist(MatchList.ListDescriptor blocklist);
private static native boolean reloadFirewallWhitelist(MatchList.ListDescriptor whitelist);
private static native boolean reloadMalwareWhitelist(MatchList.ListDescriptor whitelist);
private static native boolean reloadDecryptionWhitelist(MatchList.ListDescriptor whitelist);
private static native boolean reloadDecryptionList(MatchList.ListDescriptor whitelist);
public static native void askStatsDump();
public static native byte[] getPcapHeader();
public static native void nativeSetFirewallEnabled(boolean enabled);
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/com/emanuelef/remote_capture/MitmAddon.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
import java.lang.ref.WeakReference;

public class MitmAddon {
public static final long PACKAGE_VERSION_CODE = 14;
public static final String PACKAGE_VERSION_NAME = "v0.14";
public static final long PACKAGE_VERSION_CODE = 15;
public static final String PACKAGE_VERSION_NAME = "v0.15";
public static final String REPOSITORY = "https://github.com/emanuele-f/PCAPdroid-mitm";
private static final String TAG = "MitmAddon";
private final Context mContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ private enum MsgType {
DATA_TRUNCATED,
MASTER_SECRET,
LOG,
JS_INJECTED
}

private static class PendingMessage {
Expand Down Expand Up @@ -319,9 +320,11 @@ private void handleMessage(ConnectionDescriptor conn, MsgType type, byte[] messa
// see ConnectionDescriptor.processUpdate
if(conn.status == ConnectionDescriptor.CONN_STATUS_CLOSED)
conn.status = ConnectionDescriptor.CONN_STATUS_CLIENT_ERROR;
} else if(type == MsgType.DATA_TRUNCATED)
} else if(type == MsgType.DATA_TRUNCATED) {
conn.setPayloadTruncatedByAddon();
else
} else if(type == MsgType.JS_INJECTED) {
conn.js_injected_scripts = new String(message, StandardCharsets.US_ASCII);
} else
conn.addPayloadChunkMitm(new PayloadChunk(message, getChunkType(type), isSent(type), tstamp));
}

Expand Down Expand Up @@ -380,6 +383,8 @@ private static MsgType parseMsgType(String str) {
return MsgType.MASTER_SECRET;
case "log":
return MsgType.LOG;
case "js_inject":
return MsgType.JS_INJECTED;
default:
return MsgType.UNKNOWN;
}
Expand Down
10 changes: 5 additions & 5 deletions app/src/main/java/com/emanuelef/remote_capture/PCAPdroid.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public class PCAPdroid extends Application {
private MatchList mVisMask;
private MatchList mMalwareWhitelist;
private MatchList mFirewallWhitelist;
private MatchList mDecryptionWhitelist;
private MatchList mDecryptionList;
private Blocklist mBlocklist;
private Blacklists mBlacklists;
private CtrlPermissions mCtrlPermissions;
Expand Down Expand Up @@ -154,11 +154,11 @@ public MatchList getFirewallWhitelist() {
return mFirewallWhitelist;
}

public MatchList getDecryptionWhitelist() {
if(mDecryptionWhitelist == null)
mDecryptionWhitelist = new MatchList(mLocalizedContext, Prefs.PREF_DECRYPTION_WHITELIST);
public MatchList getDecryptionList() {
if(mDecryptionList == null)
mDecryptionList = new MatchList(mLocalizedContext, Prefs.PREF_DECRYPTION_LIST);

return mDecryptionWhitelist;
return mDecryptionList;
}

public CtrlPermissions getCtrlPermissions() {
Expand Down
76 changes: 75 additions & 1 deletion app/src/main/java/com/emanuelef/remote_capture/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -1506,6 +1506,80 @@ public static boolean validatePort(String value) {
}
}

// from bouncycastle
private static boolean isValidIPv6(String address) {
if (address.length() == 0)
return false;

char firstChar = address.charAt(0);
if (firstChar != ':' && Character.digit(firstChar, 16) < 0)
return false;

int segmentCount = 0;
String temp = address + ":";
boolean doubleColonFound = false;

int pos = 0, end;
while (pos < temp.length() && (end = temp.indexOf(':', pos)) >= pos) {
if (segmentCount == 8)
return false;

if (pos != end) {
String value = temp.substring(pos, end);

if (end == temp.length() - 1 && value.indexOf('.') > 0) {
// add an extra one as address covers 2 words.
if (++segmentCount == 8)
return false;
if (!validateIpv4Address(value))
return false;
}
else if (!isParseableIPv6Segment(temp, pos, end))
return false;
} else {
if (end != 1 && end != temp.length() - 1 && doubleColonFound)
return false;
doubleColonFound = true;
}

pos = end + 1;
++segmentCount;
}

return segmentCount == 8 || doubleColonFound;
}

private static boolean isParseableIPv6Segment(String s, int pos, int end) {
return isParseable(s, pos, end, 16, 4, true, 0x0000, 0xFFFF);
}

private static boolean isParseable(String s, int pos, int end, int radix,
int maxLength, boolean allowLeadingZero,
int minValue, int maxValue) {
int length = end - pos;
if (length < 1 | length > maxLength)
return false;

boolean checkLeadingZero = length > 1 & !allowLeadingZero;
if (checkLeadingZero && Character.digit(s.charAt(pos), radix) <= 0)
return false;

int value = 0;
while (pos < end) {
char c = s.charAt(pos++);
int d = Character.digit(c, radix);
if (d < 0)
{
return false;
}

value *= radix;
value += d;
}

return value >= minValue & value <= maxValue;
}

@SuppressWarnings("deprecation")
public static boolean validateIpAddress(String value) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
Expand All @@ -1526,7 +1600,7 @@ public static boolean validateIpv4Address(String s) {
}

public static boolean validateIpv6Address(String s) {
return validateIpAddress(s) && !validateIpv4Address(s);
return isValidIPv6(s) && !validateIpv4Address(s);
}

// rough validation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,13 @@
import com.emanuelef.remote_capture.Billing;
import com.emanuelef.remote_capture.CaptureService;
import com.emanuelef.remote_capture.ConnectionsRegister;
import com.emanuelef.remote_capture.PCAPdroid;
import com.emanuelef.remote_capture.R;
import com.emanuelef.remote_capture.Utils;
import com.emanuelef.remote_capture.model.ConnectionDescriptor.Status;
import com.emanuelef.remote_capture.model.ConnectionDescriptor.DecryptionStatus;
import com.emanuelef.remote_capture.model.ConnectionDescriptor.FilteringStatus;
import com.emanuelef.remote_capture.model.FilterDescriptor;
import com.emanuelef.remote_capture.model.ListInfo;
import com.emanuelef.remote_capture.model.MatchList;
import com.emanuelef.remote_capture.model.Prefs;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
Expand Down Expand Up @@ -113,7 +111,6 @@ protected void onCreate(Bundle savedInstanceState) {
mDecChips = new ArrayList<>(Arrays.asList(
new Pair<>(DecryptionStatus.DECRYPTED, findViewById(R.id.dec_status_decrypted)),
new Pair<>(DecryptionStatus.NOT_DECRYPTABLE, findViewById(R.id.dec_status_not_decryptable)),
new Pair<>(DecryptionStatus.WHITELISTED, findViewById(R.id.dec_status_whitelisted)),
new Pair<>(DecryptionStatus.ERROR, findViewById(R.id.dec_status_error))
));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ protected void onResume() {

if(mNavView != null) {
Menu navMenu = mNavView.getMenu();
navMenu.findItem(R.id.dec_whitelist).setVisible(Prefs.getTlsDecryptionEnabled(mPrefs) && !Prefs.isRootCaptureEnabled(mPrefs));
navMenu.findItem(R.id.tls_decryption).setVisible(Prefs.getTlsDecryptionEnabled(mPrefs) && !Prefs.isRootCaptureEnabled(mPrefs));
}

checkPaidDrawerEntries();
Expand Down Expand Up @@ -503,9 +503,9 @@ public boolean onNavigationItemSelected(@NonNull MenuItem item) {
} else if (id == R.id.malware_detection) {
Intent intent = new Intent(MainActivity.this, MalwareDetection.class);
startActivity(intent);
} else if(id == R.id.dec_whitelist) {
} else if(id == R.id.tls_decryption) {
Intent intent = new Intent(MainActivity.this, EditListActivity.class);
intent.putExtra(EditListActivity.LIST_TYPE_EXTRA, ListInfo.Type.DECRYPTION_WHITELIST);
intent.putExtra(EditListActivity.LIST_TYPE_EXTRA, ListInfo.Type.DECRYPTION_LIST);
startActivity(intent);
} else if(id == R.id.firewall) {
Intent intent = new Intent(MainActivity.this, FirewallActivity.class);
Expand Down Expand Up @@ -642,9 +642,15 @@ public boolean onOptionsItemSelected(MenuItem item) {
private void initAppState() {
boolean is_active = CaptureService.isServiceActive();

if (!is_active)
if (!is_active) {
appStateReady();
else

// PCAPdroid could have been closed unexpectedly (e.g. due to low memory), try to export
// the keylog file if exists
mKeylogFile = MitmReceiver.getKeylogFilePath(MainActivity.this);
if(mKeylogFile.exists())
startExportSslkeylogfile();
} else
appStateRunning();
}

Expand Down Expand Up @@ -800,6 +806,13 @@ private void sslkeyfileExportResult(final ActivityResult result) {
Utils.showToastLong(this, R.string.export_failed);
}
}
mKeylogFile = null;

if(mKeylogFile != null) {
// upon closing the dialog, delete the keylog

//noinspection ResultOfMethodCallIgnored
mKeylogFile.delete();
mKeylogFile = null;
}
}
}
Loading

0 comments on commit 9b8ee80

Please sign in to comment.