@Test public void testOutgoingOriginalFlowFilter() { NetworkFactory nf = new NetworkFactory(); Configuration c = nf.configurationBuilder().setConfigurationFormat(ConfigurationFormat.CISCO_IOS).build(); Vrf vrf = nf.vrfBuilder().setOwner(c).build(); Interface iface = nf.interfaceBuilder().setOwner(c).setVrf(vrf).build(); Ip blockedSrcIp = Ip.parse("1.1.1.1"); Ip permittedSrcIp = Ip.parse("1.1.1.2"); Ip dstIp = Ip.parse("2.2.2.2"); IpAccessList filter = nf.aclBuilder() .setLines( ExprAclLine.rejecting(AclLineMatchExprs.matchSrc(blockedSrcIp)), ExprAclLine.ACCEPT_ALL) .build(); iface.setOutgoingOriginalFlowFilter(filter); Flow flowWithBlockedSrc = Flow.builder() .setSrcIp(blockedSrcIp) .setDstIp(dstIp) .setIngressNode(c.getHostname()) .setIngressVrf(vrf.getName()) .build(); Flow flowWithPermittedSrc = flowWithBlockedSrc.toBuilder().setSrcIp(permittedSrcIp).build(); ForwardingAnalysis forwardingAnalysis = MockForwardingAnalysis.builder() .setDeliveredToSubnet( ImmutableMap.of( c.getHostname(), ImmutableMap.of( vrf.getName(), ImmutableMap.of(iface.getName(), dstIp.toIpSpace())))) .build(); ImmutableMap<String, Configuration> configs = ImmutableMap.of(c.getHostname(), c); TracerouteEngineImplContext ctxt = new TracerouteEngineImplContext( MockDataPlane.builder().setForwardingAnalysis(forwardingAnalysis).build(), Topology.EMPTY, ImmutableSet.of(), ImmutableSet.of(), ImmutableMap.of(), false, configs); FlowDiff flowDiff = FlowDiff.flowDiff(IpField.SOURCE, blockedSrcIp, permittedSrcIp); TransformationStep placeholderTransformationStep = new TransformationStep( new TransformationStepDetail( TransformationType.SOURCE_NAT, ImmutableSortedSet.of(flowDiff)), StepAction.TRANSFORMED); { List<Step<?>> steps = new ArrayList<>(); steps.add(placeholderTransformationStep); List<TraceAndReverseFlow> traces = new ArrayList<>(); FlowTracer flowTracer = new FlowTracer( ctxt, c, null, new Node(c.getHostname()), new LegacyTraceRecorder(traces::add), NodeInterfacePair.of("node", "iface"), new ArrayList<>(), flowWithBlockedSrc, vrf.getName(), new ArrayList<>(), steps, new Stack<>(), flowWithPermittedSrc, 0, 0); flowTracer.forwardOutInterface(iface, dstIp, null); assertThat(traces, hasSize(1)); assertThat(traces.get(0).getTrace(), hasDisposition(DENIED_OUT)); } { List<Step<?>> steps = new ArrayList<>(); steps.add(placeholderTransformationStep); List<TraceAndReverseFlow> traces = new ArrayList<>(); FlowTracer flowTracer = new FlowTracer( ctxt, c, null, new Node(c.getHostname()), new LegacyTraceRecorder(traces::add), NodeInterfacePair.of("node", "iface"), new ArrayList<>(), flowWithPermittedSrc, vrf.getName(), new ArrayList<>(), steps, new Stack<>(), flowWithBlockedSrc, 0, 0); flowTracer.forwardOutInterface(iface, dstIp, null); assertThat(traces, hasSize(1)); assertThat(traces.get(0).getTrace(), hasDisposition(DELIVERED_TO_SUBNET)); } }
@VisibleForTesting void forwardOutInterface( Interface outgoingInterface, Ip nextHopIp, @Nullable Ip overriddenNextHopIp) { if (applyFilter( outgoingInterface.getPreTransformationOutgoingFilter(), PRE_TRANSFORMATION_EGRESS_FILTER) == DENIED) { return; } applyTransformation(outgoingInterface.getOutgoingTransformation()); if (applyFilter(outgoingInterface.getOutgoingFilter(), EGRESS_FILTER) == DENIED) { return; } if (applyFilterToOriginalFlow( outgoingInterface.getOutgoingOriginalFlowFilter(), EGRESS_ORIGINAL_FLOW_FILTER) == DENIED) { return; } FirewallSessionInterfaceInfo firewallSessionInterfaceInfo = outgoingInterface.getFirewallSessionInterfaceInfo(); if (firewallSessionInterfaceInfo != null) { @Nullable FirewallSessionTraceInfo session = buildFirewallSessionTraceInfo(firewallSessionInterfaceInfo); if (session != null) { _newSessions.add(session); _steps.add( new SetupSessionStep( SetupSessionStepDetail.builder() .setSessionScope(session.getSessionScope()) .setMatchCriteria(session.getMatchCriteria()) .setSessionAction(session.getAction()) .setTransformation(returnFlowDiffs(_originalFlow, _currentFlow)) .build())); } } String currentNodeName = _currentNode.getName(); String outgoingIfaceName = outgoingInterface.getName(); _steps.add(buildExitOutputIfaceStep(outgoingIfaceName)); SortedSet<NodeInterfacePair> neighborIfaces = _tracerouteContext.getInterfaceNeighbors(currentNodeName, outgoingIfaceName); if (neighborIfaces.isEmpty()) { Ip arpIp = firstNonNull(overriddenNextHopIp, _currentFlow.getDstIp()); FlowDisposition disposition = _tracerouteContext.computeDisposition(currentNodeName, outgoingIfaceName, arpIp); buildArpFailureTrace(outgoingIfaceName, arpIp, disposition); } else { processOutgoingInterfaceEdges( outgoingIfaceName, firstNonNull(overriddenNextHopIp, nextHopIp), neighborIfaces); } }
FlowTracer { @VisibleForTesting void forwardOutInterface( Interface outgoingInterface, Ip nextHopIp, @Nullable Ip overriddenNextHopIp) { if (applyFilter( outgoingInterface.getPreTransformationOutgoingFilter(), PRE_TRANSFORMATION_EGRESS_FILTER) == DENIED) { return; } applyTransformation(outgoingInterface.getOutgoingTransformation()); if (applyFilter(outgoingInterface.getOutgoingFilter(), EGRESS_FILTER) == DENIED) { return; } if (applyFilterToOriginalFlow( outgoingInterface.getOutgoingOriginalFlowFilter(), EGRESS_ORIGINAL_FLOW_FILTER) == DENIED) { return; } FirewallSessionInterfaceInfo firewallSessionInterfaceInfo = outgoingInterface.getFirewallSessionInterfaceInfo(); if (firewallSessionInterfaceInfo != null) { @Nullable FirewallSessionTraceInfo session = buildFirewallSessionTraceInfo(firewallSessionInterfaceInfo); if (session != null) { _newSessions.add(session); _steps.add( new SetupSessionStep( SetupSessionStepDetail.builder() .setSessionScope(session.getSessionScope()) .setMatchCriteria(session.getMatchCriteria()) .setSessionAction(session.getAction()) .setTransformation(returnFlowDiffs(_originalFlow, _currentFlow)) .build())); } } String currentNodeName = _currentNode.getName(); String outgoingIfaceName = outgoingInterface.getName(); _steps.add(buildExitOutputIfaceStep(outgoingIfaceName)); SortedSet<NodeInterfacePair> neighborIfaces = _tracerouteContext.getInterfaceNeighbors(currentNodeName, outgoingIfaceName); if (neighborIfaces.isEmpty()) { Ip arpIp = firstNonNull(overriddenNextHopIp, _currentFlow.getDstIp()); FlowDisposition disposition = _tracerouteContext.computeDisposition(currentNodeName, outgoingIfaceName, arpIp); buildArpFailureTrace(outgoingIfaceName, arpIp, disposition); } else { processOutgoingInterfaceEdges( outgoingIfaceName, firstNonNull(overriddenNextHopIp, nextHopIp), neighborIfaces); } } }
FlowTracer { @VisibleForTesting void forwardOutInterface( Interface outgoingInterface, Ip nextHopIp, @Nullable Ip overriddenNextHopIp) { if (applyFilter( outgoingInterface.getPreTransformationOutgoingFilter(), PRE_TRANSFORMATION_EGRESS_FILTER) == DENIED) { return; } applyTransformation(outgoingInterface.getOutgoingTransformation()); if (applyFilter(outgoingInterface.getOutgoingFilter(), EGRESS_FILTER) == DENIED) { return; } if (applyFilterToOriginalFlow( outgoingInterface.getOutgoingOriginalFlowFilter(), EGRESS_ORIGINAL_FLOW_FILTER) == DENIED) { return; } FirewallSessionInterfaceInfo firewallSessionInterfaceInfo = outgoingInterface.getFirewallSessionInterfaceInfo(); if (firewallSessionInterfaceInfo != null) { @Nullable FirewallSessionTraceInfo session = buildFirewallSessionTraceInfo(firewallSessionInterfaceInfo); if (session != null) { _newSessions.add(session); _steps.add( new SetupSessionStep( SetupSessionStepDetail.builder() .setSessionScope(session.getSessionScope()) .setMatchCriteria(session.getMatchCriteria()) .setSessionAction(session.getAction()) .setTransformation(returnFlowDiffs(_originalFlow, _currentFlow)) .build())); } } String currentNodeName = _currentNode.getName(); String outgoingIfaceName = outgoingInterface.getName(); _steps.add(buildExitOutputIfaceStep(outgoingIfaceName)); SortedSet<NodeInterfacePair> neighborIfaces = _tracerouteContext.getInterfaceNeighbors(currentNodeName, outgoingIfaceName); if (neighborIfaces.isEmpty()) { Ip arpIp = firstNonNull(overriddenNextHopIp, _currentFlow.getDstIp()); FlowDisposition disposition = _tracerouteContext.computeDisposition(currentNodeName, outgoingIfaceName, arpIp); buildArpFailureTrace(outgoingIfaceName, arpIp, disposition); } else { processOutgoingInterfaceEdges( outgoingIfaceName, firstNonNull(overriddenNextHopIp, nextHopIp), neighborIfaces); } } @VisibleForTesting  FlowTracer(
      TracerouteEngineImplContext tracerouteContext,
      Configuration currentConfig,
      @Nullable String ingressInterface,
      Node currentNode,
      TraceRecorder traceRecorder,
      @Nullable NodeInterfacePair lastHopNodeAndOutgoingInterface,
      List<FirewallSessionTraceInfo> newSessions,
      Flow originalFlow,
      @Nonnull String vrfName,
      List<HopInfo> hops,
      List<Step<?>> steps,
      Stack<Breadcrumb> breadcrumbs,
      Flow currentFlow,
      int origNewSessionsSize,
      int origBreadcrumbsSize); }
FlowTracer { @VisibleForTesting void forwardOutInterface( Interface outgoingInterface, Ip nextHopIp, @Nullable Ip overriddenNextHopIp) { if (applyFilter( outgoingInterface.getPreTransformationOutgoingFilter(), PRE_TRANSFORMATION_EGRESS_FILTER) == DENIED) { return; } applyTransformation(outgoingInterface.getOutgoingTransformation()); if (applyFilter(outgoingInterface.getOutgoingFilter(), EGRESS_FILTER) == DENIED) { return; } if (applyFilterToOriginalFlow( outgoingInterface.getOutgoingOriginalFlowFilter(), EGRESS_ORIGINAL_FLOW_FILTER) == DENIED) { return; } FirewallSessionInterfaceInfo firewallSessionInterfaceInfo = outgoingInterface.getFirewallSessionInterfaceInfo(); if (firewallSessionInterfaceInfo != null) { @Nullable FirewallSessionTraceInfo session = buildFirewallSessionTraceInfo(firewallSessionInterfaceInfo); if (session != null) { _newSessions.add(session); _steps.add( new SetupSessionStep( SetupSessionStepDetail.builder() .setSessionScope(session.getSessionScope()) .setMatchCriteria(session.getMatchCriteria()) .setSessionAction(session.getAction()) .setTransformation(returnFlowDiffs(_originalFlow, _currentFlow)) .build())); } } String currentNodeName = _currentNode.getName(); String outgoingIfaceName = outgoingInterface.getName(); _steps.add(buildExitOutputIfaceStep(outgoingIfaceName)); SortedSet<NodeInterfacePair> neighborIfaces = _tracerouteContext.getInterfaceNeighbors(currentNodeName, outgoingIfaceName); if (neighborIfaces.isEmpty()) { Ip arpIp = firstNonNull(overriddenNextHopIp, _currentFlow.getDstIp()); FlowDisposition disposition = _tracerouteContext.computeDisposition(currentNodeName, outgoingIfaceName, arpIp); buildArpFailureTrace(outgoingIfaceName, arpIp, disposition); } else { processOutgoingInterfaceEdges( outgoingIfaceName, firstNonNull(overriddenNextHopIp, nextHopIp), neighborIfaces); } } @VisibleForTesting  FlowTracer(
      TracerouteEngineImplContext tracerouteContext,
      Configuration currentConfig,
      @Nullable String ingressInterface,
      Node currentNode,
      TraceRecorder traceRecorder,
      @Nullable NodeInterfacePair lastHopNodeAndOutgoingInterface,
      List<FirewallSessionTraceInfo> newSessions,
      Flow originalFlow,
      @Nonnull String vrfName,
      List<HopInfo> hops,
      List<Step<?>> steps,
      Stack<Breadcrumb> breadcrumbs,
      Flow currentFlow,
      int origNewSessionsSize,
      int origBreadcrumbsSize);  }
FlowTracer { @VisibleForTesting void forwardOutInterface( Interface outgoingInterface, Ip nextHopIp, @Nullable Ip overriddenNextHopIp) { if (applyFilter( outgoingInterface.getPreTransformationOutgoingFilter(), PRE_TRANSFORMATION_EGRESS_FILTER) == DENIED) { return; } applyTransformation(outgoingInterface.getOutgoingTransformation()); if (applyFilter(outgoingInterface.getOutgoingFilter(), EGRESS_FILTER) == DENIED) { return; } if (applyFilterToOriginalFlow( outgoingInterface.getOutgoingOriginalFlowFilter(), EGRESS_ORIGINAL_FLOW_FILTER) == DENIED) { return; } FirewallSessionInterfaceInfo firewallSessionInterfaceInfo = outgoingInterface.getFirewallSessionInterfaceInfo(); if (firewallSessionInterfaceInfo != null) { @Nullable FirewallSessionTraceInfo session = buildFirewallSessionTraceInfo(firewallSessionInterfaceInfo); if (session != null) { _newSessions.add(session); _steps.add( new SetupSessionStep( SetupSessionStepDetail.builder() .setSessionScope(session.getSessionScope()) .setMatchCriteria(session.getMatchCriteria()) .setSessionAction(session.getAction()) .setTransformation(returnFlowDiffs(_originalFlow, _currentFlow)) .build())); } } String currentNodeName = _currentNode.getName(); String outgoingIfaceName = outgoingInterface.getName(); _steps.add(buildExitOutputIfaceStep(outgoingIfaceName)); SortedSet<NodeInterfacePair> neighborIfaces = _tracerouteContext.getInterfaceNeighbors(currentNodeName, outgoingIfaceName); if (neighborIfaces.isEmpty()) { Ip arpIp = firstNonNull(overriddenNextHopIp, _currentFlow.getDstIp()); FlowDisposition disposition = _tracerouteContext.computeDisposition(currentNodeName, outgoingIfaceName, arpIp); buildArpFailureTrace(outgoingIfaceName, arpIp, disposition); } else { processOutgoingInterfaceEdges( outgoingIfaceName, firstNonNull(overriddenNextHopIp, nextHopIp), neighborIfaces); } } @VisibleForTesting  FlowTracer(
      TracerouteEngineImplContext tracerouteContext,
      Configuration currentConfig,
      @Nullable String ingressInterface,
      Node currentNode,
      TraceRecorder traceRecorder,
      @Nullable NodeInterfacePair lastHopNodeAndOutgoingInterface,
      List<FirewallSessionTraceInfo> newSessions,
      Flow originalFlow,
      @Nonnull String vrfName,
      List<HopInfo> hops,
      List<Step<?>> steps,
      Stack<Breadcrumb> breadcrumbs,
      Flow currentFlow,
      int origNewSessionsSize,
      int origBreadcrumbsSize);   }