package ciscoroutertool.scanner; import ciscoroutertool.rules.Rule; import ciscoroutertool.scanner.parser.RouterConfigManager; import ciscoroutertool.utils.Host; import com.jcraft.jsch.Channel; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import net.sf.expectit.Expect; import net.sf.expectit.ExpectBuilder; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.concurrent.Callable; import static net.sf.expectit.matcher.Matchers.contains; /** * Runs the scan for a host and holds the results * @version 0.01ALPHA * @author Andrew Johnston */ public class Scanner implements Callable<HostReport> { /** * The list of rules to check each host against. */ public static ArrayList<Rule> rules; /** * The list of rules that the host matched. */ private ArrayList<Rule> matched; /** * The port the SSH Server is listening on. */ private static final int SSH_PORT = 22; /** * The command to get the full configuration file from the device. */ private static final String GET_ALL_CONFIG = "show running-config full"; /** * The command to enable superuser privileges */ private static final String ENABLE_SUPERUSER = "enable"; /** * The command to disable the use of "more" to pipe the config file */ private static final String DISABLE_OUTPUT_BUFFERING = "terminal length 0"; /** * The host that the Scanner object will scan. */ private final Host host; private static final String PASSWORD_PROMPT = "Password:"; /** * Initializes the scanner. * @param h The host to be scanned */ public Scanner(Host h) { host = h; } /** * Performs the scan and returns a HostReport containing all matched rules. * @return The HostReport containing the matched rules. * @throws Exception Any Unhandled exception generated during the scan. */ @Override public HostReport call() { ArrayList<String> configlines = null; try { configlines = getConfigFile(); } catch (Exception e) { System.err.println("Failed to connect to host " + host.toString() + ". Please check " + "URL and credentials and rerun."); System.err.println("The exact error was: " + e.getMessage()); //We won't have any data on the host, so construct an empty report and throw it back HostReport failedToConnect = new HostReport(host); return failedToConnect; } ArrayList<String> activeLines = RouterConfigManager.getActiveConfig(configlines); return getHostReport(activeLines); } /** * Connects to the device and retrieves the configuration file from the * device. * @return A ArrayList containing the output from the GET_ALL_CONFIG * command */ private ArrayList<String> getConfigFile() throws Exception{ JSch jsch = new JSch(); InputStream in = null; Session session = jsch.getSession( host.getUser(), host.toString(), SSH_PORT); session.setPassword(host.getPass()); //If this line isn't present, every host must be in known_hosts session.setConfig("StrictHostKeyChecking", "no"); session.connect(); Channel channel = session.openChannel("shell"); in = channel.getInputStream(); OutputStream outputStream = channel.getOutputStream(); Expect expect = new ExpectBuilder() .withOutput(outputStream) .withInputs(channel.getInputStream(), channel.getExtInputStream()) //.withEchoOutput(System.out) //.withEchoInput(System.out) .build(); channel.connect(); if (host.usesEnable()) { expect.expect(contains(">")); expect.sendLine(ENABLE_SUPERUSER); expect.expect(contains(PASSWORD_PROMPT)); expect.sendLine(host.getEnablePass()); } expect.expect(contains("#")); //# expect.sendLine(DISABLE_OUTPUT_BUFFERING); //terminal length 0 expect.expect(contains("#")); //# expect.sendLine(GET_ALL_CONFIG); //show running-config full String result = expect.expect(contains("#")).getBefore(); //# channel.disconnect(); session.disconnect(); expect.close(); String[] arrLines = result.split("\n"); ArrayList<String> lines = new ArrayList<>(Arrays.asList(arrLines)); return lines; } /** * Compares the rules to the configuration file and stores the matched ones * @param activeConfig The configuration with all shutdown interfaces * removed. * @return A HostReport containing all matched rules */ private HostReport getHostReport(ArrayList<String> activeConfig) { HostReport report = new HostReport(host); for (Rule r : rules) { if (r.matchesRule(activeConfig)) { report.addMatchedRule(r); } } return report; } }