diff --git a/changes/issue-4754-improve-primary-ip b/changes/issue-4754-improve-primary-ip new file mode 100644 index 0000000000..831b6fb494 --- /dev/null +++ b/changes/issue-4754-improve-primary-ip @@ -0,0 +1 @@ +* Improve host detail query to populate primary ip and mac address on host. diff --git a/server/service/osquery_test.go b/server/service/osquery_test.go index d79acc2d2b..564bc9d363 100644 --- a/server/service/osquery_test.go +++ b/server/service/osquery_test.go @@ -560,10 +560,11 @@ func TestHostDetailQueries(t *testing.T) { queries, discovery, err = svc.detailQueriesForHost(context.Background(), &host) require.NoError(t, err) - // 2 additional queries, but -3 expected queries due to removed disk space query (only 1 of 2 - // active for a given platform) and removed two Windows-specific operating system queries, - // so the result is -1. - require.Equal(t, len(expectedDetailQueries)-1, len(queries), distQueriesMapKeys(queries)) + // 2 - 4 = -2 + // └───┼────┼─► additional queries: bim, foobar + // └────┼─► windows specific queries: os_windows, os_version_windows, network_interface_windows, disk_space_windows + // └─► net difference + require.Equal(t, len(expectedDetailQueries)-2, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) for name := range queries { assert.True(t, @@ -743,9 +744,8 @@ func TestLabelQueries(t *testing.T) { // should be turned on so that we can quickly fill labels) queries, discovery, acc, err := svc.GetDistributedQueries(ctx) require.NoError(t, err) - // -3 expected queries due to removed disk space query (only 1 of 2 active for a given platform) - // and removed two Windows-specific operating system queries - require.Equal(t, len(expectedDetailQueries)-3, len(queries), distQueriesMapKeys(queries)) + // -4 windows specific queries: disk_space_windows, network_interface_windows, os_windows, os_version_windows + require.Equal(t, len(expectedDetailQueries)-4, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) assert.NotZero(t, acc) @@ -835,9 +835,8 @@ func TestLabelQueries(t *testing.T) { ctx = hostctx.NewContext(ctx, host) queries, discovery, acc, err = svc.GetDistributedQueries(ctx) require.NoError(t, err) - // +3 for label queries, but -3 expected queries due to removed disk space query (only 1 of 2 - // active for a given platform) and removed two Windows-specific operating system queries - require.Equal(t, len(expectedDetailQueries), len(queries), distQueriesMapKeys(queries)) + // +3 for label queries, but -4 windows specific queries + require.Equal(t, len(expectedDetailQueries)-1, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) assert.Zero(t, acc) @@ -905,10 +904,9 @@ func TestDetailQueriesWithEmptyStrings(t *testing.T) { // queries) queries, discovery, acc, err := svc.GetDistributedQueries(ctx) require.NoError(t, err) - // -5 due to windows not having battery, mdm, munki_info and removed disk space query and - // operating system query (only 1 of 2 active for a given platform) + // -3 unix, -2 macos, // -1 due to 'windows_update_history' - if !assert.Equal(t, len(expectedDetailQueries)-5, len(queries)-1) { + if !assert.Equal(t, len(expectedDetailQueries)-6, len(queries)-1) { // this is just to print the diff between the expected and actual query // keys when the count assertion fails, to help debugging - they are not // expected to match. @@ -919,99 +917,85 @@ func TestDetailQueriesWithEmptyStrings(t *testing.T) { resultJSON := ` { -"fleet_detail_query_network_interface": [ - { - "address": "192.168.0.1", - "broadcast": "192.168.0.255", - "ibytes": "", - "ierrors": "", - "interface": "en0", - "ipackets": "25698094", - "last_change": "1474233476", - "mac": "5f:3d:4b:10:25:82", - "mask": "255.255.255.0", - "metric": "", - "mtu": "", - "obytes": "", - "oerrors": "", - "opackets": "", - "point_to_point": "", - "type": "" - } -], -"fleet_detail_query_os_version": [ - { - "platform": "darwin", - "build": "15G1004", - "major": "10", - "minor": "10", - "name": "Mac OS X", - "patch": "6" - } -], -"fleet_detail_query_osquery_info": [ - { - "build_distro": "10.10", - "build_platform": "darwin", - "config_hash": "3c6e4537c4d0eb71a7c6dda19d", - "config_valid": "1", - "extensions": "active", - "pid": "38113", - "start_time": "1475603155", - "version": "1.8.2", - "watcher": "38112" - } -], -"fleet_detail_query_system_info": [ - { - "computer_name": "computer", - "cpu_brand": "Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz", - "cpu_logical_cores": "8", - "cpu_physical_cores": "4", - "cpu_subtype": "Intel x86-64h Haswell", - "cpu_type": "x86_64h", - "hardware_model": "MacBookPro11,4", - "hardware_serial": "ABCDEFGH", - "hardware_vendor": "Apple Inc.", - "hardware_version": "1.0", - "hostname": "computer.local", - "physical_memory": "17179869184", - "uuid": "uuid" - } -], -"fleet_detail_query_uptime": [ - { - "days": "20", - "hours": "0", - "minutes": "48", - "seconds": "13", - "total_seconds": "1730893" - } -], -"fleet_detail_query_osquery_flags": [ - { - "name":"config_tls_refresh", - "value":"" - }, - { - "name":"distributed_interval", - "value":"" - }, - { - "name":"logger_tls_period", - "value":"" - } -], -"fleet_detail_query_orbit_info": [ - { - "name":"version", - "value":"42" - }, - { - "name":"device_auth_token", - "value":"foo" - } -] + "fleet_detail_query_network_interface_windows": [ + { + "address": "192.168.0.1", + "mac": "5f:3d:4b:10:25:82" + } + ], + "fleet_detail_query_os_version": [ + { + "platform": "darwin", + "build": "15G1004", + "major": "10", + "minor": "10", + "name": "Mac OS X", + "patch": "6" + } + ], + "fleet_detail_query_osquery_info": [ + { + "build_distro": "10.10", + "build_platform": "darwin", + "config_hash": "3c6e4537c4d0eb71a7c6dda19d", + "config_valid": "1", + "extensions": "active", + "pid": "38113", + "start_time": "1475603155", + "version": "1.8.2", + "watcher": "38112" + } + ], + "fleet_detail_query_system_info": [ + { + "computer_name": "computer", + "cpu_brand": "Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz", + "cpu_logical_cores": "8", + "cpu_physical_cores": "4", + "cpu_subtype": "Intel x86-64h Haswell", + "cpu_type": "x86_64h", + "hardware_model": "MacBookPro11,4", + "hardware_serial": "ABCDEFGH", + "hardware_vendor": "Apple Inc.", + "hardware_version": "1.0", + "hostname": "computer.local", + "physical_memory": "17179869184", + "uuid": "uuid" + } + ], + "fleet_detail_query_uptime": [ + { + "days": "20", + "hours": "0", + "minutes": "48", + "seconds": "13", + "total_seconds": "1730893" + } + ], + "fleet_detail_query_osquery_flags": [ + { + "name": "config_tls_refresh", + "value": "" + }, + { + "name": "distributed_interval", + "value": "" + }, + { + "name": "logger_tls_period", + "value": "" + } + ], + "fleet_detail_query_orbit_info": [ + { + "name": "version", + "value": "42" + }, + { + "name": "device_auth_token", + "value": "foo" + } + ] } ` @@ -1066,9 +1050,9 @@ func TestDetailQueriesWithEmptyStrings(t *testing.T) { queries, discovery, acc, err = svc.GetDistributedQueries(ctx) require.NoError(t, err) // somehow confusingly, the query response above changed the host's platform - // from windows to darwin, so now it has all expected queries except the - // extra disk space one and two windows-specific operating system queries - require.Equal(t, len(expectedDetailQueries)-3, len(queries), distQueriesMapKeys(queries)) + // from windows to darwin + // -4 windows queries + require.Equal(t, len(expectedDetailQueries)-4, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) assert.Zero(t, acc) } @@ -1131,9 +1115,8 @@ func TestDetailQueries(t *testing.T) { // queries) queries, discovery, acc, err := svc.GetDistributedQueries(ctx) require.NoError(t, err) - // -6 due to linux platform, so battery, mdm, and munki are missing, and the extra disk space - // query, and two windows-specific operating system queries, then +1 due to software inventory being enabled. - if !assert.Equal(t, len(expectedDetailQueries)-5, len(queries)) { + // -3 macos queries, -4 windows quries, +1 for software inventory + if !assert.Equal(t, len(expectedDetailQueries)-6, len(queries)) { // this is just to print the diff between the expected and actual query // keys when the count assertion fails, to help debugging - they are not // expected to match. @@ -1390,10 +1373,8 @@ func TestDetailQueries(t *testing.T) { queries, discovery, acc, err = svc.GetDistributedQueries(ctx) require.NoError(t, err) - // host platform changed to darwin, so -3 for the - // extra disk space query and two windows-specific operating system queries, - // +1 for the software inventory enabled. - require.Equal(t, len(expectedDetailQueries)-2, len(queries), distQueriesMapKeys(queries)) + // -4 windows queries, +1 software inventory + require.Equal(t, len(expectedDetailQueries)-3, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) assert.Zero(t, acc) } @@ -1517,8 +1498,8 @@ func TestDistributedQueryResults(t *testing.T) { // Now we should get the active distributed query queries, discovery, acc, err := svc.GetDistributedQueries(hostCtx) require.NoError(t, err) - // -3 for the non-windows queries, +1 for the distributed query for campaign ID 42 - if !assert.Equal(t, len(expectedDetailQueries)-3, len(queries)) { + // -3 unix, -2 macos, +1 for the distributed query for campaign ID 42 + if !assert.Equal(t, len(expectedDetailQueries)-4, len(queries)) { // this is just to print the diff between the expected and actual query // keys when the count assertion fails, to help debugging - they are not // expected to match. @@ -2132,9 +2113,9 @@ func TestDistributedQueriesLogsManyErrors(t *testing.T) { err := svc.SubmitDistributedQueryResults( ctx, map[string][]map[string]string{ - hostDetailQueryPrefix + "network_interface": {{"col1": "val1"}}, // we need one detail query that updates hosts. - hostLabelQueryPrefix + "1": {{"col1": "val1"}}, - hostAdditionalQueryPrefix + "1": {{"col1": "val1"}}, + hostDetailQueryPrefix + "network_interface_unix": {{"col1": "val1"}}, // we need one detail query that updates hosts. + hostLabelQueryPrefix + "1": {{"col1": "val1"}}, + hostAdditionalQueryPrefix + "1": {{"col1": "val1"}}, }, map[string]fleet.OsqueryStatus{}, map[string]string{}, @@ -2146,11 +2127,12 @@ func TestDistributedQueriesLogsManyErrors(t *testing.T) { logs := buf.String() parts := strings.Split(strings.TrimSpace(logs), "\n") require.Len(t, parts, 1) - logData := make(map[string]json.RawMessage) + + var logData map[string]interface{} err = json.Unmarshal([]byte(parts[0]), &logData) require.NoError(t, err) - assert.Equal(t, json.RawMessage(`"something went wrong || something went wrong"`), logData["err"]) - assert.Equal(t, json.RawMessage(`"Missing authorization check"`), logData["internal"]) + assert.Equal(t, "something went wrong || something went wrong", logData["err"]) + assert.Equal(t, "Missing authorization check", logData["internal"]) } func TestDistributedQueriesReloadsHostIfDetailsAreIn(t *testing.T) { @@ -2174,7 +2156,7 @@ func TestDistributedQueriesReloadsHostIfDetailsAreIn(t *testing.T) { err := svc.SubmitDistributedQueryResults( ctx, map[string][]map[string]string{ - hostDetailQueryPrefix + "network_interface": {{"col1": "val1"}}, + hostDetailQueryPrefix + "network_interface_unix": {{"col1": "val1"}}, }, map[string]fleet.OsqueryStatus{}, map[string]string{}, @@ -2357,9 +2339,8 @@ func TestPolicyQueries(t *testing.T) { queries, discovery, _, err := svc.GetDistributedQueries(ctx) require.NoError(t, err) - // all queries -3 for the extra disk space one and two windows-specific operating system queries, - // and +2 for the policy queries - require.Equal(t, len(expectedDetailQueries)-1, len(queries), distQueriesMapKeys(queries)) + // all queries -4 windows only queries +2 policy queries + require.Equal(t, len(expectedDetailQueries)-2, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) checkPolicyResults := func(queries map[string]string) { @@ -2415,8 +2396,8 @@ func TestPolicyQueries(t *testing.T) { ctx = hostctx.NewContext(context.Background(), host) queries, discovery, _, err = svc.GetDistributedQueries(ctx) require.NoError(t, err) - // all standard queries minus the extra disk space and two windows-specific operating system queries - require.Equal(t, len(expectedDetailQueries)-3, len(queries), distQueriesMapKeys(queries)) + // all standard queries -4 windows only queries + require.Equal(t, len(expectedDetailQueries)-4, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) noPolicyResults(queries) @@ -2425,9 +2406,8 @@ func TestPolicyQueries(t *testing.T) { queries, discovery, _, err = svc.GetDistributedQueries(ctx) require.NoError(t, err) - // all standard queries -3 (the extra disk space and two windows-specific operating system - // queries) and +2 policy queries - require.Equal(t, len(expectedDetailQueries)-1, len(queries), distQueriesMapKeys(queries)) + // all standard queries -4 windows only queries +2 policy queries + require.Equal(t, len(expectedDetailQueries)-2, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) checkPolicyResults(queries) @@ -2455,8 +2435,8 @@ func TestPolicyQueries(t *testing.T) { ctx = hostctx.NewContext(context.Background(), host) queries, discovery, _, err = svc.GetDistributedQueries(ctx) require.NoError(t, err) - // all standard queries minus the extra disk space and two windows-specific operating system queries - require.Equal(t, len(expectedDetailQueries)-3, len(queries), distQueriesMapKeys(queries)) + // all standard queries -4 windows only queries + require.Equal(t, len(expectedDetailQueries)-4, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) noPolicyResults(queries) @@ -2465,9 +2445,8 @@ func TestPolicyQueries(t *testing.T) { ctx = hostctx.NewContext(context.Background(), host) queries, discovery, _, err = svc.GetDistributedQueries(ctx) require.NoError(t, err) - // all standard queries3-2 (the extra disk space and two windows-specific operating system - // query) and +2 policy queries - require.Equal(t, len(expectedDetailQueries)-1, len(queries), distQueriesMapKeys(queries)) + // all standard queries -4 windows only queries +2 policy queries + require.Equal(t, len(expectedDetailQueries)-2, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) checkPolicyResults(queries) @@ -2497,8 +2476,8 @@ func TestPolicyQueries(t *testing.T) { ctx = hostctx.NewContext(context.Background(), host) queries, discovery, _, err = svc.GetDistributedQueries(ctx) require.NoError(t, err) - // all standard queries minus the extra disk space and two windows-specific operating system queries - require.Equal(t, len(expectedDetailQueries)-3, len(queries), distQueriesMapKeys(queries)) + // all standard queries -4 windows only queries + require.Equal(t, len(expectedDetailQueries)-4, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) noPolicyResults(queries) } @@ -2563,8 +2542,8 @@ func TestPolicyWebhooks(t *testing.T) { queries, discovery, _, err := svc.GetDistributedQueries(ctx) require.NoError(t, err) - // all queries -3 for extra disk space and two windows-specific operating system queries, +3 for policies - require.Equal(t, len(expectedDetailQueries), len(queries), distQueriesMapKeys(queries)) + // all queries -4 windows only, +3 for policies + require.Equal(t, len(expectedDetailQueries)-1, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) checkPolicyResults := func(queries map[string]string) { @@ -2677,8 +2656,8 @@ func TestPolicyWebhooks(t *testing.T) { ctx = hostctx.NewContext(context.Background(), host) queries, discovery, _, err = svc.GetDistributedQueries(ctx) require.NoError(t, err) - // all standard queries minus the extra disk space and two windows-specific operating system queries - require.Equal(t, len(expectedDetailQueries)-3, len(queries), distQueriesMapKeys(queries)) + // all queries -4 windows only queries + require.Equal(t, len(expectedDetailQueries)-4, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) noPolicyResults(queries) @@ -2687,8 +2666,8 @@ func TestPolicyWebhooks(t *testing.T) { queries, discovery, _, err = svc.GetDistributedQueries(ctx) require.NoError(t, err) - // all queries -3 for extra disk space and two windows-specific operating system queries, +3 for policies - require.Equal(t, len(expectedDetailQueries)-0, len(queries), distQueriesMapKeys(queries)) + // all queries -4 windows only queries, +3 for policies + require.Equal(t, len(expectedDetailQueries)-1, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) checkPolicyResults(queries) @@ -2811,8 +2790,8 @@ func TestLiveQueriesFailing(t *testing.T) { queries, discovery, _, err := svc.GetDistributedQueries(ctx) require.NoError(t, err) - // all standard queries minus the extra disk space and two windows-specific operating system queries - require.Equal(t, len(expectedDetailQueries)-3, len(queries), distQueriesMapKeys(queries)) + // all standard queries minus windows only queries + require.Equal(t, len(expectedDetailQueries)-4, len(queries), distQueriesMapKeys(queries)) verifyDiscovery(t, queries, discovery) logs, err := io.ReadAll(buf) diff --git a/server/service/osquery_utils/queries.go b/server/service/osquery_utils/queries.go index 4e5479079a..2169b9c5cf 100644 --- a/server/service/osquery_utils/queries.go +++ b/server/service/osquery_utils/queries.go @@ -3,7 +3,6 @@ package osquery_utils import ( "context" "fmt" - "net" "os" "regexp" "strconv" @@ -62,71 +61,47 @@ func (q *DetailQuery) RunsForPlatform(platform string) bool { // // This map should not be modified at runtime. var hostDetailQueries = map[string]DetailQuery{ - "network_interface": { - Query: `select ia.address, id.mac, id.interface - from interface_details id join interface_addresses ia - on ia.interface = id.interface where length(mac) > 0 - order by (ibytes + obytes) desc`, - IngestFunc: func(ctx context.Context, logger log.Logger, host *fleet.Host, rows []map[string]string) (err error) { - if len(rows) == 0 { - logger.Log("component", "service", "method", "IngestFunc", "err", - "detail_query_network_interface expected 1 or more results") - 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 { - continue - } - - // Skip link-local and loopback interfaces - if ip.IsLinkLocalUnicast() || ip.IsLoopback() { - continue - } - - // Skip docker interfaces as these are sometimes heavily - // trafficked, but rarely the interface that Fleet users want to - // see. https://github.com/fleetdm/fleet/issues/4754. - if strings.Contains(row["interface"], "docker") { - continue - } - - 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 so that we don't get an empty value. - default: - selected = rows[0] - } - - host.PrimaryIP = selected["address"] - host.PrimaryMac = selected["mac"] - host.PublicIP = publicip.FromContext(ctx) - return nil - }, + "network_interface_unix": { + Query: ` +select + ia.address, + id.mac +from + interface_addresses ia + join interface_details id on id.interface = ia.interface + join routes r on r.interface = ia.interface +where + r.destination = '0.0.0.0' + and r.netmask = 0 + and r.type = 'gateway' + and instr(ia.address, '.') > 0 +order by + r.metric asc +limit 1 +`, + Platforms: append(fleet.HostLinuxOSs, "darwin"), + IngestFunc: ingestNetworkInterface, + }, + "network_interface_windows": { + Query: ` +select + ia.address, + id.mac +from + interface_addresses ia + join interface_details id on id.interface = ia.interface + join routes r on r.interface = ia.address +where + r.destination = '0.0.0.0' + and r.netmask = 0 + and r.type = 'remote' + and instr(ia.address, '.') > 0 +order by + r.metric asc +limit 1 +`, + Platforms: []string{"windows"}, + IngestFunc: ingestNetworkInterface, }, "os_version": { // Collect operating system information for the `hosts` table. @@ -408,6 +383,55 @@ FROM logical_drives WHERE file_system = 'NTFS' LIMIT 1;`, }, } +func ingestNetworkInterface(ctx context.Context, logger log.Logger, host *fleet.Host, rows []map[string]string) error { + if len(rows) != 1 { + logger.Log("component", "service", "method", "IngestFunc", "err", + fmt.Sprintf("detail_query_network_interface expected single result, got %d", len(rows))) + return nil + } + + host.PrimaryIP = rows[0]["address"] + host.PrimaryMac = rows[0]["mac"] + host.PublicIP = publicip.FromContext(ctx) + return nil +} + +func directIngestDiskSpace(ctx context.Context, logger log.Logger, host *fleet.Host, ds fleet.Datastore, rows []map[string]string, failed bool) error { + if failed { + level.Error(logger).Log("op", "directIngestDiskSpace", "err", "failed") + return nil + } + if len(rows) != 1 { + logger.Log("component", "service", "method", "directIngestDiskSpace", "err", + fmt.Sprintf("detail_query_disk_space expected single result got %d", len(rows))) + return nil + } + + gigsAvailable, err := strconv.ParseFloat(EmptyToZero(rows[0]["gigs_disk_space_available"]), 64) + if err != nil { + return err + } + percentAvailable, err := strconv.ParseFloat(EmptyToZero(rows[0]["percent_disk_space_available"]), 64) + if err != nil { + return err + } + + return ds.SetOrUpdateHostDisksSpace(ctx, host.ID, gigsAvailable, percentAvailable) +} + +func ingestKubequeryInfo(ctx context.Context, logger log.Logger, host *fleet.Host, rows []map[string]string) error { + if len(rows) != 1 { + return fmt.Errorf("kubernetes_info expected single result got: %d", len(rows)) + } + + host.Hostname = fmt.Sprintf("kubequery %s", rows[0]["cluster_name"]) + + // These values are not provided by kubequery + host.OsqueryVersion = "kubequery" + host.Platform = "kubequery" + return nil +} + // extraDetailQueries defines extra detail queries that should be run on the host, as // well as how the results of those queries should be ingested into the hosts related tables // (via DirectIngestFunc). @@ -1155,29 +1179,6 @@ func directIngestUsers(ctx context.Context, logger log.Logger, host *fleet.Host, return nil } -func directIngestDiskSpace(ctx context.Context, logger log.Logger, host *fleet.Host, ds fleet.Datastore, rows []map[string]string, failed bool) error { - if failed { - level.Error(logger).Log("op", "directIngestDiskSpace", "err", "failed") - return nil - } - if len(rows) != 1 { - logger.Log("component", "service", "method", "directIngestDiskSpace", "err", - fmt.Sprintf("detail_query_disk_space expected single result got %d", len(rows))) - return nil - } - - gigsAvailable, err := strconv.ParseFloat(EmptyToZero(rows[0]["gigs_disk_space_available"]), 64) - if err != nil { - return err - } - percentAvailable, err := strconv.ParseFloat(EmptyToZero(rows[0]["percent_disk_space_available"]), 64) - if err != nil { - return err - } - - return ds.SetOrUpdateHostDisksSpace(ctx, host.ID, gigsAvailable, percentAvailable) -} - func directIngestMDM(ctx context.Context, logger log.Logger, host *fleet.Host, ds fleet.Datastore, rows []map[string]string, failed bool) error { if len(rows) == 0 || failed { // assume the extension is not there @@ -1222,19 +1223,6 @@ func directIngestMunkiInfo(ctx context.Context, logger log.Logger, host *fleet.H return ds.SetOrUpdateMunkiInfo(ctx, host.ID, rows[0]["version"], errList, warnList) } -func ingestKubequeryInfo(ctx context.Context, logger log.Logger, host *fleet.Host, rows []map[string]string) error { - if len(rows) != 1 { - return fmt.Errorf("kubernetes_info expected single result got: %d", len(rows)) - } - - host.Hostname = fmt.Sprintf("kubequery %s", rows[0]["cluster_name"]) - - // These values are not provided by kubequery - host.OsqueryVersion = "kubequery" - host.Platform = "kubequery" - return nil -} - func GetDetailQueries(fleetConfig config.FleetConfig, features *fleet.Features) map[string]DetailQuery { generatedMap := make(map[string]DetailQuery) for key, query := range hostDetailQueries { diff --git a/server/service/osquery_utils/queries_test.go b/server/service/osquery_utils/queries_test.go index 8860d0fe69..528bb7962a 100644 --- a/server/service/osquery_utils/queries_test.go +++ b/server/service/osquery_utils/queries_test.go @@ -24,84 +24,22 @@ func TestDetailQueryNetworkInterfaces(t *testing.T) { var initialHost fleet.Host host := initialHost - ingest := GetDetailQueries(config.FleetConfig{}, nil)["network_interface"].IngestFunc + ingest := GetDetailQueries(config.FleetConfig{}, nil)["network_interface_unix"].IngestFunc assert.NoError(t, ingest(context.Background(), log.NewNopLogger(), &host, nil)) assert.Equal(t, initialHost, host) var rows []map[string]string - // docker interface should be skipped even though it shows up first require.NoError(t, json.Unmarshal([]byte(` [ - {"address":"127.0.0.1","mac":"00:00:00:00:00:00","interface":"lo0"}, - {"address":"::1","mac":"00:00:00:00:00:00","interface":"lo0"}, - {"address":"fe80::1%lo0","mac":"00:00:00:00:00:00","interface":"lo0"}, - {"address":"172.17.0.1","mac":"d3:4d:b3:3f:58:5b","interface":"docker0"}, - {"address":"fe80::df:429b:971c:d051%en0","mac":"f4:5c:89:92:57:5b","interface":"en0"}, - {"address":"192.168.1.3","mac":"f4:5d:79:93:58:5b","interface":"en0"}, - {"address":"fe80::241a:9aff:fe60:d80a%awdl0","mac":"27:1b:aa:60:e8:0a","interface":"en0"}, - {"address":"fe80::3a6f:582f:86c5:8296%utun0","mac":"00:00:00:00:00:00","interface":"utun0"} + {"address":"10.0.1.2","mac":"bc:d0:74:4b:10:6d"} ]`), &rows, )) assert.NoError(t, ingest(context.Background(), log.NewNopLogger(), &host, rows)) - assert.Equal(t, "192.168.1.3", host.PrimaryIP) - assert.Equal(t, "f4:5d:79:93:58:5b", host.PrimaryMac) - - // Only IPv6 - require.NoError(t, json.Unmarshal([]byte(` -[ - {"address":"127.0.0.1","mac":"00:00:00:00:00:00","interface":"lo0"}, - {"address":"::1","mac":"00:00:00:00:00:00","interface":"lo0"}, - {"address":"fe80::1%lo0","mac":"00:00:00:00:00:00","interface":"lo0"}, - {"address":"fe80::df:429b:971c:d051%en0","mac":"f4:5c:89:92:57:5b","interface":"en0"}, - {"address":"2604:3f08:1337:9411:cbe:814f:51a6:e4e3","mac":"27:1b:aa:60:e8:0a","interface":"en0"}, - {"address":"3333:3f08:1337:9411:cbe:814f:51a6:e4e3","mac":"bb:1b:aa:60:e8:bb","interface":"en0"}, - {"address":"fe80::3a6f:582f:86c5:8296%utun0","mac":"00:00:00:00:00:00","interface":"utun0"} -]`), - &rows, - )) - - assert.NoError(t, ingest(context.Background(), 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","interface":"lo0"}, - {"address":"::1","mac":"00:00:00:00:00:00","interface":"lo0"}, - {"address":"fe80::1%lo0","mac":"00:00:00:00:00:00","interface":"lo0"}, - {"address":"fe80::df:429b:971c:d051%en0","mac":"f4:5c:89:92:57:5b","interface":"en0"}, - {"address":"2604:3f08:1337:9411:cbe:814f:51a6:e4e3","mac":"27:1b:aa:60:e8:0a","interface":"en0"}, - {"address":"205.111.43.79","mac":"ab:1b:aa:60:e8:0a","interface":"en1"}, - {"address":"205.111.44.80","mac":"bb:bb:aa:60:e8:0a","interface":"en1"}, - {"address":"fe80::3a6f:582f:86c5:8296%utun0","mac":"00:00:00:00:00:00","interface":"utun0"} -]`), - &rows, - )) - - assert.NoError(t, ingest(context.Background(), 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","interface":"lo0"}, - {"address":"::1","mac":"00:00:00:00:00:00","interface":"lo0"}, - {"address":"fe80::1%lo0","mac":"00:00:00:00:00:00","interface":"lo0"}, - {"address":"fe80::df:429b:971c:d051%en0","mac":"f4:5c:89:92:57:5b","interface":"en0"}, - {"address":"fe80::241a:9aff:fe60:d80a%awdl0","mac":"27:1b:aa:60:e8:0a","interface":"en0"}, - {"address":"fe80::3a6f:582f:86c5:8296%utun0","mac":"00:00:00:00:00:00","interface":"utun0"} -]`), - &rows, - )) - - assert.NoError(t, ingest(context.Background(), log.NewNopLogger(), &host, rows)) - assert.Equal(t, "127.0.0.1", host.PrimaryIP) - assert.Equal(t, "00:00:00:00:00:00", host.PrimaryMac) + assert.Equal(t, "10.0.1.2", host.PrimaryIP) + assert.Equal(t, "bc:d0:74:4b:10:6d", host.PrimaryMac) } func TestDetailQueryScheduledQueryStats(t *testing.T) { @@ -297,10 +235,11 @@ func sortedKeysCompare(t *testing.T, m map[string]DetailQuery, expectedKeys []st func TestGetDetailQueries(t *testing.T) { queriesNoConfig := GetDetailQueries(config.FleetConfig{}, nil) - require.Len(t, queriesNoConfig, 18) + require.Len(t, queriesNoConfig, 19) baseQueries := []string{ - "network_interface", + "network_interface_unix", + "network_interface_windows", "os_version", "os_version_windows", "osquery_flags", @@ -322,14 +261,14 @@ func TestGetDetailQueries(t *testing.T) { sortedKeysCompare(t, queriesNoConfig, baseQueries) queriesWithoutWinOSVuln := GetDetailQueries(config.FleetConfig{Vulnerabilities: config.VulnerabilitiesConfig{DisableWinOSVulnerabilities: true}}, nil) - require.Len(t, queriesWithoutWinOSVuln, 17) + require.Len(t, queriesWithoutWinOSVuln, 18) queriesWithUsers := GetDetailQueries(config.FleetConfig{App: config.AppConfig{EnableScheduledQueryStats: true}}, &fleet.Features{EnableHostUsers: true}) - require.Len(t, queriesWithUsers, 20) + require.Len(t, queriesWithUsers, 21) sortedKeysCompare(t, queriesWithUsers, append(baseQueries, "users", "scheduled_query_stats")) queriesWithUsersAndSoftware := GetDetailQueries(config.FleetConfig{App: config.AppConfig{EnableScheduledQueryStats: true}}, &fleet.Features{EnableHostUsers: true, EnableSoftwareInventory: true}) - require.Len(t, queriesWithUsersAndSoftware, 23) + require.Len(t, queriesWithUsersAndSoftware, 24) sortedKeysCompare(t, queriesWithUsersAndSoftware, append(baseQueries, "users", "software_macos", "software_linux", "software_windows", "scheduled_query_stats")) }