// make a clone of all GraphNode except that only a few GraphEdge are kept // remove all uneeded GraphEdge to have only one GraphEdge between 2 GraphNodes (direct or indirect link) private GraphNode GenerateSimplifiedGraph(GraphNodeCollection nodes, GraphNode centralNode) { List <GraphNode> nodeAlreadyExamined = new List <GraphNode>(); GraphNode output = GraphNode.CloneWithoutTrusts(centralNode); Dictionary <DomainKey, GraphNode> graph = new Dictionary <DomainKey, GraphNode>(); graph.Add(output.Domain, output); List <GraphNode> nodesToExamine = new List <GraphNode>(); nodesToExamine.Add(centralNode); // proceed layer by layer for (int currentLevel = 0; ; currentLevel++) { List <GraphNode> nodesToExamineForNextLevel = new List <GraphNode>(); // this first iteration is important // it avoid a recursing exploration foreach (GraphNode nodeToExamine in nodesToExamine) { nodeAlreadyExamined.Add(nodeToExamine); } foreach (GraphNode nodeToExamine in nodesToExamine) { foreach (GraphEdge edge in nodeToExamine.Trusts.Values) { if (!nodeAlreadyExamined.Contains(edge.Destination) && !nodesToExamine.Contains(edge.Destination) && !nodesToExamineForNextLevel.Contains(edge.Destination)) { // make a clone and add one GraphEdge nodesToExamineForNextLevel.Add(edge.Destination); graph.Add(edge.Destination.Domain, GraphNode.CloneWithoutTrusts(edge.Destination)); GraphEdge newEdge = new GraphEdge(graph[nodeToExamine.Domain], graph[edge.Destination.Domain], null, false); graph[nodeToExamine.Domain].Trusts.Add(edge.Destination.Domain, newEdge); } } } if (nodesToExamineForNextLevel.Count == 0) { break; } nodesToExamine = nodesToExamineForNextLevel; } return(output); }
static public GraphNodeCollection BuildModel(PingCastleReportCollection <HealthcheckData> consolidation, OwnerInformationReferences EntityData) { GraphNodeCollection nodes = new GraphNodeCollection(); // build links based on the most to the less reliable information Trace.WriteLine("Building model"); int nodeNumber = 0; Trace.WriteLine("domain reports"); // enumerate official domains foreach (HealthcheckData data in consolidation) { GraphNode node = nodes.CreateNodeIfNeeded(ref nodeNumber, data.Domain, data.NetBIOSName, data.GenerationDate); node.HealthCheckData = data; node.SetForest(data.Forest); } Trace.WriteLine("direct trust"); // get trust map based on direct trusts data foreach (HealthcheckData data in consolidation) { GraphNode source = nodes.Locate(data); foreach (var trust in data.Trusts) { GraphNode destination = nodes.CreateNodeIfNeeded(ref nodeNumber, trust.Domain, trust.NetBiosName, data.GenerationDate); source.Link(destination, trust); } } Trace.WriteLine("forest trust"); foreach (HealthcheckData data in consolidation) { foreach (var trust in data.Trusts) { // do not examine if we have more accurate information (aka the forest report) if (consolidation.GetDomain(trust.Domain) != null) { continue; } if (trust.KnownDomains != null) { GraphNode source = nodes.Locate(trust); foreach (var domainInfo in trust.KnownDomains) { GraphNode destination = nodes.CreateNodeIfNeeded(ref nodeNumber, domainInfo.Domain, domainInfo.NetbiosName, data.GenerationDate); source.LinkInsideAForest(destination, domainInfo.CreationDate); destination.SetForest(domainInfo.Forest); } } } } Trace.WriteLine("Building reachable links"); // make links based on reachable domains. Information is less reliable. foreach (HealthcheckData data in consolidation) { // ignore report without reachable domains if (data.ReachableDomains == null) { continue; } // ignore reachable links if we have the forest domain report if (consolidation.GetDomain(data.Forest) != null) { continue; } foreach (HealthCheckTrustDomainInfoData di in data.ReachableDomains) { // domain info can contain only netbios name (not FQDN) // enrich it if (di.NetbiosName.Equals(di.DnsName, StringComparison.InvariantCultureIgnoreCase)) { EnrichDomainInfo(consolidation, di); } // if no information was given (only Netbios name!) fallback to a forest trust if (String.IsNullOrEmpty(di.ForestName) || di.ForestName == di.DnsName) { GraphNode childDomain = nodes.CreateNodeIfNeeded(ref nodeNumber, di.Domain, di.NetbiosName, data.GenerationDate); GraphNode myForestRoot = nodes.CreateNodeIfNeeded(ref nodeNumber, data.Forest, null, data.GenerationDate); myForestRoot.LinkTwoForests(childDomain); myForestRoot.SetForest(myForestRoot.Domain); } else { // ignore the domain if the forest trust is known (information should be already there) if (consolidation.GetDomain(di.Forest) != null) { continue; } // add the forest trust if needed GraphNode remoteForestRoot = nodes.CreateNodeIfNeeded(ref nodeNumber, di.Forest, di.ForestNetbios, data.GenerationDate); remoteForestRoot.SetForest(remoteForestRoot.Domain); // add the forest root if needed GraphNode myForestRoot = nodes.CreateNodeIfNeeded(ref nodeNumber, data.Forest, null, data.GenerationDate); myForestRoot.LinkTwoForests(remoteForestRoot); myForestRoot.SetForest(myForestRoot.Domain); // add the trust if the domain is a child of the forest) // (ignore the trust if forest root = trust) GraphNode childDomain = nodes.CreateNodeIfNeeded(ref nodeNumber, di.Domain, di.NetbiosName, data.GenerationDate); remoteForestRoot.LinkInsideAForest(childDomain); childDomain.SetForest(remoteForestRoot.Domain); } } } Trace.WriteLine("enrich forest information"); nodes.EnrichForestInformation(); Trace.WriteLine("done"); nodes.EnrichEntity(EntityData); nodes.RemoveDeletedNodes(); return(nodes); }