Merge pull request #197 from tomwilkie/196-foo

Don't make adjacency edges into 'the internet' if they refer to valid nodes
This commit is contained in:
Tom Wilkie
2015-06-10 10:31:22 +01:00
12 changed files with 97 additions and 81 deletions

View File

@@ -18,10 +18,10 @@ func (s StaticReport) Report() report.Report {
var testReport = report.Report{
Endpoint: report.Topology{
Adjacency: report.Adjacency{
report.MakeAdjacencyID("hostA", report.MakeEndpointNodeID("hostA", "192.168.1.1", "12345")): report.MakeIDList(report.MakeEndpointNodeID("hostB", "192.168.1.2", "80")),
report.MakeAdjacencyID("hostA", report.MakeEndpointNodeID("hostA", "192.168.1.1", "12346")): report.MakeIDList(report.MakeEndpointNodeID("hostB", "192.168.1.2", "80")),
report.MakeAdjacencyID("hostA", report.MakeEndpointNodeID("hostA", "192.168.1.1", "8888")): report.MakeIDList(report.MakeEndpointNodeID("", "1.2.3.4", "22")),
report.MakeAdjacencyID("hostB", report.MakeEndpointNodeID("hostB", "192.168.1.2", "80")): report.MakeIDList(report.MakeEndpointNodeID("hostA", "192.168.1.1", "12345")),
report.MakeAdjacencyID(report.MakeEndpointNodeID("hostA", "192.168.1.1", "12345")): report.MakeIDList(report.MakeEndpointNodeID("hostB", "192.168.1.2", "80")),
report.MakeAdjacencyID(report.MakeEndpointNodeID("hostA", "192.168.1.1", "12346")): report.MakeIDList(report.MakeEndpointNodeID("hostB", "192.168.1.2", "80")),
report.MakeAdjacencyID(report.MakeEndpointNodeID("hostA", "192.168.1.1", "8888")): report.MakeIDList(report.MakeEndpointNodeID("", "1.2.3.4", "22")),
report.MakeAdjacencyID(report.MakeEndpointNodeID("hostB", "192.168.1.2", "80")): report.MakeIDList(report.MakeEndpointNodeID("hostA", "192.168.1.1", "12345")),
},
EdgeMetadatas: report.EdgeMetadatas{
report.MakeEdgeID(report.MakeEndpointNodeID("hostA", "192.168.1.1", "12345"), report.MakeEndpointNodeID("hostB", "192.168.1.2", "80")): report.EdgeMetadata{
@@ -79,8 +79,8 @@ func (s StaticReport) Report() report.Report {
Address: report.Topology{
Adjacency: report.Adjacency{
report.MakeAdjacencyID("hostA", report.MakeAddressNodeID("hostA", "192.168.1.1")): report.MakeIDList(report.MakeAddressNodeID("hostB", "192.168.1.2"), report.MakeAddressNodeID("", "1.2.3.4")),
report.MakeAdjacencyID("hostB", report.MakeAddressNodeID("hostB", "192.168.1.2")): report.MakeIDList(report.MakeAddressNodeID("hostA", "192.168.1.1")),
report.MakeAdjacencyID(report.MakeAddressNodeID("hostA", "192.168.1.1")): report.MakeIDList(report.MakeAddressNodeID("hostB", "192.168.1.2"), report.MakeAddressNodeID("", "1.2.3.4")),
report.MakeAdjacencyID(report.MakeAddressNodeID("hostB", "192.168.1.2")): report.MakeIDList(report.MakeAddressNodeID("hostA", "192.168.1.1")),
},
EdgeMetadatas: report.EdgeMetadatas{
report.MakeEdgeID(report.MakeAddressNodeID("hostA", "192.168.1.1"), report.MakeAddressNodeID("hostB", "192.168.1.2")): report.EdgeMetadata{

View File

@@ -59,12 +59,12 @@ func DemoReport(nodeCount int) report.Report {
srcPort = rand.Intn(50000) + 10000
srcPortID = report.MakeEndpointNodeID("", src, strconv.Itoa(srcPort))
dstPortID = report.MakeEndpointNodeID("", dst, strconv.Itoa(c.dstPort))
srcID = report.MakeAdjacencyID("hostX", srcPortID)
dstID = report.MakeAdjacencyID("hostX", dstPortID)
srcID = report.MakeAdjacencyID(srcPortID)
dstID = report.MakeAdjacencyID(dstPortID)
srcAddressID = report.MakeAddressNodeID("", src)
dstAddressID = report.MakeAddressNodeID("", dst)
nodeSrcAddressID = report.MakeAdjacencyID("hostX", srcAddressID)
nodeDstAddressID = report.MakeAdjacencyID("hostX", dstAddressID)
nodeSrcAddressID = report.MakeAdjacencyID(srcAddressID)
nodeDstAddressID = report.MakeAdjacencyID(dstAddressID)
)
// Endpoint topology

View File

@@ -59,12 +59,12 @@ func DemoReport(nodeCount int) report.Report {
srcPort = rand.Intn(50000) + 10000
srcPortID = report.MakeEndpointNodeID("", src, strconv.Itoa(srcPort))
dstPortID = report.MakeEndpointNodeID("", dst, strconv.Itoa(c.dstPort))
srcID = report.MakeAdjacencyID("hostX", srcPortID)
dstID = report.MakeAdjacencyID("hostX", dstPortID)
srcID = report.MakeAdjacencyID(srcPortID)
dstID = report.MakeAdjacencyID(dstPortID)
srcAddressID = report.MakeAddressNodeID("", src)
dstAddressID = report.MakeAddressNodeID("", dst)
nodeSrcAddressID = report.MakeAdjacencyID("hostX", srcAddressID)
nodeDstAddressID = report.MakeAdjacencyID("hostX", dstAddressID)
nodeSrcAddressID = report.MakeAdjacencyID(srcAddressID)
nodeDstAddressID = report.MakeAdjacencyID(dstAddressID)
)
// Endpoint topology

View File

@@ -45,7 +45,7 @@ func addConnection(
var (
scopedLocal = report.MakeAddressNodeID(hostID, c.LocalAddress.String())
scopedRemote = report.MakeAddressNodeID(hostID, c.RemoteAddress.String())
key = report.MakeAdjacencyID(hostID, scopedLocal)
key = report.MakeAdjacencyID(scopedLocal)
edgeKey = report.MakeEdgeID(scopedLocal, scopedRemote)
)
@@ -67,7 +67,7 @@ func addConnection(
var (
scopedLocal = report.MakeEndpointNodeID(hostID, c.LocalAddress.String(), strconv.Itoa(int(c.LocalPort)))
scopedRemote = report.MakeEndpointNodeID(hostID, c.RemoteAddress.String(), strconv.Itoa(int(c.RemotePort)))
key = report.MakeAdjacencyID(hostID, scopedLocal)
key = report.MakeAdjacencyID(scopedLocal)
edgeKey = report.MakeEdgeID(scopedLocal, scopedRemote)
)

View File

@@ -82,7 +82,7 @@ func TestSpyNoProcesses(t *testing.T) {
var (
scopedLocal = report.MakeAddressNodeID(nodeID, fixLocalAddress.String())
scopedRemote = report.MakeAddressNodeID(nodeID, fixRemoteAddress.String())
localKey = report.MakeAdjacencyID(nodeID, scopedLocal)
localKey = report.MakeAdjacencyID(scopedLocal)
)
if want, have := 1, len(r.Address.Adjacency[localKey]); want != have {
@@ -112,7 +112,7 @@ func TestSpyWithProcesses(t *testing.T) {
var (
scopedLocal = report.MakeEndpointNodeID(nodeID, fixLocalAddress.String(), strconv.Itoa(int(fixLocalPort)))
scopedRemote = report.MakeEndpointNodeID(nodeID, fixRemoteAddress.String(), strconv.Itoa(int(fixRemotePort)))
localKey = report.MakeAdjacencyID(nodeID, scopedLocal)
localKey = report.MakeAdjacencyID(scopedLocal)
)
if want, have := 1, len(r.Endpoint.Adjacency[localKey]); want != have {

View File

@@ -22,26 +22,17 @@ const (
EdgeDelim = "|"
)
// MakeAdjacencyID produces an adjacency ID from composite parts.
func MakeAdjacencyID(hostID, srcNodeID string) string {
// Here we rely on the fact that every possible source node ID has the
// host ID as the first scope-delimited field, and therefore don't
// duplicate that information.
// MakeAdjacencyID produces an adjacency ID from a node id.
func MakeAdjacencyID(srcNodeID string) string {
return ">" + srcNodeID
}
// ParseAdjacencyID splits an adjacency ID to its composite parts.
func ParseAdjacencyID(adjacencyID string) (hostID, srcNodeID string, ok bool) {
// ParseAdjacencyID produces a node id from an adjancency id
func ParseAdjacencyID(adjacencyID string) (string, bool) {
if !strings.HasPrefix(adjacencyID, ">") {
return "", "", false
return "", false
}
// This relies on every node ID having hostID as its first scoped field.
adjacencyID = adjacencyID[1:]
fields := strings.SplitN(adjacencyID, ScopeDelim, 2)
if len(fields) != 2 {
return "", "", false
}
return fields[0], adjacencyID, true
return adjacencyID[1:], true
}
// MakeEdgeID produces an edge ID from composite parts.
@@ -81,6 +72,15 @@ func MakeHostNodeID(hostID string) string {
return hostID + ScopeDelim + "<host>"
}
// ParseNodeID produces the scope and remainder from a node ID
func ParseNodeID(nodeID string) (string, string, bool) {
fields := strings.SplitN(nodeID, ScopeDelim, 2)
if len(fields) != 2 {
return "", "", false
}
return fields[0], fields[1], true
}
// MakePseudoNodeID produces a pseudo node ID from its composite parts.
func MakePseudoNodeID(parts ...string) string {
return strings.Join(append([]string{"pseudo"}, parts...), ScopeDelim)

View File

@@ -20,36 +20,31 @@ func TestAdjacencyID(t *testing.T) {
unknownAddressNodeID,
clientHostNodeID,
serverHostNodeID,
">1.2.3.4",
">",
";",
"",
} {
if hostID, srcNodeID, ok := report.ParseAdjacencyID(bad); ok {
t.Errorf("%q: expected failure, but got (%q, %q)", bad, hostID, srcNodeID)
if srcNodeID, ok := report.ParseAdjacencyID(bad); ok {
t.Errorf("%q: expected failure, but got (%q)", bad, srcNodeID)
}
}
for input, want := range map[string]struct{ hostID, srcNodeID string }{
report.MakeAdjacencyID("a", report.MakeEndpointNodeID("a", "b", "c")): {"a", report.MakeEndpointNodeID("a", "b", "c")},
report.MakeAdjacencyID("a", report.MakeAddressNodeID("a", "b")): {"a", report.MakeAddressNodeID("a", "b")},
report.MakeAdjacencyID("a", report.MakeProcessNodeID("a", "b")): {"a", report.MakeProcessNodeID("a", "b")},
report.MakeAdjacencyID("a", report.MakeHostNodeID("a")): {"a", report.MakeHostNodeID("a")},
">host.com;1.2.3.4": {"host.com", "host.com;1.2.3.4"},
">a;b;c": {"a", "a;b;c"},
">a;b": {"a", "a;b"},
">a;": {"a", "a;"},
">;b": {"", ";b"},
">;": {"", ";"},
for input, want := range map[string]struct{ srcNodeID string }{
report.MakeAdjacencyID(report.MakeEndpointNodeID("a", "b", "c")): {report.MakeEndpointNodeID("a", "b", "c")},
report.MakeAdjacencyID(report.MakeAddressNodeID("a", "b")): {report.MakeAddressNodeID("a", "b")},
report.MakeAdjacencyID(report.MakeProcessNodeID("a", "b")): {report.MakeProcessNodeID("a", "b")},
report.MakeAdjacencyID(report.MakeHostNodeID("a")): {report.MakeHostNodeID("a")},
">host.com;1.2.3.4": {"host.com;1.2.3.4"},
">a;b;c": {"a;b;c"},
">a;b": {"a;b"},
">a;": {"a;"},
">;b": {";b"},
">;": {";"},
} {
hostID, srcNodeID, ok := report.ParseAdjacencyID(input)
srcNodeID, ok := report.ParseAdjacencyID(input)
if !ok {
t.Errorf("%q: not OK", input)
continue
}
if want, have := want.hostID, hostID; want != have {
t.Errorf("%q: want %q, have %q", input, want, have)
}
if want, have := want.srcNodeID, srcNodeID; want != have {
t.Errorf("%q: want %q, have %q", input, want, have)
}

View File

@@ -205,5 +205,8 @@ func trySplitAddr(addr string) (string, string) {
if len(fields) == 3 {
return fields[1], fields[2]
}
return fields[1], ""
if len(fields) == 2 {
return fields[1], ""
}
panic(addr)
}

View File

@@ -7,9 +7,9 @@ import (
var reportFixture = report.Report{
Endpoint: report.Topology{
Adjacency: report.Adjacency{
report.MakeAdjacencyID(clientHostID, client54001EndpointNodeID): report.MakeIDList(server80EndpointNodeID),
report.MakeAdjacencyID(clientHostID, client54002EndpointNodeID): report.MakeIDList(server80EndpointNodeID),
report.MakeAdjacencyID(serverHostID, server80EndpointNodeID): report.MakeIDList(client54001EndpointNodeID, client54002EndpointNodeID, unknown1EndpointNodeID, unknown2EndpointNodeID, unknown3EndpointNodeID),
report.MakeAdjacencyID(client54001EndpointNodeID): report.MakeIDList(server80EndpointNodeID),
report.MakeAdjacencyID(client54002EndpointNodeID): report.MakeIDList(server80EndpointNodeID),
report.MakeAdjacencyID(server80EndpointNodeID): report.MakeIDList(client54001EndpointNodeID, client54002EndpointNodeID, unknown1EndpointNodeID, unknown2EndpointNodeID, unknown3EndpointNodeID),
},
NodeMetadatas: report.NodeMetadatas{
client54001EndpointNodeID: report.NodeMetadata{
@@ -71,8 +71,8 @@ var reportFixture = report.Report{
},
Address: report.Topology{
Adjacency: report.Adjacency{
report.MakeAdjacencyID(clientHostID, clientAddressNodeID): report.MakeIDList(serverAddressNodeID),
report.MakeAdjacencyID(serverHostID, serverAddressNodeID): report.MakeIDList(clientAddressNodeID, unknownAddressNodeID),
report.MakeAdjacencyID(clientAddressNodeID): report.MakeIDList(serverAddressNodeID),
report.MakeAdjacencyID(serverAddressNodeID): report.MakeIDList(clientAddressNodeID, unknownAddressNodeID),
},
NodeMetadatas: report.NodeMetadatas{
clientAddressNodeID: report.NodeMetadata{

View File

@@ -25,9 +25,9 @@ func TestReportLocalNetworks(t *testing.T) {
func TestReportSquash(t *testing.T) {
{
want := report.Adjacency{
report.MakeAdjacencyID(clientHostID, client54001EndpointNodeID): report.MakeIDList(server80EndpointNodeID),
report.MakeAdjacencyID(clientHostID, client54002EndpointNodeID): report.MakeIDList(server80EndpointNodeID),
report.MakeAdjacencyID(serverHostID, server80EndpointNodeID): report.MakeIDList(client54001EndpointNodeID, client54002EndpointNodeID, report.TheInternet),
report.MakeAdjacencyID(client54001EndpointNodeID): report.MakeIDList(server80EndpointNodeID),
report.MakeAdjacencyID(client54002EndpointNodeID): report.MakeIDList(server80EndpointNodeID),
report.MakeAdjacencyID(server80EndpointNodeID): report.MakeIDList(client54001EndpointNodeID, client54002EndpointNodeID, report.TheInternet),
}
have := reportFixture.Squash().Endpoint.Adjacency
if !reflect.DeepEqual(want, have) {
@@ -36,8 +36,8 @@ func TestReportSquash(t *testing.T) {
}
{
want := report.Adjacency{
report.MakeAdjacencyID(clientHostID, clientAddressNodeID): report.MakeIDList(serverAddressNodeID),
report.MakeAdjacencyID(serverHostID, serverAddressNodeID): report.MakeIDList(clientAddressNodeID, report.TheInternet),
report.MakeAdjacencyID(clientAddressNodeID): report.MakeIDList(serverAddressNodeID),
report.MakeAdjacencyID(serverAddressNodeID): report.MakeIDList(clientAddressNodeID, report.TheInternet),
}
have := reportFixture.Squash().Address.Adjacency
if !reflect.DeepEqual(want, have) {

View File

@@ -113,19 +113,20 @@ func (t Topology) RenderBy(mapFunc MapFunc, pseudoFunc PseudoFunc) map[string]Re
// Walk the graph and make connections.
for src, dsts := range t.Adjacency {
var (
srcOriginHostID, srcNodeAddress, ok = ParseAdjacencyID(src)
srcRenderableID = address2mapped[srcNodeAddress] // must exist
srcRenderableNode = nodes[srcRenderableID] // must exist
srcNodeID, ok1 = ParseAdjacencyID(src)
srcOriginHostID, _, ok2 = ParseNodeID(srcNodeID)
srcRenderableID = address2mapped[srcNodeID] // must exist
srcRenderableNode = nodes[srcRenderableID] // must exist
)
if !ok {
if !ok1 || !ok2 {
log.Printf("bad adjacency ID %q", src)
continue
}
for _, dstNodeAddress := range dsts {
dstRenderableID, ok := address2mapped[dstNodeAddress]
for _, dstNodeID := range dsts {
dstRenderableID, ok := address2mapped[dstNodeID]
if !ok {
pseudoNode, ok := pseudoFunc(srcNodeAddress, srcRenderableNode, dstNodeAddress)
pseudoNode, ok := pseudoFunc(srcNodeID, srcRenderableNode, dstNodeID)
if !ok {
continue
}
@@ -137,13 +138,13 @@ func (t Topology) RenderBy(mapFunc MapFunc, pseudoFunc PseudoFunc) map[string]Re
Pseudo: true,
Metadata: AggregateMetadata{}, // populated below - or not?
}
address2mapped[dstNodeAddress] = dstRenderableID
address2mapped[dstNodeID] = dstRenderableID
}
srcRenderableNode.Adjacency = srcRenderableNode.Adjacency.Add(dstRenderableID)
srcRenderableNode.Origins = srcRenderableNode.Origins.Add(MakeHostNodeID(srcOriginHostID))
srcRenderableNode.Origins = srcRenderableNode.Origins.Add(srcNodeAddress)
edgeID := MakeEdgeID(srcNodeAddress, dstNodeAddress)
srcRenderableNode.Origins = srcRenderableNode.Origins.Add(srcNodeID)
edgeID := MakeEdgeID(srcNodeID, dstNodeID)
if md, ok := t.EdgeMetadatas[edgeID]; ok {
srcRenderableNode.Metadata.Merge(md.Transform())
}
@@ -184,12 +185,29 @@ func (t Topology) EdgeMetadata(mapFunc MapFunc, srcRenderableID, dstRenderableID
// Squash squashes all non-local nodes in the topology to a super-node called
// the Internet.
// We rely on the values in the t.Adjacency lists being valid keys in
// t.NodeMetadata (or t.Adjacency).
func (t Topology) Squash(f IDAddresser, localNets []*net.IPNet) Topology {
isRemote := func(ip net.IP) bool { return !netsContain(localNets, ip) }
isRemote := func(id string) bool {
if _, ok := t.NodeMetadatas[id]; ok {
return false // it is a node, cannot possibly be remote
}
if _, ok := t.Adjacency[MakeAdjacencyID(id)]; ok {
return false // it is in our adjacency list, cannot possibly be remote
}
if ip := f(id); ip != nil && netsContain(localNets, ip) {
return false // it is in our local nets, so it is not remote
}
return true
}
for srcID, dstIDs := range t.Adjacency {
newDstIDs := make(IDList, 0, len(dstIDs))
for _, dstID := range dstIDs {
if ip := f(dstID); ip != nil && isRemote(ip) {
if isRemote(dstID) {
dstID = TheInternet
}
newDstIDs = newDstIDs.Add(dstID)

View File

@@ -36,9 +36,9 @@ var (
report = Report{
Endpoint: Topology{
Adjacency: Adjacency{
MakeAdjacencyID("client.hostname.com", client54001): MakeIDList(server80),
MakeAdjacencyID("client.hostname.com", client54002): MakeIDList(server80),
MakeAdjacencyID("server.hostname.com", server80): MakeIDList(client54001, client54002, unknownClient1, unknownClient2, unknownClient3),
MakeAdjacencyID(client54001): MakeIDList(server80),
MakeAdjacencyID(client54002): MakeIDList(server80),
MakeAdjacencyID(server80): MakeIDList(client54001, client54002, unknownClient1, unknownClient2, unknownClient3),
},
NodeMetadatas: NodeMetadatas{
// NodeMetadata is arbitrary. We're free to put only precisely what we
@@ -101,9 +101,9 @@ var (
},
Address: Topology{
Adjacency: Adjacency{
MakeAdjacencyID("client.hostname.com", clientIP): MakeIDList(serverIP),
MakeAdjacencyID("random.hostname.com", randomIP): MakeIDList(serverIP),
MakeAdjacencyID("server.hostname.com", serverIP): MakeIDList(clientIP, unknownIP), // no backlink to random
MakeAdjacencyID(clientIP): MakeIDList(serverIP),
MakeAdjacencyID(randomIP): MakeIDList(serverIP),
MakeAdjacencyID(serverIP): MakeIDList(clientIP, unknownIP), // no backlink to random
},
NodeMetadatas: NodeMetadatas{
clientIP: NodeMetadata{