Java tutorial
/*------------------------------------------------------------------------- Distributed Firewall Anomaly Detector Copyright (C) 2012 Sylvain Hall This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. -------------------------------------------------------------------------*/ package ca.uqac.dim.net.verify; import java.io.*; import ca.uqac.logic.vl.Utilities; import org.apache.commons.cli.*; /** * Main executable class to discover anomalies in a network of * distributed firewalls. * @author sylvain * */ public class NetworkChecker { /** * Full path to the NuSMV executable */ private static String NUSMV_EXEC = "NuSMV"; /** * Main loop. Processes command line arguments, loads the network, builds and * sends a file to NuSMV and handles its response. * @param args Command-line arguments */ public static void main(String[] args) { // Configuration variables boolean opt_show_file = false, opt_show_messages = true, opt_show_stats = false; // Create and parse command line options Option opt = null; Options options = new Options(); options.addOption("f", "file", false, "Output NuSMV file to stdout"); options.addOption("s", "time", false, "Display statistics"); options.addOption("h", "help", false, "Show usage information"); options.addOption("q", "quiet", false, "Do not display any message or explanation"); opt = new Option("i", "file", true, "Input directory"); opt.setRequired(true); options.addOption(opt); CommandLineParser parser = new PosixParser(); CommandLine cmd = null; try { cmd = parser.parse(options, args); } catch (ParseException e) { System.err.println("Error parsing command line arguments"); showUsage(options); System.exit(1); } if (cmd == null) { System.err.println("Error parsing command line arguments"); showUsage(options); System.exit(1); } // Get options assert cmd != null; opt_show_file = cmd.hasOption("f"); opt_show_messages = !cmd.hasOption("q"); opt_show_stats = cmd.hasOption("s"); if (opt_show_messages) System.err.println( "Distributed anomaly verifier\n(C) 2012 Sylvain Hall, Universit du Qubec Chicoutimi\n"); // Get input directory and blob assert cmd.hasOption("i"); String slash = System.getProperty("file.separator"); String input_dir = cmd.getOptionValue("i"); int loc = input_dir.lastIndexOf(slash); String dir_name = "", blob = ""; if (loc == -1) { dir_name = ""; blob = input_dir; } else { dir_name = input_dir.substring(0, loc); blob = input_dir.substring(loc + 1); } // Load network Network net = null; try { net = loadNetworkFromDirectory(dir_name, blob, slash); } catch (FileNotFoundException e) { System.err.print("Error reading "); System.err.println(e.getMessage()); System.exit(1); } catch (IOException e) { System.err.println(e); System.exit(1); } // Build NuSMV file assert net != null; StringBuilder sb = new StringBuilder(); if (opt_show_file) { sb.append("-- File auto-generated by DistributedChecker\n"); sb.append("-- (C) 2012 Sylvain Hall, Universit du Qubec Chicoutimi\n\n"); } sb.append(net.toSmv(opt_show_file)); // Simple shadowing String f_shadowing = "G (frozen -> !(interval_l <= rule_interval_l & interval_r >= rule_interval_r & decision != rule_decision))"; sb.append("\n\nLTLSPEC\n").append(f_shadowing); // Run NuSMV and parse its return value if (opt_show_file) { System.out.println(sb); System.exit(0); } RuntimeInfos ri = null; try { ri = runNuSMV(sb.toString()); } catch (IOException e) { System.err.println(e.getMessage()); System.exit(1); } catch (InterruptedException e) { System.err.println(e.getMessage()); System.exit(1); } assert ri != null; // If requested, compute and show an explanation from NuSMV's returned contents if (opt_show_messages) { ExplanationTrace t = null; try { t = net.explain(ri.m_return_contents); } catch (NuSmvParseException e) { System.err.println("Error reading NuSMV's answer"); System.exit(1); } if (t == null) { // No explanation => no anomaly found System.out.println("No anomaly found"); } else System.out.println(t); } // If requested, show runtime statistics if (opt_show_stats) { StringBuilder out = new StringBuilder(); out.append(net.getNodeSize()).append(","); out.append(net.getFirewallRuleSize()).append(","); out.append(net.getRoutingTableSize()).append(","); out.append(ri.m_runtime); System.out.println(out); } System.exit(0); } /** * Simple class used to contain info resulting from calling NuSMV * @author sylvain * */ private static class RuntimeInfos { String m_return_contents; long m_runtime; public RuntimeInfos(String return_contents, long runtime) { m_return_contents = return_contents; m_runtime = runtime; } } /** * Show command line usage * @param options */ private static void showUsage(Options options) { int screen_width = 80; String header = "", footer = ""; int padding_l = 1, padding_r = 1; HelpFormatter hf = new HelpFormatter(); PrintWriter pw = new PrintWriter(System.err); hf.printHelp(pw, screen_width, "verify [-f] [-h] -i <arg> [-s]", header, options, padding_l, padding_r, footer); pw.close(); } /** * Runs the NuSMV program as a spawned command-line process, and passes the * file to process through that process' standard input * @param file_contents A String containing the NuSMV model to process */ private static RuntimeInfos runNuSMV(String file_contents) throws IOException, InterruptedException { StringBuilder sb = new StringBuilder(); Runtime rt = Runtime.getRuntime(); long time_start = 0, time_end = 0; // Start NuSMV, and feed the model through its standard input time_start = System.currentTimeMillis(); Process p = rt.exec(NUSMV_EXEC); OutputStream o = p.getOutputStream(); InputStream i = p.getInputStream(); InputStream e = p.getErrorStream(); Writer w = new PrintWriter(o); w.write(file_contents); w.close(); // Close stdin so NuSMV can start processing it // Wait for NuSMV to be done, then collect its standard output int exitVal = p.waitFor(); if (exitVal != 0) throw new IOException("NuSMV's return value indicates an error in processing its input"); BufferedReader br = new BufferedReader(new InputStreamReader(i)); String line; while ((line = br.readLine()) != null) { sb.append(line).append("\n"); } time_end = System.currentTimeMillis(); i.close(); // Close stdout e.close(); // Close stderr return new RuntimeInfos(sb.toString(), time_end - time_start); } /** * Simple implementation of a FileFilter that takes as input * a file pattern in blob syntax (e.g. <tt>*.txt</tt> or * <tt>abc-*.ex?</tt>. Internally the BlobFilter converts the * blob into an equivalent regular expression and uses regex * matching to filter files. * @author sylvain * */ private static class BlobFilter implements FilenameFilter { /** * Holds the regex equivalent to the blob passed to the constructor */ private String m_blob; /** * Instantiates the filter. * @param blob A file pattern in blob syntax */ public BlobFilter(String blob) { super(); blob = blob.replace(".", "\\."); blob = blob.replace("*", ".*"); blob = blob.replace("?", "."); m_blob = "^" + blob + "$"; } @Override public boolean accept(File dir, String name) { return name.matches(m_blob); } } private static Network loadNetworkFromDirectory(String dirname, String blob, String slash) throws IOException { Network net = new Network(); File dir = new File(dirname); String[] children = dir.list(new NetworkChecker.BlobFilter(blob)); for (String filename : children) { String s = Utilities.readFileAsString(dirname + slash + filename); NetworkNode nn = new NetworkNode(s); net.add(nn); } return net; } @SuppressWarnings("unused") private static Network loadNetworkFromFile(String filename) { Network net = new Network(); try { String file_contents = Utilities.readFileAsString(filename); String[] lines = file_contents.split("[\\r|\\n]"); for (String li : lines) { li = li.trim(); if (li.isEmpty()) continue; if (li.startsWith("#")) continue; String s = Utilities.readFileAsString(li); NetworkNode nn = new NetworkNode(s); net.add(nn); } } catch (IOException e) { e.printStackTrace(); } return net; } }