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;
}
}