package org.batfish.question;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.batfish.common.Answerer;
import org.batfish.common.BatfishException;
import org.batfish.common.plugin.IBatfish;
import org.batfish.datamodel.Configuration;
import org.batfish.datamodel.IpsecVpn;
import org.batfish.datamodel.answers.AnswerElement;
import org.batfish.datamodel.questions.Question;
import com.fasterxml.jackson.annotation.JsonProperty;
public class PairwiseVpnConnectivityQuestionPlugin extends QuestionPlugin {
public static class PairwiseVpnConnectivityAnswerElement
implements AnswerElement {
private SortedMap<String, SortedSet<String>> _connectedNeighbors;
private SortedSet<String> _ipsecVpnNodes;
private SortedMap<String, SortedSet<String>> _missingNeighbors;
public PairwiseVpnConnectivityAnswerElement() {
_connectedNeighbors = new TreeMap<>();
_ipsecVpnNodes = new TreeSet<>();
_missingNeighbors = new TreeMap<>();
}
public SortedMap<String, SortedSet<String>> getConnectedNeighbors() {
return _connectedNeighbors;
}
public SortedSet<String> getIpsecVpnNodes() {
return _ipsecVpnNodes;
}
public SortedMap<String, SortedSet<String>> getMissingNeighbors() {
return _missingNeighbors;
}
public void setConnectedNeighbors(
SortedMap<String, SortedSet<String>> connectedNeighbors) {
_connectedNeighbors = connectedNeighbors;
}
public void setIpsecVpnNodes(SortedSet<String> ipsecVpnNodes) {
_ipsecVpnNodes = ipsecVpnNodes;
}
public void setMissingNeighbors(
SortedMap<String, SortedSet<String>> missingNeighbors) {
_missingNeighbors = missingNeighbors;
}
}
public static class PairwiseVpnConnectivityAnswerer extends Answerer {
public PairwiseVpnConnectivityAnswerer(Question question,
IBatfish batfish) {
super(question, batfish);
}
@Override
public AnswerElement answer() {
PairwiseVpnConnectivityQuestion question = (PairwiseVpnConnectivityQuestion) _question;
Pattern node1Regex;
Pattern node2Regex;
try {
node1Regex = Pattern.compile(question.getNode1Regex());
node2Regex = Pattern.compile(question.getNode2Regex());
}
catch (PatternSyntaxException e) {
throw new BatfishException(String.format(
"One of the supplied regexes (%s OR %s) is not a valid java regex.",
question.getNode1Regex(), question.getNode2Regex()), e);
}
PairwiseVpnConnectivityAnswerElement answerElement = new PairwiseVpnConnectivityAnswerElement();
_batfish.checkConfigurations();
Map<String, Configuration> configurations = _batfish
.loadConfigurations();
_batfish.initRemoteIpsecVpns(configurations);
Set<String> ipsecVpnNodes = answerElement.getIpsecVpnNodes();
Set<String> node2RegexNodes = new HashSet<>();
for (Configuration c : configurations.values()) {
String hostname = c.getHostname();
if (!c.getIpsecVpns().isEmpty()) {
if (node1Regex.matcher(hostname).matches()) {
ipsecVpnNodes.add(c.getHostname());
}
if (node2Regex.matcher(hostname).matches()) {
node2RegexNodes.add(hostname);
}
}
}
for (Configuration c : configurations.values()) {
String hostname = c.getHostname();
if (!ipsecVpnNodes.contains(hostname)) {
continue;
}
SortedSet<String> currentNeighbors = new TreeSet<>();
if (!c.getIpsecVpns().isEmpty()) {
for (IpsecVpn ipsecVpn : c.getIpsecVpns().values()) {
if (ipsecVpn.getRemoteIpsecVpn() != null) {
for (IpsecVpn remoteIpsecVpn : ipsecVpn
.getCandidateRemoteIpsecVpns()) {
String remoteHost = remoteIpsecVpn.getOwner()
.getHostname();
if (node2RegexNodes.contains(remoteHost)) {
currentNeighbors.add(remoteHost);
}
}
}
}
SortedSet<String> missingNeighbors = new TreeSet<>();
missingNeighbors.addAll(node2RegexNodes);
missingNeighbors.removeAll(currentNeighbors);
missingNeighbors.remove(hostname);
answerElement.getConnectedNeighbors().put(hostname,
currentNeighbors);
answerElement.getMissingNeighbors().put(hostname,
missingNeighbors);
}
}
return answerElement;
}
}
// <question_page_comment>
/**
* Checks if VPN connectivity between pairs of nodes is correctly configured.
* <p>
* Details coming on what it means to be correctly configured.
*
* @type PairwiseVpnConnectivity multifile
*
* @param node1Regex
* Regular expression to match the nodes names for one end of the
* sessions. Default is '.*' (all nodes).
* @param node2Regex
* Regular expression to match the nodes names for the other end of
* the sessions. Default is '.*' (all nodes).
*
* @example bf_answer("PairwiseVpnConnectivity", node1Regex="as1.*",
* node2Regex="as2.*") Checks pairwise VPN connectivity between
* nodes that start with as1 and those that start with as2.
*/
public static class PairwiseVpnConnectivityQuestion extends Question {
private static final String NODE1_REGEX_VAR = "node1Regex";
private static final String NODE2_REGEX_VAR = "node2Regex";
private String _node1Regex;
private String _node2Regex;
public PairwiseVpnConnectivityQuestion() {
_node1Regex = ".*";
_node2Regex = ".*";
}
@Override
public boolean getDataPlane() {
return false;
}
@Override
public String getName() {
return "pairwisevpnconnectivity";
}
@JsonProperty(NODE1_REGEX_VAR)
public String getNode1Regex() {
return _node1Regex;
}
@JsonProperty(NODE2_REGEX_VAR)
public String getNode2Regex() {
return _node2Regex;
}
@Override
public boolean getTraffic() {
return false;
}
@JsonProperty(NODE1_REGEX_VAR)
public void setNode1Regex(String regex) {
_node1Regex = regex;
}
@JsonProperty(NODE2_REGEX_VAR)
public void setNode2Regex(String regex) {
_node2Regex = regex;
}
}
@Override
protected Answerer createAnswerer(Question question, IBatfish batfish) {
return new PairwiseVpnConnectivityAnswerer(question, batfish);
}
@Override
protected Question createQuestion() {
return new PairwiseVpnConnectivityQuestion();
}
}