use of org.batfish.datamodel.Ip in project batfish by batfish.
the class Client method validateType.
/**
* Validate the contents contained in json-encoded {@code value} matches the type required by
* {@code variable}, and the length of input string meets the requirement of minimum length if
* specified in {@code variable}. Call {@link Variable#getType()} on {@code variable} gives the
* expected type.
*
* @throws BatfishException if the content encoded in input {@code value} does not satisfy the
* requirements specified in {@code variable}.
*/
static void validateType(JsonNode value, Variable variable) throws BatfishException {
int minLength = variable.getMinLength() == null ? 0 : variable.getMinLength();
if (value.isTextual() && value.textValue().length() < minLength) {
throw new BatfishException(String.format("Must be at least %s characters in length", minLength));
}
Variable.Type expectedType = variable.getType();
switch(expectedType) {
case BOOLEAN:
if (!value.isBoolean()) {
throw new BatfishException(String.format("It is not a valid JSON %s value", expectedType.getName()));
}
break;
case COMPARATOR:
if (!(COMPARATORS.contains(value.textValue()))) {
throw new BatfishException(String.format("It is not a known %s. Valid options are:" + " %s", expectedType.getName(), COMPARATORS));
}
break;
case DOUBLE:
if (!value.isDouble()) {
throw new BatfishException(String.format("It is not a valid JSON %s value", expectedType.getName()));
}
break;
case FLOAT:
if (!value.isFloat()) {
throw new BatfishException(String.format("It is not a valid JSON %s value", expectedType.getName()));
}
break;
case INTEGER:
if (!value.isInt()) {
throw new BatfishException(String.format("It is not a valid JSON %s value", expectedType.getName()));
}
break;
case LONG:
if (!value.isLong()) {
throw new BatfishException(String.format("It is not a valid JSON %s value", expectedType.getName()));
}
break;
case IP:
// TODO: Need to double check isInetAddress()
if (!(value.isTextual())) {
throw new BatfishException(String.format("A Batfish %s must be a JSON string", expectedType.getName()));
}
new Ip(value.textValue());
break;
case IP_PROTOCOL:
if (!value.isTextual()) {
throw new BatfishException(String.format("A Batfish %s must be a JSON string", expectedType.getName()));
}
try {
IpProtocol.fromString(value.textValue());
} catch (IllegalArgumentException e) {
throw new BatfishException(String.format("Unknown %s string", expectedType.getName()));
}
break;
case IP_WILDCARD:
if (!value.isTextual()) {
throw new BatfishException(String.format("A Batfish %s must be a JSON string", expectedType.getName()));
}
new IpWildcard(value.textValue());
break;
case JAVA_REGEX:
if (!value.isTextual()) {
throw new BatfishException(String.format("A Batfish %s must be a JSON string", expectedType.getName()));
}
try {
Pattern.compile(value.textValue());
} catch (PatternSyntaxException e) {
throw new BatfishException("It is not a valid Java regular " + "expression", e);
}
break;
case JSON_PATH_REGEX:
if (!value.isTextual()) {
throw new BatfishException(String.format("A Batfish %s must be a JSON string", expectedType.getName()));
}
validateJsonPathRegex(value.textValue());
break;
case PREFIX:
if (!value.isTextual()) {
throw new BatfishException(String.format("A Batfish %s must be a JSON string", expectedType.getName()));
}
Prefix.parse(value.textValue());
break;
case PREFIX_RANGE:
if (!value.isTextual()) {
throw new BatfishException(String.format("A Batfish %s must be a JSON string", expectedType.getName()));
}
PrefixRange.fromString(value.textValue());
break;
case QUESTION:
// TODO: Implement
break;
case STRING:
if (!value.isTextual()) {
throw new BatfishException(String.format("A Batfish %s must be a JSON string", expectedType.getName()));
}
break;
case SUBRANGE:
if (!(value.isTextual() || value.isInt())) {
throw new BatfishException(String.format("A Batfish %s must be a JSON string or " + "integer", expectedType.getName()));
}
Object actualValue = value.isTextual() ? value.textValue() : value.asInt();
new SubRange(actualValue);
break;
case PROTOCOL:
if (!value.isTextual()) {
throw new BatfishException(String.format("A Batfish %s must be a JSON string", expectedType.getName()));
}
Protocol.fromString(value.textValue());
break;
case JSON_PATH:
validateJsonPath(value);
break;
default:
throw new BatfishException(String.format("Unsupported parameter type: %s", expectedType));
}
}
use of org.batfish.datamodel.Ip in project batfish by batfish.
the class CommonUtil method initRemoteIpsecVpns.
public static void initRemoteIpsecVpns(Map<String, Configuration> configurations) {
Map<IpsecVpn, Ip> vpnRemoteIps = new IdentityHashMap<>();
Map<Ip, Set<IpsecVpn>> externalIpVpnMap = new HashMap<>();
SetMultimap<Ip, IpWildcardSetIpSpace> privateIpsByPublicIp = initPrivateIpsByPublicIp(configurations);
for (Configuration c : configurations.values()) {
for (IpsecVpn ipsecVpn : c.getIpsecVpns().values()) {
Ip remoteIp = ipsecVpn.getIkeGateway().getAddress();
vpnRemoteIps.put(ipsecVpn, remoteIp);
Set<InterfaceAddress> externalAddresses = ipsecVpn.getIkeGateway().getExternalInterface().getAllAddresses();
for (InterfaceAddress address : externalAddresses) {
Ip ip = address.getIp();
Set<IpsecVpn> vpnsUsingExternalAddress = externalIpVpnMap.computeIfAbsent(ip, k -> Sets.newIdentityHashSet());
vpnsUsingExternalAddress.add(ipsecVpn);
}
}
}
for (Entry<IpsecVpn, Ip> e : vpnRemoteIps.entrySet()) {
IpsecVpn ipsecVpn = e.getKey();
Ip remoteIp = e.getValue();
Ip localIp = ipsecVpn.getIkeGateway().getLocalIp();
ipsecVpn.initCandidateRemoteVpns();
Set<IpsecVpn> remoteIpsecVpnCandidates = externalIpVpnMap.get(remoteIp);
if (remoteIpsecVpnCandidates != null) {
for (IpsecVpn remoteIpsecVpnCandidate : remoteIpsecVpnCandidates) {
Ip remoteIpsecVpnLocalAddress = remoteIpsecVpnCandidate.getIkeGateway().getLocalIp();
if (remoteIpsecVpnLocalAddress != null && !remoteIpsecVpnLocalAddress.equals(remoteIp)) {
continue;
}
Ip reciprocalRemoteAddress = vpnRemoteIps.get(remoteIpsecVpnCandidate);
Set<IpsecVpn> reciprocalVpns = externalIpVpnMap.get(reciprocalRemoteAddress);
if (reciprocalVpns == null) {
Set<IpWildcardSetIpSpace> privateIpsBehindReciprocalRemoteAddress = privateIpsByPublicIp.get(reciprocalRemoteAddress);
if (privateIpsBehindReciprocalRemoteAddress != null && privateIpsBehindReciprocalRemoteAddress.stream().anyMatch(ipSpace -> ipSpace.containsIp(localIp))) {
reciprocalVpns = externalIpVpnMap.get(localIp);
ipsecVpn.setRemoteIpsecVpn(remoteIpsecVpnCandidate);
ipsecVpn.getCandidateRemoteIpsecVpns().add(remoteIpsecVpnCandidate);
remoteIpsecVpnCandidate.initCandidateRemoteVpns();
remoteIpsecVpnCandidate.setRemoteIpsecVpn(ipsecVpn);
remoteIpsecVpnCandidate.getCandidateRemoteIpsecVpns().add(ipsecVpn);
}
} else if (reciprocalVpns.contains(ipsecVpn)) {
ipsecVpn.setRemoteIpsecVpn(remoteIpsecVpnCandidate);
ipsecVpn.getCandidateRemoteIpsecVpns().add(remoteIpsecVpnCandidate);
}
}
}
}
}
use of org.batfish.datamodel.Ip in project batfish by batfish.
the class CommonUtil method initRemoteBgpNeighbors.
/**
* Initialize BGP neighbors for all nodes.
*
* @param configurations map of all configurations, keyed by hostname
* @param ipOwners mapping of Ips to a set of nodes (hostnames) that owns those IPs
* @param checkReachability whether bgp neighbor reachability should be checked
* @param flowProcessor dataplane plugin to use to check reachability. Must not be {@code null} if
* {@code checkReachability = true}
* @param dp dataplane to use to check reachability. Must not be {@code null} if {@code
* checkReachability = true}
*/
public static void initRemoteBgpNeighbors(Map<String, Configuration> configurations, Map<Ip, Set<String>> ipOwners, boolean checkReachability, @Nullable FlowProcessor flowProcessor, @Nullable DataPlane dp) {
// TODO: handle duplicate ips on different vrfs
Map<BgpNeighbor, Ip> remoteAddresses = new IdentityHashMap<>();
Map<Ip, Set<BgpNeighbor>> localAddresses = new HashMap<>();
/*
* Construct maps indicating which neighbor owns which Ip Address
*/
for (Configuration node : configurations.values()) {
String hostname = node.getHostname();
for (Vrf vrf : node.getVrfs().values()) {
BgpProcess proc = vrf.getBgpProcess();
if (proc == null) {
// nothing to do if no bgp process on this VRF
continue;
}
for (BgpNeighbor bgpNeighbor : proc.getNeighbors().values()) {
/*
* Begin by initializing candidate neighbors to an empty set
*/
bgpNeighbor.initCandidateRemoteBgpNeighbors();
// Skip things we don't handle
if (bgpNeighbor.getPrefix().getPrefixLength() < Prefix.MAX_PREFIX_LENGTH) {
throw new BatfishException(hostname + ": Do not support dynamic bgp sessions at this time: " + bgpNeighbor.getPrefix());
}
Ip remoteAddress = bgpNeighbor.getAddress();
if (remoteAddress == null) {
throw new BatfishException(hostname + ": Could not determine remote address of bgp neighbor: " + bgpNeighbor);
}
Ip localAddress = bgpNeighbor.getLocalIp();
if (localAddress == null || !ipOwners.containsKey(localAddress) || !ipOwners.get(localAddress).contains(hostname)) {
// Local address is not owned by anybody
continue;
}
remoteAddresses.put(bgpNeighbor, remoteAddress);
// Add this neighbor as owner of its local address
localAddresses.computeIfAbsent(localAddress, k -> Collections.newSetFromMap(new IdentityHashMap<>())).add(bgpNeighbor);
}
}
}
/*
* For each neighbor, construct the set of candidate neighbors, then filter out impossible
* sessions.
*/
for (Entry<BgpNeighbor, Ip> e : remoteAddresses.entrySet()) {
BgpNeighbor bgpNeighbor = e.getKey();
Ip remoteAddress = e.getValue();
Ip localAddress = bgpNeighbor.getLocalIp();
int localLocalAs = bgpNeighbor.getLocalAs();
int localRemoteAs = bgpNeighbor.getRemoteAs();
/*
* Let the set of candidate neighbors be set of neighbors that own the remoteAddress
*/
Set<BgpNeighbor> remoteBgpNeighborCandidates = localAddresses.get(remoteAddress);
if (remoteBgpNeighborCandidates == null) {
// No possible remote neighbors
continue;
}
/*
* Filter the set of candidate neighbors based on these checks:
* - Remote neighbor's remote address is the same as our local address
* - Remote neighbor's remote AS is the same as our local AS (and vice-versa)
*/
for (BgpNeighbor remoteBgpNeighborCandidate : remoteBgpNeighborCandidates) {
int remoteLocalAs = remoteBgpNeighborCandidate.getLocalAs();
int remoteRemoteAs = remoteBgpNeighborCandidate.getRemoteAs();
Ip reciprocalRemoteIp = remoteBgpNeighborCandidate.getAddress();
if (localAddress.equals(reciprocalRemoteIp) && localLocalAs == remoteRemoteAs && localRemoteAs == remoteLocalAs) {
/*
* Fairly confident establishing the session is possible here, but still check
* reachability if needed.
* We should check reachability only for eBgp multihop or iBgp
*/
if (checkReachability && (bgpNeighbor.getEbgpMultihop() || localLocalAs == remoteLocalAs)) {
/*
* Ensure that the session can be established by running traceroute in both directions
*/
if (flowProcessor == null || dp == null) {
throw new BatfishException("Cannot compute neighbor reachability without a dataplane");
}
Flow.Builder fb = new Flow.Builder();
fb.setIpProtocol(IpProtocol.TCP);
fb.setTag("neighbor-resolution");
fb.setIngressNode(bgpNeighbor.getOwner().getHostname());
fb.setSrcIp(localAddress);
fb.setDstIp(remoteAddress);
fb.setSrcPort(NamedPort.EPHEMERAL_LOWEST.number());
fb.setDstPort(NamedPort.BGP.number());
Flow forwardFlow = fb.build();
fb.setIngressNode(remoteBgpNeighborCandidate.getOwner().getHostname());
fb.setSrcIp(forwardFlow.getDstIp());
fb.setDstIp(forwardFlow.getSrcIp());
fb.setSrcPort(forwardFlow.getDstPort());
fb.setDstPort(forwardFlow.getSrcPort());
Flow backwardFlow = fb.build();
SortedMap<Flow, Set<FlowTrace>> traces = flowProcessor.processFlows(dp, ImmutableSet.of(forwardFlow, backwardFlow));
if (traces.values().stream().map(fts -> fts.stream().allMatch(ft -> ft.getDisposition() != FlowDisposition.ACCEPTED)).anyMatch(Predicate.isEqual(true))) {
/*
* If either flow has all traceroutes fail, do not consider the neighbor valid
*/
continue;
}
bgpNeighbor.getCandidateRemoteBgpNeighbors().add(remoteBgpNeighborCandidate);
} else {
bgpNeighbor.getCandidateRemoteBgpNeighbors().add(remoteBgpNeighborCandidate);
}
}
}
Set<BgpNeighbor> finalCandidates = bgpNeighbor.getCandidateRemoteBgpNeighbors();
if (finalCandidates.size() > 1) {
/* If we still have not narrowed it down to a single neighbor,
* pick based on sorted hostnames
*/
SortedMap<String, BgpNeighbor> hostnameToNeighbor = finalCandidates.stream().collect(ImmutableSortedMap.toImmutableSortedMap(String::compareTo, k -> k.getOwner().getHostname(), Function.identity()));
bgpNeighbor.setRemoteBgpNeighbor(hostnameToNeighbor.get(hostnameToNeighbor.firstKey()));
} else if (finalCandidates.size() == 1) {
bgpNeighbor.setRemoteBgpNeighbor(finalCandidates.iterator().next());
} else {
bgpNeighbor.setRemoteBgpNeighbor(null);
}
}
}
use of org.batfish.datamodel.Ip in project batfish by batfish.
the class IpPair method part2.
private static Ip part2(String s) {
String trimmed = s.substring(1, s.length() - 1);
String[] parts = trimmed.split(":");
String part2Str = parts[1];
Ip part2 = new Ip(part2Str);
return part2;
}
use of org.batfish.datamodel.Ip in project batfish by batfish.
the class IpPair method part1.
private static Ip part1(String s) {
String trimmed = s.substring(1, s.length() - 1);
String[] parts = trimmed.split(":");
String part1Str = parts[0];
Ip part1 = new Ip(part1Str);
return part1;
}
Aggregations