package org.batfish.common.util; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import java.util.stream.Stream; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import javax.ws.rs.client.ClientBuilder; import org.apache.commons.io.FileUtils; import org.batfish.common.BatfishException; import org.skyscreamer.jsonassert.JSONAssert; public class CommonUtil { private static class TrustAllHostNameVerifier implements HostnameVerifier { @Override public boolean verify(String hostname, SSLSession session) { return true; } } public static final String FACT_BLOCK_FOOTER = "\n//FACTS END HERE\n" + " }) // clauses\n" + "} <-- .\n"; public static String applyPrefix(String prefix, String msg) { String[] lines = msg.split("\n"); StringBuilder sb = new StringBuilder(); for (String line : lines) { sb.append(prefix + line + "\n"); } return sb.toString(); } public static boolean bothNullOrEqual(Object a, Object b) { if (a == null && b == null) { return true; } else if (a != null && b != null) { return a.equals(b); } else { return false; } } public static boolean checkJsonEqual(Object a, Object b) { BatfishObjectMapper mapper = new BatfishObjectMapper(); try { String aString = mapper.writeValueAsString(a); String bString = mapper.writeValueAsString(b); JSONAssert.assertEquals(aString, bString, false); return true; } catch (Exception e) { throw new BatfishException("JSON equality check failed: " + e.getMessage() + e.getStackTrace()); } catch (AssertionError err) { return false; } finally { } } public static long communityStringToLong(String str) { String[] parts = str.split(":"); long high = Long.parseLong(parts[0]); long low = Long.parseLong(parts[1]); long result = low + (high << 16); return result; } public static void createDirectories(Path path) { try { Files.createDirectories(path); } catch (IOException e) { throw new BatfishException( "Could not create directories leading up to and including '" + path.toString() + "'", e); } } public static void delete(Path path) { try { Files.delete(path); } catch (NoSuchFileException e) { } catch (IOException e) { throw new BatfishException("Failed to delete file: " + path, e); } } public static void deleteDirectory(Path path) { try { FileUtils.deleteDirectory(path.toFile()); } catch (IOException | NullPointerException e) { throw new BatfishException("Could not delete directory: " + path, e); } } public static <S extends Set<T>, T> S difference(Set<T> minuendSet, Set<T> subtrahendSet, Supplier<S> setConstructor) { S differenceSet = setConstructor.get(); differenceSet.addAll(minuendSet); differenceSet.removeAll(subtrahendSet); return differenceSet; } public static String escape(String offendingTokenText) { return offendingTokenText.replace("\n", "\\n").replace("\t", "\\t") .replace("\r", "\\r"); } public static String extractBits(long l, int start, int end) { String s = ""; for (int pos = end; pos >= start; pos--) { long mask = 1L << pos; long bit = l & mask; s += (bit != 0) ? 1 : 0; } return s; } public static ClientBuilder getClientBuilder(boolean secure, boolean trustAll) throws Exception { if (secure) { if (trustAll) { SSLContext sslcontext = SSLContext.getInstance("TLS"); sslcontext.init(null, new TrustManager[] { new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } } }, new java.security.SecureRandom()); return ClientBuilder.newBuilder().sslContext(sslcontext) .hostnameVerifier(new TrustAllHostNameVerifier()); } else { return ClientBuilder.newBuilder(); } } else { return ClientBuilder.newBuilder(); } } public static Path getConfigProperties(Class<?> locatorClass, String propertiesFilename) { Path configDir = getJarOrClassDir(locatorClass); return configDir.resolve(propertiesFilename); } public static String getIndentedString(String str, int indentLevel) { String indent = getIndentString(indentLevel); StringBuilder sb = new StringBuilder(); String[] lines = str.split("\n"); for (String line : lines) { sb.append(indent + line + "\n"); } return sb.toString(); } public static String getIndentString(int indentLevel) { String retString = ""; for (int i = 0; i < indentLevel; i++) { retString += " "; } return retString; } public static Integer getInterfaceVlanNumber(String ifaceName) { String prefix = "vlan"; String ifaceNameLower = ifaceName.toLowerCase(); String withoutDot = ifaceNameLower.replaceAll("\\.", ""); if (withoutDot.startsWith(prefix)) { String vlanStr = withoutDot.substring(prefix.length()); if (vlanStr.length() > 0) { return Integer.parseInt(vlanStr); } } return null; } public static Path getJarOrClassDir(Class<?> locatorClass) { Path locatorDirFile = null; URL locatorSourceURL = locatorClass.getProtectionDomain().getCodeSource() .getLocation(); String locatorSourceString = locatorSourceURL.toString(); if (locatorSourceString.startsWith("onejar:")) { URI onejarSourceURI = null; try { URL onejarSourceURL = Class.forName("com.simontuffs.onejar.Boot") .getProtectionDomain().getCodeSource().getLocation(); onejarSourceURI = onejarSourceURL.toURI(); } catch (ClassNotFoundException e) { throw new BatfishException("could not find onejar class"); } catch (URISyntaxException e) { throw new BatfishException("Failed to convert onejar URL to URI", e); } Path jarDir = Paths.get(onejarSourceURI).getParent(); return jarDir; } else { char separator = System.getProperty("file.separator").charAt(0); String locatorPackageResourceName = locatorClass.getPackage().getName() .replace('.', separator); try { locatorDirFile = Paths.get(locatorClass.getClassLoader() .getResource(locatorPackageResourceName).toURI()); } catch (URISyntaxException e) { throw new BatfishException("Failed to resolve locator directory", e); } return locatorDirFile; } } public static List<String> getMatchingStrings(String regex, Set<String> allStrings) { List<String> matchingStrings = new ArrayList<>(); Pattern pattern; try { pattern = Pattern.compile(regex); } catch (PatternSyntaxException e) { throw new BatfishException( "Supplied regex is not a valid java regex: \"" + regex + "\"", e); } if (pattern != null) { for (String s : allStrings) { Matcher matcher = pattern.matcher(s); if (matcher.matches()) { matchingStrings.add(s); } } } else { matchingStrings.addAll(allStrings); } return matchingStrings; } public static String getTime(long millis) { long cs = (millis / 10) % 100; long s = (millis / 1000) % 60; long m = (millis / (1000 * 60)) % 60; long h = (millis / (1000 * 60 * 60)) % 24; String time = String.format("%02d:%02d:%02d.%02d", h, m, s, cs); return time; } public static <S extends Set<T>, T> S intersection(Set<T> set1, Set<T> set2, Supplier<S> setConstructor) { S intersectionSet = setConstructor.get(); intersectionSet.addAll(set1); intersectionSet.retainAll(set2); return intersectionSet; } public static int intWidth(int n) { if (n == 0) { return 1; } else { return 32 - Integer.numberOfLeadingZeros(n); } } public static boolean isLoopback(String interfaceName) { return (interfaceName.startsWith("Loopback") || interfaceName.startsWith("lo")); } public static boolean isNullInterface(String ifaceName) { String lcIfaceName = ifaceName.toLowerCase(); return lcIfaceName.startsWith("null"); } public static Stream<Path> list(Path configsPath) { try { return Files.list(configsPath); } catch (IOException e) { throw new BatfishException( "Could not list files in '" + configsPath.toString() + "'", e); } } public static String longToCommunity(Long l) { Long upper = l >> 16; Long lower = l & 0xFFFF; return upper.toString() + ":" + lower; } public static String md5Digest(String saltedSecret) { MessageDigest digest = null; try { digest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new BatfishException("Could not initialize md5 hasher", e); } byte[] plainTextBytes = null; plainTextBytes = saltedSecret.getBytes(StandardCharsets.UTF_8); byte[] digestBytes = digest.digest(plainTextBytes); StringBuffer sb = new StringBuffer(); for (int i = 0; i < digestBytes.length; i++) { int digestByteAsInt = 0xff & digestBytes[i]; if (digestByteAsInt < 0x10) { sb.append('0'); } sb.append(Integer.toHexString(digestByteAsInt)); } String md5 = sb.toString(); return md5; } public static int nullChecker(Object a, Object b) { if (a == null && b == null) { return 0; } else if (a != null && b != null) { return 1; } else { return -1; } } public static void outputFileLines(Path downloadedFile, Consumer<String> outputFunction) { try (BufferedReader br = new BufferedReader( new FileReader(downloadedFile.toFile()))) { String line = null; while ((line = br.readLine()) != null) { outputFunction.accept(line + "\n"); } } catch (IOException e) { throw new BatfishException("Failed to read and output lines of file: '" + downloadedFile.toString() + "'"); } } public static String readFile(Path file) { String text = null; try { text = new String(Files.readAllBytes(file), "UTF-8"); } catch (IOException e) { throw new BatfishException("Failed to read file: " + file.toString(), e); } return text; } public static String sha256Digest(String saltedSecret) { MessageDigest digest = null; try { digest = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { throw new BatfishException("Could not initialize sha256 hasher", e); } byte[] plainTextBytes = null; plainTextBytes = saltedSecret.getBytes(StandardCharsets.UTF_8); byte[] digestBytes = digest.digest(plainTextBytes); StringBuffer sb = new StringBuffer(); for (int i = 0; i < digestBytes.length; i++) { int digestByteAsInt = 0xff & digestBytes[i]; if (digestByteAsInt < 0x10) { sb.append('0'); } sb.append(Integer.toHexString(digestByteAsInt)); } String sha256 = sb.toString(); return sha256; } public static <S extends Set<T>, T> S symmetricDifference(Set<T> set1, Set<T> set2, Supplier<S> constructor) { S differenceSet = constructor.get(); differenceSet.addAll(set1); differenceSet.addAll(set2); S intersection = intersection(set1, set2, constructor); differenceSet.removeAll(intersection); return differenceSet; } public static SortedMap<Integer, String> toLineMap(String str) { SortedMap<Integer, String> map = new TreeMap<>(); String[] lines = str.split("\n"); for (int i = 0; i < lines.length; i++) { String line = lines[i]; map.put(i, line); } return map; } /** * Unescapes a string that contains standard Java escape sequences. * <ul> * <li><strong>\b \f \n \r \t \" \'</strong> : * BS, FF, NL, CR, TAB, double and single quote.</li> * <li><strong>\X \XX \XXX</strong> : Octal character * specification (0 - 377, 0x00 - 0xFF).</li> * <li><strong>\uXXXX</strong> : Hexadecimal based Unicode * character.</li> * </ul> * * @param st * A string optionally containing standard java escape sequences. * @return The translated string. */ public static String unescapeJavaString(String st) { if (st == null) { return null; } StringBuilder sb = new StringBuilder(st.length()); for (int i = 0; i < st.length(); i++) { char ch = st.charAt(i); if (ch == '\\') { char nextChar = (i == st.length() - 1) ? '\\' : st.charAt(i + 1); // Octal escape? if (nextChar >= '0' && nextChar <= '7') { String code = "" + nextChar; i++; if ((i < st.length() - 1) && st.charAt(i + 1) >= '0' && st.charAt(i + 1) <= '7') { code += st.charAt(i + 1); i++; if ((i < st.length() - 1) && st.charAt(i + 1) >= '0' && st.charAt(i + 1) <= '7') { code += st.charAt(i + 1); i++; } } sb.append((char) Integer.parseInt(code, 8)); continue; } switch (nextChar) { case '\\': ch = '\\'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case '\"': ch = '\"'; break; case '\'': ch = '\''; break; // Hex Unicode: u???? case 'u': if (i >= st.length() - 5) { ch = 'u'; break; } int code = Integer.parseInt("" + st.charAt(i + 2) + st.charAt(i + 3) + st.charAt(i + 4) + st.charAt(i + 5), 16); sb.append(Character.toChars(code)); i += 5; continue; } i++; } sb.append(ch); } return sb.toString(); } public static <S extends Set<T>, T> S union(Set<T> set1, Set<T> set2, Supplier<S> setConstructor) { S unionSet = setConstructor.get(); unionSet.addAll(set1); unionSet.addAll(set2); return unionSet; } public static void writeFile(Path outputPath, String output) { try { Files.write(outputPath, output.getBytes()); } catch (IOException e) { throw new BatfishException("Failed to write file: " + outputPath, e); } } }