Falco 命令行参数解析

Falco使用cxxopts库来解析命令行参数

比如之前的运行方式为

sudo ./userspace/falco/falco -c ../falco.yaml -r ../rules/falco_rules.yaml

所以需要对-c 和-r两个参数进行解析。

对应代码在app_cmdline_options.cpp中:

void cmdline_options::define()
{
	m_cmdline_opts.add_options()
		("h,help",                        "Print this page", cxxopts::value(help)->default_value("false"))
#ifdef BUILD_TYPE_RELEASE
		("c",                             "Configuration file. If not specified uses " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
#else
		("c",                             "Configuration file. If not specified tries " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
#endif
		("A",                             "Monitor all events, including those with EF_DROP_SIMPLE_CONS flag.", cxxopts::value(all_events)->default_value("false"))
		("b,print-base64",                "Print data buffers in base64. This is useful for encoding binary data that needs to be used over media designed to consume this format.")
		("cri",                           "Path to CRI socket for container metadata. Use the specified socket to fetch data from a CRI-compatible runtime. If not specified, uses libs default. It can be passed multiple times to specify socket to be tried until a successful one is found.", cxxopts::value(cri_socket_paths), "<path>")
		("d,daemon",                      "Run as a daemon.", cxxopts::value(daemon)->default_value("false"))
		("disable-cri-async",             "Disable asynchronous CRI metadata fetching. This is useful to let the input event wait for the container metadata fetch to finish before moving forward. Async fetching, in some environments leads to empty fields for container metadata when the fetch is not fast enough to be completed asynchronously. This can have a performance penalty on your environment depending on the number of containers and the frequency at which they are created/started/stopped.", cxxopts::value(disable_cri_async)->default_value("false"))
		("disable-source",                "Disable a specific event source. Available event sources are: syscall or any source from a configured source plugin. It can be passed multiple times. Can not disable all event sources.", cxxopts::value(disable_sources), "<event_source>")
		("D",                             "Disable any rules with names having the substring <substring>. Can be specified multiple times. Can not be specified with -t.", cxxopts::value(disabled_rule_substrings), "<substring>")
		("e",                             "Read the events from <events_file> in .scap format instead of tapping into live.", cxxopts::value(trace_filename), "<events_file>")
		("i",                             "Print all events that are ignored by default (i.e. without the -A flag) and exit.", cxxopts::value(print_ignored_events)->default_value("false"))
#ifndef MINIMAL_BUILD
		("k,k8s-api",                     "Enable Kubernetes support by connecting to the API server specified as argument. E.g. \"http://admin:password@127.0.0.1:8080\". The API server can also be specified via the environment variable FALCO_K8S_API.", cxxopts::value(k8s_api), "<url>")
		("K,k8s-api-cert",                "Use the provided files names to authenticate user and (optionally) verify the K8S API server identity. Each entry must specify full (absolute, or relative to the current directory) path to the respective file. Private key password is optional (needed only if key is password protected). CA certificate is optional. For all files, only PEM file format is supported. Specifying CA certificate only is obsoleted - when single entry is provided for this option, it will be interpreted as the name of a file containing bearer token. Note that the format of this command-line option prohibits use of files whose names contain ':' or '#' characters in the file name.", cxxopts::value(k8s_api_cert), "(<bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>])")
		("k8s-node",                      "The node name will be used as a filter when requesting metadata of pods to the API server. Usually, it should be set to the current node on which Falco is running. If empty, no filter is set, which may have a performance penalty on large clusters.", cxxopts::value(k8s_node_name), "<node_name>")
#endif
		("L",                             "Show the name and description of all rules and exit.", cxxopts::value(describe_all_rules)->default_value("false"))
		("l",                             "Show the name and description of the rule with name <rule> and exit.", cxxopts::value(describe_rule), "<rule>")
		("list",                          "List all defined fields. If <source> is provided, only list those fields for the source <source>. Current values for <source> are \"syscall\" or any source from a configured source plugin.", cxxopts::value(list_source_fields)->implicit_value(""), "<source>")
		("list-syscall-events",  		  "List all defined system call events.", cxxopts::value<bool>(list_syscall_events))
#ifndef MUSL_OPTIMIZED
		("list-plugins",                  "Print info on all loaded plugins and exit.", cxxopts::value(list_plugins)->default_value("false"))
#endif
#ifndef MINIMAL_BUILD
		("m,mesos-api",                   "Enable Mesos support by connecting to the API server specified as argument. E.g. \"http://admin:password@127.0.0.1:5050\". Marathon url is optional and defaults to Mesos address, port 8080. The API servers can also be specified via the environment variable FALCO_MESOS_API.", cxxopts::value(mesos_api), "<url[,marathon_url]>")
#endif
		("M",                             "Stop collecting after <num_seconds> reached.", cxxopts::value(duration_to_tot)->default_value("0"), "<num_seconds>")
		("markdown",                      "When used with --list/--list-syscall-events, print the content in Markdown format", cxxopts::value<bool>(markdown))
		("N",                             "When used with --list, only print field names.", cxxopts::value(names_only)->default_value("false"))
		("o,option",                      "Set the value of option <opt> to <val>. Overrides values in configuration file. <opt> can be identified using its location in configuration file using dot notation. Elements which are entries of lists can be accessed via square brackets [].\n    E.g. base.id = val\n         base.subvalue.subvalue2 = val\n         base.list[1]=val", cxxopts::value(cmdline_config_options), "<opt>=<val>")
		("p,print",                       "Add additional information to each falco notification's output.\nWith -pc or -pcontainer will use a container-friendly format.\nWith -pk or -pkubernetes will use a kubernetes-friendly format.\nWith -pm or -pmesos will use a mesos-friendly format.\nAdditionally, specifying -pc/-pk/-pm will change the interpretation of %container.info in rule output fields.", cxxopts::value(print_additional), "<output_format>")
		("P,pidfile",                     "When run as a daemon, write pid to specified file", cxxopts::value(pidfilename)->default_value("/var/run/falco.pid"), "<pid_file>")
		("r",                             "Rules file/directory (defaults to value set in configuration file, or /etc/falco_rules.yaml). Can be specified multiple times to read from multiple files/directories.", cxxopts::value<std::vector<std::string>>(), "<rules_file>")
		("s",                             "If specified, append statistics related to Falco's reading/processing of events to this file (only useful in live mode).", cxxopts::value(stats_filename), "<stats_file>")
		("stats-interval",                "When using -s <stats_file>, write statistics every <msec> ms. This uses signals, so don't recommend intervals below 200 ms. Defaults to 5000 (5 seconds).", cxxopts::value(stats_interval)->default_value("5000"),  "<msec>")
		("S,snaplen",                     "Capture the first <len> bytes of each I/O buffer. By default, the first 80 bytes are captured. Use this option with caution, it can generate huge trace files.", cxxopts::value(snaplen)->default_value("0"), "<len>")
		("support",                       "Print support information including version, rules files used, etc. and exit.", cxxopts::value(print_support)->default_value("false"))
		("T",                             "Disable any rules with a tag=<tag>. Can be specified multiple times. Can not be specified with -t", cxxopts::value<std::vector<std::string>>(), "<tag>")
		("t",                             "Only run those rules with a tag=<tag>. Can be specified multiple times. Can not be specified with -T/-D.", cxxopts::value<std::vector<std::string>>(), "<tag>")
		("U,unbuffered",                  "Turn off output buffering to configured outputs. This causes every single line emitted by falco to be flushed which generates higher CPU usage but is useful when piping those outputs into another process or into a script.", cxxopts::value(unbuffered_outputs)->default_value("false"))
		("u,userspace",                   "Parse events from userspace. To be used in conjunction with the ptrace(2) based driver (pdig)", cxxopts::value(userspace)->default_value("false"))
		("V,validate",                    "Read the contents of the specified rules(s) file and exit. Can be specified multiple times to validate multiple files.", cxxopts::value(validate_rules_filenames), "<rules_file>")
		("v",                             "Verbose output.", cxxopts::value(verbose)->default_value("false"))
		("version",                       "Print version number.", cxxopts::value(print_version_info)->default_value("false"));

	m_cmdline_opts.set_width(140);
}

m_cmdline_opts.add_options(),这个是注册命令行参数解析配置,如果需要添加新的命令行可以在此追加。我们分析" -c ../falco.yaml"。对应到代码中的

#ifdef BUILD_TYPE_RELEASE
		("c",                             "Configuration file. If not specified uses " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
#else
		("c",                             "Configuration file. If not specified tries " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
#endif

结果保存在class cmdline_options中的conf_filename字段中。

class cmdline_options {
public:
	cmdline_options();
	~cmdline_options();

	// Each of these maps directly to a command line option.
	bool help;
	std::string conf_filename;
......
	bool parse(int argc, char **argv, std::string &errstr);

	std::string usage();
private:
	void define();

	cxxopts::Options m_cmdline_opts;
	cxxopts::ParseResult m_cmdline_parsed;
};

部分属性先屏蔽掉。系统执行时,先调用cmdline_options::cmdline_options()构造函数,内部调用define私有函数然后继续调用cmdline_options::define(),注册我们的命令行参数解析规则。然后调用cmdline_options::parse(),进入函数继续调用m_cmdline_opts.parse(),即cxxopts的解析函数。

代码如下:

bool cmdline_options::parse(int argc, char **argv, std::string &errstr)
{
	try {
		m_cmdline_parsed = m_cmdline_opts.parse(argc, argv);//解析命令行
	}
	catch (std::exception &e)
	{
		errstr = e.what();
		return false;
	}

	// Some options require additional processing/validation
	std::ifstream conf_stream;
	if (!conf_filename.empty())//是否使用-c 指定了对应配置文件,存在,进入,然后打开
	{
		conf_stream.open(conf_filename);
		if (!conf_stream.is_open())
		{
			errstr = std::string("Could not find configuration file at ") + conf_filename;
			return false;
		}
	}
	else
	{
#ifndef BUILD_TYPE_RELEASE
		conf_stream.open(FALCO_SOURCE_CONF_FILE);
		if (conf_stream.is_open())
		{
			conf_filename = FALCO_SOURCE_CONF_FILE;
		}
		else
#endif
		{
			conf_stream.open(FALCO_INSTALL_CONF_FILE);
			if (conf_stream.is_open())
			{
				conf_filename = FALCO_INSTALL_CONF_FILE;
			}
			else
			{
				// Note we do not return false here. Although there is
				// no valid config file, some ways of running falco
				// (e.g. --help, --list) do not need a config file.
				//
				// Later, when it comes time to read a config file, if
				// the filename is empty we exit with an error.
				conf_filename = "";
			}
		}
	}

	if(m_cmdline_parsed.count("b") > 0)
	{
		event_buffer_format = sinsp_evt::PF_BASE64;
	}

	// Expand any paths provided via -r and fill in rules_filenames
	if(m_cmdline_parsed.count("r") > 0)//如果指定了规则文件(可以是多个),则遍历获取读取相关文件内容
	{
		for(auto &path : m_cmdline_parsed["r"].as<std::vector<std::string>>())
		{
			falco_configuration::read_rules_file_directory(path, rules_filenames);
		}
	}

	// Convert the vectors of enabled/disabled tags into sets to match falco engine API
	if(m_cmdline_parsed.count("T") > 0)
	{
		for(auto &tag : m_cmdline_parsed["T"].as<std::vector<std::string>>())
		{
			disabled_rule_tags.insert(tag);
		}
	}

	if(m_cmdline_parsed.count("t") > 0)
	{
		for(auto &tag : m_cmdline_parsed["t"].as<std::vector<std::string>>())
		{
			enabled_rule_tags.insert(tag);
		}
	}

	// Some combinations of arguments are not allowed.

	// You can't both disable and enable rules
	if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) &&
	   enabled_rule_tags.size() > 0)
	{
		errstr = std::string("You can not specify both disabled (-D/-T) and enabled (-t) rules");
		return false;
	}

	if (daemon && pidfilename == "") {
		errstr = std::string("If -d is provided, a pid file must also be provided");
		return false;
	}

	list_fields = m_cmdline_parsed.count("list") > 0 ? true : false;

	return true;
}

基于官网的例子,我们写个测试程序验证一下:

#include <iostream>

#include "cxxopts.hpp"

int main(int argc, char** argv)
{
    cxxopts::Options options("test", "A brief description");

    std::string conf_filename;
    options.add_options()
        ("b,bar", "Param bar", cxxopts::value<std::string>())
        ("d,debug", "Enable debugging", cxxopts::value<bool>()->default_value("false"))
        ("f,foo", "Param foo", cxxopts::value<int>()->default_value("10"))
        ("c",                             "Configuration file. If not specified uses .", cxxopts::value(conf_filename), "<path>")
        ("h,help", "Print usage")
    ;

    auto result = options.parse(argc, argv);

    if (result.count("help"))
    {
      std::cout << options.help() << std::endl;
      exit(0);
    }
    bool debug = result["debug"].as<bool>();
    std::string bar;
    if (result.count("bar"))
            bar = result["bar"].as<std::string>();
    int foo = result["foo"].as<int>();
    if (conf_filename.size())
    {
            std::cout <<"conf  file :" << conf_filename << std::endl;
    }
    return 0;
}

编译命令如下:

 g++ test.cpp -o test  -I cxxopts/include/

运行:

"-r ../rules/falco_rules.yaml" 对应下面的注册代码

("r",                             "Rules file/directory (defaults to value set in configuration file, or /etc/falco_rules.yaml). Can be specified multiple times to read from multiple files/directories.", cxxopts::value<std::vector<std::string>>(), "<rules_file>")

表示规则文件,注释说可能存在多个这样配置,所以使用了std::vector<std::string>>数组。

所以在cmdline_options::parse()函数中,通过m_cmdline_parsed解析结果搜索并遍历相关参数。j检查是否存在将文件路径保存在cmdline_options的rules_filenames属性中。代码在falco_configuration::init函数中。

main=>falco_init=>application::run=>application::load_config=>falco_configuration::init:

void falco_configuration::init(string conf_filename, const vector<string> &cmdline_options)
{
	string m_config_file = conf_filename;
	m_config = new yaml_configuration();
	try
	{
		m_config->load_from_file(m_config_file);
	}
	catch(const std::exception& e)
	{
		std::cerr << "Cannot read config file (" + m_config_file + "): " + e.what() + "\n";
		throw e;
	}

	init_cmdline_options(cmdline_options);

	list<string> rules_files;

	m_config->get_sequence<list<string>>(rules_files, string("rules_file"));

	for(auto &file : rules_files)
	{
		// Here, we only include files that exist
		struct stat buffer;
		if(stat(file.c_str(), &buffer) == 0)//检查文件是否存在
		{
			read_rules_file_directory(file, m_rules_filenames);
		}
	}
......
}

main=>falco_init=>application::run=>application::load_config=>falco_configuration::init=>falco_configuration::read_rules_file_directory:


void falco_configuration::read_rules_file_directory(const string &path, list<string> &rules_filenames)
{
	struct stat st;

	int rc = stat(path.c_str(), &st);

	if(rc != 0)
	{
		std::cerr << "Could not get info on rules file " << path << ": " << strerror(errno) << std::endl;
		exit(-1);
	}

	if(st.st_mode & S_IFDIR)//如果是目录,遍历目录将所有文件保存至rules_filenames
	{
		// It's a directory. Read the contents, sort
		// alphabetically, and add every path to
		// rules_filenames
		vector<string> dir_filenames;

		DIR *dir = opendir(path.c_str());

		if(!dir)
		{
			std::cerr << "Could not get read contents of directory " << path << ": " << strerror(errno) << std::endl;
			exit(-1);
		}

		for(struct dirent *ent = readdir(dir); ent; ent = readdir(dir))
		{
			string efile = path + "/" + ent->d_name;

			rc = stat(efile.c_str(), &st);

			if(rc != 0)
			{
				std::cerr << "Could not get info on rules file " << efile << ": " << strerror(errno) << std::endl;
				exit(-1);
			}

			if(st.st_mode & S_IFREG)
			{
				dir_filenames.push_back(efile);
			}
		}

		closedir(dir);

		std::sort(dir_filenames.begin(),
			  dir_filenames.end());

		for(string &ent : dir_filenames)
		{
			rules_filenames.push_back(ent);
		}
	}
	else//如果是文件,将其保存至rules_filenames中
	{
		// Assume it's a file and just add to
		// rules_filenames. If it can't be opened/etc that
		// will be reported later..
		rules_filenames.push_back(path);
	}
}

其中重点函数是application::run, 这个函数在里面通过std::bind将需要执行的函数添加到run_steps,然后遍历这个std::list循环执行,根据返回值决定是否继续执行后面的函数。

bool application::run(std::string &errstr, bool &restart)
{
	run_result res;

	// The order here is the order in which the methods will be
	// called. Before changing the order, ensure that all
	// dependencies are honored (e.g. don't process events before
	// loading plugins, opening inspector, etc.).
	std::list<std::function<run_result()>> run_steps = {
		std::bind(&application::print_help, this),
		std::bind(&application::print_version, this),
		std::bind(&application::create_signal_handlers, this),
		std::bind(&application::load_config, this),
		std::bind(&application::init_inspector, this),
		std::bind(&application::init_falco_engine, this),
		std::bind(&application::load_plugins, this),
		std::bind(&application::list_fields, this),
		std::bind(&application::list_plugins, this),
		std::bind(&application::load_rules_files, this),
		std::bind(&application::print_ignored_events, this),
		std::bind(&application::print_support, this),
		std::bind(&application::validate_rules_files, this),
		std::bind(&application::daemonize, this),
		std::bind(&application::init_outputs, this),
		std::bind(&application::open_inspector, this),
#ifndef MINIMAL_BUILD
		std::bind(&application::start_grpc_server, this),
		std::bind(&application::start_webserver, this),
#endif
		std::bind(&application::process_events, this)
	};

	std::list<std::function<bool(std::string &)>> teardown_steps = {
		std::bind(&application::close_inspector, this, _1),
		std::bind(&application::unregister_signal_handlers, this, _1),
#ifndef MINIMAL_BUILD
		std::bind(&application::stop_grpc_server, this, _1),
		std::bind(&application::stop_webserver, this, _1)
#endif
	};

	for (auto &func : run_steps)
	{
		res = func();

		if(!res.proceed)
		{
			break;
		}
	}

	for (auto &func : teardown_steps)
	{
		std::string errstr;

		if(!func(errstr))
		{
			// Note only printing warning here--we want all functions
			// to occur even if some return errors.
			fprintf(stderr, "Could not tear down in run(): %s\n", errstr.c_str());
		}
	}

	if(!res.success)
	{
		errstr = res.errstr;
	}

	restart = m_state->restart;

	return res.success;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要安装Sysdig Falco,您可以按照以下步骤进操作: 1. 部署收集程序:使用以下命令在Docker中运Falco收集程序,并指定展示程序地址: ``` docker run -d \ -p 2801:2801 \ --name falcosidekick \ -e WEBUI_URL=http://192.168.130.145:2802 \ falcosecurity/falcosidekick ``` 这将在Docker中启动Falco收集程序,并将展示程序地址设置为http://192.168.130.145:2802。# vim falco.yaml ...... json_output: true ...... http_output: enabled: true url: "http://192.168.130.145:2801/" user_agent: "falcosecurity/falco" [root@k8s-node1 falco# systemctl restart falco-custom ``` 这将修改Falco配置文件,使其以JSON格式输出,并启用HTTP输出,并将收集程序地址设置为http://192.168.130.145:2801。然后重新启动Falco服务。123 #### 引用[.reference_title] - *1* *3* [K8s进阶7——Sysdig、Falco、审计日志](https://blog.csdn.net/yi_qingjun/article/details/130260005)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}} ] [.reference_item] - *2* [Sysdig Falco:你不可不知的Docker安全监控利器](https://blog.csdn.net/weixin_34376562/article/details/89594095)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值