Compare commits
78 Commits
Author | SHA1 | Date |
---|---|---|
|
12d8e63d34 | |
|
d608d7282e | |
|
3fdac75fd0 | |
|
b7bb92fafe | |
|
8f53f05a62 | |
|
7c1d5695b4 | |
|
f5474a80f2 | |
|
69176a7e5d | |
|
a202a120f9 | |
|
6ac3b4df0a | |
|
c61e9d1502 | |
|
85cf8fd4c4 | |
|
f412a34986 | |
|
cf6f8ab52e | |
|
3b45fdb759 | |
|
e6d0e188aa | |
|
32963fb3d2 | |
|
d861afb22d | |
|
167ec5a390 | |
|
e69d2950eb | |
|
13ebd8dc96 | |
|
fda10fc439 | |
|
7e92b1b241 | |
|
5a1efd0257 | |
|
7955010144 | |
|
faca7745ba | |
|
024430afc9 | |
|
e6084751c5 | |
|
ede33484c2 | |
|
40ff9af243 | |
|
98fd1a5dcd | |
|
2eb4a3106b | |
|
9130ff4b53 | |
|
c36a0e0259 | |
|
64aa8490f4 | |
|
64ea3ace4e | |
|
9cd2769c2f | |
|
c43c0044a1 | |
|
1a38f04582 | |
|
18133edb5c | |
|
9a9dc4288a | |
|
7b2cafbb8d | |
|
401e4d02e0 | |
|
ace67303af | |
|
76e31c63c5 | |
|
fc6f7fb3d1 | |
|
38733055ee | |
|
5e5da37395 | |
|
be201d72ac | |
|
4c944ba0f0 | |
|
33a5a80a44 | |
|
20d960fdb4 | |
|
2eb0c61922 | |
|
fe10de21ed | |
|
979fc36c78 | |
|
f1de2c9de8 | |
|
be971a90dd | |
|
079755064b | |
|
55e9d809dc | |
|
13612c304e | |
|
85b034dc52 | |
|
b68cf68689 | |
|
8beb7b8c68 | |
|
0aa96151a6 | |
|
452df6bdaf | |
|
24a8aaee77 | |
|
255177d4b7 | |
|
95d8cfcd97 | |
|
13b461eb01 | |
|
6fdfd31005 | |
|
aa8e5cecdd | |
|
60a09e9ff8 | |
|
662472b510 | |
|
c2c8a3e406 | |
|
5885ebe25a | |
|
bd1eead4c4 | |
|
3352b0e7f4 | |
|
260e4c2e40 |
|
@ -0,0 +1,22 @@
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: gomod
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
groups:
|
||||||
|
gomod:
|
||||||
|
update-types:
|
||||||
|
- "patch"
|
||||||
|
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
open-pull-requests-limit: 10
|
||||||
|
groups:
|
||||||
|
actions:
|
||||||
|
update-types:
|
||||||
|
- "minor"
|
||||||
|
- "patch"
|
|
@ -0,0 +1,37 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run-tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout plugin-sdk-go
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- name: Setup Golang
|
||||||
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||||
|
with:
|
||||||
|
go-version: '^1.19'
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: go test ./...
|
||||||
|
|
||||||
|
build-example-plugins:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout plugin-sdk-go
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- name: Setup Golang
|
||||||
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||||
|
with:
|
||||||
|
go-version: '^1.19'
|
||||||
|
|
||||||
|
- name: Build all example plugins
|
||||||
|
run: make examples
|
|
@ -1,22 +1,12 @@
|
||||||
# For most projects, this workflow file will not need changing; you simply need
|
|
||||||
# to commit it to your repository.
|
|
||||||
#
|
|
||||||
# You may wish to alter this file to override the set of languages analyzed,
|
|
||||||
# or to provide custom queries or build logic.
|
|
||||||
#
|
|
||||||
# ******** NOTE ********
|
|
||||||
# We have attempted to detect the languages in your repository. Please check
|
|
||||||
# the `language` matrix defined below to confirm you have the correct set of
|
|
||||||
# supported CodeQL languages.
|
|
||||||
#
|
|
||||||
name: "CodeQL"
|
name: "CodeQL"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main ]
|
branches:
|
||||||
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
# The branches below must be a subset of the branches above
|
branches:
|
||||||
branches: [ main ]
|
- main
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '45 5 * * 2'
|
- cron: '45 5 * * 2'
|
||||||
|
|
||||||
|
@ -32,40 +22,21 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
language: [ 'go' ]
|
language:
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
- 'go'
|
||||||
# Learn more:
|
|
||||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v1
|
uses: github/codeql-action/init@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
||||||
# By default, queries listed here will override any specified in a config file.
|
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
||||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v1
|
uses: github/codeql-action/autobuild@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
|
||||||
# 📚 https://git.io/JvXDl
|
|
||||||
|
|
||||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
|
||||||
# and modify them (or add more) to build your code if your project
|
|
||||||
# uses a compiled language
|
|
||||||
|
|
||||||
#- run: |
|
|
||||||
# make bootstrap
|
|
||||||
# make release
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v1
|
uses: github/codeql-action/analyze@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
|
||||||
|
|
|
@ -7,23 +7,25 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||||
with:
|
with:
|
||||||
go-version: 1.17
|
go-version: 1.17
|
||||||
|
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@v3
|
uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0
|
||||||
with:
|
with:
|
||||||
distribution: goreleaser
|
args: release --clean --timeout 60m
|
||||||
version: v1.10.3
|
|
||||||
args: release --rm-dist --timeout 60m
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
*~
|
*~
|
||||||
|
.vscode
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
project_name: plugin-sdk-go
|
project_name: plugin-sdk-go
|
||||||
build:
|
version: 2
|
||||||
skip: true
|
|
||||||
|
builds:
|
||||||
|
- skip: true
|
||||||
|
|
||||||
release:
|
release:
|
||||||
github:
|
github: {}
|
||||||
prerelease: auto
|
prerelease: auto
|
||||||
|
|
19
Makefile
19
Makefile
|
@ -1,5 +1,6 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
# Copyright (C) 2021 The Falco Authors.
|
# Copyright (C) 2025 The Falco Authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||||
# the License. You may obtain a copy of the License at
|
# the License. You may obtain a copy of the License at
|
||||||
|
@ -13,8 +14,9 @@
|
||||||
SHELL := /bin/bash
|
SHELL := /bin/bash
|
||||||
GO ?= $(shell which go)
|
GO ?= $(shell which go)
|
||||||
CURL ?= $(shell which curl)
|
CURL ?= $(shell which curl)
|
||||||
|
PATCH ?= $(shell which patch)
|
||||||
|
|
||||||
FALCOSECURITY_LIBS_REVISION ?= 000eb27573af74168510e4836330ff6958c3f355
|
FALCOSECURITY_LIBS_REVISION ?= 0.21.0
|
||||||
FALCOSECURITY_LIBS_REPO ?= falcosecurity/libs
|
FALCOSECURITY_LIBS_REPO ?= falcosecurity/libs
|
||||||
PLUGINLIB_URL=https://raw.githubusercontent.com/${FALCOSECURITY_LIBS_REPO}/${FALCOSECURITY_LIBS_REVISION}/userspace/plugin
|
PLUGINLIB_URL=https://raw.githubusercontent.com/${FALCOSECURITY_LIBS_REPO}/${FALCOSECURITY_LIBS_REVISION}/userspace/plugin
|
||||||
|
|
||||||
|
@ -30,13 +32,16 @@ clean: clean-pluginlib $(examples_clean)
|
||||||
|
|
||||||
.PHONY: pluginlib
|
.PHONY: pluginlib
|
||||||
pluginlib:
|
pluginlib:
|
||||||
@$(CURL) -Lso pkg/sdk/plugin_types.h $(PLUGINLIB_URL)/plugin_types.h
|
$(CURL) -Lso pkg/sdk/plugin_types.h $(PLUGINLIB_URL)/plugin_types.h
|
||||||
@$(CURL) -Lso pkg/sdk/plugin_api.h $(PLUGINLIB_URL)/plugin_api.h
|
$(CURL) -Lso pkg/sdk/plugin_api.h $(PLUGINLIB_URL)/plugin_api.h
|
||||||
@$(CURL) -Lso pkg/loader/plugin_loader.h $(PLUGINLIB_URL)/plugin_loader.h
|
$(CURL) -Lso pkg/loader/plugin_loader.h $(PLUGINLIB_URL)/plugin_loader.h
|
||||||
@$(CURL) -Lso pkg/loader/plugin_loader.c $(PLUGINLIB_URL)/plugin_loader.c
|
$(CURL) -Lso pkg/loader/plugin_loader.c $(PLUGINLIB_URL)/plugin_loader.c
|
||||||
|
$(PATCH) -p1 < pkg/loader/plugin_api_include.patch
|
||||||
|
$(PATCH) -p1 < pkg/loader/strlcpy.patch
|
||||||
|
$(PATCH) -p1 < pkg/sdk/plugin_types_include.patch
|
||||||
|
|
||||||
clean-pluginlib:
|
clean-pluginlib:
|
||||||
@rm -f \
|
rm -f \
|
||||||
pkg/sdk/plugin_types.h \
|
pkg/sdk/plugin_types.h \
|
||||||
pkg/sdk/plugin_api.h \
|
pkg/sdk/plugin_api.h \
|
||||||
pkg/loader/plugin_loader.h \
|
pkg/loader/plugin_loader.h \
|
||||||
|
|
1
OWNERS
1
OWNERS
|
@ -7,4 +7,3 @@ emeritus_approvers:
|
||||||
- kris-nova
|
- kris-nova
|
||||||
- mstemm
|
- mstemm
|
||||||
- ldegio
|
- ldegio
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
# plugin-sdk-go
|
# plugin-sdk-go
|
||||||
|
|
||||||
|
[](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#core-scope) [](https://github.com/falcosecurity/evolution/blob/main/REPOSITORIES.md#stable) [](./LICENSE)
|
||||||
|
|
||||||
[](https://pkg.go.dev/github.com/falcosecurity/plugin-sdk-go/pkg/sdk)
|
[](https://pkg.go.dev/github.com/falcosecurity/plugin-sdk-go/pkg/sdk)
|
||||||
[](https://github.com/falcosecurity/plugin-sdk-go/releases/latest)
|
[](https://github.com/falcosecurity/plugin-sdk-go/releases/latest)
|
||||||
[](https://goreportcard.com/report/github.com/falcosecurity/plugin-sdk-go)
|
[](https://goreportcard.com/report/github.com/falcosecurity/plugin-sdk-go)
|
||||||
[](LICENSE)
|
|
||||||
|
|
||||||
|
|
||||||
Note: *The plugin system is a new feature introduced since Falco 0.31.0. You can find more detail in the original [proposal document](https://github.com/falcosecurity/falco/blob/master/proposals/20210501-plugin-system.md).*
|
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
# Copyright (C) 2022 The Falco Authors.
|
# Copyright (C) 2023 The Falco Authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||||
# the License. You may obtain a copy of the License at
|
# the License. You may obtain a copy of the License at
|
||||||
|
@ -25,5 +26,5 @@ clean:
|
||||||
|
|
||||||
$(OUTPUT): bench.cpp bench.go
|
$(OUTPUT): bench.cpp bench.go
|
||||||
mkdir -p $(OUTPUTDIR)
|
mkdir -p $(OUTPUTDIR)
|
||||||
GODEBUG=cgocheck=2 $(GO) build -buildmode=c-archive -o $(OUTPUTGO) bench.go
|
GODEBUG=cgocheck=1 $(GO) build -buildmode=c-archive -o $(OUTPUTGO) bench.go
|
||||||
$(CXX) bench.cpp $(OUTPUTGO) -std=c++11 -pthread -o $(OUTPUT)
|
$(CXX) bench.cpp $(OUTPUTGO) -std=c++11 -pthread -o $(OUTPUT)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -23,14 +24,14 @@ limitations under the License.
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "../../pkg/sdk/plugin_types.h"
|
#include "../../pkg/sdk/plugin_api.h"
|
||||||
|
|
||||||
// defined in Go and exported from bench.go
|
// defined in Go and exported from bench.go
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
void plugin_destroy(ss_plugin_t*);
|
void plugin_destroy(ss_plugin_t*);
|
||||||
ss_plugin_t* plugin_init(const char*, ss_plugin_rc*);
|
ss_plugin_t* plugin_init(const ss_plugin_init_input *input, ss_plugin_rc *rc);
|
||||||
ss_plugin_rc plugin_extract_fields(ss_plugin_t*, const ss_plugin_event*, uint32_t, ss_plugin_extract_field*);
|
ss_plugin_rc plugin_extract_fields(ss_plugin_t*, const ss_plugin_event_input*, const ss_plugin_field_extract_input*);
|
||||||
}
|
}
|
||||||
|
|
||||||
// global benchmark options
|
// global benchmark options
|
||||||
|
@ -111,13 +112,16 @@ static void benchmark(ss_plugin_t *plugin) noexcept
|
||||||
e.arg_present = false;
|
e.arg_present = false;
|
||||||
e.ftype = FTYPE_UINT64;
|
e.ftype = FTYPE_UINT64;
|
||||||
e.flist = false;
|
e.flist = false;
|
||||||
|
ss_plugin_field_extract_input in;
|
||||||
|
in.fields = &e;
|
||||||
|
in.num_fields = 1;
|
||||||
|
|
||||||
// request multiple extractions and compute total execution time
|
// request multiple extractions and compute total execution time
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
auto start = std::chrono::high_resolution_clock::now();
|
||||||
ss_plugin_rc rc = SS_PLUGIN_FAILURE;
|
ss_plugin_rc rc = SS_PLUGIN_FAILURE;
|
||||||
for (int i = 0; i < g_niterations; i++)
|
for (int i = 0; i < g_niterations; i++)
|
||||||
{
|
{
|
||||||
rc = plugin_extract_fields(plugin, NULL, 1, &e);
|
rc = plugin_extract_fields(plugin, NULL, &in);
|
||||||
if (rc != SS_PLUGIN_SUCCESS)
|
if (rc != SS_PLUGIN_SUCCESS)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "plugin %" PRIu64 ": plugin_extract_fields failure: %d\n", (uint64_t) plugin, rc);
|
fprintf(stderr, "plugin %" PRIu64 ": plugin_extract_fields failure: %d\n", (uint64_t) plugin, rc);
|
||||||
|
@ -146,7 +150,9 @@ int main(int argc, char** argv)
|
||||||
for (int i = 0; i < g_parallelism; ++i)
|
for (int i = 0; i < g_parallelism; ++i)
|
||||||
{
|
{
|
||||||
ss_plugin_rc rc = SS_PLUGIN_FAILURE;
|
ss_plugin_rc rc = SS_PLUGIN_FAILURE;
|
||||||
plugins.push_back(plugin_init(g_use_async ? "async" : "", &rc));
|
ss_plugin_init_input in;
|
||||||
|
in.config = g_use_async ? "async" : "";
|
||||||
|
plugins.push_back(plugin_init(&in, &rc));
|
||||||
if (rc != SS_PLUGIN_SUCCESS)
|
if (rc != SS_PLUGIN_SUCCESS)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "can't initialize plugin");
|
fprintf(stderr, "can't initialize plugin");
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
# Copyright (C) 2021 The Falco Authors.
|
# Copyright (C) 2023 The Falco Authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||||
# the License. You may obtain a copy of the License at
|
# the License. You may obtain a copy of the License at
|
||||||
|
@ -23,4 +24,4 @@ clean:
|
||||||
@rm -f *.so *.h
|
@rm -f *.so *.h
|
||||||
|
|
||||||
$(OUTPUT): *.go
|
$(OUTPUT): *.go
|
||||||
@GODEBUG=cgocheck=2 $(GO) build -buildmode=c-shared -o $(OUTPUT)
|
@GODEBUG=cgocheck=1 $(GO) build -buildmode=c-shared -o $(OUTPUT)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
# Copyright (C) 2021 The Falco Authors.
|
# Copyright (C) 2023 The Falco Authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||||
# the License. You may obtain a copy of the License at
|
# the License. You may obtain a copy of the License at
|
||||||
|
@ -23,4 +24,4 @@ clean:
|
||||||
@rm -f *.so *.h
|
@rm -f *.so *.h
|
||||||
|
|
||||||
$(OUTPUT): *.go
|
$(OUTPUT): *.go
|
||||||
@GODEBUG=cgocheck=2 $(GO) build -buildmode=c-shared -o $(OUTPUT)
|
@GODEBUG=cgocheck=1 $(GO) build -buildmode=c-shared -o $(OUTPUT)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
# Copyright (C) 2021 The Falco Authors.
|
# Copyright (C) 2023 The Falco Authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||||
# the License. You may obtain a copy of the License at
|
# the License. You may obtain a copy of the License at
|
||||||
|
@ -23,4 +24,4 @@ clean:
|
||||||
@rm -f *.so *.h
|
@rm -f *.so *.h
|
||||||
|
|
||||||
$(OUTPUT): *.go
|
$(OUTPUT): *.go
|
||||||
@GODEBUG=cgocheck=2 $(GO) build -buildmode=c-shared -o $(OUTPUT)
|
@GODEBUG=cgocheck=1 $(GO) build -buildmode=c-shared -o $(OUTPUT)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -28,6 +29,7 @@ import (
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/alecthomas/jsonschema"
|
"github.com/alecthomas/jsonschema"
|
||||||
|
@ -55,6 +57,7 @@ type MyPluginConfig struct {
|
||||||
type MyPlugin struct {
|
type MyPlugin struct {
|
||||||
plugins.BasePlugin
|
plugins.BasePlugin
|
||||||
config MyPluginConfig
|
config MyPluginConfig
|
||||||
|
initTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defining a type for the plugin source capture instances returned by Open().
|
// Defining a type for the plugin source capture instances returned by Open().
|
||||||
|
@ -127,6 +130,7 @@ func (m *MyPlugin) InitSchema() *sdk.SchemaInfo {
|
||||||
// always well-formed according to the provided schema.
|
// always well-formed according to the provided schema.
|
||||||
// This method is mandatory.
|
// This method is mandatory.
|
||||||
func (m *MyPlugin) Init(config string) error {
|
func (m *MyPlugin) Init(config string) error {
|
||||||
|
m.initTime = time.Now()
|
||||||
// Deserialize the config json. Ignoring the error
|
// Deserialize the config json. Ignoring the error
|
||||||
// and not validating the config values is possible
|
// and not validating the config values is possible
|
||||||
// due to the schema defined through InitSchema(),
|
// due to the schema defined through InitSchema(),
|
||||||
|
@ -143,6 +147,13 @@ func (m *MyPlugin) Fields() []sdk.FieldEntry {
|
||||||
return []sdk.FieldEntry{
|
return []sdk.FieldEntry{
|
||||||
{Type: "uint64", Name: "example.count", Display: "Counter value", Desc: "Current value of the internal counter"},
|
{Type: "uint64", Name: "example.count", Display: "Counter value", Desc: "Current value of the internal counter"},
|
||||||
{Type: "string", Name: "example.countstr", Display: "Counter string value", Desc: "String represetation of current value of the internal counter"},
|
{Type: "string", Name: "example.countstr", Display: "Counter string value", Desc: "String represetation of current value of the internal counter"},
|
||||||
|
{Type: "bool", Name: "example.oddcount", Display: "Counter value is odd", Desc: "True if the current value of the internal counter is an odd number"},
|
||||||
|
{Type: "reltime", Name: "example.initduration", Display: "Time since init", Desc: "Time since the plugin was initialized"},
|
||||||
|
{Type: "abstime", Name: "example.evttime", Display: "Event timestamp", Desc: "Event timestamp"},
|
||||||
|
{Type: "ipaddr", Name: "example.ipv4addr", Display: "Sample IPv4 address", Desc: "A sample IPv4 address"},
|
||||||
|
{Type: "ipaddr", Name: "example.ipv6addr", Display: "Sample IPv6 address", Desc: "A sample IPv6 address"},
|
||||||
|
{Type: "ipnet", Name: "example.ipv4net", Display: "Sample IPv4 network", Desc: "A sample IPv4 network"},
|
||||||
|
{Type: "ipnet", Name: "example.ipv6net", Display: "Sample IPv6 network", Desc: "A sample IPv6 network"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,13 +167,44 @@ func (m *MyPlugin) Extract(req sdk.ExtractRequest, evt sdk.EventReader) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch req.FieldID() {
|
switch req.Field() {
|
||||||
case 0:
|
case "example.count":
|
||||||
req.SetValue(value)
|
req.SetValue(value)
|
||||||
return nil
|
return nil
|
||||||
case 1:
|
case "example.countstr":
|
||||||
req.SetValue(fmt.Sprintf("%d", value))
|
req.SetValue(fmt.Sprintf("%d", value))
|
||||||
return nil
|
return nil
|
||||||
|
case "example.oddcount":
|
||||||
|
req.SetValue((value%2 == 1))
|
||||||
|
return nil
|
||||||
|
case "example.initduration":
|
||||||
|
req.SetValue(time.Since(m.initTime))
|
||||||
|
return nil
|
||||||
|
case "example.evttime":
|
||||||
|
req.SetValue(time.Unix(0, int64(evt.Timestamp())))
|
||||||
|
return nil
|
||||||
|
case "example.ipv4addr":
|
||||||
|
req.SetValue(net.IPv4allsys.To4())
|
||||||
|
return nil
|
||||||
|
case "example.ipv6addr":
|
||||||
|
req.SetValue(net.IPv6loopback)
|
||||||
|
return nil
|
||||||
|
case "example.ipv4net":
|
||||||
|
_, n, err := net.ParseCIDR("192.0.2.1/24")
|
||||||
|
if err == nil {
|
||||||
|
req.SetValue(n)
|
||||||
|
} else {
|
||||||
|
println(err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case "example.ipv6net":
|
||||||
|
_, n, err := net.ParseCIDR("2002::1234:abcd:ffff:c0a8:101/64")
|
||||||
|
if err == nil {
|
||||||
|
req.SetValue(n)
|
||||||
|
} else {
|
||||||
|
println(err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported field: %s", req.Field())
|
return fmt.Errorf("unsupported field: %s", req.Field())
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
# Copyright (C) 2023 The Falco Authors.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
- rule: Sample plugin rule
|
||||||
|
desc: Some sample rule for testing
|
||||||
|
condition:
|
||||||
|
evt.num > 0 and evt.num < 5
|
||||||
|
and example.count > 0
|
||||||
|
and example.oddcount = true
|
||||||
|
and example.initduration exists
|
||||||
|
and example.evttime exists
|
||||||
|
and example.ipv4addr = "224.0.0.1"
|
||||||
|
and example.ipv6addr = "::1"
|
||||||
|
and example.ipv4net = "192.0.3.1/16"
|
||||||
|
and example.ipv6net = "2002::1234:abcd:ffff:c0a8:102:ffff/32"
|
||||||
|
output: Some event (
|
||||||
|
example.count=%example.count,
|
||||||
|
example.countstr=%example.countstr,
|
||||||
|
example.oddcount=%example.oddcount,
|
||||||
|
example.initduration=%example.initduration,
|
||||||
|
example.evttime=%example.evttime,
|
||||||
|
evt.time=%evt.rawtime,
|
||||||
|
example.ipv4addr=%example.ipv4addr,
|
||||||
|
example.ipv6addr=%example.ipv6addr,
|
||||||
|
example.ipv4net=%example.ipv4net,
|
||||||
|
example.ipv6net=%example.ipv6net
|
||||||
|
info=%evt.plugininfo
|
||||||
|
plugin=%evt.pluginname)
|
||||||
|
priority: CRITICAL
|
||||||
|
source: example
|
|
@ -5,6 +5,6 @@ replace github.com/falcosecurity/plugin-sdk-go => ../../
|
||||||
go 1.15
|
go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alecthomas/jsonschema v0.0.0-20211228220459-151e3c21f49d
|
github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b
|
||||||
github.com/falcosecurity/plugin-sdk-go v0.0.0-00010101000000-000000000000
|
github.com/falcosecurity/plugin-sdk-go v0.0.0-00010101000000-000000000000
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,16 +1,27 @@
|
||||||
github.com/alecthomas/jsonschema v0.0.0-20211228220459-151e3c21f49d h1:4BQNwS4T13UU3Yee4GfzZH3Q9SNpKeJvLigfw8fDjX0=
|
github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b h1:doCpXjVwui6HUN+xgNsNS3SZ0/jUZ68Eb+mJRNOZfog=
|
||||||
github.com/alecthomas/jsonschema v0.0.0-20211228220459-151e3c21f49d/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
|
github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk=
|
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk=
|
||||||
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
|
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709 h1:Ko2LQMrRU+Oy/+EDBwX7eZ2jp3C47eDBB8EIhKTun+I=
|
|
||||||
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
# Copyright (C) 2021 The Falco Authors.
|
# Copyright (C) 2023 The Falco Authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||||
# the License. You may obtain a copy of the License at
|
# the License. You may obtain a copy of the License at
|
||||||
|
@ -23,5 +24,5 @@ clean:
|
||||||
@rm -f *.so *.h
|
@rm -f *.so *.h
|
||||||
|
|
||||||
$(OUTPUT): *.go
|
$(OUTPUT): *.go
|
||||||
@GODEBUG=cgocheck=2 $(GO) build -buildmode=c-shared -o $(OUTPUT)
|
@GODEBUG=cgocheck=1 $(GO) build -buildmode=c-shared -o $(OUTPUT)
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
12
go.mod
12
go.mod
|
@ -1,8 +1,16 @@
|
||||||
module github.com/falcosecurity/plugin-sdk-go
|
module github.com/falcosecurity/plugin-sdk-go
|
||||||
|
|
||||||
go 1.15
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
github.com/stretchr/testify v1.8.2
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
|
|
15
go.sum
15
go.sum
|
@ -1,10 +1,16 @@
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
@ -12,3 +18,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -16,6 +17,12 @@ limitations under the License.
|
||||||
|
|
||||||
package cgo
|
package cgo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync/atomic"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
// Handle is an alternative implementation of cgo.Handle introduced by
|
// Handle is an alternative implementation of cgo.Handle introduced by
|
||||||
// Go 1.17, see https://pkg.go.dev/runtime/cgo. This implementation
|
// Go 1.17, see https://pkg.go.dev/runtime/cgo. This implementation
|
||||||
// optimizes performance in use cases related to plugins. It is intended
|
// optimizes performance in use cases related to plugins. It is intended
|
||||||
|
@ -42,12 +49,18 @@ package cgo
|
||||||
// The usage in other contexts is discuraged.
|
// The usage in other contexts is discuraged.
|
||||||
type Handle uintptr
|
type Handle uintptr
|
||||||
|
|
||||||
|
const (
|
||||||
// MaxHandle is the largest value that an Handle can hold
|
// MaxHandle is the largest value that an Handle can hold
|
||||||
const MaxHandle = 32 - 1
|
MaxHandle = 256 - 1
|
||||||
|
|
||||||
|
// max number of times we're willing to iterate over the vector of reusable
|
||||||
|
// handles to do compare-and-swap before giving up
|
||||||
|
maxNewHandleRounds = 20
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
handles [MaxHandle + 1]interface{} // [int]interface{}
|
handles [MaxHandle + 1]unsafe.Pointer // [int]*interface{}
|
||||||
noHandle int = 0
|
noHandle unsafe.Pointer = nil
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -71,13 +84,30 @@ func init() {
|
||||||
//
|
//
|
||||||
// This function is not thread-safe.
|
// This function is not thread-safe.
|
||||||
func NewHandle(v interface{}) Handle {
|
func NewHandle(v interface{}) Handle {
|
||||||
for i := 1; i <= MaxHandle; i++ {
|
rounds := 0
|
||||||
if handles[i] == &noHandle {
|
for h := uintptr(1); ; h++ {
|
||||||
handles[i] = v
|
// we acquired ownership of an handle, return it
|
||||||
return Handle(i)
|
// note: we attempt accessing slots 1..MaxHandle (included)
|
||||||
|
if atomic.CompareAndSwapPointer(&handles[h], noHandle, (unsafe.Pointer)(&v)) {
|
||||||
|
return Handle(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we haven't acquired a handle, but we can try with the next one
|
||||||
|
if h < MaxHandle {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// we iterated over the whole vector of handles, so we get back to start
|
||||||
|
// and try again with another round. Once we do this too many times,
|
||||||
|
// we have no choice if not panic-ing
|
||||||
|
h = uintptr(0) // note: will be incremented when continuing
|
||||||
|
if rounds < maxNewHandleRounds {
|
||||||
|
rounds++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(fmt.Sprintf("plugin-sdk-go/cgo: could not obtain a new handle after round #%d", rounds))
|
||||||
}
|
}
|
||||||
panic("plugin-sdk-go/cgo: ran out of handle space")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value returns the associated Go value for a valid handle.
|
// Value returns the associated Go value for a valid handle.
|
||||||
|
@ -85,10 +115,10 @@ func NewHandle(v interface{}) Handle {
|
||||||
// The method panics if the handle is invalid.
|
// The method panics if the handle is invalid.
|
||||||
// This function is not thread-safe.
|
// This function is not thread-safe.
|
||||||
func (h Handle) Value() interface{} {
|
func (h Handle) Value() interface{} {
|
||||||
if h > MaxHandle || handles[h] == &noHandle {
|
if h > MaxHandle || atomic.LoadPointer(&handles[h]) == noHandle {
|
||||||
panic("plugin-sdk-go/cgo: misuse of an invalid Handle")
|
panic(fmt.Sprintf("plugin-sdk-go/cgo: misuse (value) of an invalid Handle %d", h))
|
||||||
}
|
}
|
||||||
return handles[h]
|
return *(*interface{})(atomic.LoadPointer(&handles[h]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete invalidates a handle. This method should only be called once
|
// Delete invalidates a handle. This method should only be called once
|
||||||
|
@ -98,14 +128,14 @@ func (h Handle) Value() interface{} {
|
||||||
// The method panics if the handle is invalid.
|
// The method panics if the handle is invalid.
|
||||||
// This function is not thread-safe.
|
// This function is not thread-safe.
|
||||||
func (h Handle) Delete() {
|
func (h Handle) Delete() {
|
||||||
if h > MaxHandle || handles[h] == &noHandle {
|
if h > MaxHandle || atomic.LoadPointer(&handles[h]) == noHandle {
|
||||||
panic("plugin-sdk-go/cgo: misuse of an invalid Handle")
|
panic(fmt.Sprintf("plugin-sdk-go/cgo: misuse (delete) of an invalid Handle %d", h))
|
||||||
}
|
}
|
||||||
handles[h] = &noHandle
|
atomic.StorePointer(&handles[h], noHandle)
|
||||||
}
|
}
|
||||||
|
|
||||||
func resetHandles() {
|
func resetHandles() {
|
||||||
for i := 0; i <= MaxHandle; i++ {
|
for i := 0; i <= MaxHandle; i++ {
|
||||||
handles[i] = &noHandle
|
atomic.StorePointer(&handles[i], noHandle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -18,6 +19,7 @@ package cgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,7 +62,7 @@ func TestHandle(t *testing.T) {
|
||||||
|
|
||||||
siz := 0
|
siz := 0
|
||||||
for i := 0; i < MaxHandle; i++ {
|
for i := 0; i < MaxHandle; i++ {
|
||||||
if handles[i] != &noHandle {
|
if atomic.LoadPointer(&handles[i]) != noHandle {
|
||||||
siz++
|
siz++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -45,9 +46,9 @@ static const char *__get_init_schema(plugin_api* p, ss_plugin_schema_type *s)
|
||||||
return p->get_init_schema(s);
|
return p->get_init_schema(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ss_plugin_t* __init(plugin_api* p, const char *cfg, ss_plugin_rc *rc)
|
static ss_plugin_t* __init(plugin_api* p, const ss_plugin_init_input *in, ss_plugin_rc *rc)
|
||||||
{
|
{
|
||||||
return p->init(cfg, rc);
|
return p->init(in, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __destroy(plugin_api* p, ss_plugin_t* s)
|
static void __destroy(plugin_api* p, ss_plugin_t* s)
|
||||||
|
@ -80,19 +81,19 @@ static const char* __get_progress(plugin_api* p, ss_plugin_t* s, ss_instance_t*
|
||||||
return p->get_progress(s, h, r);
|
return p->get_progress(s, h, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* __event_to_string(plugin_api* p, ss_plugin_t *s, const ss_plugin_event *e)
|
static const char* __event_to_string(plugin_api* p, ss_plugin_t *s, const ss_plugin_event_input *e)
|
||||||
{
|
{
|
||||||
return p->event_to_string(s, e);
|
return p->event_to_string(s, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ss_plugin_rc __next_batch(plugin_api* p, ss_plugin_t* s, ss_instance_t* h, uint32_t *n, ss_plugin_event **e)
|
static ss_plugin_rc __next_batch(plugin_api* p, ss_plugin_t* s, ss_instance_t* h, uint32_t *n, ss_plugin_event ***e)
|
||||||
{
|
{
|
||||||
return p->next_batch(s, h, n, e);
|
return p->next_batch(s, h, n, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ss_plugin_rc __extract_fields(plugin_api* p, ss_plugin_t *s, const ss_plugin_event *e, uint32_t n, ss_plugin_extract_field *f)
|
static ss_plugin_rc __extract_fields(plugin_api* p, ss_plugin_t *s, const ss_plugin_event_input *e, ss_plugin_field_extract_input *in)
|
||||||
{
|
{
|
||||||
return p->extract_fields(s, e, n, f);
|
return p->extract_fields(s, e, in);
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -109,6 +110,12 @@ import (
|
||||||
"github.com/xeipuuv/gojsonschema"
|
"github.com/xeipuuv/gojsonschema"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// todo(jasondellaluce,therealbobo): the loader must support the new features of
|
||||||
|
// the plugin API:
|
||||||
|
// - event parsing capability
|
||||||
|
// - async events capability
|
||||||
|
// - get_extract_event_types
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errNotInitialized = errors.New("plugin is not initialized")
|
errNotInitialized = errors.New("plugin is not initialized")
|
||||||
errNoSourcingCap = errors.New("plugin does not support event sourcing capability")
|
errNoSourcingCap = errors.New("plugin does not support event sourcing capability")
|
||||||
|
@ -126,6 +133,17 @@ type Plugin struct {
|
||||||
fields []sdk.FieldEntry
|
fields []sdk.FieldEntry
|
||||||
validated bool
|
validated bool
|
||||||
validErr error
|
validErr error
|
||||||
|
capBrokenErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func errAppend(left, right error) error {
|
||||||
|
if left == nil {
|
||||||
|
return right
|
||||||
|
}
|
||||||
|
if right == nil {
|
||||||
|
return left
|
||||||
|
}
|
||||||
|
return fmt.Errorf("%s, %s", left.Error(), right.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewValidPlugin is the same as NewPlugin(), but returns an error if
|
// NewValidPlugin is the same as NewPlugin(), but returns an error if
|
||||||
|
@ -170,7 +188,10 @@ func NewPlugin(path string) (*Plugin, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get supported capabilities
|
// get supported capabilities
|
||||||
p.caps = C.plugin_get_capabilities(p.handle)
|
p.caps = C.plugin_get_capabilities(p.handle, errBuf)
|
||||||
|
if p.caps&C.CAP_BROKEN != 0 {
|
||||||
|
p.capBrokenErr = errors.New(C.GoString(errBuf))
|
||||||
|
}
|
||||||
|
|
||||||
// read static info (if available)
|
// read static info (if available)
|
||||||
p.info = plugins.Info{
|
p.info = plugins.Info{
|
||||||
|
@ -178,9 +199,9 @@ func NewPlugin(path string) (*Plugin, error) {
|
||||||
RequiredAPIVersion: C.GoString(C.__get_info_str(p.handle.api.get_required_api_version)),
|
RequiredAPIVersion: C.GoString(C.__get_info_str(p.handle.api.get_required_api_version)),
|
||||||
Name: C.GoString(C.__get_info_str(p.handle.api.get_name)),
|
Name: C.GoString(C.__get_info_str(p.handle.api.get_name)),
|
||||||
Description: C.GoString(C.__get_info_str(p.handle.api.get_description)),
|
Description: C.GoString(C.__get_info_str(p.handle.api.get_description)),
|
||||||
EventSource: C.GoString(C.__get_info_str(p.handle.api.anon0.get_event_source)),
|
|
||||||
Contact: C.GoString(C.__get_info_str(p.handle.api.get_contact)),
|
Contact: C.GoString(C.__get_info_str(p.handle.api.get_contact)),
|
||||||
ID: uint32(C.__get_info_u32(p.handle.api.anon0.get_id)),
|
ID: uint32(C.__get_info_u32(p.handle.api.anon0.get_id)),
|
||||||
|
EventSource: C.GoString(C.__get_info_str(p.handle.api.anon0.get_event_source)),
|
||||||
ExtractEventSources: []string{},
|
ExtractEventSources: []string{},
|
||||||
}
|
}
|
||||||
if p.handle.api.get_init_schema != nil {
|
if p.handle.api.get_init_schema != nil {
|
||||||
|
@ -193,19 +214,23 @@ func NewPlugin(path string) (*Plugin, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get static info related to extraction capability (if available)
|
// get static info related to extraction capability (if available)
|
||||||
if p.HasCapExtraction() && p.handle.api.anon1.get_extract_event_sources != nil {
|
if p.HasCapExtraction() {
|
||||||
|
// capability is considered not supported if data is corrupted
|
||||||
|
if p.handle.api.anon1.get_extract_event_sources != nil {
|
||||||
str := C.GoString(C.__get_info_str(p.handle.api.anon1.get_extract_event_sources))
|
str := C.GoString(C.__get_info_str(p.handle.api.anon1.get_extract_event_sources))
|
||||||
if err := json.Unmarshal(([]byte)(str), &p.info.ExtractEventSources); err != nil {
|
if err := json.Unmarshal(([]byte)(str), &p.info.ExtractEventSources); err != nil {
|
||||||
// capability is considered not supported if data is corrupted
|
p.caps &= ^C.CAP_EXTRACTION
|
||||||
p.caps ^= C.CAP_EXTRACTION
|
p.caps |= C.CAP_BROKEN
|
||||||
|
p.capBrokenErr = errAppend(p.capBrokenErr, errors.New("get_extract_event_sources does not return a well-formed json array"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p.HasCapExtraction() {
|
|
||||||
str := C.GoString(C.__get_info_str(p.handle.api.anon1.get_fields))
|
str := C.GoString(C.__get_info_str(p.handle.api.anon1.get_fields))
|
||||||
if err := json.Unmarshal(([]byte)(str), &p.fields); err != nil {
|
if err := json.Unmarshal(([]byte)(str), &p.fields); err != nil {
|
||||||
// capability is considered not supported if data is corrupted
|
p.caps &= ^C.CAP_EXTRACTION
|
||||||
p.caps ^= C.CAP_EXTRACTION
|
p.caps |= C.CAP_BROKEN
|
||||||
|
p.capBrokenErr = errAppend(p.capBrokenErr, errors.New("get_fields does not return a well-formed json array"))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
|
@ -234,9 +259,9 @@ func (p *Plugin) validate() error {
|
||||||
p.validErr = errors.New(C.GoString(errBuf))
|
p.validErr = errors.New(C.GoString(errBuf))
|
||||||
return p.validErr
|
return p.validErr
|
||||||
}
|
}
|
||||||
if p.caps == C.CAP_NONE {
|
if (p.caps & ^C.CAP_BROKEN) == C.CAP_NONE {
|
||||||
p.validErr = errors.New("plugin supports no capability")
|
p.validErr = errors.New("plugin supports no capability")
|
||||||
return p.validErr
|
return errAppend(p.validErr, p.capBrokenErr)
|
||||||
}
|
}
|
||||||
p.validated = true
|
p.validated = true
|
||||||
}
|
}
|
||||||
|
@ -252,6 +277,16 @@ func (p *Plugin) Validate() error {
|
||||||
return p.validate()
|
return p.validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasCapBroken returns true if the plugin has any of its capabilities broken.
|
||||||
|
func (p *Plugin) HasCapBroken() bool {
|
||||||
|
return p.caps&C.CAP_BROKEN != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapBrokenError returns a non-nil error if HasCapBroken returns true.
|
||||||
|
func (p *Plugin) CapBrokenError() error {
|
||||||
|
return p.capBrokenErr
|
||||||
|
}
|
||||||
|
|
||||||
// HasCapExtraction returns true if the plugin supports the
|
// HasCapExtraction returns true if the plugin supports the
|
||||||
// field extraction capability.
|
// field extraction capability.
|
||||||
func (p *Plugin) HasCapExtraction() bool {
|
func (p *Plugin) HasCapExtraction() bool {
|
||||||
|
@ -349,8 +384,14 @@ func (p *Plugin) Init(config string) error {
|
||||||
return fmt.Errorf("invalid plugin config: %s", err.Error())
|
return fmt.Errorf("invalid plugin config: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo(jasondelluce,therealbobo): support owner pointer and implement table access
|
||||||
|
in := C.ss_plugin_init_input{}
|
||||||
|
in.owner = nil
|
||||||
|
in.get_owner_last_error = nil
|
||||||
|
in.tables = nil
|
||||||
|
in.config = C.CString(config)
|
||||||
rc := C.ss_plugin_rc(sdk.SSPluginSuccess)
|
rc := C.ss_plugin_rc(sdk.SSPluginSuccess)
|
||||||
p.state = (*C.ss_plugin_t)(C.__init(&p.handle.api, C.CString(config), (*C.ss_plugin_rc)(&rc)))
|
p.state = (*C.ss_plugin_t)(C.__init(&p.handle.api, &in, (*C.ss_plugin_rc)(&rc)))
|
||||||
if rc == C.ss_plugin_rc(sdk.SSPluginSuccess) {
|
if rc == C.ss_plugin_rc(sdk.SSPluginSuccess) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
diff --git a/pkg/loader/plugin_loader.h b/pkg/loader/plugin_loader.h
|
||||||
|
index e6e8333..8db0d70 100644
|
||||||
|
--- a/pkg/loader/plugin_loader.h
|
||||||
|
+++ b/pkg/loader/plugin_loader.h
|
||||||
|
@@ -18,7 +18,7 @@ limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
-#include <plugin/plugin_api.h>
|
||||||
|
+#include "plugin_api.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -22,21 +23,63 @@ limitations under the License.
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
typedef void* library_handle_t;
|
typedef void* library_handle_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "plugin_loader.h"
|
#include "plugin_loader.h"
|
||||||
|
|
||||||
static inline void add_str_prefix(char* s, const char* prefix)
|
// note(jasondellaluce,therealbobo): implementation taken from falcosecurity/libs
|
||||||
{
|
// note(leogr): to avoid clashing with `strlcpy` introduced by glibc 2.38,
|
||||||
char tmp[PLUGIN_MAX_ERRLEN];
|
// the func has been renamed to plugin_loader_strlcpy.
|
||||||
strncpy(tmp, prefix, PLUGIN_MAX_ERRLEN - 1);
|
// N.B.: our building system here is not smart enough to detect if the function
|
||||||
strncat(tmp, s, PLUGIN_MAX_ERRLEN - 1);
|
// was declared already.
|
||||||
strcpy(s, tmp);
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
/*!
|
||||||
|
\brief Copy up to size - 1 characters from the NUL-terminated string src to dst, NUL-terminating the result.
|
||||||
|
|
||||||
|
\return The length of the source string.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline size_t plugin_loader_strlcpy(char *dst, const char *src, size_t size) {
|
||||||
|
size_t srcsize = strlen(src);
|
||||||
|
if (size == 0) {
|
||||||
|
return srcsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* getsym(library_handle_t handle, const char* name)
|
size_t copysize = srcsize;
|
||||||
{
|
|
||||||
|
if (copysize > size - 1) {
|
||||||
|
copysize = size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dst, src, copysize);
|
||||||
|
dst[copysize] = '\0';
|
||||||
|
|
||||||
|
return srcsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void err_prepend(char* s, const char* prefix, const char* sep) {
|
||||||
|
char tmp[PLUGIN_MAX_ERRLEN];
|
||||||
|
size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
|
||||||
|
if(*s != '\0') {
|
||||||
|
plugin_loader_strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||||
|
prefix_len += strlen(sep);
|
||||||
|
}
|
||||||
|
plugin_loader_strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||||
|
plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void err_append(char* s, const char* suffix, const char* sep) {
|
||||||
|
if(*s != '\0') {
|
||||||
|
strlcat(s, sep, PLUGIN_MAX_ERRLEN);
|
||||||
|
}
|
||||||
|
strlcat(s, suffix, PLUGIN_MAX_ERRLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* getsym(library_handle_t handle, const char* name) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return (void*)GetProcAddress(handle, name);
|
return (void*)GetProcAddress(handle, name);
|
||||||
#else
|
#else
|
||||||
|
@ -45,42 +88,39 @@ static void* getsym(library_handle_t handle, const char* name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// little hack for simplifying the plugin_load function
|
// little hack for simplifying the plugin_load function
|
||||||
#define SYM_RESOLVE(h, s) \
|
#define SYM_RESOLVE(h, s) *(void**)(&(h->api.s)) = getsym(h->handle, "plugin_" #s)
|
||||||
*(void **)(&(h->api.s)) = getsym(h->handle, "plugin_"#s)
|
|
||||||
|
|
||||||
plugin_handle_t* plugin_load(const char* path, char* err)
|
plugin_handle_t* plugin_load(const char* path, char* err) {
|
||||||
{
|
|
||||||
// alloc and init memory
|
// alloc and init memory
|
||||||
strcpy(err, "");
|
err[0] = '\0';
|
||||||
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
|
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
|
||||||
|
if(!ret) {
|
||||||
|
plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// open dynamic library
|
// open dynamic library
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ret->handle = LoadLibrary(path);
|
ret->handle = LoadLibrary(path);
|
||||||
if(ret->handle == NULL)
|
if(ret->handle == NULL) {
|
||||||
{
|
DWORD flg = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
DWORD flg = FORMAT_MESSAGE_ALLOCATE_BUFFER
|
FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||||
| FORMAT_MESSAGE_FROM_SYSTEM
|
|
||||||
| FORMAT_MESSAGE_IGNORE_INSERTS;
|
|
||||||
LPTSTR msg_buf = 0;
|
LPTSTR msg_buf = 0;
|
||||||
if (FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR) &msg_buf, 0, NULL) && msg_buf)
|
if(FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR)&msg_buf, 0, NULL) && msg_buf) {
|
||||||
{
|
plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
|
||||||
strncpy(err, msg_buf, PLUGIN_MAX_ERRLEN -1 );
|
|
||||||
LocalFree(msg_buf);
|
LocalFree(msg_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
ret->handle = dlopen(path, RTLD_LAZY);
|
ret->handle = dlopen(path, RTLD_LAZY);
|
||||||
if (ret->handle == NULL)
|
if(ret->handle == NULL) {
|
||||||
{
|
plugin_loader_strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
|
||||||
strncpy(err, (const char*) dlerror(), PLUGIN_MAX_ERRLEN - 1);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// return NULL if library loading had errors
|
// return NULL if library loading had errors
|
||||||
if (ret->handle == NULL)
|
if(ret->handle == NULL) {
|
||||||
{
|
err_prepend(err, "can't load plugin dynamic library:", " ");
|
||||||
add_str_prefix(err, "can't load plugin dynamic library: ");
|
|
||||||
free(ret);
|
free(ret);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -106,15 +146,70 @@ plugin_handle_t* plugin_load(const char* path, char* err)
|
||||||
SYM_RESOLVE(ret, get_fields);
|
SYM_RESOLVE(ret, get_fields);
|
||||||
SYM_RESOLVE(ret, extract_fields);
|
SYM_RESOLVE(ret, extract_fields);
|
||||||
SYM_RESOLVE(ret, get_extract_event_sources);
|
SYM_RESOLVE(ret, get_extract_event_sources);
|
||||||
|
SYM_RESOLVE(ret, get_extract_event_types);
|
||||||
|
SYM_RESOLVE(ret, get_parse_event_types);
|
||||||
|
SYM_RESOLVE(ret, get_parse_event_sources);
|
||||||
|
SYM_RESOLVE(ret, parse_event);
|
||||||
|
SYM_RESOLVE(ret, get_async_event_sources);
|
||||||
|
SYM_RESOLVE(ret, get_async_events);
|
||||||
|
SYM_RESOLVE(ret, set_async_event_handler);
|
||||||
|
SYM_RESOLVE(ret, dump_state);
|
||||||
|
SYM_RESOLVE(ret, set_config);
|
||||||
|
SYM_RESOLVE(ret, get_metrics);
|
||||||
|
SYM_RESOLVE(ret, capture_open);
|
||||||
|
SYM_RESOLVE(ret, capture_close);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void plugin_unload(plugin_handle_t* h)
|
plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
|
||||||
{
|
// alloc and init memory
|
||||||
if (h)
|
err[0] = '\0';
|
||||||
{
|
if(!api) {
|
||||||
if (h->handle)
|
plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
|
||||||
{
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
|
||||||
|
if(!ret) {
|
||||||
|
plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ret->api = *api;
|
||||||
|
|
||||||
|
// todo: remove this if/when we get to API version 4
|
||||||
|
uint32_t major, minor, patch;
|
||||||
|
const char* ver;
|
||||||
|
if(api->get_required_api_version == NULL) {
|
||||||
|
plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ver = api->get_required_api_version();
|
||||||
|
if(sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3) {
|
||||||
|
snprintf(err,
|
||||||
|
PLUGIN_MAX_ERRLEN,
|
||||||
|
"plugin provided an invalid required API version: '%s'",
|
||||||
|
ver);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API 3.10 introduced dump_state in the middle of the plugin_api struct.
|
||||||
|
// Fix up older 3.x plugins by shifting the fields by one
|
||||||
|
if(major == 3 && minor < 10) {
|
||||||
|
size_t from_offset = offsetof(plugin_api, dump_state);
|
||||||
|
size_t to_offset = offsetof(plugin_api, set_config);
|
||||||
|
size_t size = sizeof(plugin_api) - to_offset;
|
||||||
|
char* api_ptr = (char*)&ret->api;
|
||||||
|
memmove(api_ptr + to_offset, api_ptr + from_offset, size);
|
||||||
|
ret->api.dump_state = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plugin_unload(plugin_handle_t* h) {
|
||||||
|
if(h) {
|
||||||
|
if(h->handle) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
FreeLibrary(h->handle);
|
FreeLibrary(h->handle);
|
||||||
#else
|
#else
|
||||||
|
@ -125,8 +220,7 @@ void plugin_unload(plugin_handle_t* h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool plugin_is_loaded(const char* path)
|
bool plugin_is_loaded(const char* path) {
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/*
|
/*
|
||||||
* LoadLibrary maps the module into the address space of the calling process, if necessary,
|
* LoadLibrary maps the module into the address space of the calling process, if necessary,
|
||||||
|
@ -149,65 +243,103 @@ bool plugin_is_loaded(const char* path)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool plugin_check_required_api_version(const plugin_handle_t* h, char* err)
|
bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) {
|
||||||
{
|
|
||||||
uint32_t major, minor, patch;
|
uint32_t major, minor, patch;
|
||||||
const char *ver, *failmsg;
|
const char *ver, *failmsg;
|
||||||
if (h->api.get_required_api_version == NULL)
|
if(h->api.get_required_api_version == NULL) {
|
||||||
{
|
plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||||
strncpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN - 1);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ver = h->api.get_required_api_version();
|
ver = h->api.get_required_api_version();
|
||||||
if (sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3)
|
if(sscanf(ver, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &patch) != 3) {
|
||||||
{
|
snprintf(err,
|
||||||
snprintf(err, PLUGIN_MAX_ERRLEN, "plugin provided an invalid required API version: '%s'", ver);
|
PLUGIN_MAX_ERRLEN,
|
||||||
|
"plugin provided an invalid required API version: '%s'",
|
||||||
|
ver);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
failmsg = NULL;
|
failmsg = NULL;
|
||||||
if(PLUGIN_API_VERSION_MAJOR != major)
|
/* The plugin requires a minimum framework version */
|
||||||
{
|
if(PLUGIN_API_VERSION_MAJOR != major) {
|
||||||
failmsg = "major versions disagree";
|
failmsg = "major versions disagree";
|
||||||
}
|
} else if(PLUGIN_API_VERSION_MINOR < minor) {
|
||||||
else if(PLUGIN_API_VERSION_MINOR < minor)
|
|
||||||
{
|
|
||||||
failmsg = "framework's minor is less than the requested one";
|
failmsg = "framework's minor is less than the requested one";
|
||||||
}
|
} else if(PLUGIN_API_VERSION_MINOR == minor && PLUGIN_API_VERSION_PATCH < patch) {
|
||||||
else if(PLUGIN_API_VERSION_MINOR == minor && PLUGIN_API_VERSION_PATCH < patch)
|
|
||||||
{
|
|
||||||
failmsg = "framework's patch is less than the requested one";
|
failmsg = "framework's patch is less than the requested one";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (failmsg != NULL)
|
if(failmsg != NULL) {
|
||||||
{
|
snprintf(err,
|
||||||
snprintf(err, PLUGIN_MAX_ERRLEN,
|
PLUGIN_MAX_ERRLEN,
|
||||||
"plugin required API version '%s' not compatible with the framework's API version '%s': %s",
|
"plugin required API version '%s' not compatible with the framework's API version "
|
||||||
ver, PLUGIN_API_VERSION_STR, failmsg);
|
"'%s': %s",
|
||||||
|
ver,
|
||||||
|
PLUGIN_API_VERSION_STR,
|
||||||
|
failmsg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h)
|
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h, char* err) {
|
||||||
{
|
|
||||||
plugin_caps_t caps = CAP_NONE;
|
plugin_caps_t caps = CAP_NONE;
|
||||||
|
plugin_loader_strlcpy(err, "", PLUGIN_MAX_ERRLEN);
|
||||||
|
|
||||||
if (h->api.get_id != NULL
|
if(h->api.open != NULL && h->api.close != NULL && h->api.next_batch != NULL) {
|
||||||
&& h->api.get_event_source != NULL
|
bool has_id = h->api.get_id != NULL && h->api.get_id() != 0;
|
||||||
&& h->api.open != NULL
|
bool has_source = h->api.get_event_source != NULL && strlen(h->api.get_event_source()) > 0;
|
||||||
&& h->api.close != NULL
|
if((has_id && has_source) || (!has_id && !has_source)) {
|
||||||
&& h->api.next_batch != NULL)
|
|
||||||
{
|
|
||||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_SOURCING);
|
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_SOURCING);
|
||||||
|
} else {
|
||||||
|
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
|
||||||
|
err_append(err,
|
||||||
|
"must implement both 'plugin_get_id' and 'plugin_get_event_source' or "
|
||||||
|
"neither (event sourcing)",
|
||||||
|
", ");
|
||||||
|
}
|
||||||
|
} else if(h->api.open != NULL || h->api.close != NULL || h->api.next_batch != NULL) {
|
||||||
|
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
|
||||||
|
err_append(err,
|
||||||
|
"must implement all of 'plugin_open', 'plugin_close', and 'plugin_next_batch' "
|
||||||
|
"(event sourcing)",
|
||||||
|
", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h->api.get_fields != NULL
|
if(h->api.get_fields != NULL && h->api.extract_fields != NULL) {
|
||||||
&& h->api.extract_fields != NULL)
|
|
||||||
{
|
|
||||||
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_EXTRACTION);
|
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_EXTRACTION);
|
||||||
|
} else if(h->api.extract_fields != NULL) {
|
||||||
|
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
|
||||||
|
err_append(err,
|
||||||
|
"must implement both 'plugin_get_fields' and 'plugin_extract_fields' (field "
|
||||||
|
"extraction)",
|
||||||
|
", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(h->api.parse_event != NULL) {
|
||||||
|
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_PARSING);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(h->api.get_async_events != NULL && h->api.set_async_event_handler != NULL) {
|
||||||
|
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_ASYNC);
|
||||||
|
} else if(h->api.set_async_event_handler != NULL) {
|
||||||
|
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
|
||||||
|
err_append(err,
|
||||||
|
"must implement both 'plugin_get_async_events' and "
|
||||||
|
"'plugin_set_async_event_handler' (async events)",
|
||||||
|
", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(h->api.capture_open != NULL && h->api.capture_close != NULL) {
|
||||||
|
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_CAPTURE_LISTENING);
|
||||||
|
} else if(h->api.capture_open != NULL) {
|
||||||
|
caps = (plugin_caps_t)((uint32_t)caps | (uint32_t)CAP_BROKEN);
|
||||||
|
err_append(err,
|
||||||
|
"must implement both 'plugin_capture_open' and 'plugin_capture_close' (capture "
|
||||||
|
"listening)",
|
||||||
|
", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
return caps;
|
return caps;
|
||||||
|
@ -216,15 +348,13 @@ plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h)
|
||||||
// little hack for simplifying the plugin_check_required_symbols function
|
// little hack for simplifying the plugin_check_required_symbols function
|
||||||
#define SYM_REQCHECK(a, e, s) \
|
#define SYM_REQCHECK(a, e, s) \
|
||||||
do { \
|
do { \
|
||||||
if(a->api.s == NULL) \
|
if(a->api.s == NULL) { \
|
||||||
{ \
|
snprintf(e, PLUGIN_MAX_ERRLEN, "required symbol not implemented: '%s'", #s); \
|
||||||
snprintf(e, PLUGIN_MAX_ERRLEN, "symbol not implemented: %s", #s); \
|
|
||||||
return false; \
|
return false; \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
bool plugin_check_required_symbols(const plugin_handle_t* h, char* err)
|
bool plugin_check_required_symbols(const plugin_handle_t* h, char* err) {
|
||||||
{
|
|
||||||
SYM_REQCHECK(h, err, get_required_api_version);
|
SYM_REQCHECK(h, err, get_required_api_version);
|
||||||
SYM_REQCHECK(h, err, get_version);
|
SYM_REQCHECK(h, err, get_version);
|
||||||
SYM_REQCHECK(h, err, get_name);
|
SYM_REQCHECK(h, err, get_name);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -19,16 +20,12 @@ limitations under the License.
|
||||||
|
|
||||||
#include "plugin_api.h"
|
#include "plugin_api.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\brief The maximum length of the error strings written by the plugin loader
|
|
||||||
*/
|
|
||||||
#define PLUGIN_MAX_ERRLEN 2048
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief This enums the capabilities supported by plugins.
|
\brief This enums the capabilities supported by plugins.
|
||||||
Each plugin can support one or more of these, in which case the enum flags
|
Each plugin can support one or more of these, in which case the enum flags
|
||||||
|
@ -36,12 +33,18 @@ extern "C" {
|
||||||
Currently, the supported capabilities are:
|
Currently, the supported capabilities are:
|
||||||
* ability to source events and provide them to the event loop
|
* ability to source events and provide them to the event loop
|
||||||
* ability to extract fields from events created by other plugins
|
* ability to extract fields from events created by other plugins
|
||||||
|
* ability to parse events from the event loop (at most once) before
|
||||||
|
the field extraction phase
|
||||||
|
* ability to inject events asynchronously in the event loop
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum {
|
||||||
{
|
|
||||||
CAP_NONE = 0,
|
CAP_NONE = 0,
|
||||||
CAP_SOURCING = 1 << 0,
|
CAP_SOURCING = 1 << 0,
|
||||||
CAP_EXTRACTION = 1 << 1
|
CAP_EXTRACTION = 1 << 1,
|
||||||
|
CAP_PARSING = 1 << 2,
|
||||||
|
CAP_ASYNC = 1 << 3,
|
||||||
|
CAP_CAPTURE_LISTENING = 1 << 4,
|
||||||
|
CAP_BROKEN = 1 << 31, // used to report inconsistencies
|
||||||
} plugin_caps_t;
|
} plugin_caps_t;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -49,8 +52,7 @@ typedef enum
|
||||||
Pointers to this struct must be obtained through the plugin_load()
|
Pointers to this struct must be obtained through the plugin_load()
|
||||||
and released through plugin_unload().
|
and released through plugin_unload().
|
||||||
*/
|
*/
|
||||||
typedef struct plugin_handle_t
|
typedef struct plugin_handle_t {
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HINSTANCE handle; ///< Handle of the dynamic library
|
HINSTANCE handle; ///< Handle of the dynamic library
|
||||||
#else
|
#else
|
||||||
|
@ -59,6 +61,13 @@ typedef struct plugin_handle_t
|
||||||
plugin_api api; ///< The vtable method of the plugin that define its API
|
plugin_api api; ///< The vtable method of the plugin that define its API
|
||||||
} plugin_handle_t;
|
} plugin_handle_t;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Uses the given plugin api and returns a plugin_handle_t*
|
||||||
|
representing the loaded plugin. In case of error, returns NULL and fills
|
||||||
|
the err string up to PLUGIN_MAX_ERRLEN chars.
|
||||||
|
*/
|
||||||
|
plugin_handle_t* plugin_load_api(const plugin_api* api, char* err);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Loads a dynamic library from the given path and returns a
|
\brief Loads a dynamic library from the given path and returns a
|
||||||
plugin_handle_t* representing the loaded plugin. In case of error,
|
plugin_handle_t* representing the loaded plugin. In case of error,
|
||||||
|
@ -92,9 +101,12 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err);
|
||||||
bool plugin_check_required_symbols(const plugin_handle_t* h, char* err);
|
bool plugin_check_required_symbols(const plugin_handle_t* h, char* err);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Returns the capabilities supported by the given plugin handle
|
\brief Returns the capabilities supported by the given plugin handle.
|
||||||
|
In case of inconsistencies, the result will have the CAP_BROKEN bit set
|
||||||
|
and the err string will be filled up to PLUGIN_MAX_ERRLEN chars representing
|
||||||
|
the error encountered.
|
||||||
*/
|
*/
|
||||||
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h);
|
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h, char* err);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
diff --git a/pkg/loader/plugin_loader.c b/pkg/loader/plugin_loader.c
|
||||||
|
index 2943335..7bebeeb 100644
|
||||||
|
--- a/pkg/loader/plugin_loader.c
|
||||||
|
+++ b/pkg/loader/plugin_loader.c
|
||||||
|
@@ -24,22 +24,52 @@ typedef HINSTANCE library_handle_t;
|
||||||
|
typedef void* library_handle_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-#include <libscap/strl.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
-#include <plugin/plugin_loader.h>
|
||||||
|
+#include "plugin_loader.h"
|
||||||
|
+
|
||||||
|
+// note(jasondellaluce,therealbobo): implementation taken from falcosecurity/libs
|
||||||
|
+// note(leogr): to avoid clashing with `strlcpy` introduced by glibc 2.38,
|
||||||
|
+// the func has been renamed to plugin_loader_strlcpy.
|
||||||
|
+// N.B.: our building system here is not smart enough to detect if the function
|
||||||
|
+// was declared already.
|
||||||
|
+#include <stdint.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+/*!
|
||||||
|
+ \brief Copy up to size - 1 characters from the NUL-terminated string src to dst, NUL-terminating the result.
|
||||||
|
+
|
||||||
|
+ \return The length of the source string.
|
||||||
|
+*/
|
||||||
|
+
|
||||||
|
+static inline size_t plugin_loader_strlcpy(char *dst, const char *src, size_t size) {
|
||||||
|
+ size_t srcsize = strlen(src);
|
||||||
|
+ if (size == 0) {
|
||||||
|
+ return srcsize;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ size_t copysize = srcsize;
|
||||||
|
+
|
||||||
|
+ if (copysize > size - 1) {
|
||||||
|
+ copysize = size - 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ memcpy(dst, src, copysize);
|
||||||
|
+ dst[copysize] = '\0';
|
||||||
|
+
|
||||||
|
+ return srcsize;
|
||||||
|
+}
|
||||||
|
|
||||||
|
static inline void err_prepend(char* s, const char* prefix, const char* sep) {
|
||||||
|
char tmp[PLUGIN_MAX_ERRLEN];
|
||||||
|
- size_t prefix_len = strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
|
||||||
|
+ size_t prefix_len = plugin_loader_strlcpy(tmp, prefix, PLUGIN_MAX_ERRLEN);
|
||||||
|
if(*s != '\0') {
|
||||||
|
- strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||||
|
+ plugin_loader_strlcpy(&tmp[prefix_len], sep, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||||
|
prefix_len += strlen(sep);
|
||||||
|
}
|
||||||
|
- strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||||
|
- strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
|
||||||
|
+ plugin_loader_strlcpy(&tmp[prefix_len], s, PLUGIN_MAX_ERRLEN - prefix_len);
|
||||||
|
+ plugin_loader_strlcpy(s, tmp, PLUGIN_MAX_ERRLEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void err_append(char* s, const char* suffix, const char* sep) {
|
||||||
|
@@ -65,7 +95,7 @@ plugin_handle_t* plugin_load(const char* path, char* err) {
|
||||||
|
err[0] = '\0';
|
||||||
|
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
|
||||||
|
if(!ret) {
|
||||||
|
- strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||||
|
+ plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -77,14 +107,14 @@ plugin_handle_t* plugin_load(const char* path, char* err) {
|
||||||
|
FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||||
|
LPTSTR msg_buf = 0;
|
||||||
|
if(FormatMessageA(flg, 0, GetLastError(), 0, (LPTSTR)&msg_buf, 0, NULL) && msg_buf) {
|
||||||
|
- strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
|
||||||
|
+ plugin_loader_strlcpy(err, msg_buf, PLUGIN_MAX_ERRLEN);
|
||||||
|
LocalFree(msg_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ret->handle = dlopen(path, RTLD_LAZY);
|
||||||
|
if(ret->handle == NULL) {
|
||||||
|
- strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
|
||||||
|
+ plugin_loader_strlcpy(err, (const char*)dlerror(), PLUGIN_MAX_ERRLEN);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -135,13 +165,13 @@ plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
|
||||||
|
// alloc and init memory
|
||||||
|
err[0] = '\0';
|
||||||
|
if(!api) {
|
||||||
|
- strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
|
||||||
|
+ plugin_loader_strlcpy(err, "can't allocate plugin handle with invalid API table", PLUGIN_MAX_ERRLEN);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin_handle_t* ret = (plugin_handle_t*)calloc(1, sizeof(plugin_handle_t));
|
||||||
|
if(!ret) {
|
||||||
|
- strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||||
|
+ plugin_loader_strlcpy(err, "error allocating plugin handle", PLUGIN_MAX_ERRLEN);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ret->api = *api;
|
||||||
|
@@ -150,7 +180,7 @@ plugin_handle_t* plugin_load_api(const plugin_api* api, char* err) {
|
||||||
|
uint32_t major, minor, patch;
|
||||||
|
const char* ver;
|
||||||
|
if(api->get_required_api_version == NULL) {
|
||||||
|
- strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||||
|
+ plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -217,7 +247,7 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) {
|
||||||
|
uint32_t major, minor, patch;
|
||||||
|
const char *ver, *failmsg;
|
||||||
|
if(h->api.get_required_api_version == NULL) {
|
||||||
|
- strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||||
|
+ plugin_loader_strlcpy(err, "plugin_get_required_api_version symbol not implemented", PLUGIN_MAX_ERRLEN);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -256,7 +286,7 @@ bool plugin_check_required_api_version(const plugin_handle_t* h, char* err) {
|
||||||
|
|
||||||
|
plugin_caps_t plugin_get_capabilities(const plugin_handle_t* h, char* err) {
|
||||||
|
plugin_caps_t caps = CAP_NONE;
|
||||||
|
- strlcpy(err, "", PLUGIN_MAX_ERRLEN);
|
||||||
|
+ plugin_loader_strlcpy(err, "", PLUGIN_MAX_ERRLEN);
|
||||||
|
|
||||||
|
if(h->api.open != NULL && h->api.close != NULL && h->api.next_batch != NULL) {
|
||||||
|
bool has_id = h->api.get_id != NULL && h->api.get_id() != 0;
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2025 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -29,6 +30,20 @@ import (
|
||||||
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
|
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// pluginEventCode is the event code for the PPME_PLUGINEVENT_E scap event.
|
||||||
|
// todo(jasondellaluce): pull this information from falcosecurity/libs in the future
|
||||||
|
const pluginEventCode = 322
|
||||||
|
|
||||||
|
// todo(leogr): replace this with PLUGIN_EVENT_PAYLOAD_OFFSET from "plugin_api.h"
|
||||||
|
|
||||||
|
// PluginEventPayloadOffset is the size of a scap event header, plus the
|
||||||
|
// params lenght and the plugin ID integers of a PPME_PLUGINEVENT_E event.
|
||||||
|
// In other words, this is the size of a plugin event with an empty data payload.
|
||||||
|
//
|
||||||
|
// 26 bytes for the event header, plus 2*4 bytes for the parameter lengths,
|
||||||
|
// plus 4 bytes for the plugin ID.
|
||||||
|
const PluginEventPayloadOffset = C.sizeof_ss_plugin_event + 4 + 4 + 4
|
||||||
|
|
||||||
// EventWriter can be used to represent events produced by a plugin.
|
// EventWriter can be used to represent events produced by a plugin.
|
||||||
// This interface is meant to be used in the next/next_batch.
|
// This interface is meant to be used in the next/next_batch.
|
||||||
//
|
//
|
||||||
|
@ -114,6 +129,7 @@ type EventWriters interface {
|
||||||
|
|
||||||
type eventWriters struct {
|
type eventWriters struct {
|
||||||
evts []*eventWriter
|
evts []*eventWriter
|
||||||
|
evtPtrs **C.ss_plugin_event
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEventWriters creates a new instance of sdk.EventWriters.
|
// NewEventWriters creates a new instance of sdk.EventWriters.
|
||||||
|
@ -130,15 +146,15 @@ func NewEventWriters(size, dataSize int64) (EventWriters, error) {
|
||||||
|
|
||||||
ret := &eventWriters{
|
ret := &eventWriters{
|
||||||
evts: make([]*eventWriter, size),
|
evts: make([]*eventWriter, size),
|
||||||
|
evtPtrs: (**C.ss_plugin_event)(C.malloc((C.size_t)(size * C.sizeof_uintptr_t))),
|
||||||
}
|
}
|
||||||
pluginEvtArray := (*C.ss_plugin_event)(C.malloc((C.size_t)(size * C.sizeof_ss_plugin_event)))
|
|
||||||
var err error
|
var err error
|
||||||
for i := range ret.evts {
|
for i := range ret.evts {
|
||||||
// get i-th element of pluginEvtArray
|
if ret.evts[i], err = newEventWriter(dataSize); err != nil {
|
||||||
evtPtr := unsafe.Pointer(uintptr(unsafe.Pointer(pluginEvtArray)) + uintptr(i*C.sizeof_ss_plugin_event))
|
|
||||||
if ret.evts[i], err = newEventWriter(evtPtr, dataSize); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
*(**C.ss_plugin_event)(unsafe.Pointer(uintptr(unsafe.Pointer(ret.evtPtrs)) + uintptr(i*C.sizeof_uintptr_t))) = ret.evts[i].ssPluginEvt
|
||||||
}
|
}
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
@ -159,37 +175,52 @@ func (p *eventWriters) Free() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *eventWriters) ArrayPtr() unsafe.Pointer {
|
func (p *eventWriters) ArrayPtr() unsafe.Pointer {
|
||||||
return p.evts[0].ssPluginEvt
|
return unsafe.Pointer(p.evtPtrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
type eventWriter struct {
|
type eventWriter struct {
|
||||||
data ptr.BytesReadWriter
|
data ptr.BytesReadWriter
|
||||||
dataSize int64
|
dataSize int64
|
||||||
ssPluginEvt unsafe.Pointer
|
ssPluginEvt *C.ss_plugin_event
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEventWriter(evtPtr unsafe.Pointer, dataSize int64) (*eventWriter, error) {
|
func newEventWriter(dataSize int64) (*eventWriter, error) {
|
||||||
evt := (*C.ss_plugin_event)(evtPtr)
|
evt := (*C.ss_plugin_event)(C.calloc(1, C.size_t(dataSize+PluginEventPayloadOffset)))
|
||||||
|
evt._type = pluginEventCode
|
||||||
evt.ts = C.uint64_t(C.UINT64_MAX)
|
evt.ts = C.uint64_t(C.UINT64_MAX)
|
||||||
evt.data = (*C.uint8_t)(C.malloc(C.size_t(dataSize)))
|
evt.tid = C.uint64_t(C.UINT64_MAX)
|
||||||
evt.datalen = 0
|
evt.len = (C.uint32_t)(PluginEventPayloadOffset)
|
||||||
brw, err := ptr.NewBytesReadWriter(unsafe.Pointer(evt.data), int64(dataSize), int64(dataSize))
|
// note(jasondellaluce): CGO fails to properly encode nparams for *reasons*,
|
||||||
|
// so we're forced to write their value manually with an offset
|
||||||
|
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + 22)) = 2
|
||||||
|
// plugin ID size (4 bytes)
|
||||||
|
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + C.sizeof_ss_plugin_event + 0)) = 4
|
||||||
|
// data payload size (0 bytes for now)
|
||||||
|
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + C.sizeof_ss_plugin_event + 4)) = 0
|
||||||
|
// plugin ID value (note: putting zero makes the framework set it automatically)
|
||||||
|
*(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(evt)) + C.sizeof_ss_plugin_event + 8)) = 0
|
||||||
|
// create a read/writer for the data payload
|
||||||
|
brw, err := ptr.NewBytesReadWriter(unsafe.Pointer(uintptr(unsafe.Pointer(evt))+PluginEventPayloadOffset), int64(dataSize), int64(dataSize))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &eventWriter{
|
return &eventWriter{
|
||||||
ssPluginEvt: evtPtr,
|
ssPluginEvt: evt,
|
||||||
data: brw,
|
data: brw,
|
||||||
dataSize: dataSize,
|
dataSize: dataSize,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *eventWriter) dataLenPtr() *C.uint32_t {
|
||||||
|
return (*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(p.ssPluginEvt)) + C.sizeof_ss_plugin_event + 4))
|
||||||
|
}
|
||||||
|
|
||||||
func (p *eventWriter) Writer() io.Writer {
|
func (p *eventWriter) Writer() io.Writer {
|
||||||
p.data.SetLen(p.dataSize)
|
p.data.SetLen(p.dataSize)
|
||||||
p.data.Seek(0, io.SeekStart)
|
p.data.Seek(0, io.SeekStart)
|
||||||
(*C.ss_plugin_event)(p.ssPluginEvt).datalen = 0
|
p.ssPluginEvt.len = (C.uint32_t)(PluginEventPayloadOffset)
|
||||||
|
*p.dataLenPtr() = 0
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +229,8 @@ func (p *eventWriter) Write(data []byte) (n int, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
(*C.ss_plugin_event)(p.ssPluginEvt).datalen += C.uint32_t(n)
|
p.ssPluginEvt.len += C.uint32_t(n)
|
||||||
|
*p.dataLenPtr() += C.uint32_t(n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,26 +239,30 @@ func (p *eventWriter) SetTimestamp(value uint64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *eventWriter) free() {
|
func (p *eventWriter) free() {
|
||||||
C.free(unsafe.Pointer((*C.ss_plugin_event)(p.ssPluginEvt).data))
|
C.free(unsafe.Pointer(p.ssPluginEvt))
|
||||||
p.data = nil
|
p.data = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type eventReader C.ss_plugin_event
|
type eventReader C.ss_plugin_event_input
|
||||||
|
|
||||||
// NewEventReader wraps a pointer to a ss_plugin_event C structure to create
|
// NewEventReader wraps a pointer to a ss_plugin_event_input C structure to create
|
||||||
// a new instance of EventReader. It's not possible to check that the pointer is valid.
|
// a new instance of EventReader. It's not possible to check that the pointer is valid.
|
||||||
// Passing an invalid pointer may cause undefined behavior.
|
// Passing an invalid pointer may cause undefined behavior.
|
||||||
func NewEventReader(ssPluginEvt unsafe.Pointer) EventReader {
|
func NewEventReader(ssPluginEvtInput unsafe.Pointer) EventReader {
|
||||||
return (*eventReader)(ssPluginEvt)
|
return (*eventReader)(ssPluginEvtInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *eventReader) Reader() io.ReadSeeker {
|
func (e *eventReader) Reader() io.ReadSeeker {
|
||||||
brw, _ := ptr.NewBytesReadWriter(unsafe.Pointer(e.data), int64(e.datalen), int64(e.datalen))
|
if e.evt._type != pluginEventCode {
|
||||||
|
panic(fmt.Sprintf("plugin-sdk-go/sdk: reveived extraction request for non-plugin event (code=%d)", e.evt._type))
|
||||||
|
}
|
||||||
|
datalen := *(*C.uint32_t)(unsafe.Pointer(uintptr(unsafe.Pointer(e.evt)) + C.sizeof_ss_plugin_event + 4))
|
||||||
|
brw, _ := ptr.NewBytesReadWriter(unsafe.Pointer(uintptr(unsafe.Pointer(e.evt))+PluginEventPayloadOffset), int64(datalen), int64(datalen))
|
||||||
return brw
|
return brw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *eventReader) Timestamp() uint64 {
|
func (e *eventReader) Timestamp() uint64 {
|
||||||
return uint64(e.ts)
|
return uint64(e.evt.ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *eventReader) EventNum() uint64 {
|
func (e *eventReader) EventNum() uint64 {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2025 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -28,11 +29,17 @@ package sdk
|
||||||
typedef union {
|
typedef union {
|
||||||
const char* str;
|
const char* str;
|
||||||
uint64_t u64;
|
uint64_t u64;
|
||||||
|
uint32_t u32;
|
||||||
|
ss_plugin_bool boolean;
|
||||||
|
ss_plugin_byte_buffer buf;
|
||||||
} field_result_t;
|
} field_result_t;
|
||||||
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
|
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
|
||||||
|
@ -53,8 +60,14 @@ type ExtractRequest interface {
|
||||||
FieldID() uint64
|
FieldID() uint64
|
||||||
//
|
//
|
||||||
// FieldType returns the type of the field for which the value extraction
|
// FieldType returns the type of the field for which the value extraction
|
||||||
// is requested. For now, only sdk.FieldTypeUint64 and
|
// is requested. For now, the supported types are:
|
||||||
// sdk.FieldTypeCharBuf are supported.
|
// - sdk.FieldTypeBool
|
||||||
|
// - sdk.FieldTypeUint64
|
||||||
|
// - sdk.FieldTypeCharBuf
|
||||||
|
// - sdk.FieldTypeRelTime
|
||||||
|
// - sdk.FieldTypeAbsTime
|
||||||
|
// - sdk.FieldTypeIPAddr
|
||||||
|
// - sdk.FieldTypeIPNet
|
||||||
FieldType() uint32
|
FieldType() uint32
|
||||||
//
|
//
|
||||||
// Field returns the name of the field for which the value extraction
|
// Field returns the name of the field for which the value extraction
|
||||||
|
@ -80,11 +93,39 @@ type ExtractRequest interface {
|
||||||
// The underlying type of v must be compatible with the field type
|
// The underlying type of v must be compatible with the field type
|
||||||
// associated to this extract request (as the returned by FieldType()),
|
// associated to this extract request (as the returned by FieldType()),
|
||||||
// otherwise SetValue will panic.
|
// otherwise SetValue will panic.
|
||||||
|
//
|
||||||
|
// Coherently to the FieldType of the extraction request, this function
|
||||||
|
// panics if the passed value is not one of the following types (or slices
|
||||||
|
// of them, in case IsList() returns true):
|
||||||
|
// - sdk.FieldTypeBool: bool
|
||||||
|
// - sdk.FieldTypeUint64: uint64
|
||||||
|
// - sdk.FieldTypeCharBuf: string
|
||||||
|
// - sdk.FieldTypeRelTime: time.Duration, *time.Duration
|
||||||
|
// - sdk.FieldTypeAbsTime: time.Time, *time.Time
|
||||||
|
// - sdk.FieldTypeIPAddr: net.IP, *net.IP
|
||||||
|
// - sdk.FieldTypeIPNet: net.IPNet, *net.IPNet
|
||||||
SetValue(v interface{})
|
SetValue(v interface{})
|
||||||
//
|
//
|
||||||
|
// TODO SetValueOffsets sets the start offset and length of one or
|
||||||
|
// more fields. The start offset for each field must be from the
|
||||||
|
// beginning of the event to the start of the field data.
|
||||||
|
// sdk.PluginEventPayloadOffset should be used to get the event
|
||||||
|
// header size. {0,0} can be used to indicate that the field doesn't
|
||||||
|
// correspond to any bytes in the event or log data.
|
||||||
|
SetValueOffset(start, length uint32)
|
||||||
|
//
|
||||||
// SetPtr sets a pointer to a ss_plugin_extract_field C structure to
|
// SetPtr sets a pointer to a ss_plugin_extract_field C structure to
|
||||||
// be wrapped in this instance of ExtractRequest.
|
// be wrapped in this instance of ExtractRequest.
|
||||||
SetPtr(unsafe.Pointer)
|
SetPtr(unsafe.Pointer)
|
||||||
|
//
|
||||||
|
// SetOffsetPtrs sets the pointers to the memory locations that will
|
||||||
|
// hold the values set by SetValueOffset.
|
||||||
|
SetOffsetPtrs(startPtr, lengthPtr unsafe.Pointer)
|
||||||
|
//
|
||||||
|
// WantOffset returns true if the caller is requesting the offset
|
||||||
|
// for the current field.
|
||||||
|
//
|
||||||
|
WantOffset() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractRequestPool represents a pool of reusable ExtractRequest objects.
|
// ExtractRequestPool represents a pool of reusable ExtractRequest objects.
|
||||||
|
@ -95,6 +136,18 @@ type ExtractRequestPool interface {
|
||||||
// position inside the pool. Indexes can be non-contiguous.
|
// position inside the pool. Indexes can be non-contiguous.
|
||||||
Get(requestIndex int) ExtractRequest
|
Get(requestIndex int) ExtractRequest
|
||||||
//
|
//
|
||||||
|
// MakeOffsetArrayPtrs allocates and initializes the start offset and length arrays,
|
||||||
|
// then assigns their pointers to the provided ss_plugin_extract_value_offsets structure.
|
||||||
|
// These arrays track field boundaries for extracted values.
|
||||||
|
//
|
||||||
|
// This function must be called before using any ExtractRequest returned by Get,
|
||||||
|
// as the arrays are uninitialized until this point.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// - extractValueOffsets: pointer to ss_plugin_extract_value_offsets structure to populate
|
||||||
|
// - cap: required capacity for the offset arrays
|
||||||
|
MakeOffsetArrayPtrs(extractValueOffsets unsafe.Pointer, cap uint32)
|
||||||
|
//
|
||||||
// Free deallocates any memory used by the pool that can't be disposed
|
// Free deallocates any memory used by the pool that can't be disposed
|
||||||
// through garbage collection. The behavior of Free after the first call
|
// through garbage collection. The behavior of Free after the first call
|
||||||
// is undefined.
|
// is undefined.
|
||||||
|
@ -103,6 +156,8 @@ type ExtractRequestPool interface {
|
||||||
|
|
||||||
type extractRequestPool struct {
|
type extractRequestPool struct {
|
||||||
reqs map[uint]*extractRequest
|
reqs map[uint]*extractRequest
|
||||||
|
startArrayPtr, lengthArrayPtr unsafe.Pointer
|
||||||
|
arrayPtrCap uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *extractRequestPool) Get(requestIndex int) ExtractRequest {
|
func (e *extractRequestPool) Get(requestIndex int) ExtractRequest {
|
||||||
|
@ -112,12 +167,42 @@ func (e *extractRequestPool) Get(requestIndex int) ExtractRequest {
|
||||||
resBuf: (*C.field_result_t)(C.malloc((C.size_t)(minResultBufferLen * C.sizeof_field_result_t))),
|
resBuf: (*C.field_result_t)(C.malloc((C.size_t)(minResultBufferLen * C.sizeof_field_result_t))),
|
||||||
resBufLen: minResultBufferLen,
|
resBufLen: minResultBufferLen,
|
||||||
resStrBufs: []StringBuffer{&ptr.StringBuffer{}},
|
resStrBufs: []StringBuffer{&ptr.StringBuffer{}},
|
||||||
|
resValPtrs: make([]unsafe.Pointer, minResultBufferLen),
|
||||||
|
}
|
||||||
|
for i := 0; i < minResultBufferLen; i++ {
|
||||||
|
ptr := (*C.field_result_t)(unsafe.Pointer(uintptr(unsafe.Pointer(r.resBuf)) + uintptr(i*C.sizeof_field_result_t)))
|
||||||
|
r.resValPtrs[i] = unsafe.Pointer(ptr)
|
||||||
}
|
}
|
||||||
e.reqs[uint(requestIndex)] = r
|
e.reqs[uint(requestIndex)] = r
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *extractRequestPool) MakeOffsetArrayPtrs(extractValueOffsets unsafe.Pointer, cap uint32) {
|
||||||
|
// If we need more capacity, free old arrays and allocate new ones
|
||||||
|
if cap > e.arrayPtrCap {
|
||||||
|
// Free existing arrays if they exist
|
||||||
|
if e.arrayPtrCap > 0 {
|
||||||
|
C.free(e.startArrayPtr)
|
||||||
|
C.free(e.lengthArrayPtr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate new arrays with required capacity - calloc zeros the memory
|
||||||
|
e.startArrayPtr = unsafe.Pointer(C.calloc(C.size_t(cap), C.sizeof_uint32_t))
|
||||||
|
e.lengthArrayPtr = unsafe.Pointer(C.calloc(C.size_t(cap), C.sizeof_uint32_t))
|
||||||
|
|
||||||
|
e.arrayPtrCap = cap
|
||||||
|
} else {
|
||||||
|
// Capacity is sufficient, just zero the arrays for fresh extraction request
|
||||||
|
size := C.size_t(cap) * C.sizeof_uint32_t
|
||||||
|
C.memset(e.startArrayPtr, 0, size)
|
||||||
|
C.memset(e.lengthArrayPtr, 0, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
(*C.ss_plugin_extract_value_offsets)(extractValueOffsets).start = (*C.uint32_t)(e.startArrayPtr)
|
||||||
|
(*C.ss_plugin_extract_value_offsets)(extractValueOffsets).length = (*C.uint32_t)(e.lengthArrayPtr)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *extractRequestPool) Free() {
|
func (e *extractRequestPool) Free() {
|
||||||
for _, v := range e.reqs {
|
for _, v := range e.reqs {
|
||||||
for _, b := range v.resStrBufs {
|
for _, b := range v.resStrBufs {
|
||||||
|
@ -125,6 +210,10 @@ func (e *extractRequestPool) Free() {
|
||||||
}
|
}
|
||||||
C.free(unsafe.Pointer(v.resBuf))
|
C.free(unsafe.Pointer(v.resBuf))
|
||||||
}
|
}
|
||||||
|
if e.arrayPtrCap > 0 {
|
||||||
|
C.free(e.startArrayPtr)
|
||||||
|
C.free(e.lengthArrayPtr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewExtractRequestPool returns a new empty ExtractRequestPool.
|
// NewExtractRequestPool returns a new empty ExtractRequestPool.
|
||||||
|
@ -137,18 +226,31 @@ func NewExtractRequestPool() ExtractRequestPool {
|
||||||
|
|
||||||
type extractRequest struct {
|
type extractRequest struct {
|
||||||
req *C.ss_plugin_extract_field
|
req *C.ss_plugin_extract_field
|
||||||
|
// Pointer to the field's offset
|
||||||
|
resOffsetStart *C.uint32_t
|
||||||
|
// Pointer to the field's length
|
||||||
|
resOffsetLength *C.uint32_t
|
||||||
// Pointer to a C-allocated array of field_result_t
|
// Pointer to a C-allocated array of field_result_t
|
||||||
resBuf *C.field_result_t
|
resBuf *C.field_result_t
|
||||||
// Length of the array pointed by resBuf
|
// Length of the array pointed by resBuf
|
||||||
resBufLen uint32
|
resBufLen uint32
|
||||||
// List of StringBuffer to return string results
|
// List of StringBuffer to return string results
|
||||||
resStrBufs []StringBuffer
|
resStrBufs []StringBuffer
|
||||||
|
// List of BytesReadWriter to return binary results
|
||||||
|
resBinBufs []ptr.BytesReadWriter
|
||||||
|
// List of *field_result_t to be filled with the values of a request
|
||||||
|
resValPtrs []unsafe.Pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *extractRequest) SetPtr(pef unsafe.Pointer) {
|
func (e *extractRequest) SetPtr(pef unsafe.Pointer) {
|
||||||
e.req = (*C.ss_plugin_extract_field)(pef)
|
e.req = (*C.ss_plugin_extract_field)(pef)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *extractRequest) SetOffsetPtrs(startPtr, lengthPtr unsafe.Pointer) {
|
||||||
|
e.resOffsetStart = (*C.uint32_t)(startPtr)
|
||||||
|
e.resOffsetLength = (*C.uint32_t)(lengthPtr)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *extractRequest) FieldID() uint64 {
|
func (e *extractRequest) FieldID() uint64 {
|
||||||
return uint64(e.req.field_id)
|
return uint64(e.req.field_id)
|
||||||
}
|
}
|
||||||
|
@ -170,52 +272,175 @@ func (e *extractRequest) ArgIndex() uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *extractRequest) ArgPresent() bool {
|
func (e *extractRequest) ArgPresent() bool {
|
||||||
return bool(e.req.arg_present)
|
return e.req.arg_present != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *extractRequest) IsList() bool {
|
func (e *extractRequest) IsList() bool {
|
||||||
return bool(e.req.flist)
|
return e.req.flist != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *extractRequest) boolToU32(v bool) uint32 {
|
||||||
|
if v {
|
||||||
|
return uint32(1)
|
||||||
|
}
|
||||||
|
return uint32(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *extractRequest) resizeResValPtrs(length, dataSize int) []unsafe.Pointer {
|
||||||
|
if e.resBufLen < uint32(length) {
|
||||||
|
C.free(unsafe.Pointer(e.resBuf))
|
||||||
|
e.resBufLen = uint32(length)
|
||||||
|
e.resBuf = (*C.field_result_t)(C.malloc((C.size_t)(e.resBufLen * C.sizeof_field_result_t)))
|
||||||
|
e.resValPtrs = make([]unsafe.Pointer, length)
|
||||||
|
}
|
||||||
|
// we need to recompute the pointers everytime, because
|
||||||
|
// the same extractRequest can be reused with different dataSizes.
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
e.resValPtrs[i] = unsafe.Pointer(uintptr(unsafe.Pointer(e.resBuf)) + uintptr(i*dataSize))
|
||||||
|
}
|
||||||
|
e.req.res_len = (C.uint64_t)(length)
|
||||||
|
return e.resValPtrs[:length]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *extractRequest) SetValue(v interface{}) {
|
func (e *extractRequest) SetValue(v interface{}) {
|
||||||
switch e.FieldType() {
|
switch e.FieldType() {
|
||||||
case FieldTypeUint64:
|
case FieldTypeBool:
|
||||||
if e.req.flist {
|
if e.IsList() {
|
||||||
if e.resBufLen < uint32(len(v.([]uint64))) {
|
for i, ptr := range e.resizeResValPtrs(len(v.([]bool)), C.sizeof_uint32_t) {
|
||||||
C.free(unsafe.Pointer(e.resBuf))
|
*((*C.uint32_t)(ptr)) = (C.uint32_t)(e.boolToU32((v.([]bool))[i]))
|
||||||
e.resBufLen = uint32(len(v.([]uint64)))
|
|
||||||
e.resBuf = (*C.field_result_t)(C.malloc((C.size_t)(e.resBufLen * C.sizeof_field_result_t)))
|
|
||||||
}
|
}
|
||||||
for i, val := range v.([]uint64) {
|
|
||||||
*((*C.uint64_t)(unsafe.Pointer(uintptr(unsafe.Pointer(e.resBuf)) + uintptr(i*C.sizeof_field_result_t)))) = (C.uint64_t)(val)
|
|
||||||
}
|
|
||||||
e.req.res_len = (C.uint64_t)(len(v.([]uint64)))
|
|
||||||
} else {
|
} else {
|
||||||
*((*C.uint64_t)(unsafe.Pointer(e.resBuf))) = (C.uint64_t)(v.(uint64))
|
ptr := e.resizeResValPtrs(1, C.sizeof_uint32_t)[0]
|
||||||
e.req.res_len = (C.uint64_t)(1)
|
*((*C.uint32_t)(ptr)) = (C.uint32_t)(e.boolToU32(v.(bool)))
|
||||||
|
}
|
||||||
|
case FieldTypeUint64:
|
||||||
|
if e.IsList() {
|
||||||
|
for i, ptr := range e.resizeResValPtrs(len(v.([]uint64)), C.sizeof_uint64_t) {
|
||||||
|
*((*C.uint64_t)(ptr)) = (C.uint64_t)((v.([]uint64))[i])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ptr := e.resizeResValPtrs(1, C.sizeof_uint64_t)[0]
|
||||||
|
*((*C.uint64_t)(ptr)) = (C.uint64_t)(v.(uint64))
|
||||||
}
|
}
|
||||||
case FieldTypeCharBuf:
|
case FieldTypeCharBuf:
|
||||||
if e.req.flist {
|
if e.IsList() {
|
||||||
if e.resBufLen < uint32(len(v.([]string))) {
|
for i, out := range e.resizeResValPtrs(len(v.([]string)), C.sizeof_uintptr_t) {
|
||||||
C.free(unsafe.Pointer(e.resBuf))
|
|
||||||
e.resBufLen = uint32(len(v.([]string)))
|
|
||||||
e.resBuf = (*C.field_result_t)(C.malloc((C.size_t)(e.resBufLen * C.sizeof_field_result_t)))
|
|
||||||
}
|
|
||||||
for i, val := range v.([]string) {
|
|
||||||
if len(e.resStrBufs) <= i {
|
if len(e.resStrBufs) <= i {
|
||||||
e.resStrBufs = append(e.resStrBufs, &ptr.StringBuffer{})
|
e.resStrBufs = append(e.resStrBufs, &ptr.StringBuffer{})
|
||||||
}
|
}
|
||||||
e.resStrBufs[i].Write(val)
|
e.resStrBufs[i].Write(v.([]string)[i])
|
||||||
*((**C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(e.resBuf)) + uintptr(i*C.sizeof_field_result_t)))) = (*C.char)(e.resStrBufs[i].CharPtr())
|
*((**C.char)(out)) = (*C.char)(e.resStrBufs[i].CharPtr())
|
||||||
}
|
}
|
||||||
e.req.res_len = (C.uint64_t)(len(v.([]string)))
|
|
||||||
} else {
|
} else {
|
||||||
|
out := e.resizeResValPtrs(1, C.sizeof_uintptr_t)[0]
|
||||||
e.resStrBufs[0].Write(v.(string))
|
e.resStrBufs[0].Write(v.(string))
|
||||||
*((**C.char)(unsafe.Pointer(e.resBuf))) = (*C.char)(e.resStrBufs[0].CharPtr())
|
*((**C.char)(out)) = (*C.char)(e.resStrBufs[0].CharPtr())
|
||||||
e.req.res_len = (C.uint64_t)(1)
|
}
|
||||||
|
case FieldTypeRelTime:
|
||||||
|
if e.IsList() {
|
||||||
|
if val, ok := v.([]time.Duration); ok {
|
||||||
|
for i, ptr := range e.resizeResValPtrs(len(val), C.sizeof_uint64_t) {
|
||||||
|
*((*C.uint64_t)(ptr)) = (C.uint64_t)(val[i].Nanoseconds())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i, ptr := range e.resizeResValPtrs(len(v.([]*time.Duration)), C.sizeof_uint64_t) {
|
||||||
|
*((*C.uint64_t)(ptr)) = (C.uint64_t)(v.([]*time.Duration)[i].Nanoseconds())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ptr := e.resizeResValPtrs(1, C.sizeof_uint64_t)[0]
|
||||||
|
if val, ok := v.(time.Duration); ok {
|
||||||
|
*((*C.uint64_t)(ptr)) = (C.uint64_t)(val.Nanoseconds())
|
||||||
|
} else {
|
||||||
|
*((*C.uint64_t)(ptr)) = (C.uint64_t)(v.(*time.Duration).Nanoseconds())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case FieldTypeAbsTime:
|
||||||
|
if e.IsList() {
|
||||||
|
if val, ok := v.([]time.Time); ok {
|
||||||
|
for i, ptr := range e.resizeResValPtrs(len(val), C.sizeof_uint64_t) {
|
||||||
|
*((*C.uint64_t)(ptr)) = (C.uint64_t)(val[i].UnixNano())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i, ptr := range e.resizeResValPtrs(len(v.([]*time.Time)), C.sizeof_uint64_t) {
|
||||||
|
*((*C.uint64_t)(ptr)) = (C.uint64_t)(v.([]*time.Time)[i].UnixNano())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ptr := e.resizeResValPtrs(1, C.sizeof_uint64_t)[0]
|
||||||
|
if val, ok := v.(time.Time); ok {
|
||||||
|
*((*C.uint64_t)(ptr)) = (C.uint64_t)(val.UnixNano())
|
||||||
|
} else {
|
||||||
|
*((*C.uint64_t)(ptr)) = (C.uint64_t)(v.(*time.Time).UnixNano())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case FieldTypeIPAddr:
|
||||||
|
if e.IsList() {
|
||||||
|
if val, ok := v.([]net.IP); ok {
|
||||||
|
for i, ptr := range e.resizeResValPtrs(len(val), C.sizeof_struct_ss_plugin_byte_buffer) {
|
||||||
|
val := ([]byte)((val)[i])
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i, ptr := range e.resizeResValPtrs(len(v.([]*net.IP)), C.sizeof_struct_ss_plugin_byte_buffer) {
|
||||||
|
val := ([]byte)(*(v.([]*net.IP))[i])
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var val []byte
|
||||||
|
ptr := e.resizeResValPtrs(1, C.sizeof_struct_ss_plugin_byte_buffer)[0]
|
||||||
|
if ipv, ok := v.(net.IP); ok {
|
||||||
|
val = ([]byte)(ipv)
|
||||||
|
} else {
|
||||||
|
val = ([]byte)(*(v.(*net.IP)))
|
||||||
|
}
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
|
||||||
|
}
|
||||||
|
case FieldTypeIPNet:
|
||||||
|
if e.IsList() {
|
||||||
|
if ipv, ok := v.([]net.IPNet); ok {
|
||||||
|
for i, ptr := range e.resizeResValPtrs(len(ipv), C.sizeof_struct_ss_plugin_byte_buffer) {
|
||||||
|
val := ([]byte)((ipv)[i].IP)
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i, ptr := range e.resizeResValPtrs(len(v.([]*net.IPNet)), C.sizeof_struct_ss_plugin_byte_buffer) {
|
||||||
|
val := ([]byte)((v.([]*net.IPNet))[i].IP)
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var val []byte
|
||||||
|
ptr := e.resizeResValPtrs(1, C.sizeof_struct_ss_plugin_byte_buffer)[0]
|
||||||
|
if ipv, ok := v.(net.IPNet); ok {
|
||||||
|
val = ([]byte)(ipv.IP)
|
||||||
|
} else {
|
||||||
|
val = ([]byte)(v.(*net.IPNet).IP)
|
||||||
|
}
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).len = C.uint32_t(len(val))
|
||||||
|
(*C.struct_ss_plugin_byte_buffer)(ptr).ptr = unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&val)).Data)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("plugin-sdk-go/sdk: called SetValue with unsupported field type")
|
panic("plugin-sdk-go/sdk: called SetValue with unsupported field type")
|
||||||
}
|
}
|
||||||
*((*C.uintptr_t)(unsafe.Pointer(&e.req.res))) = *(*C.uintptr_t)(unsafe.Pointer(&e.resBuf))
|
*((*C.uintptr_t)(unsafe.Pointer(&e.req.res))) = *(*C.uintptr_t)(unsafe.Pointer(&e.resBuf))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *extractRequest) WantOffset() bool {
|
||||||
|
return e.resOffsetStart != nil && e.resOffsetLength != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *extractRequest) SetValueOffset(start, length uint32) {
|
||||||
|
if !e.WantOffset() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
*e.resOffsetStart = C.uint32_t(start)
|
||||||
|
*e.resOffsetLength = C.uint32_t(length)
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2025 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -18,18 +19,26 @@ package sdk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
|
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func boolToUint32(v bool) _Ctype_uint32_t {
|
||||||
|
if v {
|
||||||
|
return _Ctype_uint32_t(1)
|
||||||
|
}
|
||||||
|
return _Ctype_uint32_t(0)
|
||||||
|
}
|
||||||
|
|
||||||
func allocSSPluginExtractField(fid, ftype uint32, fname, farg_key string, farg_index uint64, farg_present bool, list bool) (*_Ctype_ss_plugin_extract_field, func()) {
|
func allocSSPluginExtractField(fid, ftype uint32, fname, farg_key string, farg_index uint64, farg_present bool, list bool) (*_Ctype_ss_plugin_extract_field, func()) {
|
||||||
ret := &_Ctype_ss_plugin_extract_field{}
|
ret := &_Ctype_ss_plugin_extract_field{}
|
||||||
ret.field_id = _Ctype_uint32_t(fid)
|
ret.field_id = _Ctype_uint32_t(fid)
|
||||||
ret.ftype = _Ctype_uint32_t(ftype)
|
ret.ftype = _Ctype_uint32_t(ftype)
|
||||||
ret.arg_present = _Ctype__Bool(farg_present)
|
ret.arg_present = boolToUint32(farg_present)
|
||||||
ret.flist = _Ctype__Bool(list)
|
ret.flist = boolToUint32(list)
|
||||||
ret.arg_index = _Ctype_uint64_t(farg_index)
|
ret.arg_index = _Ctype_uint64_t(farg_index)
|
||||||
|
|
||||||
argKeyBuf := ptr.StringBuffer{}
|
argKeyBuf := ptr.StringBuffer{}
|
||||||
|
@ -49,18 +58,51 @@ func allocSSPluginExtractField(fid, ftype uint32, fname, farg_key string, farg_i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func allocSSPluginExtractOffset() *_Ctype_uint32_t {
|
||||||
|
var offset _Ctype_uint32_t = _Ctype_uint32_t(0)
|
||||||
|
return &offset
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBoolResSSPluingExtractField(t *testing.T, ptr *_Ctype_ss_plugin_extract_field, index int) bool {
|
||||||
|
if ptr.res_len < (_Ctype_uint64_t)(index) {
|
||||||
|
t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(ptr.res_len))
|
||||||
|
}
|
||||||
|
value := (uint32)(*((*_Ctype_uint32_t)(unsafe.Pointer(uintptr(*(*_Ctype_uintptr_t)(unsafe.Pointer(&ptr.res))) + uintptr(index*_Ciconst_sizeof_uint32_t)))))
|
||||||
|
return value != uint32(0)
|
||||||
|
}
|
||||||
|
|
||||||
func getStrResSSPluingExtractField(t *testing.T, p *_Ctype_ss_plugin_extract_field, index int) string {
|
func getStrResSSPluingExtractField(t *testing.T, p *_Ctype_ss_plugin_extract_field, index int) string {
|
||||||
if p.res_len < (_Ctype_uint64_t)(index) {
|
if p.res_len < (_Ctype_uint64_t)(index) {
|
||||||
t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(p.res_len))
|
t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(p.res_len))
|
||||||
}
|
}
|
||||||
return ptr.GoString(unsafe.Pointer((*((**_Ctype_char)(unsafe.Pointer(uintptr(*(*_Ctype_uintptr_t)(unsafe.Pointer(&p.res))) + uintptr(index*_Ciconst_sizeof_field_result_t)))))))
|
return ptr.GoString(unsafe.Pointer((*((**_Ctype_char)(unsafe.Pointer(uintptr(*(*_Ctype_uintptr_t)(unsafe.Pointer(&p.res))) + uintptr(index*_Ciconst_sizeof_uintptr_t)))))))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getU64ResSSPluingExtractField(t *testing.T, ptr *_Ctype_ss_plugin_extract_field, index int) uint64 {
|
func getU64ResSSPluingExtractField(t *testing.T, ptr *_Ctype_ss_plugin_extract_field, index int) uint64 {
|
||||||
if ptr.res_len < (_Ctype_uint64_t)(index) {
|
if ptr.res_len < (_Ctype_uint64_t)(index) {
|
||||||
t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(ptr.res_len))
|
t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(ptr.res_len))
|
||||||
}
|
}
|
||||||
return (uint64)(*((*_Ctype_uint64_t)(unsafe.Pointer(uintptr(*(*_Ctype_uintptr_t)(unsafe.Pointer(&ptr.res))) + uintptr(index*_Ciconst_sizeof_field_result_t)))))
|
return (uint64)(*((*_Ctype_uint64_t)(unsafe.Pointer(uintptr(*(*_Ctype_uintptr_t)(unsafe.Pointer(&ptr.res))) + uintptr(index*_Ciconst_sizeof_uint64_t)))))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBinResSSPluingExtractField(t *testing.T, p *_Ctype_ss_plugin_extract_field, index int) []byte {
|
||||||
|
if p.res_len < (_Ctype_uint64_t)(index) {
|
||||||
|
t.Errorf("trying to access extract field res at index %d, but res len is %d", index, (int)(p.res_len))
|
||||||
|
}
|
||||||
|
|
||||||
|
bufListPtr := *(*unsafe.Pointer)(unsafe.Pointer(&p.res))
|
||||||
|
curBufPtr := (unsafe.Pointer)(unsafe.Pointer(uintptr(bufListPtr) + uintptr(index*_Ciconst_sizeof_field_result_t)))
|
||||||
|
size := *(*uint32)(curBufPtr)
|
||||||
|
buf := make([]byte, size)
|
||||||
|
ptrBytes := *(*unsafe.Pointer)(unsafe.Pointer(uintptr(curBufPtr) + uintptr(8)))
|
||||||
|
for i := 0; i < int(size); i++ {
|
||||||
|
buf[i] = *(*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(ptrBytes)) + uintptr(i)))
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func getResSSPluginExtractOffsetFromPtr(offset *_Ctype_uint32_t) uint32 {
|
||||||
|
return uint32(*offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertPanic(t *testing.T, fun func()) {
|
func assertPanic(t *testing.T, fun func()) {
|
||||||
|
@ -93,27 +135,60 @@ func TestExtractRequestSetValue(t *testing.T) {
|
||||||
// init test data
|
// init test data
|
||||||
testStr := "test str"
|
testStr := "test str"
|
||||||
testU64 := uint64(99)
|
testU64 := uint64(99)
|
||||||
|
testU64Start := uint32(PluginEventPayloadOffset)
|
||||||
|
testU64Length := uint32(8)
|
||||||
|
testBool := true
|
||||||
|
testIPv6 := net.IPv6loopback
|
||||||
testStrList := make([]string, 0)
|
testStrList := make([]string, 0)
|
||||||
testU64List := make([]uint64, 0)
|
testU64List := make([]uint64, 0)
|
||||||
for i := 0; i < minResultBufferLen+1; i++ { // cause a list resizing
|
testU64ListStart := uint32(PluginEventPayloadOffset)
|
||||||
|
testU64ListLength := uint32(0)
|
||||||
|
testBoolList := make([]bool, 0)
|
||||||
|
dataArray := make([]byte, (minResultBufferLen+1)*int(len(testIPv6)))
|
||||||
|
for i := 0; i < (minResultBufferLen+1)*int(len(testIPv6)); i++ {
|
||||||
|
dataArray[i] = byte(i)
|
||||||
|
}
|
||||||
|
testIPv6List := make([]net.IP, minResultBufferLen+1)
|
||||||
|
for i := 0; i < minResultBufferLen+1; i++ {
|
||||||
testStrList = append(testStrList, fmt.Sprintf("test-%d", i))
|
testStrList = append(testStrList, fmt.Sprintf("test-%d", i))
|
||||||
testU64List = append(testU64List, uint64(i))
|
testU64List = append(testU64List, uint64(i))
|
||||||
|
testU64ListLength += testU64Length
|
||||||
|
testBoolList = append(testBoolList, i%3 == 0)
|
||||||
|
testIPv6List[i] = dataArray[i*len(testIPv6) : (i+1)*len(testIPv6)]
|
||||||
}
|
}
|
||||||
|
|
||||||
// init extract requests
|
// init extract requests
|
||||||
pool := NewExtractRequestPool()
|
pool := NewExtractRequestPool()
|
||||||
u64Ptr, freeU64Ptr := allocSSPluginExtractField(1, FieldTypeUint64, "test.u64", "", 0, true, false)
|
u64Ptr, freeU64Ptr := allocSSPluginExtractField(1, FieldTypeUint64, "test.u64", "", 0, true, false)
|
||||||
|
u64OffsetStartPtr := allocSSPluginExtractOffset()
|
||||||
|
u64OffsetLengthPtr := allocSSPluginExtractOffset()
|
||||||
u64ListPtr, freeU64ListPtr := allocSSPluginExtractField(2, FieldTypeUint64, "test.u64", "", 0, true, true)
|
u64ListPtr, freeU64ListPtr := allocSSPluginExtractField(2, FieldTypeUint64, "test.u64", "", 0, true, true)
|
||||||
|
u64ListOffsetStartPtr := allocSSPluginExtractOffset()
|
||||||
|
u64ListOffsetLengthPtr := allocSSPluginExtractOffset()
|
||||||
strPtr, freeStrPtr := allocSSPluginExtractField(3, FieldTypeCharBuf, "test.str", "", 0, true, false)
|
strPtr, freeStrPtr := allocSSPluginExtractField(3, FieldTypeCharBuf, "test.str", "", 0, true, false)
|
||||||
strListPtr, freeStrListPtr := allocSSPluginExtractField(4, FieldTypeCharBuf, "test.str", "", 0, true, true)
|
strListPtr, freeStrListPtr := allocSSPluginExtractField(4, FieldTypeCharBuf, "test.str", "", 0, true, true)
|
||||||
|
boolPtr, freeBoolPtr := allocSSPluginExtractField(5, FieldTypeBool, "test.bool", "", 0, true, false)
|
||||||
|
boolListPtr, freeBoolListPtr := allocSSPluginExtractField(6, FieldTypeBool, "test.bool", "", 0, true, true)
|
||||||
|
binPtr, freeBinPtr := allocSSPluginExtractField(7, FieldTypeIPAddr, "test.ipv6addr", "", 0, true, false)
|
||||||
|
binListPtr, freeBinListPtr := allocSSPluginExtractField(8, FieldTypeIPAddr, "test.ipv6addr", "", 0, true, true)
|
||||||
u64Req := pool.Get(0)
|
u64Req := pool.Get(0)
|
||||||
u64ReqList := pool.Get(1)
|
u64ReqList := pool.Get(1)
|
||||||
strReq := pool.Get(2)
|
strReq := pool.Get(2)
|
||||||
strReqList := pool.Get(3)
|
strReqList := pool.Get(3)
|
||||||
|
boolReq := pool.Get(4)
|
||||||
|
boolReqList := pool.Get(5)
|
||||||
|
binReq := pool.Get(6)
|
||||||
|
binReqList := pool.Get(7)
|
||||||
u64Req.SetPtr(unsafe.Pointer(u64Ptr))
|
u64Req.SetPtr(unsafe.Pointer(u64Ptr))
|
||||||
|
u64Req.SetOffsetPtrs(unsafe.Pointer(u64OffsetStartPtr), unsafe.Pointer(u64OffsetLengthPtr))
|
||||||
u64ReqList.SetPtr(unsafe.Pointer(u64ListPtr))
|
u64ReqList.SetPtr(unsafe.Pointer(u64ListPtr))
|
||||||
|
u64ReqList.SetOffsetPtrs(unsafe.Pointer(u64ListOffsetStartPtr), unsafe.Pointer(u64ListOffsetLengthPtr))
|
||||||
strReq.SetPtr(unsafe.Pointer(strPtr))
|
strReq.SetPtr(unsafe.Pointer(strPtr))
|
||||||
strReqList.SetPtr(unsafe.Pointer(strListPtr))
|
strReqList.SetPtr(unsafe.Pointer(strListPtr))
|
||||||
|
boolReq.SetPtr(unsafe.Pointer(boolPtr))
|
||||||
|
boolReqList.SetPtr(unsafe.Pointer(boolListPtr))
|
||||||
|
binReq.SetPtr(unsafe.Pointer(binPtr))
|
||||||
|
binReqList.SetPtr(unsafe.Pointer(binListPtr))
|
||||||
|
|
||||||
// check that info is passed-through correctly
|
// check that info is passed-through correctly
|
||||||
if u64Req.FieldID() != 1 {
|
if u64Req.FieldID() != 1 {
|
||||||
|
@ -144,9 +219,23 @@ func TestExtractRequestSetValue(t *testing.T) {
|
||||||
// check panics
|
// check panics
|
||||||
assertPanic(t, func() {
|
assertPanic(t, func() {
|
||||||
u64Req.SetValue("test")
|
u64Req.SetValue("test")
|
||||||
|
u64Req.SetValue(bool(true))
|
||||||
|
boolReq.SetValue([]byte{0x41, 0x41, 0x41, 0x41})
|
||||||
})
|
})
|
||||||
assertPanic(t, func() {
|
assertPanic(t, func() {
|
||||||
strReq.SetValue(uint64(1))
|
strReq.SetValue(uint64(1))
|
||||||
|
strReq.SetValue(bool(true))
|
||||||
|
boolReq.SetValue([]byte{0x41, 0x41, 0x41, 0x41})
|
||||||
|
})
|
||||||
|
assertPanic(t, func() {
|
||||||
|
boolReq.SetValue(uint64(1))
|
||||||
|
boolReq.SetValue("test")
|
||||||
|
boolReq.SetValue([]byte{0x41, 0x41, 0x41, 0x41})
|
||||||
|
})
|
||||||
|
assertPanic(t, func() {
|
||||||
|
binReq.SetValue(uint64(1))
|
||||||
|
binReq.SetValue("test")
|
||||||
|
binReq.SetValue(bool(true))
|
||||||
})
|
})
|
||||||
|
|
||||||
// check set correct values
|
// check set correct values
|
||||||
|
@ -154,12 +243,26 @@ func TestExtractRequestSetValue(t *testing.T) {
|
||||||
if getU64ResSSPluingExtractField(t, u64Ptr, 0) != testU64 {
|
if getU64ResSSPluingExtractField(t, u64Ptr, 0) != testU64 {
|
||||||
t.Errorf("expected value '%d', but found '%d'", testU64, getU64ResSSPluingExtractField(t, u64Ptr, 0))
|
t.Errorf("expected value '%d', but found '%d'", testU64, getU64ResSSPluingExtractField(t, u64Ptr, 0))
|
||||||
}
|
}
|
||||||
|
u64Req.SetValueOffset(testU64Start, testU64Length)
|
||||||
|
if getResSSPluginExtractOffsetFromPtr(u64OffsetStartPtr) != testU64Start {
|
||||||
|
t.Errorf("expected start offset '%d', but found '%d'", testU64Start, getResSSPluginExtractOffsetFromPtr(u64OffsetStartPtr))
|
||||||
|
}
|
||||||
|
if getResSSPluginExtractOffsetFromPtr(u64OffsetLengthPtr) != testU64Length {
|
||||||
|
t.Errorf("expected length '%d', but found '%d'", testU64Length, getResSSPluginExtractOffsetFromPtr(u64OffsetLengthPtr))
|
||||||
|
}
|
||||||
u64ReqList.SetValue(testU64List)
|
u64ReqList.SetValue(testU64List)
|
||||||
|
u64ReqList.SetValueOffset(testU64ListStart, testU64ListLength)
|
||||||
for i, d := range testU64List {
|
for i, d := range testU64List {
|
||||||
if getU64ResSSPluingExtractField(t, u64ListPtr, i) != d {
|
if getU64ResSSPluingExtractField(t, u64ListPtr, i) != d {
|
||||||
t.Errorf("expected value '%d', but found '%d'", testU64, getU64ResSSPluingExtractField(t, u64Ptr, i))
|
t.Errorf("expected value '%d', but found '%d'", testU64, getU64ResSSPluingExtractField(t, u64Ptr, i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if getResSSPluginExtractOffsetFromPtr(u64ListOffsetStartPtr) != testU64ListStart {
|
||||||
|
t.Errorf("expected start offset '%d', but found '%d'", testU64ListStart, getResSSPluginExtractOffsetFromPtr(u64ListOffsetStartPtr))
|
||||||
|
}
|
||||||
|
if getResSSPluginExtractOffsetFromPtr(u64ListOffsetLengthPtr) != testU64ListLength {
|
||||||
|
t.Errorf("expected length '%d', but found '%d'", testU64ListLength, getResSSPluginExtractOffsetFromPtr(u64ListOffsetLengthPtr))
|
||||||
|
}
|
||||||
strReq.SetValue(testStr)
|
strReq.SetValue(testStr)
|
||||||
if getStrResSSPluingExtractField(t, strPtr, 0) != testStr {
|
if getStrResSSPluingExtractField(t, strPtr, 0) != testStr {
|
||||||
t.Errorf("expected value '%s', but found '%s'", testStr, getStrResSSPluingExtractField(t, strPtr, 0))
|
t.Errorf("expected value '%s', but found '%s'", testStr, getStrResSSPluingExtractField(t, strPtr, 0))
|
||||||
|
@ -170,10 +273,49 @@ func TestExtractRequestSetValue(t *testing.T) {
|
||||||
t.Errorf("expected value '%s', but found '%s'", s, getStrResSSPluingExtractField(t, strPtr, i))
|
t.Errorf("expected value '%s', but found '%s'", s, getStrResSSPluingExtractField(t, strPtr, i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
boolReq.SetValue(testBool)
|
||||||
|
if getBoolResSSPluingExtractField(t, boolPtr, 0) != testBool {
|
||||||
|
t.Errorf("expected value '%v', but found '%v'", testBool, getBoolResSSPluingExtractField(t, boolPtr, 0))
|
||||||
|
}
|
||||||
|
boolReqList.SetValue(testBoolList)
|
||||||
|
for i, b := range testBoolList {
|
||||||
|
if getBoolResSSPluingExtractField(t, boolListPtr, i) != b {
|
||||||
|
t.Errorf("expected value '%v', but found '%v' at index %d", b, getBoolResSSPluingExtractField(t, boolPtr, i), i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binReq.SetValue(testIPv6)
|
||||||
|
testIPv6res := getBinResSSPluingExtractField(t, binPtr, 0)
|
||||||
|
if len(testIPv6res) != len(testIPv6) {
|
||||||
|
t.Errorf("expected value '%v', but found '%v'", testIPv6, getBinResSSPluingExtractField(t, binPtr, 0))
|
||||||
|
} else {
|
||||||
|
for i := 0; i < len(testIPv6); i++ {
|
||||||
|
if testIPv6[i] != testIPv6res[i] {
|
||||||
|
t.Errorf("expected value '%v', but found '%v'", testIPv6, getBinResSSPluingExtractField(t, binPtr, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binReqList.SetValue(testIPv6List)
|
||||||
|
for i, s := range testIPv6List {
|
||||||
|
testIPv6res := getBinResSSPluingExtractField(t, binListPtr, i)
|
||||||
|
if len(testIPv6res) != len(s) {
|
||||||
|
t.Errorf("expected size '%v', but found '%v'", len(s), len(testIPv6res))
|
||||||
|
} else {
|
||||||
|
for k := 0; k < len(s); k++ {
|
||||||
|
if s[k] != testIPv6res[k] {
|
||||||
|
t.Errorf("expected value '%v', but found '%v'", s, testIPv6res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pool.Free()
|
pool.Free()
|
||||||
freeU64Ptr()
|
freeU64Ptr()
|
||||||
freeU64ListPtr()
|
freeU64ListPtr()
|
||||||
freeStrPtr()
|
freeStrPtr()
|
||||||
freeStrListPtr()
|
freeStrListPtr()
|
||||||
|
freeBoolPtr()
|
||||||
|
freeBoolListPtr()
|
||||||
|
freeBinPtr()
|
||||||
|
freeBinListPtr()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -23,12 +24,12 @@ limitations under the License.
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// API versions of this plugin framework
|
// API versions of this plugin framework
|
||||||
//
|
//
|
||||||
#define PLUGIN_API_VERSION_MAJOR 2
|
// todo(jasondellaluce): when/if major changes to v4, check and solve all todos
|
||||||
#define PLUGIN_API_VERSION_MINOR 0
|
#define PLUGIN_API_VERSION_MAJOR 3
|
||||||
|
#define PLUGIN_API_VERSION_MINOR 11
|
||||||
#define PLUGIN_API_VERSION_PATCH 0
|
#define PLUGIN_API_VERSION_PATCH 0
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -36,13 +37,482 @@ extern "C" {
|
||||||
//
|
//
|
||||||
#define QUOTE(str) #str
|
#define QUOTE(str) #str
|
||||||
#define EXPAND_AND_QUOTE(str) QUOTE(str)
|
#define EXPAND_AND_QUOTE(str) QUOTE(str)
|
||||||
#define PLUGIN_API_VERSION PLUGIN_API_VERSION_MAJOR.PLUGIN_API_VERSION_MINOR.PLUGIN_API_VERSION_PATCH
|
#define PLUGIN_API_VERSION \
|
||||||
|
PLUGIN_API_VERSION_MAJOR.PLUGIN_API_VERSION_MINOR.PLUGIN_API_VERSION_PATCH
|
||||||
#define PLUGIN_API_VERSION_STR EXPAND_AND_QUOTE(PLUGIN_API_VERSION)
|
#define PLUGIN_API_VERSION_STR EXPAND_AND_QUOTE(PLUGIN_API_VERSION)
|
||||||
|
|
||||||
|
//
|
||||||
|
// The max length of errors returned by a plugin in some of its API symbols.
|
||||||
|
//
|
||||||
|
#define PLUGIN_MAX_ERRLEN 1024
|
||||||
|
|
||||||
|
// Supported by the API but deprecated. Use the extended version ss_plugin_table_reader_vtable_ext
|
||||||
|
// instead. todo(jasondellaluce): when/if major changes to v4, remove this and give this name to the
|
||||||
|
// associated *_ext struct.
|
||||||
|
typedef struct {
|
||||||
|
const ss_plugin_table_fieldinfo* (*list_table_fields)(ss_plugin_table_t* t, uint32_t* nfields);
|
||||||
|
ss_plugin_table_field_t* (*get_table_field)(ss_plugin_table_t* t,
|
||||||
|
const char* name,
|
||||||
|
ss_plugin_state_type data_type);
|
||||||
|
ss_plugin_table_field_t* (*add_table_field)(ss_plugin_table_t* t,
|
||||||
|
const char* name,
|
||||||
|
ss_plugin_state_type data_type);
|
||||||
|
} ss_plugin_table_fields_vtable;
|
||||||
|
|
||||||
|
// Vtable for controlling and the fields for the entries of a state table.
|
||||||
|
// This allows discovering the fields available in the table, defining new ones,
|
||||||
|
// and obtaining accessors usable at runtime for reading and writing the fields'
|
||||||
|
// data from each entry of a given state table.
|
||||||
|
typedef struct {
|
||||||
|
// Returns a pointer to an array containing info about all the fields
|
||||||
|
// available in the entries of the table. nfields will be filled with the number
|
||||||
|
// of elements of the returned array. The array's memory is owned by the
|
||||||
|
// tables's owner. Returns NULL in case of error.
|
||||||
|
const ss_plugin_table_fieldinfo* (*list_table_fields)(ss_plugin_table_t* t, uint32_t* nfields);
|
||||||
|
//
|
||||||
|
// Returns an opaque pointer representing an accessor to a data field
|
||||||
|
// present in all entries of the table, given its name and type.
|
||||||
|
// This can later be used for read and write operations for all entries of
|
||||||
|
// the table. The pointer is owned by the table's owner.
|
||||||
|
// Returns NULL in case of issues (including when the field is not defined
|
||||||
|
// or it has a type different than the specified one).
|
||||||
|
ss_plugin_table_field_t* (*get_table_field)(ss_plugin_table_t* t,
|
||||||
|
const char* name,
|
||||||
|
ss_plugin_state_type data_type);
|
||||||
|
//
|
||||||
|
// Defines a new field in the table given its name and data type,
|
||||||
|
// which will then be available in all entries contained in the table.
|
||||||
|
// Returns an opaque pointer representing an accessor to the newly-defined
|
||||||
|
// field. This can later be used for read and write operations for all entries of
|
||||||
|
// the table. The pointer is owned by the table's owner.
|
||||||
|
// Returns NULL in case of issues (including when a field is defined multiple
|
||||||
|
// times with different data types).
|
||||||
|
ss_plugin_table_field_t* (*add_table_field)(ss_plugin_table_t* t,
|
||||||
|
const char* name,
|
||||||
|
ss_plugin_state_type data_type);
|
||||||
|
} ss_plugin_table_fields_vtable_ext;
|
||||||
|
|
||||||
|
// Supported by the API but deprecated. Use the extended version ss_plugin_table_reader_vtable_ext
|
||||||
|
// instead. todo(jasondellaluce): when/if major changes to v4, remove this and give this name to the
|
||||||
|
// associated *_ext struct.
|
||||||
|
typedef struct {
|
||||||
|
const char* (*get_table_name)(ss_plugin_table_t* t);
|
||||||
|
uint64_t (*get_table_size)(ss_plugin_table_t* t);
|
||||||
|
ss_plugin_table_entry_t* (*get_table_entry)(ss_plugin_table_t* t,
|
||||||
|
const ss_plugin_state_data* key);
|
||||||
|
ss_plugin_rc (*read_entry_field)(ss_plugin_table_t* t,
|
||||||
|
ss_plugin_table_entry_t* e,
|
||||||
|
const ss_plugin_table_field_t* f,
|
||||||
|
ss_plugin_state_data* out);
|
||||||
|
} ss_plugin_table_reader_vtable;
|
||||||
|
|
||||||
|
// Opaque pointer to the state data relative to a state table iteration.
|
||||||
|
// This is passed initially by the invoker when starting the iteration, and
|
||||||
|
// is then dispatched to the iterator for each of the entries of the table.
|
||||||
|
typedef void ss_plugin_table_iterator_state_t;
|
||||||
|
|
||||||
|
// Iterator function callback used by a plugin for looping through all the
|
||||||
|
// entries of a given state table. Returns true if the iteration should
|
||||||
|
// proceed to the next element, or false in case of break out.
|
||||||
|
typedef ss_plugin_bool (*ss_plugin_table_iterator_func_t)(ss_plugin_table_iterator_state_t* s,
|
||||||
|
ss_plugin_table_entry_t* e);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// Returns the table's name, or NULL in case of error.
|
||||||
|
// The returned pointer is owned by the table's owner.
|
||||||
|
const char* (*get_table_name)(ss_plugin_table_t* t);
|
||||||
|
//
|
||||||
|
// Returns the number of entries in the table, or ((uint64_t) -1) in
|
||||||
|
// case of error.
|
||||||
|
uint64_t (*get_table_size)(ss_plugin_table_t* t);
|
||||||
|
//
|
||||||
|
// Returns an opaque pointer to an entry present in the table at the given
|
||||||
|
// key, or NULL in case of issues (including if no entry is found at the
|
||||||
|
// given key). The returned pointer is owned by the table's owner.
|
||||||
|
// Every non-NULL returned entry must be released by invoking release_table_entry()
|
||||||
|
// once it becomes no more used by the invoker.
|
||||||
|
ss_plugin_table_entry_t* (*get_table_entry)(ss_plugin_table_t* t,
|
||||||
|
const ss_plugin_state_data* key);
|
||||||
|
//
|
||||||
|
// Reads the value of an entry field from a table's entry.
|
||||||
|
// The field accessor must be obtainied during plugin_init().
|
||||||
|
// The read value is stored in the "out" parameter.
|
||||||
|
// Returns SS_PLUGIN_SUCCESS if successful, and SS_PLUGIN_FAILURE otherwise.
|
||||||
|
ss_plugin_rc (*read_entry_field)(ss_plugin_table_t* t,
|
||||||
|
ss_plugin_table_entry_t* e,
|
||||||
|
const ss_plugin_table_field_t* f,
|
||||||
|
ss_plugin_state_data* out);
|
||||||
|
//
|
||||||
|
// Releases a table entry obtained by from previous invocation of get_table_entry().
|
||||||
|
// After being released, the same table entry cannot be reused by the invoker.
|
||||||
|
// However, the same entry can be re-obtained through an invocation of get_table_entry().
|
||||||
|
void (*release_table_entry)(ss_plugin_table_t* t, ss_plugin_table_entry_t* e);
|
||||||
|
//
|
||||||
|
// Iterates through all the entries of a table, invoking the interation
|
||||||
|
// callback function for each of them. Returns false in case of failure or
|
||||||
|
// iteration break-out, and true otherwise.
|
||||||
|
ss_plugin_bool (*iterate_entries)(ss_plugin_table_t* t,
|
||||||
|
ss_plugin_table_iterator_func_t it,
|
||||||
|
ss_plugin_table_iterator_state_t* s);
|
||||||
|
} ss_plugin_table_reader_vtable_ext;
|
||||||
|
|
||||||
|
// Supported by the API but deprecated. Use the extended version ss_plugin_table_writer_vtable_ext
|
||||||
|
// instead. todo(jasondellaluce): when/if major changes to v4, remove this and give this name to the
|
||||||
|
// associated *_ext struct.
|
||||||
|
typedef struct {
|
||||||
|
ss_plugin_rc (*clear_table)(ss_plugin_table_t* t);
|
||||||
|
ss_plugin_rc (*erase_table_entry)(ss_plugin_table_t* t, const ss_plugin_state_data* key);
|
||||||
|
ss_plugin_table_entry_t* (*create_table_entry)(ss_plugin_table_t* t);
|
||||||
|
void (*destroy_table_entry)(ss_plugin_table_t* t, ss_plugin_table_entry_t* e);
|
||||||
|
ss_plugin_table_entry_t* (*add_table_entry)(ss_plugin_table_t* t,
|
||||||
|
const ss_plugin_state_data* key,
|
||||||
|
ss_plugin_table_entry_t* entry);
|
||||||
|
ss_plugin_rc (*write_entry_field)(ss_plugin_table_t* t,
|
||||||
|
ss_plugin_table_entry_t* e,
|
||||||
|
const ss_plugin_table_field_t* f,
|
||||||
|
const ss_plugin_state_data* in);
|
||||||
|
} ss_plugin_table_writer_vtable;
|
||||||
|
|
||||||
|
// Vtable for controlling a state table for write operations.
|
||||||
|
typedef struct {
|
||||||
|
// Erases all the entries of the table.
|
||||||
|
// Returns SS_PLUGIN_SUCCESS if successful, and SS_PLUGIN_FAILURE otherwise.
|
||||||
|
ss_plugin_rc (*clear_table)(ss_plugin_table_t* t);
|
||||||
|
//
|
||||||
|
// Erases an entry from a table at the given key.
|
||||||
|
// Returns SS_PLUGIN_SUCCESS if successful, and SS_PLUGIN_FAILURE otherwise.
|
||||||
|
ss_plugin_rc (*erase_table_entry)(ss_plugin_table_t* t, const ss_plugin_state_data* key);
|
||||||
|
//
|
||||||
|
// Creates a new entry that can later be added to the same table it was
|
||||||
|
// created from. The entry is represented as an opaque pointer owned
|
||||||
|
// by the plugin. Once obtained, the plugin can either add the entry
|
||||||
|
// to the table through add_table_entry(), or destroy it throgh
|
||||||
|
// destroy_table_entry(). Returns an opaque pointer to the newly-created
|
||||||
|
// entry, or NULL in case of error.
|
||||||
|
ss_plugin_table_entry_t* (*create_table_entry)(ss_plugin_table_t* t);
|
||||||
|
//
|
||||||
|
// Destroys a table entry obtained by from previous invocation of create_table_entry().
|
||||||
|
void (*destroy_table_entry)(ss_plugin_table_t* t, ss_plugin_table_entry_t* e);
|
||||||
|
//
|
||||||
|
// Adds a new entry to a table obtained by from previous invocation of
|
||||||
|
// create_table_entry() on the same table. The entry is inserted in the table
|
||||||
|
// with the given key. If another entry is already present with the same key,
|
||||||
|
// it gets replaced. After insertion, table will be come the owner of the
|
||||||
|
// entry's pointer. Returns an opaque pointer to the newly-added table's entry,
|
||||||
|
// or NULL in case of error. Every non-NULL returned entry must be released
|
||||||
|
// by invoking release_table_entry() once it becomes no more used by the invoker.
|
||||||
|
ss_plugin_table_entry_t* (*add_table_entry)(ss_plugin_table_t* t,
|
||||||
|
const ss_plugin_state_data* key,
|
||||||
|
ss_plugin_table_entry_t* entry);
|
||||||
|
//
|
||||||
|
// Updates a table's entry by writing a value for one of its fields.
|
||||||
|
// The field accessor must be obtainied during plugin_init().
|
||||||
|
// The written value is read from the "in" parameter.
|
||||||
|
// Returns SS_PLUGIN_SUCCESS if successful, and SS_PLUGIN_FAILURE otherwise.
|
||||||
|
ss_plugin_rc (*write_entry_field)(ss_plugin_table_t* t,
|
||||||
|
ss_plugin_table_entry_t* e,
|
||||||
|
const ss_plugin_table_field_t* f,
|
||||||
|
const ss_plugin_state_data* in);
|
||||||
|
} ss_plugin_table_writer_vtable_ext;
|
||||||
|
|
||||||
|
// Plugin-provided input passed to the add_table() callback of
|
||||||
|
// ss_plugin_init_tables_input, that can be used by the plugin to inform its
|
||||||
|
// owner about one of the state tables owned by the plugin. The plugin
|
||||||
|
// is responsible of owning all the memory pointed by this struct and
|
||||||
|
// of implementing all the API functions. These will be used by other
|
||||||
|
// plugins loaded by the falcosecurity libraries to interact with the state
|
||||||
|
// of a given plugin to implement cross-plugin state access.
|
||||||
|
typedef struct {
|
||||||
|
// The name of the state table.
|
||||||
|
const char* name;
|
||||||
|
//
|
||||||
|
// The type of the state table's key.
|
||||||
|
ss_plugin_state_type key_type;
|
||||||
|
//
|
||||||
|
// A non-NULL opaque pointer to the state table.
|
||||||
|
// This will be passed as parameters to all the callbacks defined below.
|
||||||
|
ss_plugin_table_t* table;
|
||||||
|
//
|
||||||
|
// Supported but deprecated. Use the extended version reader_ext.
|
||||||
|
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||||
|
// give this name to the associated *_ext pointer.
|
||||||
|
ss_plugin_table_reader_vtable reader;
|
||||||
|
//
|
||||||
|
// Supported but deprecated. Use the extended version writer_ext.
|
||||||
|
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||||
|
// give this name to the associated *_ext pointer.
|
||||||
|
ss_plugin_table_writer_vtable writer;
|
||||||
|
//
|
||||||
|
// Supported but deprecated. Use the extended version fields_ext.
|
||||||
|
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||||
|
// give this name to the associated *_ext pointer.
|
||||||
|
ss_plugin_table_fields_vtable fields;
|
||||||
|
//
|
||||||
|
// Vtable for controlling read operations on the state table.
|
||||||
|
ss_plugin_table_reader_vtable_ext* reader_ext;
|
||||||
|
//
|
||||||
|
// Vtable for controlling write operations on the state table.
|
||||||
|
ss_plugin_table_writer_vtable_ext* writer_ext;
|
||||||
|
//
|
||||||
|
// Vtable for controlling operations related to fields on the state table.
|
||||||
|
ss_plugin_table_fields_vtable_ext* fields_ext;
|
||||||
|
} ss_plugin_table_input;
|
||||||
|
|
||||||
|
// Initialization-time input related to the event parsing or field extraction capability.
|
||||||
|
// This provides the plugin with callback functions implemented by its owner
|
||||||
|
// that can be used to discover, access, and define state tables.
|
||||||
|
typedef struct {
|
||||||
|
// Returns a pointer to an array containing info about all the tables
|
||||||
|
// registered in the plugin's owner. ntables will be filled with the number
|
||||||
|
// of elements of the returned array. The array's memory is owned by the
|
||||||
|
// plugin's owner. Returns NULL in case of error.
|
||||||
|
ss_plugin_table_info* (*list_tables)(ss_plugin_owner_t* o, uint32_t* ntables);
|
||||||
|
//
|
||||||
|
// Returns an opaque accessor to a state table registered in the plugin's
|
||||||
|
// owner, given its name and key type. Returns NULL if an case of error.
|
||||||
|
ss_plugin_table_t* (*get_table)(ss_plugin_owner_t* o,
|
||||||
|
const char* name,
|
||||||
|
ss_plugin_state_type key_type);
|
||||||
|
//
|
||||||
|
// Registers a new state table in the plugin's owner. Returns
|
||||||
|
// SS_PLUGIN_SUCCESS in case of success, and SS_PLUGIN_FAILURE otherwise.
|
||||||
|
// The state table is owned by the plugin itself, and the input will be used
|
||||||
|
// by other actors of the plugin's owner to interact with the state table.
|
||||||
|
ss_plugin_rc (*add_table)(ss_plugin_owner_t* o, const ss_plugin_table_input* in);
|
||||||
|
//
|
||||||
|
// Supported but deprecated. Use the extended version fields_ext.
|
||||||
|
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||||
|
// give this name to the associated *_ext pointer.
|
||||||
|
ss_plugin_table_fields_vtable fields;
|
||||||
|
//
|
||||||
|
// Vtable for controlling operations related to fields on the state tables
|
||||||
|
// registered in the plugin's owner.
|
||||||
|
ss_plugin_table_fields_vtable_ext* fields_ext;
|
||||||
|
//
|
||||||
|
// Vtable for controlling read operations on the state tables registered
|
||||||
|
// in the plugin's owner.
|
||||||
|
ss_plugin_table_reader_vtable_ext* reader_ext;
|
||||||
|
//
|
||||||
|
// Vtable for controlling write operations on the state tables registered
|
||||||
|
// in the plugin's owner.
|
||||||
|
ss_plugin_table_writer_vtable_ext* writer_ext;
|
||||||
|
} ss_plugin_init_tables_input;
|
||||||
|
|
||||||
|
// Function used by plugin for sending messages to the framework-provided logger
|
||||||
|
// Arguments:
|
||||||
|
// - component: name of the component that is logging
|
||||||
|
// (if set to NULL automatically falls back to the plugin name in the log)
|
||||||
|
// - msg: message to log
|
||||||
|
// (it doesn't have to be '\n' terminated)
|
||||||
|
// - sev: message severity as defined in ss_plugin_log_severity
|
||||||
|
typedef void (*ss_plugin_log_fn_t)(ss_plugin_owner_t* o,
|
||||||
|
const char* component,
|
||||||
|
const char* msg,
|
||||||
|
ss_plugin_log_severity sev);
|
||||||
|
|
||||||
|
// Input passed at the plugin through plugin_init(). This contain information
|
||||||
|
// common to any plugin, and also information useful only in case the plugin
|
||||||
|
// implements a given capability. If a certain capability is not implemented
|
||||||
|
// by the plugin, its information is set to NULL.
|
||||||
|
typedef struct ss_plugin_init_input {
|
||||||
|
// An opaque string representing the plugin init configuration.
|
||||||
|
// The format of the string is arbitrary and defined by the plugin itself.
|
||||||
|
const char* config;
|
||||||
|
//
|
||||||
|
// The plugin's owner. Can be passed by the plugin to the callbacks available
|
||||||
|
// in this struct in order to invoke functions of its owner.
|
||||||
|
// It doesn't change during the whole plugin's lifecycle, it's safe to store it in the state
|
||||||
|
ss_plugin_owner_t* owner;
|
||||||
|
//
|
||||||
|
// Return a string with the error that was last generated by the plugin's
|
||||||
|
// owner, or NULL if no error is present.
|
||||||
|
// The string pointer is owned by the plugin's owenr.
|
||||||
|
const char* (*get_owner_last_error)(ss_plugin_owner_t* o);
|
||||||
|
//
|
||||||
|
// Init input related to the event parsing or field extraction capability.
|
||||||
|
// It's set to NULL if the plugin does not implement at least one of the two
|
||||||
|
// capabilities. The callbacks available in this input take the plugin's owner
|
||||||
|
// as a parameter.
|
||||||
|
const ss_plugin_init_tables_input* tables;
|
||||||
|
//
|
||||||
|
// Log function passed to the plugin through the init input
|
||||||
|
// It doesn't change during the whole plugin's lifecycle, it's safe to store it in the state
|
||||||
|
ss_plugin_log_fn_t log_fn;
|
||||||
|
} ss_plugin_init_input;
|
||||||
|
|
||||||
|
// Input passed to the plugin when extracting a field from an event for
|
||||||
|
// the field extraction capability.
|
||||||
|
typedef struct ss_plugin_field_extract_input {
|
||||||
|
//
|
||||||
|
// The plugin's owner. Can be passed by the plugin to the callbacks available
|
||||||
|
// in this struct in order to invoke functions of its owner.
|
||||||
|
ss_plugin_owner_t* owner;
|
||||||
|
//
|
||||||
|
// Return a string with the error that was last generated by the plugin's
|
||||||
|
// owner, or NULL if no error is present.
|
||||||
|
// The string pointer is owned by the plugin's owenr.
|
||||||
|
const char* (*get_owner_last_error)(ss_plugin_owner_t* o);
|
||||||
|
//
|
||||||
|
// The length of the fields array.
|
||||||
|
uint32_t num_fields;
|
||||||
|
//
|
||||||
|
// An array of ss_plugin_extract_field structs. Each entry
|
||||||
|
// contains a single field + optional argument as input, and the corresponding
|
||||||
|
// extracted value as output. Memory pointers set as output must be allocated
|
||||||
|
// by the plugin and must not be deallocated or modified until the next
|
||||||
|
// extract_fields() call.
|
||||||
|
ss_plugin_extract_field* fields;
|
||||||
|
//
|
||||||
|
// Supported but deprecated. Use the extended version table_reader_ext.
|
||||||
|
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||||
|
// give this name to the associated *_ext pointer.
|
||||||
|
ss_plugin_table_reader_vtable table_reader;
|
||||||
|
//
|
||||||
|
// Vtable for controlling a state table for read operations.
|
||||||
|
ss_plugin_table_reader_vtable_ext* table_reader_ext;
|
||||||
|
|
||||||
|
// An array of ss_plugin_extract_value_offsets structs. The start
|
||||||
|
// and length in each entry should be set to nullptr, and as with
|
||||||
|
// the "fields" member, memory pointers set as output must be
|
||||||
|
// allocated by the plugin and must not be deallocated or modified
|
||||||
|
// until the next extract_fields() call.
|
||||||
|
// This member is optional, and might be ignored by extractors.
|
||||||
|
ss_plugin_extract_value_offsets* value_offsets;
|
||||||
|
} ss_plugin_field_extract_input;
|
||||||
|
|
||||||
|
// Input passed to the plugin when parsing an event for the event parsing
|
||||||
|
// capability.
|
||||||
|
typedef struct ss_plugin_event_parse_input {
|
||||||
|
//
|
||||||
|
// The plugin's owner. Can be passed by the plugin to the callbacks available
|
||||||
|
// in this struct in order to invoke functions of its owner.
|
||||||
|
ss_plugin_owner_t* owner;
|
||||||
|
//
|
||||||
|
// Return a string with the error that was last generated by the plugin's
|
||||||
|
// owner, or NULL if no error is present.
|
||||||
|
// The string pointer is owned by the plugin's owenr.
|
||||||
|
const char* (*get_owner_last_error)(ss_plugin_owner_t* o);
|
||||||
|
//
|
||||||
|
// Supported but deprecated. Use the extended version table_reader_ext.
|
||||||
|
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||||
|
// give this name to the associated *_ext pointer.
|
||||||
|
ss_plugin_table_reader_vtable table_reader;
|
||||||
|
//
|
||||||
|
// Supported but deprecated. Use the extended version table_writer_ext.
|
||||||
|
// todo(jasondellaluce): when/if major changes to v4, remove this and
|
||||||
|
// give this name to the associated *_ext pointer.
|
||||||
|
ss_plugin_table_writer_vtable table_writer;
|
||||||
|
//
|
||||||
|
// Vtable for controlling a state table for read operations.
|
||||||
|
ss_plugin_table_reader_vtable_ext* table_reader_ext;
|
||||||
|
//
|
||||||
|
// Vtable for controlling a state table for write operations.
|
||||||
|
ss_plugin_table_writer_vtable_ext* table_writer_ext;
|
||||||
|
} ss_plugin_event_parse_input;
|
||||||
|
|
||||||
|
// Input passed to the plugin when setting a new configuration
|
||||||
|
typedef struct ss_plugin_set_config_input {
|
||||||
|
//
|
||||||
|
// An opaque string representing the new configuration provided by the framework
|
||||||
|
const char* config;
|
||||||
|
} ss_plugin_set_config_input;
|
||||||
|
|
||||||
|
//
|
||||||
|
// An opaque pointer representing a routine subscribed in the framework-provided thread pool
|
||||||
|
typedef void ss_plugin_routine_t;
|
||||||
|
|
||||||
|
//
|
||||||
|
// An opaque pointer representing the state of the routine on each iteration
|
||||||
|
typedef void ss_plugin_routine_state_t;
|
||||||
|
|
||||||
|
//
|
||||||
|
// The function executed by the routine on each iteration.
|
||||||
|
// Arguments:
|
||||||
|
// - s: the plugin state, returned by init(). Can be NULL.
|
||||||
|
// - i: the routine state, provided by the plugin when the routine is subscribed
|
||||||
|
//
|
||||||
|
// Return value: Returning false causes the routine to be unsubcribed from the thread pool.
|
||||||
|
typedef ss_plugin_bool (*ss_plugin_routine_fn_t)(ss_plugin_t* s, ss_plugin_routine_state_t* i);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Vtable used by the plugin to subscribe and unsubscribe recurring loop-like routines
|
||||||
|
// to the framework-provide thread pool
|
||||||
|
typedef struct {
|
||||||
|
//
|
||||||
|
// Subscribes a routine to the framework-provided thread pool.
|
||||||
|
// Arguments:
|
||||||
|
// - o: the plugin's owner
|
||||||
|
// - f: the function executed by the routine on each iteration
|
||||||
|
// - i: the routine's state
|
||||||
|
//
|
||||||
|
// Return value: A routine handle that can be used to later unsubscribe the routine. Returns
|
||||||
|
// null in case of failure.
|
||||||
|
ss_plugin_routine_t* (*subscribe)(ss_plugin_owner_t* o,
|
||||||
|
ss_plugin_routine_fn_t f,
|
||||||
|
ss_plugin_routine_state_t* i);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Unsubscribes a routine from the framework-provided thread pool.
|
||||||
|
// Arguments:
|
||||||
|
// - o: the plugin's owner
|
||||||
|
// - r: the routine's handle
|
||||||
|
//
|
||||||
|
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||||
|
ss_plugin_rc (*unsubscribe)(ss_plugin_owner_t* o, ss_plugin_routine_t* r);
|
||||||
|
} ss_plugin_routine_vtable;
|
||||||
|
|
||||||
|
// Input passed to the plugin when the framework start and stops the capture.
|
||||||
|
typedef struct ss_plugin_capture_listen_input {
|
||||||
|
//
|
||||||
|
// The plugin's owner. Can be passed by the plugin to the callbacks available
|
||||||
|
// in this struct in order to invoke functions of its owner.
|
||||||
|
ss_plugin_owner_t* owner;
|
||||||
|
//
|
||||||
|
// Vtable containing callbacks that can be used by the plugin
|
||||||
|
// for subscribing and unsubscribing routines to the framework's thread pool.
|
||||||
|
ss_plugin_routine_vtable* routine;
|
||||||
|
//
|
||||||
|
// Vtable for controlling a state table for read operations.
|
||||||
|
ss_plugin_table_reader_vtable_ext* table_reader_ext;
|
||||||
|
//
|
||||||
|
// Vtable for controlling a state table for write operations.
|
||||||
|
ss_plugin_table_writer_vtable_ext* table_writer_ext;
|
||||||
|
//
|
||||||
|
// Return a string with the error that was last generated by the plugin's
|
||||||
|
// owner, or NULL if no error is present.
|
||||||
|
// The string pointer is owned by the plugin's owenr.
|
||||||
|
const char* (*get_owner_last_error)(ss_plugin_owner_t* o);
|
||||||
|
} ss_plugin_capture_listen_input;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Function handler used by plugin for sending asynchronous events to the
|
||||||
|
// Falcosecurity libs during a live event capture. The asynchronous events
|
||||||
|
// must be encoded as an async event type (code 402) as for the libscap specific.
|
||||||
|
//
|
||||||
|
// The plugin framework will automatically set the plugin ID of the produced
|
||||||
|
// async event depending on the running event source in which the event will
|
||||||
|
// be injected into. The event's thread ID can be set to control the system
|
||||||
|
// thread associated, with value (uint64_t) -1) representing no thread
|
||||||
|
// association. The event's timestamp can be set to forcefully specify
|
||||||
|
// the timestamp of the phenomena that the event represents, and value
|
||||||
|
// (uint64_t) -1) will cause the plugin framework to automatically assign
|
||||||
|
// a timestamp as the time in which the event is received asynchronously.
|
||||||
|
//
|
||||||
|
// The function returns SS_PLUGIN_SUCCESS in case of success, or
|
||||||
|
// SS_PLUGIN_FAILURE otherwise. If a non-NULL char pointer is passed for
|
||||||
|
// the "err" argument, it will be filled with an error message string
|
||||||
|
// in case the handler function returns SS_PLUGIN_FAILURE. The error string
|
||||||
|
// has a max length of PLUGIN_MAX_ERRLEN (termination char included) and its
|
||||||
|
// memory must be allocated and owned by the plugin.
|
||||||
|
typedef ss_plugin_rc (*ss_plugin_async_event_handler_t)(ss_plugin_owner_t* o,
|
||||||
|
const ss_plugin_event* evt,
|
||||||
|
char* err);
|
||||||
|
|
||||||
//
|
//
|
||||||
// The struct below define the functions and arguments for plugins capabilities:
|
// The struct below define the functions and arguments for plugins capabilities:
|
||||||
// * event sourcing
|
// * event sourcing
|
||||||
// * field extraction
|
// * field extraction
|
||||||
|
// * event parsing
|
||||||
// The structs are used by the plugin framework to load and interface with plugins.
|
// The structs are used by the plugin framework to load and interface with plugins.
|
||||||
//
|
//
|
||||||
// From the perspective of the plugin, each function below should be
|
// From the perspective of the plugin, each function below should be
|
||||||
|
@ -68,8 +538,7 @@ extern "C" {
|
||||||
//
|
//
|
||||||
// Plugins API vtable
|
// Plugins API vtable
|
||||||
//
|
//
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
//
|
//
|
||||||
// Return the version of the plugin API used by this plugin.
|
// Return the version of the plugin API used by this plugin.
|
||||||
// Required: yes
|
// Required: yes
|
||||||
|
@ -107,8 +576,7 @@ typedef struct
|
||||||
// Initialize the plugin and allocate its state.
|
// Initialize the plugin and allocate its state.
|
||||||
// Required: yes
|
// Required: yes
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - config: a string with the plugin configuration. The format of the
|
// - in: init-time input for the plugin.
|
||||||
// string is chosen by the plugin itself.
|
|
||||||
// - rc: pointer to a ss_plugin_rc that will contain the initialization result
|
// - rc: pointer to a ss_plugin_rc that will contain the initialization result
|
||||||
// Return value: pointer to the plugin state that will be treated as opaque
|
// Return value: pointer to the plugin state that will be treated as opaque
|
||||||
// by the framework and passed to the other plugin functions.
|
// by the framework and passed to the other plugin functions.
|
||||||
|
@ -118,7 +586,7 @@ typedef struct
|
||||||
// If a non-NULL ss_plugin_t* state is returned, then subsequent invocations
|
// If a non-NULL ss_plugin_t* state is returned, then subsequent invocations
|
||||||
// of init() must not return the same ss_plugin_t* value again, if not after
|
// of init() must not return the same ss_plugin_t* value again, if not after
|
||||||
// it has been disposed with destroy() first.
|
// it has been disposed with destroy() first.
|
||||||
ss_plugin_t *(*init)(const char *config, ss_plugin_rc *rc);
|
ss_plugin_t* (*init)(const ss_plugin_init_input* input, ss_plugin_rc* rc);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Destroy the plugin and, if plugin state was allocated, free it.
|
// Destroy the plugin and, if plugin state was allocated, free it.
|
||||||
|
@ -174,20 +642,32 @@ typedef struct
|
||||||
const char* (*get_version)();
|
const char* (*get_version)();
|
||||||
|
|
||||||
// Event sourcing capability API
|
// Event sourcing capability API
|
||||||
struct
|
struct {
|
||||||
{
|
|
||||||
//
|
//
|
||||||
// Return the unique ID of the plugin.
|
// Return the unique ID of the plugin.
|
||||||
// Required: yes
|
// Required: yes if get_event_source is defined and returns a non-empty string, no
|
||||||
// EVERY PLUGIN WITH EVENT SOURCING CAPABILITIES MUST OBTAIN AN OFFICIAL ID FROM THE
|
// otherwise.
|
||||||
// FALCOSECURITY ORGANIZATION, OTHERWISE IT WON'T PROPERLY COEXIST WITH OTHER PLUGINS.
|
//
|
||||||
|
// If the plugin has a specific ID and event source, then its next_batch()
|
||||||
|
// function is allowed to only return events of plugin type (code 322)
|
||||||
|
// with its own plugin ID and event source.
|
||||||
|
//
|
||||||
|
// EVERY PLUGIN WITH EVENT SOURCING CAPABILITY IMPLEMENTING
|
||||||
|
// A SPECIFIC EVENT SOURCE MUST OBTAIN AN OFFICIAL ID FROM THE
|
||||||
|
// FALCOSECURITY ORGANIZATION, OTHERWISE IT WON'T PROPERLY COEXIST
|
||||||
|
// WITH OTHER PLUGINS.
|
||||||
//
|
//
|
||||||
uint32_t (*get_id)();
|
uint32_t (*get_id)();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Return a string representing the name of the event source generated
|
// Return a string representing the name of the event source generated
|
||||||
// by this plugin.
|
// by this plugin.
|
||||||
// Required: yes
|
// Required: yes if get_id is defined and returns a non-zero number, no otherwise.
|
||||||
|
//
|
||||||
|
// If the plugin has a specific ID and event source, then its next_batch()
|
||||||
|
// function is allowed to only return events of plugin type (code 322)
|
||||||
|
// with its own plugin ID and event source.
|
||||||
|
//
|
||||||
// Example event sources would be strings like "aws_cloudtrail",
|
// Example event sources would be strings like "aws_cloudtrail",
|
||||||
// "k8s_audit", etc. The source can be used by plugins with event
|
// "k8s_audit", etc. The source can be used by plugins with event
|
||||||
// sourcing capabilities to filter the events they receive.
|
// sourcing capabilities to filter the events they receive.
|
||||||
|
@ -270,10 +750,15 @@ typedef struct
|
||||||
const char* (*get_progress)(ss_plugin_t* s, ss_instance_t* h, uint32_t* progress_pct);
|
const char* (*get_progress)(ss_plugin_t* s, ss_instance_t* h, uint32_t* progress_pct);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Return a text representation of an event generated by this plugin with event sourcing capabilities.
|
// Return a text representation of an event generated by this plugin with
|
||||||
|
// event sourcing capability. Even if defined, this function is not
|
||||||
|
// used by the framework if the plugin does not implement a specific
|
||||||
|
// event source (get_id() is zero or get_event_source() is empty).
|
||||||
|
//
|
||||||
// Required: no
|
// Required: no
|
||||||
|
//
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - evt: an event struct produced by a call to next_batch().
|
// - evt: an event input provided by the framework.
|
||||||
// This is allocated by the framework, and it is not guaranteed
|
// This is allocated by the framework, and it is not guaranteed
|
||||||
// that the event struct pointer is the same returned by the last
|
// that the event struct pointer is the same returned by the last
|
||||||
// next_batch() call.
|
// next_batch() call.
|
||||||
|
@ -288,7 +773,7 @@ typedef struct
|
||||||
// If the returned pointer is non-NULL, then it must be uniquely
|
// If the returned pointer is non-NULL, then it must be uniquely
|
||||||
// attached to the ss_plugin_t* parameter value. The pointer must not
|
// attached to the ss_plugin_t* parameter value. The pointer must not
|
||||||
// be shared across multiple distinct ss_plugin_t* values.
|
// be shared across multiple distinct ss_plugin_t* values.
|
||||||
const char* (*event_to_string)(ss_plugin_t *s, const ss_plugin_event *evt);
|
const char* (*event_to_string)(ss_plugin_t* s, const ss_plugin_event_input* evt);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Return the next batch of events.
|
// Return the next batch of events.
|
||||||
|
@ -302,27 +787,62 @@ typedef struct
|
||||||
// next_batch() or close().
|
// next_batch() or close().
|
||||||
// Required: yes
|
// Required: yes
|
||||||
//
|
//
|
||||||
|
// If a plugin implements a specific event source (get_id() is non-zero
|
||||||
|
// and get_event_source() is non-empty), then, it is only allowed to
|
||||||
|
// produce events of type plugin (code 322) containing its own plugin ID
|
||||||
|
// (as returned by get_id()). In such a case, when an event contains
|
||||||
|
// a zero plugin ID, the framework automatically sets the plugin ID of
|
||||||
|
// the event to the one of the plugin. If a plugin does not implement
|
||||||
|
// a specific event source, it is allowed to produce events of any
|
||||||
|
// of the types supported by the libscap specific.
|
||||||
|
//
|
||||||
// This function can be invoked concurrently by multiple threads,
|
// This function can be invoked concurrently by multiple threads,
|
||||||
// each with distinct and unique parameter values.
|
// each with distinct and unique parameter values.
|
||||||
// The value of the ss_plugin_event** output parameter must be uniquely
|
// The value of the ss_plugin_event** output parameter must be uniquely
|
||||||
// attached to the ss_instance_t* parameter value. The pointer must not
|
// attached to the ss_instance_t* parameter value. The pointer must not
|
||||||
// be shared across multiple distinct ss_instance_t* values.
|
// be shared across multiple distinct ss_instance_t* values.
|
||||||
ss_plugin_rc (*next_batch)(ss_plugin_t* s, ss_instance_t* h, uint32_t *nevts, ss_plugin_event **evts);
|
ss_plugin_rc (*next_batch)(ss_plugin_t* s,
|
||||||
|
ss_instance_t* h,
|
||||||
|
uint32_t* nevts,
|
||||||
|
ss_plugin_event*** evts);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Field extraction capability API
|
// Field extraction capability API
|
||||||
struct
|
struct {
|
||||||
{
|
|
||||||
//
|
//
|
||||||
// Return a string describing the event sources that this
|
// Return the list of event types that this plugin will receive
|
||||||
// plugin can consume.
|
// for field extraction. The event types follow the libscap specific.
|
||||||
|
// This will be invoked only once by the framework after the plugin's
|
||||||
|
// initialization. Events that are not included in the returned list
|
||||||
|
// will not be received by the plugin.
|
||||||
|
//
|
||||||
|
// This is a non-functional filter that should not influence the plugin's
|
||||||
|
// functional behavior. Instead, this is a performance optimization
|
||||||
|
// with the goal of avoiding unnecessary communication between the
|
||||||
|
// framework and the plugin for events that are known to be not used for
|
||||||
|
// field extraction.
|
||||||
|
//
|
||||||
|
// Required: no
|
||||||
|
//
|
||||||
|
// This function is optional--if NULL or an empty array, then:
|
||||||
|
// - the plugin will receive every event type if the result of
|
||||||
|
// get_extract_event_sources (either default or custom) is compatible
|
||||||
|
// with the "syscall" event source, otherwise
|
||||||
|
// - the plugin will only receive events of plugin type (code 322).
|
||||||
|
// todo(jasondellaluce): when/if major changes to v4, reorder the arguments
|
||||||
|
// and put ss_plugin_t* as first
|
||||||
|
uint16_t* (*get_extract_event_types)(uint32_t* numtypes, ss_plugin_t* s);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return a string describing the event sources that this plugin
|
||||||
|
// can consume for field extraction.
|
||||||
// Required: no
|
// Required: no
|
||||||
// Return value: a json array of strings containing event
|
// Return value: a json array of strings containing event
|
||||||
// sources returned by a plugin with event sourcing capabilities get_event_source()
|
// sources returned by a plugin with event sourcing capabilities get_event_source()
|
||||||
// function.
|
// function, or "syscall" for indicating support to non-plugin events.
|
||||||
// This function is optional--if NULL or an empty array, then if plugin has sourcing capability
|
// This function is optional--if NULL or an empty array, then if plugin has sourcing
|
||||||
// it will only receive events matching its event source,
|
// capability, and implements a specific event source, it will only receive events matching
|
||||||
// otherwise it will receive every event for extraction.
|
// its event source, otherwise it will receive events from all event sources.
|
||||||
//
|
//
|
||||||
const char* (*get_extract_event_sources)();
|
const char* (*get_extract_event_sources)();
|
||||||
|
|
||||||
|
@ -334,8 +854,9 @@ typedef struct
|
||||||
// array.
|
// array.
|
||||||
// Each field entry is a json object with the following properties:
|
// Each field entry is a json object with the following properties:
|
||||||
// "name": a string with a name for the field
|
// "name": a string with a name for the field
|
||||||
// "type": one of "string", "uint64"
|
// "type": one of "string", "uint64", "bool", "reltime", "abstime",
|
||||||
// "isList: (optional) If present and set to true, notes
|
// "ipaddr", "ipnet"
|
||||||
|
// "isList: (optional) if present and set to true, notes
|
||||||
// that the field extracts a list of values.
|
// that the field extracts a list of values.
|
||||||
// "arg": (optional) if present, notes that the field can accept
|
// "arg": (optional) if present, notes that the field can accept
|
||||||
// an argument e.g. field[arg]. More precisely, the following
|
// an argument e.g. field[arg]. More precisely, the following
|
||||||
|
@ -352,10 +873,13 @@ typedef struct
|
||||||
// display the field instead of the name. Used in tools
|
// display the field instead of the name. Used in tools
|
||||||
// like wireshark.
|
// like wireshark.
|
||||||
// "desc": a string with a description of the field
|
// "desc": a string with a description of the field
|
||||||
|
// "addOutput": (optional) if true, suggest this field to be appended to the
|
||||||
|
// output string for compatible event sources.
|
||||||
// Example return value:
|
// Example return value:
|
||||||
// [
|
// [
|
||||||
// {"type": "uint64", "name": "field1", "desc": "Describing field 1"},
|
// {"type": "uint64", "name": "field1", "desc": "Describing field 1", "addOutput": true},
|
||||||
// {"type": "string", "name": "field2", "arg": {"isRequired": true, "isIndex": true}, "desc": "Describing field 2"},
|
// {"type": "string", "name": "field2", "arg": {"isRequired": true, "isIndex": true},
|
||||||
|
// "desc": "Describing field 2"},
|
||||||
// ]
|
// ]
|
||||||
const char* (*get_fields)();
|
const char* (*get_fields)();
|
||||||
|
|
||||||
|
@ -363,16 +887,16 @@ typedef struct
|
||||||
// Extract one or more a filter field values from an event.
|
// Extract one or more a filter field values from an event.
|
||||||
// Required: yes
|
// Required: yes
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - evt: an event struct produced by a call to next_batch().
|
// - evt: an event input provided by the framework.
|
||||||
// This is allocated by the framework, and it is not guaranteed
|
// This is allocated by the framework, and it is not guaranteed
|
||||||
// that the event struct pointer is the same returned by the last
|
// that the event struct pointer is the same returned by the last
|
||||||
// next_batch() call.
|
// next_batch() call.
|
||||||
// - num_fields: the length of the fields array.
|
// - in: An input struct representing the extraction request.
|
||||||
// - fields: an array of ss_plugin_extract_field structs. Each entry
|
// The input includes vtables containing callbacks that can be used by
|
||||||
// contains a single field + optional argument as input, and the corresponding
|
// the plugin for performing read/write operations on a state table
|
||||||
// extracted value as output. Memory pointers set as output must be allocated
|
// not owned by itelf, for which it obtained accessors at init time.
|
||||||
// by the plugin and must not be deallocated or modified until the next
|
// The plugin does not need to go through this vtable in order
|
||||||
// extract_fields() call.
|
// to read and write from a table it owns.
|
||||||
//
|
//
|
||||||
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||||
//
|
//
|
||||||
|
@ -381,7 +905,231 @@ typedef struct
|
||||||
// The value of the ss_plugin_extract_field* output parameter must be
|
// The value of the ss_plugin_extract_field* output parameter must be
|
||||||
// uniquely attached to the ss_plugin_t* parameter value. The pointer
|
// uniquely attached to the ss_plugin_t* parameter value. The pointer
|
||||||
// must not be shared across multiple distinct ss_plugin_t* values.
|
// must not be shared across multiple distinct ss_plugin_t* values.
|
||||||
ss_plugin_rc (*extract_fields)(ss_plugin_t *s, const ss_plugin_event *evt, uint32_t num_fields, ss_plugin_extract_field *fields);
|
ss_plugin_rc (*extract_fields)(ss_plugin_t* s,
|
||||||
|
const ss_plugin_event_input* evt,
|
||||||
|
const ss_plugin_field_extract_input* in);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Event parsing capability API
|
||||||
|
struct {
|
||||||
|
//
|
||||||
|
// Return the list of event types that this plugin will receive
|
||||||
|
// for event parsing. The event types follow the libscap specific.
|
||||||
|
// This will be invoked only once by the framework after the plugin's
|
||||||
|
// initialization. Events that are not included in the returned list
|
||||||
|
// will not be received by the plugin.
|
||||||
|
//
|
||||||
|
// This is a non-functional filter that should not influence the plugin's
|
||||||
|
// functional behavior. Instead, this is a performance optimization
|
||||||
|
// with the goal of avoiding unnecessary communication between the
|
||||||
|
// framework and the plugin for events that are known to be not used for
|
||||||
|
// event parsing.
|
||||||
|
//
|
||||||
|
// Required: no
|
||||||
|
//
|
||||||
|
// This function is optional--if NULL or an empty array, then:
|
||||||
|
// - the plugin will receive every event type if the result of
|
||||||
|
// get_parse_event_sources (either default or custom) is compatible
|
||||||
|
// with the "syscall" event source, otherwise
|
||||||
|
// - the plugin will only receive events of plugin type (code 322).
|
||||||
|
// todo(jasondellaluce): when/if major changes to v4, reorder the arguments
|
||||||
|
// and put ss_plugin_t* as first
|
||||||
|
uint16_t* (*get_parse_event_types)(uint32_t* numtypes, ss_plugin_t* s);
|
||||||
|
//
|
||||||
|
// Return a string describing the event sources that this plugin
|
||||||
|
// is capable of parsing.
|
||||||
|
//
|
||||||
|
// Required: no
|
||||||
|
//
|
||||||
|
// Return value: a json array of strings containing event
|
||||||
|
// sources returned by a plugin with event sourcing capabilities get_event_source()
|
||||||
|
// function, or "syscall" for indicating support to non-plugin events.
|
||||||
|
// This function is optional--if NULL or an empty array, then if plugin has sourcing
|
||||||
|
// capability, and implements a specific event source, it will only receive events matching
|
||||||
|
// its event source, otherwise it will receive events from all event sources.
|
||||||
|
//
|
||||||
|
const char* (*get_parse_event_sources)();
|
||||||
|
//
|
||||||
|
// Receives an event from the current capture and parses its content.
|
||||||
|
// The plugin is guaranteed to receive an event at most once, after any
|
||||||
|
// operation related the event sourcing capability, and before
|
||||||
|
// any operation related to the field extraction capability.
|
||||||
|
//
|
||||||
|
// Required: yes
|
||||||
|
//
|
||||||
|
// Arguments:
|
||||||
|
// - evt: an event input provided by the framework.
|
||||||
|
// This is allocated by the framework, and it is not guaranteed
|
||||||
|
// that the event struct pointer is the same returned by the last
|
||||||
|
// next_batch() call.
|
||||||
|
// - in: A vtable containing callbacks that can be used by
|
||||||
|
// the plugin for performing read/write operations on a state table
|
||||||
|
// not owned by itelf, for which it obtained accessors at init time.
|
||||||
|
// The plugin does not need to go through this vtable in order
|
||||||
|
// to read and write from a table it owns.
|
||||||
|
//
|
||||||
|
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||||
|
//
|
||||||
|
// This function can be invoked concurrently by multiple threads,
|
||||||
|
// each with distinct and unique parameter values.
|
||||||
|
// The value of the ss_plugin_event_parse_input* output parameter must be
|
||||||
|
// uniquely attached to the ss_plugin_t* parameter value. The pointer
|
||||||
|
// must not be shared across multiple distinct ss_plugin_t* values.
|
||||||
|
ss_plugin_rc (*parse_event)(ss_plugin_t* s,
|
||||||
|
const ss_plugin_event_input* evt,
|
||||||
|
const ss_plugin_event_parse_input* in);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Async events capability API
|
||||||
|
struct {
|
||||||
|
//
|
||||||
|
// Return a string describing the event sources for which this plugin
|
||||||
|
// is capable of injecting async events in the event stream of a capture.
|
||||||
|
//
|
||||||
|
// Required: no
|
||||||
|
//
|
||||||
|
// Return value: a json array of strings containing event
|
||||||
|
// sources returned by a plugin with event sourcing capabilities
|
||||||
|
// get_event_source() function, or "syscall" for indicating
|
||||||
|
// support to non-plugin events.
|
||||||
|
// This function is optional--if NULL or an empty array, then async
|
||||||
|
// events produced by this plugin will be injected in the event stream
|
||||||
|
// of any data source.
|
||||||
|
//
|
||||||
|
const char* (*get_async_event_sources)();
|
||||||
|
//
|
||||||
|
// Return a string describing the name list of all asynchronous events
|
||||||
|
// that this plugin is capable of pushing into a live event stream.
|
||||||
|
// The framework rejects async events produced by a plugin if their
|
||||||
|
// name is not on the name list returned by this function.
|
||||||
|
//
|
||||||
|
// Required: yes
|
||||||
|
//
|
||||||
|
// Return value: a non-empty json array of strings containing the
|
||||||
|
// names of the async events returned by a plugin.
|
||||||
|
const char* (*get_async_events)();
|
||||||
|
//
|
||||||
|
// Sets a function handler that allows the plugin to send asynchronous
|
||||||
|
// events to its owner during a live event capture. The handler is
|
||||||
|
// a thread-safe function that can be invoked concurrently by
|
||||||
|
// multiple threads. The asynchronous events must be encoded as
|
||||||
|
// an async event type (code 402) as for the libscap specific.
|
||||||
|
//
|
||||||
|
// The plugin can start sending async events through the passed-in
|
||||||
|
// handler right after returning from this function.
|
||||||
|
// set_async_event_handler() can be invoked multiple times during the
|
||||||
|
// lifetime of a plugin. In that case, the registered function handler
|
||||||
|
// remains valid up until the next invocation of set_async_event_handler()
|
||||||
|
// on the same plugin, after which the new handler set will replace any
|
||||||
|
// already-set one. If the handler is set to a NULL function pointer,
|
||||||
|
// the plugin is instructed about disabling or stopping the
|
||||||
|
// production of async events. If a NULL handler is set, and an
|
||||||
|
// asynchronous job has been started by the plugin before, the plugin
|
||||||
|
// should stop the job and wait for it to be finished before returning
|
||||||
|
// from this function. Although the event handler is thread-safe and
|
||||||
|
// can be invoked concurrently, this function is still invoked
|
||||||
|
// by the framework sequentially from the same thread.
|
||||||
|
//
|
||||||
|
// Async events encode a plugin ID that defines its event source.
|
||||||
|
// However, this value is set by the framework when the async event
|
||||||
|
// is received, and is set to the ID associated to the plugin-defined
|
||||||
|
// event source currently open during a live capture, or zero in case
|
||||||
|
// of the "syscall" event source. The event source assigned by the
|
||||||
|
// framework to the async event can only be among the ones compatible
|
||||||
|
// with the list returned by get_async_event_sources().
|
||||||
|
//
|
||||||
|
// Async events encode a string representing their event name, which is
|
||||||
|
// used for runtime matching and define the encoded data payload.
|
||||||
|
// Plugins are allowed to only send async events with one of the names
|
||||||
|
// expressed in the list returned by get_async_events(). The name
|
||||||
|
// of an async event acts as a contract on the encoding of the data
|
||||||
|
// payload of all async events with the same name.
|
||||||
|
//
|
||||||
|
// Required: yes
|
||||||
|
//
|
||||||
|
// Arguments:
|
||||||
|
// - owner: Opaque pointer to the plugin's owner. Must be passed
|
||||||
|
// as an argument to the async event function handler.
|
||||||
|
// - handler: Function handler to be used for sending asynchronous
|
||||||
|
// events to the plugin's owner. The handler must be invoked with
|
||||||
|
// the same owner opaque pointer passed to this function, and with
|
||||||
|
// an event pointer owned and controlled by the plugin. The event
|
||||||
|
// pointer is not retained by the handler after it returns.
|
||||||
|
//
|
||||||
|
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||||
|
//
|
||||||
|
ss_plugin_rc (*set_async_event_handler)(ss_plugin_t* s,
|
||||||
|
ss_plugin_owner_t* owner,
|
||||||
|
const ss_plugin_async_event_handler_t handler);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Called by the framework when a capture file dump is requested.
|
||||||
|
//
|
||||||
|
// Required: no
|
||||||
|
// Arguments:
|
||||||
|
// - s: the plugin state, returned by init(). Can be NULL.
|
||||||
|
// - owner: Opaque pointer to the plugin's owner. Must be passed
|
||||||
|
// as an argument to the async event function handler.
|
||||||
|
// - handler: Function handler to be used for sending events to be dumped
|
||||||
|
// to the plugin's owner. The handler must be invoked with
|
||||||
|
// the same owner opaque pointer passed to this function, and with
|
||||||
|
// an event pointer owned and controlled by the plugin. The event
|
||||||
|
// pointer is not retained by the handler after it returns.
|
||||||
|
//
|
||||||
|
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||||
|
ss_plugin_rc (*dump_state)(ss_plugin_t* s,
|
||||||
|
ss_plugin_owner_t* owner,
|
||||||
|
const ss_plugin_async_event_handler_t handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sets a new plugin configuration when provided by the framework.
|
||||||
|
// Required: no
|
||||||
|
// Arguments:
|
||||||
|
// - s: the plugin state, returned by init(). Can be NULL.
|
||||||
|
// - i: configuration input provided by the framework.
|
||||||
|
//
|
||||||
|
// Return value: A ss_plugin_rc with value SS_PLUGIN_SUCCESS if the config is accepted
|
||||||
|
// or SS_PLUGIN_FAILURE if the config is rejected.
|
||||||
|
// If rejected the plugin should provide context in the string returned by get_last_error().
|
||||||
|
ss_plugin_rc (*set_config)(ss_plugin_t* s, const ss_plugin_set_config_input* i);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return an updated set of metrics provided by this plugin.
|
||||||
|
// Required: no
|
||||||
|
// Arguments:
|
||||||
|
// - s: the plugin state, returned by init(). Can be NULL.
|
||||||
|
// - num_metrics: lenght of the returned metrics array.
|
||||||
|
//
|
||||||
|
// Return value: Pointer to the first element of the metrics array.
|
||||||
|
// 'num_metrics' must be set to the lenght of the array before returning
|
||||||
|
// and it can be set to 0 if no metrics are provided.
|
||||||
|
ss_plugin_metric* (*get_metrics)(ss_plugin_t* s, uint32_t* num_metrics);
|
||||||
|
|
||||||
|
// Capture listening capability API
|
||||||
|
struct {
|
||||||
|
//
|
||||||
|
// Called by the framework when the event capture opens.
|
||||||
|
//
|
||||||
|
// Required: no
|
||||||
|
// Arguments:
|
||||||
|
// - s: the plugin state, returned by init(). Can be NULL.
|
||||||
|
// - i: input containing vtables for performing table operations and subscribe/unsubscribe
|
||||||
|
// async routines
|
||||||
|
//
|
||||||
|
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||||
|
ss_plugin_rc (*capture_open)(ss_plugin_t* s, const ss_plugin_capture_listen_input* i);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Called by the framework when the event capture closes.
|
||||||
|
//
|
||||||
|
// Required: yes if capture_open is defined
|
||||||
|
// Arguments:
|
||||||
|
// - s: the plugin state, returned by init(). Can be NULL.
|
||||||
|
// - i: input containing vtables for performing table operations and subscribe/unsubscribe
|
||||||
|
// async routines
|
||||||
|
//
|
||||||
|
// Return value: A ss_plugin_rc with values SS_PLUGIN_SUCCESS or SS_PLUGIN_FAILURE.
|
||||||
|
ss_plugin_rc (*capture_close)(ss_plugin_t* s, const ss_plugin_capture_listen_input* i);
|
||||||
};
|
};
|
||||||
} plugin_api;
|
} plugin_api;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -21,21 +22,36 @@ limitations under the License.
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
// An implementation-independent representation of boolean.
|
||||||
|
// A 4-byte representation is equal to how bools are encoded in falcosecurity libs.
|
||||||
|
typedef uint32_t ss_plugin_bool;
|
||||||
|
|
||||||
// The noncontinguous numbers are to maintain equality with underlying
|
// The noncontinguous numbers are to maintain equality with underlying
|
||||||
// falcosecurity libs types.
|
// falcosecurity libs types.
|
||||||
typedef enum ss_plugin_field_type
|
typedef enum ss_plugin_field_type {
|
||||||
{
|
// A 64bit unsigned integer.
|
||||||
FTYPE_UINT64 = 8,
|
FTYPE_UINT64 = 8,
|
||||||
FTYPE_STRING = 9
|
// A printable buffer of bytes, NULL terminated
|
||||||
|
FTYPE_STRING = 9,
|
||||||
|
// A relative time. Seconds * 10^9 + nanoseconds. 64bit.
|
||||||
|
FTYPE_RELTIME = 20,
|
||||||
|
// An absolute time interval. Seconds from epoch * 10^9 + nanoseconds. 64bit.
|
||||||
|
FTYPE_ABSTIME = 21,
|
||||||
|
// A boolean value, 4 bytes.
|
||||||
|
FTYPE_BOOL = 25,
|
||||||
|
// Either an IPv4 or IPv6 address. The length indicates which one it is.
|
||||||
|
FTYPE_IPADDR = 40,
|
||||||
|
// Either an IPv4 or IPv6 network. The length indicates which one it is.
|
||||||
|
// The field encodes only the IP address, so this differs from FTYPE_IPADDR,
|
||||||
|
// from the way the framework perform runtime checks and comparisons.
|
||||||
|
FTYPE_IPNET = 41,
|
||||||
} ss_plugin_field_type;
|
} ss_plugin_field_type;
|
||||||
|
|
||||||
// Values to return from init() / open() / next_batch() /
|
// Values to return from init() / open() / next_batch() /
|
||||||
// extract_fields().
|
// extract_fields().
|
||||||
typedef enum ss_plugin_rc
|
typedef enum ss_plugin_rc {
|
||||||
{
|
|
||||||
SS_PLUGIN_SUCCESS = 0,
|
SS_PLUGIN_SUCCESS = 0,
|
||||||
SS_PLUGIN_FAILURE = 1,
|
SS_PLUGIN_FAILURE = 1,
|
||||||
SS_PLUGIN_TIMEOUT = -1,
|
SS_PLUGIN_TIMEOUT = -1,
|
||||||
|
@ -44,8 +60,7 @@ typedef enum ss_plugin_rc
|
||||||
} ss_plugin_rc;
|
} ss_plugin_rc;
|
||||||
|
|
||||||
// The supported schema formats for the init configuration.
|
// The supported schema formats for the init configuration.
|
||||||
typedef enum ss_plugin_schema_type
|
typedef enum ss_plugin_schema_type {
|
||||||
{
|
|
||||||
// The schema is undefined and the init configuration
|
// The schema is undefined and the init configuration
|
||||||
// is an opaque string.
|
// is an opaque string.
|
||||||
SS_PLUGIN_SCHEMA_NONE = 0,
|
SS_PLUGIN_SCHEMA_NONE = 0,
|
||||||
|
@ -57,26 +72,75 @@ typedef enum ss_plugin_schema_type
|
||||||
} ss_plugin_schema_type;
|
} ss_plugin_schema_type;
|
||||||
|
|
||||||
// This struct represents an event returned by the plugin, and is used
|
// This struct represents an event returned by the plugin, and is used
|
||||||
// below in next_batch().
|
// below in next_batch(). It observes the event specifics of libscap.
|
||||||
// - evtnum: incremented for each event returned. Might not be contiguous.
|
// An event is represented as a contiguous region of memory composed by
|
||||||
// - data: pointer to a memory buffer pointer. The plugin will set it
|
// a header and a list of parameters appended, in the form of:
|
||||||
// to point to the memory containing the next event.
|
|
||||||
// - datalen: pointer to a 32bit integer. The plugin will set it the size of the
|
|
||||||
// buffer pointed by data.
|
|
||||||
// - ts: the event timestamp, in nanoseconds since the epoch.
|
|
||||||
// Can be (uint64_t)-1, in which case the engine will automatically
|
|
||||||
// fill the event time with the current time.
|
|
||||||
//
|
//
|
||||||
// Note: event numbers are assigned by the plugin
|
// | evt header | len param 1 (2B/4B) | ... | len param N (2B/4B) | data param 1 | ... | data param
|
||||||
// framework. Therefore, there isn't any need to fill in evtnum when
|
// N |
|
||||||
// returning an event via plugin_next_batch. It will be ignored.
|
//
|
||||||
typedef struct ss_plugin_event
|
// The event header is composed of:
|
||||||
{
|
// - ts: the event timestamp, in nanoseconds since the epoch.
|
||||||
|
// Can be (uint64_t)-1, in which case the framework will automatically
|
||||||
|
// fill the event time with the current time.
|
||||||
|
// - tid: the tid of the thread that generated this event.
|
||||||
|
// Can be (uint64_t)-1 in case no thread is specified, such as when generating
|
||||||
|
// a plugin event (type code 322).
|
||||||
|
// - len: the event len, including the header
|
||||||
|
// - type: the type of the event, as per the ones supported by the libscap specifics.
|
||||||
|
// This dictates the number and kind of parameters, and whether the lenght is
|
||||||
|
// encoded as a 2 bytes or 4 bytes integer.
|
||||||
|
// - nparams: the number of parameters of the event
|
||||||
|
#if defined _MSC_VER
|
||||||
|
#pragma pack(push)
|
||||||
|
#pragma pack(1)
|
||||||
|
#else
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
#endif
|
||||||
|
struct ss_plugin_event {
|
||||||
|
#ifdef PPM_ENABLE_SENTINEL
|
||||||
|
uint32_t sentinel_begin;
|
||||||
|
#endif
|
||||||
|
uint64_t ts; /* timestamp, in nanoseconds from epoch */
|
||||||
|
uint64_t tid; /* the tid of the thread that generated this event */
|
||||||
|
uint32_t len; /* the event len, including the header */
|
||||||
|
uint16_t type; /* the event type */
|
||||||
|
uint32_t nparams; /* the number of parameters of the event */
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
typedef struct ss_plugin_event ss_plugin_event;
|
||||||
|
|
||||||
|
// This struct represents an event provided by the framework to the plugin
|
||||||
|
// as a read-only input.
|
||||||
|
// - evt: a pointer to the header of the provided event.
|
||||||
|
// - evtnum: assigned by the framework and incremented for each event.
|
||||||
|
// Might not be contiguous.
|
||||||
|
// - evtsrc: The name of the event's source. Can be "syscall" or any other
|
||||||
|
// event source name implemented by a plugin.
|
||||||
|
typedef struct ss_plugin_event_input {
|
||||||
|
const ss_plugin_event* evt;
|
||||||
uint64_t evtnum;
|
uint64_t evtnum;
|
||||||
const uint8_t *data;
|
const char* evtsrc;
|
||||||
uint32_t datalen;
|
} ss_plugin_event_input;
|
||||||
uint64_t ts;
|
|
||||||
} ss_plugin_event;
|
typedef struct ss_plugin_byte_buffer {
|
||||||
|
uint32_t len;
|
||||||
|
const void* ptr;
|
||||||
|
} ss_plugin_byte_buffer;
|
||||||
|
|
||||||
|
// Used in extract_fields_and_offsets to receive field value offsets
|
||||||
|
// along with field data.
|
||||||
|
// Extraction functions that support offsets should be set these to an
|
||||||
|
// array of zero-indexed start offsets and lengths of each returned
|
||||||
|
// value in the event or log data. {0, 0} can be used to indicate that
|
||||||
|
// there are no valid offsets, e.g. if the value was generated or
|
||||||
|
// computed from other data.
|
||||||
|
// Extraction functions might not support offsets. In order to detect
|
||||||
|
// this, callers should initialize the start and length to nullptr.
|
||||||
|
typedef struct ss_plugin_extract_value_offsets {
|
||||||
|
uint32_t* start;
|
||||||
|
uint32_t* length;
|
||||||
|
} ss_plugin_extract_value_offsets;
|
||||||
|
|
||||||
// Used in extract_fields functions below to receive a field/arg
|
// Used in extract_fields functions below to receive a field/arg
|
||||||
// pair and return an extracted value.
|
// pair and return an extracted value.
|
||||||
|
@ -116,16 +180,17 @@ typedef struct ss_plugin_event
|
||||||
// If the field is a list type, then res_len can must be any value from 0 to N, depending
|
// If the field is a list type, then res_len can must be any value from 0 to N, depending
|
||||||
// on how many values can be extracted from a given event.
|
// on how many values can be extracted from a given event.
|
||||||
// Setting res_len to 0 means that no value of this field can be extracted from a given event.
|
// Setting res_len to 0 means that no value of this field can be extracted from a given event.
|
||||||
typedef struct ss_plugin_extract_field
|
typedef struct ss_plugin_extract_field {
|
||||||
{
|
|
||||||
// NOTE: For a given architecture, this has always the same size which
|
// NOTE: For a given architecture, this has always the same size which
|
||||||
// is sizeof(uintptr_t). Adding new value types will not create breaking
|
// is sizeof(uintptr_t). Adding new value types will not create breaking
|
||||||
// changes in the plugin API. However, we must make sure that each added
|
// changes in the plugin API. However, we must make sure that each added
|
||||||
// type is always a pointer.
|
// type is always a pointer.
|
||||||
union
|
union {
|
||||||
{
|
|
||||||
const char** str;
|
const char** str;
|
||||||
uint64_t* u64;
|
uint64_t* u64;
|
||||||
|
uint32_t* u32;
|
||||||
|
ss_plugin_bool* boolean;
|
||||||
|
ss_plugin_byte_buffer* buf;
|
||||||
} res;
|
} res;
|
||||||
uint64_t res_len;
|
uint64_t res_len;
|
||||||
|
|
||||||
|
@ -136,16 +201,77 @@ typedef struct ss_plugin_extract_field
|
||||||
const char* field;
|
const char* field;
|
||||||
const char* arg_key;
|
const char* arg_key;
|
||||||
uint64_t arg_index;
|
uint64_t arg_index;
|
||||||
bool arg_present;
|
ss_plugin_bool arg_present;
|
||||||
uint32_t ftype;
|
uint32_t ftype;
|
||||||
bool flist;
|
ss_plugin_bool flist;
|
||||||
} ss_plugin_extract_field;
|
} ss_plugin_extract_field;
|
||||||
|
|
||||||
|
// Opaque a pointer to a state table. The falcosecurity libs define stateful
|
||||||
|
// components in the form of tables.
|
||||||
|
typedef void ss_plugin_table_t;
|
||||||
|
|
||||||
|
// Opaque a pointer to an entry of a state table.
|
||||||
|
typedef void ss_plugin_table_entry_t;
|
||||||
|
|
||||||
|
// Opaque accessor to a data field available in the entries of a state table.
|
||||||
|
typedef void ss_plugin_table_field_t;
|
||||||
|
|
||||||
|
// Types supported by entry fields of state tables.
|
||||||
|
// The noncontinguous numbers are to maintain equality with underlying
|
||||||
|
// falcosecurity libs types.
|
||||||
|
// todo(jasondellaluce): should we merge this with ss_plugin_field_type?
|
||||||
|
typedef enum ss_plugin_state_type {
|
||||||
|
SS_PLUGIN_ST_INT8 = 1,
|
||||||
|
SS_PLUGIN_ST_INT16 = 2,
|
||||||
|
SS_PLUGIN_ST_INT32 = 3,
|
||||||
|
SS_PLUGIN_ST_INT64 = 4,
|
||||||
|
SS_PLUGIN_ST_UINT8 = 5,
|
||||||
|
SS_PLUGIN_ST_UINT16 = 6,
|
||||||
|
SS_PLUGIN_ST_UINT32 = 7,
|
||||||
|
SS_PLUGIN_ST_UINT64 = 8,
|
||||||
|
SS_PLUGIN_ST_STRING = 9,
|
||||||
|
SS_PLUGIN_ST_TABLE = 10,
|
||||||
|
SS_PLUGIN_ST_BOOL = 25
|
||||||
|
} ss_plugin_state_type;
|
||||||
|
|
||||||
|
// Data representation of entry fields of state tables.
|
||||||
|
// todo(jasondellaluce): should we merge this with what we have for field extraction?
|
||||||
|
typedef union ss_plugin_state_data {
|
||||||
|
int8_t s8;
|
||||||
|
int16_t s16;
|
||||||
|
int32_t s32;
|
||||||
|
int64_t s64;
|
||||||
|
uint8_t u8;
|
||||||
|
uint16_t u16;
|
||||||
|
uint32_t u32;
|
||||||
|
uint64_t u64;
|
||||||
|
const char* str;
|
||||||
|
ss_plugin_bool b;
|
||||||
|
ss_plugin_table_t* table;
|
||||||
|
} ss_plugin_state_data;
|
||||||
|
|
||||||
|
// Info about a state table.
|
||||||
|
typedef struct ss_plugin_table_info {
|
||||||
|
const char* name;
|
||||||
|
ss_plugin_state_type key_type;
|
||||||
|
} ss_plugin_table_info;
|
||||||
|
|
||||||
|
// Info about a data field contained in the entires of a state table.
|
||||||
|
typedef struct ss_plugin_table_fieldinfo {
|
||||||
|
const char* name;
|
||||||
|
ss_plugin_state_type field_type;
|
||||||
|
ss_plugin_bool read_only;
|
||||||
|
} ss_plugin_table_fieldinfo;
|
||||||
|
|
||||||
|
// Opaque pointer to the owner of a plugin. It can be used to invert the
|
||||||
|
// control and invoke functions of the plugin's owner from within the plugin.
|
||||||
|
typedef void ss_plugin_owner_t;
|
||||||
|
|
||||||
//
|
//
|
||||||
// This is the opaque pointer to the state of a plugin.
|
// This is the opaque pointer to the state of a plugin.
|
||||||
// It points to any data that might be needed plugin-wise. It is
|
// It points to any data that might be needed plugin-wise. It is
|
||||||
// allocated by init() and must be destroyed by destroy().
|
// allocated by init() and must be destroyed by destroy().
|
||||||
// It is defined as void because the engine doesn't care what it is
|
// It is defined as void because the framework doesn't care what it is
|
||||||
// and it treats is as opaque.
|
// and it treats is as opaque.
|
||||||
//
|
//
|
||||||
typedef void ss_plugin_t;
|
typedef void ss_plugin_t;
|
||||||
|
@ -155,11 +281,69 @@ typedef void ss_plugin_t;
|
||||||
// plugin.
|
// plugin.
|
||||||
// It points to any data that is needed while a capture is running. It is
|
// It points to any data that is needed while a capture is running. It is
|
||||||
// allocated by open() and must be destroyed by close().
|
// allocated by open() and must be destroyed by close().
|
||||||
// It is defined as void because the engine doesn't care what it is
|
// It is defined as void because the framework doesn't care what it is
|
||||||
// and it treats is as opaque.
|
// and it treats is as opaque.
|
||||||
//
|
//
|
||||||
typedef void ss_instance_t;
|
typedef void ss_instance_t;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Severity available in the logging facility provided by the framework
|
||||||
|
typedef enum ss_plugin_log_severity {
|
||||||
|
SS_PLUGIN_LOG_SEV_FATAL = 1,
|
||||||
|
SS_PLUGIN_LOG_SEV_CRITICAL = 2,
|
||||||
|
SS_PLUGIN_LOG_SEV_ERROR = 3,
|
||||||
|
SS_PLUGIN_LOG_SEV_WARNING = 4,
|
||||||
|
SS_PLUGIN_LOG_SEV_NOTICE = 5,
|
||||||
|
SS_PLUGIN_LOG_SEV_INFO = 6,
|
||||||
|
SS_PLUGIN_LOG_SEV_DEBUG = 7,
|
||||||
|
SS_PLUGIN_LOG_SEV_TRACE = 8,
|
||||||
|
} ss_plugin_log_severity;
|
||||||
|
|
||||||
|
// Types supported by the by the metric values
|
||||||
|
typedef enum ss_plugin_metric_value_type {
|
||||||
|
SS_PLUGIN_METRIC_VALUE_TYPE_U32 = 0,
|
||||||
|
SS_PLUGIN_METRIC_VALUE_TYPE_S32 = 1,
|
||||||
|
SS_PLUGIN_METRIC_VALUE_TYPE_U64 = 2,
|
||||||
|
SS_PLUGIN_METRIC_VALUE_TYPE_S64 = 3,
|
||||||
|
SS_PLUGIN_METRIC_VALUE_TYPE_D = 4,
|
||||||
|
SS_PLUGIN_METRIC_VALUE_TYPE_F = 5,
|
||||||
|
SS_PLUGIN_METRIC_VALUE_TYPE_I = 6,
|
||||||
|
} ss_plugin_metric_value_type;
|
||||||
|
|
||||||
|
// Data representation of metric values
|
||||||
|
typedef union ss_plugin_metric_value {
|
||||||
|
uint32_t u32;
|
||||||
|
int32_t s32;
|
||||||
|
uint64_t u64;
|
||||||
|
int64_t s64;
|
||||||
|
double d;
|
||||||
|
float f;
|
||||||
|
int i;
|
||||||
|
} ss_plugin_metric_value;
|
||||||
|
|
||||||
|
// Metric types
|
||||||
|
typedef enum ss_plugin_metric_type {
|
||||||
|
SS_PLUGIN_METRIC_TYPE_MONOTONIC = 0,
|
||||||
|
SS_PLUGIN_METRIC_TYPE_NON_MONOTONIC = 1,
|
||||||
|
} ss_plugin_metric_type;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Struct representing a metric to be provided to the plugin framework
|
||||||
|
typedef struct ss_plugin_metric {
|
||||||
|
//
|
||||||
|
// Opaque string representing the metric name
|
||||||
|
const char* name;
|
||||||
|
//
|
||||||
|
// Metric type
|
||||||
|
ss_plugin_metric_type type;
|
||||||
|
//
|
||||||
|
// Metric numeric value
|
||||||
|
ss_plugin_metric_value value;
|
||||||
|
//
|
||||||
|
// Metric value data type
|
||||||
|
ss_plugin_metric_value_type value_type;
|
||||||
|
} ss_plugin_metric;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,13 @@
|
||||||
|
diff --git a/pkg/sdk/plugin_api.h b/pkg/sdk/plugin_api.h
|
||||||
|
index 0c877a2..54949b3 100644
|
||||||
|
--- a/pkg/sdk/plugin_api.h
|
||||||
|
+++ b/pkg/sdk/plugin_api.h
|
||||||
|
@@ -18,7 +18,7 @@ limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
-#include <plugin/plugin_types.h>
|
||||||
|
+#include "plugin_types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -54,6 +55,9 @@ func (m *testPlugin) Extract(req sdk.ExtractRequest, evt sdk.EventReader) error
|
||||||
switch req.FieldID() {
|
switch req.FieldID() {
|
||||||
case 0:
|
case 0:
|
||||||
req.SetValue(uint64(0))
|
req.SetValue(uint64(0))
|
||||||
|
if req.WantOffset() {
|
||||||
|
req.SetValueOffset(sdk.PluginEventPayloadOffset, 8)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported field: %s", req.Field())
|
return fmt.Errorf("unsupported field: %s", req.Field())
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
|
||||||
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -48,10 +50,22 @@ const DefaultEvtSize uint32 = 256 * 1024
|
||||||
const DefaultBatchSize uint32 = 128
|
const DefaultBatchSize uint32 = 128
|
||||||
|
|
||||||
// The full set of values that can be returned in the ftype
|
// The full set of values that can be returned in the ftype
|
||||||
// member of ss_plugin_extract_field structs.
|
// member of ss_plugin_extract_field structs (ppm_events_public.h).
|
||||||
const (
|
const (
|
||||||
|
// A 64bit unsigned integer.
|
||||||
FieldTypeUint64 uint32 = 8
|
FieldTypeUint64 uint32 = 8
|
||||||
FieldTypeCharBuf uint32 = 9 // A printable buffer of bytes, NULL terminated
|
// A printable buffer of bytes, NULL terminated.
|
||||||
|
FieldTypeCharBuf uint32 = 9
|
||||||
|
// A relative time. Seconds * 10^9 + nanoseconds. 64bit.
|
||||||
|
FieldTypeRelTime uint32 = 20
|
||||||
|
// An absolute time interval. Seconds from epoch * 10^9 + nanoseconds. 64bit.
|
||||||
|
FieldTypeAbsTime uint32 = 21
|
||||||
|
// A boolean value, 4 bytes.
|
||||||
|
FieldTypeBool uint32 = 25
|
||||||
|
// Either an IPv4 or IPv6 address. The length indicates which one it is.
|
||||||
|
FieldTypeIPAddr uint32 = 40
|
||||||
|
// Either an IPv4 or IPv6 network. The length indicates which one it is.
|
||||||
|
FieldTypeIPNet uint32 = 41
|
||||||
)
|
)
|
||||||
|
|
||||||
// FieldEntry represents a single field entry that a plugin with field extraction
|
// FieldEntry represents a single field entry that a plugin with field extraction
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -38,7 +39,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
//export plugin_event_to_string
|
//export plugin_event_to_string
|
||||||
func plugin_event_to_string(pState C.uintptr_t, evt *C.ss_plugin_event) *C.char {
|
func plugin_event_to_string(pState C.uintptr_t, evt *C.ss_plugin_event_input) *C.char {
|
||||||
buf := cgo.Handle(pState).Value().(sdk.StringerBuffer).StringerBuffer()
|
buf := cgo.Handle(pState).Value().(sdk.StringerBuffer).StringerBuffer()
|
||||||
stringer, ok := cgo.Handle(pState).Value().(sdk.Stringer)
|
stringer, ok := cgo.Handle(pState).Value().(sdk.Stringer)
|
||||||
if ok {
|
if ok {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -39,15 +40,16 @@ type sampleEvtStr struct {
|
||||||
expectedData []byte
|
expectedData []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event, func()) {
|
func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event_input, func()) {
|
||||||
ret := &_Ctype_struct_ss_plugin_event{}
|
ret := &_Ctype_struct_ss_plugin_event_input{}
|
||||||
|
evts, _ := sdk.NewEventWriters(1, int64(len(data)))
|
||||||
|
evt := evts.Get(0)
|
||||||
|
evt.Writer().Write(data)
|
||||||
|
ret.evt = *(**_Ctype_struct_ss_plugin_event)(evts.ArrayPtr())
|
||||||
ret.evtnum = _Ctype_uint64_t(num)
|
ret.evtnum = _Ctype_uint64_t(num)
|
||||||
ret.ts = _Ctype_uint64_t(ts)
|
|
||||||
ret.data = (*_Ctype_uint8_t)(&data[0])
|
|
||||||
ret.datalen = _Ctype_uint32_t(len(data))
|
|
||||||
|
|
||||||
return ret, func() {
|
return ret, func() {
|
||||||
// nothing to deallocate here
|
evts.Free()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -91,6 +92,10 @@ const (
|
||||||
// asyncBatchSize is the physical size of batches allocated
|
// asyncBatchSize is the physical size of batches allocated
|
||||||
// in C memory, namely the total number of locks available
|
// in C memory, namely the total number of locks available
|
||||||
asyncBatchSize = cgo.MaxHandle + 1
|
asyncBatchSize = cgo.MaxHandle + 1
|
||||||
|
//
|
||||||
|
// max number of seconds we're willing to wait for a worker to exit
|
||||||
|
// once released before triggering a panic
|
||||||
|
workerReleaseTimeoutInSeconds = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -185,7 +190,9 @@ func (a *asyncContext) acquireWorker(workerIdx int32) {
|
||||||
for _, i := range batchIdxs {
|
for _, i := range batchIdxs {
|
||||||
// reduce sync overhead by skipping unused batch slots
|
// reduce sync overhead by skipping unused batch slots
|
||||||
if i > a.maxBatchIdx {
|
if i > a.maxBatchIdx {
|
||||||
continue
|
// from this point on we'll only encountered unused slots
|
||||||
|
// so we mind as well just start over
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for incoming request, if any, otherwise busy waits
|
// check for incoming request, if any, otherwise busy waits
|
||||||
|
@ -199,6 +206,7 @@ func (a *asyncContext) acquireWorker(workerIdx int32) {
|
||||||
a.batch[i].evt,
|
a.batch[i].evt,
|
||||||
uint32(a.batch[i].num_fields),
|
uint32(a.batch[i].num_fields),
|
||||||
a.batch[i].fields,
|
a.batch[i].fields,
|
||||||
|
a.batch[i].value_offsets,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
// processing done, return back to waiting state
|
// processing done, return back to waiting state
|
||||||
|
@ -243,13 +251,23 @@ func (a *asyncContext) releaseWorker(workerIdx int32) {
|
||||||
// side, we use the first visible slot and set an exit request. The worker
|
// side, we use the first visible slot and set an exit request. The worker
|
||||||
// will eventually synchronize with the used lock and stop.
|
// will eventually synchronize with the used lock and stop.
|
||||||
idx := a.workerIdxToBatchIdxs(workerIdx)[0]
|
idx := a.workerIdxToBatchIdxs(workerIdx)[0]
|
||||||
|
waitStartTime := time.Now()
|
||||||
for !atomic.CompareAndSwapInt32((*int32)(&a.batch[idx].lock), state_unused, state_exit_req) {
|
for !atomic.CompareAndSwapInt32((*int32)(&a.batch[idx].lock), state_unused, state_exit_req) {
|
||||||
// spin
|
// spinning, but let's yield first
|
||||||
|
runtime.Gosched()
|
||||||
|
if time.Since(waitStartTime).Seconds() > workerReleaseTimeoutInSeconds {
|
||||||
|
panic("plugin-sdk-go/sdk/symbols/extract: async worker release timeout expired (1)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for worker exiting
|
// wait for worker exiting
|
||||||
|
waitStartTime = time.Now()
|
||||||
for atomic.LoadInt32((*int32)(&a.batch[idx].lock)) != state_exit_ack {
|
for atomic.LoadInt32((*int32)(&a.batch[idx].lock)) != state_exit_ack {
|
||||||
// spin
|
// spinning, but let's yield first
|
||||||
|
runtime.Gosched()
|
||||||
|
if time.Since(waitStartTime).Seconds() > workerReleaseTimeoutInSeconds {
|
||||||
|
panic("plugin-sdk-go/sdk/symbols/extract: async worker release timeout expired (2)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore first worker slot
|
// restore first worker slot
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -27,6 +28,8 @@ import (
|
||||||
"github.com/falcosecurity/plugin-sdk-go/pkg/sdk"
|
"github.com/falcosecurity/plugin-sdk-go/pkg/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const testAsyncMaxPlugins = 32 // note: must be <= cgo.MaxHandle
|
||||||
|
|
||||||
type sampleAsyncExtract struct {
|
type sampleAsyncExtract struct {
|
||||||
sampleExtract
|
sampleExtract
|
||||||
counter uint64
|
counter uint64
|
||||||
|
@ -156,7 +159,7 @@ func TestAsyncExtract(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// run with increasing number of concurrent consumers
|
// run with increasing number of concurrent consumers
|
||||||
for i := 1; i <= cgo.MaxHandle; i *= 2 {
|
for i := 1; i <= testAsyncMaxPlugins; i *= 2 {
|
||||||
// run with increasing number of extractions
|
// run with increasing number of extractions
|
||||||
for j := 1; j < 10000; j *= 10 {
|
for j := 1; j < 10000; j *= 10 {
|
||||||
workload(i, j)
|
workload(i, j)
|
||||||
|
@ -165,7 +168,10 @@ func TestAsyncExtract(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStartStopAsync(t *testing.T) {
|
func TestStartStopAsync(t *testing.T) {
|
||||||
nPlugins := cgo.MaxHandle
|
nPlugins := testAsyncMaxPlugins
|
||||||
|
// checking that an odd or event number of plugins is not relevant
|
||||||
|
for i := nPlugins - 1; i <= nPlugins+1; i++ {
|
||||||
|
t.Run(fmt.Sprintf("unbalanced-startstop#%d", i), func(t *testing.T) {
|
||||||
testWithMockPlugins(nPlugins, func(handles []cgo.Handle) {
|
testWithMockPlugins(nPlugins, func(handles []cgo.Handle) {
|
||||||
// test unbalanced start/stop calls
|
// test unbalanced start/stop calls
|
||||||
assertPanic(t, func() {
|
assertPanic(t, func() {
|
||||||
|
@ -187,10 +193,14 @@ func TestStartStopAsync(t *testing.T) {
|
||||||
a.StopAsync(handles[0], testReleaseAsyncBatch)
|
a.StopAsync(handles[0], testReleaseAsyncBatch)
|
||||||
a.StopAsync(handles[0], testReleaseAsyncBatch)
|
a.StopAsync(handles[0], testReleaseAsyncBatch)
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run(fmt.Sprintf("inconsistent-async#%d", i), func(t *testing.T) {
|
||||||
|
testWithMockPlugins(nPlugins, func(handles []cgo.Handle) {
|
||||||
// test with inconsistent enabled values
|
// test with inconsistent enabled values
|
||||||
a := asyncContext{}
|
a := asyncContext{}
|
||||||
enabled := true
|
enabled := false
|
||||||
for i := 0; i < nPlugins; i++ {
|
for i := 0; i < nPlugins; i++ {
|
||||||
a.SetAsync(enabled)
|
a.SetAsync(enabled)
|
||||||
a.StartAsync(handles[i], testAllocAsyncBatch)
|
a.StartAsync(handles[i], testAllocAsyncBatch)
|
||||||
|
@ -204,25 +214,31 @@ func TestStartStopAsync(t *testing.T) {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
for _, h := range handles {
|
for _, h := range handles {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
a.SetAsync(enabled)
|
||||||
a.StartAsync(h, testAllocAsyncBatch)
|
a.StartAsync(h, testAllocAsyncBatch)
|
||||||
go func(h cgo.Handle) {
|
go func(h cgo.Handle, enabled bool) {
|
||||||
counter := uint64(0)
|
counter := uint64(0)
|
||||||
field, freeField := allocSSPluginExtractField(1, sdk.FieldTypeUint64, "", "")
|
field, freeField := allocSSPluginExtractField(1, sdk.FieldTypeUint64, "", "")
|
||||||
defer freeField()
|
defer freeField()
|
||||||
for e := 0; e < 1000; e++ {
|
for e := 0; e < 1000; e++ {
|
||||||
|
if enabled {
|
||||||
testSimulateAsyncRequest(t, &a, h, field)
|
testSimulateAsyncRequest(t, &a, h, field)
|
||||||
value := **((**uint64)(unsafe.Pointer(&field.res[0])))
|
value := **((**uint64)(unsafe.Pointer(&field.res[0])))
|
||||||
if value != counter {
|
if value != counter {
|
||||||
panic(fmt.Sprintf("extracted %d but expected %d", value, counter))
|
panic(fmt.Sprintf("extracted %d but expected %d", value, counter))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
counter++
|
counter++
|
||||||
}
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}(h)
|
}(h, enabled)
|
||||||
|
enabled = !enabled
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
for _, h := range handles {
|
for _, h := range handles {
|
||||||
a.StopAsync(h, testReleaseAsyncBatch)
|
a.StopAsync(h, testReleaseAsyncBatch)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -52,17 +53,17 @@ void async_deinit()
|
||||||
|
|
||||||
// Defined in extract.go
|
// Defined in extract.go
|
||||||
extern int32_t plugin_extract_fields_sync(ss_plugin_t *s,
|
extern int32_t plugin_extract_fields_sync(ss_plugin_t *s,
|
||||||
const ss_plugin_event *evt,
|
const ss_plugin_event_input *evt,
|
||||||
uint32_t num_fields,
|
uint32_t num_fields,
|
||||||
ss_plugin_extract_field *fields);
|
ss_plugin_extract_field *fields,
|
||||||
|
ss_plugin_extract_value_offsets *offsets);
|
||||||
|
|
||||||
// This is the plugin API function. If s_async_ctx_batch is
|
// This is the plugin API function. If s_async_ctx_batch is
|
||||||
// non-NULL, it calls the async extractor function. Otherwise, it
|
// non-NULL, it calls the async extractor function. Otherwise, it
|
||||||
// calls the synchronous extractor function.
|
// calls the synchronous extractor function.
|
||||||
FALCO_PLUGIN_SDK_PUBLIC int32_t plugin_extract_fields(ss_plugin_t *s,
|
FALCO_PLUGIN_SDK_PUBLIC int32_t plugin_extract_fields(ss_plugin_t *s,
|
||||||
const ss_plugin_event *evt,
|
const ss_plugin_event_input *evt,
|
||||||
uint32_t num_fields,
|
const ss_plugin_field_extract_input* in)
|
||||||
ss_plugin_extract_field *fields)
|
|
||||||
{
|
{
|
||||||
// note: concurrent requests are supported on the context batch, but each
|
// note: concurrent requests are supported on the context batch, but each
|
||||||
// slot with a different value of ss_plugin_t *s. As such, for each lock
|
// slot with a different value of ss_plugin_t *s. As such, for each lock
|
||||||
|
@ -78,14 +79,15 @@ FALCO_PLUGIN_SDK_PUBLIC int32_t plugin_extract_fields(ss_plugin_t *s,
|
||||||
if (s_async_ctx_batch == NULL
|
if (s_async_ctx_batch == NULL
|
||||||
|| atomic_load_explicit(&s_async_ctx_batch[(size_t)s - 1].lock, memory_order_seq_cst) != WAIT)
|
|| atomic_load_explicit(&s_async_ctx_batch[(size_t)s - 1].lock, memory_order_seq_cst) != WAIT)
|
||||||
{
|
{
|
||||||
return plugin_extract_fields_sync(s, evt, num_fields, fields);
|
return plugin_extract_fields_sync(s, evt, in->num_fields, in->fields, in->value_offsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set input data
|
// Set input data
|
||||||
s_async_ctx_batch[(size_t)s - 1].s = s;
|
s_async_ctx_batch[(size_t)s - 1].s = s;
|
||||||
s_async_ctx_batch[(size_t)s - 1].evt = evt;
|
s_async_ctx_batch[(size_t)s - 1].evt = evt;
|
||||||
s_async_ctx_batch[(size_t)s - 1].num_fields = num_fields;
|
s_async_ctx_batch[(size_t)s - 1].num_fields = in->num_fields;
|
||||||
s_async_ctx_batch[(size_t)s - 1].fields = fields;
|
s_async_ctx_batch[(size_t)s - 1].fields = in->fields;
|
||||||
|
s_async_ctx_batch[(size_t)s - 1].value_offsets = in->value_offsets;
|
||||||
|
|
||||||
// notify data request
|
// notify data request
|
||||||
atomic_store_explicit(&s_async_ctx_batch[(size_t)s - 1].lock, DATA_REQ, memory_order_seq_cst);
|
atomic_store_explicit(&s_async_ctx_batch[(size_t)s - 1].lock, DATA_REQ, memory_order_seq_cst);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2025 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -27,6 +28,7 @@ limitations under the License.
|
||||||
package extract
|
package extract
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
#include "extract.h"
|
#include "extract.h"
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
@ -38,20 +40,34 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
//export plugin_extract_fields_sync
|
//export plugin_extract_fields_sync
|
||||||
func plugin_extract_fields_sync(plgState C.uintptr_t, evt *C.ss_plugin_event, numFields uint32, fields *C.ss_plugin_extract_field) int32 {
|
func plugin_extract_fields_sync(plgState C.uintptr_t, evt *C.ss_plugin_event_input, numFields uint32, fields *C.ss_plugin_extract_field, offsets *C.ss_plugin_extract_value_offsets) int32 {
|
||||||
pHandle := cgo.Handle(plgState)
|
pHandle := cgo.Handle(plgState)
|
||||||
extract := pHandle.Value().(sdk.Extractor)
|
extract := pHandle.Value().(sdk.Extractor)
|
||||||
extrReqs := pHandle.Value().(sdk.ExtractRequests)
|
extrReqs := pHandle.Value().(sdk.ExtractRequests)
|
||||||
|
|
||||||
// https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices
|
// https://go.dev/wiki/cgo#turning-c-arrays-into-go-slices
|
||||||
flds := (*[1 << 28]C.struct_ss_plugin_extract_field)(unsafe.Pointer(fields))[:numFields:numFields]
|
flds := (*[1 << 28]C.struct_ss_plugin_extract_field)(unsafe.Pointer(fields))[:numFields:numFields]
|
||||||
var i uint32
|
var i uint32
|
||||||
var extrReq sdk.ExtractRequest
|
var extrReq sdk.ExtractRequest
|
||||||
|
|
||||||
|
if offsets != nil {
|
||||||
|
extrReqs.ExtractRequests().MakeOffsetArrayPtrs(unsafe.Pointer(offsets), numFields)
|
||||||
|
}
|
||||||
|
|
||||||
for i = 0; i < numFields; i++ {
|
for i = 0; i < numFields; i++ {
|
||||||
flds[i].res_len = (C.uint64_t)(0)
|
flds[i].res_len = (C.uint64_t)(0)
|
||||||
extrReq = extrReqs.ExtractRequests().Get(int(flds[i].field_id))
|
extrReq = extrReqs.ExtractRequests().Get(int(flds[i].field_id))
|
||||||
extrReq.SetPtr(unsafe.Pointer(&flds[i]))
|
extrReq.SetPtr(unsafe.Pointer(&flds[i]))
|
||||||
|
|
||||||
|
if offsets == nil {
|
||||||
|
extrReq.SetOffsetPtrs(nil, nil)
|
||||||
|
} else {
|
||||||
|
extrReq.SetOffsetPtrs(
|
||||||
|
unsafe.Add(unsafe.Pointer(offsets.start), i*C.sizeof_uint32_t),
|
||||||
|
unsafe.Add(unsafe.Pointer(offsets.length), i*C.sizeof_uint32_t),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
err := extract.Extract(extrReq, sdk.NewEventReader(unsafe.Pointer(evt)))
|
err := extract.Extract(extrReq, sdk.NewEventReader(unsafe.Pointer(evt)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pHandle.Value().(sdk.LastError).SetLastError(err)
|
pHandle.Value().(sdk.LastError).SetLastError(err)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -17,7 +18,7 @@ limitations under the License.
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
#include "../../plugin_types.h"
|
#include "../../plugin_api.h"
|
||||||
|
|
||||||
typedef struct async_extractor_info
|
typedef struct async_extractor_info
|
||||||
{
|
{
|
||||||
|
@ -26,9 +27,10 @@ typedef struct async_extractor_info
|
||||||
|
|
||||||
// input data
|
// input data
|
||||||
ss_plugin_t *s;
|
ss_plugin_t *s;
|
||||||
const ss_plugin_event *evt;
|
const ss_plugin_event_input *evt;
|
||||||
uint32_t num_fields;
|
uint32_t num_fields;
|
||||||
ss_plugin_extract_field *fields;
|
ss_plugin_extract_field *fields;
|
||||||
|
ss_plugin_extract_value_offsets *value_offsets;
|
||||||
|
|
||||||
// output data
|
// output data
|
||||||
int32_t rc;
|
int32_t rc;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -76,15 +77,24 @@ func allocSSPluginExtractField(fid, ftype uint32, fname, farg string) (*_Ctype_s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event, func()) {
|
func allocSSPluginExtractValueOffsets(start *uint32, length *uint32) (*_Ctype_ss_plugin_extract_value_offsets) {
|
||||||
ret := &_Ctype_struct_ss_plugin_event{}
|
ret := &_Ctype_ss_plugin_extract_value_offsets{}
|
||||||
|
ret.start = (*_Ctype_uint32_t)(start)
|
||||||
|
ret.length = (*_Ctype_uint32_t)(length)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func allocSSPluginEvent(num, ts uint64, data []byte) (*_Ctype_struct_ss_plugin_event_input, func()) {
|
||||||
|
ret := &_Ctype_struct_ss_plugin_event_input{}
|
||||||
|
evts, _ := sdk.NewEventWriters(1, int64(len(data)))
|
||||||
|
evt := evts.Get(0)
|
||||||
|
evt.Writer().Write(data)
|
||||||
|
ret.evt = *(**_Ctype_struct_ss_plugin_event)(evts.ArrayPtr())
|
||||||
ret.evtnum = _Ctype_uint64_t(num)
|
ret.evtnum = _Ctype_uint64_t(num)
|
||||||
ret.ts = _Ctype_uint64_t(ts)
|
|
||||||
ret.data = (*_Ctype_uint8_t)(&data[0])
|
|
||||||
ret.datalen = _Ctype_uint32_t(len(data))
|
|
||||||
|
|
||||||
return ret, func() {
|
return ret, func() {
|
||||||
// nothing to deallocate here
|
evts.Free()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,11 +126,22 @@ func TestExtract(t *testing.T) {
|
||||||
// panic
|
// panic
|
||||||
badHandle := cgo.NewHandle(1)
|
badHandle := cgo.NewHandle(1)
|
||||||
assertPanic(t, func() {
|
assertPanic(t, func() {
|
||||||
plugin_extract_fields_sync(_Ctype_uintptr_t(badHandle), event, 1, field)
|
plugin_extract_fields_sync(_Ctype_uintptr_t(badHandle), event, 1, field, nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
// success
|
// success
|
||||||
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field)
|
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field, nil)
|
||||||
|
if res != sdk.SSPluginSuccess {
|
||||||
|
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
|
||||||
|
} else if sample.lastErr != nil {
|
||||||
|
t.Errorf("(lastErr): should be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
// success + offsets
|
||||||
|
val_start := uint32(0)
|
||||||
|
val_length := uint32(8)
|
||||||
|
offsets := allocSSPluginExtractValueOffsets(&val_start, &val_length)
|
||||||
|
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field, offsets)
|
||||||
if res != sdk.SSPluginSuccess {
|
if res != sdk.SSPluginSuccess {
|
||||||
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
|
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
|
||||||
} else if sample.lastErr != nil {
|
} else if sample.lastErr != nil {
|
||||||
|
@ -129,7 +150,7 @@ func TestExtract(t *testing.T) {
|
||||||
|
|
||||||
// error
|
// error
|
||||||
sample.err = errTest
|
sample.err = errTest
|
||||||
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field)
|
res = plugin_extract_fields_sync(_Ctype_uintptr_t(handle), event, 1, field, nil)
|
||||||
if res != sdk.SSPluginFailure {
|
if res != sdk.SSPluginFailure {
|
||||||
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginFailure, res)
|
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginFailure, res)
|
||||||
} else if sample.lastErr != errTest {
|
} else if sample.lastErr != errTest {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -22,3 +23,12 @@ const char* get_default_required_api_version()
|
||||||
{
|
{
|
||||||
return PLUGIN_API_VERSION_STR;
|
return PLUGIN_API_VERSION_STR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo(jasondellaluce,therealbobo): support this for real when we decide to
|
||||||
|
// deal with non-plugin events in the SDK Go
|
||||||
|
uint16_t* plugin_get_extract_event_types(uint32_t* num_types)
|
||||||
|
{
|
||||||
|
static uint16_t types[] = { 322 }; // PPME_PLUGINEVENT_E
|
||||||
|
*num_types = sizeof(types) / sizeof(uint16_t);
|
||||||
|
return &types[0];
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -16,6 +17,7 @@ limitations under the License.
|
||||||
|
|
||||||
// This package exports a set of C functions that provide general
|
// This package exports a set of C functions that provide general
|
||||||
// information about the plugin. The exported functions are:
|
// information about the plugin. The exported functions are:
|
||||||
|
//
|
||||||
// uint32_t get_type();
|
// uint32_t get_type();
|
||||||
// uint32_t get_id();
|
// uint32_t get_id();
|
||||||
// char* get_name();
|
// char* get_name();
|
||||||
|
@ -36,6 +38,7 @@ package info
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
|
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
|
||||||
)
|
)
|
||||||
|
@ -105,7 +108,33 @@ func plugin_get_required_api_version() *C.char {
|
||||||
return (*C.char)(pRequiredAPIVersion.CharPtr())
|
return (*C.char)(pRequiredAPIVersion.CharPtr())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func splitVersionString(version string) (string, string, string) {
|
||||||
|
nums := strings.Split(version, ".")
|
||||||
|
if len(nums) != 3 {
|
||||||
|
panic("Incorrect format. Expected: Semantic Versioning: X.Y.Z")
|
||||||
|
}
|
||||||
|
return nums[0], nums[1], nums[2]
|
||||||
|
}
|
||||||
|
|
||||||
func SetRequiredAPIVersion(apiVer string) {
|
func SetRequiredAPIVersion(apiVer string) {
|
||||||
|
if apiVer != "" {
|
||||||
|
pluginRequiredMajor, pluginRequiredMinor, pluginRequiredPatch := splitVersionString(apiVer)
|
||||||
|
sdkRequiredMajor, sdkRequiredMinor, sdkRequiredPatch := splitVersionString(C.GoString(C.get_default_required_api_version()))
|
||||||
|
|
||||||
|
// The plugin should always require a version lower or equal to the one required by the SDK
|
||||||
|
// because the SDK couldn't support features coming from new framework versions.
|
||||||
|
// On the other side the plugin could require a lower version because maybe it doesn't
|
||||||
|
// need all features provided by the framework.
|
||||||
|
if sdkRequiredMajor != pluginRequiredMajor {
|
||||||
|
panic("Incompatible required Major version between SDK and the plugin. Major SDK version is equal to " + sdkRequiredMajor + " but the plugin uses " + pluginRequiredMajor + ". The 2 Major versions should be equal.")
|
||||||
|
}
|
||||||
|
if sdkRequiredMinor < pluginRequiredMinor {
|
||||||
|
panic("The plugin requires a Minor version greater than the SDK one. Minor SDK version is equal to " + sdkRequiredMinor + " but the plugin uses " + pluginRequiredMinor + ". The plugin should always require a Minor version lower or equal to the SDK one.")
|
||||||
|
}
|
||||||
|
if sdkRequiredMinor == pluginRequiredMinor && sdkRequiredPatch < pluginRequiredPatch {
|
||||||
|
panic("The plugin requires a Patch version greater than the SDK one. Patch SDK version is equal to " + sdkRequiredPatch + " but the plugin uses " + pluginRequiredPatch + ". The plugin should always require a Patch version lower or equal to the SDK one.")
|
||||||
|
}
|
||||||
|
}
|
||||||
pRequiredAPIVersion.Write(apiVer)
|
pRequiredAPIVersion.Write(apiVer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2022 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -18,16 +19,22 @@ package info
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
|
"github.com/falcosecurity/plugin-sdk-go/pkg/ptr"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testStr = "test"
|
var testStr = "test"
|
||||||
var testU32 = uint32(1)
|
var testU32 = uint32(1)
|
||||||
var testStrSlice = []string{"hello", "world"}
|
var testStrSlice = []string{"hello", "world"}
|
||||||
|
|
||||||
|
func testFormatVer(major, minor, patch int) string {
|
||||||
|
return fmt.Sprintf("%d.%d.%d", major, minor, patch)
|
||||||
|
}
|
||||||
|
|
||||||
func TestInfo(t *testing.T) {
|
func TestInfo(t *testing.T) {
|
||||||
var resU32 uint32
|
var resU32 uint32
|
||||||
var resStr string
|
var resStr string
|
||||||
|
@ -36,7 +43,7 @@ func TestInfo(t *testing.T) {
|
||||||
SetId(testU32)
|
SetId(testU32)
|
||||||
resU32 = plugin_get_id()
|
resU32 = plugin_get_id()
|
||||||
if resU32 != testU32 {
|
if resU32 != testU32 {
|
||||||
t.Errorf("(id) expected %d, but found %d", testU32, resU32)
|
t.Errorf("(plugin id) expected %d, but found %d", testU32, resU32)
|
||||||
}
|
}
|
||||||
|
|
||||||
SetName(testStr)
|
SetName(testStr)
|
||||||
|
@ -63,12 +70,6 @@ func TestInfo(t *testing.T) {
|
||||||
t.Errorf("(version) expected %s, but found %s", testStr, resStr)
|
t.Errorf("(version) expected %s, but found %s", testStr, resStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
SetRequiredAPIVersion(testStr)
|
|
||||||
resStr = ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
|
|
||||||
if resStr != testStr {
|
|
||||||
t.Errorf("(requiredApiVersion) expected %s, but found %s", testStr, resStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
SetEventSource(testStr)
|
SetEventSource(testStr)
|
||||||
resStr = ptr.GoString(unsafe.Pointer(plugin_get_event_source()))
|
resStr = ptr.GoString(unsafe.Pointer(plugin_get_event_source()))
|
||||||
if resStr != testStr {
|
if resStr != testStr {
|
||||||
|
@ -102,3 +103,109 @@ func TestInfo(t *testing.T) {
|
||||||
t.Errorf("(extractEventSources) expected %s, but found %s", testStr, resStr)
|
t.Errorf("(extractEventSources) expected %s, but found %s", testStr, resStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSplitVersionString(t *testing.T) {
|
||||||
|
t.Run("invalid version string 1", func(t *testing.T) {
|
||||||
|
panicFunc := func() {
|
||||||
|
splitVersionString("2..1..2")
|
||||||
|
}
|
||||||
|
assert.Panics(t, panicFunc)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid version string 2", func(t *testing.T) {
|
||||||
|
panicFunc := func() {
|
||||||
|
splitVersionString("2.2.3..32")
|
||||||
|
}
|
||||||
|
assert.Panics(t, panicFunc)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid version string 3", func(t *testing.T) {
|
||||||
|
panicFunc := func() {
|
||||||
|
splitVersionString("2.2.3.")
|
||||||
|
}
|
||||||
|
assert.Panics(t, panicFunc)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid version string 4", func(t *testing.T) {
|
||||||
|
panicFunc := func() {
|
||||||
|
splitVersionString("2..2.3")
|
||||||
|
}
|
||||||
|
assert.Panics(t, panicFunc)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("valid version string", func(t *testing.T) {
|
||||||
|
panicFunc := func() {
|
||||||
|
splitVersionString("2.2.3")
|
||||||
|
}
|
||||||
|
assert.NotPanics(t, panicFunc)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("check split version string", func(t *testing.T) {
|
||||||
|
major, minor, patch := splitVersionString("2.4.3")
|
||||||
|
if major != "2" {
|
||||||
|
t.Errorf("(Major) expected %s, but found %s", "2", major)
|
||||||
|
}
|
||||||
|
if minor != "4" {
|
||||||
|
t.Errorf("(Minor) expected %s, but found %s", "4", minor)
|
||||||
|
}
|
||||||
|
if patch != "3" {
|
||||||
|
t.Errorf("(Patch) expected %s, but found %s", "3", patch)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSemver(t *testing.T) {
|
||||||
|
// Get the SDK required version
|
||||||
|
// we set an empty string to obtain the default SDK version
|
||||||
|
SetRequiredAPIVersion("")
|
||||||
|
versionSDK := ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
|
||||||
|
var majorSDK, minorSDK, patchSDK int
|
||||||
|
nums, err := fmt.Sscanf(versionSDK, "%d.%d.%d", &majorSDK, &minorSDK, &patchSDK)
|
||||||
|
if nums != 3 || err != nil {
|
||||||
|
t.Errorf("Unable to obtain the default SDK version")
|
||||||
|
}
|
||||||
|
|
||||||
|
// plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch == SDK Patch
|
||||||
|
t.Run("plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch == SDK Patch", func(t *testing.T) {
|
||||||
|
SetRequiredAPIVersion(testFormatVer(majorSDK, minorSDK, patchSDK))
|
||||||
|
requiredAPIVersion := ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
|
||||||
|
expectedRequiredAPIVersion := testFormatVer(majorSDK, minorSDK, patchSDK)
|
||||||
|
if expectedRequiredAPIVersion != requiredAPIVersion {
|
||||||
|
t.Errorf("(requiredApiVersion) expected %s, but found %s", expectedRequiredAPIVersion, requiredAPIVersion)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// plguin Major > SDK Major
|
||||||
|
t.Run("plguin Major > SDK Major", func(t *testing.T) {
|
||||||
|
panicFunc := func() {
|
||||||
|
SetRequiredAPIVersion(testFormatVer(majorSDK+1, minorSDK, patchSDK))
|
||||||
|
}
|
||||||
|
assert.PanicsWithValue(t, fmt.Sprintf("Incompatible required Major version between SDK and the plugin. Major SDK version is equal to %d but the plugin uses %d. The 2 Major versions should be equal.", majorSDK, majorSDK+1), panicFunc)
|
||||||
|
})
|
||||||
|
|
||||||
|
// plguin Major == SDK Major && plguin Minor > SDK Minor
|
||||||
|
t.Run("plguin Major == SDK Major && plguin Minor > SDK Minor", func(t *testing.T) {
|
||||||
|
panicFunc := func() {
|
||||||
|
SetRequiredAPIVersion(testFormatVer(majorSDK, minorSDK+1, patchSDK))
|
||||||
|
}
|
||||||
|
assert.PanicsWithValue(t, fmt.Sprintf("The plugin requires a Minor version greater than the SDK one. Minor SDK version is equal to %d but the plugin uses %d. The plugin should always require a Minor version lower or equal to the SDK one.", minorSDK, minorSDK+1), panicFunc)
|
||||||
|
})
|
||||||
|
|
||||||
|
// plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch > SDK Patch
|
||||||
|
t.Run("plguin Major == SDK Major && plguin Minor == SDK Minor && plguin Patch > SDK Patch", func(t *testing.T) {
|
||||||
|
panicFunc := func() {
|
||||||
|
SetRequiredAPIVersion(testFormatVer(majorSDK, minorSDK, patchSDK+1))
|
||||||
|
}
|
||||||
|
assert.PanicsWithValue(t, fmt.Sprintf("The plugin requires a Patch version greater than the SDK one. Patch SDK version is equal to %d but the plugin uses %d. The plugin should always require a Patch version lower or equal to the SDK one.", patchSDK, patchSDK+1), panicFunc)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("empty plugin version", func(t *testing.T) {
|
||||||
|
// This should set as default the SDK required version since we don't provide the required plugin version
|
||||||
|
SetRequiredAPIVersion("")
|
||||||
|
requiredAPIVersion := ptr.GoString(unsafe.Pointer(plugin_get_required_api_version()))
|
||||||
|
expectedRequiredAPIVersion := testFormatVer(majorSDK, minorSDK, patchSDK)
|
||||||
|
if expectedRequiredAPIVersion != requiredAPIVersion {
|
||||||
|
t.Errorf("(requiredApiVersion) expected %s, but found %s", expectedRequiredAPIVersion, requiredAPIVersion)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -38,7 +39,7 @@ limitations under the License.
|
||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#include <stdint.h>
|
#include "../../plugin_api.h"
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
|
@ -82,11 +83,12 @@ func SetOnInit(fn OnInitFn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//export plugin_init
|
//export plugin_init
|
||||||
func plugin_init(config *C.char, rc *int32) C.uintptr_t {
|
func plugin_init(in *C.ss_plugin_init_input, rc *int32) C.uintptr_t {
|
||||||
var state sdk.PluginState
|
var state sdk.PluginState
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
state, err = onInitFn(C.GoString(config))
|
// todo(jasondellaluce,therealbobo): support table access and owner operations
|
||||||
|
state, err = onInitFn(C.GoString(in.config))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
state = &baseInit{}
|
state = &baseInit{}
|
||||||
state.(sdk.LastError).SetLastError(err)
|
state.(sdk.LastError).SetLastError(err)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -80,7 +81,16 @@ func TestInitialize(t *testing.T) {
|
||||||
SetOnInit(func(config string) (sdk.PluginState, error) {
|
SetOnInit(func(config string) (sdk.PluginState, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
})
|
})
|
||||||
handle = cgo.Handle(plugin_init((*_Ctype_char)(cStr.CharPtr()), &res))
|
|
||||||
|
// create an init input
|
||||||
|
var in _Ctype_struct_ss_plugin_init_input
|
||||||
|
in.config = nil
|
||||||
|
in.owner = nil
|
||||||
|
in.get_owner_last_error = nil
|
||||||
|
in.tables = nil
|
||||||
|
|
||||||
|
in.config = (*_Ctype_char)(cStr.CharPtr())
|
||||||
|
handle = cgo.Handle(plugin_init(&in, &res))
|
||||||
if res != sdk.SSPluginSuccess {
|
if res != sdk.SSPluginSuccess {
|
||||||
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
|
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
|
||||||
} else if handle.Value() != nil {
|
} else if handle.Value() != nil {
|
||||||
|
@ -92,7 +102,8 @@ func TestInitialize(t *testing.T) {
|
||||||
SetOnInit(func(config string) (sdk.PluginState, error) {
|
SetOnInit(func(config string) (sdk.PluginState, error) {
|
||||||
return nil, errTest
|
return nil, errTest
|
||||||
})
|
})
|
||||||
handle = cgo.Handle(plugin_init((*_Ctype_char)(cStr.CharPtr()), &res))
|
in.config = (*_Ctype_char)(cStr.CharPtr())
|
||||||
|
handle = cgo.Handle(plugin_init(&in, &res))
|
||||||
if res != sdk.SSPluginFailure {
|
if res != sdk.SSPluginFailure {
|
||||||
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginFailure, res)
|
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginFailure, res)
|
||||||
}
|
}
|
||||||
|
@ -109,7 +120,8 @@ func TestInitialize(t *testing.T) {
|
||||||
SetOnInit(func(config string) (sdk.PluginState, error) {
|
SetOnInit(func(config string) (sdk.PluginState, error) {
|
||||||
return state, nil
|
return state, nil
|
||||||
})
|
})
|
||||||
handle = cgo.Handle(plugin_init((*_Ctype_char)(cStr.CharPtr()), &res))
|
in.config = (*_Ctype_char)(cStr.CharPtr())
|
||||||
|
handle = cgo.Handle(plugin_init(&in, &res))
|
||||||
if res != sdk.SSPluginSuccess {
|
if res != sdk.SSPluginSuccess {
|
||||||
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
|
t.Errorf("(res): expected %d, but found %d", sdk.SSPluginSuccess, res)
|
||||||
} else if handle.Value() != state {
|
} else if handle.Value() != state {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -15,7 +16,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// This package exports the following C function:
|
// This package exports the following C function:
|
||||||
// - ss_plugin_rc plugin_next_batch(ss_plugin_t* s, ss_instance_t* h, uint32_t *nevts, ss_plugin_event **evts)
|
// - ss_plugin_rc plugin_next_batch(ss_plugin_t* s, ss_instance_t* h, uint32_t *nevts, ss_plugin_event ***evts)
|
||||||
//
|
//
|
||||||
// The exported plugin_next_batch requires s and h to be a handles
|
// The exported plugin_next_batch requires s and h to be a handles
|
||||||
// of cgo.Handle from this SDK. The value of the s handle must implement
|
// of cgo.Handle from this SDK. The value of the s handle must implement
|
||||||
|
@ -37,12 +38,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
//export plugin_next_batch
|
//export plugin_next_batch
|
||||||
func plugin_next_batch(pState C.uintptr_t, iState C.uintptr_t, nevts *uint32, retEvts **C.ss_plugin_event) int32 {
|
func plugin_next_batch(pState C.uintptr_t, iState C.uintptr_t, nevts *uint32, retEvts ***C.ss_plugin_event) int32 {
|
||||||
events := cgo.Handle(iState).Value().(sdk.Events).Events()
|
events := cgo.Handle(iState).Value().(sdk.Events).Events()
|
||||||
n, err := cgo.Handle(iState).Value().(sdk.NextBatcher).NextBatch(cgo.Handle(pState).Value().(sdk.PluginState), events)
|
n, err := cgo.Handle(iState).Value().(sdk.NextBatcher).NextBatch(cgo.Handle(pState).Value().(sdk.PluginState), events)
|
||||||
|
|
||||||
*nevts = uint32(n)
|
*nevts = uint32(n)
|
||||||
*retEvts = (*C.ss_plugin_event)(events.ArrayPtr())
|
*retEvts = (**C.ss_plugin_event)(events.ArrayPtr())
|
||||||
switch err {
|
switch err {
|
||||||
case nil:
|
case nil:
|
||||||
return sdk.SSPluginSuccess
|
return sdk.SSPluginSuccess
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -68,7 +69,7 @@ func TestNextBatch(t *testing.T) {
|
||||||
// generic testing callback
|
// generic testing callback
|
||||||
doTest := func(name string, res int32, num uint32, ptr unsafe.Pointer, err error) {
|
doTest := func(name string, res int32, num uint32, ptr unsafe.Pointer, err error) {
|
||||||
var resNum uint32
|
var resNum uint32
|
||||||
var resPtr *_Ctype_ss_plugin_event
|
var resPtr **_Ctype_ss_plugin_event
|
||||||
r := plugin_next_batch(_Ctype_uintptr_t(handle), _Ctype_uintptr_t(handle), &resNum, &resPtr)
|
r := plugin_next_batch(_Ctype_uintptr_t(handle), _Ctype_uintptr_t(handle), &resNum, &resPtr)
|
||||||
if r != res {
|
if r != res {
|
||||||
t.Errorf("(%s - res): expected %d, but found %d", name, res, r)
|
t.Errorf("(%s - res): expected %d, but found %d", name, res, r)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2021 The Falco Authors.
|
Copyright (C) 2023 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
Loading…
Reference in New Issue