From 5b5dd1379bfc6af0d77ca4572cfb3b5b98aaeec4 Mon Sep 17 00:00:00 2001 From: Zach Wasserman Date: Fri, 26 Mar 2021 18:05:49 -0700 Subject: [PATCH] Prefer IPv4 in Host Details (#548) - Use a non-loopback, non-link-local IPv4 address if available - Otherwise use non-loopback, non-link-local IPv6 address if available - Otherwise use any address Closes #532 --- server/service/service_osquery.go | 37 ++++++++++++++++++------ server/service/service_osquery_test.go | 39 +++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/server/service/service_osquery.go b/server/service/service_osquery.go index a78a51e5bd..57d7f19683 100644 --- a/server/service/service_osquery.go +++ b/server/service/service_osquery.go @@ -346,6 +346,9 @@ var detailQueries = map[string]struct { return nil } + // Rows are ordered by traffic, so we will get the most active + // interface by iterating in order + var firstIPv4, firstIPv6 map[string]string for _, row := range rows { ip := net.ParseIP(row["address"]) if ip == nil { @@ -357,17 +360,35 @@ var detailQueries = map[string]struct { continue } - // Rows are ordered by traffic, so we will get the most active - // interface by iterating in order - host.PrimaryIP = row["address"] - host.PrimaryMac = row["mac"] - return nil + if strings.Contains(row["address"], ":") { + //IPv6 + if firstIPv6 == nil { + firstIPv6 = row + } + } else { + // IPv4 + if firstIPv4 == nil { + firstIPv4 = row + } + } } + var selected map[string]string + switch { + // Prefer IPv4 + case firstIPv4 != nil: + selected = firstIPv4 + // Otherwise IPv6 + case firstIPv6 != nil: + selected = firstIPv6 // If only link-local and loopback found, still use the first - // interface. - host.PrimaryIP = rows[0]["address"] - host.PrimaryMac = rows[0]["mac"] + // interface so that we don't get an empty value. + default: + selected = rows[0] + } + + host.PrimaryIP = selected["address"] + host.PrimaryMac = selected["mac"] return nil }, }, diff --git a/server/service/service_osquery_test.go b/server/service/service_osquery_test.go index 322bd301b0..e3323fe253 100644 --- a/server/service/service_osquery_test.go +++ b/server/service/service_osquery_test.go @@ -887,7 +887,44 @@ func TestDetailQueryNetworkInterfaces(t *testing.T) { assert.Equal(t, "192.168.1.3", host.PrimaryIP) assert.Equal(t, "f4:5d:79:93:58:5b", host.PrimaryMac) - // Only local/loopback + // Only IPv6 + require.NoError(t, json.Unmarshal([]byte(` +[ + {"address":"127.0.0.1","mac":"00:00:00:00:00:00"}, + {"address":"::1","mac":"00:00:00:00:00:00"}, + {"address":"fe80::1%lo0","mac":"00:00:00:00:00:00"}, + {"address":"fe80::df:429b:971c:d051%en0","mac":"f4:5c:89:92:57:5b"}, + {"address":"2604:3f08:1337:9411:cbe:814f:51a6:e4e3","mac":"27:1b:aa:60:e8:0a"}, + {"address":"3333:3f08:1337:9411:cbe:814f:51a6:e4e3","mac":"bb:1b:aa:60:e8:bb"}, + {"address":"fe80::3a6f:582f:86c5:8296%utun0","mac":"00:00:00:00:00:00"} +]`), + &rows, + )) + + assert.NoError(t, ingest(log.NewNopLogger(), &host, rows)) + assert.Equal(t, "2604:3f08:1337:9411:cbe:814f:51a6:e4e3", host.PrimaryIP) + assert.Equal(t, "27:1b:aa:60:e8:0a", host.PrimaryMac) + + // IPv6 appears before IPv4 (v4 should be prioritized) + require.NoError(t, json.Unmarshal([]byte(` +[ + {"address":"127.0.0.1","mac":"00:00:00:00:00:00"}, + {"address":"::1","mac":"00:00:00:00:00:00"}, + {"address":"fe80::1%lo0","mac":"00:00:00:00:00:00"}, + {"address":"fe80::df:429b:971c:d051%en0","mac":"f4:5c:89:92:57:5b"}, + {"address":"2604:3f08:1337:9411:cbe:814f:51a6:e4e3","mac":"27:1b:aa:60:e8:0a"}, + {"address":"205.111.43.79","mac":"ab:1b:aa:60:e8:0a"}, + {"address":"205.111.44.80","mac":"bb:bb:aa:60:e8:0a"}, + {"address":"fe80::3a6f:582f:86c5:8296%utun0","mac":"00:00:00:00:00:00"} +]`), + &rows, + )) + + assert.NoError(t, ingest(log.NewNopLogger(), &host, rows)) + assert.Equal(t, "205.111.43.79", host.PrimaryIP) + assert.Equal(t, "ab:1b:aa:60:e8:0a", host.PrimaryMac) + + // Only link-local/loopback require.NoError(t, json.Unmarshal([]byte(` [ {"address":"127.0.0.1","mac":"00:00:00:00:00:00"},