├── .clang-format
├── .clang-tidy
├── .clang-tidy.ignore
├── .github
├── dependabot.yml
└── workflows
│ └── main.yml
├── .gitignore
├── .gitmodules
├── .pre-commit-config.yaml
├── .swift-format
├── .update-changes.cfg
├── 3rdparty
├── CMakeLists.txt
├── LICENSE.3rdparty
├── bsd-getopt-long.c
├── bsd-getopt-long.h
└── sqlite
│ ├── shell.c
│ ├── sqlite
│ ├── sqlite3.c
│ ├── sqlite3.h
│ └── sqlite3ext.h
├── CHANGES
├── CMakeLists.txt
├── CPPLINT.cfg
├── LICENSE
├── Makefile
├── Package.swift
├── README.md
├── VERSION
├── auxil
├── autodoc-to-md
├── autodoc-to-zeek
├── format-zeek-script
├── log-example.png
├── md-to-toc
├── pycodestyle.cfg
├── run-clang-tidy
├── update-license-headers
├── update-readme
├── zeek-agent.excalidraw
└── zeek-agent.png
├── cmake
├── BPF.cmake
├── CheckCompiler.cmake
├── CheckFunctions.cmake
├── TargetOptions.cmake
└── Util.cmake
├── configure
├── packaging
├── CMakeLists.txt
├── darwin
│ ├── codesign-wrapper
│ ├── hdiutil-with-codesign
│ ├── notarize
│ └── post-build.cmake
├── windows
│ ├── appicon.rc
│ ├── banner.png
│ ├── banner.svg
│ ├── icon.ico
│ ├── sidebar.png
│ ├── sidebar.svg
│ ├── wix-extra.xml.in
│ ├── wix-patch.xml
│ └── wix-string-overrides.wxl
└── zeek-agent.cfg.template
├── src
├── CMakeLists.txt
├── config.h.in
├── core
│ ├── CMakeLists.txt
│ ├── configuration.cc
│ ├── configuration.h
│ ├── database.cc
│ ├── database.h
│ ├── logger.cc
│ ├── logger.h
│ ├── scheduler.cc
│ ├── scheduler.h
│ ├── signal.h
│ ├── signal.posix.cc
│ ├── signal.windows.cc
│ ├── sqlite.cc
│ ├── sqlite.h
│ ├── table.cc
│ └── table.h
├── io
│ ├── CMakeLists.txt
│ ├── console.cc
│ ├── console.h
│ ├── zeek.cc
│ └── zeek.h
├── main.cc
├── platform
│ ├── CMakeLists.txt
│ ├── darwin
│ │ ├── CMakeLists.txt
│ │ ├── CPPLINT.cfg
│ │ ├── ZeekAgent.app
│ │ │ ├── CMakeLists.txt
│ │ │ ├── ExtensionManager.swift
│ │ │ ├── Info.plist.agent.in
│ │ │ ├── Info.plist.app.in
│ │ │ ├── XPC.swift
│ │ │ ├── ZeekAgent.icns
│ │ │ ├── ZeekAgent.iconset
│ │ │ │ ├── icon_128x128.png
│ │ │ │ ├── icon_256x256.png
│ │ │ │ ├── icon_32x32.png
│ │ │ │ ├── icon_512x512.png
│ │ │ │ └── icon_64x64.png
│ │ │ ├── embedded.provisionprofile.agent
│ │ │ ├── embedded.provisionprofile.app
│ │ │ ├── entitlements.plist.agent
│ │ │ ├── entitlements.plist.app
│ │ │ ├── main.swift
│ │ │ └── zeek.png
│ │ ├── endpoint-security.h
│ │ ├── endpoint-security.mm
│ │ ├── network-extension.h
│ │ ├── network-extension.mm
│ │ ├── os-log-sink.h
│ │ ├── os-log-sink.mm
│ │ ├── platform.h
│ │ ├── platform.mm
│ │ ├── xpc.h
│ │ └── xpc.mm
│ ├── linux
│ │ ├── CMakeLists.txt
│ │ ├── bpf.cc
│ │ ├── bpf.h
│ │ ├── platform.cc
│ │ └── platform.h
│ ├── platform.h
│ ├── testing.cc
│ └── windows
│ │ ├── CMakeLists.txt
│ │ ├── platform.cc
│ │ └── platform.h
├── tables
│ ├── CMakeLists.txt
│ ├── files
│ │ ├── CMakeLists.txt
│ │ ├── files.cc
│ │ ├── files.h
│ │ ├── files.posix.cc
│ │ └── files.windows.cc
│ ├── processes
│ │ ├── CMakeLists.txt
│ │ ├── processes.darwin.cc
│ │ ├── processes.h
│ │ ├── processes.linux.bpf.c
│ │ ├── processes.linux.cc
│ │ ├── processes.linux.event.h
│ │ ├── processes.test.cc
│ │ └── processes.windows.cc
│ ├── sockets
│ │ ├── CMakeLists.txt
│ │ ├── sockets.darwin.cc
│ │ ├── sockets.h
│ │ ├── sockets.linux.bpf.c
│ │ ├── sockets.linux.cc
│ │ ├── sockets.linux.event.h
│ │ ├── sockets.test.cc
│ │ └── sockets.windows.cc
│ ├── system_logs
│ │ ├── ActivityStreamSPI.h
│ │ ├── CMakeLists.txt
│ │ ├── system_logs.darwin.cc
│ │ ├── system_logs.h
│ │ ├── system_logs.linux.cc
│ │ ├── system_logs.test.cc
│ │ └── system_logs.windows.cc
│ ├── users
│ │ ├── CMakeLists.txt
│ │ ├── users.darwin.mm
│ │ ├── users.h
│ │ ├── users.linux.cc
│ │ ├── users.test.cc
│ │ └── users.windows.cc
│ └── zeek_agent
│ │ ├── CMakeLists.txt
│ │ ├── zeek_agent.darwin.mm
│ │ ├── zeek_agent.h
│ │ ├── zeek_agent.linux.cc
│ │ ├── zeek_agent.test.cc
│ │ └── zeek_agent.windows.cc
└── util
│ ├── CMakeLists.txt
│ ├── ascii-table.cc
│ ├── ascii-table.h
│ ├── color.h
│ ├── filesystem.h
│ ├── fmt.h
│ ├── helpers.cc
│ ├── helpers.h
│ ├── pimpl.h
│ ├── result.cc
│ ├── result.h
│ ├── socket.cc
│ ├── socket.h
│ ├── socket.no-ipc.cc
│ ├── socket.posix.cc
│ ├── testing.h
│ └── variant.h
├── tests
├── .gitignore
├── Baseline
│ ├── zeek.error
│ │ └── reporter.log
│ ├── zeek.if-missing-table
│ │ └── zeek..stdout
│ ├── zeek.log
│ │ └── changes
│ ├── zeek.query
│ │ └── zeek.output
│ ├── zeek.requires-table
│ │ └── zeek..stdout
│ ├── zeek.scheduled
│ │ └── zeek.output
│ ├── zeek.table.files
│ │ └── zeek.zeek-agent-files.log
│ ├── zeek.table.processes
│ │ └── zeek.zeek-agent-processes.log
│ ├── zeek.table.sockets
│ │ └── zeek.zeek-agent-sockets.log
│ ├── zeek.table.ssh
│ │ └── zeek.zeek-agent-ssh-authorized-keys.log
│ ├── zeek.table.system_logs
│ │ └── zeek.zeek-agent-system-logs.log
│ └── zeek.table.users
│ │ └── zeek.zeek-agent-users.log
├── Files
│ └── random.seed
├── Makefile
├── Scripts
│ ├── canonifier
│ ├── diff-remove-timestamps
│ └── get-zeek-env
├── agent
│ └── ctest.sh
├── btest.cfg
├── test-setup.zeek
├── zeek-agent.cfg
└── zeek
│ ├── error.zeek
│ ├── if-missing-table.zeek
│ ├── log.zeek
│ ├── query.zeek
│ ├── requires-table.zeek
│ ├── scheduled.zeek
│ └── table
│ ├── files.zeek
│ ├── processes.zeek
│ ├── sockets.zeek
│ ├── ssh.zeek
│ ├── system_logs.zeek
│ └── users.zeek
└── vcpkg.json
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | AccessModifierOffset: -4
3 | AlignAfterOpenBracket: Align
4 | AlignConsecutiveAssignments: false
5 | AlignConsecutiveDeclarations: false
6 | AlignEscapedNewlines: Right
7 | AlignOperands: true
8 | AlignTrailingComments: true
9 | AllowAllParametersOfDeclarationOnNextLine: false
10 | AllowShortBlocksOnASingleLine: false
11 | AllowShortCaseLabelsOnASingleLine: true
12 | AllowShortFunctionsOnASingleLine: true
13 | AllowShortIfStatementsOnASingleLine: false
14 | AllowShortLoopsOnASingleLine: false
15 | AlwaysBreakAfterDefinitionReturnType: None
16 | AlwaysBreakAfterReturnType: None
17 | AlwaysBreakBeforeMultilineStrings: true
18 | AlwaysBreakTemplateDeclarations: Yes
19 | BinPackArguments: true
20 | BinPackParameters: true
21 | BraceWrapping:
22 | AfterClass: false
23 | AfterControlStatement: false
24 | AfterEnum: false
25 | AfterFunction: false
26 | AfterNamespace: false
27 | AfterObjCDeclaration: false
28 | AfterStruct: false
29 | AfterUnion: false
30 | AfterExternBlock: false
31 | BeforeCatch: false
32 | BeforeElse: true
33 | IndentBraces: false
34 | SplitEmptyFunction: false
35 | SplitEmptyRecord: false
36 | SplitEmptyNamespace: false
37 | BreakBeforeBinaryOperators: None
38 | BreakBeforeBraces: Custom
39 | BreakBeforeInheritanceComma: false
40 | BreakInheritanceList: BeforeColon
41 | BreakBeforeTernaryOperators: false
42 | BreakConstructorInitializersBeforeComma: false
43 | BreakConstructorInitializers: BeforeColon
44 | BreakAfterJavaFieldAnnotations: false
45 | BreakStringLiterals: true
46 | ColumnLimit: 120
47 | CommentPragmas: 'NOLINT'
48 | CompactNamespaces: false
49 | ConstructorInitializerAllOnOneLineOrOnePerLine: true
50 | ConstructorInitializerIndentWidth: 4
51 | ContinuationIndentWidth: 4
52 | Cpp11BracedListStyle: true
53 | DerivePointerAlignment: false
54 | DisableFormat: false
55 | ExperimentalAutoDetectBinPacking: false
56 | FixNamespaceComments: true
57 | ForEachMacros:
58 | - foreach
59 | - Q_FOREACH
60 | - BOOST_FOREACH
61 | IncludeBlocks: Regroup
62 | IncludeCategories:
63 | - Regex: '".*\.h"'
64 | Priority: 1
65 | - Regex: '^<([[:alnum:]]|_)+>'
66 | Priority: 2
67 | - Regex: '^<[[:alnum:]]*\.(h|hxx|hpp)>'
68 | Priority: 3
69 | - Regex: '^<.*/.*\.(h|hxx|hpp)>'
70 | Priority: 4
71 | - Regex: '.*'
72 | Priority: 10
73 | IncludeIsMainRegex: '$'
74 | IndentCaseLabels: true
75 | IndentPPDirectives: None
76 | IndentWidth: 4
77 | IndentWrappedFunctionNames: false
78 | JavaScriptQuotes: Leave
79 | JavaScriptWrapImports: true
80 | KeepEmptyLinesAtTheStartOfBlocks: false
81 | MacroBlockBegin: '^BEGIN_'
82 | MacroBlockEnd: '^END_'
83 | MaxEmptyLinesToKeep: 2
84 | NamespaceIndentation: None
85 | ObjCBinPackProtocolList: Auto
86 | ObjCBlockIndentWidth: 2
87 | ObjCSpaceAfterProperty: false
88 | ObjCSpaceBeforeProtocolList: true
89 | PenaltyBreakAssignment: 2
90 | PenaltyBreakBeforeFirstCallParameter: 500
91 | PenaltyBreakComment: 300
92 | PenaltyBreakFirstLessLess: 120
93 | PenaltyBreakString: 1000
94 | PenaltyBreakTemplateDeclaration: 10
95 | PenaltyExcessCharacter: 1000000
96 | PenaltyReturnTypeOnItsOwnLine: 1000
97 | PointerAlignment: Left
98 | ReflowComments: true
99 | SortIncludes: true
100 | SortUsingDeclarations: true
101 | SpaceAfterCStyleCast: false
102 | SpaceAfterTemplateKeyword: false
103 | SpaceAfterLogicalNot: true
104 | SpaceBeforeAssignmentOperators: true
105 | SpaceBeforeCpp11BracedList: false
106 | SpaceBeforeCtorInitializerColon: true
107 | SpaceBeforeInheritanceColon: true
108 | SpaceBeforeParens: ControlStatements
109 | SpaceBeforeRangeBasedForLoopColon: true
110 | SpaceInEmptyParentheses: false
111 | SpacesBeforeTrailingComments: 1
112 | SpacesInAngles: false
113 | SpacesInContainerLiterals: true
114 | SpacesInCStyleCastParentheses: false
115 | SpacesInParentheses: false
116 | SpacesInSquareBrackets: false
117 | SpacesInConditionalStatement: true
118 | Standard: Cpp11
119 | StatementMacros:
120 | - STANDARD_OPERATOR_1
121 | TabWidth: 4
122 | UseTab: Never
123 | ...
124 |
--------------------------------------------------------------------------------
/.clang-tidy:
--------------------------------------------------------------------------------
1 | ---
2 | Checks: 'bugprone-*,
3 | cert-*,
4 | clang-*,
5 | concurrency-*,
6 | misc-*,
7 | modernize-*,
8 | performance-*,
9 | portability-*,
10 | readability-*,
11 |
12 | -bugprone-assignment-in-if-condition,
13 | -bugprone-easily-swappable-parameters,
14 | -bugprone-reserved-identifier,
15 | -bugprone-unchecked-optional-access,
16 | -cert-err58-cpp,
17 | -clang-analyzer-cplusplus.NewDeleteLeaks,
18 | -clang-diagnostic-c++2a-designator,
19 | -clang-diagnostic-deprecated-copy,
20 | -clang-diagnostic-range-loop-analysis,
21 | -concurrency-mt-unsafe,
22 | -misc-const-correctnes,
23 | -misc-macro-parentheses,
24 | -misc-no-recursion,
25 | -misc-non-private-member-variables-in-classes,
26 | -misc-suspicious-semicolon,
27 | -misc-unused-parameters,
28 | -misc-use-anonymous-namespace
29 | -modernize-avoid-c-arrays,
30 | -modernize-macro-to-enum,
31 | -modernize-use-equals-default,
32 | -modernize-use-nodiscard,
33 | -modernize-use-trailing-return-type,
34 | -performance-no-int-to-ptr,
35 | -readability-braces-around-statements,
36 | -readability-container-size-empty,
37 | -readability-convert-member-functions-to-static,
38 | -readability-else-after-return,
39 | -readability-function-cognitive-complexity,
40 | -readability-function-size,
41 | -readability-identifier-length,
42 | -readability-implicit-bool-conversion,
43 | -readability-isolate-declaration,
44 | -readability-magic-numbers,
45 | -readability-make-member-function-const,
46 | -readability-named-parameter,
47 | -readability-qualified-auto,
48 | -readability-static-definition-in-anonymous-namespace,÷
49 | '
50 |
51 | HeaderFilterRegex: '/src'
52 | WarningsAsErrors: '*'
53 |
--------------------------------------------------------------------------------
/.clang-tidy.ignore:
--------------------------------------------------------------------------------
1 | # Paths to source files to ignore when running clang-tidy. This is
2 | # evaluated by auxil/run-clang-tidy.
3 | #
4 | # Note that this doesn't catch header files to ignore. We use a
5 | # combination of HeaderFilterRegex and file names starting with "__" to
6 | # select any headers to skip (if necessary).
7 |
8 | .*3rdparty/
9 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2020-2023 by the Zeek Project. See LICENSE for details.
2 |
3 | version: 2
4 | updates:
5 | - package-ecosystem: "gitsubmodule"
6 | directory: "/"
7 | schedule:
8 | interval: "weekly"
9 |
10 | - package-ecosystem: "github-actions"
11 | directory: "/"
12 | schedule:
13 | interval: "weekly"
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /build*
2 | tmp
3 | *.pyc
4 | .##*
5 | compile_commands.json
6 | .clangd
7 | .cache
8 | .build
9 | *.swp
10 | old
11 | .DS_Store
12 | .ccache
13 |
14 | # Windows port
15 | /.vs
16 | /out
17 | /CMakeSettings.json
18 | /packaging/windows/extra_install.cmake
19 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "3rdparty/doctest"]
2 | path = 3rdparty/doctest
3 | url = https://github.com/onqtam/doctest
4 | [submodule "3rdparty/filesystem"]
5 | path = 3rdparty/filesystem
6 | url = https://github.com/gulrak/filesystem.git
7 | [submodule "3rdparty/spdlog"]
8 | path = 3rdparty/spdlog
9 | url = https://github.com/gabime/spdlog
10 | [submodule "3rdparty/fmt"]
11 | path = 3rdparty/fmt
12 | url = https://github.com/fmtlib/fmt
13 | [submodule "3rdparty/tomlplusplus"]
14 | path = 3rdparty/tomlplusplus
15 | url = https://github.com/marzer/tomlplusplus.git
16 | [submodule "3rdparty/pathfind"]
17 | path = 3rdparty/pathfind
18 | url = https://github.com/bkloppenborg/pathfind
19 | [submodule "3rdparty/replxx"]
20 | path = 3rdparty/replxx
21 | url = https://github.com/AmokHuginnsson/replxx.git
22 | [submodule "3rdparty/stduuid"]
23 | path = 3rdparty/stduuid
24 | url = https://github.com/mariusbancila/stduuid
25 | [submodule "3rdparty/pfs"]
26 | path = 3rdparty/pfs
27 | url = https://github.com/dtrugman/pfs
28 | [submodule "3rdparty/reproc"]
29 | path = 3rdparty/reproc
30 | url = https://github.com/DaanDeMeyer/reproc
31 | [submodule "3rdparty/json"]
32 | path = 3rdparty/json
33 | url = https://github.com/nlohmann/json
34 | [submodule "3rdparty/broker"]
35 | path = 3rdparty/broker
36 | url = https://github.com/zeek/broker.git
37 | [submodule "zeek-agent"]
38 | path = zeek-agent
39 | url = https://github.com/zeek-packages/zeek-agent-v2
40 | [submodule "3rdparty/out_ptr"]
41 | path = 3rdparty/out_ptr
42 | url = https://github.com/soasis/out_ptr
43 | [submodule "3rdparty/IXWebSocket"]
44 | path = 3rdparty/IXWebSocket
45 | url = https://github.com/machinezone/IXWebSocket
46 | [submodule "3rdparty/vcpkg"]
47 | path = 3rdparty/vcpkg
48 | url = https://github.com/microsoft/vcpkg
49 | [submodule "3rdparty/glob"]
50 | path = 3rdparty/glob
51 | url = https://github.com/p-ranav/glob.git
52 | [submodule "3rdparty/bpftool"]
53 | path = 3rdparty/bpftool
54 | url = https://github.com/libbpf/bpftool
55 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | # See https://pre-commit.com for more information
2 | # See https://pre-commit.com/hooks.html for more hooks
3 | repos:
4 |
5 | - repo: local
6 | hooks:
7 | - id: autogen-readme
8 | name: Update README
9 | entry: ./auxil/update-readme
10 | language: script
11 | pass_filenames: false
12 |
13 | - repo: local
14 | hooks:
15 | - id: zeek-script
16 | name: Format Zeek scripts
17 | entry: auxil/format-zeek-script
18 | files: \.zeek$
19 | language: script
20 |
21 | - repo: https://github.com/pre-commit/mirrors-clang-format
22 | rev: 'v13.0.0'
23 | hooks:
24 | - id: clang-format
25 |
26 | - repo: https://github.com/pre-commit/pre-commit-hooks
27 | rev: v4.0.1
28 | hooks:
29 | - id: trailing-whitespace
30 | - id: end-of-file-fixer
31 | - id: check-yaml
32 | - id: check-added-large-files
33 |
34 | - repo: https://github.com/cpplint/cpplint
35 | rev: 1.6.1
36 | hooks:
37 | - id: cpplint
38 | args: ["--quiet"]
39 |
40 | - repo: https://github.com/jorisroovers/gitlint
41 | rev: v0.17.0
42 | hooks:
43 | - id: gitlint
44 |
45 | exclude: 3rdparty/|/Baseline/
46 |
--------------------------------------------------------------------------------
/.swift-format:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "indentation": {
4 | "spaces": 4
5 | },
6 | "tabWidth" : 4,
7 | "lineLength" : 120,
8 | }
9 |
--------------------------------------------------------------------------------
/.update-changes.cfg:
--------------------------------------------------------------------------------
1 | show_authors=0
2 |
--------------------------------------------------------------------------------
/3rdparty/sqlite/sqlite:
--------------------------------------------------------------------------------
1 | sqlite
--------------------------------------------------------------------------------
/CPPLINT.cfg:
--------------------------------------------------------------------------------
1 | filter=-,+build/include_what_you_use,+readability/casting
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021-2024 by the Zeek Project through the International
2 | Computer Science Institute. All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | (1) Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 |
10 | (2) Redistributions in binary form must reproduce the above copyright
11 | notice, this list of conditions and the following disclaimer in the
12 | documentation and/or other materials provided with the distribution.
13 |
14 | (3) Neither the name of the Zeek Project, the International Computer
15 | Science Institute, nor the names of contributors may be used to
16 | endorse or promote products derived from this software without
17 | specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Helper Makefile assuming build/ as the build directory, as configure does by default.
2 |
3 | all: build
4 |
5 | .PHONY: build install test
6 |
7 | build:
8 | @if [ -e build/Makefile ]; then $(MAKE) -j 4 -C build; else true; fi
9 | @if [ -e build/build.ninja ]; then ninja -C build; else true; fi
10 |
11 | install:
12 | @if [ -e build/Makefile ]; then $(MAKE) -j 4 -C build install; else true; fi
13 | @if [ -e build/build.ninja ]; then ninja -C build install; else true; fi
14 |
15 | test:
16 | @if command -v zeek >/dev/null 2>&1; then \
17 | $(MAKE) -C zeek-agent test; \
18 | $(MAKE) -C tests test; \
19 | else \
20 | $(MAKE) -C tests test-no-zeek; \
21 | fi
22 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | //
3 | // We don't use this for the actualy build. We have it only so that
4 | // sourcekit-lsp knows about our Swift code.
5 |
6 | import PackageDescription
7 |
8 | let package = Package(
9 | name: "ZeekAgent",
10 | platforms: [.macOS("12.0")],
11 | targets: [
12 | .target(name: "ZeekAgent", path: "packaging/darwin/ZeekAgent.app"),
13 | ]
14 | )
15 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 2.3.0-19
2 |
--------------------------------------------------------------------------------
/auxil/autodoc-to-md:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python3
2 | #
3 | # Generates a Markdown reference from the agent's --autodoc output, which
4 | # must be piped in on stdin.
5 |
6 | import json
7 | import re
8 | import sys
9 | import textwrap
10 |
11 | def fatalError(message: str):
12 | print(message, file=sys.stderr)
13 | sys.exit(1)
14 |
15 | def fmtDoc(doc):
16 | n = []
17 | doc = doc.split("\n\n")
18 | for i in doc:
19 | x = textwrap.dedent(i).strip()
20 | wrapped = textwrap.fill(x)
21 | if wrapped:
22 | n += [wrapped]
23 |
24 | return "\n\n".join(n)
25 |
26 | def renderTable(name, meta):
27 | platforms = []
28 | for p in meta["platforms"]:
29 | if p == "linux":
30 | platforms.append("Linux")
31 | elif p == "darwin":
32 | platforms.append("macOS")
33 | elif p == "windows":
34 | platforms.append("Windows")
35 | else:
36 | platforms.append(p)
37 |
38 | print("")
39 | print("{}: {} [{}]
".format(name, meta["summary"], ", ".join(sorted(platforms))))
40 | print()
41 |
42 | description = fmtDoc(meta["description"])
43 | if len(description):
44 | print(description)
45 | print()
46 |
47 |
48 | params = [c for c in meta["columns"] if c["is_parameter"]]
49 | if params:
50 | print("| Parameter | Type | Description | Default")
51 | print("| --- | --- | --- | --- |")
52 |
53 | for column in params:
54 | name = re.sub("^_+", "", column["name"])
55 | type = column["type"]
56 | comment = column["summary"]
57 |
58 | default = column["default"]
59 | if default != None:
60 | if default == "":
61 | default = ''
62 |
63 | default = "`{}`".format(default.replace("|", "\\|"))
64 | else:
65 | default = ""
66 |
67 | print("| `{}` | {} | {} | {} |".format(name, type, comment, default))
68 |
69 | print()
70 |
71 |
72 | print("| Column | Type | Description")
73 | print("| --- | --- | --- |")
74 |
75 | for column in [c for c in meta["columns"] if not c["is_parameter"]]:
76 | name = column["name"]
77 | type = column["type"]
78 | comment = column["summary"]
79 |
80 | print("| `{}` | {} | {} |".format(name, type, comment))
81 |
82 | print(" ")
83 | print()
84 |
85 | ### Main
86 |
87 | new_stdout = open(sys.__stdout__.fileno(),
88 | mode=sys.__stdout__.mode,
89 | buffering=1,
90 | encoding=sys.__stdout__.encoding,
91 | errors=sys.__stdout__.errors,
92 | newline='\n',
93 | closefd=False)
94 | sys.stdout = new_stdout
95 |
96 | try:
97 | data = json.load(sys.stdin)
98 | except ValueError as e:
99 | fatalError("cannot parse input: {}".format(e))
100 |
101 | for tbl in sorted(data["tables"].keys()):
102 | renderTable(tbl, data["tables"][tbl])
103 |
--------------------------------------------------------------------------------
/auxil/autodoc-to-zeek:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python3
2 | #
3 | # Generates a Zeek record definition from the agent's --autodoc output, which
4 | # must be piped in on stdin.ä
5 |
6 | import json
7 | import os
8 | import os.path
9 | import sys
10 | import textwrap
11 |
12 | def fatalError(message: str):
13 | print(message, file=sys.stderr)
14 | sys.exit(1)
15 |
16 | def snakeToCamel(x):
17 | return ''.join(x.title() for x in x.split("_"))
18 |
19 | def fmtComment(txt, prefix, single_line=False):
20 | txt = txt.strip()
21 | if not txt:
22 | return ""
23 |
24 | prefix += " "
25 |
26 | if single_line:
27 | return "{} {}".format(prefix, txt)
28 | else:
29 | return textwrap.fill(txt, initial_indent=prefix, subsequent_indent=prefix)
30 |
31 | def fmtID(id):
32 | if id in ("time", "type"):
33 | return "%s_" % id
34 |
35 | return id
36 |
37 | ### Main
38 |
39 | if len(sys.argv) != 2:
40 | fatalError("usage: {}
".format(os.path.basename(sys.argv[0])))
41 | sys.exit(1)
42 |
43 | try:
44 | data = json.load(sys.stdin)
45 | except ValueError as e:
46 | fatalError("cannot parse input: {}".format(e))
47 |
48 | table_name = sys.argv[1]
49 |
50 | try:
51 | table = data["tables"][table_name]
52 | except Exception:
53 | fatalError("no such table")
54 |
55 | new_stdout = open(sys.__stdout__.fileno(),
56 | mode=sys.__stdout__.mode,
57 | buffering=1,
58 | encoding=sys.__stdout__.encoding,
59 | errors=sys.__stdout__.errors,
60 | newline='\n',
61 | closefd=False)
62 | sys.stdout = new_stdout
63 |
64 | indent = "\t"
65 |
66 | summary = table["summary"].capitalize()
67 | if not summary.endswith("."):
68 | summary += "."
69 |
70 | print("{}{}".format(indent, fmtComment(summary, "##")))
71 | print("{}type Columns: record {{".format(indent))
72 |
73 | for column in table["columns"]:
74 | if column["is_parameter"]:
75 | continue
76 |
77 | name = fmtID(column["name"])
78 | comment = column["summary"]
79 | type = column["type"]
80 |
81 | if type == "int":
82 | type = "int"
83 | elif type == "text" or type == "blob":
84 | type = "string"
85 | elif type == "real":
86 | type = "double"
87 | elif type == "null":
88 | # ignore
89 | continue
90 | else:
91 | fatalError("unknown column type '{}'".format(type))
92 |
93 | print("{}{}{}: {} &optional &log;{}".format(indent, indent, name, type, fmtComment(comment, "\t##<", True)))
94 |
95 | print("{}}};".format(indent))
96 |
--------------------------------------------------------------------------------
/auxil/format-zeek-script:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 |
3 | type -P zeek-script >/dev/null 2>&1 || exit 0
4 |
5 | for i in $@; do
6 | zeek-script format ${i} >${i}.tmp && mv -f ${i}.tmp ${i}
7 | done
8 |
--------------------------------------------------------------------------------
/auxil/log-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeek/zeek-agent-v2/fb1fe0f8017db6c30356e3ea77595ae432950efa/auxil/log-example.png
--------------------------------------------------------------------------------
/auxil/md-to-toc:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 |
3 | gawk '
4 |
5 | function fmt_entry(prefix, line) {
6 | title = gensub("^#* *", "", 1, line);
7 | link = tolower(gensub(" ", "-", "g", title));
8 | printf("%s [%s](#%s)\n", prefix, title, link);
9 | }
10 |
11 | /^#.* Contents/ { next; }
12 | /^## / { fmt_entry("-", $0); }
13 | /^### / { fmt_entry(" -", $0); }
14 | #/^#### / { fmt_entry(" -", $0); }
15 | '
16 |
--------------------------------------------------------------------------------
/auxil/pycodestyle.cfg:
--------------------------------------------------------------------------------
1 | [pycodestyle]
2 | ignore = E501,E302,E305,E266
3 |
--------------------------------------------------------------------------------
/auxil/run-clang-tidy:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | #
3 | # Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details.
4 |
5 | usage() {
6 | echo "Usage: $(basename $0) [--fixit] [-j ] [--clang-tidy-path ] [--clang-tidy-arg ] []"
7 | exit 1
8 | }
9 |
10 | error() {
11 | echo "$@" >&2
12 | }
13 |
14 | abspath() {
15 | printf "%s/%s\n" "$(cd $(dirname $1) && pwd)" "$(basename $1)"
16 | }
17 |
18 | cleanup() {
19 | rm -rf "${tmpdir} ${error}"
20 | }
21 |
22 | fix=""
23 | clang_tidy_args=""
24 | files=""
25 | parallel=1
26 |
27 | if [ -n "${CLANG_TIDY}" ]; then
28 | clang_tidy_path=${CLANG_TIDY}
29 | else
30 | clang_tidy_path=$(which clang-tidy 2>/dev/null)
31 | fi
32 |
33 | while true; do
34 | case "$1" in
35 | --fixit) fix=1; shift;;
36 | --clang-tidy-path) clang_tidy_path="$2"; shift; shift;;
37 | --clang-tidy-arg) clang_tidy_args="${clang_tidy_args} $2"; shift; shift;;
38 | --ignore) ignores="${ignores:+${ignores}|}$2"; shift; shift;;
39 | -j) parallel="$2"; shift; shift;;
40 | -h | --help) usage;;
41 | --) shift; break;;
42 | --*) usage;;
43 | *) break;;
44 | esac
45 | done
46 |
47 | if [ $# -lt 1 ]; then
48 | usage
49 | fi
50 |
51 | build=$(cd $1 && pwd)
52 | root=$(cd ${build}/.. && pwd)
53 | shift
54 |
55 | for f in $@; do
56 | files=$(printf "%s %s\n" ${files} $(abspath ${f}))
57 | done
58 |
59 | cd ${build}
60 |
61 | cmake_cache=CMakeCache.txt
62 | compile_json=compile_commands.json
63 | clang_tidy_ignore=${root}/.clang-tidy.ignore
64 |
65 | if ! which jq >/dev/null 2>&1; then
66 | error "Need jq in PATH, aborting." && exit 1
67 | fi
68 |
69 | for i in ${cmake_cache} ${compile_json}; do
70 | if [ ! -f ${i} ]; then
71 | error "${i} not found, did you configure and build?" && exit 1
72 | fi
73 | done
74 |
75 | if [ -z "${clang_tidy_path}" ]; then
76 | clang_tidy_path=$(cat ${cmake_cache} | grep CMAKE_CXX_COMPILER:PATH | cut -d = -f 2 | sed 's/clang+\{0,2\}/clang-tidy/')
77 | fi
78 |
79 | if [ ! -x "${clang_tidy_path}" ]; then
80 | error "cannot find clang-tidy" && exit 1
81 | fi
82 |
83 | if [ "${fix}" = 1 -a -n "$(git status --porcelain | egrep -v '^(M|\?\?) ')" ]; then
84 | echo >&2
85 | echo "error: uncommitted changes in working directory, won't apply changes" >&2
86 | echo >&2
87 | git status -sb >&2
88 | exit 1
89 | fi
90 |
91 | clang_apply_replacements_path=$(echo ${clang_tidy_path} | sed 's/clang-tidy/clang-apply-replacements/')
92 |
93 | if [ -n "${fix}" -a ! -x "${clang_apply_replacements_path}" ]; then
94 | error "cannot find clang-apply-replacements" && exit 1
95 | fi
96 |
97 | if [ -f "${clang_tidy_ignore}" ]; then
98 | x=$(cat ${clang_tidy_ignore} | egrep -v '^ *(#.*)?$' | awk '{printf "%s|", $1}' | sed 's/|$//g')
99 | ignores="${ignores:+${ignores}|}${x}"
100 | fi
101 |
102 | if [ -z "${ignores}" ]; then
103 | ignores="__NEVER_MATCHES__"
104 | fi
105 |
106 | if [ -z "${files}" ]; then
107 | files=$(cat ${compile_json} | jq -r '.[].file' | egrep '\.(cc|c|h)$' | grep -v autogen/__ | grep -v '\.bif\.' | egrep -v "${root}/(${ignores})")
108 | fi
109 |
110 | cmd="${clang_tidy_path} -quiet -p=${build} ${clang_tidy_args}"
111 |
112 | error=/tmp/$(basename $0).$$.error.tmp
113 | tmpdir=/tmp/$(basename $0).$$.tmp
114 | rm -rf "${tmpdir}"
115 | mkdir -p "${tmpdir}"
116 | trap cleanup EXIT
117 |
118 | base=$(cd ${build}/.. && pwd)
119 | rm -f ${error}
120 |
121 | echo "${files}" | awk -v "cmd=${cmd}" -v "tmp=${tmpdir}" '{t=$1; gsub("[/]", "_", t); printf("%s -export-fixes=%s/%s.yaml %s\n", cmd, tmp, t, $1);}' \
122 | | tr '\n' '\0' | (xargs -0 -n 1 -P ${parallel} sh -c 2>&1 || touch ${error}) | grep -v 'warnings\? generated\.$' | sed "s#^../\(.*:\)#${base}/\1#g"
123 |
124 | if [ -e "${error}" ]; then
125 | rc=1
126 | else
127 | rc=0
128 | fi
129 |
130 | if [ ${rc} != 0 -a -n "${fix}" ]; then
131 | # It looks like clang-apply-replacements can merge & unique changes from
132 | # multiple files. In case that turns out not to work, we could borrow
133 | # from LLVM's run-clang-tidy.py script). That has Python code to merge
134 | # replacements ahead of time.
135 | ${clang_apply_replacements_path} ${tmpdir}
136 | fi
137 |
138 | exit ${rc}
139 |
--------------------------------------------------------------------------------
/auxil/update-license-headers:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 |
3 | find . -type d -mindepth 1 -maxdepth 1 | grep -E -v '^\.(/build.*|/\.git|/3rdparty|/\.cache|/\.build)(/|$)' | while read dir; do
4 | echo ${dir} >/dev/tty
5 | find "${dir}" -type f | while read file; do
6 | echo ${file} | grep -E -q '/3rdparty/|/\..*/|update-license-headers' && continue
7 | cat ${file} | grep -q Copyright || continue
8 | gsed -i'' 's/Copyright .* by the Zeek Project\..* details\./Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details./' "${file}"
9 | done
10 | done
11 |
--------------------------------------------------------------------------------
/auxil/update-readme:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env bash
2 |
3 | cd $(dirname $0)
4 |
5 | if [ ! -x ../build/bin/zeek-agent ]; then
6 | echo "no build/bin/zeek-agent, cannot update README" >&2
7 | exit 0 # don't fail pre-commit
8 | fi
9 |
10 | README=../README.md
11 |
12 | tmp=/tmp/README.$$.tmp
13 | trap "rm -f ${tmp}" EXIT
14 |
15 | gawk '
16 | BEGIN { p = 1 }
17 |
18 | // { print;
19 | system("cat ../README.md | ./md-to-toc");
20 | p = 0; }
21 | // { p = 1; }
22 |
23 | // { print;
24 | system("../build/bin/zeek-agent --autodoc | ./autodoc-to-md");
25 | p = 0; }
26 | // { p = 1; }
27 |
28 | p != 0 { print; }
29 | ' <${README} >${tmp}
30 |
31 | cmp -s ${README} ${tmp} || mv -f ${tmp} ${README}
32 |
--------------------------------------------------------------------------------
/auxil/zeek-agent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeek/zeek-agent-v2/fb1fe0f8017db6c30356e3ea77595ae432950efa/auxil/zeek-agent.png
--------------------------------------------------------------------------------
/cmake/BPF.cmake:
--------------------------------------------------------------------------------
1 |
2 | if ( NOT BPFTOOL )
3 | message(FATAL_ERROR "BPFTOOL not available (but should be set automatically by build when on Linux")
4 | endif ()
5 |
6 | if ( NOT CMAKE_C_COMPILER_ID STREQUAL "Clang" )
7 | message(FATAL_ERROR "Must compile with clang as C compiler because of BPF support (have: ${CMAKE_C_COMPILER_ID}).")
8 | endif ()
9 |
10 | file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/include/autogen/bpf")
11 |
12 | # Map target architecture (per CMAKE_SYSTEM_PROCESSOR) to architecture define
13 | # as expected by bpf_traching.h. Add missing architectures as needed.
14 | set(bpf_arch_aarch64 arm64)
15 | set(bpf_arch_i386 x86)
16 | set(bpf_arch_i686 x86)
17 | set(bpf_arch_x86_64 x86)
18 | set(bpf_arch "${bpf_arch_${CMAKE_SYSTEM_PROCESSOR}}")
19 |
20 | if ( "${bpf_arch}" STREQUAL "" )
21 | message(FATAL_ERROR "Unknown architecture ${CMAKE_SYSTEM_PROCESSOR} for BPF, update BPF.cmake for ${CMAKE_SYSTEM_PROCESSOR}")
22 | endif ()
23 |
24 | # Send the object code through bpftool to get the header skeleton, which
25 | # will contain the compiled BPF byte code. The caller will need to `#include`
26 | # this header somewhere.
27 | macro (generate_bpf_code target name src)
28 | set(lib "bpf_${name}")
29 | add_library(${lib} ${src})
30 | set_property(SOURCE ${src} APPEND PROPERTY OBJECT_DEPENDS bpftool)
31 | target_include_directories(${lib} PRIVATE ${BPF_INCLUDE_DIR})
32 | target_compile_options(${lib} PRIVATE -target bpf -O2 -D__TARGET_ARCH_${bpf_arch}) # -O2 because of https://bugzilla.redhat.com/show_bug.cgi?id=1618958
33 |
34 | set(skel_h "${CMAKE_BINARY_DIR}/include/autogen/bpf/${name}.skel.h")
35 | set(lib_skel "bpf_${name}_skel")
36 |
37 | add_custom_command(
38 | COMMAND ${BPFTOOL} gen skeleton $ name ${name} >${skel_h}
39 | DEPENDS bpftool ${lib}
40 | OUTPUT ${skel_h}
41 | )
42 |
43 | add_custom_target(${lib_skel} DEPENDS ${skel_h})
44 | add_dependencies(${target} ${lib_skel})
45 | endmacro ()
46 |
--------------------------------------------------------------------------------
/cmake/CheckCompiler.cmake:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details.
2 | #
3 | # Adapted from Zeek.
4 |
5 | set(clang_minimum_version "9.0")
6 | set(apple_clang_minimum_version "11.0")
7 | set(gcc_minimum_version "9.0")
8 | set(msvc_toolset_minimum_version "143") # Visual Studio 2022
9 |
10 | include(CheckCXXSourceCompiles)
11 |
12 | macro(cxx17_compile_test)
13 | check_cxx_source_compiles("
14 | #include
15 | int main() { std::optional a; }"
16 | cxx17_works)
17 |
18 | if (NOT cxx17_works)
19 | message(FATAL_ERROR "failed using C++17 for compilation")
20 | endif ()
21 | endmacro()
22 |
23 | set(HAVE_GCC no)
24 | set(HAVE_CLANG no)
25 | set(HAVE_MSVC no)
26 |
27 | if ( CMAKE_CXX_COMPILER_ID STREQUAL "GNU" )
28 | set(HAVE_GCC yes)
29 | if ( CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${gcc_minimum_version} )
30 | message(FATAL_ERROR "GCC version must be at least "
31 | "${gcc_minimum_version} for C++17 support, detected: "
32 | "${CMAKE_CXX_COMPILER_VERSION}")
33 | endif ()
34 |
35 | elseif ( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
36 | set(HAVE_CLANG yes)
37 | if ( CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${clang_minimum_version} )
38 | message(FATAL_ERROR "Clang version must be at least "
39 | "${clang_minimum_version} for C++17 support, detected: "
40 | "${CMAKE_CXX_COMPILER_VERSION}")
41 | endif ()
42 | if ( CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5 )
43 | set(cxx17_flag "-std=c++1z")
44 | endif ()
45 | elseif ( CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" )
46 | set(HAVE_CLANG yes)
47 | if ( CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${apple_clang_minimum_version} )
48 | message(FATAL_ERROR "Apple Clang version must be at least "
49 | "${apple_clang_minimum_version} for C++17 support, detected: "
50 | "${CMAKE_CXX_COMPILER_VERSION}")
51 | endif ()
52 | elseif ( CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
53 | set(HAVE_MSVC yes)
54 | if ( MSVC_TOOLSET_VERSION LESS ${msvc_toolset_minimum_version} )
55 | message(FATAL_ERROR "MSVC Toolset version must be at least "
56 | "${msvc_clang_minimum_version} for C++20 support, detected: "
57 | "${MSVC_TOOLSET_VERSION}")
58 | endif()
59 | else()
60 | # Unrecognized compiler: fine to be permissive of other compilers as long
61 | # as they are able to support C++17 and can compile the test program, but
62 | # we just won't be able to give specific advice on what compiler version a
63 | # user needs in the case it actually doesn't support C++17.
64 | endif ()
65 |
66 | cxx17_compile_test()
67 |
--------------------------------------------------------------------------------
/cmake/CheckFunctions.cmake:
--------------------------------------------------------------------------------
1 | include (CheckFunctionExists)
2 |
3 | check_function_exists(getopt_long HAVE_GETOPT_LONG)
4 |
--------------------------------------------------------------------------------
/cmake/TargetOptions.cmake:
--------------------------------------------------------------------------------
1 |
2 | # Adds our compile and link options to an executble target.
3 | macro(add_target_options target scope)
4 | if ( NOT HAVE_WINDOWS )
5 | if ( CMAKE_BUILD_TYPE STREQUAL "Debug" )
6 | target_compile_options(${target} ${scope} -O0)
7 | endif()
8 |
9 | target_compile_options(${target} ${scope} $<$:-Werror>)
10 | target_compile_options(${target} ${scope} -Wno-unused-parameter)
11 | endif()
12 |
13 | if ( HAVE_CLANG )
14 | target_compile_options(${target} ${scope} -Wpedantic)
15 | target_compile_options(${target} ${scope} -Wno-c99-designator)
16 | target_compile_options(${target} ${scope} -Wno-vla-extension)
17 | endif ()
18 |
19 | if ( HAVE_GCC )
20 | target_compile_options(${target} ${scope} -Wno-missing-field-initializers)
21 | endif ()
22 |
23 | if ( HAVE_WINDOWS )
24 | # Keep min and max macros from being defined, which breaks std::min and std::max.
25 | target_compile_options(${target} ${scope} /DNOMINMAX)
26 | # Reduce the amount of stuff that gets included with windows.h.
27 | target_compile_options(${target} ${scope} /DWIN32_LEAN_AND_MEAN)
28 |
29 | target_compile_options(${target} ${scope} $<$:/WX>)
30 | # TODO: enable this eventually after figuring out how to disable it for third party code.
31 | # Equivalent to -Wpedantic but on Windows
32 | # target_compile_options(${target} ${scope} /Wall)
33 |
34 | # This is needed so that the console window pops up when you run the exe.
35 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
36 |
37 | set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_SOURCE_DIR}/packaging/windows/appicon.rc")
38 | endif ()
39 |
40 | if ( NOT "${USE_DOCTEST}" )
41 | add_compile_definitions(DOCTEST_CONFIG_DISABLE)
42 | endif ()
43 |
44 | if ( USE_SANITIZERS )
45 | target_compile_options(${target} ${scope} -fsanitize=${USE_SANITIZERS})
46 |
47 | if ( NOT HAVE_WINDOWS )
48 | # Recommended flags per https://github.com/google/sanitizers/wiki/AddressSanitizer
49 | # GCC vs clang: https://stackoverflow.com/a/47022141
50 | target_compile_options(${target} ${scope} -fno-omit-frame-pointer -fno-optimize-sibling-calls) # Removed -O1
51 | target_link_options(${target} ${scope} -fsanitize=${USE_SANITIZERS})
52 | endif ()
53 |
54 | if ( HAVE_CLANG )
55 | target_compile_options(${target} ${scope} -shared-libsan)
56 | target_link_options(${target} ${scope} -shared-libsan -frtlib-add-rpath)
57 | endif ()
58 | endif()
59 |
60 | endmacro()
61 |
--------------------------------------------------------------------------------
/cmake/Util.cmake:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details.
2 | #
3 | # A collection of small helpers for the Zeek Agent build system.
4 |
5 | # Warn or abort if we don't a given version isn't recent enough.
6 | function(require_version name found have need require)
7 | if ( NOT ${found} )
8 | if ( require )
9 | message(FATAL_ERROR "${name} required, but not found")
10 | else ()
11 | set(${found} no PARENT_SCOPE)
12 | set(${have} "not found")
13 | endif ()
14 | else ()
15 | if ( ${have} VERSION_LESS "${need}" )
16 | if ( require )
17 | message(FATAL_ERROR "Need ${name} version >= ${need}, found ${${have}}")
18 | endif ()
19 |
20 | message(STATUS "Warning: Need ${name} version >= ${need}, found ${${have}}")
21 | set(${found} no PARENT_SCOPE)
22 | set(${have} "${${have}} (error: too old, must be at least ${zeek_mininum_version})" PARENT_SCOPE)
23 | endif()
24 | endif()
25 | endfunction ()
26 |
--------------------------------------------------------------------------------
/packaging/darwin/codesign-wrapper:
--------------------------------------------------------------------------------
1 | # /usr/bin/env bash
2 |
3 | if [ -z "${MACOS_CERTIFICATE_APPLICATION_ID}" ]; then
4 | echo "=== Skipping codesign execution, MACOS_CERTIFICATE_APPLICATION_ID is not set"
5 | exit 0
6 | fi
7 |
8 | #echo "== CODESIGN: $@" >/dev/tty
9 | /usr/bin/codesign "$@"
10 |
--------------------------------------------------------------------------------
/packaging/darwin/hdiutil-with-codesign:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | #
3 | # CMake doesn't provide a hook running after the app bundle has been fully
4 | # assembled, but before the the DMG is being created. To get in there, we
5 | # replace hdituil with this script, so that we can codesign the final state of
6 | # the bundle the way we need to.
7 | #
8 | # Note to future self on logging: CPack doesn't seem to setup stdout/stderr, so
9 | # by default we don't see any output. That's why we redirect to /dev/tty if we have it.
10 | # However, in GH actions, we don't have that either, so we fall back to a log file.
11 |
12 | args=("$@")
13 | base=$(cd $(dirname $0)/../.. && pwd)
14 | app_src=${base}/src/platform/darwin/ZeekAgent.app
15 | log_no_tty="/tmp/zeek-agent-hdiutil.log"
16 |
17 | codesign="/usr/bin/codesign -s '${MACOS_CERTIFICATE_APPLICATION_ID}' -v --force --options=runtime --strict --timestamp"
18 |
19 | if sh -c ": >/dev/tty" >/dev/null 2>/dev/null; then
20 | have_tty=1
21 | else
22 | have_tty=0
23 | rm -f ${log_no_tty}
24 | fi
25 |
26 | log() {
27 | if [ "${have_tty}" = "1" ]; then
28 | echo "$@" >/dev/tty
29 | else
30 | echo "$@" >>${log_no_tty}
31 | fi
32 | }
33 |
34 | log_pipe() {
35 | if [ "${have_tty}" = "1" ]; then
36 | cat >/dev/tty
37 | else
38 | cat >>${log_no_tty}
39 | fi
40 | }
41 |
42 | codesign() {
43 | cd "$1"
44 | app="ZeekAgent.app"
45 |
46 | if [ -n "${MACOS_CERTIFICATE_APPLICATION_ID}" ]; then
47 | log "-- Signing ${app}"
48 | else
49 | log "-- Not signing ${app}, MACOS_CERTIFICATE_APPLICATION_ID not set"
50 | return
51 | fi
52 |
53 | eval ${codesign} --entitlements "${app_src}/entitlements.plist.agent" "${app}/Contents/Library/SystemExtensions/org.zeek.zeek-agent.agent.systemextension" 2>&1 | log_pipe
54 | eval ${codesign} --entitlements "${app_src}/entitlements.plist.app" "${app}" 2>&1 | log_pipe
55 | }
56 |
57 | log "== Running hdiutil"
58 | log "-- cmdline: $@"
59 |
60 | if [ "$1" == "create" ]; then
61 | while [ "$#" != 0 ]; do
62 | if [ "$1" = "-srcfolder" -a "$2" != "" ]; then
63 | codesign "$2"
64 | break
65 | fi
66 | shift
67 | done
68 | fi
69 |
70 | set -- "${args[@]}"
71 | /usr/bin/hdiutil "$@"
72 |
--------------------------------------------------------------------------------
/packaging/darwin/notarize:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env bash
2 | #
3 | # Submits a bundle (e.g., a DMG or ZIP) for Apple notarization.
4 | #
5 | # This script can sign with either application or installers certificates. We
6 | # currently don't use the latter, but we're keeping in the functionality in
7 | # case it'll come in handy some day.
8 | #
9 | # For notarization, store the App Store Connect credentials in the default
10 | # keychain through `xcrun notarytool store-credentials "App Store Connect API -
11 | # zeek-agent"`.
12 |
13 | set -e
14 |
15 | function usage {
16 | echo "Usage: $(basename $0) application|installer " >&2
17 | }
18 |
19 | if [ $# != 2 ]; then
20 | usage
21 | exit 1
22 | fi
23 |
24 | base=$(cd $(dirname $0)/../.. && pwd)
25 | app_src=${base}/src/platform/darwin/ZeekAgent.app
26 | sign_type=$1
27 | bundle=$2
28 |
29 | echo "== Notarizing bundle ..."
30 |
31 | if [ "${sign_type}" == "installer" ]; then
32 | if [ -z "${MACOS_CERTIFICATE_INSTALLER_ID}" ]; then
33 | echo "Error: MACOS_CERTIFICATE_INSTALLER_ID not set" >&2
34 | exit 1
35 | fi
36 |
37 | echo "-- Signing installer ..."
38 | productsign --sign "${MACOS_CERTIFICATE_INSTALLER_ID}" "${bundle}" "${bundle}.tmp"
39 | mv "${bundle}.tmp" "${bundle}"
40 |
41 | elif [ "$1" == "application" ]; then
42 | if [ -z "${MACOS_CERTIFICATE_APPLICATION_ID}" ]; then
43 | echo "Error: MACOS_CERTIFICATE_APPLICATION_ID not set" >&2
44 | exit 1
45 | fi
46 |
47 | echo "-- Signing bundle ..."
48 | codesign -f -s "${MACOS_CERTIFICATE_APPLICATION_ID}" --timestamp --entitlements ${app_src}/entitlements.plist.app ${bundle}
49 |
50 | else
51 | usage
52 | exit 1
53 | fi
54 |
55 | echo "-- Uploading for notarization ..."
56 |
57 | xcrun notarytool submit --keychain-profile "App Store Connect API - zeek-agent" --wait --timeout 20m "${bundle}"
58 |
59 | echo "-- Stapling ..."
60 |
61 | xcrun stapler staple ${bundle}
62 |
63 | echo "-- Verifying ..."
64 |
65 | spctl -a -vv -t install ${bundle}
66 | xcrun stapler validate ${bundle}
67 |
--------------------------------------------------------------------------------
/packaging/darwin/post-build.cmake:
--------------------------------------------------------------------------------
1 | # Validate/display signatures and entitlements to the degree we can.
2 | foreach (pkg "${CPACK_PACKAGE_FILES}")
3 | string(REPLACE ".dmg" "" bundle "${pkg}")
4 | foreach (path
5 | ZeekAgent.app
6 | ZeekAgent.app/Contents/Library/SystemExtensions/org.zeek.zeek-agent.agent.systemextension
7 | )
8 | get_filename_component(name "${path}" NAME)
9 | message(STATUS "Validating ${name}")
10 | execute_process(COMMAND /usr/bin/codesign -vv --strict "${bundle}/${path}")
11 | execute_process(COMMAND /usr/bin/codesign -dv --strict "${bundle}/${path}")
12 | execute_process(COMMAND /usr/bin/codesign -d --entitlements - "${bundle}/${path}")
13 | endforeach()
14 | endforeach()
15 |
16 | if ( NOT "$ENV{MACOS_NOTARIZE}" STREQUAL "")
17 | foreach (pkg "${CPACK_PACKAGE_FILES}")
18 | execute_process(COMMAND ${CMAKE_CURRENT_LIST_DIR}/notarize application "${pkg}" COMMAND_ERROR_IS_FATAL ANY)
19 | endforeach()
20 | else ()
21 | message(STATUS "Not notarizing application, MACOS_NOTARIZE not set")
22 | endif()
23 |
--------------------------------------------------------------------------------
/packaging/windows/appicon.rc:
--------------------------------------------------------------------------------
1 | ID1_ICON1 ICON DISCARDABLE "icon.ico"
2 |
--------------------------------------------------------------------------------
/packaging/windows/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeek/zeek-agent-v2/fb1fe0f8017db6c30356e3ea77595ae432950efa/packaging/windows/banner.png
--------------------------------------------------------------------------------
/packaging/windows/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeek/zeek-agent-v2/fb1fe0f8017db6c30356e3ea77595ae432950efa/packaging/windows/icon.ico
--------------------------------------------------------------------------------
/packaging/windows/sidebar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeek/zeek-agent-v2/fb1fe0f8017db6c30356e3ea77595ae432950efa/packaging/windows/sidebar.png
--------------------------------------------------------------------------------
/packaging/windows/wix-extra.xml.in:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/packaging/windows/wix-patch.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/packaging/windows/wix-string-overrides.wxl:
--------------------------------------------------------------------------------
1 |
2 | Thank you for installing [ProductName]. To complete the installation, modify the zeek-agent.cfg file in the %PROGRAMDATA%\[ProductName] directory and reboot your computer.
3 |
4 | Click the Finish button to exit the Setup.
5 |
6 |
--------------------------------------------------------------------------------
/packaging/zeek-agent.cfg.template:
--------------------------------------------------------------------------------
1 | # Configuration file for ZeekAgent. Most of these options should work with their
2 | # normal defaults. The main option that should be modified is the zeek.destinations
3 | # option. See the documentation below for the valid values for each option. Some of
4 | # these options (such as the log level) can be overridden with command-line flags.
5 | # See zeek-agent --help for more information about those flags.
6 |
7 | [log]
8 | # The granulatity of the log information.
9 | # Valid values: "trace", "debug", "info", "warning", "error", "critical", "off"
10 | # "trace" will return the most log data, while "critical" returns the least.
11 | # Setting this option to "off" will disable all logging.
12 | #level = "info"
13 |
14 | # Valid values:
15 | # "file": send all logs to the file defined in the log.path option
16 | # "system": send logs the appropriate system logging facility (e.g. syslog)
17 | # "stdout": send all logs to stdout
18 | #type = "stdout"
19 |
20 | # A path to a file to store log data if the log.type option is set to "file".
21 | #path = ""
22 |
23 | [zeek]
24 | # A bracketed list of hostname/ip:port values that define what hosts running Zeek
25 | # that the agent should send data to. This option must be set for zeek-agent to
26 | # function properly.
27 | #destination = []
28 |
29 | # The interval in seconds to expire any state from a connected Zeek instance if
30 | # no activity has been seen from it.
31 | #timeout = 120
32 |
33 | # The interval in seconds for when "hello" pings are sent.
34 | #hello_interval = 60
35 |
36 | # The amount of time in seconds to wait to reconnect to a Zeek instance if the
37 | # connection is closed.
38 | #reconnect_interval = 30
39 |
40 | #groups =
41 |
42 | # If true, the agent will not use SSL for network connections. By default,
43 | # SSL will be used even if no certificates / CAs have been configured, so
44 | # that the communication will always be encrypted.
45 | #ssl_disable = false
46 |
47 | # Path to a file containing concatenated trusted certificates in PEM format.
48 | # If set, the agent will require valid certificates for all peers.
49 | #ssl_cafile = ""
50 |
51 | # Path to an OpenSSL-style directory of trusted certfiicates. If set, the
52 | # agent will rqeuire valid certificates from all peers.
53 | #ssl_capath = ""
54 |
55 | # Path to a file containing an X.509 certificat for this node in PEM format.
56 | # If set, the agent will require valid certificates for all peers.
57 | #ssl_certificate = ""
58 |
59 | # Path to the file containing the private key for this node's certificate.
60 | # If set, the agent will require valid certificates for all peers.
61 | #ssl_keyfile = ""
62 |
63 | # Passphrase to decrypt the private key specified by the ssl_keyfile option.
64 | # If set, the agent will require valid certificates for all peers.
65 | #ssl_passphrase =
66 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details.
2 |
3 | ### Setup compiler
4 |
5 | if ( HAVE_WINDOWS )
6 | # We require C++20 on MSVC because designated-initializers don't exist in C++17 mode.
7 | set(CMAKE_CXX_STANDARD 20)
8 | else()
9 | set(CMAKE_CXX_STANDARD 17)
10 | endif()
11 |
12 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
13 | set(CMAKE_CXX_EXTENSIONS OFF)
14 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
15 |
16 | include(CheckCompiler)
17 | include(CheckFunctions)
18 | include(TargetOptions)
19 |
20 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/include)
21 |
22 | add_executable(zeek-agent main.cc ${APP_ICON_RESOURCE_WINDOWS})
23 | add_target_options(zeek-agent PRIVATE)
24 |
25 | add_subdirectory(core)
26 | add_subdirectory(io)
27 | add_subdirectory(platform)
28 | add_subdirectory(tables)
29 | add_subdirectory(util)
30 |
31 | if ( USE_BROKER )
32 | # Ensure that we include our Broker version even if existing includes may lead us elswhere.
33 | target_include_directories(zeek-agent PRIVATE $)
34 | endif ()
35 |
36 | target_link_libraries(zeek-agent PRIVATE ${CMAKE_DL_LIBS})
37 | target_link_libraries(zeek-agent PRIVATE doctest::doctest)
38 | target_link_libraries(zeek-agent PRIVATE fmt::fmt)
39 | target_link_libraries(zeek-agent PRIVATE ghcFilesystem::ghc_filesystem)
40 | target_link_libraries(zeek-agent PRIVATE nlohmann_json)
41 | target_link_libraries(zeek-agent PRIVATE ixwebsocket::ixwebsocket)
42 | target_link_libraries(zeek-agent PRIVATE pathfind::pathfind)
43 | target_link_libraries(zeek-agent PRIVATE replxx::replxx)
44 | target_link_libraries(zeek-agent PRIVATE reproc++)
45 | target_link_libraries(zeek-agent PRIVATE spdlog::spdlog)
46 | target_link_libraries(zeek-agent PRIVATE sqlite::sqlite)
47 | target_link_libraries(zeek-agent PRIVATE stduuid)
48 | target_link_libraries(zeek-agent PRIVATE tomlplusplus::tomlplusplus)
49 | target_link_libraries(zeek-agent PRIVATE ztd::out_ptr)
50 | target_link_libraries(zeek-agent PRIVATE Glob)
51 |
52 | if ( USE_BROKER )
53 | target_link_libraries(zeek-agent PRIVATE broker_static)
54 | endif ()
55 |
56 | if ( NOT HAVE_GETOPT_LONG )
57 | target_link_libraries(zeek-agent PRIVATE 3rdparty:3rdparty)
58 | endif()
59 |
60 | if ( HAVE_WINDOWS )
61 | target_link_libraries(zeek-agent PRIVATE ntdll)
62 | target_link_libraries(zeek-agent PRIVATE ws2_32)
63 | target_link_libraries(zeek-agent PRIVATE iphlpapi)
64 | target_link_libraries(zeek-agent PRIVATE wbemuuid)
65 | target_link_libraries(zeek-agent PRIVATE shlwapi)
66 | endif()
67 |
68 | if ( NOT HAVE_DARWIN ) # On Darwin, we customize the install location later
69 | install(TARGETS zeek-agent)
70 | endif ()
71 |
72 | configure_file(config.h.in "${CMAKE_BINARY_DIR}/include/autogen/config.h")
73 |
74 | # Create a test with a dependency on zeek-agent.
75 | # See https://stackoverflow.com/a/56448477
76 | add_test(build-zeek-agent "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --config "$" --target zeek-agent)
77 | set_tests_properties(build-zeek-agent PROPERTIES FIXTURES_SETUP test_fixture)
78 | add_test(NAME zeek-agent COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/zeek-agent --test)
79 | set_tests_properties(zeek-agent PROPERTIES FIXTURES_REQUIRED test_fixture)
80 |
--------------------------------------------------------------------------------
/src/config.h.in:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details.
2 |
3 | #pragma once
4 |
5 | #cmakedefine HAVE_POSIX
6 | #cmakedefine HAVE_DARWIN
7 | #cmakedefine HAVE_LINUX
8 | #cmakedefine HAVE_WINDOWS
9 | #cmakedefine HAVE_GCC
10 | #cmakedefine HAVE_CLANG
11 | #cmakedefine HAVE_MSVC
12 | #cmakedefine HAVE_GETOPT_LONG
13 | #cmakedefine HAVE_BROKER
14 |
15 | namespace zeek::agent {
16 | inline const auto Version = "${ZEEK_AGENT_VERSION}";
17 | inline const auto VersionLong = "${ZEEK_AGENT_VERSION_LONG}";
18 | inline const auto InstallLibDir = "${CMAKE_INSTALL_LIBDIR}";
19 | inline const auto InstallPrefix = "${CMAKE_INSTALL_PREFIX}";
20 | } // namespace zeek::agent
21 |
--------------------------------------------------------------------------------
/src/core/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details.
2 |
3 | target_sources(zeek-agent
4 | PRIVATE
5 | configuration.cc
6 | database.cc
7 | logger.cc
8 | scheduler.cc
9 | sqlite.cc
10 | table.cc
11 | )
12 |
13 | if ( HAVE_POSIX )
14 | target_sources(zeek-agent PRIVATE signal.posix.cc)
15 | elseif ( HAVE_WINDOWS )
16 | target_sources(zeek-agent PRIVATE signal.windows.cc)
17 | endif ()
18 |
--------------------------------------------------------------------------------
/src/core/logger.cc:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details.
2 |
3 | #include "logger.h"
4 |
5 | #include "autogen/config.h"
6 | #include "core/configuration.h"
7 | #include "util/filesystem.h"
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #ifdef HAVE_DARWIN
19 | #include
20 | #endif
21 |
22 | #ifndef HAVE_WINDOWS
23 | #include
24 | #endif
25 |
26 | #ifdef HAVE_WINDOWS
27 | #define STDOUT_FILENO 0
28 | #endif
29 |
30 | using namespace zeek::agent;
31 |
32 | namespace {
33 | std::shared_ptr global_logger = {};
34 | }
35 |
36 | Result zeek::agent::setGlobalLogger(options::LogType type, options::LogLevel level,
37 | const std::optional& path) {
38 | spdlog::sink_ptr sink{};
39 |
40 | // Note we are creating thread-safe logger here (`*_mt`).
41 | switch ( type ) {
42 | case options::LogType::Stderr: sink = std::make_shared(); break;
43 |
44 | case options::LogType::Stdout:
45 | if ( isatty(STDOUT_FILENO) )
46 | sink = std::make_shared();
47 | else
48 | sink = std::make_shared();
49 |
50 | break;
51 |
52 | case options::LogType::System:
53 | #if defined(HAVE_LINUX)
54 | sink = std::make_shared("zeek-agent", 0, LOG_USER, false);
55 | #elif defined(HAVE_DARWIN)
56 | sink = std::make_shared();
57 | #elif defined(HAVE_WINDOWS)
58 | // TODO: Where should Windows system logging go? The event log?
59 | logger()->warn("system logging currently not supported on Windows");
60 | #else
61 | #error "Unsupported platform in setGlobalLogger()"
62 | #endif
63 | break;
64 |
65 | case options::LogType::File:
66 | if ( ! path )
67 | return result::Error("file logging requires a path");
68 |
69 | sink = std::make_shared(path_to_spdlog_filename(*path));
70 | break;
71 | }
72 |
73 | global_logger = std::make_shared("Zeek Agent", std::move(sink));
74 | global_logger->set_level(level);
75 |
76 | return Nothing();
77 | }
78 |
79 | spdlog::logger* zeek::agent::logger() {
80 | if ( ! global_logger )
81 | // Default until something else is set.
82 | setGlobalLogger(options::LogType::Stdout, options::default_log_level);
83 |
84 | return global_logger.get();
85 | }
86 |
--------------------------------------------------------------------------------
/src/core/logger.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details.
2 |
3 | #pragma once
4 |
5 | #include "core/configuration.h"
6 |
7 | #include
8 |
9 | namespace zeek::agent {
10 |
11 | Result setGlobalLogger(options::LogType type, options::LogLevel level,
12 | const std::optional& path = {});
13 |
14 | /** Returns the global logger instance. Use of the logger is thread-safe. */
15 | extern spdlog::logger* logger();
16 |
17 | #define __ZEEK_AGENT_LOG(level, component, ...) /* NOLINT */ \
18 | logger()->log(level, frmt("[{}] ", component) + frmt(__VA_ARGS__))
19 |
20 | #ifndef NDEBUG
21 | #define ZEEK_AGENT_DEBUG(component, ...) __ZEEK_AGENT_LOG(spdlog::level::debug, component, __VA_ARGS__)
22 | #define ZEEK_AGENT_TRACE(component, ...) __ZEEK_AGENT_LOG(spdlog::level::trace, component, __VA_ARGS__)
23 | #else
24 | #define ZEEK_AGENT_DEBUG(component, ...) __ZEEK_AGENT_LOG(spdlog::level::debug, component, __VA_ARGS__)
25 | #define ZEEK_AGENT_TRACE(component, ...)
26 | #endif
27 |
28 | } // namespace zeek::agent
29 |
--------------------------------------------------------------------------------
/src/core/scheduler.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details.
2 |
3 | #pragma once
4 |
5 | #include "util/helpers.h"
6 | #include "util/pimpl.h"
7 |
8 | #include
9 |
10 | namespace zeek::agent {
11 |
12 | namespace timer {
13 | /** Unique ID for a scheduled timer. */
14 | using ID = uint64_t;
15 |
16 | /**
17 | * Callback triggering when a timer expires. If the callback returns a non-zero interval, the
18 | * scheduler will automatically reschedule the timer the given amount of time into the future.
19 | * The reschedule timer will keep its ID.
20 | */
21 | using Callback = std::function;
22 | } // namespace timer
23 |
24 | namespace task {
25 | /** Callback for an operation queued for execution. */
26 | using Callback = std::function;
27 | } // namespace task
28 |
29 | /**
30 | * Manages a set of scheduled timers with associated callbacks to eventually
31 | * execute. The scheduler has an internal notion of time and will execute the
32 | * callback associated with a timer once its expiration time has been reached.
33 | * Timer and callback will then be deleted afterwards.
34 | *
35 | * A scheduler doesn't automatically advances it's time; that must be driven
36 | * externally by calls to `advance()`. That allows the caller to decide the
37 | * semantics of time: they can drive it either through a real-time clock, or
38 | * for example through a deterministic sequence of fixed steps. The latter is
39 | * particularly useful for unit testing.
40 | *
41 | * Note that methods of this class aren't thread-safe unless stated othewise.
42 | */
43 | class Scheduler : public Pimpl {
44 | public:
45 | Scheduler();
46 | ~Scheduler();
47 |
48 | /**
49 | * Schedules a new timer to a specific point of time in the future.
50 | *
51 | * This method is thread-safe and may be called from any thread. The
52 | * callback will always be executed on the main thread.
53 | *
54 | * @param t time to schedule the timer for
55 | * @param cb callback to execute when `t` has been reached
56 | * @returns a unique ID for the scheduled timer, which will remain valid
57 | * until the timer fires or gets canceled
58 | */
59 | timer::ID schedule(Time t, timer::Callback cb);
60 |
61 | /**
62 | * Enqueues a callback to execute at the next possible opportunity fro the
63 | * scheduler's thread.
64 | *
65 | * This method is thread-safe and may be called from any thread. The
66 | * callback will always be executed on the main thread.
67 | *
68 | * @param cb callback to execute as soon as possible
69 | */
70 | void schedule(task::Callback cb);
71 |
72 | /**
73 | * Cancels a previously installed timer. The timer will be deleted without
74 | * its callback executing.
75 | *
76 | * @param id timer's ID as previously returned by one of the `schedule()`
77 | * methods; it's ok if the timer already doesn't exist anymore
78 | */
79 | void cancel(timer::ID id);
80 |
81 | /**
82 | * Advances to scheduler's notion of the current time. This will let all
83 | * timers fire that are currently scheduled for a time <= `now`. Their
84 | * callbacks will have fully executed before the method returns, and they
85 | * will run from the same thread as the caller of this method. Advancing
86 | * will also execute any callbacks scheduled with
87 | * `registerAdvanceCallback()`.
88 | *
89 | * @param t new current time for the scheduler; if `t` is <= `now()`, the
90 | * method will not do anything
91 | */
92 | void advance(Time t);
93 |
94 | /**
95 | * Returns the scheduler's current time. This is the most recent time
96 | * passed to `advance().
97 | */
98 | Time currentTime() const;
99 |
100 | /**
101 | * Returns the number of timers/tasks currently scheduled for execution.
102 | */
103 | size_t pendingTimers() const;
104 |
105 | /**
106 | * Request processing to terminate. This will stop
107 | * `processUntilTerminated()`, but can also act more globally as signal to
108 | * users of the scheduler to cease operations. They can query the
109 | * termination state through `terminating()`.
110 | */
111 | void terminate();
112 |
113 | /** Returns true if `terminate()` has been called previously. */
114 | bool terminating() const;
115 |
116 | /**
117 | * Executes pending activity up to current wall clock. If nothing is
118 | * pending, blocks for a little while (with new activity interrupting the
119 | * block).
120 | *
121 | * @return true if processing is to continue; false if the scheduler has
122 | * been asked to terminate
123 | */
124 | bool loop();
125 | };
126 |
127 | } // namespace zeek::agent
128 |
--------------------------------------------------------------------------------
/src/core/signal.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details.
2 |
3 | #pragma once
4 |
5 | #include "util/pimpl.h"
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | namespace zeek::agent {
12 | // Signal number, specified through the standard `SIGxxx` macros
13 | using Signal = int;
14 |
15 | class SignalManager;
16 |
17 | namespace signal {
18 |
19 | class Handler {
20 | public:
21 | using Callback = std::function;
22 |
23 | /**
24 | * Constructor. Instantiates a handler and registers it with a manager for
25 | * handling a specified signal. The handler will remain active during its
26 | * entire life-time and unregster itself at destruction time.
27 | *
28 | * @param mgr manager to register the handler with
29 | * @param signal signal number, which must be part of the set the manager was asked to handle
30 | * @param cb callback to execute when manager receives signal
31 | */
32 | Handler(SignalManager* mgr, Signal sig, Callback cb);
33 | ~Handler();
34 |
35 | private:
36 | SignalManager* _manager;
37 | Signal _signal;
38 | std::list::iterator _handler; // position of handler in manager's list
39 | };
40 | } // namespace signal
41 |
42 | /**
43 | * Manages Unix signal handling by keeping a registry of signal handlers to
44 | * dispatch to when receiving a signal. To register a handler, instantiate it
45 | * with the manager as an argument. If multiple handlers are registered for the
46 | * same signal, the most recent one will receive control when the signal fires.
47 | *
48 | * A manager assumes that it's the only one manipulating signal behaviour for
49 | * the current process. That implies that no two managers should exist at the
50 | * same time.
51 | **/
52 | class SignalManager : public Pimpl {
53 | public:
54 | /**
55 | * Constructor.
56 | *
57 | * @param set of signals that this manager is to (exclusively) handle
58 | */
59 | SignalManager(const std::vector& signals_to_handle);
60 | ~SignalManager();
61 | };
62 |
63 | extern SignalManager* signal_mgr;
64 |
65 | } // namespace zeek::agent
66 |
--------------------------------------------------------------------------------
/src/core/signal.windows.cc:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2021-2024 by the Zeek Project. See LICENSE for details.
2 |
3 | #include "./signal.h"
4 |
5 | #include "logger.h"
6 | #include "util/fmt.h"
7 | #include "util/testing.h"
8 |
9 | #include
10 | #include
11 | #include
12 | #include