NetBIOSInfoFetcher implemented

git-svn-id: https://ipscan.svn.sourceforge.net/svnroot/ipscan/trunk@233 375186e5-ef17-0410-b0b6-91563547dcda
This commit is contained in:
angryziber 2007-11-09 18:24:50 +00:00
parent 6b11be87b2
commit 8650cf8667
6 changed files with 206 additions and 4 deletions

6
TODO
View File

@ -1,7 +1,6 @@
Before 3.0 beta:
* export/import of settings (profiles?)
* NetBIOS fetchers (like in 2.x)
Before 3.0:
@ -13,14 +12,13 @@ Before 3.0:
* startup as root option
* compile librocksaw for mac
* preferences & select fetchers buttons in the toolbar
* plugin loader
Later:
* preferences profiles (maybe even save with favorites)
* preferences profiles (tied to favorites?)
* offer installation on Windows
* free text (advanced) feeder
* comments fetcher
* saving and restoring of results together with all options
* plugin loader
* advanced find (firefox-like)
* use jpcap for raw packet injection and ARP scanning

View File

@ -28,3 +28,4 @@ clipboard
ctrl
compiz
placeholder
firewall

View File

@ -184,6 +184,8 @@ fetcher.comment=Comments
fetcher.comment.info=Allows writing of comments for each host.\nThe comments are persisted and always shown then the host is scanned.
fetcher.webDetect=Web detect
fetcher.webDetect.info=Detects the web server software name and version, if possible.\n\nWorks by sending a HEAD request and reading the Server HTTP header from the response.
fetcher.netbios=NetBIOS Info
fetcher.netbios.info=Retrieves the NetBIOS information about Windows machines.\n\nThe response has the following format:\nDOMAIN\\USER@COMPUTER [MAC]\n\nWhere:\nDOMAIN - Windows domain or workgroup\nUSER - currently logged in user\nCOMPUTER - Windows computer name (may be different from DNS name)\nSome parts may be absent, depending on the response.\n\nNote that this won't work with machines that have firewall enabled (which are most modern installations).\nThis fetcher is provided mostly for feature-compatibility with version 2.x.
fetcher.value.ms=\u00A0ms
fetcher.value.notAvailable=[n/a]
fetcher.value.notScanned=[n/s]

View File

@ -22,6 +22,7 @@ import net.azib.ipscan.fetchers.FetcherRegistryImpl;
import net.azib.ipscan.fetchers.FilteredPortsFetcher;
import net.azib.ipscan.fetchers.HostnameFetcher;
import net.azib.ipscan.fetchers.IPFetcher;
import net.azib.ipscan.fetchers.NetBIOSInfoFetcher;
import net.azib.ipscan.fetchers.PingFetcher;
import net.azib.ipscan.fetchers.PingTTLFetcher;
import net.azib.ipscan.fetchers.PortsFetcher;
@ -97,6 +98,7 @@ public class ComponentRegistry {
container.registerComponentImplementation(FilteredPortsFetcher.class);
container.registerComponentImplementation(WebDetectFetcher.class);
container.registerComponentImplementation(CommentFetcher.class);
container.registerComponentImplementation(NetBIOSInfoFetcher.class);
container.registerComponentImplementation(PingerRegistry.class, PingerRegistryImpl.class);
container.registerComponentImplementation(ScanningResultList.class);

View File

@ -0,0 +1,146 @@
/**
* 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.fetchers;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.azib.ipscan.config.GlobalConfig;
import net.azib.ipscan.config.LoggerFactory;
import net.azib.ipscan.core.ScanningSubject;
/**
* NetBIOSInfoFetcher - gathers NetBIOS info about Windows machines.
* Provided for feature-compatibility with version 2.x
*
* @author Anton Keks
*/
public class NetBIOSInfoFetcher implements Fetcher {
private static final Logger LOG = LoggerFactory.getLogger();
private static final int NETBIOS_UDP_PORT = 137;
private static final byte[] REQUEST_DATA = {(byte)0xA2, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x43, 0x4b, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x21, 0x00, 0x01};
private static final int RESPONSE_BASE_LEN = 57;
private static final int RESPONSE_NAME_LEN = 15;
private static final int RESPONSE_NAME_BLOCK_LEN = 18;
private static final int GROUP_NAME_FLAG = 128;
private static final int NAME_TYPE_DOMAIN = 0x00;
private static final int NAME_TYPE_MESSENGER = 0x03;
private GlobalConfig config;
public NetBIOSInfoFetcher(GlobalConfig config) {
this.config = config;
}
public String getLabel() {
return "fetcher.netbios";
}
public Object scan(ScanningSubject subject) {
DatagramSocket socket = null;
try {
socket = new DatagramSocket();
socket.setSoTimeout(config.pingTimeout);
socket.connect(subject.getAddress(), NETBIOS_UDP_PORT);
socket.send(new DatagramPacket(REQUEST_DATA, REQUEST_DATA.length));
byte[] response = new byte[1024];
DatagramPacket responsePacket = new DatagramPacket(response, response.length);
socket.receive(responsePacket);
if (responsePacket.getLength() < RESPONSE_BASE_LEN) {
// response was too short for some reason
return null;
}
int nameCount = response[RESPONSE_BASE_LEN-1] & 0xFF;
if (responsePacket.getLength() < RESPONSE_BASE_LEN + RESPONSE_NAME_BLOCK_LEN * (nameCount-1)) {
// data was truncated or something is wrong
return null;
}
return extractNames(response, nameCount);
}
catch (SocketException e) {
// this includes PortUnreachableException and SocketTimeoutException
return null;
}
catch (Exception e) {
// bugs?
LOG.log(Level.WARNING, null, e);
return null;
}
finally {
if (socket != null) {
socket.close();
}
}
}
static String extractNames(byte[] response, int nameCount) {
String computerName = name(response, 0);
String groupName = null;
for (int i = 1; i < nameCount; i++) {
if (nameType(response, i) == NAME_TYPE_DOMAIN && (nameFlag(response, i) & GROUP_NAME_FLAG) > 0) {
groupName = name(response, i);
break;
}
}
String userName = null;
for (int i = nameCount - 1; i > 0; i--) {
if (nameType(response, i) == NAME_TYPE_MESSENGER) {
userName = name(response, i);
break;
}
}
String macAddress = String.format("%02X-%02X-%02X-%02X-%02X-%02X",
nameByte(response, nameCount, 0), nameByte(response, nameCount, 1),
nameByte(response, nameCount, 2), nameByte(response, nameCount, 3),
nameByte(response, nameCount, 4), nameByte(response, nameCount, 5));
return (groupName != null ? groupName + "\\" : "") +
(userName != null ? userName + "@" : "") +
computerName + " [" + macAddress + "]";
}
private static String name(byte[] response, int i) {
// as we have no idea in what encoding are the received names,
// assume that local default encoding matches the remote one (they are on the same LAN most probably)
return new String(response, RESPONSE_BASE_LEN + RESPONSE_NAME_BLOCK_LEN * i, RESPONSE_NAME_LEN).trim();
}
private static int nameByte(byte[] response, int i, int n) {
return response[RESPONSE_BASE_LEN + RESPONSE_NAME_BLOCK_LEN * i + n] & 0xFF;
}
private static int nameFlag(byte[] response, int i) {
return response[RESPONSE_BASE_LEN + RESPONSE_NAME_BLOCK_LEN * i + RESPONSE_NAME_LEN + 1] & 0xFF +
(response[RESPONSE_BASE_LEN + RESPONSE_NAME_BLOCK_LEN * i + RESPONSE_NAME_LEN + 2] & 0xFF) * 0xFF;
}
private static int nameType(byte[] response, int i) {
return response[RESPONSE_BASE_LEN + RESPONSE_NAME_BLOCK_LEN * i + RESPONSE_NAME_LEN] & 0xFF;
}
public void init() {
}
public void cleanup() {
}
}

View File

@ -0,0 +1,53 @@
/**
* 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.fetchers;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
/**
* NetBIOSInfoFetcherTest
*
* @author Anton Keks
*/
public class NetBIOSInfoFetcherTest {
@Test
public void extractNamesNoUserNoGroup() throws Exception {
byte[] response = ("01234567890123456789012345678901234567890123456789012345\u0001" +
"ComputerName XYY" +
"\u00DE\u00AD\u00BE\u00EF\u0000\u0000 XYY"
).getBytes("ISO-8859-1");
assertEquals("ComputerName [DE-AD-BE-EF-00-00]", NetBIOSInfoFetcher.extractNames(response, 1));
}
@Test
public void extractNamesNoUserWithGroup() throws Exception {
byte[] response = ("01234567890123456789012345678901234567890123456789012345\u0002" +
"ComputerName XYY" +
"GroupName \u0000\u0080\u0000" +
"\u0001\u0002\u0003\u0004\u0005\u0006 XYY"
).getBytes("ISO-8859-1");
assertEquals("GroupName\\ComputerName [01-02-03-04-05-06]", NetBIOSInfoFetcher.extractNames(response, 2));
}
@Test
public void extractNamesWithUserAndGroup() throws Exception {
byte[] response = ("01234567890123456789012345678901234567890123456789012345\u0007" +
"ComputerName XYY" +
"SomeName X\u007F\u0000" +
"SomeName X\u0085\u0000" +
"GroupName \u0000\u0085\u0000" +
"WrongUserName \u0003YY" +
"UserName \u0003YY" +
"SomeName XYY" +
"\u00DE\u00AD\u00BE\u00EF\u0000\u0000 XYY"
).getBytes("ISO-8859-1");
assertEquals("GroupName\\UserName@ComputerName [DE-AD-BE-EF-00-00]", NetBIOSInfoFetcher.extractNames(response, 7));
}
}