Skip to content

Commit f9ef4a5

Browse files
Merge pull request #21 from stealthcopter/feature/develop
Feature/develop
2 parents ad97603 + 7eabe56 commit f9ef4a5

28 files changed

+848
-187
lines changed

.circleci/config.yml

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@ jobs:
3131
name: Run Tests
3232
command: ./gradlew test
3333

34-
- store_artifacts:
35-
path: app/build/reports
36-
destination: reports
34+
#- store_test_results:
35+
#path: app/build/reports
36+
#destination: reports
3737

3838
- store_test_results:
39-
path: app/build/test-results
39+
name: Save Libary Unit Tests
40+
path: library/build/reports
41+
destination: reports
4042

4143
# Compile release apks
4244
- run:
@@ -58,7 +60,12 @@ jobs:
5860
name: Save APK Files
5961
path: /tmp/artifacts
6062
destination: build
61-
63+
64+
# Publish release to github if applicable
65+
- run:
66+
name: Publish release to Github
67+
command: scripts/github-release.sh
68+
6269
# Upload to beta if requested and then publish webhooks
6370
- run:
6471
name: Publish to Google Play

.circleci/keystore.enc

2.14 KB
Binary file not shown.

app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ android {
3030
applicationId "com.stealthcotper.networktools"
3131
minSdkVersion minSdkVer
3232
targetSdkVersion targetSdkVer
33-
versionCode 8
34-
versionName "0.1.12"
33+
versionCode 10
34+
versionName "0.3.0"
3535
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
3636
}
3737

app/src/main/java/com/stealthcotper/networktools/MainActivity.java

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@
1414
import android.widget.TextView;
1515

1616
import com.stealthcopter.networktools.ARPInfo;
17+
import com.stealthcopter.networktools.IPTools;
1718
import com.stealthcopter.networktools.Ping;
1819
import com.stealthcopter.networktools.PortScan;
20+
import com.stealthcopter.networktools.SubnetDevices;
1921
import com.stealthcopter.networktools.WakeOnLan;
2022
import com.stealthcopter.networktools.ping.PingResult;
2123
import com.stealthcopter.networktools.ping.PingStats;
24+
import com.stealthcopter.networktools.subnet.Device;
2225

2326
import java.io.IOException;
27+
import java.net.InetAddress;
2428
import java.util.ArrayList;
2529

2630
public class MainActivity extends AppCompatActivity {
@@ -38,6 +42,11 @@ protected void onCreate(Bundle savedInstanceState) {
3842
resultText = (TextView) findViewById(R.id.resultText);
3943
editIpAddress = (EditText) findViewById(R.id.editIpAddress);
4044

45+
InetAddress ipAddress = IPTools.getLocalIPv4Address();
46+
if (ipAddress != null){
47+
editIpAddress.setText(ipAddress.getHostAddress());
48+
}
49+
4150
findViewById(R.id.pingButton).setOnClickListener(new View.OnClickListener() {
4251
@Override
4352
public void onClick(View v) {
@@ -86,8 +95,23 @@ public void run() {
8695
}
8796
});
8897

89-
}
98+
findViewById(R.id.subnetDevicesButton).setOnClickListener(new View.OnClickListener() {
99+
@Override
100+
public void onClick(View v) {
101+
new Thread(new Runnable() {
102+
@Override
103+
public void run() {
104+
try {
105+
findSubnetDevices();
106+
} catch (Exception e) {
107+
e.printStackTrace();
108+
}
109+
}
110+
}).start();
111+
}
112+
});
90113

114+
}
91115

92116
private void appendResultsText(final String text) {
93117
runOnUiThread(new Runnable() {
@@ -146,7 +170,7 @@ private void doWakeOnLan() throws IllegalArgumentException {
146170
String macAddress = ARPInfo.getMACFromIPAddress(ipAddress);
147171

148172
if (macAddress == null) {
149-
appendResultsText("Could not find MAC address, cannot send WOL packet without it.");
173+
appendResultsText("Could not fromIPAddress MAC address, cannot send WOL packet without it.");
150174
return;
151175
}
152176

@@ -174,8 +198,10 @@ private void doPortScan() throws Exception {
174198
appendResultsText("PortScanning IP: " + ipAddress);
175199
ArrayList<Integer> openPorts = PortScan.onAddress(ipAddress).setPort(21).doScan();
176200

201+
final long startTimeMillis = System.currentTimeMillis();
202+
177203
// Perform an asynchronous port scan
178-
PortScan.onAddress(ipAddress).setTimeOutMillis(1000).setPortsAll().doScan(new PortScan.PortListener() {
204+
PortScan.onAddress(ipAddress).setPortsAll().doScan(new PortScan.PortListener() {
179205
@Override
180206
public void onResult(int portNo, boolean open) {
181207
if (open) appendResultsText("Open: " + portNo);
@@ -184,12 +210,35 @@ public void onResult(int portNo, boolean open) {
184210
@Override
185211
public void onFinished(ArrayList<Integer> openPorts) {
186212
appendResultsText("Open Ports: " + openPorts.size());
213+
appendResultsText("Time Taken: " + ((System.currentTimeMillis() - startTimeMillis)/1000.0f));
187214
}
188215
});
189216

217+
}
218+
219+
220+
private void findSubnetDevices() {
221+
222+
final long startTimeMillis = System.currentTimeMillis();
223+
224+
SubnetDevices.fromLocalAddress().findDevices(new SubnetDevices.OnSubnetDeviceFound() {
225+
@Override
226+
public void onDeviceFound(Device device) {
227+
appendResultsText("Device: " + device.ip+" "+ device.hostname);
228+
}
229+
230+
@Override
231+
public void onFinished(ArrayList<Device> devicesFound) {
232+
float timeTaken = (System.currentTimeMillis() - startTimeMillis)/1000.0f;
233+
appendResultsText("Devices Found: " + devicesFound.size());
234+
appendResultsText("Finished "+timeTaken+" s");
235+
}
236+
});
190237

191238
}
192239

240+
241+
193242
@Override
194243
public boolean onCreateOptionsMenu(Menu menu) {
195244
MenuInflater inflater = getMenuInflater();

app/src/main/res/layout/content_main.xml

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@
3636
android:layout_width="match_parent"
3737
android:layout_height="wrap_content"
3838
android:hint="@string/hint_ip_address"
39-
android:inputType="textNoSuggestions"
40-
android:text="192.168.0.1"/>
39+
android:inputType="textNoSuggestions"/>
4140
</android.support.design.widget.TextInputLayout>
4241

4342
<LinearLayout
@@ -47,8 +46,9 @@
4746

4847
<Button
4948
android:id="@+id/pingButton"
50-
android:layout_width="wrap_content"
49+
android:layout_width="0dp"
5150
android:layout_height="wrap_content"
51+
android:layout_weight="1"
5252
android:text="@string/ping"
5353
/>
5454

@@ -60,12 +60,27 @@
6060
/>
6161
<Button
6262
android:id="@+id/portScanButton"
63-
android:layout_width="wrap_content"
63+
android:layout_width="0dp"
6464
android:layout_height="wrap_content"
65+
android:layout_weight="1"
6566
android:text="@string/port_scan"
6667
/>
6768
</LinearLayout>
6869

70+
<LinearLayout
71+
android:layout_width="match_parent"
72+
android:layout_height="wrap_content"
73+
android:orientation="horizontal">
74+
75+
<Button
76+
android:id="@+id/subnetDevicesButton"
77+
android:layout_width="wrap_content"
78+
android:layout_height="wrap_content"
79+
android:text="@string/subnet"
80+
/>
81+
82+
</LinearLayout>
83+
6984
</LinearLayout>
7085

7186
<ScrollView

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
<string name="port_scan">Port Scan</string>
88
<string name="github_page">Github</string>
99
<string name="github_url">https://github.com/stealthcopter/AndroidNetworkTools</string>
10+
<string name="subnet">Subnet Devices</string>
1011
</resources>

library/build.gradle

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ android {
77
defaultConfig {
88
minSdkVersion minSdkVer
99
targetSdkVersion targetSdkVer
10-
versionCode 4
11-
versionName "0.2.2"
10+
versionCode 10
11+
versionName "0.3.0"
1212
}
1313
buildTypes {
1414
release {
@@ -19,8 +19,7 @@ android {
1919
}
2020

2121
dependencies {
22-
compile fileTree(dir: 'libs', include: ['*.jar'])
2322
testCompile 'junit:junit:4.12'
24-
testCompile 'org.mockito:mockito-core:1.9.5'
23+
testCompile 'org.mockito:mockito-core:1.10.19'
2524
provided 'com.android.support:appcompat-v7:24.2.0'
2625
}

library/src/main/java/com/stealthcopter/networktools/ARPInfo.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
/**
1313
* Created by mat on 09/12/15.
1414
* <p/>
15-
* Looks at the file at /proc/net/arp to find ip/mac addresses from the cache
15+
* Looks at the file at /proc/net/arp to fromIPAddress ip/mac addresses from the cache
1616
* We assume that the file has this structure:
1717
* <p/>
1818
* IP address HW type Flags HW address Mask Device
@@ -21,6 +21,11 @@
2121
*/
2222
public class ARPInfo {
2323

24+
// This class is not to be instantiated
25+
private ARPInfo() {
26+
}
27+
28+
2429
/**
2530
* Try to extract a hardware MAC address from a given IP address using the
2631
* ARP cache (/proc/net/arp).

library/src/main/java/com/stealthcopter/networktools/IPTools.java

Lines changed: 90 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
package com.stealthcopter.networktools;
22

3+
import android.support.annotation.Nullable;
4+
5+
import java.net.Inet4Address;
6+
import java.net.InetAddress;
7+
import java.net.NetworkInterface;
8+
import java.net.SocketException;
9+
import java.util.ArrayList;
10+
import java.util.Enumeration;
311
import java.util.regex.Pattern;
412

513
/**
614
* Created by mat on 14/12/15.
715
*/
816
public class IPTools {
917

10-
// public void findDevicesOnSubnet(){
11-
// // TODO: provide Ip address
12-
//
13-
// // TODO: Cheat by looking at ARP Cache for a headstart.
14-
//
15-
// // TODO: Ping devices on network
16-
//
17-
// // TODO Results.
18-
// }
19-
//
20-
// public void getLocalIpAddress(){
21-
//
22-
// }
18+
// This class is not to be instantiated
19+
private IPTools() {
20+
}
2321

2422

2523
/**
@@ -40,20 +38,91 @@ public class IPTools {
4038
Pattern.compile(
4139
"^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");
4240

43-
public static boolean isIPv4Address(final String input) {
44-
return IPV4_PATTERN.matcher(input).matches();
41+
public static boolean isIPv4Address(final String address) {
42+
return IPV4_PATTERN.matcher(address).matches();
43+
}
44+
45+
public static boolean isIPv6StdAddress(final String address) {
46+
return IPV6_STD_PATTERN.matcher(address).matches();
47+
}
48+
49+
public static boolean isIPv6HexCompressedAddress(final String address) {
50+
return IPV6_HEX_COMPRESSED_PATTERN.matcher(address).matches();
51+
}
52+
53+
public static boolean isIPv6Address(final String address) {
54+
return isIPv6StdAddress(address) || isIPv6HexCompressedAddress(address);
55+
}
56+
57+
/**
58+
* @return The first local IPv4 address, or null
59+
*/
60+
@Nullable
61+
public static InetAddress getLocalIPv4Address() {
62+
ArrayList<InetAddress> localAddresses = getLocalIPv4Addresses();
63+
return localAddresses.size() > 0 ? localAddresses.get(0) : null;
4564
}
4665

47-
public static boolean isIPv6StdAddress(final String input) {
48-
return IPV6_STD_PATTERN.matcher(input).matches();
66+
/**
67+
* @return The list of all IPv4 addresses found
68+
*/
69+
public static ArrayList<InetAddress> getLocalIPv4Addresses() {
70+
71+
ArrayList<InetAddress> foundAddresses = new ArrayList<>();
72+
73+
Enumeration<NetworkInterface> ifaces;
74+
try {
75+
ifaces = NetworkInterface.getNetworkInterfaces();
76+
77+
while (ifaces.hasMoreElements()) {
78+
NetworkInterface iface = ifaces.nextElement();
79+
Enumeration<InetAddress> addresses = iface.getInetAddresses();
80+
81+
while (addresses.hasMoreElements()) {
82+
InetAddress addr = addresses.nextElement();
83+
if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) {
84+
foundAddresses.add(addr);
85+
}
86+
}
87+
}
88+
} catch (SocketException e) {
89+
e.printStackTrace();
90+
}
91+
return foundAddresses;
4992
}
5093

51-
public static boolean isIPv6HexCompressedAddress(final String input) {
52-
return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
94+
95+
/**
96+
* Check if the provided ip address refers to the localhost
97+
*
98+
* https://stackoverflow.com/a/2406819/315998
99+
*
100+
* @param addr - address to check
101+
* @return - true if ip address is self
102+
*/
103+
public static boolean isIpAddressLocalhost(InetAddress addr) {
104+
// Check if the address is a valid special local or loop back
105+
if (addr.isAnyLocalAddress() || addr.isLoopbackAddress())
106+
return true;
107+
108+
// Check if the address is defined on any interface
109+
try {
110+
return NetworkInterface.getByInetAddress(addr) != null;
111+
} catch (SocketException e) {
112+
return false;
113+
}
53114
}
54115

55-
public static boolean isIPv6Address(final String input) {
56-
return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input);
116+
/**
117+
* Check if the provided ip address refers to the localhost
118+
*
119+
* https://stackoverflow.com/a/2406819/315998
120+
*
121+
* @param addr - address to check
122+
* @return - true if ip address is self
123+
*/
124+
public static boolean isIpAddressLocalNetwork(InetAddress addr) {
125+
return addr.isSiteLocalAddress();
57126
}
58127

59128

0 commit comments

Comments
 (0)