package org.batfish.client;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.function.Supplier;
import org.batfish.common.BatfishException;
import org.batfish.datamodel.ForwardingAction;
import org.batfish.datamodel.Ip;
import org.batfish.datamodel.IpWildcard;
import org.batfish.datamodel.Protocol;
import org.batfish.datamodel.questions.*;
import com.fasterxml.jackson.annotation.JsonCreator;
public class QuestionHelper {
public enum MacroType {
CHECKPROTECTION("checkprotection"),
CHECKREACHABILITY("checkreachability"),
TRACEROUTE("traceroute");
private final static Map<String, MacroType> _map = buildMap();
private static Map<String, MacroType> buildMap() {
Map<String, MacroType> map = new HashMap<>();
for (MacroType value : MacroType.values()) {
String name = value._name;
map.put(name, value);
}
return Collections.unmodifiableMap(map);
}
@JsonCreator
public static MacroType fromName(String name) {
MacroType instance = _map.get(name.toLowerCase());
if (instance == null) {
throw new BatfishException(
"Not a valid MacroType: \"" + name + "\"");
}
return instance;
}
private final String _name;
private MacroType(String name) {
_name = name;
}
public String macroTypeName() {
return _name;
}
}
public static final String MACRO_PREFIX = "#";
public static String getParametersString(Map<String, String> parameters)
throws Exception {
String retString = "{\n";
for (String paramKey : parameters.keySet()) {
retString += String.format("\"%s\" : %s,\n", paramKey,
parameters.get(paramKey));
}
retString += "}\n";
return retString;
}
public static Question getQuestion(String questionTypeStr,
Map<String, Supplier<Question>> questions) {
Supplier<Question> supplier = questions.get(questionTypeStr);
if (supplier == null) {
throw new BatfishException("No question of type: " + questionTypeStr);
}
Question question = supplier.get();
return question;
}
public static String getQuestionString(String questionTypeStr,
Map<String, Supplier<Question>> questions, boolean full) {
Question question = getQuestion(questionTypeStr, questions);
if (full) {
return question.toFullJsonString();
}
else {
return question.toJsonString();
}
}
public static IQuestion getReachabilityQuestion(String dstIp,
String protocolStr, String ingressNodeRegex, ForwardingAction action,
Map<String, Supplier<Question>> questions) {
IReachabilityQuestion question = (IReachabilityQuestion) questions
.get(IReachabilityQuestion.NAME).get();
question.setDstIps(new TreeSet<>(
Collections.singleton(new IpWildcard(new Ip(dstIp)))));
boolean inverted = false;
if (protocolStr.startsWith("!")) {
inverted = true;
protocolStr = protocolStr.substring(1);
}
SortedSet<Protocol> protocols = new TreeSet<>(
Collections.singleton(Protocol.fromString(protocolStr)));
if (inverted) {
question.setNotDstProtocols(protocols);
}
else {
question.setDstProtocols(protocols);
}
if (ingressNodeRegex != null) {
question.setIngressNodeRegex(ingressNodeRegex);
}
SortedSet<ForwardingAction> actionSet = new TreeSet<>();
actionSet.add(action);
question.setActions(actionSet);
return question;
}
public static String resolveMacro(String macroName, String paramsLine,
Map<String, Supplier<Question>> questions) {
String macro = macroName.replace(MACRO_PREFIX, "");
MacroType macroType = MacroType.fromName(macro);
switch (macroType) {
case CHECKPROTECTION: {
String[] words = paramsLine.split(" ");
if (words.length < 2 || words.length > 3) {
throw new BatfishException(
"Incorrect usage for noreachability macro. "
+ "Should be:\n #checkreachability <dstip> <protocol> [<ingressNodeRegex>]");
}
String dstIp = words[0];
String protocol = words[1];
String ingressNodeRegex = (words.length == 3) ? words[2] : null;
return getReachabilityQuestion(dstIp, protocol, ingressNodeRegex,
ForwardingAction.ACCEPT, questions).toJsonString();
}
case CHECKREACHABILITY: {
String[] words = paramsLine.split(" ");
if (words.length < 2 || words.length > 3) {
throw new BatfishException(
"Incorrect usage for noreachability macro. "
+ "Should be:\n #checkreachability <dstip> <protocol> [<ingressNodeRegex>]");
}
String dstIp = words[0];
String protocol = words[1];
String ingressNodeRegex = (words.length == 3) ? words[2] : null;
return getReachabilityQuestion(dstIp, protocol, ingressNodeRegex,
ForwardingAction.DROP, questions).toJsonString();
}
case TRACEROUTE: {
String[] words = paramsLine.split(" ");
if (words.length < 2 || words.length > 3) {
throw new BatfishException("Incorrect usage for traceroute macro. "
+ "Should be:\n #traceroute <srcNode> <dstip> [<protocol>]");
}
ITracerouteQuestion question = (ITracerouteQuestion) questions
.get(ITracerouteQuestion.NAME).get();
String srcNode = words[0];
String dstIp = words[1];
question.setIngressNode(srcNode);
question.setDstIp(new Ip(dstIp));
if (words.length == 3) {
String protocolStr = words[2];
Protocol protocol = Protocol.fromString(protocolStr);
question.setDstProtocol(protocol);
}
// else {
// question.setIpProtocol(IpProtocol.ICMP);
// }
return question.toJsonString();
}
default:
throw new BatfishException("Unknown macrotype: " + macroType);
}
}
}