Facebook开源的基于SQL的操作系统检测和监控框架:osquery Table详解
写在前面
上一篇介绍了osquery的一些用法,即如何使用SQL语句查询系统信息。本文就来介绍下这个table是如何定义的,及table中的数据是如何取得的。
本文以uptime和process两张表为例。本文介绍的osquery版本是1.7.6。
uptime
uptime主要用来获取系统的启动时间:
osquery> select * from uptime;
+------+-------+---------+---------+---------------+
| days | hours | minutes | seconds | total_seconds |
+------+-------+---------+---------+---------------+
| 1 | 23 | 19 | 53 | 170393 |
+------+-------+---------+---------+---------------+
uptime表中的这条数据是如何获取的呢?
一般来说,对于table的描述分为两部分。一部分是spec,一部分是impl。
- spec用于说明表的名称、结构以及对应实现的方法,其代码主要在/specs中。
- impl则是表的具体实现,其代码主要在/osquery/tables中。
Spec
首先来看uptime.table
table_name("uptime")
description("Track time passed since last boot.")
schema([
Column("days", INTEGER, "Days of uptime"),
Column("hours", INTEGER, "Hours of uptime"),
Column("minutes", INTEGER, "Minutes of uptime"),
Column("seconds", INTEGER, "Seconds of uptime"),
Column("total_seconds", BIGINT, "Total uptime seconds"),
])
implementation("system/uptime@genUptime")
可以看到uptime表有5列,分别是days,hours,minutes,seconds,total_seconds。
其实现的代码是system/uptime中的genUptime函数。
Impl
那么直接来看具体实现uptime.cpp。
QueryData genUptime(QueryContext& context) {
Row r;
QueryData results;
long uptime_in_seconds = getUptime(); //获取启动的时间(根据不同的系统,有不同的方法获取)
if (uptime_in_seconds >= 0) {
r["days"] = INTEGER(uptime_in_seconds / 60 / 60 / 24);
r["hours"] = INTEGER((uptime_in_seconds / 60 / 60) % 24);
r["minutes"] = INTEGER((uptime_in_seconds / 60) % 60);
r["seconds"] = INTEGER(uptime_in_seconds % 60);
r["total_seconds"] = BIGINT(uptime_in_seconds);
results.push_back(r);
}
return results;
}
Row r是一行数据,其对应于SQL查询结果的一行,包含有该表的每一列。QueryData results是SQL查询返回的所有查询结果的集合,可以包含若干行。
可以看到该函数是首先获取启动时间,然后在行Row r中对应的字段填入相应的数据。
之后将结果通过results.push_back(r);填入到返回数据中,然后最终返回查询的结果。
因为uptime表只是获取对应的时间,所以只有一行。这里genUptime也就对应只填写了一行进行返回。
uptime是一个比较简单的表,下面对一个更为复杂的表processes进行分析。
Process
processes表相对来说,就复杂一些,其提供了正在running的进程的相关信息。
spec
首先来看processes.table,
可以看到该表包含了很多列。这里就不一一介绍了。
table_name("processes")
description("All running processes on the host system.")
schema([
Column("pid", BIGINT, "Process (or thread) ID", index=True),
Column("name", TEXT, "The process path or shorthand argv[0]"),
Column("path", TEXT, "Path to executed binary"),
Column("cmdline", TEXT, "Complete argv"),
Column("state", TEXT, "Process state"),
Column("cwd", TEXT, "Process current working directory"),
Column("root", TEXT, "Process virtual root directory"),
Column("uid", BIGINT, "Unsigned user ID"),
Column("gid", BIGINT, "Unsigned group ID"),
Column("euid", BIGINT, "Unsigned effective user ID"),
Column("egid", BIGINT, "Unsigned effective group ID"),
Column("suid", BIGINT, "Unsigned saved user ID"),
Column("sgid", BIGINT, "Unsigned saved group ID"),
Column("on_disk", INTEGER,
"The process path exists yes=1, no=0, unknown=-1"),
Column("wired_size", BIGINT, "Bytes of unpagable memory used by process"),
Column("resident_size", BIGINT, "Bytes of private memory used by process"),
Column("phys_footprint", BIGINT, "Bytes of total physical memory used"),
Column("user_time", BIGINT, "CPU time spent in user space"),
Column("system_time", BIGINT, "CPU time spent in kernel space"),
Column("start_time", BIGINT,
"Process start in seconds since boot (non-sleeping)"),
Column("parent", BIGINT, "Process parent's PID"),
Column("pgroup", BIGINT, "Process group"),
Column("nice", INTEGER, "Process nice level (-20 to 20, default 0)"),
])
implementation("system/processes@genProcesses")
examples([
"select * from processes where pid = 1",
])
可以看到起其实现是processes中的genProcesses函数。
Impl
processes中的genProcesses函数为不同系统提供了不同的实现。本文主要是从linux/processes.cpp来做分析。
首先看实现函数genProcesses:
QueryData genProcesses(QueryContext& context) {
QueryData results;
auto pidlist = getProcList(context);
for (const auto& pid : pidlist) {
genProcess(pid, results);
}
return results;
}
可以看到该函数主要有两部分。
- 根据context获取pid列表
- 根据pid列表依次获取每个pid的信息
获取pid列表
getProcList函数主要是根据context获取pid列表。
std::set<std::string> getProcList(const QueryContext& context) {
std::set<std::string> pidlist;
if (context.constraints.count("pid") > 0 &&
context.constraints.at("pid").exists(EQUALS)) {
for (const auto& pid : context.constraints.at("pid").getAll(EQUALS)) {
if (isDirectory("/proc/" + pid)) {
pidlist.insert(pid);
}
}
} else {
osquery::procProcesses(pidlist);
}
return pidlist;
}
从代码里可以看到,这里可以根据查询条件进行筛选。如果查询条件里面有where pid=xxxx的时候,即符合了
if (context.constraints.count("pid") > 0 && context.constraints.at("pid").exists(EQUALS))的条件,因此只需要将该pid加入到pidList中。
这一步的好处在于如果有where pid=xxxx的条件,就不需要检索所有的pid,只需要去获取特定的pid信息就可以了。
如果没有这种限制条件,则去获取所有的pid。获取的方法是procProcesses函数:
const std::string kLinuxProcPath = "/proc";
Status procProcesses(std::set<std::string>& processes) {
// Iterate over each process-like directory in proc.
boost::filesystem::directory_iterator it(kLinuxProcPath), end;
try {
for (; it != end; ++it) {
if (boost::filesystem::is_directory(it->status())) {
// See #792: std::regex is incomplete until GCC 4.9
if (std::atoll(it->path().leaf().string().c_str()) > 0) {
processes.insert(it->path().leaf().string());
}
}
}
} catch (const boost::filesystem::filesystem_error& e) {
VLOG(1) << "Exception iterating Linux processes " << e.what();
return Status(1, e.what());
}
return Status(0, "OK");
}
可以看到,获取所有的pid就是遍历/proc下的所有文件夹,判断文件夹是不是纯数字,如果是,则加入到processes集合里。
获取process的信息
有了pidList,接下来就是根据pidList,依次获取每个pid的信息。
void genProcess(const std::string& pid, QueryData& results) {
// Parse the process stat and status.
auto proc_stat = getProcStat(pid);
Row r;
r["pid"] = pid;
r["parent"] = proc_stat.parent;
r["path"] = readProcLink("exe", pid);
r["name"] = proc_stat.name;
r["pgroup"] = proc_stat.group;
r["state"] = proc_stat.state;
r["nice"] = proc_stat.nice;
// Read/parse cmdline arguments.
r["cmdline"] = readProcCMDLine(pid);
r["cwd"] = readProcLink("cwd", pid);
r["root"] = readProcLink("root", pid);
r["uid"] = proc_stat.real_uid;
r["euid"] = proc_stat.effective_uid;
r["suid"] = proc_stat.saved_uid;
r["gid"] = proc_stat.real_gid;
r["egid"] = proc_stat.effective_gid;
r["sgid"] = proc_stat.saved_gid;
// If the path of the executable that started the process is available and
// the path exists on disk, set on_disk to 1. If the path is not
// available, set on_disk to -1. If, and only if, the path of the
// executable is available and the file does NOT exist on disk, set on_disk
// to 0.
r["on_disk"] = osquery::pathExists(r["path"]).toString();
// size/memory information
r["wired_size"] = "0"; // No support for unpagable counters in linux.
r["resident_size"] = proc_stat.resident_size;
r["phys_footprint"] = proc_stat.phys_footprint;
// time information
r["user_time"] = proc_stat.user_time;
r["system_time"] = proc_stat.system_time;
r["start_time"] = proc_stat.start_time;
results.push_back(r);
}
可以看到首先是用getProcStat函数获取pid的信息。
这里getProcStat函数就不展开分析了,其主要就是读取/proc/<pid>/stat文件,然后将对应的字段获取出来。
然后genProcess函数将从getProcStat获取到的信息,填入到行r中的对应列,最后将行r加到返回的结果集中。
Facebook开源的基于SQL的操作系统检测和监控框架:osquery Table详解的更多相关文章
- Facebook开源的基于SQL的操作系统检测和监控框架:osquery daemon详解
osqueryd osqueryd(osquery daemon)是可以定期执行SQL查询和记录系统状态改变的驻守程序. osqueryd能够根据配置手机归档查询结果,并产生日志. 同时也可以使用系统 ...
- Facebook开源的基于SQL的操作系统检测和监控框架:osquery
osquery简介 osquery是一款由facebook开源的,面向OSX和Linux的操作系统检测框架. osquery顾名思义,就是query os,允许通过使用SQL的方式来获取操作系统的数据 ...
- [转帖]技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解
技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解 http://www.52im.net/thread-1309-1-1.html 本文来自腾讯资深研发工程师罗成的技术分享, ...
- Android中实现java与PHP服务器(基于新浪云免费云平台)http通信详解
Android中实现java与PHP服务器(基于新浪云免费云平台)http通信详解 (本文转自: http://blog.csdn.net/yinhaide/article/details/44756 ...
- SQL Server中通用数据库角色权限的处理详解
SQL Server中通用数据库角色权限的处理详解 前言 安全性是所有数据库管理系统的一个重要特征.理解安全性问题是理解数据库管理系统安全性机制的前提. 最近和同事在做数据库权限清理的事情,主要是删除 ...
- SQL Server中排名函数row_number,rank,dense_rank,ntile详解
SQL Server中排名函数row_number,rank,dense_rank,ntile详解 从SQL SERVER2005开始,SQL SERVER新增了四个排名函数,分别如下:1.row_n ...
- 开源一个基于dotnet standard的轻量级的ORM框架-Light.Data
还在dotnet framework 2.0的时代,当时还没有EF,而NHibernate之类的又太复杂,并且自己也有一些特殊需求,如查询结果直接入表.水平分表和新增数据默认值等,就试着折腾个轻量点O ...
- SQL Server 表的管理_关于完整性约束的详解(案例代码)
SQL Server 表的管理之_关于完整性约束的详解 一.概述: ●约束是SQL Server提供的自动保持数据库完整性的一种方法, 它通过限制字段中数据.记录中数据和表之间的数据来保证数据的完整性 ...
- 第三十一节,目标检测算法之 Faster R-CNN算法详解
Ren, Shaoqing, et al. “Faster R-CNN: Towards real-time object detection with region proposal network ...
随机推荐
- Appium Android Bootstrap源码分析之简介
在上一个系列中我们分析了UiAutomator的核心源码,对UiAutomator是怎么运行的原理有了根本的了解.今天我们会开始另外一个在安卓平台上基于UiAutomator的新起之秀--Appium ...
- mysql utf8mb4与emoji表情
一 什么是Emoji emoji就是表情符号:词义来自日语(えもじ,e-moji,moji在日语中的含义是字符) 表情符号现已普遍应用于手机短信和网络聊天软件. emoji表情符号,在外国的手机短信里 ...
- Bundle压缩JS和CSS
ASP.NET MVC之Bundle压缩JS和CSS 介绍Bundle之前先引用<淘宝技术这十年>中一段话,对Web前端稍微有点常识的人都应该知道,浏览器下一步会加载页面中用到的CSS.J ...
- 快速构建Windows 8风格应用9-竖直视图
原文:快速构建Windows 8风格应用9-竖直视图 本篇博文主要介绍竖直视图概览.关于竖直视图设计.如何构建竖直视图 竖直视图概览 Windows 8为了支持旋转的设备提供了竖屏视图,我们开发的应用 ...
- 6. SQL Server数据库监控 - 如何告警
原文:6. SQL Server数据库监控 - 如何告警 常用的告警方式大致有:短信.邮件.应用程序 (beep提示,图标提示,升窗提示等),可是不能一直坐在电脑前看着应用程序,或者用脚本部署监控,根 ...
- UVA11125 - Arrange Some Marbles(dp)
UVA11125 - Arrange Some Marbles(dp) option=com_onlinejudge&Itemid=8&category=24&page=sho ...
- C#编程实践–产假方案优化版
前言 既然作为一个踏踏实实学习技术的人,就要有一颗谦卑.虚心和追求卓越的心,我不能一次就写出很完美的代码,但我相信,踏踏实实一步一步的优化,代码就可以变得趋近完美,至少在某一个特定场景下相对完美,这和 ...
- Node填坑教程——简易http服务器
我们这一期做一个简易的http服务器. 先建一个文件夹,就算是一个空的项目了.然后新建app.js和package.json文件. 这样一个简易项目的基本文件就建好了. 通过命令行工具,在项目路径下输 ...
- 捣鼓一个Ajax请求管理器
随着前端技术的不断发展,现在做的项目里很多页面里都会有大量的ajax请求,随之而来就有了一些问题: 1.没必要的ajax请求怎么处理? 2.ajax链式调用怎么维护? ajax链式调用最原始的写法: ...
- c语言算法题目求职用
1.栈的压入与压出/* 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序.n<=100000 用一个栈作辅助,顺序描述压入序列和弹出序列,如果当前位置上压入序列 ...