1Nmap4j nmap4j = new Nmap4j( "/usr/local"); 2nmap4j.includeHost("192.168.1.1-255"); 3nmap4j.excludeHost( "192.168.1.110" ); 4nmap4j.addFlags("-T3 -oX - -O -sV"); 5nmap4j.execute(); 6if(!nma4j.hasError()){ 7NMapRun nmapRun = nmap4j.getResults(); 8} else { 9System.out.println(nmap4j.getExecutionResults().getErrors()); 10}
DOC: http://www.oistc.com/nmap4j/
1package com.oistc 2 3import java.util.ArrayList; 4import java.util.Collection; 5import java.util.HashMap; 6import java.util.TreeMap; 7import java.util.logging.Level; 8import java.util.logging.Logger; 9 10import org.nmap4j.Nmap4j; 11import org.nmap4j.core.nmap.ExecutionResults; 12import org.nmap4j.data.NMapRun; 13import org.nmap4j.data.host.Address; 14import org.nmap4j.data.host.ports.Port; 15import org.nmap4j.data.nmaprun.Host; 16 17/** 18 * Thread class which can monitor and log reachability of N ports on M servers. 19 * Once initial state is recorded and logged, subsequent scans only log state changes. 20 * Each thread can monitor N ports on M servers with a single scan sweep, and you 21 * can run multiple threads for different combinations of ports, servers, and protocols. 22 * The underlying scanning tool is NMAP, and NMAP4J is used to wrap those calls 23 * for configuration and output/error parsing convenience. 24 * @author justin.cranford 25 */ 26public class ServerReachabilityMonitor extends Thread { 27 private static final Logger LOGGER = Logger.getLogger(""); 28 29 private final static boolean DUMP_NMAP4J_OUTPUT = true; 30 private final static boolean DUMP_NMAP4J_DEBUG = false; 31 private final static boolean WORKAROUND_NMAPRUN_XML_PARSE_CONCURRENCY_BUG = true; // workaround suspected Nmap4j concurrency issue with parsing NmapRun XML results 32 33 public static final String JVM_PROP_OSNAME = System.getProperty("os.name"); 34 public static final boolean JVM_PROP_ISWIN = JVM_PROP_OSNAME.toLowerCase().startsWith("win"); 35 36 private ArrayList<String> addresses; // each element is an address, FQDN, or hostname 37 private ArrayList<Integer> ports; // each element is integer 1-65535, or a range of integers 38 private String protocol; // TCP_SYN, TCP_CONNECT, or UDP (Example: TCP_SYN works for 443 on Xsuite, but not 443 on PA Windows, so you might have to use TCP_CONNECT) 39 40 @SuppressWarnings("hiding") 41 public ServerReachabilityMonitor(final ArrayList<String> addresses, final ArrayList<Integer> ports, final String protocol) { 42 this.addresses = new ArrayList<>(addresses); 43 this.ports = new ArrayList<>(ports); 44 this.protocol = protocol; 45 this.setPriority(Thread.MIN_PRIORITY); // avoid hogging CPU if normal priority threads 46 this.setDaemon(true); // stop when JVM stops 47 this.setContextClassLoader(null); // release Tomcat 6+ WebAppClassLoader reference to avoid blocking war unloading during reload or stop 48 this.setName("ServerReachabilityMonitor"); 49 } 50 51 @SuppressWarnings("hiding") 52 public ServerReachabilityMonitor(final String address, final ArrayList<Integer> ports, final String protocol) { 53 this.addresses = new ArrayList<>(1); 54 this.addresses.add(address); 55 this.ports = new ArrayList<>(ports); 56 this.protocol = protocol; 57 this.setPriority(Thread.MIN_PRIORITY); // avoid hogging CPU if normal priority threads 58 this.setDaemon(true); // stop when JVM stops 59 this.setContextClassLoader(null); // release Tomcat 6+ WebAppClassLoader reference to avoid blocking war unloading during reload or stop 60 this.setName("ServerReachabilityMonitor"); 61 } 62 63 public void run() { 64 final String addressesStr = CollectionToString(this.addresses, ","); 65 final String portsStr = CollectionToString(this.ports, ","); 66 67 HashMap<String,TreeMap<Integer,String>> previousAddressToPortAndState = null, currentAddressToPortAndState = null; 68 int scanAttempts = 0; 69 long scanTotalTime = 0L, scanCurrentStartTime = 0L, scanCurrentElapsedTime = 0L; 70 while (true) { 71 try { 72 LOGGER.log(Level.WARNING, "ServerReachabilityMonitor.run Scanning addresses '" + addressesStr + "', ports '" + portsStr + "', protocol '" + this.protocol + "'."); 73 try { 74 scanCurrentStartTime = System.nanoTime(); 75 currentAddressToPortAndState = performNmapScan(this.addresses, this.ports, this.protocol); 76 } catch(Exception e) { 77 LOGGER.log(Level.INFO, "ServerReachabilityMonitor.run Server '" + addressesStr + "' scan failed.", e); 78 } finally { 79 scanCurrentElapsedTime = System.nanoTime() - scanCurrentStartTime; // nanoseconds to execute check, so we can log fraction of milliseconds in LAN 80 if (scanCurrentElapsedTime < 0L) { 81 scanCurrentElapsedTime = 0L; // watch out for negatives 82 } 83 scanTotalTime += scanCurrentElapsedTime; 84 scanAttempts++; 85 LOGGER.log(Level.WARNING, "ServerReachabilityMonitor.run Scanned addresses '" + addressesStr + "', ports '" + portsStr + "', protocol '" + this.protocol + "' in time="+(scanCurrentElapsedTime/1000000F)+"ms [Total="+(scanTotalTime/1000000F)+"ms, Count="+scanAttempts+", Average="+((float) scanTotalTime / (float) scanAttempts / 1000000F)+"ms]."); 86 } 87 if (null == currentAddressToPortAndState) { // log port-level state differences between current scan and previous scan 88 LOGGER.log(Level.WARNING, "ServerReachabilityMonitor.run No results."); 89 } else { 90 LOGGER.log(Level.WARNING, "ServerReachabilityMonitor.run Checking results."); 91 for (String currentAddress : this.addresses) { 92 TreeMap<Integer,String> differentPortAndState = new TreeMap<>(); 93 94 // retrieve previous state, or use empty map for previous state 95 TreeMap<Integer,String> previousPortAndState; 96 if (null == previousAddressToPortAndState) { 97 previousPortAndState = new TreeMap<>(); 98 } else { 99 previousPortAndState = previousAddressToPortAndState.get(currentAddress); 100 if (null == previousPortAndState) { 101 previousPortAndState = new TreeMap<>(); 102 } 103 } 104 105 // compare current state to previous state 106 TreeMap<Integer,String> currentPortAndState = currentAddressToPortAndState.get(currentAddress); 107 int numPortStateChanges = 0; 108 for (Integer port : this.ports) { 109 final String previousState = previousPortAndState.get(port); 110 final String currentState = (null == currentPortAndState ? null : currentPortAndState.get(port)); 111 if (null == currentState) { 112 if (null == previousState) { 113 differentPortAndState.put(port, port.toString()+"=<no data>"); // STILL NO DATA 114 } else { 115 differentPortAndState.put(port, port.toString()+"=<removed> ("+previousState+")"); // DISAPPEARED 116 numPortStateChanges++; 117 } 118 } else { 119 if (null == previousState) { 120 differentPortAndState.put(port, port.toString()+"="+currentState+" <new>"); // FIRST DATA 121 numPortStateChanges++; 122 } else if (! currentState.equals(previousState)) { 123 differentPortAndState.put(port, port.toString()+"="+currentState+" ("+previousState+")"); // CHANGED 124 numPortStateChanges++; 125 } 126 } 127 } 128 129 // log if one or more port-level states changed (or log level >= FINE) 130 if (numPortStateChanges > 0) { 131 LOGGER.log(Level.WARNING, "ServerReachabilityMonitor.run Server '" + currentAddress + "' reachability changed: " + CollectionToString(differentPortAndState.values(), ", ")); 132 } else { 133 LOGGER.log(Level.WARNING, "ServerReachabilityMonitor.run Server '" + currentAddress + "' reachability did not change"); 134 } 135 136 // if no current scan result, copy previous scan to current results so we can carry it forward to next comparison 137 if (null == currentPortAndState) { 138 if (null != previousAddressToPortAndState) { 139 currentAddressToPortAndState.put(currentAddress, previousPortAndState); 140 } 141 } 142 } 143 144 // copy current scan results to previous for next scan comparison 145 previousAddressToPortAndState = currentAddressToPortAndState; 146 currentAddressToPortAndState = null; 147 } 148 } catch (Exception e) { 149 LOGGER.log(Level.SEVERE, "ServerReachabilityMonitor.run Unexpected Exception.", e); 150 } 151 } 152 } 153 154 private static final String NMAP_PROTOCOL_TCP_SYN = "TCP_SYN"; 155 private static final String NMAP_PROTOCOL_TCP_CONNECT = "TCP_CONNECT"; 156 private static final String NMAP_PROTOCOL_TCP_UDP = "UDP"; 157 private static final String NMAP_PATH_WINDOWS = "C:/Program Files (x86)/Nmap"; 158 private static final String NMAP_PATH_UNIX = "/usr/bin/nmap"; 159 private static final String NMAP_OPTIONS_TCP_SYN = "-n -T4 -sS -PN --disable-arp-ping --max-scan-delay 0ms --min-rate 1000000 --max-retries 0 -p "; // TCP SYN scan 160 private static final String NMAP_OPTIONS_TCP_CONNECT = "-n -T4 -sT -PN --disable-arp-ping --max-scan-delay 0ms --min-rate 1000000 --max-retries 0 -p "; // TCP connect scan 161 private static final String NMAP_OPTIONS_UDP = "-n -T4 -sU -PN --disable-arp-ping --max-scan-delay 0ms --min-rate 1000000 --max-retries 0 -p "; // UDP scan 162 private static HashMap<String, TreeMap<Integer, String>> performNmapScan(ArrayList<String> addresses, ArrayList<Integer> ports, String protocol) throws Exception { 163 final HashMap<String, TreeMap<Integer, String>> addressToPortAndState = new HashMap<>(); 164 final String nmapAddresses = CollectionToString(addresses," "); 165 final String nmapOptions; 166 if (protocol.equals(NMAP_PROTOCOL_TCP_SYN)) { 167 nmapOptions = NMAP_OPTIONS_TCP_SYN + CollectionToString(ports,","); 168 } else if (protocol.equals(NMAP_PROTOCOL_TCP_CONNECT)) { 169 nmapOptions = NMAP_OPTIONS_TCP_CONNECT + CollectionToString(ports,","); 170 } else if (protocol.equals(NMAP_PROTOCOL_TCP_UDP)) { 171 nmapOptions = NMAP_OPTIONS_UDP + CollectionToString(ports,","); 172 } else { 173 throw new Exception("ServerReachabilityMonitor.run Unsupported protocol '" + protocol + "'."); 174 } 175 Nmap4j nmap4j = new Nmap4j(JVM_PROP_ISWIN ? NMAP_PATH_WINDOWS : NMAP_PATH_UNIX); 176 nmap4j.includeHosts(nmapAddresses); 177 nmap4j.addFlags(nmapOptions); 178 nmap4j.execute(); 179 if (!nmap4j.hasError()) { 180 String addressStr; 181 Integer portNum; 182 String stateStr; 183 TreeMap<Integer,String> portStatesForAddress; 184 NMapRun nmapRun; 185 // workaround suspected Nmap4j concurrency issue with parsing NmapRun XML results? 186 if (ServerReachabilityMonitor.WORKAROUND_NMAPRUN_XML_PARSE_CONCURRENCY_BUG) { 187 synchronized (ServerReachabilityMonitor.class) { 188 nmapRun = nmap4j.getResult(); 189 } 190 } else { 191 nmapRun = nmap4j.getResult(); 192 } 193 if (DUMP_NMAP4J_OUTPUT) { 194 // Dump Nmap4j output, and indicate if Nmap4j.getResult() returned good NmapRun) 195 LOGGER.log(Level.WARNING, "OUTPUT (NmapRun OK: "+(null!=nmapRun)+"): " + nmap4j.getOutput()); 196 } 197 if (null == nmapRun) { 198 ExecutionResults executionResults = nmap4j.getExecutionResults(); 199 if (null == executionResults) { 200 LOGGER.log(Level.SEVERE, "NULL NmapRun, NULL ExecutionResults"); 201 } else { 202 LOGGER.log(Level.SEVERE, "NULL NmapRun, ExecutionResults.getOutput: " + executionResults.getOutput()); 203 LOGGER.log(Level.SEVERE, "NULL NmapRun, ExecutionResults.getErrors: " + executionResults.getErrors()); 204 } 205 } else { 206 if (DUMP_NMAP4J_DEBUG) { 207 LOGGER.log(Level.WARNING, "ARGS: " + nmapRun.getArgs()); 208 LOGGER.log(Level.WARNING, "DEBUG: " + nmapRun.getDebugging()); 209 } 210 for (Host host : nmapRun.getHosts()) { 211 for (Address address : host.getAddresses()) { 212 addressStr = address.getAddr(); 213 for (Port port : host.getPorts().getPorts()) { 214 portStatesForAddress = addressToPortAndState.get(addressStr); 215 if (null == portStatesForAddress) { 216 portStatesForAddress = new TreeMap<>(); 217 addressToPortAndState.put(addressStr, portStatesForAddress); 218 } 219 portNum = new Integer((int)port.getPortId()); 220 stateStr = port.getState().getState(); 221 portStatesForAddress.put(portNum, stateStr); 222 } 223 } 224 } 225 } 226 } else { 227 throw new Exception("ServerReachabilityMonitor.run Scan failed: " + nmap4j.getExecutionResults().getErrors()); 228 } 229 return addressToPortAndState; 230 } 231 232 public static String CollectionToString(Collection<? extends Object> inputCollection, String delimiter) { 233 StringBuilder result = new StringBuilder(); 234 if (inputCollection != null) { 235 for (Object object : inputCollection) { 236 result.append(object).append(delimiter); 237 } 238 } 239 return(0 == result.length() ? "" : result.substring(0, result.length()-delimiter.length())); 240 } 241 public static void main(String[] args) throws Exception { 242 final boolean isNmapConcurrent = false; // true (single nmap thread scanning multiple addresses), false (multiple nmap threads scanning single addresses) 243 final String protocol = NMAP_PROTOCOL_TCP_CONNECT; 244 final ArrayList<Integer> ports = new ArrayList<>(); 245 { 246 ports.add(new Integer(443)); // HTTPS 247 ports.add(new Integer(3306)); // MySQL 248 ports.add(new Integer(5900)); // Hazelcast 249 ports.add(new Integer(7900)); // JGroups 250 ports.add(new Integer(7901)); // JGroups 251 } 252 final ArrayList<String> addresses = new ArrayList<>(); 253 { 254 addresses.add("10.1.10.23"); // remote DNS server (unknown) 255 addresses.add("10.1.10.164"); // remote Debian 5 x32 test build (VMware ESX VM) 256 addresses.add("10.1.200.181"); // remote Debian 5 x32 test build (VMware ESX VM) 257 addresses.add("10.20.0.144"); // localhost Windows 7 Pro x64 (VMware Workstation VM) 258 addresses.add("192.168.0.1"); // LAN Windows Server 2003 R2 x32 DNS server (VMware ESX VM) 259 } 260 261 if (isNmapConcurrent) { 262 new ServerReachabilityMonitor(addresses, ports, protocol).run(); // single nmap call in main() thread (never returns) 263 } else { 264 for (String address : addresses) { 265 new ServerReachabilityMonitor(address, ports, protocol).start(); // separate nmap calls to scan addresses separately 266 } 267 Thread.sleep(Long.MAX_VALUE); // do not allow "main" thread to return and join, otherwise JVM will stop because ServerReachabilityMonitor threads have daemon=true 268 } 269 } 270}