Merge pull request #1410 from weaveworks/1408-dnat-shortlived-connections

Correctly attribute DNAT-ed short-lived connections
This commit is contained in:
Alfonso Acosta
2016-05-05 19:37:35 +01:00
7 changed files with 99 additions and 17 deletions

View File

@@ -298,7 +298,7 @@ func (c *container) NetworkMode() (string, bool) {
func addScopeToIPs(hostID string, ips []string) []string {
ipsWithScopes := []string{}
for _, ip := range ips {
ipsWithScopes = append(ipsWithScopes, report.MakeScopedAddressNodeID(hostID, ip))
ipsWithScopes = append(ipsWithScopes, report.MakeAddressNodeID(hostID, ip))
}
return ipsWithScopes
}

View File

@@ -113,7 +113,7 @@ func TestContainer(t *testing.T) {
want := report.EmptySets.
Add("docker_container_ports", report.MakeStringSet("1.2.3.4:80->80/tcp", "81/tcp")).
Add("docker_container_ips", report.MakeStringSet("1.2.3.4")).
Add("docker_container_ips_with_scopes", report.MakeStringSet("scope;1.2.3.4"))
Add("docker_container_ips_with_scopes", report.MakeStringSet(";1.2.3.4"))
test.Poll(t, 100*time.Millisecond, want, func() interface{} {
return c.NetworkInfo([]net.IP{})

View File

@@ -30,7 +30,7 @@ func TestNat(t *testing.T) {
// the setup is this:
//
// container2 (10.0.47.2:222222), host2 (2.3.4.5:22223) ->
// host1 (1.2.3.4:80), container1 (10.0.47.2:80)
// host1 (1.2.3.4:80), container1 (10.0.47.1:80)
// from the PoV of host1
{

View File

@@ -106,7 +106,7 @@ func (r *Reporter) Report() (report.Report, error) {
rpt := report.MakeReport()
seenTuples := map[string]fourTuple{}
// Consult the flowWalker for short-live connections
// Consult the flowWalker for short-lived connections
{
extraNodeInfo := map[string]string{
Conntracked: "true",
@@ -118,6 +118,18 @@ func (r *Reporter) Report() (report.Report, error) {
uint16(f.Original.Layer4.SrcPort),
uint16(f.Original.Layer4.DstPort),
}
// Handle DNAT-ed short-lived connections.
// The NAT mapper won't help since it only runs periodically,
// missing the short-lived connections.
if f.Original.Layer3.DstIP != f.Reply.Layer3.SrcIP {
tuple = fourTuple{
f.Reply.Layer3.DstIP,
f.Reply.Layer3.SrcIP,
uint16(f.Reply.Layer4.DstPort),
uint16(f.Reply.Layer4.SrcPort),
}
}
seenTuples[tuple.key()] = tuple
r.addConnection(&rpt, tuple, extraNodeInfo, extraNodeInfo)
})

View File

@@ -94,7 +94,7 @@ func (r *Reporter) podEvent(e Event, pod Pod) {
}
func isPauseContainer(n report.Node, rpt report.Report) bool {
containerImageIDs, ok := n.Sets.Lookup(report.ContainerImage)
containerImageIDs, ok := n.Parents.Lookup(report.ContainerImage)
if !ok {
return false
}

View File

@@ -138,8 +138,12 @@ func probeMain(flags probeFlags) {
p.AddTagger(probe.NewTopologyTagger(), host.NewTagger(hostID))
if flags.dockerEnabled {
if err := report.AddLocalBridge(flags.dockerBridge); err != nil {
log.Errorf("Docker: problem with bridge %s: %v", flags.dockerBridge, err)
// Don't add the bridge in Kubernetes since container IPs are global and
// shouldn't be scoped
if !flags.kubernetesEnabled {
if err := report.AddLocalBridge(flags.dockerBridge); err != nil {
log.Errorf("Docker: problem with bridge %s: %v", flags.dockerBridge, err)
}
}
if registry, err := docker.NewRegistry(flags.dockerInterval, clients, true, hostID); err == nil {
defer registry.Stop()

View File

@@ -4,6 +4,8 @@ import (
"fmt"
"testing"
"github.com/weaveworks/scope/common/mtime"
"github.com/weaveworks/scope/probe/docker"
"github.com/weaveworks/scope/probe/endpoint"
"github.com/weaveworks/scope/probe/host"
@@ -23,10 +25,27 @@ var (
serverPort = "80"
serverEndpointNodeID = report.MakeEndpointNodeID(serverHostID, serverIP, serverPort)
containerID = "a1b2c3d4e5"
containerIP = "192.168.0.1"
containerName = "foo"
containerNodeID = report.MakeContainerNodeID(containerID)
container1ID = "11b2c3d4e5"
container1IP = "192.168.0.1"
container1Name = "foo"
container1NodeID = report.MakeContainerNodeID(container1ID)
container1Port = "16782"
container1EndpointNodeID = report.MakeEndpointNodeID(serverHostID, container1IP, container1Port)
duplicatedIP = "192.168.0.2"
duplicatedPort = "80"
duplicatedEndpointNodeID = report.MakeEndpointNodeID(serverHostID, duplicatedIP, duplicatedPort)
container2ID = "21b2c3d4e5"
container2IP = duplicatedIP
container2Name = "bar"
container2NodeID = report.MakeContainerNodeID(container2ID)
pauseContainerID = "31b2c3d4e5"
pauseContainerIP = duplicatedIP
pauseContainerName = "POD"
pauseContainerNodeID = report.MakeContainerNodeID(pauseContainerID)
rpt = report.Report{
Endpoint: report.Topology{
@@ -44,19 +63,52 @@ var (
endpoint.Conntracked: "true",
}).
WithTopology(report.Endpoint),
container1EndpointNodeID: report.MakeNodeWith(container1EndpointNodeID, map[string]string{
endpoint.Addr: container1IP,
endpoint.Port: container1Port,
endpoint.Conntracked: "true",
}).
WithAdjacent(duplicatedEndpointNodeID).WithTopology(report.Endpoint),
duplicatedEndpointNodeID: report.MakeNodeWith(duplicatedEndpointNodeID, map[string]string{
endpoint.Addr: duplicatedIP,
endpoint.Port: duplicatedPort,
endpoint.Conntracked: "true",
}).
WithTopology(report.Endpoint),
},
},
Container: report.Topology{
Nodes: report.Nodes{
containerNodeID: report.MakeNodeWith(containerNodeID, map[string]string{
docker.ContainerID: containerID,
docker.ContainerName: containerName,
container1NodeID: report.MakeNodeWith(container1NodeID, map[string]string{
docker.ContainerID: container1ID,
docker.ContainerName: container1Name,
report.HostNodeID: serverHostNodeID,
}).
WithSets(report.EmptySets.
Add(docker.ContainerIPs, report.MakeStringSet(containerIP)).
Add(docker.ContainerIPs, report.MakeStringSet(container1IP)).
Add(docker.ContainerIPsWithScopes, report.MakeStringSet(report.MakeAddressNodeID("", container1IP))).
Add(docker.ContainerPorts, report.MakeStringSet(fmt.Sprintf("%s:%s->%s/tcp", serverIP, serverPort, serverPort))),
).WithTopology(report.Container),
container2NodeID: report.MakeNodeWith(container2NodeID, map[string]string{
docker.ContainerID: container2ID,
docker.ContainerName: container2Name,
report.HostNodeID: serverHostNodeID,
}).
WithSets(report.EmptySets.
Add(docker.ContainerIPs, report.MakeStringSet(container2IP)).
Add(docker.ContainerIPsWithScopes, report.MakeStringSet(report.MakeAddressNodeID("", container2IP))),
).WithTopology(report.Container),
pauseContainerNodeID: report.MakeNodeWith(pauseContainerNodeID, map[string]string{
docker.ContainerID: pauseContainerID,
docker.ContainerName: pauseContainerName,
report.HostNodeID: serverHostNodeID,
}).
WithSets(report.EmptySets.
Add(docker.ContainerIPs, report.MakeStringSet(pauseContainerIP)).
Add(docker.ContainerIPsWithScopes, report.MakeStringSet(report.MakeAddressNodeID("", pauseContainerIP))),
).WithTopology(report.Container).WithLatest(report.DoesNotMakeConnections, mtime.Now(), ""),
},
},
Host: report.Topology{
@@ -81,7 +133,21 @@ func TestShortLivedInternetNodeConnections(t *testing.T) {
t.Fatal("Expected output to have an incoming internet node")
}
if !internet.Adjacency.Contains(report.MakeContainerNodeID(containerID)) {
t.Errorf("Expected internet node to have adjacency to %s, but only had %v", report.MakeContainerNodeID(containerID), internet.Adjacency)
if !internet.Adjacency.Contains(container1NodeID) {
t.Errorf("Expected internet node to have adjacency to %s, but only had %v", container1NodeID, internet.Adjacency)
}
}
func TestPauseContainerDiscarded(t *testing.T) {
have := Prune(render.ContainerWithImageNameRenderer.Render(rpt, render.FilterNoop))
// There should be a single connection between from container1 and the destination should be container2
container1, ok := have[container1NodeID]
if !ok {
t.Fatal("Expected output to have container1")
}
if !container1.Adjacency.Contains(container2NodeID) {
t.Errorf("Expected container1 to have adjacency to %s, but only had %v", container2NodeID, container1.Adjacency)
}
}