Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronjwood committed Jan 2, 2020
2 parents 8ff1cef + ae1c33f commit 6c88686
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 73 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ jdk:
android:
components:
- tools
- build-tools-27.0.2
- android-27
- build-tools-28.0.3
- android-29
- extra-android-m2repository

env:
Expand Down
17 changes: 8 additions & 9 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ sonarqube {
}

android {
compileSdkVersion 27
buildToolsVersion '27.0.2'
compileSdkVersion 29
buildToolsVersion '28.0.3'

defaultConfig {
minSdkVersion 14
targetSdkVersion 27
versionCode 55
versionName "2.2.8"
targetSdkVersion 29
versionCode 56
versionName "2.2.10"
applicationId "com.aaronjwood.portauthority"
setProperty("archivesBaseName", "PortAuthority-$versionName")
}
Expand Down Expand Up @@ -65,12 +65,11 @@ android {
}

dependencies {
compile 'com.android.support:support-v4:27.0.2'
compile 'com.android.support:appcompat-v7:27.0.2'
compile 'com.squareup.okhttp3:okhttp:3.9.1'
compile 'com.android.support:support-v4:28.0.0'
compile 'com.android.support:appcompat-v7:28.0.0'
compile 'com.squareup.okhttp3:okhttp:3.10.0'
compile 'jcifs:jcifs:1.3.17'
compile 'dnsjava:dnsjava:2.1.7'
//This does absolutely nothing
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
testCompile 'junit:junit:4.12'
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!-- Needed to read the SSID on Android 8+. -->
<uses-permission android:name="android.permission.INTERNET" />

<application
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public abstract class HostActivity extends AppCompatActivity implements HostAsyn
protected int layout;
protected ArrayAdapter<String> adapter;
protected ListView portList;
protected final List<String> ports = Collections.synchronizedList(new ArrayList<String>());
protected final List<String> ports = Collections.synchronizedList(new ArrayList<>());
protected ProgressDialog scanProgressDialog;
protected Dialog portRangeDialog;
protected Handler handler;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.aaronjwood.portauthority.activity;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
Expand All @@ -9,13 +11,17 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.sqlite.SQLiteException;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
Expand Down Expand Up @@ -62,6 +68,7 @@
public final class MainActivity extends AppCompatActivity implements MainAsyncResponse {

private final static int TIMER_INTERVAL = 1500;
private final static int COARSE_LOCATION_REQUEST = 1;

private Wireless wifi;
private ListView hostList;
Expand All @@ -78,7 +85,7 @@ public final class MainActivity extends AppCompatActivity implements MainAsyncRe
private Handler scanHandler;
private IntentFilter intentFilter = new IntentFilter();
private HostAdapter hostAdapter;
private List<Host> hosts = Collections.synchronizedList(new ArrayList<Host>());
private List<Host> hosts = Collections.synchronizedList(new ArrayList<>());
private Database db;
private DownloadAsyncTask ouiTask;
private DownloadAsyncTask portTask;
Expand Down Expand Up @@ -123,16 +130,40 @@ protected void onCreate(Bundle savedInstanceState) {
discoverHostsBtn = findViewById(R.id.discoverHosts);
discoverHostsStr = getResources().getString(R.string.hostDiscovery);

wifi = new Wireless(getApplicationContext());
Context context = getApplicationContext();
wifi = new Wireless(context);
scanHandler = new Handler(Looper.getMainLooper());

checkDatabase();
db = Database.getInstance(getApplicationContext());
db = Database.getInstance(context);

setupHostsAdapter();
setupDrawer();
setupHostDiscovery();

// Android 8+ now require this permission to read the SSID.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!UserPreference.getLocationPermDiag(context)) {
Activity activity = this;
new AlertDialog.Builder(activity, R.style.DialogTheme).setTitle("SSID Access")
.setMessage("Android 8+ now requires location permissions to read the SSID. " +
"If this is not something you're comfortable with just deny the request and go without the functionality.")
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
UserPreference.saveLocationPermDiag(context);
if (ContextCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
COARSE_LOCATION_REQUEST);
}
}
})
.setIcon(android.R.drawable.ic_dialog_alert).show().setCanceledOnTouchOutside(false);
}
}

intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
}

Expand Down Expand Up @@ -455,7 +486,7 @@ public void run() {
Errors.showError(context, resources.getString(R.string.failedSignal));
return;
}

signalStrength.setText(String.format(resources.getString(R.string.signalLink), signal, speed));
signalHandler.postDelayed(this, TIMER_INTERVAL);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.aaronjwood.portauthority.async;

import android.os.AsyncTask;
import android.os.Build;
import android.util.Pair;

import com.aaronjwood.portauthority.db.Database;
import com.aaronjwood.portauthority.network.Host;
Expand All @@ -16,6 +18,8 @@
import java.lang.ref.WeakReference;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
Expand All @@ -27,6 +31,9 @@ public class ScanHostsAsyncTask extends AsyncTask<Integer, Void, Void> {
private final WeakReference<MainAsyncResponse> delegate;
private Database db;
private static final String ARP_TABLE = "/proc/net/arp";
private static final String IP_CMD = "ip neighbor";
private static final String NEIGHBOR_INCOMPLETE = "INCOMPLETE";
private static final String NEIGHBOR_FAILED = "FAILED";
private static final String ARP_INCOMPLETE = "0x0";
private static final String ARP_INACTIVE = "00:00:00:00:00:00";
private static final int NETBIOS_FILE_SERVER = 0x20;
Expand All @@ -51,14 +58,38 @@ protected Void doInBackground(Integer... params) {
int ipv4 = params[0];
int cidr = params[1];
int timeout = params[2];

MainAsyncResponse activity = delegate.get();
File file = new File(ARP_TABLE);
if (!file.exists() || !file.canRead()) {
activity.processFinish(new FileNotFoundException("Unable to access device ARP table"));
activity.processFinish(true);

return null;
// Android 10+ doesn't let us access the ARP table.
// Do an early check to see if we can get what we need from the system.
// https://developer.android.com/about/versions/10/privacy/changes#proc-net-filesystem
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
try {
Process ipProc = Runtime.getRuntime().exec(IP_CMD);
ipProc.waitFor();
if (ipProc.exitValue() != 0) {
activity.processFinish(new IOException("Unable to access ARP entries"));
activity.processFinish(true);

return null;
}
} catch (IOException | InterruptedException e) {
activity.processFinish(new IOException("Unable to parse ARP entries"));
activity.processFinish(true);
}
} else {
File file = new File(ARP_TABLE);
if (!file.exists()) {
activity.processFinish(new FileNotFoundException("Unable to find ARP table"));
activity.processFinish(true);

return null;
}

if (!file.canRead()) {
activity.processFinish(new IOException("Unable to read ARP table"));
activity.processFinish(true);
}
}

ExecutorService executor = Executors.newCachedThreadPool();
Expand Down Expand Up @@ -107,63 +138,103 @@ protected final void onProgressUpdate(Void... params) {
final MainAsyncResponse activity = delegate.get();
ExecutorService executor = Executors.newCachedThreadPool();
final AtomicInteger numHosts = new AtomicInteger(0);
List<Pair<String, String>> pairs = new ArrayList<>();

try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(ARP_TABLE), "UTF-8"));
reader.readLine(); // Skip header.
String line;

while ((line = reader.readLine()) != null) {
String[] arpLine = line.split("\\s+");

final String ip = arpLine[0];
final String flag = arpLine[2];
final String macAddress = arpLine[3];

if (!ARP_INCOMPLETE.equals(flag) && !ARP_INACTIVE.equals(macAddress)) {
numHosts.incrementAndGet();
executor.execute(new Runnable() {

@Override
public void run() {
Host host;
try {
host = new Host(ip, macAddress, db);
} catch (IOException e) {
host = new Host(ip, macAddress);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Process ipProc = Runtime.getRuntime().exec(IP_CMD);
ipProc.waitFor();
if (ipProc.exitValue() != 0) {
throw new Exception("Unable to access ARP entries");
}

MainAsyncResponse activity = delegate.get();
try {
InetAddress add = InetAddress.getByName(ip);
String hostname = add.getCanonicalHostName();
host.setHostname(hostname);
reader = new BufferedReader(new InputStreamReader(ipProc.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
String[] neighborLine = line.split("\\s+");

if (activity != null) {
activity.processFinish(host, numHosts);
}
} catch (UnknownHostException e) {
numHosts.decrementAndGet();
activity.processFinish(e);
return;
// We don't have a validated ARP entry for this case.
if (neighborLine.length <= 4) {
continue;
}

String ip = neighborLine[0];
InetAddress addr = InetAddress.getByName(ip);
if (addr.isLinkLocalAddress() || addr.isLoopbackAddress()) {
continue;
}

String macAddress = neighborLine[4];
String state = neighborLine[neighborLine.length - 1];

// Determine if the ARP entry is valid.
// https://github.com/sivasankariit/iproute2/blob/master/ip/ipneigh.c
if (!NEIGHBOR_FAILED.equals(state) && !NEIGHBOR_INCOMPLETE.equals(state)) {
pairs.add(new Pair<>(ip, macAddress));
}
}
} else {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(ARP_TABLE), "UTF-8"));
reader.readLine(); // Skip header.
String line;

while ((line = reader.readLine()) != null) {
String[] arpLine = line.split("\\s+");
String ip = arpLine[0];
String flag = arpLine[2];
String macAddress = arpLine[3];

if (!ARP_INCOMPLETE.equals(flag) && !ARP_INACTIVE.equals(macAddress)) {
pairs.add(new Pair<>(ip, macAddress));
}
}
}

numHosts.addAndGet(pairs.size());
for (Pair<String, String> pair : pairs) {
String ip = pair.first;
String macAddress = pair.second;
executor.execute(new Runnable() {

@Override
public void run() {
Host host;
try {
host = new Host(ip, macAddress, db);
} catch (IOException e) {
host = new Host(ip, macAddress);
}

MainAsyncResponse activity = delegate.get();
try {
InetAddress add = InetAddress.getByName(ip);
String hostname = add.getCanonicalHostName();
host.setHostname(hostname);

if (activity != null) {
activity.processFinish(host, numHosts);
}
} catch (UnknownHostException e) {
numHosts.decrementAndGet();
activity.processFinish(e);
return;
}

try {
NbtAddress[] netbios = NbtAddress.getAllByAddress(ip);
for (NbtAddress addr : netbios) {
if (addr.getNameType() == NETBIOS_FILE_SERVER) {
host.setHostname(addr.getHostName());
return;
}
try {
NbtAddress[] netbios = NbtAddress.getAllByAddress(ip);
for (NbtAddress addr : netbios) {
if (addr.getNameType() == NETBIOS_FILE_SERVER) {
host.setHostname(addr.getHostName());
return;
}
} catch (UnknownHostException e) {
// It's common that many discovered hosts won't have a NetBIOS entry.
}
} catch (UnknownHostException e) {
// It's common that many discovered hosts won't have a NetBIOS entry.
}
});
}
}
});
}
} catch (IOException e) {
} catch (Exception e) {
if (activity != null) {
activity.processFinish(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ protected Void doInBackground(String... params) {
String ip = params[1];

byte[] macBytes = new byte[6];
String[] macHex = mac.split("(:|-)");
String[] macHex = mac.split("([:\\-])");
for (int i = 0; i < 6; i++) {
macBytes[i] = (byte) Integer.parseInt(macHex[i], 16);
}
Expand Down
Loading

0 comments on commit 6c88686

Please sign in to comment.