Skip to content

Commit dd15796

Browse files
committed
Made port scanner multi threaded
1 parent 92af34a commit dd15796

File tree

3 files changed

+112
-26
lines changed

3 files changed

+112
-26
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ protected void onCreate(Bundle savedInstanceState) {
4444

4545
InetAddress ipAddress = IPTools.getLocalIPv4Address();
4646
if (ipAddress != null){
47-
editIpAddress.setText(ipAddress.toString());
47+
editIpAddress.setText(ipAddress.getHostAddress());
4848
}
4949

5050
findViewById(R.id.pingButton).setOnClickListener(new View.OnClickListener() {
@@ -198,8 +198,10 @@ private void doPortScan() throws Exception {
198198
appendResultsText("PortScanning IP: " + ipAddress);
199199
ArrayList<Integer> openPorts = PortScan.onAddress(ipAddress).setPort(21).doScan();
200200

201+
final long startTimeMillis = System.currentTimeMillis();
202+
201203
// Perform an asynchronous port scan
202-
PortScan.onAddress(ipAddress).setTimeOutMillis(1000).setPortsAll().doScan(new PortScan.PortListener() {
204+
PortScan.onAddress(ipAddress).setTimeOutMillis(1000).setPortsAll().setNoThreads(50).doScan(new PortScan.PortListener() {
203205
@Override
204206
public void onResult(int portNo, boolean open) {
205207
if (open) appendResultsText("Open: " + portNo);
@@ -208,6 +210,7 @@ public void onResult(int portNo, boolean open) {
208210
@Override
209211
public void onFinished(ArrayList<Integer> openPorts) {
210212
appendResultsText("Open Ports: " + openPorts.size());
213+
appendResultsText("Time Taken: " + ((System.currentTimeMillis() - startTimeMillis)/1000.0f));
211214
}
212215
});
213216

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

Lines changed: 105 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
package com.stealthcopter.networktools;
22

33
import android.support.annotation.NonNull;
4+
import android.support.annotation.Nullable;
45

56
import com.stealthcopter.networktools.portscanning.PortScanTCP;
67

78
import java.net.InetAddress;
89
import java.net.UnknownHostException;
910
import java.util.ArrayList;
11+
import java.util.Collections;
12+
import java.util.concurrent.ExecutorService;
13+
import java.util.concurrent.Executors;
14+
import java.util.concurrent.TimeUnit;
1015

1116
/**
1217
* Created by mat on 14/12/15.
1318
*/
1419
public class PortScan {
1520

21+
private int noThreads = 50;
22+
private InetAddress address;
23+
private int timeOutMillis = 1000;
24+
private boolean cancelled = false;
25+
private ArrayList<Integer> ports = new ArrayList<>();
26+
private ArrayList<Integer> openPortsFound = new ArrayList<>();
27+
28+
@Nullable
29+
private PortListener portListener;
30+
1631
// This class is not to be instantiated
1732
private PortScan() {
1833
}
@@ -22,11 +37,6 @@ public interface PortListener{
2237
void onFinished(ArrayList<Integer> openPorts);
2338
}
2439

25-
private InetAddress address;
26-
private int timeOutMillis = 1000;
27-
private boolean cancelled = false;
28-
private ArrayList<Integer> ports = new ArrayList<>();
29-
3040
/**
3141
* Set the address to ping
3242
* @param address - Address to be pinged
@@ -54,8 +64,18 @@ public static PortScan onAddress(@NonNull InetAddress ia) {
5464
}
5565

5666
/**
57-
* Set the timeout
67+
* Sets the timeout for each port scanned
68+
*
69+
* If you raise the timeout you may want to consider increasing the thread count {@link #setNoThreads(int)} to compensate.
70+
* We can afford to have quite a high thread count as most of the time the thread is just sitting
71+
* idle and waiting for the socket to timeout.
72+
*
5873
* @param timeOutMillis - the timeout for each ping in milliseconds
74+
* Recommendations:
75+
* Local host: 20 - 500 ms - can be very fast as request doesn't need to go over network
76+
* Local network 500 - 2500 ms
77+
* Remote Scan 2500+ ms
78+
*
5979
* @return this object to allow chaining
6080
*/
6181
public PortScan setTimeOutMillis(int timeOutMillis){
@@ -172,6 +192,20 @@ private void setAddress(InetAddress address) {
172192
this.address = address;
173193
}
174194

195+
196+
/**
197+
*
198+
* @param noThreads set the number of threads to work with, note we default to a large number
199+
* as these requests are network heavy not cpu heavy.
200+
* @return self
201+
* @throws IllegalAccessException - if no threads is less than 1
202+
*/
203+
public PortScan setNoThreads(int noThreads) throws IllegalAccessException {
204+
if (noThreads < 1) throw new IllegalArgumentException("Cannot have less than 1 thread");
205+
this.noThreads = noThreads;
206+
return this;
207+
}
208+
175209
/**
176210
* Cancel a running ping
177211
*/
@@ -180,23 +214,34 @@ public void cancel() {
180214
}
181215

182216
/**
183-
* Perform a synchrnous port scan and return a list of open ports
217+
* Perform a synchronous port scan and return a list of open ports
184218
* @return - ping result
185219
*/
186220
public ArrayList<Integer> doScan(){
187221

188222
cancelled = false;
223+
openPortsFound.clear();
189224

190-
ArrayList<Integer> openPorts = new ArrayList<>();
225+
ExecutorService executor = Executors.newFixedThreadPool(noThreads);
191226

192227
for (int portNo : ports) {
193-
if (PortScanTCP.scanAddress(address, portNo, timeOutMillis)){
194-
openPorts.add(portNo);
195-
}
196-
if (cancelled) break;
228+
Runnable worker = new PortScanRunnable(address, portNo, timeOutMillis);
229+
executor.execute(worker);
230+
}
231+
232+
// This will make the executor accept no new threads
233+
// and finish all existing threads in the queue
234+
executor.shutdown();
235+
// Wait until all threads are finish
236+
try {
237+
executor.awaitTermination(1, TimeUnit.HOURS);
238+
} catch (InterruptedException e) {
239+
e.printStackTrace();
197240
}
198241

199-
return openPorts;
242+
Collections.sort(openPortsFound);
243+
244+
return openPortsFound;
200245
}
201246

202247
/**
@@ -206,23 +251,34 @@ public ArrayList<Integer> doScan(){
206251
*/
207252
public PortScan doScan(final PortListener portListener){
208253

254+
this.portListener = portListener;
255+
openPortsFound.clear();
256+
cancelled = false;
257+
209258
new Thread(new Runnable() {
210259
@Override
211260
public void run() {
212-
cancelled = false;
213261

214-
ArrayList<Integer> openPorts = new ArrayList<>();
262+
ExecutorService executor = Executors.newFixedThreadPool(noThreads);
263+
215264
for (int portNo : ports) {
216-
boolean open = PortScanTCP.scanAddress(address, portNo, 1000);
217-
if (portListener!=null){
218-
portListener.onResult(portNo, open);
219-
if (open) openPorts.add(portNo);
220-
}
221-
if (cancelled) break;
265+
Runnable worker = new PortScanRunnable(address, portNo, timeOutMillis);
266+
executor.execute(worker);
267+
}
268+
269+
// This will make the executor accept no new threads
270+
// and finish all existing threads in the queue
271+
executor.shutdown();
272+
// Wait until all threads are finish
273+
try {
274+
executor.awaitTermination(1, TimeUnit.HOURS);
275+
} catch (InterruptedException e) {
276+
e.printStackTrace();
222277
}
223278

224279
if (portListener!=null){
225-
portListener.onFinished(openPorts);
280+
Collections.sort(openPortsFound);
281+
portListener.onFinished(openPortsFound);
226282
}
227283

228284
}
@@ -231,5 +287,32 @@ public void run() {
231287
return this;
232288
}
233289

290+
private synchronized void portScanned(int port, boolean open){
291+
if (open){
292+
openPortsFound.add(port);
293+
}
294+
if (portListener != null) {
295+
portListener.onResult(port, open);
296+
}
297+
}
298+
299+
private class PortScanRunnable implements Runnable {
300+
private final InetAddress address;
301+
private final int portNo;
302+
private final int timeOutMillis;
303+
304+
PortScanRunnable(InetAddress address, int portNo, int timeOutMillis) {
305+
this.address = address;
306+
this.portNo = portNo;
307+
this.timeOutMillis = timeOutMillis;
308+
}
309+
310+
@Override
311+
public void run() {
312+
if (cancelled) return;
313+
portScanned(portNo, PortScanTCP.scanAddress(address, portNo, timeOutMillis));
314+
}
315+
}
316+
234317

235318
}

scripts/decrypt-secrets.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
# Following this guide to encrypt / decrypt files
44
# https://github.com/circleci/encrypted-files
55

6-
# Encrypted using openssl 1.1.0g
6+
# Encrypted using openssl 1.1.0g /usr/local/bin/openssl
77

88
# Encrypt
99
#openssl aes-256-cbc -e -in key.p12 -out .circleci/key.p12.enc -k $ANDROID_NETWORK_TOOLS_DECRYPTKEY1
1010

1111
# Decrypt
1212
openssl aes-256-cbc -d -in .circleci/key.p12.enc -out key.p12 -k $ANDROID_NETWORK_TOOLS_DECRYPTKEY1
13-
openssl aes-256-cbc -d -in .circleci/keystore.enc -out keystore -k $ANDROID_NETWORK_TOOLS_DECRYPTKEY2
13+
openssl aes-256-cbc -d -in .circleci/keystore.enc -out keystore -k $ANDROID_NETWORK_TOOLS_DECRYPTKEY2

0 commit comments

Comments
 (0)