* multiple requested ports are now supported

* preference added to use requested ports in PortsFetcher

git-svn-id: https://ipscan.svn.sourceforge.net/svnroot/ipscan/trunk@370 375186e5-ef17-0410-b0b6-91563547dcda
This commit is contained in:
angryziber 2008-04-06 17:56:39 +00:00
parent 412400f263
commit c822f91f7f
15 changed files with 236 additions and 78 deletions

1
TODO
View File

@ -1,6 +1,5 @@
Before 3.0:
* multiple requestedPort support, more docs
* save default selection of pinger (Combined for non-root users)
* command-line scanning start
* fetcher-specific options

View File

@ -192,7 +192,7 @@ fetcher.ping.ttl.info=Shows the TTL (Time To Live) value in ping reply packets (
fetcher.hostname=Hostname
fetcher.hostname.info=Shows the hostname of the host obtained by the reverse DNS lookup.\n\nThis is the registered host name on the DNS server and may be different from the host name configured on the machine itself.
fetcher.ports=Ports
fetcher.ports.info=Shows the list of open ports from the ones that were scanned.\n\nA port is open when it is possible to complete TCP handshake with it and estabilish a connection.\nYou can select scanned ports in the Preferences dialog.
fetcher.ports.info=Shows the list of open ports from the ones that were scanned.\n\nA port is open when it is possible to complete TCP handshake with it and estabilish a connection.\nYou can select scanned ports in the Preferences dialog.\n\nThe number in the column heading shows the current number of selected ports for scanning; '+' is shown if requested ports for each host are scanned as well.
fetcher.ports.filtered=Filtered Ports
fetcher.ports.filtered.info=Shows the list of filtered ports from the ones that were scanned.\n\nA port is filtered when no response is being received to the connection attempt within specified amount of time. If a port is filtered, then it is probably blocked by a firewall.
fetcher.comment=Comments
@ -222,6 +222,8 @@ preferences.ports.timing.adaptTimeout=Adapt timeout to ping roundtrip time (if a
preferences.ports.timing.minTimeout=Minimal adapted connect timeout (in ms):
preferences.ports.ports=Port selection
preferences.ports.portsDescription=Specify ports to scan here. Ranges are supported.\nExample: 1-3,5,7,10-15,6000-6100\nIf many ports are specified, scanning can take a lot of time.
preferences.ports.addRequested=For each host, add requested specific ports
preferences.ports.addRequested.info=Feeders may support specifying requested ports in addition to addresses (e.g. File Feeder, in form of address:port)\nThis allows for rescanning of exported IP:Port list files. Can be useful for HTTP proxy lists and such.\nChecking this will always scan each host's requested ports in addition to the common ports specified above.
preferences.display.list=Display in the results list
preferences.display.list.ALL=All scanned hosts
preferences.display.list.ALIVE=Alive hosts (responding to pings) only

View File

@ -27,6 +27,7 @@ public class ScannerConfig {
public boolean adaptPortTimeout;
public int minPortTimeout;
public String portString;
public boolean useRequestedPorts;
public String notAvailableText;
public String notScannedText;
@ -49,6 +50,7 @@ public class ScannerConfig {
adaptPortTimeout = preferences.getBoolean("adaptPortTimeout", !Platform.CRIPPLED_WINDOWS);
minPortTimeout = preferences.getInt("minPortTimeout", 100);
portString = preferences.get("portString", "");
useRequestedPorts = preferences.getBoolean("useRequestedPorts", true);
notAvailableText = preferences.get("notAvailableText", Labels.getLabel("fetcher.value.notAvailable"));
notScannedText = preferences.get("notScannedText", Labels.getLabel("fetcher.value.notScanned"));
}
@ -68,6 +70,7 @@ public class ScannerConfig {
preferences.putBoolean("adaptPortTimeout", adaptPortTimeout);
preferences.putInt("minPortTimeout", minPortTimeout);
preferences.put("portString", portString);
preferences.putBoolean("useRequestedPorts", useRequestedPorts);
preferences.put("notAvailableText", notAvailableText);
preferences.put("notScannedText", notScannedText);
}

View File

@ -5,6 +5,8 @@
*/
package net.azib.ipscan.core;
import java.util.Iterator;
/**
* A class for iteration of ports, specified in special format, like:
@ -12,7 +14,7 @@ package net.azib.ipscan.core;
*
* @author Anton Keks
*/
public final class PortIterator implements Cloneable {
public final class PortIterator implements Iterator<Integer>, Cloneable {
private int[] portRangeStart;
private int[] portRangeEnd;
@ -63,7 +65,7 @@ public final class PortIterator implements Cloneable {
/**
* @return next port number
*/
public int next() {
public Integer next() {
int returnPort = currentPort++;
if (currentPort > portRangeEnd[rangeIndex]) {
@ -98,5 +100,9 @@ public final class PortIterator implements Cloneable {
return null;
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}

View File

@ -6,7 +6,10 @@
package net.azib.ipscan.core;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.azib.ipscan.config.Config;
@ -30,8 +33,8 @@ public class ScanningSubject {
/** The address being scanned */
private InetAddress address;
/** The requested port that the user wishes to put more attention to, can be null. E.g. port 3128 for scanning of proxy servers. */
private Integer requestedPort;
/** The requested ports that the user wishes to put more attention to, can be null. E.g. port 3128 for scanning of proxy servers. */
private List<Integer> requestedPorts;
/** Arbitrary parameters for sharing among different (but related) Fetchers */
private Map<String, Object> parameters;
/** The result type constant value, can be modified by some Fetchers */
@ -106,18 +109,24 @@ public class ScanningSubject {
this.isAborted = true;
}
public boolean isAnyPortRequested() {
return requestedPorts != null;
}
/**
* @return the port that the user wishes to pay attention to, e.g. 3128 for proxies, or null.
* @return ports that the user wishes to pay attention to, e.g. 3128 for proxies, or null.
*/
public Integer getRequestedPort() {
return requestedPort;
public Iterator<Integer> requestedPortsIterator() {
return requestedPorts == null ? null : requestedPorts.iterator();
}
/**
* @param requestedPort the port that user wants to scan
*/
public void setRequestedPort(Integer requestedPort) {
this.requestedPort = requestedPort;
public void addRequestedPort(Integer requestedPort) {
if (requestedPorts == null)
requestedPorts = new ArrayList<Integer>();
requestedPorts.add(requestedPort);
}
/**
@ -142,7 +151,15 @@ public class ScanningSubject {
@Override
public String toString() {
return address.getHostAddress() + requestedPort != null ? ":" + requestedPort : "";
StringBuilder sb = new StringBuilder(address.getHostAddress());
if (requestedPorts != null) {
sb.append(':');
for (Integer port : requestedPorts)
sb.append(port).append(',');
if (sb.charAt(sb.length()-1) == ',')
sb.deleteCharAt(sb.length()-1);
}
return sb.toString();
}
}

View File

@ -13,8 +13,8 @@ import java.io.Reader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@ -37,7 +37,7 @@ public class FileFeeder extends AbstractFeeder {
static final Logger LOG = LoggerFactory.getLogger();
/** Found IP address Strings are put here */
private List<ScanningSubject> foundIPAddresses;
private Map<String, ScanningSubject> foundIPAddresses;
private Iterator<ScanningSubject> foundIPAddressesIterator;
private int currentIndex;
@ -66,23 +66,27 @@ public class FileFeeder extends AbstractFeeder {
BufferedReader fileReader = new BufferedReader(reader);
currentIndex = 0;
foundIPAddresses = new LinkedList<ScanningSubject>();
foundIPAddresses = new LinkedHashMap<String, ScanningSubject>();
try {
String fileLine;
while ((fileLine = fileReader.readLine()) != null) {
Matcher matcher = InetAddressUtils.IP_ADDRESS_REGEX.matcher(fileLine);
while (matcher.find()) {
try {
String address = matcher.group();
ScanningSubject subject = new ScanningSubject(InetAddress.getByName(address));
String address = matcher.group();
ScanningSubject subject = foundIPAddresses.get(address);
if (subject == null)
subject = new ScanningSubject(InetAddress.getByName(address));
if (!matcher.hitEnd() && fileLine.charAt(matcher.end()) == ':') {
// see if any valid port is requested
Matcher portMatcher = PORT_REGEX.matcher(fileLine.substring(matcher.end()+1));
if (portMatcher.lookingAt()) {
subject.setRequestedPort(Integer.valueOf(portMatcher.group()));
subject.addRequestedPort(Integer.valueOf(portMatcher.group()));
}
}
foundIPAddresses.add(subject);
foundIPAddresses.put(address, subject);
}
catch (UnknownHostException e) {
LOG.log(Level.WARNING, "malformedIP", e);
@ -100,12 +104,10 @@ public class FileFeeder extends AbstractFeeder {
try {
fileReader.close();
}
catch (IOException e) {
// ignore, what else to do?
}
catch (IOException e) {}
}
foundIPAddressesIterator = foundIPAddresses.iterator();
foundIPAddressesIterator = foundIPAddresses.values().iterator();
}
public int percentageComplete() {

View File

@ -13,6 +13,8 @@ import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Collections;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@ -45,45 +47,48 @@ public abstract class PortTextFetcher extends AbstractFetcher {
}
public Object scan(ScanningSubject subject) {
Socket socket = new Socket();
try {
// TODO: support multiple ports and check them sequentially
socket.connect(new InetSocketAddress(subject.getAddress(), subject.getRequestedPort() != null ? subject.getRequestedPort() : defaultPort), subject.getAdaptedPortTimeout());
socket.setTcpNoDelay(true);
socket.setSoTimeout(scannerConfig.portTimeout*2);
socket.setSoLinger(true, 0);
socket.getOutputStream().write(textToSend.getBytes());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
Matcher matcher = matchingRegexp.matcher(line);
if (matcher.find()) {
// mark that additional info is available
subject.setResultType(ResultType.WITH_PORTS);
// return the required contents
return matcher.group(1);
Iterator<Integer> portIterator = subject.isAnyPortRequested() ? subject.requestedPortsIterator() : Collections.singleton(defaultPort).iterator();
while (portIterator.hasNext() && !Thread.currentThread().isInterrupted()) {
Socket socket = new Socket();
try {
socket.connect(new InetSocketAddress(subject.getAddress(), portIterator.next()), subject.getAdaptedPortTimeout());
socket.setTcpNoDelay(true);
socket.setSoTimeout(scannerConfig.portTimeout*2);
socket.setSoLinger(true, 0);
socket.getOutputStream().write(textToSend.getBytes());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
Matcher matcher = matchingRegexp.matcher(line);
if (matcher.find()) {
// mark that additional info is available
subject.setResultType(ResultType.WITH_PORTS);
// return the required contents
return matcher.group(1);
}
}
}
}
catch (ConnectException e) {
// no connection
}
catch (SocketTimeoutException e) {
// no information
}
catch (SocketException e) {
// connection reset
}
catch (IOException e) {
LOG.log(Level.FINE, subject.getAddress().toString(), e);
}
finally {
try {
socket.close();
catch (ConnectException e) {
// no connection
}
catch (SocketTimeoutException e) {
// no information
}
catch (SocketException e) {
// connection reset
}
catch (IOException e) {
LOG.log(Level.FINE, subject.getAddress().toString(), e);
}
finally {
try {
socket.close();
}
catch (IOException e) {}
}
catch (IOException e) {}
}
return null;
}

View File

@ -10,6 +10,7 @@ import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;
@ -17,9 +18,9 @@ import net.azib.ipscan.config.ScannerConfig;
import net.azib.ipscan.core.PortIterator;
import net.azib.ipscan.core.ScanningSubject;
import net.azib.ipscan.core.ScanningResult.ResultType;
import net.azib.ipscan.core.values.NotAvailable;
import net.azib.ipscan.core.values.NotScanned;
import net.azib.ipscan.core.values.NumericRangeList;
import net.azib.ipscan.util.SequenceIterator;
/**
* PortsFetcher scans TCP ports.
@ -51,7 +52,7 @@ public class PortsFetcher extends AbstractFetcher {
@Override
public String getFullName() {
int numPorts = new PortIterator(config.portString).size();
return getName() + " " + (numPorts > 0 ? "[" + numPorts + "]" : NotAvailable.VALUE);
return getName() + " [" + numPorts + (config.useRequestedPorts ? "+" : "" ) + "]";
}
/**
@ -60,6 +61,7 @@ public class PortsFetcher extends AbstractFetcher {
* @param subject the address to scan
* @return true if any ports were scanned, false otherwise
*/
@SuppressWarnings("unchecked")
protected boolean scanPorts(ScanningSubject subject) {
SortedSet<Integer> openPorts = getOpenPorts(subject);
@ -74,17 +76,21 @@ public class PortsFetcher extends AbstractFetcher {
Socket socket = null;
// clone port iterator for performance instead of creating for every thread
PortIterator i = portIteratorPrototype.copy();
if (!i.hasNext()) {
Iterator<Integer> portsIterator = portIteratorPrototype.copy();
if (config.useRequestedPorts && subject.isAnyPortRequested()) {
// add requested ports to the iteration
portsIterator = new SequenceIterator<Integer>(portsIterator, subject.requestedPortsIterator());
}
if (!portsIterator.hasNext()) {
// no ports are configured for scanning
return false;
}
while (i.hasNext() && !Thread.currentThread().isInterrupted()) {
while (portsIterator.hasNext() && !Thread.currentThread().isInterrupted()) {
// TODO: UDP ports?
// TODO: reuse sockets?
socket = new Socket();
int port = i.next();
int port = portsIterator.next();
try {
// set some optimization options
socket.setReuseAddress(true);

View File

@ -67,6 +67,7 @@ public class PreferencesDialog extends AbstractModalDialog {
private TabItem portsTabItem;
private Text portTimeoutText;
private Button adaptTimeoutCheckbox;
private Button addRequestedPortsCheckbox;
private Text minPortTimeoutText;
private Text portsText;
private Text notAvailableText;
@ -357,6 +358,10 @@ public class PreferencesDialog extends AbstractModalDialog {
portsText = new Text(portsGroup, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
portsText.setLayoutData(new RowData(SWT.DEFAULT, 60));
portsText.addKeyListener(new PortsTextValidationListener());
addRequestedPortsCheckbox = new Button(portsGroup, SWT.CHECK);
addRequestedPortsCheckbox.setText(Labels.getLabel("preferences.ports.addRequested"));
addRequestedPortsCheckbox.setToolTipText(Labels.getLabel("preferences.ports.addRequested.info"));
}
/**
@ -402,6 +407,7 @@ public class PreferencesDialog extends AbstractModalDialog {
minPortTimeoutText.setText(Integer.toString(scannerConfig.minPortTimeout));
minPortTimeoutText.setEnabled(scannerConfig.adaptPortTimeout);
portsText.setText(scannerConfig.portString);
addRequestedPortsCheckbox.setSelection(scannerConfig.useRequestedPorts);
notAvailableText.setText(scannerConfig.notAvailableText);
notScannedText.setText(scannerConfig.notScannedText);
displayMethod[guiConfig.displayMethod.ordinal()].setSelection(true);
@ -437,6 +443,7 @@ public class PreferencesDialog extends AbstractModalDialog {
scannerConfig.adaptPortTimeout = adaptTimeoutCheckbox.getSelection();
scannerConfig.minPortTimeout = parseIntValue(minPortTimeoutText);
scannerConfig.portString = portsText.getText();
scannerConfig.useRequestedPorts = addRequestedPortsCheckbox.getSelection();
scannerConfig.notAvailableText = notAvailableText.getText();
scannerConfig.notScannedText = notScannedText.getText();
for (int i = 0; i < displayMethod.length; i++) {

View File

@ -38,6 +38,7 @@ public class ResultTable extends Table implements FetcherRegistryUpdateListener
private ScanningResultList scanningResults;
private GUIConfig guiConfig;
private FetcherRegistry fetcherRegistry;
private Image[] listImages = new Image[ResultType.values().length];
@ -49,6 +50,7 @@ public class ResultTable extends Table implements FetcherRegistryUpdateListener
super(parent, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION | SWT.VIRTUAL);
this.guiConfig = guiConfig;
this.scanningResults = scanningResultList;
this.fetcherRegistry = fetcherRegistry;
setHeaderVisible(true);
setLinesVisible(true);
@ -95,10 +97,10 @@ public class ResultTable extends Table implements FetcherRegistryUpdateListener
tableColumn.addListener(SWT.Selection, columnClickListener);
tableColumn.addListener(SWT.Resize, columnResizeListener);
}
updateFetcherNames(fetcherRegistry);
updateColumnNames();
}
public void updateFetcherNames(FetcherRegistry fetcherRegistry) {
public void updateColumnNames() {
int i = 0;
for (Fetcher fetcher : fetcherRegistry.getSelectedFetchers()) {
getColumn(i++).setText(fetcher.getFullName());

View File

@ -48,6 +48,7 @@ public class ToolsActions {
// refresh the results and status bar in case anything was changed
resultTable.updateResults();
resultTable.updateColumnNames();
statusBar.updateConfigText();
}
}

View File

@ -0,0 +1,44 @@
/**
* This file is a part of Angry IP Scanner source code,
* see http://www.azib.net/ for more information.
* Licensed under GPLv2.
*/
package net.azib.ipscan.util;
import java.util.Iterator;
/**
* SequenceIterator - joins several iterators together to provide a seamless iteration.
*
* @author Anton Keks
*/
public class SequenceIterator<E> implements Iterator<E> {
private Iterator<E>[] iterators;
int currentIndex = 0;
public SequenceIterator(Iterator<E>... iterators) {
this.iterators = iterators;
// check that last iterator is not empty (otherwise the code below won't work)
if (!iterators[iterators.length-1].hasNext())
throw new IllegalArgumentException();
}
public boolean hasNext() {
// combined iterator has elements until the last iterator has them
return iterators[iterators.length-1].hasNext();
}
public E next() {
// take the next iterator if current ran out of elements
if (!iterators[currentIndex].hasNext())
currentIndex++;
return iterators[currentIndex].next();
}
public void remove() {
iterators[currentIndex].remove();
}
}

View File

@ -3,14 +3,15 @@ package net.azib.ipscan.feeders;
import static net.azib.ipscan.feeders.FeederTestUtils.assertFeederException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.StringReader;
import java.util.Iterator;
import net.azib.ipscan.config.LabelsTest;
import net.azib.ipscan.core.ScanningSubject;
import org.junit.Test;
@ -117,13 +118,18 @@ public class FileFeederTest {
@Test
public void requestedPortsAreDetected() throws Exception {
StringReader reader = new StringReader("1.2.3.4:1234\n2.3.4.5:\n 7.6.5.4:789004\n 1.2.3.5:80 ");
StringReader reader = new StringReader("1.2.3.4:1234\n2.3.4.5:\n 7.6.5.4:789004\n 1.2.3.5:80 1.2.3.5:3128 ");
FileFeeder fileFeeder = new FileFeeder(reader);
assertEquals(1234, fileFeeder.next().getRequestedPort());
assertNull(fileFeeder.next().getRequestedPort());
assertNull(fileFeeder.next().getRequestedPort());
assertEquals(80, fileFeeder.next().getRequestedPort());
assertEquals(1234, fileFeeder.next().requestedPortsIterator().next());
assertFalse(fileFeeder.next().isAnyPortRequested());
assertFalse(fileFeeder.next().isAnyPortRequested());
ScanningSubject lastSubject = fileFeeder.next();
assertEquals("1.2.3.5", lastSubject.getAddress().getHostAddress());
Iterator<Integer> portIterator = lastSubject.requestedPortsIterator();
assertEquals(80, portIterator.next());
assertEquals(3128, portIterator.next());
}
private void assertAddressCount(String s, int addressCount) {

View File

@ -3,8 +3,11 @@
*/
package net.azib.ipscan.fetchers;
import static org.easymock.classextension.EasyMock.*;
import static org.junit.Assert.*;
import static org.easymock.classextension.EasyMock.createMock;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.net.InetAddress;
@ -13,7 +16,6 @@ import java.net.Socket;
import net.azib.ipscan.config.ScannerConfig;
import net.azib.ipscan.core.ScanningSubject;
import net.azib.ipscan.core.values.NotAvailable;
import net.azib.ipscan.core.values.NumericRangeList;
import org.junit.Before;
@ -36,11 +38,17 @@ public class PortsFetcherTest extends AbstractFetcherTestCase {
@Test
public void numberOfPortsInFullName() throws Exception {
config.useRequestedPorts = false;
config.portString = "";
assertEquals(fetcher.getName() + " " + NotAvailable.VALUE, fetcher.getFullName());
assertEquals(fetcher.getName() + " [0]", fetcher.getFullName());
config.portString = "1-3";
assertEquals(fetcher.getName() + " [3]", fetcher.getFullName());
config.useRequestedPorts = true;
config.portString = "21-29,40";
assertEquals(fetcher.getName() + " [10+]", fetcher.getFullName());
}
@Test

View File

@ -0,0 +1,50 @@
/**
* This file is a part of Angry IP Scanner source code,
* see http://www.azib.net/ for more information.
* Licensed under GPLv2.
*/
package net.azib.ipscan.util;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Iterator;
import org.junit.Test;
/**
* SequenceIteratorTest
*
* @author Anton Keks
*/
@SuppressWarnings("unchecked")
public class SequenceIteratorTest {
@Test
public void singleIterator() throws Exception {
Iterator<Integer> i = new SequenceIterator<Integer>(Arrays.asList(1).iterator());
assertTrue(i.hasNext());
assertEquals(1, i.next());
assertFalse(i.hasNext());
}
@Test
public void twoIterators() throws Exception {
Iterator<Integer> i = new SequenceIterator<Integer>(Arrays.asList(1, 2).iterator(), Arrays.asList(3).iterator());
assertTrue(i.hasNext());
assertEquals(1, i.next());
assertTrue(i.hasNext());
assertEquals(2, i.next());
assertTrue(i.hasNext());
assertEquals(3, i.next());
assertFalse(i.hasNext());
}
@Test
public void firstEmpty() throws Exception {
Iterator<Integer> i = new SequenceIterator<Integer>(Arrays.<Integer>asList().iterator(), Arrays.asList(3).iterator());
assertTrue(i.hasNext());
assertEquals(3, i.next());
assertFalse(i.hasNext());
}
}